| 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
| | 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 |
THING_TYPE_SHELLYBLUBUTTON, //
THING_TYPE_SHELLYBLUDW, //
THING_TYPE_SHELLYBLUMOTION, //
+ THING_TYPE_SHELLYBLUHT, //
THING_TYPE_SHELLYBLUGW, //
THING_TYPE_SHELLYPROTECTED, //
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)
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);
}
public Integer motionState;
@SerializedName("Temperature")
public Double temperature;
+ @SerializedName("Humidity")
+ public Double humidity;
public Integer rssi;
public Integer tx_power;
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;
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();
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
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
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<>();
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
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;
// 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))
.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))
.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",
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&T (Humidity & Temperature Sensor)
thing-type.shelly.shellyblugw.description = Shelly BLU Gateway
# Wall Displays
<config-description-ref uri="thing-type:shelly:blubattery"/>
</thing-type>
+ <thing-type id="shellybluht">
+ <label>Shelly BLU H&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>
/*
* 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";
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;
}
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;
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) {
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;
// 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;
}