mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[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:
parent
43e44ea39a
commit
651fa295e7
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ public class NikoHomeControlBridgeHandler1 extends NikoHomeControlBridgeHandler
|
||||
public void initialize() {
|
||||
logger.debug("initializing bridge handler");
|
||||
|
||||
setConfig();
|
||||
InetAddress addr = getAddr();
|
||||
int port = getPort();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user