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

[insteon] Added the ability to configure devices from the UI #8226

Merged
merged 2 commits into from
Aug 16, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
72 changes: 68 additions & 4 deletions bundles/org.openhab.binding.insteon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ The Insteon device is configured with the following required parameters:
|----------|-------------|
|address|Insteon or X10 address of the device. Insteon device addresses are in the format 'xx.xx.xx', and can be found on the device. X10 device address are in the format 'x.y' and are typically configured on the device.|
|productKey|Insteon binding product key that is used to identy the device. Every Insteon device type is uniquely identified by its Insteon product key, typically a six digit hex number. For some of the older device types (in particular the SwitchLinc switches and dimmers), Insteon does not give a product key, so an arbitrary fake one of the format Fxx.xx.xx (or Xxx.xx.xx for X10 devices) is assigned by the binding.|
|deviceConfig|Optional JSON object with device specific configuration. The JSON object will contain one or more key/value pairs.<br>If the key matches one of the channels associated with the device, the value must be an JSON object of key/value pairs. These key/value pairs will be assigned as parameters to the channel. The values must be either strings or integers.<br>Otherwise, the key is a parameter for the device and the type of the value will vary.|

The following is a list of the product keys and associated devices.
These have been tested and should work out of the box:
Expand Down Expand Up @@ -337,6 +338,15 @@ Bridge insteon:network:home [port="/dev/ttyUSB0"] {
}
```

Or

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="F00.00.11", deviceConfig="{'dimmer': {'dimmermax': 70}}"]
Thing device AABBCD [address="AA.BB.CD", productKey="F00.00.15", deviceConfig="{'dimmer': {'dimmermax': 60}}"]
}
```

**Items**

```
Expand Down Expand Up @@ -409,8 +419,6 @@ Then create entries in the .items file like this:
```

This will give you a contact, the battery level, and the light level.
Note that battery and light level are only updated when either there is motion, light level above/below threshold, tamper switch activated, or the sensor battery runs low.

The motion sensor II includes three additional channels:

**Items**
Expand All @@ -421,6 +429,24 @@ The motion sensor II includes three additional channels:
Number motionSensorTemperatureLevel "motion sensor temperature level" { channel="insteon:device:home:AABBCC:temperatureLevel" }
```

The battery, light level and temperature level are updated when either there is motion, light level above/below threshold, tamper switch activated, or the sensor battery runs low.
This is accomplished by querying the device for the data.
The motion sensor II will also periodically send data if the alternate heartbeat is enabled on the device.

If the alternate heartbeat is enabled, the device can be configured to not query the device and rely on the data from the alternate heartbeat.
Disabling the querying of the device should provide more accurate battery data since it appears to fluctuate with queries of the device.
This can be configured with the device configuration parameter of the device.
The key in the JSON object is `heartbeatOnly` and the value is a boolean:

**Things**

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="F00.00.24", deviceConfig="{'heartbeatOnly': true}"]
}

```

The temperature can be calculated in Fahrenheit using the following formulas:

* If the device is battery powered: `temperature = 0.73 * motionSensorTemperatureLevel - 20.53`
Expand Down Expand Up @@ -567,6 +593,14 @@ Bridge insteon:network:home [port="/dev/ttyUSB0"] {
}
```

Or

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="F00.00.15", deviceConfig="{'keypadButtonA': {'group': '0xf3'}, 'keypadButtonB': {'group': '0xf4'}, 'keypadButtonC': {'group': '0xf5'}, 'keypadButtonD': {'group': '0xf6'}}"]
}
```

The value after group must either be a number or string.
The hexadecimal value 0xf3 can either converted to a numeric value 243 or the string value "0xf3".

Expand Down Expand Up @@ -724,7 +758,7 @@ Further note that X10 devices are addressed with `houseCode.unitCode`, e.g. `A.2

The binding can command the modem to send broadcasts to a given Insteon group.
Since it is a broadcast message, the corresponding item does *not* take the address of any device, but of the modem itself.
The format is broadcastOnOff#X where X is the group that you want to be able to broadcast messages to:
The format is `broadcastOnOff#X` where X is the group that you want to be able to broadcast messages to:

**Things**

Expand All @@ -746,6 +780,18 @@ Bridge insteon:network:home [port="/dev/ttyUSB0"] {

Flipping this switch to "ON" will cause the modem to send a broadcast message with group=2, and all devices that are configured to respond to it should react.

Channels can also be configured using the device configuration parameter of the device.
The key in the JSON object is `broadcastGroups` and the value is an array of integers:

**Things**

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="0x000045", deviceConfig="{'broadcastGroups': [2]}"]
}

```

## Channel "related" Property

When an Insteon device changes its state because it is directly operated (for example by flipping a switch manually), it sends out a broadcast message to announce the state change, and the binding (if the PLM modem is properly linked as a responder) should update the corresponding openHAB items.
Expand All @@ -767,20 +813,38 @@ Bridge insteon:network:home [port="/dev/ttyUSB0"] {
}
```

Or

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="F00.00.11", deviceConfig="{'dimmer': {'related': 'AA.BB.DD'}}"]
Thing device AABBDD [address="AA.BB.DD", productKey="F00.00.11", deviceConfig="{'dimmer': {'related': 'AA.BB.CC'}}"]
}
```

Another scenario is a group broadcast message, the binding doesn't know which devices have responded to the message since its a broadcast message.
In this scenario, the "related" keyword can be used to have the binding poll one or more related device when group message are sent.
A typical example would be a switch configured to broadcast to a group, and one or more devices configured to respond to the message:

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="A.BB.CC", productKey="0x000045"] {
Thing device AABBCC [address="AA.BB.CC", productKey="0x000045"] {
Channels:
Type switch : broadcastOnOff#3 [related="AA.BB.DD"]
}
Thing device AABBDD [address="AA.BB.DD", productKey="F00.00.11"]
}
```

Or

```
Bridge insteon:network:home [port="/dev/ttyUSB0"] {
Thing device AABBCC [address="AA.BB.CC", productKey="0x000045", deviceConfig="{'broadcastGroups': [3], 'broadcastOnOff#3': {'related': 'AA.BB.DD'}}"]
Thing device AABBDD [address="AA.BB.DD", productKey="F00.00.11"]
}
```

More than one device can be polled by separating them with "+" sign, e.g. "related=aa.bb.cc+xx.yy.zz" would poll both of these devices.
The implemenation of the *related* keyword is simple: if you add it to a channel, and that channel changes its state, then the *related* device will be polled to see if its state has updated.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,15 @@ public void updateFeatureState(ChannelUID channelUID, State state) {
handler.updateState(channelUID, state);
}

public InsteonDevice makeNewDevice(InsteonAddress addr, String productKey) {
public InsteonDevice makeNewDevice(InsteonAddress addr, String productKey,
Map<String, @Nullable Object> deviceConfigMap) {
DeviceType dt = DeviceTypeLoader.instance().getDeviceType(productKey);
InsteonDevice dev = InsteonDevice.makeDevice(dt);
dev.setAddress(addr);
dev.setProductKey(productKey);
dev.setDriver(driver);
dev.setIsModem(productKey.equals(InsteonDeviceHandler.PLM_PRODUCT_KEY));
dev.setDeviceConfigMap(deviceConfigMap);
if (!dev.hasValidPollingInterval()) {
dev.setPollInterval(devicePollIntervalMilliseconds);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.binding.insteon.internal.config;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* The {@link InsteonDeviceConfiguration} class contains fields mapping thing configuration parameters.
Expand All @@ -28,11 +29,18 @@ public class InsteonDeviceConfiguration {
// required parameter
private String productKey = "";

// optional parameter
private @Nullable String deviceConfig;

public String getAddress() {
return address;
}

public String getProductKey() {
return productKey;
}

public @Nullable String getDeviceConfig() {
return deviceConfig;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static enum DeviceStatus {
private boolean hasModemDBEntry = false;
private DeviceStatus status = DeviceStatus.INITIALIZED;
private Map<Integer, @Nullable GroupMessageStateMachine> groupState = new HashMap<>();
private Map<String, @Nullable Object> deviceConfigMap = new HashMap<String, @Nullable Object>();

/**
* Constructor
Expand Down Expand Up @@ -191,7 +192,15 @@ public void setFeatureQueried(@Nullable DeviceFeature f) {
synchronized (mrequestQueue) {
featureQueried = f;
}
};
}

public void setDeviceConfigMap(Map<String, @Nullable Object> deviceConfigMap) {
this.deviceConfigMap = deviceConfigMap;
}

public Map<String, @Nullable Object> getDeviceConfigMap() {
return deviceConfigMap;
}

public @Nullable DeviceFeature getFeatureQueried() {
synchronized (mrequestQueue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,20 @@ protected double getDoubleParameter(String key, double def) {
return def;
}

protected boolean getBooleanDeviceConfig(String key, boolean def) {
Object o = feature.getDevice().getDeviceConfigMap().get(key);
if (o != null) {
if (o instanceof Boolean) {
return (Boolean) o;
} else {
logger.warn("{} {}: The value for the '{}' key is not boolean in the device configuration parameter.",
nm(), feature.getDevice().getAddress(), key);
}
}

return def;
}

/**
* Test if message refers to the button configured for given feature
*
Expand Down Expand Up @@ -1017,7 +1031,9 @@ public static class ClosedSleepingContactHandler extends MessageHandler {
public void handleMessage(int group, byte cmd1, Msg msg, DeviceFeature f) {
feature.publish(OpenClosedType.CLOSED, StateChangeType.ALWAYS);
if (f.getDevice().hasProductKey(InsteonDeviceHandler.MOTION_SENSOR_II_PRODUCT_KEY)) {
sendExtendedQuery(f, (byte) 0x2e, (byte) 03);
if (!getBooleanDeviceConfig("heartbeatOnly", false)) {
sendExtendedQuery(f, (byte) 0x2e, (byte) 03);
}
} else {
sendExtendedQuery(f, (byte) 0x2e, (byte) 00);
}
Expand All @@ -1034,7 +1050,9 @@ public static class OpenedSleepingContactHandler extends MessageHandler {
public void handleMessage(int group, byte cmd1, Msg msg, DeviceFeature f) {
feature.publish(OpenClosedType.OPEN, StateChangeType.ALWAYS);
if (f.getDevice().hasProductKey(InsteonDeviceHandler.MOTION_SENSOR_II_PRODUCT_KEY)) {
sendExtendedQuery(f, (byte) 0x2e, (byte) 03);
if (!getBooleanDeviceConfig("heartbeatOnly", false)) {
sendExtendedQuery(f, (byte) 0x2e, (byte) 03);
}
} else {
sendExtendedQuery(f, (byte) 0x2e, (byte) 00);
}
Expand Down
Loading