zigbee-herdsman-converters 14.0.496 → 14.0.499
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/converters/fromZigbee.js +100 -26
- package/converters/toZigbee.js +144 -6
- package/devices/awox.js +20 -1
- package/devices/danfoss.js +3 -2
- package/devices/fantem.js +17 -3
- package/devices/ikea.js +2 -2
- package/devices/keen_home.js +1 -1
- package/devices/lonsonho.js +1 -1
- package/devices/miboxer.js +25 -0
- package/devices/namron.js +166 -12
- package/devices/niko.js +60 -18
- package/devices/orvibo.js +7 -0
- package/devices/philips.js +9 -0
- package/devices/tuya.js +3 -2
- package/devices/xiaomi.js +9 -2
- package/lib/exposes.js +1 -1
- package/lib/tuya.js +7 -0
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -1652,6 +1652,77 @@ const converters = {
|
|
|
1652
1652
|
// #endregion
|
|
1653
1653
|
|
|
1654
1654
|
// #region Non-generic converters
|
|
1655
|
+
namron_thermostat: {
|
|
1656
|
+
cluster: 'hvacThermostat',
|
|
1657
|
+
type: ['attributeReport', 'readResponse'],
|
|
1658
|
+
convert: (model, msg, publish, options, meta) => {
|
|
1659
|
+
const result = {};
|
|
1660
|
+
const data = msg.data;
|
|
1661
|
+
if (data.hasOwnProperty(0x1000)) { // Display brightness
|
|
1662
|
+
const lookup = {0: 'low', 1: 'mid', 2: 'high'};
|
|
1663
|
+
result.lcd_brightness = lookup[data[0x1000]];
|
|
1664
|
+
}
|
|
1665
|
+
if (data.hasOwnProperty(0x1001)) { // Button vibration level
|
|
1666
|
+
const lookup = {0: 'off', 1: 'low', 2: 'high'};
|
|
1667
|
+
result.button_vibration_level = lookup[data[0x1001]];
|
|
1668
|
+
}
|
|
1669
|
+
if (data.hasOwnProperty(0x1002)) { // Floor sensor type
|
|
1670
|
+
const lookup = {1: '10k', 2: '15k', 3: '50k', 4: '100k', 5: '12k'};
|
|
1671
|
+
result.floor_sensor_type = lookup[data[0x1002]];
|
|
1672
|
+
}
|
|
1673
|
+
if (data.hasOwnProperty(0x1003)) { // Sensor
|
|
1674
|
+
const lookup = {0: 'air', 1: 'floor', 2: 'both'};
|
|
1675
|
+
result.sensor = lookup[data[0x1003]];
|
|
1676
|
+
}
|
|
1677
|
+
if (data.hasOwnProperty(0x1004)) { // PowerUpStatus
|
|
1678
|
+
const lookup = {0: 'default', 1: 'last_status'};
|
|
1679
|
+
result.powerup_status = lookup[data[0x1004]];
|
|
1680
|
+
}
|
|
1681
|
+
if (data.hasOwnProperty(0x1005)) { // FloorSensorCalibration
|
|
1682
|
+
result.floor_sensor_calibration = precisionRound(data[0x1005], 2) / 10;
|
|
1683
|
+
}
|
|
1684
|
+
if (data.hasOwnProperty(0x1006)) { // DryTime
|
|
1685
|
+
result.dry_time = data[0x1006];
|
|
1686
|
+
}
|
|
1687
|
+
if (data.hasOwnProperty(0x1007)) { // ModeAfterDry
|
|
1688
|
+
const lookup = {0: 'off', 1: 'manual', 2: 'auto', 3: 'away'};
|
|
1689
|
+
result.mode_after_dry = lookup[data[0x1007]];
|
|
1690
|
+
}
|
|
1691
|
+
if (data.hasOwnProperty(0x1008)) { // TemperatureDisplay
|
|
1692
|
+
const lookup = {0: 'room', 1: 'floor'};
|
|
1693
|
+
result.temperature_display = lookup[data[0x1008]];
|
|
1694
|
+
}
|
|
1695
|
+
if (data.hasOwnProperty(0x1009)) { // WindowOpenCheck
|
|
1696
|
+
result.window_open_check = data[0x1009];
|
|
1697
|
+
}
|
|
1698
|
+
if (data.hasOwnProperty(0x100A)) { // Hysterersis
|
|
1699
|
+
result.hysterersis = data[0x100A];
|
|
1700
|
+
}
|
|
1701
|
+
if (data.hasOwnProperty(0x100B)) { // DisplayAutoOffEnable
|
|
1702
|
+
const lookup = {0: 'enable', 1: 'disable'};
|
|
1703
|
+
result.display_auto_off_enabled = lookup[data[0x100B]];
|
|
1704
|
+
}
|
|
1705
|
+
if (data.hasOwnProperty(0x2001)) { // AlarmAirTempOverValue
|
|
1706
|
+
result.alarm_airtemp_overvalue = data[0x2001];
|
|
1707
|
+
}
|
|
1708
|
+
if (data.hasOwnProperty(0x2002)) { // Away Mode Set
|
|
1709
|
+
result.away_mode = data[0x2002] ? 'ON' : 'OFF';
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
return result;
|
|
1713
|
+
},
|
|
1714
|
+
},
|
|
1715
|
+
namron_hvac_user_interface: {
|
|
1716
|
+
cluster: 'hvacUserInterfaceCfg',
|
|
1717
|
+
type: ['attributeReport', 'readResponse'],
|
|
1718
|
+
convert: (model, msg, publish, options, meta) => {
|
|
1719
|
+
const result = {};
|
|
1720
|
+
if (msg.data.hasOwnProperty('keypadLockout')) { // Set as child lock instead as keypadlockout
|
|
1721
|
+
result.child_lock = msg.data['keypadLockout'] === 0 ? 'UNLOCK' : 'LOCK';
|
|
1722
|
+
}
|
|
1723
|
+
return result;
|
|
1724
|
+
},
|
|
1725
|
+
},
|
|
1655
1726
|
elko_thermostat: {
|
|
1656
1727
|
cluster: 'hvacThermostat',
|
|
1657
1728
|
type: ['attributeReport', 'readResponse'],
|
|
@@ -4223,7 +4294,6 @@ const converters = {
|
|
|
4223
4294
|
const dpValue = tuya.firstDpValue(msg, meta, 'tuya_air_quality');
|
|
4224
4295
|
const dp = dpValue.dp;
|
|
4225
4296
|
const value = tuya.getDataValue(dpValue);
|
|
4226
|
-
const swapPM25CO2 = ['_TZE200_ryfmq5rl', '_TZE200_dwcarsat'];
|
|
4227
4297
|
switch (dp) {
|
|
4228
4298
|
case tuya.dataPoints.tuyaSabTemp:
|
|
4229
4299
|
return {temperature: calibrateAndPrecisionRoundOptions(value / 10, options, 'temperature')};
|
|
@@ -4231,15 +4301,17 @@ const converters = {
|
|
|
4231
4301
|
return {humidity: calibrateAndPrecisionRoundOptions(value / 10, options, 'humidity')};
|
|
4232
4302
|
// DP22: Smart Air Box: Formaldehyd, Smart Air Housekeeper: co2
|
|
4233
4303
|
case tuya.dataPoints.tuyaSabFormaldehyd:
|
|
4234
|
-
if (
|
|
4304
|
+
if (['_TZE200_dwcarsat', '_TZE200_ryfmq5rl'].includes(meta.device.manufacturerName)) {
|
|
4235
4305
|
return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
|
|
4236
4306
|
} else {
|
|
4237
4307
|
return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd')};
|
|
4238
4308
|
}
|
|
4239
4309
|
// DP2: Smart Air Box: co2, Smart Air Housekeeper: MP25
|
|
4240
4310
|
case tuya.dataPoints.tuyaSabCO2:
|
|
4241
|
-
if (
|
|
4311
|
+
if (meta.device.manufacturerName === '_TZE200_dwcarsat') {
|
|
4242
4312
|
return {pm25: calibrateAndPrecisionRoundOptions(value, options, 'pm25')};
|
|
4313
|
+
} else if (meta.device.manufacturerName === '_TZE200_ryfmq5rl') {
|
|
4314
|
+
return {formaldehyd: calibrateAndPrecisionRoundOptions(value, options, 'formaldehyd')};
|
|
4243
4315
|
} else {
|
|
4244
4316
|
return {co2: calibrateAndPrecisionRoundOptions(value, options, 'co2')};
|
|
4245
4317
|
}
|
|
@@ -4692,7 +4764,7 @@ const converters = {
|
|
|
4692
4764
|
},
|
|
4693
4765
|
tuya_data_point_dump: {
|
|
4694
4766
|
cluster: 'manuSpecificTuya',
|
|
4695
|
-
type: ['commandDataResponse', 'commandDataReport', 'commandActiveStatusReport'],
|
|
4767
|
+
type: ['commandDataResponse', 'commandDataReport', 'commandActiveStatusReport', 'commandActiveStatusReportAlt'],
|
|
4696
4768
|
convert: (model, msg, publis, options, meta) => {
|
|
4697
4769
|
// Don't use in production!
|
|
4698
4770
|
// Used in: https://www.zigbee2mqtt.io/how_tos/how_to_support_new_tuya_devices.html
|
|
@@ -5800,19 +5872,9 @@ const converters = {
|
|
|
5800
5872
|
return result;
|
|
5801
5873
|
},
|
|
5802
5874
|
},
|
|
5803
|
-
xiaomi_curtain_acn002_position: {
|
|
5804
|
-
cluster: 'genAnalogOutput',
|
|
5805
|
-
type: ['attributeReport', 'readResponse'],
|
|
5806
|
-
options: [exposes.options.invert_cover()],
|
|
5807
|
-
convert: (model, msg, publish, options, meta) => {
|
|
5808
|
-
let position = precisionRound(msg.data['presentValue'], 2);
|
|
5809
|
-
position = options.invert_cover ? 100 - position : position;
|
|
5810
|
-
return {position: position};
|
|
5811
|
-
},
|
|
5812
|
-
},
|
|
5813
5875
|
xiaomi_curtain_acn002_status: {
|
|
5814
5876
|
cluster: 'genMultistateOutput',
|
|
5815
|
-
type: ['attributeReport'
|
|
5877
|
+
type: ['attributeReport'],
|
|
5816
5878
|
convert: (model, msg, publish, options, meta) => {
|
|
5817
5879
|
let running = false;
|
|
5818
5880
|
const data = msg.data;
|
|
@@ -7255,22 +7317,34 @@ const converters = {
|
|
|
7255
7317
|
},
|
|
7256
7318
|
ZB006X_settings: {
|
|
7257
7319
|
cluster: 'manuSpecificTuya',
|
|
7258
|
-
type: ['
|
|
7320
|
+
type: ['commandActiveStatusReport', 'commandActiveStatusReportAlt'],
|
|
7259
7321
|
convert: (model, msg, publish, options, meta) => {
|
|
7260
7322
|
const dpValue = tuya.firstDpValue(msg, meta, 'ZB006X_settings');
|
|
7261
7323
|
const dp = dpValue.dp;
|
|
7262
7324
|
const value = tuya.getDataValue(dpValue);
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
return {
|
|
7266
|
-
|
|
7267
|
-
|
|
7325
|
+
switch (dp) {
|
|
7326
|
+
case tuya.dataPoints.fantemPowerSupplyMode:
|
|
7327
|
+
return {power_supply_mode: {0: 'unknown', 1: 'no_neutral', 2: 'with_neutral'}[value]};
|
|
7328
|
+
case tuya.dataPoints.fantemExtSwitchType:
|
|
7329
|
+
return {ext_switch_type: {0: 'unknown', 1: 'toggle_sw', 2: 'momentary_sw', 3: 'rotary_sw',
|
|
7330
|
+
4: 'auto_config'}[value]};
|
|
7331
|
+
case tuya.dataPoints.fantemLoadDetectionMode:
|
|
7268
7332
|
return {load_detection_mode: {0: 'none', 1: 'first_power_on', 2: 'every_power_on'}[value]};
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7333
|
+
case tuya.dataPoints.fantemExtSwitchStatus:
|
|
7334
|
+
return {ext_switch_status: value};
|
|
7335
|
+
case tuya.dataPoints.fantemControlMode:
|
|
7336
|
+
return {control_mode: {0: 'ext_switch', 1: 'remote', 2: 'both'}[value]};
|
|
7337
|
+
case 111:
|
|
7338
|
+
// Value 0 is received after each device power-on. No idea what it means.
|
|
7339
|
+
return;
|
|
7340
|
+
case tuya.dataPoints.fantemLoadType:
|
|
7341
|
+
// Not sure if 0 is 'resistive' and 2 is 'resistive_inductive'.
|
|
7342
|
+
// If you see 'unknown', pls. check with Tuya gateway and app and update with label shown in Tuya app.
|
|
7343
|
+
return {load_type: {0: 'unknown', 1: 'resistive_capacitive', 2: 'unknown', 3: 'detecting'}[value]};
|
|
7344
|
+
case tuya.dataPoints.fantemLoadDimmable:
|
|
7345
|
+
return {load_dimmable: {0: 'unknown', 1: 'dimmable', 2: 'not_dimmable'}[value]};
|
|
7346
|
+
default:
|
|
7347
|
+
meta.logger.warn(`fz.ZB006X_settings: Unhandled DP|Value [${dp}|${value}][${JSON.stringify(dpValue)}]`);
|
|
7274
7348
|
}
|
|
7275
7349
|
},
|
|
7276
7350
|
},
|
package/converters/toZigbee.js
CHANGED
|
@@ -11,6 +11,7 @@ const libColor = require('../lib/color');
|
|
|
11
11
|
const exposes = require('../lib/exposes');
|
|
12
12
|
|
|
13
13
|
const manufacturerOptions = {
|
|
14
|
+
sunricher: {manufacturerCode: herdsman.Zcl.ManufacturerCode.SHENZHEN_SUNRICH},
|
|
14
15
|
xiaomi: {manufacturerCode: herdsman.Zcl.ManufacturerCode.LUMI_UNITED_TECH, disableDefaultResponse: true},
|
|
15
16
|
osram: {manufacturerCode: herdsman.Zcl.ManufacturerCode.OSRAM},
|
|
16
17
|
eurotronic: {manufacturerCode: herdsman.Zcl.ManufacturerCode.JENNIC},
|
|
@@ -791,7 +792,7 @@ const converters = {
|
|
|
791
792
|
},
|
|
792
793
|
},
|
|
793
794
|
light_onoff_brightness: {
|
|
794
|
-
key: ['state', 'brightness', 'brightness_percent'],
|
|
795
|
+
key: ['state', 'brightness', 'brightness_percent', 'on_time'],
|
|
795
796
|
options: [exposes.options.transition()],
|
|
796
797
|
convertSet: async (entity, key, value, meta) => {
|
|
797
798
|
const {message} = meta;
|
|
@@ -2438,6 +2439,20 @@ const converters = {
|
|
|
2438
2439
|
} else {
|
|
2439
2440
|
await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped, entity));
|
|
2440
2441
|
}
|
|
2442
|
+
|
|
2443
|
+
if (!['ZNCLDJ11LM', 'ZNJLBL01LM'].includes(meta.mapped.model)) {
|
|
2444
|
+
// The code below is originally added for ZNCLDJ11LM (Koenkk/zigbee2mqtt#4585).
|
|
2445
|
+
// However, in Koenkk/zigbee-herdsman-converters#4039 it was replaced by reading
|
|
2446
|
+
// directly from currentPositionLiftPercentage, so that device is excluded.
|
|
2447
|
+
// For ZNJLBL01LM, in Koenkk/zigbee-herdsman-converters#4163 the position is read
|
|
2448
|
+
// through onEvent each time the motor stops, so it becomes redundant, and the
|
|
2449
|
+
// device is excluded.
|
|
2450
|
+
// The code is left here to avoid breaking compatibility, ideally all devices using
|
|
2451
|
+
// this converter should be tested so the code can be adjusted/deleted.
|
|
2452
|
+
|
|
2453
|
+
// Xiaomi curtain does not send position update on stop, request this.
|
|
2454
|
+
await entity.read('genAnalogOutput', [0x0055]);
|
|
2455
|
+
}
|
|
2441
2456
|
} else {
|
|
2442
2457
|
const lookup = {'open': 100, 'close': 0, 'on': 100, 'off': 0};
|
|
2443
2458
|
|
|
@@ -3005,6 +3020,127 @@ const converters = {
|
|
|
3005
3020
|
await entity.read('closuresWindowCovering', [isPosition ? 'currentPositionLiftPercentage' : 'currentPositionTiltPercentage']);
|
|
3006
3021
|
},
|
|
3007
3022
|
},
|
|
3023
|
+
namron_thermostat: {
|
|
3024
|
+
key: [
|
|
3025
|
+
'lcd_brightness', 'button_vibration_level', 'floor_sensor_type', 'sensor', 'powerup_status', 'floor_sensor_calibration',
|
|
3026
|
+
'dry_time', 'mode_after_dry', 'temperature_display', 'window_open_check', 'hysterersis', 'display_auto_off_enabled',
|
|
3027
|
+
'alarm_airtemp_overvalue', 'away_mode',
|
|
3028
|
+
],
|
|
3029
|
+
convertSet: async (entity, key, value, meta) => {
|
|
3030
|
+
if (key === 'lcd_brightness') {
|
|
3031
|
+
const lookup = {'low': 0, 'mid': 1, 'high': 2};
|
|
3032
|
+
const payload = {0x1000: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3033
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3034
|
+
} else if (key === 'button_vibration_level') {
|
|
3035
|
+
const lookup = {'off': 0, 'low': 1, 'high': 2};
|
|
3036
|
+
const payload = {0x1001: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3037
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3038
|
+
} else if (key === 'floor_sensor_type') {
|
|
3039
|
+
const lookup = {'10k': 1, '15k': 2, '50k': 3, '100k': 4, '12k': 5};
|
|
3040
|
+
const payload = {0x1002: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3041
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3042
|
+
} else if (key === 'sensor') {
|
|
3043
|
+
const lookup = {'air': 0, 'floor': 1, 'both': 2};
|
|
3044
|
+
const payload = {0x1003: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3045
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3046
|
+
} else if (key==='powerup_status') {
|
|
3047
|
+
const lookup = {'default': 0, 'last_status': 1};
|
|
3048
|
+
const payload = {0x1004: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3049
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3050
|
+
} else if (key==='floor_sensor_calibration') {
|
|
3051
|
+
const payload = {0x1005: {value: Math.round(value * 10), type: 0x28}}; // INT8S
|
|
3052
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3053
|
+
} else if (key==='dry_time') {
|
|
3054
|
+
const payload = {0x1006: {value: value, type: 0x20}}; // INT8U
|
|
3055
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3056
|
+
} else if (key==='mode_after_dry') {
|
|
3057
|
+
const lookup = {'off': 0, 'manual': 1, 'auto': 2, 'away': 3};
|
|
3058
|
+
const payload = {0x1007: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3059
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3060
|
+
} else if (key==='temperature_display') {
|
|
3061
|
+
const lookup = {'room': 0, 'floor': 1};
|
|
3062
|
+
const payload = {0x1008: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3063
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3064
|
+
} else if (key==='window_open_check') {
|
|
3065
|
+
const payload = {0x1009: {value: Math.round(value * 10), type: 0x20}};
|
|
3066
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3067
|
+
} else if (key==='hysterersis') {
|
|
3068
|
+
const payload = {0x100A: {value: Math.round(value * 10), type: 0x20}};
|
|
3069
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3070
|
+
} else if (key==='display_auto_off_enabled') {
|
|
3071
|
+
const lookup = {'enable': 0, 'disabled': 1};
|
|
3072
|
+
const payload = {0x100B: {value: lookup[value], type: herdsman.Zcl.DataType.enum8}};
|
|
3073
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3074
|
+
} else if (key==='alarm_airtemp_overvalue') {
|
|
3075
|
+
const payload = {0x2001: {value: value, type: 0x20}};
|
|
3076
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3077
|
+
} else if (key==='away_mode') {
|
|
3078
|
+
const payload = {0x2002: {value: Number(value==='ON'), type: 0x30}};
|
|
3079
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
|
|
3080
|
+
}
|
|
3081
|
+
},
|
|
3082
|
+
convertGet: async (entity, key, meta) => {
|
|
3083
|
+
switch (key) {
|
|
3084
|
+
case 'lcd_brightness':
|
|
3085
|
+
await entity.read('hvacThermostat', [0x1000], manufacturerOptions.sunricher);
|
|
3086
|
+
break;
|
|
3087
|
+
case 'button_vibration_level':
|
|
3088
|
+
await entity.read('hvacThermostat', [0x1001], manufacturerOptions.sunricher);
|
|
3089
|
+
break;
|
|
3090
|
+
case 'floor_sensor_type':
|
|
3091
|
+
await entity.read('hvacThermostat', [0x1002], manufacturerOptions.sunricher);
|
|
3092
|
+
break;
|
|
3093
|
+
case 'sensor':
|
|
3094
|
+
await entity.read('hvacThermostat', [0x1003], manufacturerOptions.sunricher);
|
|
3095
|
+
break;
|
|
3096
|
+
case 'powerup_status':
|
|
3097
|
+
await entity.read('hvacThermostat', [0x1004], manufacturerOptions.sunricher);
|
|
3098
|
+
break;
|
|
3099
|
+
case 'floor_sensor_calibration':
|
|
3100
|
+
await entity.read('hvacThermostat', [0x1005], manufacturerOptions.sunricher);
|
|
3101
|
+
break;
|
|
3102
|
+
case 'dry_time':
|
|
3103
|
+
await entity.read('hvacThermostat', [0x1006], manufacturerOptions.sunricher);
|
|
3104
|
+
break;
|
|
3105
|
+
case 'mode_after_dry':
|
|
3106
|
+
await entity.read('hvacThermostat', [0x1007], manufacturerOptions.sunricher);
|
|
3107
|
+
break;
|
|
3108
|
+
case 'temperature_display':
|
|
3109
|
+
await entity.read('hvacThermostat', [0x1008], manufacturerOptions.sunricher);
|
|
3110
|
+
break;
|
|
3111
|
+
case 'window_open_check':
|
|
3112
|
+
await entity.read('hvacThermostat', [0x1009], manufacturerOptions.sunricher);
|
|
3113
|
+
break;
|
|
3114
|
+
case 'hysterersis':
|
|
3115
|
+
await entity.read('hvacThermostat', [0x100A], manufacturerOptions.sunricher);
|
|
3116
|
+
break;
|
|
3117
|
+
case 'display_auto_off_enabled':
|
|
3118
|
+
await entity.read('hvacThermostat', [0x100B], manufacturerOptions.sunricher);
|
|
3119
|
+
break;
|
|
3120
|
+
case 'alarm_airtemp_overvalue':
|
|
3121
|
+
await entity.read('hvacThermostat', [0x2001], manufacturerOptions.sunricher);
|
|
3122
|
+
break;
|
|
3123
|
+
case 'away_mode':
|
|
3124
|
+
await entity.read('hvacThermostat', [0x2002], manufacturerOptions.sunricher);
|
|
3125
|
+
break;
|
|
3126
|
+
|
|
3127
|
+
default: // Unknown key
|
|
3128
|
+
throw new Error(`Unhandled key toZigbee.namron_thermostat.convertGet ${key}`);
|
|
3129
|
+
}
|
|
3130
|
+
},
|
|
3131
|
+
|
|
3132
|
+
},
|
|
3133
|
+
namron_thermostat_child_lock: {
|
|
3134
|
+
key: ['child_lock'],
|
|
3135
|
+
convertSet: async (entity, key, value, meta) => {
|
|
3136
|
+
const keypadLockout = Number(value==='LOCK');
|
|
3137
|
+
await entity.write('hvacUserInterfaceCfg', {keypadLockout});
|
|
3138
|
+
return {readAfterWriteTime: 250, state: {child_lock: value}};
|
|
3139
|
+
},
|
|
3140
|
+
convertGet: async (entity, key, meta) => {
|
|
3141
|
+
await entity.read('hvacUserInterfaceCfg', ['keypadLockout']);
|
|
3142
|
+
},
|
|
3143
|
+
},
|
|
3008
3144
|
connecte_thermostat: {
|
|
3009
3145
|
key: [
|
|
3010
3146
|
'child_lock', 'current_heating_setpoint', 'local_temperature_calibration', 'max_temperature_protection', 'window_detection',
|
|
@@ -6373,17 +6509,19 @@ const converters = {
|
|
|
6373
6509
|
convertSet: async (entity, key, value, meta) => {
|
|
6374
6510
|
switch (key) {
|
|
6375
6511
|
case 'ext_switch_type':
|
|
6376
|
-
await tuya.sendDataPointEnum(entity,
|
|
6377
|
-
'momentary_sw': 2, 'rotary_sw': 3, 'auto_config': 4}[value]);
|
|
6512
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.fantemExtSwitchType, {'unknown': 0, 'toggle_sw': 1,
|
|
6513
|
+
'momentary_sw': 2, 'rotary_sw': 3, 'auto_config': 4}[value], 'sendData');
|
|
6378
6514
|
break;
|
|
6379
6515
|
case 'load_detection_mode':
|
|
6380
|
-
await tuya.sendDataPointEnum(entity,
|
|
6516
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.fantemLoadDetectionMode, {'none': 0, 'first_power_on': 1,
|
|
6517
|
+
'every_power_on': 2}[value], 'sendData');
|
|
6381
6518
|
break;
|
|
6382
6519
|
case 'control_mode':
|
|
6383
|
-
await tuya.sendDataPointEnum(entity,
|
|
6520
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.fantemControlMode, {'ext_switch': 0, 'remote': 1,
|
|
6521
|
+
'both': 2}[value], 'sendData');
|
|
6384
6522
|
break;
|
|
6385
6523
|
default: // Unknown key
|
|
6386
|
-
throw new Error(`
|
|
6524
|
+
throw new Error(`tz.ZB006X_settings: Unhandled key ${key}`);
|
|
6387
6525
|
}
|
|
6388
6526
|
},
|
|
6389
6527
|
},
|
package/devices/awox.js
CHANGED
|
@@ -224,11 +224,30 @@ module.exports = [
|
|
|
224
224
|
},
|
|
225
225
|
],
|
|
226
226
|
},
|
|
227
|
+
{
|
|
228
|
+
type: 'Router', manufacturerName: 'AwoX', modelID: 'TLSR82xx', endpoints: [
|
|
229
|
+
{
|
|
230
|
+
ID: 1,
|
|
231
|
+
profileID: 260,
|
|
232
|
+
deviceID: 268,
|
|
233
|
+
inputClusters: [0, 3, 4, 5, 6, 8, 768, 4096, 64599, 10],
|
|
234
|
+
outputClusters: [6],
|
|
235
|
+
},
|
|
236
|
+
{ID: 242, profileID: 41440, deviceID: 97, inputClusters: [], outputClusters: [33]},
|
|
237
|
+
{
|
|
238
|
+
ID: 3,
|
|
239
|
+
profileID: 4751,
|
|
240
|
+
deviceID: 268,
|
|
241
|
+
inputClusters: [65360, 65361],
|
|
242
|
+
outputClusters: [65360, 65361],
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
},
|
|
227
246
|
],
|
|
228
247
|
model: '33957',
|
|
229
248
|
vendor: 'AwoX',
|
|
230
249
|
description: 'LED light with color temperature',
|
|
231
|
-
extend: extend.light_onoff_brightness_colortemp(),
|
|
250
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
|
|
232
251
|
},
|
|
233
252
|
{
|
|
234
253
|
fingerprint: [
|
package/devices/danfoss.js
CHANGED
|
@@ -45,7 +45,7 @@ module.exports = [
|
|
|
45
45
|
.withDescription('Whether or not the unit needs warm water. `false` No Heat Request or `true` Heat Request'),
|
|
46
46
|
exposes.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally'])
|
|
47
47
|
.withDescription('Values observed are `0` (manual), `1` (schedule) or `2` (externally)'),
|
|
48
|
-
exposes.climate().withSetpoint('occupied_heating_setpoint', 5,
|
|
48
|
+
exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 35, 0.5).withLocalTemperature().withPiHeatingDemand()
|
|
49
49
|
.withSystemMode(['heat']).withRunningState(['idle', 'heat'], ea.STATE),
|
|
50
50
|
exposes.numeric('external_measured_room_sensor', ea.ALL)
|
|
51
51
|
.withDescription('If `radiator_covered` is `true`: Set at maximum 30 minutes interval but not more often than every ' +
|
|
@@ -79,7 +79,8 @@ module.exports = [
|
|
|
79
79
|
.withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
|
|
80
80
|
.withValueMin(-8000).withValueMax(2000),
|
|
81
81
|
exposes.numeric('load_estimate', ea.STATE_GET)
|
|
82
|
-
.withDescription('Load estimate on this radiator')
|
|
82
|
+
.withDescription('Load estimate on this radiator')
|
|
83
|
+
.withValueMin(-8000).withValueMax(3600),
|
|
83
84
|
exposes.binary('preheat_status', ea.STATE_GET, true, false)
|
|
84
85
|
.withDescription('Specific for pre-heat running in Zigbee Weekly Schedule mode'),
|
|
85
86
|
exposes.enum('adaptation_run_status', ea.STATE_GET, ['none', 'in_progress', 'found', 'lost'])
|
package/devices/fantem.js
CHANGED
|
@@ -5,6 +5,7 @@ const e = exposes.presets;
|
|
|
5
5
|
const ea = exposes.access;
|
|
6
6
|
const extend = require('../lib/extend');
|
|
7
7
|
const reporting = require('../lib/reporting');
|
|
8
|
+
const tuya = require('../lib/tuya');
|
|
8
9
|
|
|
9
10
|
module.exports = [
|
|
10
11
|
{
|
|
@@ -13,21 +14,34 @@ module.exports = [
|
|
|
13
14
|
vendor: 'Fantem',
|
|
14
15
|
description: 'Smart dimmer module without neutral',
|
|
15
16
|
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
16
|
-
fromZigbee: [...extend.light_onoff_brightness({noConfigure: true}).fromZigbee,
|
|
17
|
-
fz.command_move, fz.command_stop, fz.ZB006X_settings],
|
|
17
|
+
fromZigbee: [...extend.light_onoff_brightness({noConfigure: true}).fromZigbee,
|
|
18
|
+
fz.command_on, fz.command_off, fz.command_move, fz.command_stop, fz.ZB006X_settings],
|
|
18
19
|
toZigbee: [...extend.light_onoff_brightness({noConfigure: true}).toZigbee, tz.ZB006X_settings],
|
|
19
20
|
exposes: [e.light_brightness(),
|
|
20
21
|
e.action(['on', 'off', 'brightness_move_down', 'brightness_move_up', 'brightness_stop']),
|
|
22
|
+
exposes.enum('control_mode', ea.STATE_SET, ['ext_switch', 'remote', 'both']).withDescription('Control mode'),
|
|
21
23
|
exposes.enum('ext_switch_type', ea.STATE_SET, ['unknown', 'toggle_sw', 'momentary_sw', 'rotary_sw', 'auto_config'])
|
|
22
24
|
.withDescription('External switch type'),
|
|
25
|
+
exposes.numeric('ext_switch_status', ea.STATE).withDescription('External switch status')
|
|
26
|
+
.withValueMin(-10000).withValueMax(10000),
|
|
23
27
|
exposes.enum('load_detection_mode', ea.STATE_SET, ['none', 'first_power_on', 'every_power_on'])
|
|
24
28
|
.withDescription('Load detection mode'),
|
|
25
|
-
|
|
29
|
+
// If you see load_type 'unknown', pls. check with Tuya gateway and app and update with label from Tuya app.
|
|
30
|
+
exposes.enum('load_type', ea.STATE, ['unknown', 'resistive_capacitive', 'unknown', 'detecting'])
|
|
31
|
+
.withDescription('Load type'),
|
|
32
|
+
exposes.enum('load_dimmable', ea.STATE, ['unknown', 'dimmable', 'not_dimmable'])
|
|
33
|
+
.withDescription('Load dimmable'),
|
|
34
|
+
exposes.enum('power_supply_mode', ea.STATE, ['unknown', 'no_neutral', 'with_neutral'])
|
|
35
|
+
.withDescription('Power supply mode'),
|
|
26
36
|
],
|
|
27
37
|
meta: {disableActionGroup: true},
|
|
38
|
+
onEvent: tuya.onEventSetLocalTime,
|
|
28
39
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
29
40
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
30
41
|
const endpoint = device.getEndpoint(1);
|
|
42
|
+
// Enables reporting of physical state changes
|
|
43
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/9057#issuecomment-1007742130
|
|
44
|
+
await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
|
|
31
45
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
32
46
|
await reporting.onOff(endpoint);
|
|
33
47
|
},
|
package/devices/ikea.js
CHANGED
|
@@ -796,10 +796,10 @@ module.exports = [
|
|
|
796
796
|
extend: tradfriExtend.light_onoff_brightness(),
|
|
797
797
|
},
|
|
798
798
|
{
|
|
799
|
-
zigbeeModel: ['TRADFRIbulbGU10WS345lm', 'TRADFRI bulb GU10 WW 345lm'],
|
|
799
|
+
zigbeeModel: ['TRADFRIbulbGU10WS345lm', 'TRADFRI bulb GU10 WW 345lm', 'TRADFRIbulbGU10WS380lm'],
|
|
800
800
|
model: 'LED2005R5',
|
|
801
801
|
vendor: 'IKEA',
|
|
802
|
-
description: 'TRADFRI LED bulb GU10 345 lumen, dimmable, white spectrum',
|
|
802
|
+
description: 'TRADFRI LED bulb GU10 345/380 lumen, dimmable, white spectrum',
|
|
803
803
|
extend: tradfriExtend.light_onoff_brightness_colortemp(),
|
|
804
804
|
},
|
|
805
805
|
{
|
package/devices/keen_home.js
CHANGED
|
@@ -41,7 +41,7 @@ module.exports = [
|
|
|
41
41
|
exposes: [e.cover_position().setAccess('state', ea.ALL), e.temperature(), e.battery(), e.pressure()],
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
zigbeeModel: ['SV02-410-MP-1.3', 'SV02-412-MP-1.3', 'SV02-610-MP-1.3', 'SV02-612-MP-1.3', 'SV02-410-MP-1.0'],
|
|
44
|
+
zigbeeModel: ['SV02-410-MP-1.3', 'SV02-412-MP-1.3', 'SV02-610-MP-1.3', 'SV02-612-MP-1.3', 'SV02-410-MP-1.0', 'SV02-410-MP-1.2'],
|
|
45
45
|
model: 'SV02',
|
|
46
46
|
vendor: 'Keen Home',
|
|
47
47
|
description: 'Smart vent',
|
package/devices/lonsonho.js
CHANGED
|
@@ -127,7 +127,7 @@ module.exports = [
|
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
|
-
fingerprint: [{modelID: 'TS110F', manufacturerName: '_TZ3000_92chsky7'}],
|
|
130
|
+
fingerprint: [{modelID: 'TS110F', manufacturerName: '_TZ3000_92chsky7'}, {modelID: 'TS110E', manufacturerName: '_TZ3210_4ubylghk'}],
|
|
131
131
|
model: 'QS-Zigbee-D02-TRIAC-2C-L',
|
|
132
132
|
vendor: 'Lonsonho',
|
|
133
133
|
description: '2 gang smart dimmer switch module without neutral',
|
package/devices/miboxer.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
2
3
|
const tz = require('../converters/toZigbee');
|
|
3
4
|
const e = exposes.presets;
|
|
4
5
|
const ea = exposes.access;
|
|
@@ -47,4 +48,28 @@ module.exports = [
|
|
|
47
48
|
vendor: 'Miboxer',
|
|
48
49
|
extend: extend.light_onoff_brightness_colortemp_color({disableColorTempStartup: true, colorTempRange: [153, 500]}),
|
|
49
50
|
},
|
|
51
|
+
{
|
|
52
|
+
fingerprint: [{manufacturerName: '_TZ3000_xwh1e22x'}],
|
|
53
|
+
model: 'FUT089Z',
|
|
54
|
+
vendor: 'MiBoxer',
|
|
55
|
+
description: 'RGB+CCT Remote',
|
|
56
|
+
fromZigbee: [fz.battery],
|
|
57
|
+
toZigbee: [],
|
|
58
|
+
exposes: [e.battery(), e.battery_voltage()],
|
|
59
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
60
|
+
const endpoint = device.getEndpoint(1);
|
|
61
|
+
await endpoint.read('genBasic', ['manufacturerName', 'zclVersion', 'appVersion', 'modelId', 'powerSource', 0xfffe]);
|
|
62
|
+
await endpoint.command('genGroups', 'miboxerSetZones', {zones: [
|
|
63
|
+
{zoneNum: 1, groupId: 101},
|
|
64
|
+
{zoneNum: 2, groupId: 102},
|
|
65
|
+
{zoneNum: 3, groupId: 103},
|
|
66
|
+
{zoneNum: 4, groupId: 104},
|
|
67
|
+
{zoneNum: 5, groupId: 105},
|
|
68
|
+
{zoneNum: 6, groupId: 106},
|
|
69
|
+
{zoneNum: 7, groupId: 107},
|
|
70
|
+
{zoneNum: 8, groupId: 108},
|
|
71
|
+
]});
|
|
72
|
+
await endpoint.command('genBasic', 'tuyaSetup', {}, {disableDefaultResponse: true});
|
|
73
|
+
},
|
|
74
|
+
},
|
|
50
75
|
];
|
package/devices/namron.js
CHANGED
|
@@ -263,29 +263,68 @@ module.exports = [
|
|
|
263
263
|
model: '4512737/4512738',
|
|
264
264
|
vendor: 'Namron',
|
|
265
265
|
description: 'Touch termostat',
|
|
266
|
-
fromZigbee: [fz.thermostat, fz.
|
|
266
|
+
fromZigbee: [fz.thermostat, fz.namron_thermostat, fz.metering, fz.electrical_measurement,
|
|
267
|
+
fz.namron_hvac_user_interface],
|
|
267
268
|
toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint, tz.thermostat_occupancy,
|
|
268
269
|
tz.thermostat_local_temperature_calibration, tz.thermostat_local_temperature, tz.thermostat_outdoor_temperature,
|
|
269
270
|
tz.thermostat_system_mode, tz.thermostat_control_sequence_of_operation, tz.thermostat_running_state,
|
|
270
|
-
tz.
|
|
271
|
+
tz.namron_thermostat_child_lock, tz.namron_thermostat],
|
|
271
272
|
exposes: [
|
|
272
273
|
e.local_temperature(),
|
|
273
274
|
exposes.numeric('outdoor_temperature', ea.STATE_GET).withUnit('°C')
|
|
274
275
|
.withDescription('Current temperature measured from the floor sensor'),
|
|
275
|
-
e.keypad_lockout(),
|
|
276
276
|
exposes.climate()
|
|
277
|
-
.withSetpoint('occupied_heating_setpoint',
|
|
277
|
+
.withSetpoint('occupied_heating_setpoint', 0, 40, 0.1)
|
|
278
278
|
.withLocalTemperature()
|
|
279
279
|
.withLocalTemperatureCalibration(-30, 30, 0.1)
|
|
280
280
|
.withSystemMode(['off', 'auto', 'heat'])
|
|
281
281
|
.withRunningState(['idle', 'heat']),
|
|
282
|
+
exposes.binary('away_mode', ea.ALL, 'ON', 'OFF')
|
|
283
|
+
.withDescription('Enable/disable away mode'),
|
|
284
|
+
exposes.binary('child_lock', ea.ALL, 'LOCK', 'UNLOCK')
|
|
285
|
+
.withDescription('Enables/disables physical input on the device'),
|
|
282
286
|
e.power(), e.current(), e.voltage(), e.energy(),
|
|
287
|
+
exposes.enum('lcd_brightness', ea.ALL, ['low', 'mid', 'high'])
|
|
288
|
+
.withDescription('OLED brightness when operating the buttons. Default: Medium.'),
|
|
289
|
+
exposes.enum('button_vibration_level', ea.ALL, ['off', 'low', 'high'])
|
|
290
|
+
.withDescription('Key beep volume and vibration level. Default: Low.'),
|
|
291
|
+
exposes.enum('floor_sensor_type', ea.ALL, ['10k', '15k', '50k', '100k', '12k'])
|
|
292
|
+
.withDescription('Type of the external floor sensor. Default: NTC 10K/25.'),
|
|
293
|
+
exposes.enum('sensor', ea.ALL, ['air', 'floor', 'both'])
|
|
294
|
+
.withDescription('The sensor used for heat control. Default: Room Sensor.'),
|
|
295
|
+
exposes.enum('powerup_status', ea.ALL, ['default', 'last_status'])
|
|
296
|
+
.withDescription('The mode after a power reset. Default: Previous Mode.'),
|
|
297
|
+
exposes.numeric('floor_sensor_calibration', ea.ALL)
|
|
298
|
+
.withUnit('°C')
|
|
299
|
+
.withValueMin(-3).withValueMax(3).withValueStep(0.1)
|
|
300
|
+
.withDescription('The tempearatue calibration for the exernal floor sensor, between -3 and 3 in 0.1°C. Default: 0.'),
|
|
301
|
+
exposes.numeric('dry_time', ea.ALL)
|
|
302
|
+
.withUnit('min')
|
|
303
|
+
.withValueMin(5).withValueMax(100)
|
|
304
|
+
.withDescription('The duration of Dry Mode, between 5 and 100 minutes. Default: 5.'),
|
|
305
|
+
exposes.enum('mode_after_dry', ea.ALL, ['off', 'manual', 'auto', 'away'])
|
|
306
|
+
.withDescription('The mode after Dry Mode. Default: Auto.'),
|
|
307
|
+
exposes.enum('temperature_display', ea.ALL, ['room', 'floor'])
|
|
308
|
+
.withDescription('The temperature on the display. Default: Room Temperature.'),
|
|
309
|
+
exposes.numeric('window_open_check', ea.ALL)
|
|
310
|
+
.withUnit('°C')
|
|
311
|
+
.withValueMin(3).withValueMax(8).withValueStep(0.5)
|
|
312
|
+
.withDescription('The threshold to detect window open, between 3 and 8 in 0.5 °C. Default: 0 (disabled).'),
|
|
313
|
+
exposes.numeric('hysterersis', ea.ALL)
|
|
314
|
+
.withUnit('°C')
|
|
315
|
+
.withValueMin(5).withValueMax(20).withValueStep(0.1)
|
|
316
|
+
.withDescription('Hysteresis setting, between 5 and 20 in 0.1 °C. Default: 5.'),
|
|
317
|
+
exposes.enum('display_auto_off_enabled', ea.ALL, ['enable', 'disabled']),
|
|
318
|
+
exposes.numeric('alarm_airtemp_overvalue', ea.ALL)
|
|
319
|
+
.withUnit('°C')
|
|
320
|
+
.withValueMin(20).withValueMax(60).withValueStep(1)
|
|
321
|
+
.withDescription('Room temperature alarm threshold, between 20 and 60 in °C. 0 means disabled. Default: 45.'),
|
|
283
322
|
],
|
|
284
323
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
285
324
|
const endpoint = device.getEndpoint(1);
|
|
286
325
|
const binds = [
|
|
287
|
-
'genBasic', 'genIdentify', '
|
|
288
|
-
'
|
|
326
|
+
'genBasic', 'genIdentify', 'hvacThermostat', 'seMetering', 'haElectricalMeasurement', 'genAlarms',
|
|
327
|
+
'msOccupancySensing', 'genTime', 'hvacUserInterfaceCfg',
|
|
289
328
|
];
|
|
290
329
|
await reporting.bind(endpoint, coordinatorEndpoint, binds);
|
|
291
330
|
|
|
@@ -302,15 +341,130 @@ module.exports = [
|
|
|
302
341
|
reportableChange: null,
|
|
303
342
|
}]);
|
|
304
343
|
|
|
344
|
+
await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor', 'acCurrentMultiplier']);
|
|
345
|
+
await endpoint.read('haElectricalMeasurement', ['acCurrentDivisor']);
|
|
346
|
+
|
|
305
347
|
await reporting.activePower(endpoint);
|
|
306
|
-
await reporting.
|
|
307
|
-
await reporting.
|
|
308
|
-
await reporting.rmsCurrent(endpoint);
|
|
309
|
-
await reporting.rmsVoltage(endpoint);
|
|
348
|
+
await reporting.rmsCurrent(endpoint, {min: 10, change: 10});
|
|
349
|
+
await reporting.rmsVoltage(endpoint, {min: 10});
|
|
310
350
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
351
|
+
await reporting.currentSummDelivered(endpoint);
|
|
352
|
+
|
|
353
|
+
// Custom attributes
|
|
354
|
+
const options = {manufacturerCode: 0x1224};
|
|
355
|
+
|
|
356
|
+
// OperateDisplayLcdBrightnesss
|
|
357
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
358
|
+
attribute: {ID: 0x1000, type: 0x30},
|
|
359
|
+
minimumReportInterval: 0,
|
|
360
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
361
|
+
reportableChange: null}],
|
|
362
|
+
options);
|
|
363
|
+
// ButtonVibrationLevel
|
|
364
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
365
|
+
attribute: {ID: 0x1001, type: 0x30},
|
|
366
|
+
minimumReportInterval: 0,
|
|
367
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
368
|
+
reportableChange: null}],
|
|
369
|
+
options);
|
|
370
|
+
// FloorSensorType
|
|
371
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
372
|
+
attribute: {ID: 0x1002, type: 0x30},
|
|
373
|
+
minimumReportInterval: 0,
|
|
374
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
375
|
+
reportableChange: null}],
|
|
376
|
+
options);
|
|
377
|
+
// ControlType
|
|
378
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
379
|
+
attribute: {ID: 0x1003, type: 0x30},
|
|
380
|
+
minimumReportInterval: 0,
|
|
381
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
382
|
+
reportableChange: null}],
|
|
383
|
+
options);
|
|
384
|
+
// PowerUpStatus
|
|
385
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
386
|
+
attribute: {ID: 0x1004, type: 0x30},
|
|
387
|
+
minimumReportInterval: 0,
|
|
388
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
389
|
+
reportableChange: null}],
|
|
390
|
+
options);
|
|
391
|
+
// FloorSensorCalibration
|
|
392
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
393
|
+
attribute: {ID: 0x1005, type: 0x28},
|
|
394
|
+
minimumReportInterval: 0,
|
|
395
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
396
|
+
reportableChange: 0}],
|
|
397
|
+
options);
|
|
398
|
+
// DryTime
|
|
399
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
400
|
+
attribute: {ID: 0x1006, type: 0x20},
|
|
401
|
+
minimumReportInterval: 0,
|
|
402
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
403
|
+
reportableChange: 0}],
|
|
404
|
+
options);
|
|
405
|
+
// ModeAfterDry
|
|
406
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
407
|
+
attribute: {ID: 0x1007, type: 0x30},
|
|
408
|
+
minimumReportInterval: 0,
|
|
409
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
410
|
+
reportableChange: null}],
|
|
411
|
+
options);
|
|
412
|
+
// TemperatureDisplay
|
|
413
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
414
|
+
attribute: {ID: 0x1008, type: 0x30},
|
|
415
|
+
minimumReportInterval: 0,
|
|
416
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
417
|
+
reportableChange: null}],
|
|
418
|
+
options);
|
|
419
|
+
// WindowOpenCheck
|
|
420
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
421
|
+
attribute: {ID: 0x1009, type: 0x20},
|
|
422
|
+
minimumReportInterval: 0,
|
|
423
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
424
|
+
reportableChange: 0}],
|
|
425
|
+
options);
|
|
426
|
+
|
|
427
|
+
// Hysterersis
|
|
428
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
429
|
+
attribute: {ID: 0x100A, type: 0x20},
|
|
430
|
+
minimumReportInterval: 0,
|
|
431
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
432
|
+
reportableChange: 0}],
|
|
433
|
+
options);
|
|
434
|
+
// DisplayAutoOffEnable
|
|
435
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
436
|
+
attribute: {ID: 0x100B, type: 0x30},
|
|
437
|
+
minimumReportInterval: 0,
|
|
438
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
439
|
+
reportableChange: null}],
|
|
440
|
+
options);
|
|
441
|
+
|
|
442
|
+
// AlarmAirTempOverValue
|
|
443
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
444
|
+
attribute: {ID: 0x2001, type: 0x20},
|
|
445
|
+
minimumReportInterval: 0,
|
|
446
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
447
|
+
reportableChange: 0}],
|
|
448
|
+
options);
|
|
449
|
+
// Away Mode Set
|
|
450
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
451
|
+
attribute: {ID: 0x2002, type: 0x30},
|
|
452
|
+
minimumReportInterval: 0,
|
|
453
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
454
|
+
reportableChange: null}],
|
|
455
|
+
options);
|
|
456
|
+
|
|
457
|
+
// Device does not asks for the time with binding, we need to write time during configure
|
|
458
|
+
const time = Math.round(((new Date()).getTime() - constants.OneJanuary2000) / 1000);
|
|
459
|
+
const values = {time: time};
|
|
460
|
+
endpoint.write('genTime', values);
|
|
311
461
|
|
|
312
|
-
// Trigger read
|
|
313
|
-
await endpoint.read('hvacThermostat', ['systemMode', 'runningState', '
|
|
462
|
+
// Trigger initial read
|
|
463
|
+
await endpoint.read('hvacThermostat', ['systemMode', 'runningState', 'occupiedHeatingSetpoint']);
|
|
464
|
+
await endpoint.read('hvacThermostat', [0x1000, 0x1001, 0x1002, 0x1003], options);
|
|
465
|
+
await endpoint.read('hvacThermostat', [0x1004, 0x1005, 0x1006, 0x1007], options);
|
|
466
|
+
await endpoint.read('hvacThermostat', [0x1008, 0x1009, 0x100A, 0x100B], options);
|
|
467
|
+
await endpoint.read('hvacThermostat', [0x2001, 0x2002], options);
|
|
314
468
|
},
|
|
315
469
|
},
|
|
316
470
|
];
|
package/devices/niko.js
CHANGED
|
@@ -5,33 +5,47 @@ const reporting = require('../lib/reporting');
|
|
|
5
5
|
const e = exposes.presets;
|
|
6
6
|
const ea = exposes.access;
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const local = {
|
|
9
9
|
fz: {
|
|
10
10
|
switch_operation_mode: {
|
|
11
|
-
cluster: '
|
|
11
|
+
cluster: 'manuSpecificNiko1',
|
|
12
12
|
type: ['attributeReport', 'readResponse'],
|
|
13
13
|
convert: (model, msg, publish, options, meta) => {
|
|
14
14
|
const state = {};
|
|
15
|
-
if (msg.data.hasOwnProperty('
|
|
15
|
+
if (msg.data.hasOwnProperty('switchOperationMode')) {
|
|
16
16
|
const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
17
17
|
const operationModeMap = {0x02: 'control_relay', 0x01: 'decoupled', 0x00: 'unknown'};
|
|
18
|
-
state[operationModeProperty] = operationModeMap[msg.data.
|
|
18
|
+
state[operationModeProperty] = operationModeMap[msg.data.switchOperationMode];
|
|
19
19
|
}
|
|
20
20
|
return state;
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
23
|
switch_action: {
|
|
24
|
-
cluster: '
|
|
24
|
+
cluster: 'manuSpecificNiko2',
|
|
25
25
|
type: ['attributeReport', 'readResponse'],
|
|
26
26
|
convert: (model, msg, publish, options, meta) => {
|
|
27
27
|
const state = {};
|
|
28
28
|
|
|
29
|
-
if (msg.data.hasOwnProperty('
|
|
29
|
+
if (msg.data.hasOwnProperty('switchAction')) {
|
|
30
30
|
// NOTE: a single press = two seperate values reported, 16 followed by 64
|
|
31
31
|
// a hold/release cyle = three seperate values, 16, 32, and 48
|
|
32
32
|
const actionProperty = `action${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
33
33
|
const actionMap = {16: null, 64: 'single', 32: 'hold', 48: 'release'};
|
|
34
|
-
state[actionProperty] = actionMap[msg.data.
|
|
34
|
+
state[actionProperty] = actionMap[msg.data.switchAction];
|
|
35
|
+
}
|
|
36
|
+
return state;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
outlet: {
|
|
40
|
+
cluster: 'manuSpecificNiko1',
|
|
41
|
+
type: ['attributeReport', 'readResponse'],
|
|
42
|
+
convert: (model, msg, publish, options, meta) => {
|
|
43
|
+
const state = {};
|
|
44
|
+
if (msg.data.hasOwnProperty('outletChildLock')) {
|
|
45
|
+
state['child_lock'] = (msg.data['outletChildLock'] == 0 ? 'LOCK' : 'UNLOCK');
|
|
46
|
+
}
|
|
47
|
+
if (msg.data.hasOwnProperty('outletLedState')) {
|
|
48
|
+
state['led_enable'] = (msg.data['outletLedState'] == 1);
|
|
35
49
|
}
|
|
36
50
|
return state;
|
|
37
51
|
},
|
|
@@ -48,12 +62,32 @@ const fzLocal = {
|
|
|
48
62
|
throw new Error(`operation_mode was called with an invalid value (${value})`);
|
|
49
63
|
} else {
|
|
50
64
|
const operationModeProperty = `operation_mode${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`;
|
|
51
|
-
await entity.write('
|
|
65
|
+
await entity.write('manuSpecificNiko1', {'switchOperationMode': operationModeLookup[value]});
|
|
52
66
|
return {state: {[operationModeProperty]: value.toLowerCase()}};
|
|
53
67
|
}
|
|
54
68
|
},
|
|
55
69
|
convertGet: async (entity, key, meta) => {
|
|
56
|
-
await entity.read('
|
|
70
|
+
await entity.read('manuSpecificNiko1', ['switchOperationMode']);
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
outlet_child_lock: {
|
|
74
|
+
key: ['child_lock'],
|
|
75
|
+
convertSet: async (entity, key, value, meta) => {
|
|
76
|
+
await entity.write('manuSpecificNiko1', {'outletChildLock': ((value.toLowerCase() === 'lock') ? 0 : 1)});
|
|
77
|
+
return {state: {child_lock: ((value.toLowerCase() === 'lock') ? 'LOCK' : 'UNLOCK')}};
|
|
78
|
+
},
|
|
79
|
+
convertGet: async (entity, key, meta) => {
|
|
80
|
+
await entity.read('manuSpecificNiko1', ['outletChildLock']);
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
outlet_led_enable: {
|
|
84
|
+
key: ['led_enable'],
|
|
85
|
+
convertSet: async (entity, key, value, meta) => {
|
|
86
|
+
await entity.write('manuSpecificNiko1', {'outletLedState': ((value) ? 1 : 0)});
|
|
87
|
+
return {state: {led_enable: ((value) ? true : false)}};
|
|
88
|
+
},
|
|
89
|
+
convertGet: async (entity, key, meta) => {
|
|
90
|
+
await entity.read('manuSpecificNiko1', ['outletLedState']);
|
|
57
91
|
},
|
|
58
92
|
},
|
|
59
93
|
},
|
|
@@ -65,8 +99,11 @@ module.exports = [
|
|
|
65
99
|
model: '170-33505',
|
|
66
100
|
vendor: 'Niko',
|
|
67
101
|
description: 'Connected socket outlet',
|
|
68
|
-
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
|
|
69
|
-
toZigbee: [
|
|
102
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, local.fz.outlet],
|
|
103
|
+
toZigbee: [
|
|
104
|
+
tz.on_off, tz.electrical_measurement_power, tz.currentsummdelivered,
|
|
105
|
+
local.tz.outlet_child_lock, local.tz.outlet_led_enable,
|
|
106
|
+
],
|
|
70
107
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
71
108
|
const endpoint = device.getEndpoint(1);
|
|
72
109
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
@@ -83,11 +120,16 @@ module.exports = [
|
|
|
83
120
|
|
|
84
121
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
85
122
|
await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
|
|
123
|
+
|
|
124
|
+
await endpoint.read('manuSpecificNiko1', ['outletChildLock']);
|
|
125
|
+
await endpoint.read('manuSpecificNiko1', ['outletLedState']);
|
|
86
126
|
},
|
|
87
127
|
exposes: [
|
|
88
128
|
e.switch(),
|
|
89
129
|
e.power().withAccess(ea.STATE_GET), e.current(), e.voltage(),
|
|
90
130
|
e.energy().withAccess(ea.STATE_GET),
|
|
131
|
+
exposes.binary('child_lock', ea.ALL, 'LOCK', 'UNLOCK').withDescription('Enables/disables physical input on the device'),
|
|
132
|
+
exposes.binary('led_enable', ea.ALL, true, false).withDescription('Enable LED'),
|
|
91
133
|
],
|
|
92
134
|
},
|
|
93
135
|
{
|
|
@@ -134,13 +176,13 @@ module.exports = [
|
|
|
134
176
|
model: '552-721X1',
|
|
135
177
|
vendor: 'Niko',
|
|
136
178
|
description: 'Single connectable switch',
|
|
137
|
-
fromZigbee: [fz.on_off,
|
|
138
|
-
toZigbee: [tz.on_off,
|
|
179
|
+
fromZigbee: [fz.on_off, local.fz.switch_operation_mode, local.fz.switch_action],
|
|
180
|
+
toZigbee: [tz.on_off, local.tz.switch_operation_mode],
|
|
139
181
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
140
182
|
const endpoint = device.getEndpoint(1);
|
|
141
183
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
142
184
|
await reporting.onOff(endpoint);
|
|
143
|
-
await endpoint.read('
|
|
185
|
+
await endpoint.read('manuSpecificNiko1', ['switchOperationMode']);
|
|
144
186
|
},
|
|
145
187
|
exposes: [
|
|
146
188
|
e.switch(),
|
|
@@ -153,8 +195,8 @@ module.exports = [
|
|
|
153
195
|
model: '552-721X2',
|
|
154
196
|
vendor: 'Niko',
|
|
155
197
|
description: 'Double connectable switch',
|
|
156
|
-
fromZigbee: [fz.on_off,
|
|
157
|
-
toZigbee: [tz.on_off,
|
|
198
|
+
fromZigbee: [fz.on_off, local.fz.switch_operation_mode, local.fz.switch_action],
|
|
199
|
+
toZigbee: [tz.on_off, local.tz.switch_operation_mode],
|
|
158
200
|
endpoint: (device) => {
|
|
159
201
|
return {'l1': 1, 'l2': 2};
|
|
160
202
|
},
|
|
@@ -166,8 +208,8 @@ module.exports = [
|
|
|
166
208
|
await reporting.bind(ep2, coordinatorEndpoint, ['genOnOff']);
|
|
167
209
|
await reporting.onOff(ep1);
|
|
168
210
|
await reporting.onOff(ep2);
|
|
169
|
-
await ep1.read('
|
|
170
|
-
await ep2.read('
|
|
211
|
+
await ep1.read('manuSpecificNiko1', ['switchOperationMode']);
|
|
212
|
+
await ep2.read('manuSpecificNiko1', ['switchOperationMode']);
|
|
171
213
|
},
|
|
172
214
|
exposes: [
|
|
173
215
|
e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
|
package/devices/orvibo.js
CHANGED
|
@@ -6,6 +6,13 @@ const extend = require('../lib/extend');
|
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
|
|
8
8
|
module.exports = [
|
|
9
|
+
{
|
|
10
|
+
zigbeeModel: ['4a33f5ea766a4c96a962b371ffde9943'],
|
|
11
|
+
model: 'DS20Z07B',
|
|
12
|
+
vendor: 'ORVIBO',
|
|
13
|
+
description: 'Downlight (S series)',
|
|
14
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [166, 370]}),
|
|
15
|
+
},
|
|
9
16
|
{
|
|
10
17
|
zigbeeModel: ['ORVIBO Socket', '93e29b89b2ee45bea5bdbb7679d75d24'],
|
|
11
18
|
model: 'OR-ZB-S010-3C',
|
package/devices/philips.js
CHANGED
|
@@ -108,6 +108,15 @@ module.exports = [
|
|
|
108
108
|
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
109
109
|
ota: ota.zigbeeOTA,
|
|
110
110
|
},
|
|
111
|
+
{
|
|
112
|
+
zigbeeModel: ['915005996801', '915005996901'],
|
|
113
|
+
model: '915005996901',
|
|
114
|
+
vendor: 'Philips',
|
|
115
|
+
description: 'Hue white ambiance ceiling light Enrave L with Bluetooth',
|
|
116
|
+
meta: {turnsOffAtBrightness1: true},
|
|
117
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
118
|
+
ota: ota.zigbeeOTA,
|
|
119
|
+
},
|
|
111
120
|
{
|
|
112
121
|
zigbeeModel: ['915005997001', '915005997101'],
|
|
113
122
|
model: '915005997001',
|
package/devices/tuya.js
CHANGED
|
@@ -167,7 +167,7 @@ module.exports = [
|
|
|
167
167
|
description: 'Air quality sensor',
|
|
168
168
|
fromZigbee: [fz.tuya_air_quality],
|
|
169
169
|
toZigbee: [],
|
|
170
|
-
exposes: [e.temperature(), e.humidity(), e.co2(), e.voc(), e.formaldehyd()],
|
|
170
|
+
exposes: [e.temperature(), e.humidity(), e.co2(), e.voc().withUnit('ppm'), e.formaldehyd()],
|
|
171
171
|
},
|
|
172
172
|
{
|
|
173
173
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_dwcarsat'}],
|
|
@@ -2174,7 +2174,8 @@ module.exports = [
|
|
|
2174
2174
|
],
|
|
2175
2175
|
},
|
|
2176
2176
|
{
|
|
2177
|
-
fingerprint: [{modelID: 'TS004F', manufacturerName: '_TZ3000_4fjiwweb'}, {modelID: 'TS004F', manufacturerName: '_TZ3000_uri7ongn'}
|
|
2177
|
+
fingerprint: [{modelID: 'TS004F', manufacturerName: '_TZ3000_4fjiwweb'}, {modelID: 'TS004F', manufacturerName: '_TZ3000_uri7ongn'},
|
|
2178
|
+
{modelID: 'TS004F', manufacturerName: '_TZ3000_ixla93vd'}],
|
|
2178
2179
|
model: 'ERS-10TZBVK-AA',
|
|
2179
2180
|
vendor: 'TuYa',
|
|
2180
2181
|
description: 'Smart knob',
|
package/devices/xiaomi.js
CHANGED
|
@@ -1348,9 +1348,16 @@ module.exports = [
|
|
|
1348
1348
|
model: 'ZNJLBL01LM',
|
|
1349
1349
|
description: 'Aqara roller shade companion E1',
|
|
1350
1350
|
vendor: 'Xiaomi',
|
|
1351
|
-
fromZigbee: [fz.
|
|
1352
|
-
fz.ignore_basic_report, fz.aqara_opple],
|
|
1351
|
+
fromZigbee: [fz.xiaomi_curtain_position, fz.xiaomi_curtain_acn002_status, fz.ignore_basic_report, fz.aqara_opple],
|
|
1353
1352
|
toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_acn002_battery, tz.xiaomi_curtain_acn002_charging_status],
|
|
1353
|
+
onEvent: async (type, data, device) => {
|
|
1354
|
+
if (type === 'message' && data.type === 'attributeReport' && data.cluster === 'genMultistateOutput' &&
|
|
1355
|
+
data.data.hasOwnProperty('presentValue') && data.data['presentValue'] > 1) {
|
|
1356
|
+
// Try to read the position after the motor stops, the device occasionally report wrong data right after stopping
|
|
1357
|
+
// Might need to add delay, seems to be working without one but needs more tests.
|
|
1358
|
+
await device.getEndpoint(1).read('genAnalogOutput', ['presentValue']);
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1354
1361
|
exposes: [e.cover_position().setAccess('state', ea.ALL), e.battery().withAccess(ea.STATE_GET),
|
|
1355
1362
|
exposes.binary('charging_status', ea.STATE_GET, true, false)
|
|
1356
1363
|
.withDescription('The current charging status.'),
|
package/lib/exposes.js
CHANGED
|
@@ -550,7 +550,7 @@ module.exports = {
|
|
|
550
550
|
fan: () => new Fan(),
|
|
551
551
|
flip_indicator_light: () => new Binary('flip_indicator_light', access.ALL, 'ON', 'OFF').withDescription('After turn on, the indicator light turns on while switch is off, and vice versa'),
|
|
552
552
|
force: () => new Enum('force', access.STATE_SET, ['normal', 'open', 'close']).withDescription('Force the valve position'),
|
|
553
|
-
formaldehyd: () => new Numeric('formaldehyd', access.STATE).withDescription('The measured formaldehyd value'),
|
|
553
|
+
formaldehyd: () => new Numeric('formaldehyd', access.STATE).withDescription('The measured formaldehyd value').withUnit('mg/m³'),
|
|
554
554
|
gas: () => new Binary('gas', access.STATE, true, false).withDescription('Indicates whether the device detected gas'),
|
|
555
555
|
hcho: () => new Numeric('hcho', access.STATE).withUnit('mg/m³').withDescription('Measured Hcho value'),
|
|
556
556
|
holiday_temperature: () => new Numeric('holiday_temperature', access.STATE_SET).withUnit('°C').withDescription('Holiday temperature').withValueMin(0).withValueMax(30),
|
package/lib/tuya.js
CHANGED
|
@@ -449,16 +449,23 @@ const dataPoints = {
|
|
|
449
449
|
silvercrestSetColor: 5,
|
|
450
450
|
silvercrestSetEffect: 6,
|
|
451
451
|
// Fantem
|
|
452
|
+
fantemPowerSupplyMode: 101,
|
|
452
453
|
fantemReportingTime: 102,
|
|
454
|
+
fantemExtSwitchType: 103,
|
|
453
455
|
fantemTempCalibration: 104,
|
|
454
456
|
fantemHumidityCalibration: 105,
|
|
457
|
+
fantemLoadDetectionMode: 105,
|
|
455
458
|
fantemLuxCalibration: 106,
|
|
459
|
+
fantemExtSwitchStatus: 106,
|
|
456
460
|
fantemTemp: 107,
|
|
457
461
|
fantemHumidity: 108,
|
|
458
462
|
fantemMotionEnable: 109,
|
|
463
|
+
fantemControlMode: 109,
|
|
459
464
|
fantemBattery: 110,
|
|
460
465
|
fantemLedEnable: 111,
|
|
461
466
|
fantemReportingEnable: 112,
|
|
467
|
+
fantemLoadType: 112,
|
|
468
|
+
fantemLoadDimmable: 113,
|
|
462
469
|
// Woox
|
|
463
470
|
wooxSwitch: 102,
|
|
464
471
|
wooxBattery: 14,
|