[nikohomecontrol] Add shutter invert and fix connection with NHC does not recover (#10281)

* Ignore devices.changed event.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Null warnings cleanup.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Remove @NonNullByDefault({})

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Shorten logger messages.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Introduce rollershutter invert flag.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Add null annotations.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Connection resilience improvements and log level cleanup.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>

* Update bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml

Signed-off-by: Fabian Wolter <github@fabian-wolter.de>

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
This commit is contained in:
Mark Herwege 2021-03-13 20:44:36 +01:00 committed by GitHub
parent affc082fb5
commit 286bced20e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 456 additions and 262 deletions

View File

@ -55,7 +55,7 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
public NikoHomeControlBridgeDiscoveryService() {
super(NikoHomeControlBindingConstants.BRIDGE_THING_TYPES_UIDS, TIMEOUT);
logger.debug("Niko Home Control: bridge discovery service started");
logger.debug("bridge discovery service started");
}
/**
@ -65,10 +65,10 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
try {
String broadcastAddr = networkAddressService.getConfiguredBroadcastAddress();
if (broadcastAddr == null) {
logger.warn("Niko Home Control: discovery not possible, no broadcast address found");
logger.warn("discovery not possible, no broadcast address found");
return;
}
logger.debug("Niko Home Control: discovery broadcast on {}", broadcastAddr);
logger.debug("discovery broadcast on {}", broadcastAddr);
NikoHomeControlDiscover nhcDiscover = new NikoHomeControlDiscover(broadcastAddr);
if (nhcDiscover.isNhcII()) {
addNhcIIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId());
@ -76,12 +76,12 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
addNhcIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId());
}
} catch (IOException e) {
logger.debug("Niko Home Control: no bridge found.");
logger.debug("no bridge found.");
}
}
private void addNhcIBridge(InetAddress addr, String bridgeId) {
logger.debug("Niko Home Control: NHC I bridge found at {}", addr);
logger.debug("NHC I bridge found at {}", addr);
String bridgeName = "Niko Home Control Bridge";
ThingUID uid = new ThingUID(BINDING_ID, "bridge", bridgeId);
@ -92,7 +92,7 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
}
private void addNhcIIBridge(InetAddress addr, String bridgeId) {
logger.debug("Niko Home Control: NHC II bridge found at {}", addr);
logger.debug("NHC II bridge found at {}", addr);
String bridgeName = "Niko Home Control II Bridge";
ThingUID uid = new ThingUID(BINDING_ID, "bridge2", bridgeId);
@ -115,7 +115,7 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
@Override
protected void startBackgroundDiscovery() {
logger.debug("Niko Home Control: Start background bridge discovery");
logger.debug("Start background bridge discovery");
ScheduledFuture<?> job = nhcDiscoveryJob;
if (job == null || job.isCancelled()) {
nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverBridge, 0, REFRESH_INTERVAL,
@ -125,7 +125,7 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
@Override
protected void stopBackgroundDiscovery() {
logger.debug("Niko Home Control: Stop bridge background discovery");
logger.debug("Stop bridge background discovery");
ScheduledFuture<?> job = nhcDiscoveryJob;
if (job != null && !job.isCancelled()) {
job.cancel(true);

View File

@ -48,7 +48,7 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
public NikoHomeControlDiscoveryService(NikoHomeControlBridgeHandler handler) {
super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT, false);
logger.debug("Niko Home Control: discovery service {}", handler);
logger.debug("discovery service {}", handler);
bridgeUID = handler.getThing().getUID();
this.handler = handler;
}
@ -70,10 +70,10 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
NikoHomeControlCommunication nhcComm = handler.getCommunication();
if ((nhcComm == null) || !nhcComm.communicationActive()) {
logger.warn("Niko Home Control: not connected.");
logger.warn("not connected");
return;
}
logger.debug("Niko Home Control: getting devices on {}", handler.getThing().getUID().getId());
logger.debug("getting devices on {}", handler.getThing().getUID().getId());
Map<String, NhcAction> actions = nhcComm.getActions();
@ -99,8 +99,7 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
thingName, thingLocation);
break;
default:
logger.debug("Niko Home Control: unrecognized action type {} for {} {}", nhcAction.getType(),
actionId, thingName);
logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName);
}
});

View File

@ -14,17 +14,20 @@ package org.openhab.binding.nikohomecontrol.internal.handler;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NhcJwtToken2} represents the Niko Home Control II hobby API token payload.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
class NhcJwtToken2 {
String sub;
String iat;
String exp;
String aud;
String iss;
String jti;
List<String> role;
String sub = "";
String iat = "";
String exp = "";
String aud = "";
String iss = "";
String jti = "";
List<String> role = List.of();
}

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlActionBlindConfig} is the config class for Niko Home Control Blind Actions.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlActionBlindConfig extends NikoHomeControlActionConfig {
public boolean invert;
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlActionConfig} is the general config class for Niko Home Control Actions.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlActionConfig {
public String actionId;
public String actionId = "";
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlActionDimmerConfig} is the config class for Niko Home Control Dimmer Actions.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlActionDimmerConfig extends NikoHomeControlActionConfig {
public int step;
public int step = 10;
}

View File

@ -52,10 +52,11 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
private final Logger logger = LoggerFactory.getLogger(NikoHomeControlActionHandler.class);
private volatile @NonNullByDefault({}) NhcAction nhcAction;
private volatile @Nullable NhcAction nhcAction;
private String actionId = "";
private int stepValue;
private boolean invert;
public NikoHomeControlActionHandler(Thing thing) {
super(thing);
@ -66,8 +67,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: bridge communication not initialized when trying to execute action command "
+ actionId);
"Bridge communication not initialized when trying to execute action command " + actionId);
return;
}
@ -84,7 +84,13 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
}
private void handleCommandSelection(ChannelUID channelUID, Command command) {
logger.debug("Niko Home Control: handle command {} for {}", command, channelUID);
NhcAction nhcAction = this.nhcAction;
if (nhcAction == null) {
logger.debug("action with ID {} not initialized", actionId);
return;
}
logger.debug("handle command {} for {}", command, channelUID);
if (command == REFRESH) {
actionEvent(nhcAction.getState());
@ -109,11 +115,17 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: channel unknown " + channelUID.getId());
"Channel unknown " + channelUID.getId());
}
}
private void handleSwitchCommand(Command command) {
NhcAction nhcAction = this.nhcAction;
if (nhcAction == null) {
logger.debug("action with ID {} not initialized", actionId);
return;
}
if (command instanceof OnOffType) {
OnOffType s = (OnOffType) command;
if (OnOffType.OFF.equals(s)) {
@ -125,6 +137,12 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
}
private void handleBrightnessCommand(Command command) {
NhcAction nhcAction = this.nhcAction;
if (nhcAction == null) {
logger.debug("action with ID {} not initialized", actionId);
return;
}
if (command instanceof OnOffType) {
OnOffType s = (OnOffType) command;
if (OnOffType.OFF.equals(s)) {
@ -162,18 +180,24 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
}
private void handleRollershutterCommand(Command command) {
NhcAction nhcAction = this.nhcAction;
if (nhcAction == null) {
logger.debug("action with ID {} not initialized", actionId);
return;
}
if (command instanceof UpDownType) {
UpDownType s = (UpDownType) command;
if (UpDownType.UP.equals(s)) {
nhcAction.execute(NHCUP);
nhcAction.execute(!invert ? NHCUP : NHCDOWN);
} else {
nhcAction.execute(NHCDOWN);
nhcAction.execute(!invert ? NHCDOWN : NHCUP);
}
} else if (command instanceof StopMoveType) {
nhcAction.execute(NHCSTOP);
} else if (command instanceof PercentType) {
PercentType p = (PercentType) command;
nhcAction.execute(Integer.toString(100 - p.intValue()));
nhcAction.execute(!invert ? Integer.toString(100 - p.intValue()) : Integer.toString(p.intValue()));
}
}
@ -183,6 +207,9 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
if (thing.getThingTypeUID().equals(THING_TYPE_DIMMABLE_LIGHT)) {
config = getConfig().as(NikoHomeControlActionDimmerConfig.class);
stepValue = ((NikoHomeControlActionDimmerConfig) config).step;
} else if (thing.getThingTypeUID().equals(THING_TYPE_BLIND)) {
config = getConfig().as(NikoHomeControlActionBlindConfig.class);
invert = ((NikoHomeControlActionBlindConfig) config).invert;
} else {
config = getConfig().as(NikoHomeControlActionConfig.class);
}
@ -190,6 +217,8 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Connection with controller not started yet, could not initialize action " + actionId);
return;
}
@ -197,15 +226,14 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
scheduler.submit(() -> {
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: no connection with Niko Home Control, could not initialize action "
+ actionId);
"No connection with controller, could not initialize action " + actionId);
return;
}
nhcAction = nhcComm.getActions().get(actionId);
NhcAction nhcAction = nhcComm.getActions().get(actionId);
if (nhcAction == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: actionId does not match an action in the controller " + actionId);
"Action " + actionId + " does not match an action in the controller");
return;
}
@ -220,7 +248,9 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
actionEvent(nhcAction.getState());
logger.debug("Niko Home Control: action initialized {}", actionId);
this.nhcAction = nhcAction;
logger.debug("action initialized {}", actionId);
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
@ -232,6 +262,12 @@ 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;
}
Map<String, String> properties = new HashMap<>();
properties.put("type", String.valueOf(nhcAction.getType()));
if (getThing().getThingTypeUID() == THING_TYPE_BLIND) {
@ -250,6 +286,12 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
@Override
public void actionEvent(int actionState) {
NhcAction nhcAction = this.nhcAction;
if (nhcAction == null) {
logger.debug("action with ID {} not initialized", actionId);
return;
}
ActionType actionType = nhcAction.getType();
switch (actionType) {
@ -265,19 +307,28 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
updateStatus(ThingStatus.ONLINE);
break;
case ROLLERSHUTTER:
updateState(CHANNEL_ROLLERSHUTTER, new PercentType(actionState));
updateState(CHANNEL_ROLLERSHUTTER,
!invert ? new PercentType(100 - actionState) : new PercentType(actionState));
updateStatus(ThingStatus.ONLINE);
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: unknown action type " + actionType);
"Unknown action type " + actionType);
}
}
@Override
public void actionInitialized() {
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
updateStatus(ThingStatus.ONLINE);
}
}
@Override
public void actionRemoved() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: action has been removed from the controller " + actionId);
"Action " + actionId + " has been removed from the controller");
}
private void restartCommunication(NikoHomeControlCommunication nhcComm) {
@ -286,8 +337,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
nhcComm.restartCommunication();
// If still not active, take thing offline and return.
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: communication socket error");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Communication error");
return;
}
// Also put the bridge back online
@ -301,7 +351,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
NikoHomeControlBridgeHandler nhcBridgeHandler = getBridgeHandler();
if (nhcBridgeHandler == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for action " + actionId);
"No bridge initialized for action " + actionId);
return null;
}
NikoHomeControlCommunication nhcComm = nhcBridgeHandler.getCommunication();
@ -312,7 +362,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
Bridge nhcBridge = getBridge();
if (nhcBridge == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for action " + actionId);
"No bridge initialized for action " + actionId);
return null;
}
NikoHomeControlBridgeHandler nhcBridgeHandler = (NikoHomeControlBridgeHandler) nhcBridge.getHandler();

View File

@ -12,13 +12,16 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlBridgeConfig} is the general config class for Niko Home Control Bridges.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlBridgeConfig {
public String addr;
public String addr = "";
public int port;
public int refresh;
}

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlBridgeConfig2} is the extended config class for Niko Home Control II Bridges.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlBridgeConfig2 extends NikoHomeControlBridgeConfig {
public String profile;
public String password;
public String profile = "";
public String password = "";
}

View File

@ -95,7 +95,7 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
if (discovery != null) {
discovery.discoverDevices();
} else {
logger.debug("Niko Home Control: cannot discover devices, discovery service not started");
logger.debug("cannot discover devices, discovery service not started");
}
});
}
@ -117,9 +117,9 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
}
// This timer will restart the bridge connection periodically
logger.debug("Niko Home Control: restart bridge connection every {} min", refreshInterval);
logger.debug("restart bridge connection every {} min", refreshInterval);
refreshTimer = scheduler.scheduleWithFixedDelay(() -> {
logger.debug("Niko Home Control: restart communication at scheduled time");
logger.debug("restart communication at scheduled time");
NikoHomeControlCommunication comm = nhcComm;
if (comm != null) {
@ -141,7 +141,7 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
*/
protected void bridgeOffline() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"Niko Home Control: error starting bridge connection");
"Error with bridge connection");
}
/**
@ -153,8 +153,8 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
}
@Override
public void controllerOffline() {
bridgeOffline();
public void controllerOffline(String message) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
}
@Override
@ -231,14 +231,14 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
@Override
public void alarmEvent(String alarmText) {
logger.debug("Niko Home Control: triggering alarm channel with {}", alarmText);
logger.debug("triggering alarm channel with {}", alarmText);
triggerChannel(CHANNEL_ALARM, alarmText);
updateStatus(ThingStatus.ONLINE);
}
@Override
public void noticeEvent(String alarmText) {
logger.debug("Niko Home Control: triggering notice channel with {}", alarmText);
logger.debug("triggering notice channel with {}", alarmText);
triggerChannel(CHANNEL_NOTICE, alarmText);
updateStatus(ThingStatus.ONLINE);
}
@ -263,7 +263,7 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
try {
addr = InetAddress.getByName(config.addr);
} catch (UnknownHostException e) {
logger.debug("Niko Home Control: Cannot resolve hostname {} to IP adress", config.addr);
logger.debug("Cannot resolve hostname {} to IP adress", config.addr);
}
return addr;
}

View File

@ -41,20 +41,20 @@ public class NikoHomeControlBridgeHandler1 extends NikoHomeControlBridgeHandler
@Override
public void initialize() {
logger.debug("Niko Home Control: initializing bridge handler");
logger.debug("initializing bridge handler");
setConfig();
InetAddress addr = getAddr();
int port = getPort();
logger.debug("Niko Home Control: bridge handler host {}, port {}", addr, port);
logger.debug("bridge handler host {}, port {}", addr, port);
if (addr != null) {
nhcComm = new NikoHomeControlCommunication1(this, scheduler);
startCommunication();
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"Niko Home Control: cannot resolve bridge IP with hostname " + config.addr);
"Cannot resolve bridge IP with hostname " + config.addr);
}
}

View File

@ -57,7 +57,7 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
@Override
public void initialize() {
logger.debug("Niko Home Control: initializing NHC II bridge handler");
logger.debug("initializing NHC II bridge handler");
setConfig();
@ -69,15 +69,14 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
// advanced configuration, skipping token validation.
// This behavior would allow the same logic to be used (with profile UUID) as before token validation
// was introduced.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"Niko Home Control: token is empty");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Token is empty");
return;
}
} else {
Date now = new Date();
if (expiryDate.before(now)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"Niko Home Control: hobby api token has expired");
"Hobby api token has expired");
return;
}
}
@ -91,7 +90,7 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
} catch (CertificateException e) {
// this should not happen unless there is a programming error
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"Niko Home Control: not able to set SSL context");
"Not able to set SSL context");
return;
}
}
@ -167,9 +166,8 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
@Override
public String getToken() {
String token = ((NikoHomeControlBridgeConfig2) config).password;
if ((token == null) || token.isEmpty()) {
logger.debug("Niko Home Control: no JWT token set.");
return "";
if (token.isEmpty()) {
logger.debug("no JWT token set.");
}
return token;
}
@ -192,10 +190,10 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
try {
jwtToken = gson.fromJson(tokenPayload, NhcJwtToken2.class);
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected token payload {}", tokenPayload);
logger.debug("unexpected token payload {}", tokenPayload);
} catch (NoSuchElementException ignore) {
// Ignore if exp not present in response, this should not happen in token payload response
logger.trace("Niko Home Control: no expiry date found in payload {}", tokenPayload);
logger.trace("no expiry date found in payload {}", tokenPayload);
}
}
@ -206,20 +204,20 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
long epoch = Long.parseLong(expiryEpoch) * 1000; // convert to milliseconds
expiryDate = new Date(epoch);
} catch (NumberFormatException e) {
logger.debug("Niko Home Control: token expiry not valid {}", jwtToken.exp);
logger.debug("token expiry not valid {}", jwtToken.exp);
return null;
}
Date now = new Date();
if (expiryDate.before(now)) {
logger.warn("Niko Home Control: hobby API token expired, was valid until {}",
logger.warn("hobby API token expired, was valid until {}",
DateFormat.getDateInstance().format(expiryDate));
} else {
Calendar c = Calendar.getInstance();
c.setTime(expiryDate);
c.add(Calendar.DATE, -14);
if (c.getTime().before(now)) {
logger.info("Niko Home Control: hobby API token will expire in less than 14 days, valid until {}",
logger.info("hobby API token will expire in less than 14 days, valid until {}",
DateFormat.getDateInstance().format(expiryDate));
}
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlEnergyMeterConfig} is the config class for Niko Home Control Thermostats.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlEnergyMeterConfig {
public String energyMeterId;
public String energyMeterId = "";
}

View File

@ -48,7 +48,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
private final Logger logger = LoggerFactory.getLogger(NikoHomeControlEnergyMeterHandler.class);
private volatile @NonNullByDefault({}) NhcEnergyMeter nhcEnergyMeter;
private volatile @Nullable NhcEnergyMeter nhcEnergyMeter;
private String energyMeterId = "";
@ -58,6 +58,12 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
NhcEnergyMeter nhcEnergyMeter = this.nhcEnergyMeter;
if (nhcEnergyMeter == null) {
logger.debug("energy meter with ID {} not initialized", energyMeterId);
return;
}
if (command == REFRESH) {
energyMeterEvent(nhcEnergyMeter.getPower());
}
@ -71,6 +77,8 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Connection with controller not started yet, could not initialize energy meter " + energyMeterId);
return;
}
@ -79,16 +87,14 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
scheduler.submit(() -> {
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: no connection with Niko Home Control, could not initialize energy meter "
+ energyMeterId);
"No connection with controller, could not initialize energy meter " + energyMeterId);
return;
}
nhcEnergyMeter = nhcComm.getEnergyMeters().get(energyMeterId);
NhcEnergyMeter nhcEnergyMeter = nhcComm.getEnergyMeters().get(energyMeterId);
if (nhcEnergyMeter == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: energyMeterId does not match a energy meter in the controller "
+ energyMeterId);
"Energy meter " + energyMeterId + " does not match a energy meter in the controller");
return;
}
@ -102,7 +108,9 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
nhcComm.startEnergyMeter(energyMeterId);
}
logger.debug("Niko Home Control: energy meter intialized {}", energyMeterId);
this.nhcEnergyMeter = nhcEnergyMeter;
logger.debug("energy meter intialized {}", energyMeterId);
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
@ -144,10 +152,18 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
updateStatus(ThingStatus.ONLINE);
}
@Override
public void energyMeterInitialized() {
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
updateStatus(ThingStatus.ONLINE);
}
}
@Override
public void energyMeterRemoved() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: energy meter has been removed from the controller " + energyMeterId);
"Energy meter " + energyMeterId + " has been removed from the controller");
}
@Override
@ -157,8 +173,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: bridge communication not initialized when trying to start energy meter "
+ energyMeterId);
"Bridge communication not initialized when trying to start energy meter " + energyMeterId);
return;
}
@ -180,8 +195,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: bridge communication not initialized when trying to stop energy meter "
+ energyMeterId);
"Bridge communication not initialized when trying to stop energy meter " + energyMeterId);
return;
}
@ -206,8 +220,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
nhcComm.restartCommunication();
// If still not active, take thing offline and return.
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: communication socket error");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Communication error");
return;
}
// Also put the bridge back online
@ -221,7 +234,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
NikoHomeControlBridgeHandler nhcBridgeHandler = getBridgeHandler();
if (nhcBridgeHandler == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for energy meter " + energyMeterId);
"No bridge initialized for energy meter " + energyMeterId);
return null;
}
NikoHomeControlCommunication nhcComm = nhcBridgeHandler.getCommunication();
@ -232,7 +245,7 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
Bridge nhcBridge = getBridge();
if (nhcBridge == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for energy meter " + energyMeterId);
"No bridge initialized for energy meter " + energyMeterId);
return null;
}
NikoHomeControlBridgeHandler nhcBridgeHandler = (NikoHomeControlBridgeHandler) nhcBridge.getHandler();

View File

@ -12,12 +12,15 @@
*/
package org.openhab.binding.nikohomecontrol.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* {@link NikoHomeControlThermostatConfig} is the config class for Niko Home Control Thermostats.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlThermostatConfig {
public String thermostatId;
public int overruleTime;
public String thermostatId = "";
public int overruleTime = 60;
}

View File

@ -52,7 +52,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
private final Logger logger = LoggerFactory.getLogger(NikoHomeControlThermostatHandler.class);
private volatile @NonNullByDefault({}) NhcThermostat nhcThermostat;
private volatile @Nullable NhcThermostat nhcThermostat;
private String thermostatId = "";
private int overruleTime;
@ -69,7 +69,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: bridge communication not initialized when trying to execute thermostat command "
"Bridge communication not initialized when trying to execute thermostat command on "
+ thermostatId);
return;
}
@ -87,7 +87,13 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
}
private void handleCommandSelection(ChannelUID channelUID, Command command) {
logger.debug("Niko Home Control: handle command {} for {}", command, channelUID);
NhcThermostat nhcThermostat = this.nhcThermostat;
if (nhcThermostat == null) {
logger.debug("thermostat with ID {} not initialized", thermostatId);
return;
}
logger.debug("handle command {} for {}", command, channelUID);
if (REFRESH.equals(command)) {
thermostatEvent(nhcThermostat.getMeasured(), nhcThermostat.getSetpoint(), nhcThermostat.getMode(),
@ -140,7 +146,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: channel unknown " + channelUID.getId());
"Channel unknown " + channelUID.getId());
}
}
@ -153,6 +159,8 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
NikoHomeControlCommunication nhcComm = getCommunication();
if (nhcComm == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Connection with controller not started yet, could not initialize thermostat " + thermostatId);
return;
}
@ -161,16 +169,14 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
scheduler.submit(() -> {
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: no connection with Niko Home Control, could not initialize thermostat "
+ thermostatId);
"No connection with controller, could not initialize thermostat " + thermostatId);
return;
}
nhcThermostat = nhcComm.getThermostats().get(thermostatId);
NhcThermostat nhcThermostat = nhcComm.getThermostats().get(thermostatId);
if (nhcThermostat == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: thermostatId does not match a thermostat in the controller "
+ thermostatId);
"Thermostat " + thermostatId + " does not match a thermostat in the controller");
return;
}
@ -186,7 +192,9 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
thermostatEvent(nhcThermostat.getMeasured(), nhcThermostat.getSetpoint(), nhcThermostat.getMode(),
nhcThermostat.getOverrule(), nhcThermostat.getDemand());
logger.debug("Niko Home Control: thermostat intialized {}", thermostatId);
this.nhcThermostat = nhcThermostat;
logger.debug("thermostat intialized {}", thermostatId);
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
@ -211,6 +219,12 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
@Override
public void thermostatEvent(int measured, int setpoint, int mode, int overrule, int demand) {
NhcThermostat nhcThermostat = this.nhcThermostat;
if (nhcThermostat == null) {
logger.debug("thermostat with ID {} not initialized", thermostatId);
return;
}
updateState(CHANNEL_MEASURED, new QuantityType<>(nhcThermostat.getMeasured() / 10.0, CELSIUS));
int overruletime = nhcThermostat.getRemainingOverruletime();
@ -263,10 +277,18 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
refreshTimer = null;
}
@Override
public void thermostatInitialized() {
Bridge bridge = getBridge();
if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
updateStatus(ThingStatus.ONLINE);
}
}
@Override
public void thermostatRemoved() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Niko Home Control: thermostat has been removed from the controller " + thermostatId);
"Thermostat " + thermostatId + " has been removed from the controller");
}
private void restartCommunication(NikoHomeControlCommunication nhcComm) {
@ -275,8 +297,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
nhcComm.restartCommunication();
// If still not active, take thing offline and return.
if (!nhcComm.communicationActive()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Niko Home Control: communication socket error");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Communication error");
return;
}
// Also put the bridge back online
@ -290,7 +311,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
NikoHomeControlBridgeHandler nhcBridgeHandler = getBridgeHandler();
if (nhcBridgeHandler == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for thermostat " + thermostatId);
"No bridge initialized for thermostat " + thermostatId);
return null;
}
NikoHomeControlCommunication nhcComm = nhcBridgeHandler.getCommunication();
@ -301,7 +322,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
Bridge nhcBridge = getBridge();
if (nhcBridge == null) {
updateStatus(ThingStatus.UNINITIALIZED, ThingStatusDetail.BRIDGE_UNINITIALIZED,
"Niko Home Control: no bridge initialized for thermostat " + thermostatId);
"No bridge initialized for thermostat " + thermostatId);
return null;
}
NikoHomeControlBridgeHandler nhcBridgeHandler = (NikoHomeControlBridgeHandler) nhcBridge.getHandler();

View File

@ -158,7 +158,7 @@ public abstract class NhcAction {
protected void updateState(int state) {
NhcActionEvent eventHandler = this.eventHandler;
if (eventHandler != null) {
logger.debug("Niko Home Control: update channel state for {} with {}", id, state);
logger.debug("update channel state for {} with {}", id, state);
eventHandler.actionEvent(state);
}
}
@ -167,7 +167,7 @@ public abstract class NhcAction {
* Method called when action is removed from the Niko Home Control Controller.
*/
public void actionRemoved() {
logger.warn("Niko Home Control: action removed {}, {}", id, name);
logger.debug("action removed {}, {}", id, name);
NhcActionEvent eventHandler = this.eventHandler;
if (eventHandler != null) {
eventHandler.actionRemoved();

View File

@ -32,6 +32,12 @@ public interface NhcActionEvent {
*/
public void actionEvent(int state);
/**
* Called to indicate the action has been initialized.
*
*/
public void actionInitialized();
/**
* Called to indicate the action has been removed from the Niko Home Control controller.
*

View File

@ -67,8 +67,9 @@ public interface NhcControllerEvent {
/**
* Called to indicate the connection with the Niko Home Control Controller is offline.
*
* @param message
*/
public void controllerOffline();
public void controllerOffline(String message);
/**
* Called to indicate the connection with the Niko Home Control Controller is online.

View File

@ -56,7 +56,7 @@ public abstract class NhcEnergyMeter {
public void updateState(int power) {
NhcEnergyMeterEvent handler = eventHandler;
if (handler != null) {
logger.debug("Niko Home Control: update channel for {}", id);
logger.debug("update channel for {}", id);
handler.energyMeterEvent(power);
}
}
@ -65,7 +65,7 @@ public abstract class NhcEnergyMeter {
* Method called when energyMeters meter is removed from the Niko Home Control Controller.
*/
public void energyMeterRemoved() {
logger.warn("Niko Home Control: action removed {}, {}", id, name);
logger.debug("action removed {}, {}", id, name);
NhcEnergyMeterEvent eventHandler = this.eventHandler;
if (eventHandler != null) {
eventHandler.energyMeterRemoved();
@ -117,7 +117,7 @@ public abstract class NhcEnergyMeter {
this.power = power;
NhcEnergyMeterEvent handler = eventHandler;
if (handler != null) {
logger.debug("Niko Home Control: update power channel for {} with {}", id, power);
logger.debug("update power channel for {} with {}", id, power);
handler.energyMeterEvent(power);
}
}

View File

@ -28,14 +28,20 @@ import org.eclipse.jdt.annotation.Nullable;
public interface NhcEnergyMeterEvent {
/**
* This method is called when an energyMeters meter event is received from the Niko Home Control controller.
* This method is called when an energyMeter event is received from the Niko Home Control controller.
*
* @param power current power consumption/production in W (positive for consumption), null for an empty reading
*/
public void energyMeterEvent(@Nullable Integer power);
/**
* Called to indicate the energyMeters meter has been removed from the Niko Home Control controller.
* Called to indicate the energyMeter has been initialized.
*
*/
public void energyMeterInitialized();
/**
* Called to indicate the energyMeter has been removed from the Niko Home Control controller.
*
*/
public void energyMeterRemoved();

View File

@ -115,7 +115,7 @@ public abstract class NhcThermostat {
* Method called when thermostat is removed from the Niko Home Control Controller.
*/
public void thermostatRemoved() {
logger.warn("Niko Home Control: action removed {}, {}", id, name);
logger.debug("action removed {}, {}", id, name);
NhcThermostatEvent eventHandler = this.eventHandler;
if (eventHandler != null) {
eventHandler.thermostatRemoved();
@ -125,7 +125,7 @@ public abstract class NhcThermostat {
private void updateChannels() {
NhcThermostatEvent handler = eventHandler;
if (handler != null) {
logger.debug("Niko Home Control: update channels for {}", id);
logger.debug("update channels for {}", id);
handler.thermostatEvent(measured, setpoint, mode, overrule, demand);
}
}

View File

@ -37,6 +37,12 @@ public interface NhcThermostatEvent {
*/
public void thermostatEvent(int measured, int setpoint, int mode, int overrule, int demand);
/**
* Called to indicate the thermostat has been initialized.
*
*/
public void thermostatInitialized();
/**
* Called to indicate the thermostat has been removed from the Niko Home Control controller.
*

View File

@ -65,7 +65,7 @@ public abstract class NikoHomeControlCommunication {
public synchronized void restartCommunication() {
stopCommunication();
logger.debug("Niko Home Control: restart communication from thread {}", Thread.currentThread().getId());
logger.debug("restart communication from thread {}", Thread.currentThread().getId());
startCommunication();
}

View File

@ -70,7 +70,7 @@ public final class NikoHomeControlDiscover {
datagramSocket.send(discoveryPacket);
while (true) {
datagramSocket.receive(packet);
logger.trace("Niko Home Control: bridge discovery response {}",
logger.trace("bridge discovery response {}",
HexUtils.bytesToHex(Arrays.copyOf(packet.getData(), packet.getLength())));
if (isNhc(packet)) {
break;
@ -79,7 +79,7 @@ public final class NikoHomeControlDiscover {
addr = packet.getAddress();
setNhcBridgeId(packet);
setIsNhcII(packet);
logger.debug("Niko Home Control: IP address is {}, unique ID is {}", addr, nhcBridgeId);
logger.debug("IP address is {}, unique ID is {}", addr, nhcBridgeId);
}
}

View File

@ -74,7 +74,7 @@ public class NhcAction1 extends NhcAction {
if (getType() == ActionType.ROLLERSHUTTER) {
if (filterEvent) {
filterEvent = false;
logger.debug("Niko Home Control: filtered event {} for {}", newState, id);
logger.debug("filtered event {} for {}", newState, id);
return;
}
@ -88,7 +88,7 @@ public class NhcAction1 extends NhcAction {
}
}
if (waitForEvent) {
logger.debug("Niko Home Control: received requested rollershutter {} position event {}", id, newState);
logger.debug("received requested rollershutter {} position event {}", id, newState);
executeRollershutterTask();
} else {
state = newState;
@ -103,7 +103,7 @@ public class NhcAction1 extends NhcAction {
*/
@Override
public void execute(String command) {
logger.debug("Niko Home Control: execute action {} of type {} for {}", command, type, id);
logger.debug("execute action {} of type {} for {}", command, type, id);
String value = "";
switch (getType()) {
@ -162,7 +162,7 @@ public class NhcAction1 extends NhcAction {
} else if (command.equals(NHCSTOP)) {
executeRollershutterStop();
} else {
int newValue = 100 - Integer.parseInt(command);
int newValue = Integer.parseInt(command);
if (logger.isTraceEnabled()) {
logger.trace("handleRollerShutterCommand: rollershutter {} percent command, current {}, new {}", id,
currentValue, newValue);
@ -174,9 +174,9 @@ public class NhcAction1 extends NhcAction {
scheduleRollershutterStop(currentValue, newValue);
}
if (newValue < currentValue) {
executeRollershutterDown();
} else if (newValue > currentValue) {
executeRollershutterUp();
} else if (newValue > currentValue) {
executeRollershutterDown();
}
}
};

View File

@ -12,6 +12,8 @@
*/
package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Class {@link NhcMessageBase1} used as base class for output from gson for cmd or event feedback from Niko Home
* Control. This class only contains the common base fields required for the deserializer
@ -21,10 +23,11 @@ package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
abstract class NhcMessageBase1 {
private String cmd;
private String event;
private String cmd = "";
private String event = "";
String getCmd() {
return cmd;

View File

@ -12,6 +12,8 @@
*/
package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Class {@link NhcMessageCmd1} used as input to gson to send commands to Niko Home Control. Extends
* {@link NhcMessageBase1}.
@ -21,6 +23,7 @@ package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
* @author Mark Herwege - Initial Contribution
*/
@SuppressWarnings("unused")
@NonNullByDefault
class NhcMessageCmd1 extends NhcMessageBase1 {
private int id;
@ -29,7 +32,7 @@ class NhcMessageCmd1 extends NhcMessageBase1 {
private int value3;
private int mode;
private int overrule;
private String overruletime;
private String overruletime = "";
NhcMessageCmd1(String cmd) {
super.setCmd(cmd);

View File

@ -16,6 +16,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Class {@link NhcMessageListMap1} used as output from gson for cmd or event feedback from Niko Home Control where the
* data part is enclosed by [] and contains a list of json strings. Extends {@link NhcMessageBase1}.
@ -25,6 +27,7 @@ import java.util.Map;
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
class NhcMessageListMap1 extends NhcMessageBase1 {
private List<Map<String, String>> data = new ArrayList<>();

View File

@ -15,6 +15,8 @@ package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Class {@link NhcMessageMap1} used as output from gson for cmd or event feedback from Niko Home Control where the
* data part is a simple json string. Extends {@link NhcMessageBase1}.
@ -23,6 +25,7 @@ import java.util.Map;
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
class NhcMessageMap1 extends NhcMessageBase1 {
private Map<String, String> data = new HashMap<>();

View File

@ -42,7 +42,7 @@ public class NhcThermostat1 extends NhcThermostat {
*/
@Override
public void executeMode(int mode) {
logger.debug("Niko Home Control: execute thermostat mode {} for {}", mode, id);
logger.debug("execute thermostat mode {} for {}", mode, id);
nhcComm.executeThermostat(id, Integer.toString(mode));
}
@ -55,8 +55,7 @@ public class NhcThermostat1 extends NhcThermostat {
*/
@Override
public void executeOverrule(int overrule, int overruletime) {
logger.debug("Niko Home Control: execute thermostat overrule {} during {} min for {}", overrule, overruletime,
id);
logger.debug("execute thermostat overrule {} during {} min for {}", overrule, overruletime, id);
nhcComm.executeThermostat(id, overrule, overruletime);
}

View File

@ -20,6 +20,7 @@ import java.net.InetAddress;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
@ -94,7 +95,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
Thread.sleep(1000);
}
if (nhcEventsRunning) {
logger.debug("Niko Home Control: starting but previous connection still active after 5000ms");
logger.debug("starting but previous connection still active after 5000ms");
throw new IOException();
}
@ -105,7 +106,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
nhcSocket = socket;
nhcOut = new PrintWriter(socket.getOutputStream(), true);
nhcIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
logger.debug("Niko Home Control: connected via local port {}", socket.getLocalPort());
logger.debug("connected via local port {}", socket.getLocalPort());
// initialize all info in local fields
initialize();
@ -115,9 +116,8 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
(new Thread(this::runNhcEvents)).start();
} catch (IOException | InterruptedException e) {
logger.warn("Niko Home Control: error initializing communication");
stopCommunication();
handler.controllerOffline();
handler.controllerOffline("Error initializing communication");
}
}
@ -139,7 +139,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
}
nhcSocket = null;
logger.debug("Niko Home Control: communication stopped");
logger.debug("communication stopped");
}
@Override
@ -158,7 +158,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
private void runNhcEvents() {
String nhcMessage;
logger.debug("Niko Home Control: listening for events");
logger.debug("listening for events");
listenerStopped = false;
nhcEventsRunning = true;
@ -170,7 +170,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
if (!listenerStopped) {
nhcEventsRunning = false;
// this is a socket error, not a communication stop triggered from outside this runnable
logger.warn("Niko Home Control: IO error in listener");
logger.debug("IO error in listener");
// the IO has stopped working, so we need to close cleanly and try to restart
restartCommunication();
return;
@ -181,7 +181,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
nhcEventsRunning = false;
// this is a stop from outside the runnable, so just log it and stop
logger.debug("Niko Home Control: event listener thread stopped");
logger.debug("event listener thread stopped");
}
/**
@ -218,17 +218,16 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
@SuppressWarnings("null")
private synchronized void sendMessage(Object nhcMessage) {
String json = gsonOut.toJson(nhcMessage);
logger.debug("Niko Home Control: send json {}", json);
logger.debug("send json {}", json);
nhcOut.println(json);
if (nhcOut.checkError()) {
logger.warn("Niko Home Control: error sending message, trying to restart communication");
logger.debug("error sending message, trying to restart communication");
restartCommunication();
// retry sending after restart
logger.debug("Niko Home Control: resend json {}", json);
logger.debug("resend json {}", json);
nhcOut.println(json);
if (nhcOut.checkError()) {
logger.warn("Niko Home Control: error resending message");
handler.controllerOffline();
handler.controllerOffline("Error resending message");
}
}
}
@ -239,11 +238,14 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
* @param nhcMessage message read from Niko Home Control.
*/
private void readMessage(@Nullable String nhcMessage) {
logger.debug("Niko Home Control: received json {}", nhcMessage);
logger.debug("received json {}", nhcMessage);
try {
NhcMessageBase1 nhcMessageGson = gsonIn.fromJson(nhcMessage, NhcMessageBase1.class);
if (nhcMessageGson == null) {
return;
}
String cmd = nhcMessageGson.getCmd();
String event = nhcMessageGson.getEvent();
@ -268,10 +270,10 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
} else if ("getalarms".equals(event)) {
eventGetAlarms(((NhcMessageMap1) nhcMessageGson).getData());
} else {
logger.debug("Niko Home Control: not acted on json {}", nhcMessage);
logger.debug("not acted on json {}", nhcMessage);
}
} catch (JsonParseException e) {
logger.debug("Niko Home Control: not acted on unsupported json {}", nhcMessage);
logger.debug("not acted on unsupported json {}", nhcMessage);
}
}
@ -283,7 +285,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
}
private synchronized void cmdSystemInfo(Map<String, String> data) {
logger.debug("Niko Home Control: systeminfo");
logger.debug("systeminfo");
setIfPresent(data, "swversion", systemInfo::setSwVersion);
setIfPresent(data, "api", systemInfo::setApi);
@ -311,17 +313,17 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
if (errorCodeString != null) {
int errorCode = Integer.parseInt(errorCodeString);
if (errorCode == 0) {
logger.debug("Niko Home Control: start events success");
logger.debug("start events success");
} else {
logger.warn("Niko Home Control: error code {} returned on start events", errorCode);
logger.debug("error code {} returned on start events", errorCode);
}
} else {
logger.warn("Niko Home Control: could not determine error code returned on start events");
logger.debug("could not determine error code returned on start events");
}
}
private void cmdListLocations(List<Map<String, String>> data) {
logger.debug("Niko Home Control: list locations");
logger.debug("list locations");
locations.clear();
@ -338,7 +340,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
}
private void cmdListActions(List<Map<String, String>> data) {
logger.debug("Niko Home Control: list actions");
logger.debug("list actions");
for (Map<String, String> action : data) {
String id = action.get("id");
@ -360,7 +362,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
logger.debug("name not found in action {}", action);
continue;
}
String type = action.get("type");
String type = Optional.ofNullable(action.get("type")).orElse("");
ActionType actionType = ActionType.GENERIC;
switch (type) {
case "0":
@ -377,7 +379,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
actionType = ActionType.ROLLERSHUTTER;
break;
default:
logger.debug("Niko Home Control: unknown action type {} for action {}", type, id);
logger.debug("unknown action type {} for action {}", type, id);
continue;
}
String locationId = action.get("location");
@ -395,14 +397,18 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
// Action object already exists, so only update state.
// If we would re-instantiate action, we would lose pointer back from action to thing handler that was
// set in thing handler initialize().
actions.get(id).setState(state);
NhcAction nhcAction = actions.get(id);
if (nhcAction != null) {
nhcAction.setState(state);
}
}
}
}
private int parseIntOrThrow(@Nullable String str) throws IllegalArgumentException {
if (str == null)
if (str == null) {
throw new IllegalArgumentException("String is null");
}
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
@ -411,7 +417,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
}
private void cmdListThermostat(List<Map<String, String>> data) {
logger.debug("Niko Home Control: list thermostats");
logger.debug("list thermostats");
for (Map<String, String> thermostat : data) {
try {
@ -442,8 +448,11 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
String name = thermostat.get("name");
String locationId = thermostat.get("location");
String location = "";
if (!locationId.isEmpty()) {
location = locations.get(locationId).getName();
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);
@ -463,12 +472,12 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
try {
int errorCode = parseIntOrThrow(data.get("error"));
if (errorCode == 0) {
logger.debug("Niko Home Control: execute action success");
logger.debug("execute action success");
} else {
logger.warn("Niko Home Control: error code {} returned on command execution", errorCode);
logger.debug("error code {} returned on command execution", errorCode);
}
} catch (IllegalArgumentException e) {
logger.warn("Niko Home Control: no error code returned on command execution");
logger.debug("no error code returned on command execution");
}
}
@ -476,12 +485,12 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
try {
int errorCode = parseIntOrThrow(data.get("error"));
if (errorCode == 0) {
logger.debug("Niko Home Control: execute thermostats success");
logger.debug("execute thermostats success");
} else {
logger.warn("Niko Home Control: error code {} returned on command execution", errorCode);
logger.debug("error code {} returned on command execution", errorCode);
}
} catch (IllegalArgumentException e) {
logger.warn("Niko Home Control: no error code returned on command execution");
logger.debug("no error code returned on command execution");
}
}
@ -489,13 +498,13 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
for (Map<String, String> action : data) {
String id = action.get("id");
if (id == null || !actions.containsKey(id)) {
logger.warn("Niko Home Control: action in controller not known {}", id);
logger.warn("action in controller not known {}", id);
return;
}
String stateString = action.get("value1");
if (stateString != null) {
int state = Integer.parseInt(stateString);
logger.debug("Niko Home Control: event execute action {} with state {}", id, state);
logger.debug("event execute action {} with state {}", id, state);
NhcAction action1 = actions.get(id);
if (action1 != null) {
action1.setState(state);
@ -509,7 +518,7 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
try {
String id = thermostat.get("id");
if (!thermostats.containsKey(id)) {
logger.warn("Niko Home Control: thermostat in controller not known {}", id);
logger.warn("thermostat in controller not known {}", id);
return;
}
@ -549,15 +558,15 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
}
switch (data.getOrDefault("type", "")) {
case "0":
logger.debug("Niko Home Control: alarm - {}", alarmText);
logger.debug("alarm - {}", alarmText);
handler.alarmEvent(alarmText);
break;
case "1":
logger.debug("Niko Home Control: notice - {}", alarmText);
logger.debug("notice - {}", alarmText);
handler.noticeEvent(alarmText);
break;
default:
logger.debug("Niko Home Control: unexpected message type {}", data.get("type"));
logger.debug("unexpected message type {}", data.get("type"));
}
}

View File

@ -19,6 +19,9 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
@ -33,16 +36,17 @@ import com.google.gson.JsonParseException;
* @author Mark Herwege - Initial Contribution
*
*/
@NonNullByDefault
class NikoHomeControlMessageDeserializer1 implements JsonDeserializer<NhcMessageBase1> {
@Override
public NhcMessageBase1 deserialize(final JsonElement json, final Type typeOfT,
public @Nullable NhcMessageBase1 deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
try {
String cmd = null;
String event = null;
String cmd = "";
String event = "";
if (jsonObject.has("cmd")) {
cmd = jsonObject.get("cmd").getAsString();
}

View File

@ -115,7 +115,7 @@ public class NhcAction2 extends NhcAction {
*/
@Override
public void execute(String command) {
logger.debug("Niko Home Control: execute action {} of type {} for {}", command, type, id);
logger.debug("execute action {} of type {} for {}", command, type, id);
nhcComm.executeAction(id, command);
}

View File

@ -100,7 +100,7 @@ public class NhcMqttConnection2 implements MqttActionCallback {
tmFactory.init(keyStore);
return tmFactory.getTrustManagers();
} catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | IOException e) {
logger.warn("Niko Home Control: error with SSL context creation: {} ", e.getMessage());
logger.debug("error with SSL context creation: {} ", e.getMessage());
throw new CertificateException("SSL context creation exception", e);
} finally {
ResourceBundle.clearCache();
@ -121,14 +121,14 @@ public class NhcMqttConnection2 implements MqttActionCallback {
if (future != null) {
try {
future.get(5000, TimeUnit.MILLISECONDS);
logger.debug("Niko Home Control: finished stopping connection");
logger.debug("finished stopping connection");
} catch (InterruptedException | ExecutionException | TimeoutException ignore) {
logger.debug("Niko Home Control: error stopping connection");
logger.debug("error stopping connection");
}
stoppedFuture = null;
}
logger.debug("Niko Home Control: starting connection...");
logger.debug("starting connection...");
this.cocoAddress = cocoAddress;
this.port = port;
this.profile = profile;
@ -142,17 +142,17 @@ public class NhcMqttConnection2 implements MqttActionCallback {
subscribedFuture = connection.subscribe("#", messageSubscriber);
}
} else {
logger.debug("Niko Home Control: error connecting");
logger.debug("error connecting");
throw new MqttException("Connection execution exception");
}
} catch (InterruptedException e) {
logger.debug("Niko Home Control: connection interrupted exception");
logger.debug("connection interrupted exception");
throw new MqttException("Connection interrupted exception");
} catch (ExecutionException e) {
logger.debug("Niko Home Control: connection execution exception", e.getCause());
logger.debug("connection execution exception", e.getCause());
throw new MqttException("Connection execution exception");
} catch (TimeoutException e) {
logger.debug("Niko Home Control: connection timeout exception");
logger.debug("connection timeout exception");
throw new MqttException("Connection timeout exception");
}
}
@ -169,7 +169,7 @@ public class NhcMqttConnection2 implements MqttActionCallback {
* Stop the MQTT connection.
*/
void stopConnection() {
logger.debug("Niko Home Control: stopping connection...");
logger.debug("stopping connection...");
MqttBrokerConnection connection = mqttConnection;
if (connection != null) {
connection.removeConnectionObserver(connectionObserver);
@ -203,7 +203,7 @@ public class NhcMqttConnection2 implements MqttActionCallback {
try {
if ((future != null) && future.get(5000, TimeUnit.MILLISECONDS)) {
MqttConnectionState state = connection.connectionState();
logger.debug("Niko Home Control: connection state {} for {}", state, connection.getClientId());
logger.debug("connection state {} for {}", state, connection.getClientId());
return state == MqttConnectionState.CONNECTED;
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
@ -223,25 +223,25 @@ public class NhcMqttConnection2 implements MqttActionCallback {
void connectionPublish(String topic, String payload) throws MqttException {
MqttBrokerConnection connection = mqttConnection;
if (connection == null) {
logger.debug("Niko Home Control: cannot publish, no connection");
logger.debug("cannot publish, no connection");
throw new MqttException("No connection exception");
}
if (isConnected()) {
logger.debug("Niko Home Control: publish {}, {}", topic, payload);
logger.debug("publish {}, {}", topic, payload);
connection.publish(topic, payload.getBytes(), connection.getQos(), false);
} else {
logger.debug("Niko Home Control: cannot publish, not subscribed to connection messages");
logger.debug("cannot publish, not subscribed to connection messages");
}
}
@Override
public void onSuccess(String topic) {
logger.debug("Niko Home Control: publish succeeded {}", topic);
logger.debug("publish succeeded {}", topic);
}
@Override
public void onFailure(String topic, Throwable error) {
logger.debug("Niko Home Control: publish failed {}, {}", topic, error.getMessage(), error);
logger.debug("publish failed {}, {}", topic, error.getMessage(), error);
}
}

View File

@ -45,7 +45,7 @@ public class NhcThermostat2 extends NhcThermostat {
@Override
public void executeMode(int mode) {
logger.debug("Niko Home Control: execute thermostat mode {} for {}", mode, id);
logger.debug("execute thermostat mode {} for {}", mode, id);
String program = THERMOSTATMODES[mode];
nhcComm.executeThermostat(id, program);
@ -53,8 +53,7 @@ public class NhcThermostat2 extends NhcThermostat {
@Override
public void executeOverrule(int overrule, int overruletime) {
logger.debug("Niko Home Control: execute thermostat overrule {} during {} min for {}", overrule, overruletime,
id);
logger.debug("execute thermostat overrule {} during {} min for {}", overrule, overruletime, id);
nhcComm.executeThermostat(id, overrule, overruletime);
}

View File

@ -33,7 +33,11 @@ import java.util.stream.IntStream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.nikohomecontrol.internal.protocol.*;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAction;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcControllerEvent;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcEnergyMeter;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcThermostat;
import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.ActionType;
import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NhcDevice2.NhcProperty;
import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NhcMessage2.NhcMessageParam;
@ -104,19 +108,19 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
InetAddress addr = handler.getAddr();
if (addr == null) {
logger.warn("Niko Home Control: IP address cannot be empty");
logger.warn("IP address cannot be empty");
stopCommunication();
return;
}
String addrString = addr.getHostAddress();
int port = handler.getPort();
logger.debug("Niko Home Control: initializing for mqtt connection to CoCo on {}:{}", addrString, port);
logger.debug("initializing for mqtt connection to CoCo on {}:{}", addrString, port);
profile = handler.getProfile();
String token = handler.getToken();
if (token.isEmpty()) {
logger.warn("Niko Home Control: JWT token cannot be empty");
logger.warn("JWT token cannot be empty");
stopCommunication();
return;
}
@ -125,7 +129,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
mqttConnection.startConnection(addrString, port, profile, token);
initialize();
} catch (MqttException e) {
logger.warn("Niko Home Control: error in mqtt communication");
logger.debug("error in mqtt communication");
stopCommunication();
}
}
@ -150,7 +154,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
// Wait until we received all devices info to confirm we are active.
return started.get(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Niko Home Control: exception waiting for connection start");
logger.debug("exception waiting for connection start");
return false;
}
}
@ -176,10 +180,10 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
mqttConnection.connectionPublish(profile + "/notification/cmd", gson.toJson(message));
}
private void connectionLost() {
logger.debug("Niko Home Control: connection lost");
private void connectionLost(String message) {
logger.debug("connection lost");
stopCommunication();
handler.controllerOffline();
handler.controllerOffline(message);
}
private void systemEvt(String response) {
@ -189,13 +193,13 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
List<NhcSystemInfo2> systemInfo = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
List<NhcMessageParam> messageParams = message.params;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
timeInfo = messageParams.stream().filter(p -> (p.timeInfo != null)).findFirst().get().timeInfo;
systemInfo = messageParams.stream().filter(p -> (p.systemInfo != null)).findFirst().get().systemInfo;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if timeInfo not present in response, this should not happen in a timeInfo response
}
@ -214,12 +218,12 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
List<NhcSystemInfo2> systemInfo = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
List<NhcMessageParam> messageParams = message.params;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
systemInfo = messageParams.stream().filter(p -> (p.systemInfo != null)).findFirst().get().systemInfo;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if systemInfo not present in response, this should not happen in a systemInfo response
}
@ -234,12 +238,12 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
List<NhcService2> serviceList = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
List<NhcMessageParam> messageParams = message.params;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
serviceList = messageParams.stream().filter(p -> (p.services != null)).findFirst().get().services;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if services not present in response, this should not happen in a services response
}
@ -255,12 +259,12 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
List<NhcDevice2> deviceList = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
List<NhcMessageParam> messageParams = message.params;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
deviceList = messageParams.stream().filter(p -> (p.devices != null)).findFirst().get().devices;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if devices not present in response, this should not happen in a devices response
}
@ -274,7 +278,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
}
// Once a devices list response is received, we know the communication is fully started.
logger.debug("Niko Home Control: Communication start complete.");
logger.debug("Communication start complete.");
handler.controllerOnline();
CompletableFuture<Boolean> future = communicationStarted;
if (future != null) {
@ -289,13 +293,13 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
String method = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
method = message.method;
List<NhcMessageParam> messageParams = message.params;
method = (message != null) ? message.method : null;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
deviceList = messageParams.stream().filter(p -> (p.devices != null)).findFirst().get().devices;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if devices not present in response, this should not happen in a devices event
}
@ -308,9 +312,6 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
return;
} else if ("devices.added".equals(method)) {
deviceList.forEach(this::addDevice);
} else if ("devices.changed".equals(method)) {
deviceList.forEach(this::removeDevice);
deviceList.forEach(this::addDevice);
}
deviceList.forEach(this::updateState);
@ -322,17 +323,17 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
List<NhcNotification2> notificationList = null;
try {
NhcMessage2 message = gson.fromJson(response, messageType);
List<NhcMessageParam> messageParams = message.params;
List<NhcMessageParam> messageParams = (message != null) ? message.params : null;
if (messageParams != null) {
notificationList = messageParams.stream().filter(p -> (p.notifications != null)).findFirst()
.get().notifications;
}
} catch (JsonSyntaxException e) {
logger.debug("Niko Home Control: unexpected json {}", response);
logger.debug("unexpected json {}", response);
} catch (NoSuchElementException ignore) {
// Ignore if notifications not present in response, this should not happen in a notifications event
}
logger.debug("Niko Home Control: notifications {}", notificationList);
logger.debug("notifications {}", notificationList);
if (notificationList == null) {
return;
}
@ -348,7 +349,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
handler.noticeEvent(alarmText);
break;
default:
logger.debug("Niko Home Control: unexpected message type {}", notification.type);
logger.debug("unexpected message type {}", notification.type);
}
}
}
@ -363,7 +364,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
if ("action".equals(device.type)) {
if (!actions.containsKey(device.uuid)) {
logger.debug("Niko Home Control: adding action device {}, {}", device.uuid, device.name);
logger.debug("adding action device {}, {}", device.uuid, device.name);
ActionType actionType;
switch (device.model) {
@ -394,8 +395,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
break;
default:
actionType = ActionType.GENERIC;
logger.debug("Niko Home Control: device type {} not recognised, default to GENERIC action",
device.type);
logger.debug("device type {} not recognised, default to GENERIC action", device.type);
}
NhcAction2 nhcAction = new NhcAction2(device.uuid, device.name, device.model, device.technology,
@ -404,7 +404,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
}
} else if ("thermostat".equals(device.type)) {
if (!thermostats.containsKey(device.uuid)) {
logger.debug("Niko Home Control: adding thermostat device {}, {}", device.uuid, device.name);
logger.debug("adding thermostat device {}, {}", device.uuid, device.name);
NhcThermostat2 nhcThermostat = new NhcThermostat2(device.uuid, device.name, device.model,
device.technology, location, this);
@ -412,26 +412,28 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
}
} else if ("centralmeter".equals(device.type)) {
if (!energyMeters.containsKey(device.uuid)) {
logger.debug("Niko Home Control: adding centralmeter device {}, {}", device.uuid, device.name);
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);
}
} else {
logger.debug("Niko Home Control: device type {} not supported for {}, {}", device.type, device.uuid,
device.name);
logger.debug("device type {} not supported for {}, {}", device.type, device.uuid, device.name);
}
}
private void removeDevice(NhcDevice2 device) {
if (actions.containsKey(device.uuid)) {
actions.get(device.uuid).actionRemoved();
NhcAction action = actions.get(device.uuid);
NhcThermostat thermostat = thermostats.get(device.uuid);
NhcEnergyMeter energyMeter = energyMeters.get(device.uuid);
if (action != null) {
action.actionRemoved();
actions.remove(device.uuid);
} else if (thermostats.containsKey(device.uuid)) {
thermostats.get(device.uuid).thermostatRemoved();
} else if (thermostat != null) {
thermostat.thermostatRemoved();
thermostats.remove(device.uuid);
} else if (energyMeters.containsKey(device.uuid)) {
energyMeters.get(device.uuid).energyMeterRemoved();
} else if (energyMeter != null) {
energyMeter.energyMeterRemoved();
energyMeters.remove(device.uuid);
}
}
@ -481,10 +483,10 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
if (booleanState != null) {
if (NHCON.equals(booleanState)) {
action.setBooleanState(true);
logger.debug("Niko Home Control: setting action {} internally to ON", action.getId());
logger.debug("setting action {} internally to ON", action.getId());
} else if (NHCOFF.equals(booleanState)) {
action.setBooleanState(false);
logger.debug("Niko Home Control: setting action {} internally to OFF", action.getId());
logger.debug("setting action {} internally to OFF", action.getId());
}
}
@ -492,8 +494,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
String brightness = dimmerProperty.get().brightness;
if (brightness != null) {
action.setState(Integer.parseInt(brightness));
logger.debug("Niko Home Control: setting action {} internally to {}", action.getId(),
dimmerProperty.get().brightness);
logger.debug("setting action {} internally to {}", action.getId(), dimmerProperty.get().brightness);
}
}
}
@ -502,9 +503,9 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
deviceProperties.stream().map(p -> p.position).filter(Objects::nonNull).findFirst().ifPresent(position -> {
try {
action.setState(Integer.parseInt(position));
logger.debug("Niko Home Control: setting action {} internally to {}", action.getId(), position);
logger.debug("setting action {} internally to {}", action.getId(), position);
} catch (NumberFormatException e) {
logger.trace("Niko Home Control: received empty rollershutter {} position info", action.getId());
logger.trace("received empty rollershutter {} position info", action.getId());
}
});
}
@ -577,12 +578,10 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
.ifPresent(electricalPower -> {
try {
energyMeter.setPower(Integer.parseInt(electricalPower));
logger.trace("Niko Home Control: setting energy meter {} power to {}", energyMeter.getId(),
electricalPower);
logger.trace("setting energy meter {} power to {}", energyMeter.getId(), electricalPower);
} catch (NumberFormatException e) {
energyMeter.setPower(null);
logger.trace("Niko Home Control: received empty energy meter {} power reading",
energyMeter.getId());
logger.trace("received empty energy meter {} power reading", energyMeter.getId());
}
});
}
@ -607,6 +606,9 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
device.properties = deviceProperties;
NhcAction2 action = (NhcAction2) actions.get(actionId);
if (action == null) {
return;
}
switch (action.getType()) {
case GENERIC:
@ -639,7 +641,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
} else if (NHCDOWN.equals(value)) {
property.position = "0";
} else {
int position = 100 - Integer.parseInt(value);
int position = Integer.parseInt(value);
property.position = String.valueOf(position);
}
break;
@ -745,12 +747,18 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
String topic = profile + "/control/devices/cmd";
String gsonMessage = gson.toJson(message);
((NhcEnergyMeter2) energyMeters.get(energyMeterId)).startEnergyMeter(topic, gsonMessage);
NhcEnergyMeter2 energyMeter = (NhcEnergyMeter2) energyMeters.get(energyMeterId);
if (energyMeter != null) {
energyMeter.startEnergyMeter(topic, gsonMessage);
}
}
@Override
public void stopEnergyMeter(String energyMeterId) {
((NhcEnergyMeter2) energyMeters.get(energyMeterId)).stopEnergyMeter();
NhcEnergyMeter2 energyMeter = (NhcEnergyMeter2) energyMeters.get(energyMeterId);
if (energyMeter != null) {
energyMeter.stopEnergyMeter();
}
}
/**
@ -768,19 +776,26 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
mqttConnection.connectionPublish(topic, gsonMessage);
} catch (MqttException e) {
logger.warn("Niko Home Control: sending command failed, trying to restart communication");
String message = e.getMessage();
message = (message != null) ? message : "Communication error";
logger.debug("sending command failed, trying to restart communication");
restartCommunication();
// retry sending after restart
try {
if (communicationActive()) {
mqttConnection.connectionPublish(topic, gsonMessage);
} else {
logger.warn("Niko Home Control: failed to restart communication");
connectionLost();
logger.debug("failed to restart communication");
}
} catch (MqttException e1) {
logger.warn("Niko Home Control: error resending device command");
connectionLost();
message = e1.getMessage();
message = (message != null) ? message : "Communication error";
logger.debug("error resending device command");
}
if (!communicationActive()) {
connectionLost(message);
}
}
}
@ -791,24 +806,24 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
if ((profile + "/system/evt").equals(topic)) {
systemEvt(message);
} else if ((profile + "/system/rsp").equals(topic)) {
logger.debug("Niko Home Control: received topic {}, payload {}", topic, message);
logger.debug("received topic {}, payload {}", topic, message);
systeminfoPublishRsp(message);
} else if ((profile + "/notification/evt").equals(topic)) {
logger.debug("Niko Home Control: received topic {}, payload {}", topic, message);
logger.debug("received topic {}, payload {}", topic, message);
notificationEvt(message);
} else if ((profile + "/control/devices/evt").equals(topic)) {
logger.trace("Niko Home Control: received topic {}, payload {}", topic, message);
logger.trace("received topic {}, payload {}", topic, message);
devicesEvt(message);
} else if ((profile + "/control/devices/rsp").equals(topic)) {
logger.debug("Niko Home Control: received topic {}, payload {}", topic, message);
logger.debug("received topic {}, payload {}", topic, message);
devicesListRsp(message);
} else if ((profile + "/authentication/rsp").equals(topic)) {
logger.debug("Niko Home Control: received topic {}, payload {}", topic, message);
logger.debug("received topic {}, payload {}", topic, message);
servicesListRsp(message);
} else if ((profile + "/control/devices.error").equals(topic)) {
logger.warn("Niko Home Control: received error {}", message);
logger.warn("received error {}", message);
} else {
logger.trace("Niko Home Control: not acted on received message topic {}, payload {}", topic, message);
logger.trace("not acted on received message topic {}, payload {}", topic, message);
}
}
@ -845,10 +860,14 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
public void connectionStateChanged(MqttConnectionState state, @Nullable Throwable error) {
if (error != null) {
logger.debug("Connection state: {}", state, error);
restartCommunication();
String message = error.getMessage();
message = (message != null) ? message : "Error communicating with the controller";
if (!MqttConnectionState.CONNECTING.equals(state)) {
// This is a connection loss, try to restart
restartCommunication();
}
if (!communicationActive()) {
logger.warn("Niko Home Control: failed to restart communication");
connectionLost();
connectionLost(message);
}
} else {
logger.trace("Connection state: {}", state);

View File

@ -127,7 +127,7 @@
<description>Niko Home Control action ID</description>
<advanced>false</advanced>
</parameter>
<parameter name="step" type="integer" required="true">
<parameter name="step" type="integer">
<label>Step Value</label>
<description>Step value used for increase/decrease of dimmer brightness, default 10%</description>
<default>10</default>
@ -151,6 +151,12 @@
<description>Niko Home Control action ID</description>
<advanced>false</advanced>
</parameter>
<parameter name="invert" type="boolean">
<label>Invert Direction</label>
<description>Invert rollershutter direction</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
</config-description>
</thing-type>
<thing-type id="thermostat">