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));
}
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);
}
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();
}
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;
}
Aggregations