Skip to content

Commit

Permalink
[shelly] Support for Shelly BLU H&T (#16413)
Browse files Browse the repository at this point in the history
* Support for Shelly BLU H&T added

Signed-off-by: Markus Michels <markus7017@gmail.com>
  • Loading branch information
markus7017 committed Feb 18, 2024
1 parent 6480179 commit 51109f4
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 19 deletions.
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 @@ -1516,6 +1517,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 @@ -129,7 +129,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 @@ -213,8 +213,9 @@ public ShellyChannelDefinitions(@Reference ShellyTranslationProvider translation
.add(new ShellyChannel(m, CHGR_EMN, CHANNEL_NMETER_MISMATCH, "nmismatch", 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 @@ -244,10 +245,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

0 comments on commit 51109f4

Please sign in to comment.