Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nikohomecontrol] Energy meters and access control #12893

Merged
merged 11 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 99 additions & 154 deletions bundles/org.openhab.binding.nikohomecontrol/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
package org.openhab.binding.nikohomecontrol.internal;

import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -46,17 +45,26 @@ public class NikoHomeControlBindingConstants {
public static final ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "dimmer");
public static final ThingTypeUID THING_TYPE_BLIND = new ThingTypeUID(BINDING_ID, "blind");
public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat");
public static final ThingTypeUID THING_TYPE_ENERGYMETER_LIVE = new ThingTypeUID(BINDING_ID, "energyMeterLive");
public static final ThingTypeUID THING_TYPE_ENERGYMETER = new ThingTypeUID(BINDING_ID, "energyMeter");
public static final ThingTypeUID THING_TYPE_GASMETER = new ThingTypeUID(BINDING_ID, "gasMeter");
public static final ThingTypeUID THING_TYPE_WATERMETER = new ThingTypeUID(BINDING_ID, "waterMeter");
public static final ThingTypeUID THING_TYPE_ACCESS = new ThingTypeUID(BINDING_ID, "access");
public static final ThingTypeUID THING_TYPE_ACCESS_RINGANDCOMEIN = new ThingTypeUID(BINDING_ID,
"accessRingAndComeIn");

// thing type sets
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(BRIDGEI_THING_TYPE, BRIDGEII_THING_TYPE).collect(Collectors.toSet()));
public static final Set<ThingTypeUID> ACTION_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_PUSHBUTTON, THING_TYPE_ON_OFF_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_BLIND)
.collect(Collectors.toSet()));
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_PUSHBUTTON, THING_TYPE_ON_OFF_LIGHT, THING_TYPE_DIMMABLE_LIGHT,
THING_TYPE_BLIND, THING_TYPE_THERMOSTAT, THING_TYPE_ENERGYMETER).collect(Collectors.toSet()));
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Set.of(BRIDGEI_THING_TYPE, BRIDGEII_THING_TYPE);
public static final Set<ThingTypeUID> ACTION_THING_TYPES_UIDS = Set.of(THING_TYPE_PUSHBUTTON,
THING_TYPE_ON_OFF_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_BLIND);
public static final Set<ThingTypeUID> THERMOSTAT_THING_TYPES_UIDS = Set.of(THING_TYPE_THERMOSTAT);
public static final Set<ThingTypeUID> METER_THING_TYPES_UIDS = Set.of(THING_TYPE_ENERGYMETER_LIVE,
THING_TYPE_ENERGYMETER, THING_TYPE_GASMETER, THING_TYPE_WATERMETER);
public static final Set<ThingTypeUID> ACCESS_THING_TYPES_UIDS = Set.of(THING_TYPE_ACCESS,
THING_TYPE_ACCESS_RINGANDCOMEIN);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream.of(BRIDGE_THING_TYPES_UIDS.stream(),
ACTION_THING_TYPES_UIDS.stream(), THERMOSTAT_THING_TYPES_UIDS.stream(), METER_THING_TYPES_UIDS.stream(),
ACCESS_THING_TYPES_UIDS.stream()).flatMap(i -> i).collect(Collectors.toSet());

// List of all Channel ids
public static final String CHANNEL_BUTTON = "button";
Expand All @@ -73,6 +81,19 @@ public class NikoHomeControlBindingConstants {
public static final String CHANNEL_HEATING_DEMAND = "heatingdemand";

public static final String CHANNEL_POWER = "power";
public static final String CHANNEL_ENERGY = "energy";
public static final String CHANNEL_GAS = "gas";
public static final String CHANNEL_WATER = "water";
public static final String CHANNEL_ENERGY_DAY = "energyday";
public static final String CHANNEL_GAS_DAY = "gasday";
public static final String CHANNEL_WATER_DAY = "waterday";
public static final String CHANNEL_ENERGY_LAST = "energylast";
public static final String CHANNEL_GAS_LAST = "gaslast";
public static final String CHANNEL_WATER_LAST = "waterlast";

public static final String CHANNEL_BELL_BUTTON = "bellbutton";
public static final String CHANNEL_RING_AND_COME_IN = "ringandcomein";
public static final String CHANNEL_LOCK = "lock";

public static final String CHANNEL_ALARM = "alarm";
public static final String CHANNEL_NOTICE = "notice";
Expand All @@ -87,11 +108,15 @@ public class NikoHomeControlBindingConstants {
// Thing config properties
public static final String CONFIG_ACTION_ID = "actionId";
public static final String CONFIG_STEP_VALUE = "step";
public static final String CONFIG_INVERT = "invert";

public static final String CONFIG_THERMOSTAT_ID = "thermostatId";
public static final String CONFIG_OVERRULETIME = "overruleTime";

public static final String CONFIG_ENERGYMETER_ID = "energyMeterId";
public static final String METER_ID = "meterId";
public static final String CONFIG_METER_REFRESH = "refresh";

public static final String CONFIG_ACCESS_ID = "accessId";

// Thing properties
public static final String PROPERTY_DEVICE_TYPE = "deviceType";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlAccessHandler;
import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlActionHandler;
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.NikoHomeControlMeterHandler;
import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlThermostatHandler;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.net.NetworkAddressService;
Expand Down Expand Up @@ -68,12 +69,14 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
} else {
return new NikoHomeControlBridgeHandler1((Bridge) thing, timeZoneProvider);
}
} else if (THING_TYPE_THERMOSTAT.equals(thing.getThingTypeUID())) {
return new NikoHomeControlThermostatHandler(thing);
} else if (THING_TYPE_ENERGYMETER.equals(thing.getThingTypeUID())) {
return new NikoHomeControlEnergyMeterHandler(thing);
} else if (ACTION_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
return new NikoHomeControlActionHandler(thing);
} else if (THERMOSTAT_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
return new NikoHomeControlThermostatHandler(thing);
} else if (METER_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
return new NikoHomeControlMeterHandler(thing);
} else if (ACCESS_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
return new NikoHomeControlAccessHandler(thing);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler;
import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler2;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAccess;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAction;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcEnergyMeter;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcMeter;
import org.openhab.binding.nikohomecontrol.internal.protocol.NhcThermostat;
import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
Expand Down Expand Up @@ -78,79 +80,121 @@ public void discoverDevices() {
}
logger.debug("getting devices on {}", thingHandler.getThing().getUID().getId());

discoverActionDevices(thingHandler, nhcComm);
discoverThermostatDevices(thingHandler, nhcComm);
discoverMeterDevices(thingHandler, nhcComm);
discoverAccessDevices(thingHandler, nhcComm);
}

private void discoverActionDevices(NikoHomeControlBridgeHandler bridgeHandler,
NikoHomeControlCommunication nhcComm) {
Map<String, NhcAction> actions = nhcComm.getActions();

actions.forEach((actionId, nhcAction) -> {
actions.forEach((deviceId, nhcAction) -> {
String thingName = nhcAction.getName();
String thingLocation = nhcAction.getLocation();

switch (nhcAction.getType()) {
case TRIGGER:
addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, thingHandler.getThing().getUID(), actionId),
actionId, thingName, thingLocation);
addDevice(new ThingUID(THING_TYPE_PUSHBUTTON, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACTION_ID, deviceId, thingName, thingLocation);
break;
case RELAY:
addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, thingHandler.getThing().getUID(), actionId),
actionId, thingName, thingLocation);
addDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACTION_ID, deviceId, thingName, thingLocation);
break;
case DIMMER:
addActionDevice(new ThingUID(THING_TYPE_DIMMABLE_LIGHT, thingHandler.getThing().getUID(), actionId),
actionId, thingName, thingLocation);
addDevice(new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACTION_ID, deviceId, thingName, thingLocation);
break;
case ROLLERSHUTTER:
addActionDevice(new ThingUID(THING_TYPE_BLIND, thingHandler.getThing().getUID(), actionId),
actionId, thingName, thingLocation);
addDevice(new ThingUID(THING_TYPE_BLIND, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACTION_ID, deviceId, thingName, thingLocation);
break;
default:
logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName);
logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), deviceId, thingName);
}
});
}

private void discoverThermostatDevices(NikoHomeControlBridgeHandler bridgeHandler,
NikoHomeControlCommunication nhcComm) {
Map<String, NhcThermostat> thermostats = nhcComm.getThermostats();

thermostats.forEach((thermostatId, nhcThermostat) -> {
thermostats.forEach((deviceId, nhcThermostat) -> {
String thingName = nhcThermostat.getName();
String thingLocation = nhcThermostat.getLocation();
addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, thingHandler.getThing().getUID(), thermostatId),
thermostatId, thingName, thingLocation);
addDevice(new ThingUID(THING_TYPE_THERMOSTAT, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_THERMOSTAT_ID, deviceId, thingName, thingLocation);
});
}

private void discoverMeterDevices(NikoHomeControlBridgeHandler bridgeHandler,
NikoHomeControlCommunication nhcComm) {
if (bridgeHandler instanceof NikoHomeControlBridgeHandler2) {
// disable discovery of NHC II energy meters to avoid overload in Niko Home Control cloud, can be removed
// when Niko solves their issue with the controller sending all live power data to their cloud
return;
}

Map<String, NhcMeter> meters = nhcComm.getMeters();

Map<String, NhcEnergyMeter> energyMeters = nhcComm.getEnergyMeters();
meters.forEach((deviceId, nhcMeter) -> {
String thingName = nhcMeter.getName();
String thingLocation = nhcMeter.getLocation();

energyMeters.forEach((energyMeterId, nhcEnergyMeter) -> {
String thingName = nhcEnergyMeter.getName();
String thingLocation = nhcEnergyMeter.getLocation();
addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, thingHandler.getThing().getUID(), energyMeterId),
energyMeterId, thingName, thingLocation);
switch (nhcMeter.getType()) {
case ENERGY_LIVE:
addDevice(new ThingUID(THING_TYPE_ENERGYMETER_LIVE, bridgeHandler.getThing().getUID(), deviceId),
METER_ID, deviceId, thingName, thingLocation);
break;
case ENERGY:
addDevice(new ThingUID(THING_TYPE_ENERGYMETER, bridgeHandler.getThing().getUID(), deviceId),
METER_ID, deviceId, thingName, thingLocation);
break;
case GAS:
addDevice(new ThingUID(THING_TYPE_GASMETER, bridgeHandler.getThing().getUID(), deviceId), METER_ID,
deviceId, thingName, thingLocation);
break;
case WATER:
addDevice(new ThingUID(THING_TYPE_WATERMETER, bridgeHandler.getThing().getUID(), deviceId),
METER_ID, deviceId, thingName, thingLocation);
break;
default:
logger.debug("unrecognized meter type {} for {} {}", nhcMeter.getType(), deviceId, thingName);
}
});
}

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)
.withRepresentationProperty(CONFIG_ACTION_ID);
if (thingLocation != null) {
discoveryResultBuilder.withProperty("Location", thingLocation);
}
thingDiscovered(discoveryResultBuilder.build());
}
private void discoverAccessDevices(NikoHomeControlBridgeHandler bridgeHandler,
NikoHomeControlCommunication nhcComm) {
Map<String, NhcAccess> accessDevices = nhcComm.getAccessDevices();

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)
.withRepresentationProperty(CONFIG_THERMOSTAT_ID);
if (thingLocation != null) {
discoveryResultBuilder.withProperty("Location", thingLocation);
}
thingDiscovered(discoveryResultBuilder.build());
accessDevices.forEach((deviceId, nhcAccess) -> {
String thingName = nhcAccess.getName();
String thingLocation = nhcAccess.getLocation();

switch (nhcAccess.getType()) {
case BASE:
case BELLBUTTON:
addDevice(new ThingUID(THING_TYPE_ACCESS, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACCESS_ID, deviceId, thingName, thingLocation);
break;
case RINGANDCOMEIN:
addDevice(
new ThingUID(THING_TYPE_ACCESS_RINGANDCOMEIN, bridgeHandler.getThing().getUID(), deviceId),
CONFIG_ACCESS_ID, deviceId, thingName, thingLocation);
break;
default:
logger.debug("unrecognized access type {} for {} {}", nhcAccess.getType(), deviceId, thingName);
}
});
}

private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName,
private void addDevice(ThingUID uid, String deviceIdKey, String deviceId, String thingName,
@Nullable String thingLocation) {
DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
.withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId)
.withRepresentationProperty(CONFIG_ENERGYMETER_ID);
.withLabel(thingName).withProperty(deviceIdKey, deviceId).withRepresentationProperty(deviceIdKey);
if (thingLocation != null) {
discoveryResultBuilder.withProperty("Location", thingLocation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* {@link NikoHomeControlEnergyMeterConfig} is the config class for Niko Home Control Thermostats.
* {@link NikoHomeControlAccessConfig} is the general config class for Niko Home Control Door Locks.
*
* @author Mark Herwege - Initial Contribution
*/
@NonNullByDefault
public class NikoHomeControlEnergyMeterConfig {
public String energyMeterId = "";
public class NikoHomeControlAccessConfig {
public String accessId = "";
}
Loading