mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[shelly] Support for Shelly BLU H&T (#16413)
* Support for Shelly BLU H&T added Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
parent
64801798d8
commit
51109f4d95
@ -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
|
||||
|
||||
@ -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 |
|
||||
|
@ -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, //
|
||||
|
@ -218,7 +218,8 @@ public class ShellyDeviceProfile {
|
||||
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)
|
||||
@ -429,6 +430,8 @@ public class ShellyDeviceProfile {
|
||||
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);
|
||||
}
|
||||
|
@ -1104,6 +1104,8 @@ public class Shelly2ApiJsonDTO {
|
||||
public Integer motionState;
|
||||
@SerializedName("Temperature")
|
||||
public Double temperature;
|
||||
@SerializedName("Humidity")
|
||||
public Double humidity;
|
||||
|
||||
public Integer rssi;
|
||||
public Integer tx_power;
|
||||
|
@ -33,6 +33,7 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettings
|
||||
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;
|
||||
@ -274,9 +275,16 @@ public class ShellyBluApi extends Shelly2ApiRpc {
|
||||
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();
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -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<>();
|
||||
@ -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
|
||||
|
@ -73,6 +73,10 @@ public class ShellyBluSensorHandler extends ShellyBaseHandler {
|
||||
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;
|
||||
|
@ -129,7 +129,7 @@ public class ShellyChannelDefinitions {
|
||||
// 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))
|
||||
@ -213,8 +213,9 @@ public class ShellyChannelDefinitions {
|
||||
.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))
|
||||
@ -244,10 +245,13 @@ public class ShellyChannelDefinitions {
|
||||
.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",
|
||||
|
@ -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&T (Humidity & Temperature Sensor)
|
||||
thing-type.shelly.shellyblugw.description = Shelly BLU Gateway
|
||||
|
||||
# Wall Displays
|
||||
|
@ -46,6 +46,20 @@
|
||||
<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>
|
||||
|
@ -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";
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
@ -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) {
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user