[nikohomecontrol] Discovery improvements (#12855)

* Add discovery representation properties
* Recognized device types improvements
* Move discovery to thingHandlerService
* Discover multiple bridges in network
* Made device property names constants

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
This commit is contained in:
Mark Herwege 2022-06-03 20:08:08 +02:00 committed by GitHub
parent 43e44ea39a
commit 651fa295e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 486 additions and 322 deletions

View File

@ -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";
}

View File

@ -14,29 +14,20 @@ package org.openhab.binding.nikohomecontrol.internal;
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 @@ import org.osgi.service.component.annotations.Reference;
* @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<ThingUID, ServiceRegistration<?>> 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 class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory {
@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 class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory {
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;

View File

@ -40,8 +40,8 @@ import org.slf4j.LoggerFactory;
*
* @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 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
}
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 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
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 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
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 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
@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);
}
}

View File

@ -14,8 +14,10 @@ package org.openhab.binding.nikohomecontrol.internal.discovery;
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.binding.nikohomecontrol.internal.protocol.NikoHomeControlComm
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 @@ import org.slf4j.LoggerFactory;
* @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<String, NhcAction> actions = nhcComm.getActions();
@ -83,20 +96,21 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
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 class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
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 class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
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 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
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 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
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;
}
}

View File

@ -238,7 +238,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
nhcAction.setEventHandler(this);
updateProperties();
updateProperties(nhcAction);
String actionLocation = nhcAction.getLocation();
if (thing.getLocation() == null) {
@ -260,14 +260,9 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
});
}
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<String, String> 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 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
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);

View File

@ -16,8 +16,10 @@ import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindin
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.ChannelUID;
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 @@ import org.slf4j.LoggerFactory;
/**
* {@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 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
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 abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
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 abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
}
Configuration configuration = editConfiguration();
for (Entry<String, Object> configurationParmeter : configurationParameters.entrySet()) {
configuration.put(configurationParmeter.getKey(), configurationParmeter.getValue());
for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
}
updateConfiguration(configuration);
setConfig();
scheduler.submit(() -> {
comm.restartCommunication();
if (!comm.communicationActive()) {
@ -217,20 +206,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
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 abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
@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 abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
@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<Class<? extends ThingHandlerService>> getServices() {
return Set.of(NikoHomeControlDiscoveryService.class);
}
}

View File

@ -45,7 +45,6 @@ public class NikoHomeControlBridgeHandler1 extends NikoHomeControlBridgeHandler
public void initialize() {
logger.debug("initializing bridge handler");
setConfig();
InetAddress addr = getAddr();
int port = getPort();

View File

@ -59,8 +59,6 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
public void initialize() {
logger.debug("initializing NHC II bridge handler");
setConfig();
Date expiryDate = getTokenExpiryDate();
if (expiryDate == null) {
if (getToken().isEmpty()) {
@ -161,12 +159,12 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
@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 class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
return null;
}
@Override
protected synchronized void setConfig() {
config = getConfig().as(NikoHomeControlBridgeConfig2.class);
}
}

View File

@ -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 class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
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 class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
}
}
private void updateProperties() {
private void updateProperties(NhcEnergyMeter nhcEnergyMeter) {
Map<String, String> 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);

View File

@ -181,7 +181,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
nhcThermostat.setEventHandler(this);
updateProperties();
updateProperties(nhcThermostat);
String thermostatLocation = nhcThermostat.getLocation();
if (thing.getLocation() == null) {
@ -204,13 +204,14 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
});
}
private void updateProperties() {
private void updateProperties(NhcThermostat nhcThermostat) {
Map<String, String> 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);

View File

@ -66,9 +66,9 @@ public abstract class NhcAction {
}
/**
* 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 abstract class NhcAction {
return name;
}
/**
* Set name of action.
*
* @param name action name
*/
public void setName(String name) {
this.name = name;
}
/**
* Get type of action identified.
* <p>
@ -103,6 +112,15 @@ public abstract class NhcAction {
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.
* <p>

View File

@ -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 abstract class NhcEnergyMeter {
}
/**
* 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

View File

@ -142,9 +142,9 @@ public abstract class NhcThermostat {
}
/**
* 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 abstract class NhcThermostat {
}
/**
* 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 abstract class NhcThermostat {
return location;
}
/**
* Set location name of thermostat.
*
* @param location thermostat location name
*/
public void setLocation(@Nullable String location) {
this.location = location;
}
/**
* Get measured temperature.
*

View File

@ -16,9 +16,15 @@ import java.io.IOException;
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<String> nhcBridgeIds = new ArrayList<>();
private Map<String, InetAddress> addr = new HashMap<>();
private Map<String, Boolean> 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 final class NikoHomeControlDiscover {
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<String> 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 final class NikoHomeControlDiscover {
* @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 @@ public final class NikoHomeControlDiscover {
*
* @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 @@ public final class NikoHomeControlDiscover {
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);
}
}

View File

@ -364,38 +364,38 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
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 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
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 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
// 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) {

View File

@ -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 class NhcAction2 extends NhcAction {
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 class NhcAction2 extends NhcAction {
}
/**
* @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;
}
}

View File

@ -76,6 +76,18 @@ class NhcDevice2 {
@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

View File

@ -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 class NhcEnergyMeter2 extends NhcEnergyMeter {
}
/**
* @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;
}
}

View File

@ -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 class NhcThermostat2 extends NhcThermostat {
}
/**
* @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;
}
}

View File

@ -364,63 +364,77 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
}
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);
}
NhcAction2 nhcAction = new NhcAction2(device.uuid, device.name, device.model, device.technology,
actionType, location, this);
actions.put(device.uuid, nhcAction);
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;
}
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 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
}
private void updateEnergyMeterState(NhcEnergyMeter2 energyMeter, List<NhcProperty> 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<Integer> electricalPower = deviceProperties.stream().map(p -> p.electricalPower)
.map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null)
.filter(Objects::nonNull).findFirst();
Optional<Integer> powerFromGrid = deviceProperties.stream().map(p -> p.electricalPowerFromGrid)
.map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null)
.filter(Objects::nonNull).findFirst();
Optional<Integer> 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 class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
@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)) {