diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java index 6a0eaead4decb..17922fee54572 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java @@ -90,4 +90,9 @@ public class NikoHomeControlBindingConstants { public static final String CONFIG_OVERRULETIME = "overruleTime"; public static final String CONFIG_ENERGYMETER_ID = "energyMeterId"; + + // Thing properties + public static final String PROPERTY_DEVICE_TYPE = "deviceType"; + public static final String PROPERTY_DEVICE_TECHNOLOGY = "deviceTechnology"; + public static final String PROPERTY_DEVICE_MODEL = "deviceModel"; } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java index 6cb6c0d25fbd2..fda292a180adb 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java @@ -14,29 +14,20 @@ import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.nikohomecontrol.internal.discovery.NikoHomeControlDiscoveryService; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlActionHandler; -import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler1; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler2; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlEnergyMeterHandler; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlThermostatHandler; -import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.net.NetworkAddressService; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -47,14 +38,12 @@ * @author Mark Herwege - Initial Contribution */ -@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nikohomecontrol") @NonNullByDefault +@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nikohomecontrol") public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory { private @NonNullByDefault({}) NetworkAddressService networkAddressService; - private final Map> discoveryServiceRegs = new HashMap<>(); - @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID) || BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID); @@ -63,14 +52,11 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { @Override protected @Nullable ThingHandler createHandler(Thing thing) { if (BRIDGE_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) { - NikoHomeControlBridgeHandler handler; if (BRIDGEII_THING_TYPE.equals(thing.getThingTypeUID())) { - handler = new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService); + return new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService); } else { - handler = new NikoHomeControlBridgeHandler1((Bridge) thing); + return new NikoHomeControlBridgeHandler1((Bridge) thing); } - registerNikoHomeControlDiscoveryService(handler); - return handler; } else if (THING_TYPE_THERMOSTAT.equals(thing.getThingTypeUID())) { return new NikoHomeControlThermostatHandler(thing); } else if (THING_TYPE_ENERGYMETER.equals(thing.getThingTypeUID())) { @@ -82,29 +68,6 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { return null; } - private synchronized void registerNikoHomeControlDiscoveryService(NikoHomeControlBridgeHandler bridgeHandler) { - NikoHomeControlDiscoveryService nhcDiscoveryService = new NikoHomeControlDiscoveryService(bridgeHandler); - discoveryServiceRegs.put(bridgeHandler.getThing().getUID(), bundleContext - .registerService(DiscoveryService.class.getName(), nhcDiscoveryService, new Hashtable<>())); - nhcDiscoveryService.activate(); - } - - @Override - protected synchronized void removeHandler(ThingHandler thingHandler) { - if (thingHandler instanceof NikoHomeControlBridgeHandler) { - ServiceRegistration serviceReg = discoveryServiceRegs.remove(thingHandler.getThing().getUID()); - if (serviceReg != null) { - // remove discovery service, if bridge handler is removed - NikoHomeControlDiscoveryService service = (NikoHomeControlDiscoveryService) bundleContext - .getService(serviceReg.getReference()); - serviceReg.unregister(); - if (service != null) { - service.deactivate(); - } - } - } - } - @Reference protected void setNetworkAddressService(NetworkAddressService networkAddressService) { this.networkAddressService = networkAddressService; diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlBridgeDiscoveryService.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlBridgeDiscoveryService.java index f9891ce1010a4..f3d304c9ed10a 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlBridgeDiscoveryService.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlBridgeDiscoveryService.java @@ -40,8 +40,8 @@ * * @author Mark Herwege - Initial Contribution */ -@Component(service = DiscoveryService.class, configurationPid = "discovery.nikohomecontrol") @NonNullByDefault +@Component(service = DiscoveryService.class, configurationPid = "discovery.nikohomecontrol") public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryService { private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeDiscoveryService.class); @@ -50,11 +50,11 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ private @NonNullByDefault({}) NetworkAddressService networkAddressService; - private static final int TIMEOUT = 5; - private static final int REFRESH_INTERVAL = 60; + private static final int TIMOUT_S = 5; + private static final int REFRESH_INTERVAL_S = 60; public NikoHomeControlBridgeDiscoveryService() { - super(NikoHomeControlBindingConstants.BRIDGE_THING_TYPES_UIDS, TIMEOUT); + super(NikoHomeControlBindingConstants.BRIDGE_THING_TYPES_UIDS, TIMOUT_S); logger.debug("bridge discovery service started"); } @@ -70,13 +70,18 @@ private void discoverBridge() { } logger.debug("discovery broadcast on {}", broadcastAddr); NikoHomeControlDiscover nhcDiscover = new NikoHomeControlDiscover(broadcastAddr); - if (nhcDiscover.isNhcII()) { - addNhcIIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId()); - } else { - addNhcIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId()); + for (String nhcController : nhcDiscover.getNhcBridgeIds()) { + InetAddress addr = nhcDiscover.getAddr(nhcController); + if (addr != null) { + if (nhcDiscover.isNhcII(nhcController)) { + addNhcIIBridge(addr, nhcController); + } else { + addNhcIBridge(addr, nhcController); + } + } } } catch (IOException e) { - logger.debug("no bridge found."); + logger.debug("bridge discovery IO exception"); } } @@ -87,7 +92,8 @@ private void addNhcIBridge(InetAddress addr, String bridgeId) { ThingUID uid = new ThingUID(BINDING_ID, "bridge", bridgeId); DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withLabel(bridgeName) - .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).build(); + .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).withRepresentationProperty(CONFIG_HOST_NAME) + .build(); thingDiscovered(discoveryResult); } @@ -98,7 +104,8 @@ private void addNhcIIBridge(InetAddress addr, String bridgeId) { ThingUID uid = new ThingUID(BINDING_ID, "bridge2", bridgeId); DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withLabel(bridgeName) - .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).build(); + .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).withRepresentationProperty(CONFIG_HOST_NAME) + .build(); thingDiscovered(discoveryResult); } @@ -115,10 +122,10 @@ protected synchronized void stopScan() { @Override protected void startBackgroundDiscovery() { - logger.debug("Start background bridge discovery"); + logger.debug("Start bridge background discovery"); ScheduledFuture job = nhcDiscoveryJob; if (job == null || job.isCancelled()) { - nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverBridge, 0, REFRESH_INTERVAL, + nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverBridge, 0, REFRESH_INTERVAL_S, TimeUnit.SECONDS); } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlDiscoveryService.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlDiscoveryService.java index 5b8c4a7c1aaf6..07bc7ba77d27b 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlDiscoveryService.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlDiscoveryService.java @@ -14,8 +14,10 @@ import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*; -import java.util.Date; +import java.time.Instant; import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -27,6 +29,8 @@ import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,43 +41,52 @@ * @author Mark Herwege - Initial Contribution */ @NonNullByDefault -public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService { +public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscoveryService.class); - private static final int TIMEOUT = 5; + private volatile @Nullable ScheduledFuture nhcDiscoveryJob; - private ThingUID bridgeUID; - private NikoHomeControlBridgeHandler handler; + private static final int TIMEOUT_S = 5; + private static final int INITIAL_DELAY_S = 5; // initial delay for polling to allow time for initial request to NHC + // controller to complete + private static final int REFRESH_INTERVAL_S = 60; - public NikoHomeControlDiscoveryService(NikoHomeControlBridgeHandler handler) { - super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT, false); - logger.debug("discovery service {}", handler); - bridgeUID = handler.getThing().getUID(); - this.handler = handler; + private @Nullable ThingUID bridgeUID; + private @Nullable NikoHomeControlBridgeHandler handler; + + public NikoHomeControlDiscoveryService() { + super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT_S, true); + logger.debug("device discovery service started"); } + @Override public void activate() { - handler.setNhcDiscovery(this); + startBackgroundDiscovery(); } @Override public void deactivate() { - removeOlderResults(new Date().getTime()); - handler.setNhcDiscovery(null); + removeOlderResults(Instant.now().toEpochMilli()); + super.deactivate(); } /** * Discovers devices connected to a Niko Home Control controller */ public void discoverDevices() { - NikoHomeControlCommunication nhcComm = handler.getCommunication(); + NikoHomeControlBridgeHandler bridgeHandler = handler; + if (bridgeHandler == null) { + return; + } + + NikoHomeControlCommunication nhcComm = bridgeHandler.getCommunication(); if ((nhcComm == null) || !nhcComm.communicationActive()) { logger.warn("not connected"); return; } - logger.debug("getting devices on {}", handler.getThing().getUID().getId()); + logger.debug("getting devices on {}", bridgeHandler.getThing().getUID().getId()); Map actions = nhcComm.getActions(); @@ -83,20 +96,21 @@ public void discoverDevices() { switch (nhcAction.getType()) { case TRIGGER: - addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, handler.getThing().getUID(), actionId), + addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, bridgeHandler.getThing().getUID(), actionId), actionId, thingName, thingLocation); break; case RELAY: - addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, handler.getThing().getUID(), actionId), + addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, bridgeHandler.getThing().getUID(), actionId), actionId, thingName, thingLocation); break; case DIMMER: - addActionDevice(new ThingUID(THING_TYPE_DIMMABLE_LIGHT, handler.getThing().getUID(), actionId), + addActionDevice( + new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridgeHandler.getThing().getUID(), actionId), actionId, thingName, thingLocation); break; case ROLLERSHUTTER: - addActionDevice(new ThingUID(THING_TYPE_BLIND, handler.getThing().getUID(), actionId), actionId, - thingName, thingLocation); + addActionDevice(new ThingUID(THING_TYPE_BLIND, bridgeHandler.getThing().getUID(), actionId), + actionId, thingName, thingLocation); break; default: logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName); @@ -108,7 +122,7 @@ public void discoverDevices() { thermostats.forEach((thermostatId, nhcThermostat) -> { String thingName = nhcThermostat.getName(); String thingLocation = nhcThermostat.getLocation(); - addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, handler.getThing().getUID(), thermostatId), + addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, bridgeHandler.getThing().getUID(), thermostatId), thermostatId, thingName, thingLocation); }); @@ -116,14 +130,16 @@ public void discoverDevices() { energyMeters.forEach((energyMeterId, nhcEnergyMeter) -> { String thingName = nhcEnergyMeter.getName(); - addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, handler.getThing().getUID(), energyMeterId), - energyMeterId, thingName); + String thingLocation = nhcEnergyMeter.getLocation(); + addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, bridgeHandler.getThing().getUID(), energyMeterId), + energyMeterId, thingName, thingLocation); }); } private void addActionDevice(ThingUID uid, String actionId, String thingName, @Nullable String thingLocation) { DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID) - .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId); + .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId) + .withRepresentationProperty(CONFIG_ACTION_ID); if (thingLocation != null) { discoveryResultBuilder.withProperty("Location", thingLocation); } @@ -133,16 +149,22 @@ private void addActionDevice(ThingUID uid, String actionId, String thingName, @N private void addThermostatDevice(ThingUID uid, String thermostatId, String thingName, @Nullable String thingLocation) { DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID) - .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId); + .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId) + .withRepresentationProperty(CONFIG_THERMOSTAT_ID); if (thingLocation != null) { discoveryResultBuilder.withProperty("Location", thingLocation); } thingDiscovered(discoveryResultBuilder.build()); } - private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName) { + private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName, + @Nullable String thingLocation) { DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID) - .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId); + .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId) + .withRepresentationProperty(CONFIG_ENERGYMETER_ID); + if (thingLocation != null) { + discoveryResultBuilder.withProperty("Location", thingLocation); + } thingDiscovered(discoveryResultBuilder.build()); } @@ -156,4 +178,37 @@ protected synchronized void stopScan() { super.stopScan(); removeOlderResults(getTimestampOfLastScan()); } + + @Override + protected void startBackgroundDiscovery() { + logger.debug("Start device background discovery"); + ScheduledFuture job = nhcDiscoveryJob; + if (job == null || job.isCancelled()) { + nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, INITIAL_DELAY_S, + REFRESH_INTERVAL_S, TimeUnit.SECONDS); + } + } + + @Override + protected void stopBackgroundDiscovery() { + logger.debug("Stop device background discovery"); + ScheduledFuture job = nhcDiscoveryJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); + nhcDiscoveryJob = null; + } + } + + @Override + public void setThingHandler(@Nullable ThingHandler handler) { + if (handler instanceof NikoHomeControlBridgeHandler) { + this.handler = (NikoHomeControlBridgeHandler) handler; + bridgeUID = handler.getThing().getUID(); + } + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return handler; + } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlActionHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlActionHandler.java index d96c172fa5ffc..df5bb9544e2e8 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlActionHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlActionHandler.java @@ -238,7 +238,7 @@ public void initialize() { nhcAction.setEventHandler(this); - updateProperties(); + updateProperties(nhcAction); String actionLocation = nhcAction.getLocation(); if (thing.getLocation() == null) { @@ -260,14 +260,9 @@ public void initialize() { }); } - private void updateProperties() { - NhcAction nhcAction = this.nhcAction; - if (nhcAction == null) { - logger.debug("action with ID {} not initialized", actionId); - return; - } - + private void updateProperties(NhcAction nhcAction) { Map properties = new HashMap<>(); + properties.put("type", String.valueOf(nhcAction.getType())); if (getThing().getThingTypeUID() == THING_TYPE_BLIND) { properties.put("timeToOpen", String.valueOf(nhcAction.getOpenTime())); @@ -276,8 +271,9 @@ private void updateProperties() { if (nhcAction instanceof NhcAction2) { NhcAction2 action = (NhcAction2) nhcAction; - properties.put("model", action.getModel()); - properties.put("technology", action.getTechnology()); + properties.put(PROPERTY_DEVICE_TYPE, action.getDeviceType()); + properties.put(PROPERTY_DEVICE_TECHNOLOGY, action.getDeviceTechnology()); + properties.put(PROPERTY_DEVICE_MODEL, action.getDeviceModel()); } thing.setProperties(properties); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java index f1b688bab0d74..467bedb0923dc 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java @@ -16,8 +16,10 @@ import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Collection; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -32,6 +34,7 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,8 +42,7 @@ /** * {@link NikoHomeControlBridgeHandler} is an abstract class representing a handler to all different interfaces to the * Niko Home Control System. {@link NikoHomeControlBridgeHandler1} or {@link NikoHomeControlBridgeHandler2} should be - * used for the respective - * version of Niko Home Control. + * used for the respective version of Niko Home Control. * * @author Mark Herwege - Initial Contribution */ @@ -49,14 +51,10 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeHandler.class); - protected @NonNullByDefault({}) NikoHomeControlBridgeConfig config; - protected @Nullable NikoHomeControlCommunication nhcComm; private volatile @Nullable ScheduledFuture refreshTimer; - protected volatile @Nullable NikoHomeControlDiscoveryService nhcDiscovery; - public NikoHomeControlBridgeHandler(Bridge nikoHomeControlBridge) { super(nikoHomeControlBridge); } @@ -90,22 +88,15 @@ protected void startCommunication() { updateStatus(ThingStatus.ONLINE); - int refreshInterval = config.refresh; + int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh; setupRefreshTimer(refreshInterval); - - NikoHomeControlDiscoveryService discovery = nhcDiscovery; - if (discovery != null) { - discovery.discoverDevices(); - } else { - logger.debug("cannot discover devices, discovery service not started"); - } }); } /** * Schedule future communication refresh. * - * @param interval_config Time before refresh in minutes. + * @param refreshInterval Time before refresh in minutes. */ private void setupRefreshTimer(int refreshInterval) { ScheduledFuture timer = refreshTimer; @@ -163,7 +154,7 @@ public void controllerOffline(String message) { public void controllerOnline() { bridgeOnline(); - int refreshInterval = config.refresh; + int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh; if (refreshTimer == null) { setupRefreshTimer(refreshInterval); } @@ -199,13 +190,11 @@ public void handleConfigurationUpdate(Map configurationParameter } Configuration configuration = editConfiguration(); - for (Entry configurationParmeter : configurationParameters.entrySet()) { - configuration.put(configurationParmeter.getKey(), configurationParmeter.getValue()); + for (Entry configurationParameter : configurationParameters.entrySet()) { + configuration.put(configurationParameter.getKey(), configurationParameter.getValue()); } updateConfiguration(configuration); - setConfig(); - scheduler.submit(() -> { comm.restartCommunication(); if (!comm.communicationActive()) { @@ -217,20 +206,11 @@ public void handleConfigurationUpdate(Map configurationParameter updateStatus(ThingStatus.ONLINE); - int refreshInterval = config.refresh; + int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh; setupRefreshTimer(refreshInterval); }); } - /** - * Set discovery service handler to be able to start discovery after bridge initialization. - * - * @param nhcDiscovery - */ - public void setNhcDiscovery(@Nullable NikoHomeControlDiscoveryService nhcDiscovery) { - this.nhcDiscovery = nhcDiscovery; - } - @Override public void alarmEvent(String alarmText) { logger.debug("triggering alarm channel with {}", alarmText); @@ -262,6 +242,7 @@ public void updatePropertiesEvent() { @Override public @Nullable InetAddress getAddr() { InetAddress addr = null; + NikoHomeControlBridgeConfig config = getConfig().as(NikoHomeControlBridgeConfig.class); try { addr = InetAddress.getByName(config.addr); } catch (UnknownHostException e) { @@ -272,10 +253,11 @@ public void updatePropertiesEvent() { @Override public int getPort() { - return config.port; + return getConfig().as(NikoHomeControlBridgeConfig.class).port; } - protected synchronized void setConfig() { - config = getConfig().as(NikoHomeControlBridgeConfig.class); + @Override + public Collection> getServices() { + return Set.of(NikoHomeControlDiscoveryService.class); } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java index 004620a3abb71..958681befa1b5 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java @@ -45,7 +45,6 @@ public NikoHomeControlBridgeHandler1(Bridge nikoHomeControlBridge) { public void initialize() { logger.debug("initializing bridge handler"); - setConfig(); InetAddress addr = getAddr(); int port = getPort(); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java index 0b11604a23753..4e86d9b2b7be6 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java @@ -59,8 +59,6 @@ public NikoHomeControlBridgeHandler2(Bridge nikoHomeControlBridge, NetworkAddres public void initialize() { logger.debug("initializing NHC II bridge handler"); - setConfig(); - Date expiryDate = getTokenExpiryDate(); if (expiryDate == null) { if (getToken().isEmpty()) { @@ -161,12 +159,12 @@ protected void updateProperties() { @Override public String getProfile() { - return ((NikoHomeControlBridgeConfig2) config).profile; + return getConfig().as(NikoHomeControlBridgeConfig2.class).profile; } @Override public String getToken() { - String token = ((NikoHomeControlBridgeConfig2) config).password; + String token = getConfig().as(NikoHomeControlBridgeConfig2.class).password; if (token.isEmpty()) { logger.debug("no JWT token set."); } @@ -227,9 +225,4 @@ public String getToken() { return null; } - - @Override - protected synchronized void setConfig() { - config = getConfig().as(NikoHomeControlBridgeConfig2.class); - } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlEnergyMeterHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlEnergyMeterHandler.java index e4a6d79473761..6aee1157f7ccf 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlEnergyMeterHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlEnergyMeterHandler.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.nikohomecontrol.internal.handler; -import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.CHANNEL_POWER; +import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*; import static org.openhab.core.types.RefreshType.REFRESH; import java.util.HashMap; @@ -102,7 +102,12 @@ public void initialize() { nhcEnergyMeter.setEventHandler(this); - updateProperties(); + updateProperties(nhcEnergyMeter); + + String location = nhcEnergyMeter.getLocation(); + if (thing.getLocation() == null) { + thing.setLocation(location); + } // Subscribing to power readings starts an intensive data flow, therefore only do it when there is an item // linked to the channel @@ -132,13 +137,14 @@ public void dispose() { } } - private void updateProperties() { + private void updateProperties(NhcEnergyMeter nhcEnergyMeter) { Map properties = new HashMap<>(); if (nhcEnergyMeter instanceof NhcEnergyMeter2) { NhcEnergyMeter2 energyMeter = (NhcEnergyMeter2) nhcEnergyMeter; - properties.put("model", energyMeter.getModel()); - properties.put("technology", energyMeter.getTechnology()); + properties.put(PROPERTY_DEVICE_TYPE, energyMeter.getDeviceType()); + properties.put(PROPERTY_DEVICE_TECHNOLOGY, energyMeter.getDeviceTechnology()); + properties.put(PROPERTY_DEVICE_MODEL, energyMeter.getDeviceModel()); } thing.setProperties(properties); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java index a8f2b45b8c748..0debc0e7a4c08 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java @@ -181,7 +181,7 @@ public void initialize() { nhcThermostat.setEventHandler(this); - updateProperties(); + updateProperties(nhcThermostat); String thermostatLocation = nhcThermostat.getLocation(); if (thing.getLocation() == null) { @@ -204,13 +204,14 @@ public void initialize() { }); } - private void updateProperties() { + private void updateProperties(NhcThermostat nhcThermostat) { Map properties = new HashMap<>(); if (nhcThermostat instanceof NhcThermostat2) { NhcThermostat2 thermostat = (NhcThermostat2) nhcThermostat; - properties.put("model", thermostat.getModel()); - properties.put("technology", thermostat.getTechnology()); + properties.put(PROPERTY_DEVICE_TYPE, thermostat.getDeviceType()); + properties.put(PROPERTY_DEVICE_TECHNOLOGY, thermostat.getDeviceTechnology()); + properties.put(PROPERTY_DEVICE_MODEL, thermostat.getDeviceModel()); } thing.setProperties(properties); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcAction.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcAction.java index d962131628e51..bda23e28dfb6b 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcAction.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcAction.java @@ -66,9 +66,9 @@ public void setEventHandler(NhcActionEvent eventHandler) { } /** - * Get the id of the action. + * Get id of action. * - * @return the id + * @return id */ public String getId() { return id; @@ -83,6 +83,15 @@ public String getName() { return name; } + /** + * Set name of action. + * + * @param name action name + */ + public void setName(String name) { + this.name = name; + } + /** * Get type of action identified. *

@@ -103,6 +112,15 @@ public ActionType getType() { return location; } + /** + * Set location name of action. + * + * @param location action location name + */ + public void setLocation(@Nullable String location) { + this.location = location; + } + /** * Get state of action. *

diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java index af07cd417c4a8..89cacbf695043 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java @@ -36,14 +36,16 @@ public abstract class NhcEnergyMeter { protected String id; protected String name; + protected @Nullable String location; // This can be null as long as we do not receive power readings protected volatile @Nullable Integer power = null; private @Nullable NhcEnergyMeterEvent eventHandler; - protected NhcEnergyMeter(String id, String name, NikoHomeControlCommunication nhcComm) { + protected NhcEnergyMeter(String id, String name, @Nullable String location, NikoHomeControlCommunication nhcComm) { this.id = id; this.name = name; + this.location = location; this.nhcComm = nhcComm; } @@ -84,23 +86,50 @@ public void setEventHandler(NhcEnergyMeterEvent eventHandler) { } /** - * Get the id of the energyMeters meter. + * Get id of meter. * - * @return the id + * @return id */ public String getId() { return id; } /** - * Get name of the energyMeters meter. + * Get name of meter. * - * @return energyMeters meter name + * @return energyMeter name */ public String getName() { return name; } + /** + * Set name of meter. + * + * @param name meter name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get location name of meter. + * + * @return location energyMeter location + */ + public @Nullable String getLocation() { + return location; + } + + /** + * Set location name of meter. + * + * @param location meter location name + */ + public void setLocation(@Nullable String location) { + this.location = location; + } + /** * @return the power in W (positive for consumption, negative for production), return null if no reading received * yet diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java index 91d1818f0a9f6..6166fc6b42821 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java @@ -142,9 +142,9 @@ public void setEventHandler(NhcThermostatEvent eventHandler) { } /** - * Get the id of the thermostat. + * Get id of the thermostat. * - * @return the id + * @return id */ public String getId() { return id; @@ -160,7 +160,16 @@ public String getName() { } /** - * Get location name of action. + * Set name of thermostat. + * + * @param name thermostat name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get location name of thermostat. * * @return location name */ @@ -168,6 +177,15 @@ public String getName() { return location; } + /** + * Set location name of thermostat. + * + * @param location thermostat location name + */ + public void setLocation(@Nullable String location) { + this.location = location; + } + /** * Get measured temperature. * diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlDiscover.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlDiscover.java index 45d3cdbb07788..1113efe8fb3b6 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlDiscover.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlDiscover.java @@ -16,9 +16,15 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import java.net.SocketTimeoutException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.util.HexUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,13 +49,13 @@ public final class NikoHomeControlDiscover { private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscover.class); - private InetAddress addr; - private String nhcBridgeId = ""; - private boolean isNhcII; + private List nhcBridgeIds = new ArrayList<>(); + private Map addr = new HashMap<>(); + private Map isNhcII = new HashMap<>(); /** - * Discover a Niko Home Control IP interface by broadcasting UDP packet 0x44 to port 10000. The IP interface will - * reply. The address of the IP interface is than derived from that response. + * Discover the list of Niko Home Control IP interfaces by broadcasting UDP packet 0x44 to port 10000. The IP + * interface will reply. The address of the IP interface is than derived from that response. * * @param broadcast Broadcast address of the network * @throws IOException @@ -68,33 +74,37 @@ public NikoHomeControlDiscover(String broadcast) throws IOException { datagramSocket.setBroadcast(true); datagramSocket.setSoTimeout(500); datagramSocket.send(discoveryPacket); - while (true) { - datagramSocket.receive(packet); - logger.trace("bridge discovery response {}", - HexUtils.bytesToHex(Arrays.copyOf(packet.getData(), packet.getLength()))); - if (isNhc(packet)) { - break; + try { + while (true) { + datagramSocket.receive(packet); + logger.trace("bridge discovery response {}", + HexUtils.bytesToHex(Arrays.copyOf(packet.getData(), packet.getLength()))); + if (isNhcController(packet)) { + String bridgeId = setNhcBridgeId(packet); + setIsNhcII(bridgeId, packet); + setAddr(bridgeId, packet); + logger.debug("IP address is {}, unique ID is {}", addr, bridgeId); + } } + } catch (SocketTimeoutException e) { + // all received, continue } - addr = packet.getAddress(); - setNhcBridgeId(packet); - setIsNhcII(packet); - logger.debug("IP address is {}, unique ID is {}", addr, nhcBridgeId); } } /** - * @return the addr + * @return the discovered nhcBridgeIds */ - public InetAddress getAddr() { - return addr; + public List getNhcBridgeIds() { + return nhcBridgeIds; } /** - * @return the nhcBridgeId + * @param bridgeId discovered bridgeId + * @return the addr, null if not in the list of discovered bridgeId's */ - public String getNhcBridgeId() { - return nhcBridgeId; + public @Nullable InetAddress getAddr(String bridgeId) { + return addr.get(bridgeId); } /** @@ -103,9 +113,15 @@ public String getNhcBridgeId() { * @param packet * @return true if packet is from a Niko Home Control controller */ - private boolean isNhc(DatagramPacket packet) { + private boolean isNhcController(DatagramPacket packet) { byte[] packetData = packet.getData(); - return ((packet.getLength() > 2) && (packetData[0] == 0x44)); + boolean isNhc = (packet.getLength() > 2) && (packetData[0] == 0x44); + // filter response from Gen1 touchscreens + boolean isController = isNhc && (packetData[1] == 0x3b) || (packetData[1] == 0x0c) || (packetData[1] == 0x0e); + if (!isController) { + logger.trace("not a NHC controller"); + } + return isController; } /** @@ -113,7 +129,7 @@ private boolean isNhc(DatagramPacket packet) { * * @param packet */ - private void setNhcBridgeId(DatagramPacket packet) { + private String setNhcBridgeId(DatagramPacket packet) { byte[] packetData = packet.getData(); int packetLength = packet.getLength(); packetLength = packetLength > 6 ? 6 : packetLength; @@ -121,31 +137,45 @@ private void setNhcBridgeId(DatagramPacket packet) { for (int i = 0; i < packetLength; i++) { sb.append(String.format("%02x", packetData[i])); } - nhcBridgeId = sb.toString(); + String bridgeId = sb.toString(); + nhcBridgeIds.add(bridgeId); + return bridgeId; } /** * Checks if this is a NHC II Connected Controller * + * @param bridgeId * @param packet */ - private void setIsNhcII(DatagramPacket packet) { + private void setIsNhcII(String bridgeId, DatagramPacket packet) { byte[] packetData = packet.getData(); int packetLength = packet.getLength(); // The 16th byte in the packet is 2 for a NHC II Connected Controller if ((packetLength >= 16) && (packetData[15] >= 2)) { - isNhcII = true; + isNhcII.put(bridgeId, true); } else { - isNhcII = false; + isNhcII.put(bridgeId, false); } } + /** + * Sets the IP address retrieved from the packet response + * + * @param bridgeId + * @param packet + */ + private void setAddr(String bridgeId, DatagramPacket packet) { + addr.put(bridgeId, packet.getAddress()); + } + /** * Test if the installation is a Niko Home Control II installation * + * @param bridgeId * @return true if this is a Niko Home Control II installation */ - public boolean isNhcII() { - return isNhcII; + public boolean isNhcII(String bridgeId) { + return isNhcII.getOrDefault(bridgeId, false); } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc1/NikoHomeControlCommunication1.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc1/NikoHomeControlCommunication1.java index f37a04da05593..d66b64a9141c2 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc1/NikoHomeControlCommunication1.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc1/NikoHomeControlCommunication1.java @@ -364,38 +364,38 @@ private void cmdListActions(List> data) { String value3 = action.get("value3"); int openTime = ((value3 == null) || value3.isEmpty() ? 0 : Integer.parseInt(value3)); + String name = action.get("name"); + if (name == null) { + logger.debug("name not found in action {}", action); + continue; + } + String type = Optional.ofNullable(action.get("type")).orElse(""); + ActionType actionType = ActionType.GENERIC; + switch (type) { + case "0": + actionType = ActionType.TRIGGER; + break; + case "1": + actionType = ActionType.RELAY; + break; + case "2": + actionType = ActionType.DIMMER; + break; + case "4": + case "5": + actionType = ActionType.ROLLERSHUTTER; + break; + default: + logger.debug("unknown action type {} for action {}", type, id); + continue; + } + String locationId = action.get("location"); + String location = ""; + if (locationId != null && !locationId.isEmpty()) { + location = locations.getOrDefault(locationId, new NhcLocation1("")).getName(); + } if (!actions.containsKey(id)) { // Initial instantiation of NhcAction class for action object - String name = action.get("name"); - if (name == null) { - logger.debug("name not found in action {}", action); - continue; - } - String type = Optional.ofNullable(action.get("type")).orElse(""); - ActionType actionType = ActionType.GENERIC; - switch (type) { - case "0": - actionType = ActionType.TRIGGER; - break; - case "1": - actionType = ActionType.RELAY; - break; - case "2": - actionType = ActionType.DIMMER; - break; - case "4": - case "5": - actionType = ActionType.ROLLERSHUTTER; - break; - default: - logger.debug("unknown action type {} for action {}", type, id); - continue; - } - String locationId = action.get("location"); - String location = ""; - if (locationId != null && !locationId.isEmpty()) { - location = locations.getOrDefault(locationId, new NhcLocation1("")).getName(); - } NhcAction nhcAction = new NhcAction1(id, name, actionType, location, this, scheduler); if (actionType == ActionType.ROLLERSHUTTER) { nhcAction.setShutterTimes(openTime, closeTime); @@ -403,11 +403,13 @@ private void cmdListActions(List> data) { nhcAction.setState(state); actions.put(id, nhcAction); } else { - // Action object already exists, so only update state. + // Action object already exists, so only update state, name and location. // If we would re-instantiate action, we would lose pointer back from action to thing handler that was // set in thing handler initialize(). NhcAction nhcAction = actions.get(id); if (nhcAction != null) { + nhcAction.setName(name); + nhcAction.setLocation(location); nhcAction.setState(state); } } @@ -452,23 +454,25 @@ private void cmdListThermostat(List> data) { // measured int demand = (mode != 3) ? (setpoint > measured ? 1 : (setpoint < measured ? -1 : 0)) : 0; + String name = thermostat.get("name"); + String locationId = thermostat.get("location"); + NhcLocation1 nhcLocation = null; + if (!((locationId == null) || locationId.isEmpty())) { + nhcLocation = locations.get(locationId); + } + String location = (nhcLocation != null) ? nhcLocation.getName() : null; NhcThermostat t = thermostats.computeIfAbsent(id, i -> { // Initial instantiation of NhcThermostat class for thermostat object - String name = thermostat.get("name"); - String locationId = thermostat.get("location"); - String location = ""; - if (!((locationId == null) || locationId.isEmpty())) { - NhcLocation1 nhcLocation = locations.get(locationId); - if (nhcLocation != null) { - location = nhcLocation.getName(); - } - } if (name != null) { return new NhcThermostat1(i, name, location, this); } throw new IllegalArgumentException(); }); if (t != null) { + if (name != null) { + t.setName(name); + } + t.setLocation(location); t.updateState(measured, setpoint, mode, overrule, overruletime, ecosave, demand); } } catch (IllegalArgumentException e) { diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java index 875b2885c9bf3..f0478fcb0a6c7 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java @@ -35,14 +35,16 @@ public class NhcAction2 extends NhcAction { private final Logger logger = LoggerFactory.getLogger(NhcAction2.class); private volatile boolean booleanState; - private String model; - private String technology; + private String deviceType; + private String deviceTechnology; + private String deviceModel; - NhcAction2(String id, String name, String model, String technology, ActionType type, @Nullable String location, - NikoHomeControlCommunication nhcComm) { + NhcAction2(String id, String name, String deviceType, String deviceTechnology, String deviceModel, + @Nullable String location, ActionType type, NikoHomeControlCommunication nhcComm) { super(id, name, type, location, nhcComm); - this.model = model; - this.technology = technology; + this.deviceType = deviceType; + this.deviceTechnology = deviceTechnology; + this.deviceModel = deviceModel; } /** @@ -120,7 +122,7 @@ public void execute(String command) { logger.debug("execute action {} of type {} for {}", command, type, id); String cmd; - if ("flag".equals(model)) { + if ("flag".equals(deviceModel)) { cmd = NHCON.equals(command) ? NHCTRUE : NHCFALSE; } else { cmd = command; @@ -130,16 +132,23 @@ public void execute(String command) { } /** - * @return model as returned from Niko Home Control + * @return type as returned from Niko Home Control */ - public String getModel() { - return model; + public String getDeviceType() { + return deviceType; } /** * @return technology as returned from Niko Home Control */ - public String getTechnology() { - return technology; + public String getDeviceTechnology() { + return deviceTechnology; + } + + /** + * @return model as returned from Niko Home Control + */ + public String getDeviceModel() { + return deviceModel; } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcDevice2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcDevice2.java index fc6a2948e78f0..c708b56c086fc 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcDevice2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcDevice2.java @@ -76,6 +76,18 @@ static class NhcProperty { @Nullable String electricalPower; @Nullable + String electricalPowerToGrid; + @Nullable + String electricalPowerFromGrid; + @Nullable + String electricalPowerProduction; + @Nullable + String electricalPowerSelfConsumption; + @Nullable + String electricalPowerConsumption; + @Nullable + String electricalPowerProductionThresholdExceeded; + @Nullable String reportInstantUsage; // fields for access control @Nullable diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcEnergyMeter2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcEnergyMeter2.java index 9c8d194d1d8fa..2c9401373a88d 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcEnergyMeter2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcEnergyMeter2.java @@ -34,14 +34,16 @@ public class NhcEnergyMeter2 extends NhcEnergyMeter { private ScheduledExecutorService scheduler; private volatile @Nullable ScheduledFuture restartTimer; - private String model; - private String technology; + private String deviceType; + private String deviceTechnology; + private String deviceModel; - protected NhcEnergyMeter2(String id, String name, String model, String technology, - NikoHomeControlCommunication nhcComm, ScheduledExecutorService scheduler) { - super(id, name, nhcComm); - this.model = model; - this.technology = technology; + protected NhcEnergyMeter2(String id, String name, String deviceType, String deviceTechnology, String deviceModel, + @Nullable String location, NikoHomeControlCommunication nhcComm, ScheduledExecutorService scheduler) { + super(id, name, location, nhcComm); + this.deviceType = deviceType; + this.deviceTechnology = deviceTechnology; + this.deviceModel = deviceModel; this.scheduler = scheduler; } @@ -75,16 +77,23 @@ public void stopEnergyMeter() { } /** - * @return model as returned from Niko Home Control + * @return type as returned from Niko Home Control */ - public String getModel() { - return model; + public String getDeviceType() { + return deviceType; } /** * @return technology as returned from Niko Home Control */ - public String getTechnology() { - return technology; + public String getDeviceTechnology() { + return deviceTechnology; + } + + /** + * @return model as returned from Niko Home Control + */ + public String getDeviceModel() { + return deviceModel; } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcThermostat2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcThermostat2.java index 54a9fb013869b..40da2d9169438 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcThermostat2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcThermostat2.java @@ -33,14 +33,16 @@ public class NhcThermostat2 extends NhcThermostat { private final Logger logger = LoggerFactory.getLogger(NhcThermostat2.class); - private String model; - private String technology; + private String deviceType; + private String deviceTechnology; + private String deviceModel; - protected NhcThermostat2(String id, String name, String model, String technology, @Nullable String location, - NikoHomeControlCommunication nhcComm) { + protected NhcThermostat2(String id, String name, String deviceType, String deviceTechnology, String deviceModel, + @Nullable String location, NikoHomeControlCommunication nhcComm) { super(id, name, location, nhcComm); - this.model = model; - this.technology = technology; + this.deviceType = deviceType; + this.deviceTechnology = deviceTechnology; + this.deviceModel = deviceModel; } @Override @@ -59,16 +61,23 @@ public void executeOverrule(int overrule, int overruletime) { } /** - * @return model as returned from Niko Home Control + * @return type as returned from Niko Home Control */ - public String getModel() { - return model; + public String getDeviceType() { + return deviceType; } /** * @return technology as returned from Niko Home Control */ - public String getTechnology() { - return technology; + public String getDeviceTechnology() { + return deviceTechnology; + } + + /** + * @return model as returned from Niko Home Control + */ + public String getDeviceModel() { + return deviceModel; } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java index 13693be37fb83..d46af6f57a7b9 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java @@ -364,63 +364,77 @@ private void addDevice(NhcDevice2 device) { } if ("action".equals(device.type) || "virtual".equals(device.type)) { - if (!actions.containsKey(device.uuid)) { - logger.debug("adding action device {}, {}", device.uuid, device.name); - - ActionType actionType; - switch (device.model) { - case "generic": - case "pir": - case "simulation": - case "comfort": - case "alarms": - case "alloff": - case "overallcomfort": - case "garagedoor": - actionType = ActionType.TRIGGER; - break; - case "light": - case "socket": - case "switched-generic": - case "switched-fan": - case "flag": - actionType = ActionType.RELAY; - break; - case "dimmer": - actionType = ActionType.DIMMER; - break; - case "rolldownshutter": - case "sunblind": - case "venetianblind": - case "gate": - actionType = ActionType.ROLLERSHUTTER; - break; - default: - actionType = ActionType.GENERIC; - logger.debug("device model {} not recognised, default to GENERIC action", device.model); - } + ActionType actionType; + switch (device.model) { + case "generic": + case "pir": + case "simulation": + case "comfort": + case "alarms": + case "alloff": + case "overallcomfort": + case "garagedoor": + actionType = ActionType.TRIGGER; + break; + case "light": + case "socket": + case "switched-generic": + case "switched-fan": + case "flag": + actionType = ActionType.RELAY; + break; + case "dimmer": + actionType = ActionType.DIMMER; + break; + case "rolldownshutter": + case "sunblind": + case "venetianblind": + case "gate": + actionType = ActionType.ROLLERSHUTTER; + break; + default: + actionType = ActionType.GENERIC; + logger.debug("device type {} and model {} not recognised for {}, {}, ignoring", device.type, + device.model, device.uuid, device.name); + return; + } - NhcAction2 nhcAction = new NhcAction2(device.uuid, device.name, device.model, device.technology, - actionType, location, this); - actions.put(device.uuid, nhcAction); + NhcAction nhcAction = actions.get(device.uuid); + if (nhcAction != null) { + // update name and location so discovery will see updated name and location + nhcAction.setName(device.name); + nhcAction.setLocation(location); + } else { + logger.debug("adding action device {} model {}, {}", device.uuid, device.model, device.name); + nhcAction = new NhcAction2(device.uuid, device.name, device.type, device.technology, device.model, + location, actionType, this); } + actions.put(device.uuid, nhcAction); } else if ("thermostat".equals(device.type)) { - if (!thermostats.containsKey(device.uuid)) { - logger.debug("adding thermostat device {}, {}", device.uuid, device.name); - - NhcThermostat2 nhcThermostat = new NhcThermostat2(device.uuid, device.name, device.model, - device.technology, location, this); - thermostats.put(device.uuid, nhcThermostat); + NhcThermostat nhcThermostat = thermostats.get(device.uuid); + if (nhcThermostat != null) { + nhcThermostat.setName(device.name); + nhcThermostat.setLocation(location); + } else { + logger.debug("adding thermostat device {} model {}, {}", device.uuid, device.model, device.name); + nhcThermostat = new NhcThermostat2(device.uuid, device.name, device.type, device.technology, + device.model, location, this); } - } else if ("centralmeter".equals(device.type)) { - if (!energyMeters.containsKey(device.uuid)) { - logger.debug("adding centralmeter device {}, {}", device.uuid, device.name); - NhcEnergyMeter2 nhcEnergyMeter = new NhcEnergyMeter2(device.uuid, device.name, device.model, - device.technology, this, scheduler); - energyMeters.put(device.uuid, nhcEnergyMeter); + thermostats.put(device.uuid, nhcThermostat); + } else if ("centralmeter".equals(device.type) || "energyhome".equals(device.type)) { + NhcEnergyMeter nhcEnergyMeter = energyMeters.get(device.uuid); + if (nhcEnergyMeter != null) { + nhcEnergyMeter.setName(device.name); + nhcEnergyMeter.setLocation(location); + } else { + logger.debug("adding energy meter device {} model {}, {}", device.uuid, device.model, device.name); + nhcEnergyMeter = new NhcEnergyMeter2(device.uuid, device.name, device.type, device.technology, + device.model, location, this, scheduler); } + energyMeters.put(device.uuid, nhcEnergyMeter); } else { - logger.debug("device type {} not supported for {}, {}", device.type, device.uuid, device.name); + logger.debug("device type {} and model {} not supported for {}, {}", device.type, device.model, device.uuid, + device.name); } } @@ -580,18 +594,23 @@ private void updateThermostatState(NhcThermostat2 thermostat, List } private void updateEnergyMeterState(NhcEnergyMeter2 energyMeter, List deviceProperties) { - deviceProperties.stream().map(p -> p.electricalPower).filter(Objects::nonNull).findFirst() - .ifPresent(electricalPower -> { - try { - // Sometimes API sends a fractional part, although API should only send whole units in W, - // therefore drop fractional part - energyMeter.setPower((int) Double.parseDouble(electricalPower)); - logger.trace("setting energy meter {} power to {}", energyMeter.getId(), electricalPower); - } catch (NumberFormatException e) { - energyMeter.setPower(null); - logger.trace("received empty energy meter {} power reading", energyMeter.getId()); - } - }); + try { + Optional electricalPower = deviceProperties.stream().map(p -> p.electricalPower) + .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null) + .filter(Objects::nonNull).findFirst(); + Optional powerFromGrid = deviceProperties.stream().map(p -> p.electricalPowerFromGrid) + .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null) + .filter(Objects::nonNull).findFirst(); + Optional powerToGrid = deviceProperties.stream().map(p -> p.electricalPowerToGrid) + .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null) + .filter(Objects::nonNull).findFirst(); + int power = electricalPower.orElse(powerFromGrid.orElse(0) - powerToGrid.orElse(0)); + logger.trace("setting energy meter {} power to {}", energyMeter.getId(), electricalPower); + energyMeter.setPower(power); + } catch (NumberFormatException e) { + energyMeter.setPower(null); + logger.trace("received empty energy meter {} power reading", energyMeter.getId()); + } } @Override @@ -876,7 +895,7 @@ public String getServices() { @Override public void connectionStateChanged(MqttConnectionState state, @Nullable Throwable error) { if (error != null) { - logger.debug("Connection state: {}", state, error); + logger.debug("Connection state: {}, error", state, error); String message = error.getLocalizedMessage(); message = (message != null) ? message : "@text/offline.communication-error"; if (!MqttConnectionState.CONNECTING.equals(state)) {