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

[shelly] Support for Shelly BLU H&T #16413

Merged
merged 3 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.shelly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ The binding provides the same feature set across all devices as good as possible
| shellyblubutton | Shelly BLU Button 1 | SBBT |
| shellybludw | Shelly BLU Door/Windows | SBDW |
| shellyblumotion | Shelly BLU Motion | SBMO |
| shellybluht | Shelly BLU H&T | SBMO |

## Binding Configuration

Expand Down Expand Up @@ -1507,6 +1508,18 @@ See notes on discovery of Shelly BLU devices above.
| | lowBattery | Switch | yes | Low battery alert (< 20%) |
| device | gatewayDevice | String | yes | Shelly forwarded last status update (BLU gateway), could vary from packet to packet |

### Shelly BLU H&T(thing-type: shellybluht)

See notes on discovery of Shelly BLU devices above.

| Group | Channel | Type | read-only | Description |
| ------- | ------------- | -------- | --------- | ------------------------------------------------------- |
| sensors | temperature | Number | yes | Temperature, unit is reported by tempUnit |
| | humidity | Number | yes | Relative humidity in % |
| | lastUpdate | DateTime | yes | Timestamp of the last update (any sensor value changed) |
| battery | batteryLevel | Number | yes | Battery Level in % |
| | lowBattery | Switch | yes | Low battery alert (< 20%) |

## Shelly Wall Displays

| Group | Channel | Type | read-only | Description |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public class ShellyBindingConstants {
THING_TYPE_SHELLYBLUBUTTON, //
THING_TYPE_SHELLYBLUDW, //
THING_TYPE_SHELLYBLUMOTION, //
THING_TYPE_SHELLYBLUHT, //
THING_TYPE_SHELLYBLUGW, //

THING_TYPE_SHELLYPROTECTED, //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ public void initFromThingType(String name) {
isSmoke = thingType.equals(THING_TYPE_SHELLYSMOKE_STR) || thingType.equals(THING_TYPE_SHELLYPLUSSMOKE_STR);
boolean isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR);
boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR);
isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR);
isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR)
|| thingType.equals(THING_TYPE_SHELLYBLUHT_STR);
isDW = thingType.equals(THING_TYPE_SHELLYDOORWIN_STR) || thingType.equals(THING_TYPE_SHELLYDOORWIN2_STR)
|| thingType.equals(THING_TYPE_SHELLYBLUDW_STR);
isMotion = thingType.startsWith(THING_TYPE_SHELLYMOTION_STR)
Expand Down Expand Up @@ -429,6 +430,8 @@ public static String buildBluServiceName(String name, String mac) throws Illegal
return (THING_TYPE_SHELLYBLUDW_STR + "-" + mac).toLowerCase();
case SHELLYDT_BLUMOTION:
return (THING_TYPE_SHELLYBLUMOTION_STR + "-" + mac).toLowerCase();
case SHELLYDT_BLUHT:
return (THING_TYPE_SHELLYBLUHT_STR + "-" + mac).toLowerCase();
default:
throw new IllegalArgumentException("Unsupported BLU device model " + model);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,8 @@ public class Shelly2NotifyEventMessage {
public Integer motionState;
@SerializedName("Temperature")
public Double temperature;
@SerializedName("Humidity")
public Double humidity;

public Integer rssi;
public Integer tx_power;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorAccel;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorBat;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorHum;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorLux;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorState;
import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2NotifyEvent;
Expand Down Expand Up @@ -274,9 +275,16 @@ public void onNotifyEvent(Shelly2RpcNotifyEvent message) {
if (sensorData.tmp == null) {
sensorData.tmp = new ShellySensorTmp();
}
sensorData.tmp.units = SHELLY_TEMP_CELSIUS;
sensorData.tmp.tC = e.data.temperature;
sensorData.tmp.isValid = true;
}
if (e.data.humidity != null) {
if (sensorData.hum == null) {
sensorData.hum = new ShellySensorHum();
}
sensorData.hum.value = e.data.humidity;
}
if (e.data.rotation != null) {
if (sensorData.accel == null) {
sensorData.accel = new ShellySensorAccel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public class ShellyThingCreator {
public static final String SHELLYDT_BLUBUTTON = "SBBT";
public static final String SHELLYDT_BLUDW = "SBDW";
public static final String SHELLYDT_BLUMOTION = "SBMO";
public static final String SHELLYDT_BLUHT = "SBHT";
public static final String SHELLYDT_BLUGW = "SNGW-BT01";

// Thing names
Expand Down Expand Up @@ -202,6 +203,7 @@ public class ShellyThingCreator {
public static final String THING_TYPE_SHELLYBLUBUTTON_STR = THING_TYPE_SHELLYBLU_PREFIX + "button";
public static final String THING_TYPE_SHELLYBLUDW_STR = THING_TYPE_SHELLYBLU_PREFIX + "dw";
public static final String THING_TYPE_SHELLYBLUMOTION_STR = THING_TYPE_SHELLYBLU_PREFIX + "motion";
public static final String THING_TYPE_SHELLYBLUHT_STR = THING_TYPE_SHELLYBLU_PREFIX + "ht";
public static final String THING_TYPE_SHELLYBLUGW_STR = THING_TYPE_SHELLYBLU_PREFIX + "gw";

// Password protected or unknown device
Expand Down Expand Up @@ -324,6 +326,7 @@ public class ShellyThingCreator {
public static final ThingTypeUID THING_TYPE_SHELLYBLUDW = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYBLUDW_STR);
public static final ThingTypeUID THING_TYPE_SHELLYBLUMOTION = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYBLUMOTION_STR);
public static final ThingTypeUID THING_TYPE_SHELLYBLUHT = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYBLUHT_STR);
public static final ThingTypeUID THING_TYPE_SHELLYBLUGW = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYBLUGW_STR);

private static final Map<String, String> THING_TYPE_MAPPING = new LinkedHashMap<>();
Expand Down Expand Up @@ -409,6 +412,7 @@ public class ShellyThingCreator {
THING_TYPE_MAPPING.put(SHELLYDT_BLUBUTTON, THING_TYPE_SHELLYBLUBUTTON_STR);
THING_TYPE_MAPPING.put(SHELLYDT_BLUDW, THING_TYPE_SHELLYBLUDW_STR);
THING_TYPE_MAPPING.put(SHELLYDT_BLUMOTION, THING_TYPE_SHELLYBLUMOTION_STR);
THING_TYPE_MAPPING.put(SHELLYDT_BLUHT, THING_TYPE_SHELLYBLUHT_STR);
THING_TYPE_MAPPING.put(SHELLYDT_BLUGW, THING_TYPE_SHELLYBLUGW_STR);

// Wall displays
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public static void addBluThing(String gateway, Shelly2NotifyEvent e, @Nullable S
ttype = THING_TYPE_SHELLYBLUMOTION_STR;
tuid = THING_TYPE_SHELLYBLUMOTION;
break;
case SHELLYDT_BLUHT:
ttype = THING_TYPE_SHELLYBLUHT_STR;
tuid = THING_TYPE_SHELLYBLUHT;
break;
default:
logger.debug("{}: Unsupported BLU device model {}, MAC={}", gateway, model, mac);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public ShellyChannelDefinitions(@Reference ShellyTranslationProvider translation
// Device
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_NAME, "deviceName", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_GATEWAY, "gatewayDevice", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ITEMP, "deviceTemp", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ITEMP, "system:indoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_WAKEUP, "sensorWakeup", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS, "meterAccuWatts", ITEMT_POWER))
.add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL, "meterAccuTotal", ITEMT_ENERGY))
Expand Down Expand Up @@ -204,8 +204,9 @@ public ShellyChannelDefinitions(@Reference ShellyTranslationProvider translation
.add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_RESETTOTAL, "meterResetTotals", ITEMT_SWITCH))

// Sensors
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TEMP, "sensorTemp", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_HUM, "sensorHumidity", ITEMT_PERCENT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TEMP, "system:indoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_HUM, "system:atmospheric-humidity",
ITEMT_PERCENT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_LUX, "sensorLux", ITEMT_LUX))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ILLUM, "sensorIllumination", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VOLTAGE, "sensorADC", ITEMT_VOLT))
Expand Down Expand Up @@ -235,10 +236,13 @@ public ShellyChannelDefinitions(@Reference ShellyTranslationProvider translation
.add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_LAST_UPDATE, "lastUpdate", ITEMT_DATETIME))

// Addon with external sensors
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1, "sensorExtTemp", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2, "sensorExtTemp", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3, "sensorExtTemp", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY, "sensorExtHum", ITEMT_PERCENT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1, "system:outdoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2, "system:outdoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3, "system:outdoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4, "system:outdoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5, "system:outdoor-temperature", ITEMT_TEMP))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY, "system:atmospheric-humidity",
ITEMT_PERCENT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_VOLTAGE, "sensorExtVolt", ITEMT_VOLT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_INPUT1, "sensorContact", ITEMT_CONTACT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT, "sensorExtDigitalInput",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,10 @@ thing-type.shelly.shellyproem50.description = Shelly Pro EM-50 - 2xPower Meter +
thing-type.shelly.shellypro4pm.description = Shelly Pro 4PM - 4xRelay Switch with Power Meter

# BLU devices
thing-type.shelly.shellyblubutton.description = Shelly BLU Button 1
thing-type.shelly.shellyblubutton.description = Shelly BLU Button 1 / Button Tough 1
thing-type.shelly.shellybludw.description = Shelly BLU Door/Window Sensor
thing-type.shelly.shellyblumotion.description = Shelly BLU Motion Sensor
thing-type.shelly.shellybluht.description = Shelly BLU Shelly H&amp;T (Humidity &amp; Temperature Sensor)
thing-type.shelly.shellyblugw.description = Shelly BLU Gateway

# Wall Displays
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@
<config-description-ref uri="thing-type:shelly:blubattery"/>
</thing-type>

<thing-type id="shellybluht">
<label>Shelly BLU H&amp;T</label>
<description>@text/thing-type.shelly.shellybluht.description</description>
<category>Sensor</category>
<channel-groups>
<channel-group id="sensors" typeId="sensorData"/>
<channel-group id="battery" typeId="batteryStatus"/>
<channel-group id="device" typeId="deviceStatus"/>
</channel-groups>

<representation-property>serviceName</representation-property>
<config-description-ref uri="thing-type:shelly:blubattery"/>
</thing-type>

<thing-type id="shellyblugw">
<label>Shelly BLU Gateway</label>
<description>@text/thing-type.shelly.shellyblugw.description</description>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* This script uses the BLE scan functionality in scripting to pass scan results to openHAB
* Supported BLU Devices: BLU Button 1, BLU Door/Window, BLU Motion
* Version 0.2
* Supported BLU Devices: BLU Button 1, BLU Door/Window, BLU Motion, BLU H&T
* Version 0.3
*/

let ALLTERCO_DEVICE_NAME_PREFIX = ["SBBT", "SBDW", "SBMO"];
let ALLTERCO_DEVICE_NAME_PREFIX = ["SBBT", "SBDW", "SBMO", "SBHT"];
let ALLTERCO_MFD_ID_STR = "0ba9";
let BTHOME_SVC_ID_STR = "fcd2";

Expand All @@ -21,23 +21,34 @@ let uint16 = 2;
let int16 = 3;
let uint24 = 4;
let int24 = 5;
let uint32 = 6;
let int32 = 7;

let BTH = [];
BTH[0x00] = { n: "pid", t: uint8 };
BTH[0x01] = { n: "Battery", t: uint8, u: "%" };
BTH[0x02] = { n: "Temperature", t: int16, f: 0.01 };
BTH[0x03] = { n: "Humidity", t: uint16, f: 0.01 };
BTH[0x05] = { n: "Illuminance", t: uint24, f: 0.01 };
BTH[0x08] = { n: "Dewpoint", t: int16, f: 0.01 };
BTH[0x12] = { n: "Co2", t: uint16 };
BTH[0x14] = { n: "Moisture16", t: uint16, f: 0.01 };
BTH[0x14] = { n: "Moisture8", t: uint8 };
BTH[0x1a] = { n: "Door", t: uint8 };
BTH[0x20] = { n: "Moisture", t: uint8 };
BTH[0x21] = { n: "Motion", t: uint8 };
BTH[0x2d] = { n: "Window", t: uint8 };
BTH[0x3a] = { n: "Button", t: uint8 };
BTH[0x3f] = { n: "Rotation", t: int16, f: 0.1 };
BTH[0x43] = { n: "Current", t: uint16, f: 0.1 };
BTH[0x43] = { n: "UVIndex", t: uint8 };
BTH[0x51] = { n: "Acceleration", t: uint16, f: 0.1 };

function getByteSize(type) {
if (type === uint8 || type === int8) return 1;
if (type === uint16 || type === int16) return 2;
if (type === uint24 || type === int24) return 3;
if (type === uint32 || type === int32) return 4;
//impossible as advertisements are much smaller;
return 255;
}
Expand Down Expand Up @@ -67,6 +78,14 @@ let BTHomeDecoder = {
getInt24LE: function (buffer) {
return this.utoi(this.getUInt24LE(buffer), 24);
},
getUInt32LE: function (buffer) {
return (
(buffer.at(2) << 24) | (buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0)
);
},
getInt32LE: function (buffer) {
return this.utoi(this.getUInt32LE(buffer), 32);
},
getBufValue: function (type, buffer) {
if (buffer.length < getByteSize(type)) return null;
let res = null;
Expand All @@ -76,6 +95,8 @@ let BTHomeDecoder = {
if (type === int16) res = this.getInt16LE(buffer);
if (type === uint24) res = this.getUInt24LE(buffer);
if (type === int24) res = this.getInt24LE(buffer);
if (type === uint32) res = this.getUInt24LE(buffer);
if (type === int32) res = this.getInt24LE(buffer);
return res;
},
unpack: function (buffer) {
Expand All @@ -85,9 +106,8 @@ let BTHomeDecoder = {
let _dib = buffer.at(0);
result["encryption"] = _dib & 0x1 ? true : false;
result["BTHome_version"] = _dib >> 5;
if (result["BTHome_version"] !== 2) return null;
//Can not handle encrypted data
if (result["encryption"]) return result;
if (result["encryption"]) return result; // Can not handle encrypted data
if (result["BTHome_version"] !== 2) return null; // Can not handle BT version != 2
buffer = buffer.slice(1);

let _bth;
Expand Down Expand Up @@ -123,21 +143,23 @@ function scanCB(ev, res) {
// skip if there is no service_data member
if (typeof res.service_data === 'undefined' || typeof res.service_data[BTHOME_SVC_ID_STR] === 'undefined') return;
// skip if we have already found this device

if (typeof SHELLY_BLU_CACHE[res.addr] === 'undefined') {
if (typeof res.local_name === "undefined") console.log("res.local_name undefined")
if (typeof res.local_name !== 'string') return;
if (typeof res.local_name === "undefined") console.log("res.local_name undefined")
if (typeof res.local_name !== 'string') return;

let shellyBluNameIdx = 0;
for (shellyBluNameIdx in ALLTERCO_DEVICE_NAME_PREFIX) {
if (res.local_name.indexOf(ALLTERCO_DEVICE_NAME_PREFIX[shellyBluNameIdx]) === 0) {
console.log('New device found: address=', res.addr, ', name=', res.local_name);
Shelly.emitEvent("oh-blu.scan_result", {"addr":res.addr, "name":res.local_name, "rssi":res.rssi, "tx_power":res.tx_power_level});
SHELLY_BLU_CACHE[res.addr] = res.local_name;
}
}
}
}

let BTHparsed = ShellyBLUParser.getData(res); // skip if parsing failed
if (BTHparsed === null) {
if (BTHparsed === null) {
console.log("Failed to parse BTH data");
return;
}
Expand Down