Search in sources :

Example 1 with AbstractComponent

use of org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent in project smarthome by eclipse.

the class HomeAssistantMQTTImplementationTests method parseHATree.

@Test
public void parseHATree() throws InterruptedException, ExecutionException, TimeoutException {
    MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
    final Map<String, AbstractComponent> haComponents = new HashMap<String, AbstractComponent>();
    ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
    DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.testHomeAssistantThing, scheduler, channelStateUpdateListener, new Gson()));
    // The DiscoverComponents object calls ComponentDiscovered callbacks.
    // In the following implementation we add the found component to the `haComponents` map
    // and add the types to the channelTypeProvider, like in the real Thing handler.
    final CountDownLatch latch = new CountDownLatch(1);
    ComponentDiscovered cd = (haID, c) -> {
        haComponents.put(haID.getChannelGroupID(), c);
        c.addChannelTypes(channelTypeProvider);
        channelTypeProvider.setChannelGroupType(c.groupTypeUID(), c.type());
        latch.countDown();
    };
    // Start the discovery for 100ms. Forced timeout after 300ms.
    HaID haID = new HaID(testObjectTopic);
    CompletableFuture<Void> future = discover.startDiscovery(connection, 100, haID, cd).thenRun(() -> {
    }).exceptionally(e -> {
        failure = e;
        return null;
    });
    assertTrue(latch.await(300, TimeUnit.MILLISECONDS));
    future.get(100, TimeUnit.MILLISECONDS);
    // No failure expected and one discoverd result
    assertNull(failure);
    assertThat(haComponents.size(), is(1));
    // For the switch component we should have one channel group type and one channel type
    verify(channelTypeProvider, times(1)).setChannelGroupType(any(), any());
    verify(channelTypeProvider, times(1)).setChannelType(any(), any());
    // We expect a switch component with an OnOff channel with the initial value UNDEF:
    State value = haComponents.get(haID.getChannelGroupID()).channelTypes().get(ComponentSwitch.switchChannelID).channelState.getCache().getChannelState();
    assertThat(value, is(UnDefType.UNDEF));
    haComponents.values().stream().map(e -> e.start(connection, scheduler, 100)).reduce(CompletableFuture.completedFuture(null), (a, v) -> a.thenCompose(b -> v)).exceptionally(e -> {
        failure = e;
        return null;
    }).get();
    // We should have received the retained value, while subscribing to the channels MQTT state topic.
    verify(channelStateUpdateListener, times(1)).updateChannelState(any(), any());
    // Value should be ON now.
    value = haComponents.get(haID.getChannelGroupID()).channelTypes().get(ComponentSwitch.switchChannelID).channelState.getCache().getChannelState();
    assertThat(value, is(OnOffType.ON));
}
Also used : CoreMatchers.is(org.hamcrest.CoreMatchers.is) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) MockitoAnnotations.initMocks(org.mockito.MockitoAnnotations.initMocks) Mock(org.mockito.Mock) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) OnOffType(org.eclipse.smarthome.core.library.types.OnOffType) UnDefType(org.eclipse.smarthome.core.types.UnDefType) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) MqttConnectionState(org.eclipse.smarthome.io.transport.mqtt.MqttConnectionState) DiscoverComponents(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.DiscoverComponents) AbstractComponent(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent) ArrayList(java.util.ArrayList) MqttService(org.eclipse.smarthome.io.transport.mqtt.MqttService) ConfigurationException(org.osgi.service.cm.ConfigurationException) Nullable(org.eclipse.jdt.annotation.Nullable) Gson(com.google.gson.Gson) Map(java.util.Map) After(org.junit.After) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ChannelStateUpdateListener(org.eclipse.smarthome.binding.mqtt.generic.internal.generic.ChannelStateUpdateListener) State(org.eclipse.smarthome.core.types.State) MqttConnectionObserver(org.eclipse.smarthome.io.transport.mqtt.MqttConnectionObserver) MqttChannelTypeProvider(org.eclipse.smarthome.binding.mqtt.generic.internal.generic.MqttChannelTypeProvider) ComponentSwitch(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.ComponentSwitch) Before(org.junit.Before) JavaOSGiTest(org.eclipse.smarthome.test.java.JavaOSGiTest) ComponentDiscovered(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.DiscoverComponents.ComponentDiscovered) Logger(org.slf4j.Logger) ThingChannelConstants(org.eclipse.smarthome.binding.mqtt.generic.internal.handler.ThingChannelConstants) MqttBrokerConnection(org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnection) HaID(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.HaID) ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) Test(org.junit.Test) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Mockito(org.mockito.Mockito) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Assert(org.junit.Assert) NonNull(org.eclipse.jdt.annotation.NonNull) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) MqttChannelTypeProvider(org.eclipse.smarthome.binding.mqtt.generic.internal.generic.MqttChannelTypeProvider) HashMap(java.util.HashMap) ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) Gson(com.google.gson.Gson) CountDownLatch(java.util.concurrent.CountDownLatch) DiscoverComponents(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.DiscoverComponents) AbstractComponent(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent) ComponentDiscovered(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.DiscoverComponents.ComponentDiscovered) HaID(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.HaID) MqttConnectionState(org.eclipse.smarthome.io.transport.mqtt.MqttConnectionState) State(org.eclipse.smarthome.core.types.State) JavaOSGiTest(org.eclipse.smarthome.test.java.JavaOSGiTest) Test(org.junit.Test)

Example 2 with AbstractComponent

use of org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent in project smarthome by eclipse.

the class HomeAssistantThingHandler method accept.

/**
 * Callback of {@link DelayedBatchProcessing}.
 * Add all newly discovered components to the Thing and start the components.
 */
@SuppressWarnings("null")
@Override
public void accept(List<AbstractComponent> discoveredComponentsList) {
    MqttBrokerConnection connection = this.connection;
    if (connection == null) {
        return;
    }
    List<Channel> channels = new ArrayList<>();
    synchronized (haComponents) {
        // sync whenever discoverComponents is started
        for (AbstractComponent discovered : discoveredComponentsList) {
            AbstractComponent known = haComponents.get(discovered.uid().getId());
            // Is component already known?
            if (known != null) {
                if (discovered.getConfigHash() != known.getConfigHash()) {
                    // Don't wait for the future to complete. We are also not interested in failures.
                    // The component will be replaced in a moment.
                    known.stop();
                } else {
                    continue;
                }
            }
            // Add channel and group types to the types registry
            channelTypeProvider.setChannelGroupType(discovered.groupTypeUID(), discovered.type());
            discovered.addChannelTypes(channelTypeProvider);
            // Add component to the component map
            haComponents.put(discovered.uid().getId(), discovered);
            // Start component / Subscribe to channel topics
            discovered.start(connection, scheduler, 0).exceptionally(e -> {
                logger.warn("Failed to start component {}", discovered.uid(), e);
                return null;
            });
        }
        // Add channels to Thing
        for (AbstractComponent e : haComponents.values()) {
            for (CChannel entry : e.channelTypes().values()) {
                channels.add(entry.channel);
            }
        }
    }
    updateThing(editThing().withChannels(channels).build());
    updateStatus(ThingStatus.ONLINE);
}
Also used : AbstractComponent(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent) CChannel(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.CChannel) MqttBrokerConnection(org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnection) Channel(org.eclipse.smarthome.core.thing.Channel) CChannel(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.CChannel) ArrayList(java.util.ArrayList)

Example 3 with AbstractComponent

use of org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent in project smarthome by eclipse.

the class HomeAssistantThingHandler method initialize.

@SuppressWarnings({ "null", "unused" })
@Override
public void initialize() {
    config = getConfigAs(HandlerConfiguration.class);
    if (config.objectid.isEmpty()) {
        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Device ID unknown");
        return;
    }
    discoveryHomeAssistantID = new HaID(config.basetopic, config.objectid, "", "");
    for (Channel channel : thing.getChannels()) {
        final String groupID = channel.getUID().getGroupId();
        if (groupID == null) {
            logger.warn("Channel {} has no groupd ID", channel.getLabel());
            continue;
        }
        // Already restored component?
        @Nullable AbstractComponent component = haComponents.get(groupID);
        if (component != null) {
            continue;
        } else {
            component = CFactory.createComponent(config.basetopic, channel, this, gson);
        }
        if (component != null) {
            haComponents.put(component.uid().getId(), component);
            component.addChannelTypes(channelTypeProvider);
        } else {
            logger.warn("Could not restore component {}", thing);
        }
    }
    super.initialize();
}
Also used : AbstractComponent(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent) HandlerConfiguration(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.HandlerConfiguration) HaID(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.HaID) Channel(org.eclipse.smarthome.core.thing.Channel) CChannel(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.CChannel) Nullable(org.eclipse.jdt.annotation.Nullable)

Example 4 with AbstractComponent

use of org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent in project smarthome by eclipse.

the class HomeAssistantThingHandler method getChannelState.

@SuppressWarnings({ "null", "unused" })
@Override
@Nullable
public ChannelState getChannelState(ChannelUID channelUID) {
    String groupID = channelUID.getGroupId();
    if (groupID == null) {
        return null;
    }
    AbstractComponent component;
    synchronized (haComponents) {
        // sync whenever discoverComponents is started
        component = haComponents.get(groupID);
    }
    if (component == null) {
        return null;
    }
    CChannel componentChannel = component.channel(channelUID.getIdWithoutGroup());
    if (componentChannel == null) {
        return null;
    }
    return componentChannel.channelState;
}
Also used : AbstractComponent(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent) CChannel(org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.CChannel) Nullable(org.eclipse.jdt.annotation.Nullable)

Aggregations

AbstractComponent (org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.AbstractComponent)4 Nullable (org.eclipse.jdt.annotation.Nullable)3 CChannel (org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.CChannel)3 ArrayList (java.util.ArrayList)2 HaID (org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.HaID)2 Channel (org.eclipse.smarthome.core.thing.Channel)2 MqttBrokerConnection (org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnection)2 Gson (com.google.gson.Gson)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 CompletableFuture (java.util.concurrent.CompletableFuture)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ExecutionException (java.util.concurrent.ExecutionException)1 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)1 ScheduledThreadPoolExecutor (java.util.concurrent.ScheduledThreadPoolExecutor)1 TimeUnit (java.util.concurrent.TimeUnit)1 TimeoutException (java.util.concurrent.TimeoutException)1 NonNull (org.eclipse.jdt.annotation.NonNull)1 ComponentSwitch (org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homeassistant.ComponentSwitch)1