zigbee-herdsman-converters 14.0.612 → 14.0.615
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 +1 -1
- package/converters/toZigbee.js +49 -24
- package/devices/atlantic.js +110 -0
- package/devices/custom_devices_diy.js +31 -1
- package/devices/ecodim.js +5 -0
- package/devices/ikea.js +1 -1
- package/devices/kwikset.js +4 -3
- package/devices/ledvance.js +49 -0
- package/devices/legrand.js +17 -9
- package/devices/owon.js +47 -0
- package/devices/philips.js +7 -0
- package/devices/salus_controls.js +6 -1
- package/devices/smartwings.js +1 -1
- package/devices/tuya.js +11 -1
- package/lib/constants.js +1 -0
- package/lib/exposes.js +5 -1
- package/lib/tuya.js +2 -0
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -5119,7 +5119,7 @@ const converters = {
|
|
|
5119
5119
|
'105_14': 'press_2_and_3_and_4', '105_15': 'press_all', '105_16': 'press_energy_bar', '106_0': 'release',
|
|
5120
5120
|
};
|
|
5121
5121
|
|
|
5122
|
-
const ID = `${commandID}_${msg.data.commandFrame.raw.join('_')}`;
|
|
5122
|
+
const ID = `${commandID}_${msg.data.commandFrame.raw.slice(0, 1).join('_')}`;
|
|
5123
5123
|
if (!lookup.hasOwnProperty(ID)) {
|
|
5124
5124
|
meta.logger.error(`PTM 216Z: missing command '${ID}'`);
|
|
5125
5125
|
} else {
|
package/converters/toZigbee.js
CHANGED
|
@@ -859,7 +859,6 @@ const converters = {
|
|
|
859
859
|
state = meta.message.state = brightness === 0 ? 'off' : 'on';
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
let publishFakeOnLevel = false;
|
|
863
862
|
let publishBrightness = brightness !== undefined;
|
|
864
863
|
const targetState = state === 'toggle' ? (meta.state.state === 'ON' ? 'off' : 'on') : state;
|
|
865
864
|
if (targetState === 'off') {
|
|
@@ -886,27 +885,17 @@ const converters = {
|
|
|
886
885
|
// TODO: same problem as above.
|
|
887
886
|
// TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
|
|
888
887
|
if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
} catch (e) {
|
|
898
|
-
// OnLevel not supported; write a 'previous' value to state to avoid re-reads
|
|
888
|
+
const current = utils.getObjectProperty(meta.state, 'brightness', 254);
|
|
889
|
+
brightness = globalStore.getValue(entity, 'brightness', current);
|
|
890
|
+
try {
|
|
891
|
+
const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
|
|
892
|
+
// TODO: for groups, `read` does not wait for responses. If it did, we could still issue a single
|
|
893
|
+
// command if all values of `OnLevel` are equal, or split into one command per device if not.
|
|
894
|
+
if (attributeRead !== undefined && attributeRead['onLevel'] != 255) {
|
|
895
|
+
brightness = attributeRead['onLevel'];
|
|
899
896
|
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
onLevel = 'previous';
|
|
903
|
-
publishFakeOnLevel = true;
|
|
904
|
-
}
|
|
905
|
-
if (onLevel === 255 || onLevel === 'previous') {
|
|
906
|
-
const current = utils.getObjectProperty(meta.state, 'brightness', 254);
|
|
907
|
-
brightness = globalStore.getValue(entity, 'brightness', current);
|
|
908
|
-
} else {
|
|
909
|
-
brightness = onLevel;
|
|
897
|
+
} catch (e) {
|
|
898
|
+
// OnLevel not supported
|
|
910
899
|
}
|
|
911
900
|
// Published state might have gotten clobbered by reporting.
|
|
912
901
|
publishBrightness = true;
|
|
@@ -944,9 +933,6 @@ const converters = {
|
|
|
944
933
|
if (publishBrightness) {
|
|
945
934
|
result.state.brightness = Number(brightness);
|
|
946
935
|
}
|
|
947
|
-
if (publishFakeOnLevel) {
|
|
948
|
-
result.state.level_config = {on_level: 'previous'};
|
|
949
|
-
}
|
|
950
936
|
if (state !== null) {
|
|
951
937
|
result.state.state = brightness === 0 ? 'OFF' : 'ON';
|
|
952
938
|
}
|
|
@@ -1240,6 +1226,7 @@ const converters = {
|
|
|
1240
1226
|
Object.values(constants.thermostatProgrammingOperationModes).join(', '));
|
|
1241
1227
|
}
|
|
1242
1228
|
await entity.write('hvacThermostat', {programingOperMode: val});
|
|
1229
|
+
return {state: {programming_operation_mode: value}};
|
|
1243
1230
|
},
|
|
1244
1231
|
convertGet: async (entity, key, meta) => {
|
|
1245
1232
|
await entity.read('hvacThermostat', ['programingOperMode']);
|
|
@@ -1355,6 +1342,7 @@ const converters = {
|
|
|
1355
1342
|
}
|
|
1356
1343
|
const occupiedHeatingSetpoint = result;
|
|
1357
1344
|
await entity.write('hvacThermostat', {occupiedHeatingSetpoint});
|
|
1345
|
+
return {state: {occupied_heating_setpoint: value}};
|
|
1358
1346
|
},
|
|
1359
1347
|
convertGet: async (entity, key, meta) => {
|
|
1360
1348
|
await entity.read('hvacThermostat', ['occupiedHeatingSetpoint']);
|
|
@@ -1389,6 +1377,7 @@ const converters = {
|
|
|
1389
1377
|
}
|
|
1390
1378
|
const occupiedCoolingSetpoint = result;
|
|
1391
1379
|
await entity.write('hvacThermostat', {occupiedCoolingSetpoint});
|
|
1380
|
+
return {state: {occupied_cooling_setpoint: value}};
|
|
1392
1381
|
},
|
|
1393
1382
|
convertGet: async (entity, key, meta) => {
|
|
1394
1383
|
await entity.read('hvacThermostat', ['occupiedCoolingSetpoint']);
|
|
@@ -1441,6 +1430,7 @@ const converters = {
|
|
|
1441
1430
|
}
|
|
1442
1431
|
const minHeatSetpointLimit = result;
|
|
1443
1432
|
await entity.write('hvacThermostat', {minHeatSetpointLimit});
|
|
1433
|
+
return {state: {min_heat_setpoint_limit: value}};
|
|
1444
1434
|
},
|
|
1445
1435
|
convertGet: async (entity, key, meta) => {
|
|
1446
1436
|
await entity.read('hvacThermostat', ['minHeatSetpointLimit']);
|
|
@@ -1457,11 +1447,46 @@ const converters = {
|
|
|
1457
1447
|
}
|
|
1458
1448
|
const maxHeatSetpointLimit = result;
|
|
1459
1449
|
await entity.write('hvacThermostat', {maxHeatSetpointLimit});
|
|
1450
|
+
return {state: {max_heat_setpoint_limit: value}};
|
|
1460
1451
|
},
|
|
1461
1452
|
convertGet: async (entity, key, meta) => {
|
|
1462
1453
|
await entity.read('hvacThermostat', ['maxHeatSetpointLimit']);
|
|
1463
1454
|
},
|
|
1464
1455
|
},
|
|
1456
|
+
thermostat_min_cool_setpoint_limit: {
|
|
1457
|
+
key: ['min_cool_setpoint_limit'],
|
|
1458
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1459
|
+
let result;
|
|
1460
|
+
if (meta.options.thermostat_unit === 'fahrenheit') {
|
|
1461
|
+
result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
|
|
1462
|
+
} else {
|
|
1463
|
+
result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
|
|
1464
|
+
}
|
|
1465
|
+
const minCoolSetpointLimit = result;
|
|
1466
|
+
await entity.write('hvacThermostat', {minCoolSetpointLimit});
|
|
1467
|
+
return {state: {min_cool_setpoint_limit: value}};
|
|
1468
|
+
},
|
|
1469
|
+
convertGet: async (entity, key, meta) => {
|
|
1470
|
+
await entity.read('hvacThermostat', ['minCoolSetpointLimit']);
|
|
1471
|
+
},
|
|
1472
|
+
},
|
|
1473
|
+
thermostat_max_cool_setpoint_limit: {
|
|
1474
|
+
key: ['max_cool_setpoint_limit'],
|
|
1475
|
+
convertSet: async (entity, key, value, meta) => {
|
|
1476
|
+
let result;
|
|
1477
|
+
if (meta.options.thermostat_unit === 'fahrenheit') {
|
|
1478
|
+
result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
|
|
1479
|
+
} else {
|
|
1480
|
+
result = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
|
|
1481
|
+
}
|
|
1482
|
+
const maxCoolSetpointLimit = result;
|
|
1483
|
+
await entity.write('hvacThermostat', {maxCoolSetpointLimit});
|
|
1484
|
+
return {state: {max_cool_setpoint_limit: value}};
|
|
1485
|
+
},
|
|
1486
|
+
convertGet: async (entity, key, meta) => {
|
|
1487
|
+
await entity.read('hvacThermostat', ['maxCoolSetpointLimit']);
|
|
1488
|
+
},
|
|
1489
|
+
},
|
|
1465
1490
|
thermostat_ac_louver_position: {
|
|
1466
1491
|
key: ['ac_louver_position'],
|
|
1467
1492
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const fz = require('../converters/fromZigbee');
|
|
2
|
+
const tz = require('../converters/toZigbee');
|
|
3
|
+
const exposes = require('../lib/exposes');
|
|
4
|
+
const reporting = require('../lib/reporting');
|
|
5
|
+
const utils = require('../lib/utils');
|
|
6
|
+
const assert = require('assert');
|
|
7
|
+
const e = exposes.presets;
|
|
8
|
+
const ea = exposes.access;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const thermostatPositions = {
|
|
12
|
+
'quarter_open': 1,
|
|
13
|
+
'half_open': 2,
|
|
14
|
+
'three_quarters_open': 3,
|
|
15
|
+
'fully_open': 4,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const tzLocal = {
|
|
19
|
+
quiet_fan: {
|
|
20
|
+
key: ['quiet_fan'],
|
|
21
|
+
convertSet: async (entity, key, value, meta) => {
|
|
22
|
+
assert(typeof value === 'boolean');
|
|
23
|
+
await entity.write('hvacFanCtrl', {0x1000: {value: value ? 1 : 0, type: 0x10}}, {manufacturerCode: 0x125b});
|
|
24
|
+
return {state: {quiet_fan: value}};
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
ac_louver_position: {
|
|
28
|
+
key: ['ac_louver_position'],
|
|
29
|
+
convertSet: async (entity, key, value, meta) => {
|
|
30
|
+
value = value.toLowerCase();
|
|
31
|
+
utils.validateValue(value, Object.keys(thermostatPositions));
|
|
32
|
+
const index = thermostatPositions[value];
|
|
33
|
+
await entity.write('hvacThermostat', {0x4273: {value: index, type: 0x30}}, {manufacturerCode: 0x125b});
|
|
34
|
+
return {state: {ac_louver_position: value}};
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
preset: {
|
|
38
|
+
key: ['preset'],
|
|
39
|
+
convertSet: async (entity, key, value, meta) => {
|
|
40
|
+
value = value.toLowerCase();
|
|
41
|
+
utils.validateValue(value, ['activity', 'boost', 'eco', 'none']);
|
|
42
|
+
const activity = value === 'activity' ? 1 : 0;
|
|
43
|
+
const boost = value === 'boost' ? 1 : 0;
|
|
44
|
+
const eco = value === 'eco' ? 4 : 0;
|
|
45
|
+
|
|
46
|
+
await entity.write('hvacThermostat', {0x4275: {value: activity, type: 0x30}}, {manufacturerCode: 0x125b});
|
|
47
|
+
await entity.write('hvacThermostat', {'programingOperMode': eco});
|
|
48
|
+
await entity.write('hvacThermostat', {0x4270: {value: boost, type: 0x10}}, {manufacturerCode: 0x125b});
|
|
49
|
+
|
|
50
|
+
return {state: {preset: value}};
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
swingMode: {
|
|
54
|
+
key: ['swing_mode'],
|
|
55
|
+
convertSet: async (entity, key, value, meta) => {
|
|
56
|
+
value = value.toLowerCase();
|
|
57
|
+
utils.validateValue(value, ['on', 'off']);
|
|
58
|
+
await entity.write('hvacThermostat', {0x4274: {value: value === 'on' ? 1 : 0, type: 0x10}}, {manufacturerCode: 0x125b});
|
|
59
|
+
return {state: {swing_mode: value}};
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = [{
|
|
65
|
+
zigbeeModel: ['Adapter Zigbee FUJITSU'],
|
|
66
|
+
model: 'GW003-AS-IN-TE-FC',
|
|
67
|
+
vendor: 'Atlantic Group',
|
|
68
|
+
description: 'Interface Naviclim for Takao air conditioners',
|
|
69
|
+
fromZigbee: [
|
|
70
|
+
fz.thermostat,
|
|
71
|
+
fz.fan,
|
|
72
|
+
],
|
|
73
|
+
toZigbee: [
|
|
74
|
+
tzLocal.ac_louver_position,
|
|
75
|
+
tzLocal.preset,
|
|
76
|
+
tzLocal.quiet_fan,
|
|
77
|
+
tzLocal.swingMode,
|
|
78
|
+
tz.fan_mode,
|
|
79
|
+
tz.thermostat_local_temperature,
|
|
80
|
+
tz.thermostat_occupied_cooling_setpoint,
|
|
81
|
+
tz.thermostat_occupied_heating_setpoint,
|
|
82
|
+
tz.thermostat_programming_operation_mode,
|
|
83
|
+
tz.thermostat_system_mode,
|
|
84
|
+
],
|
|
85
|
+
exposes: [
|
|
86
|
+
e.programming_operation_mode(),
|
|
87
|
+
exposes.climate()
|
|
88
|
+
.withLocalTemperature()
|
|
89
|
+
.withSetpoint('occupied_cooling_setpoint', 18, 30, 0.5)
|
|
90
|
+
.withSetpoint('occupied_heating_setpoint', 16, 30, 0.5)
|
|
91
|
+
.withSystemMode(['off', 'heat', 'cool', 'auto', 'dry', 'fan_only'])
|
|
92
|
+
.withPreset(['activity', 'boost', 'eco'])
|
|
93
|
+
.withFanMode(['low', 'medium', 'high', 'auto'])
|
|
94
|
+
.withSwingMode(['on', 'off'], ea.STATE_SET),
|
|
95
|
+
exposes.binary('quiet_fan', ea.STATE_SET, true, false).withDescription('Fan quiet mode'),
|
|
96
|
+
exposes.enum('ac_louver_position', ea.STATE_SET, Object.keys(thermostatPositions))
|
|
97
|
+
.withDescription('Ac louver position of this device'),
|
|
98
|
+
],
|
|
99
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
100
|
+
const endpoint1 = device.getEndpoint(1);
|
|
101
|
+
const binds1 = ['hvacFanCtrl', 'genIdentify', 'hvacFanCtrl', 'hvacThermostat', 'manuSpecificPhilips2'];
|
|
102
|
+
await reporting.bind(endpoint1, coordinatorEndpoint, binds1);
|
|
103
|
+
await reporting.thermostatTemperature(endpoint1);
|
|
104
|
+
await reporting.thermostatOccupiedCoolingSetpoint(endpoint1);
|
|
105
|
+
await reporting.thermostatSystemMode(endpoint1);
|
|
106
|
+
|
|
107
|
+
const endpoint232 = device.getEndpoint(232);
|
|
108
|
+
await reporting.bind(endpoint232, coordinatorEndpoint, ['haDiagnostic']);
|
|
109
|
+
},
|
|
110
|
+
}];
|
|
@@ -772,9 +772,39 @@ module.exports = [
|
|
|
772
772
|
exposes.binary('factory_reset_co2', ea.STATE_SET, 'ON', 'OFF').withDescription('Factory Reset CO2 sensor'),
|
|
773
773
|
exposes.binary('enable_gas', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable CO2 Gas Control'),
|
|
774
774
|
exposes.numeric('high_gas', ea.STATE_SET).withUnit('ppm').withDescription('Setting High CO2 Gas Border')
|
|
775
|
-
.withValueMin(
|
|
775
|
+
.withValueMin(400).withValueMax(2000),
|
|
776
776
|
exposes.numeric('low_gas', ea.STATE_SET).withUnit('ppm').withDescription('Setting Low CO2 Gas Border')
|
|
777
|
+
.withValueMin(400).withValueMax(2000),
|
|
778
|
+
exposes.binary('enable_temperature', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable Temperature Control'),
|
|
779
|
+
exposes.numeric('high_temperature', ea.STATE_SET).withUnit('C').withDescription('Setting High Temperature Border')
|
|
780
|
+
.withValueMin(-5).withValueMax(50),
|
|
781
|
+
exposes.numeric('low_temperature', ea.STATE_SET).withUnit('C').withDescription('Setting Low Temperature Border')
|
|
782
|
+
.withValueMin(-5).withValueMax(50),
|
|
783
|
+
exposes.binary('enable_humidity', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable Humidity Control'),
|
|
784
|
+
exposes.numeric('high_humidity', ea.STATE_SET).withUnit('C').withDescription('Setting High Humidity Border')
|
|
777
785
|
.withValueMin(0).withValueMax(99),
|
|
786
|
+
exposes.numeric('low_humidity', ea.STATE_SET).withUnit('C').withDescription('Setting Low Humidity Border')
|
|
787
|
+
.withValueMin(0).withValueMax(99)],
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
zigbeeModel: ['SNZB-02_EFEKTA'],
|
|
791
|
+
model: 'SNZB-02_EFEKTA',
|
|
792
|
+
vendor: 'Custom devices (DiY)',
|
|
793
|
+
description: 'Alternative firmware for the SONOFF SNZB-02 sensor from EfektaLab, DIY',
|
|
794
|
+
fromZigbee: [fz.temperature, fz.humidity, fz.battery, fzLocal.termostat_config, fzLocal.hydrostat_config, fzLocal.node_config],
|
|
795
|
+
toZigbee: [tz.factory_reset, tzLocal.termostat_config, tzLocal.hydrostat_config, tzLocal.node_config],
|
|
796
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
797
|
+
const endpoint = device.getEndpoint(1);
|
|
798
|
+
await reporting.bind(endpoint, coordinatorEndpoint, [
|
|
799
|
+
'genPowerCfg', 'msTemperatureMeasurement', 'msRelativeHumidity']);
|
|
800
|
+
const overides = {min: 0, max: 21600, change: 0};
|
|
801
|
+
await reporting.batteryVoltage(endpoint, overides);
|
|
802
|
+
await reporting.batteryPercentageRemaining(endpoint, overides);
|
|
803
|
+
},
|
|
804
|
+
exposes: [e.battery(), e.temperature(), e.humidity(),
|
|
805
|
+
exposes.numeric('report_delay', ea.STATE_SET).withUnit('Minutes')
|
|
806
|
+
.withDescription('Adjust Report Delay. Setting the time in minutes, by default 5 minutes')
|
|
807
|
+
.withValueMin(1).withValueMax(60),
|
|
778
808
|
exposes.binary('enable_temperature', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable Temperature Control'),
|
|
779
809
|
exposes.numeric('high_temperature', ea.STATE_SET).withUnit('C').withDescription('Setting High Temperature Border')
|
|
780
810
|
.withValueMin(-5).withValueMax(50),
|
package/devices/ecodim.js
CHANGED
|
@@ -38,6 +38,11 @@ module.exports = [
|
|
|
38
38
|
{ID: 1, profileID: 260, deviceID: 257, inputClusters: [0, 3, 4, 5, 6, 8, 2821, 4096], outputClusters: [25]},
|
|
39
39
|
{ID: 242, profileID: 41440, deviceID: 97, inputClusters: [], outputClusters: [33]},
|
|
40
40
|
]},
|
|
41
|
+
{type: 'Router', manufacturerName: 'EcoDim BV', modelID: 'EcoDim-Zigbee 3.0', endpoints: [
|
|
42
|
+
{ID: 1, profileID: 260, deviceID: 257, inputClusters: [0, 3, 4, 5, 6, 8, 2821, 4096], outputClusters: [25]},
|
|
43
|
+
{ID: 67, inputClusters: [], outputClusters: []},
|
|
44
|
+
{ID: 242, profileID: 41440, deviceID: 97, inputClusters: [], outputClusters: [33]},
|
|
45
|
+
]},
|
|
41
46
|
],
|
|
42
47
|
zigbeeModel: ['Dimmer-Switch-ZB3.0'],
|
|
43
48
|
model: 'Eco-Dim.07/Eco-Dim.10',
|
package/devices/ikea.js
CHANGED
|
@@ -457,7 +457,7 @@ module.exports = [
|
|
|
457
457
|
meta: {supportsHueAndSaturation: false},
|
|
458
458
|
},
|
|
459
459
|
{
|
|
460
|
-
zigbeeModel: ['TRADFRI bulb E26 CWS 800lm', 'TRADFRI bulb E27 CWS 806lm'],
|
|
460
|
+
zigbeeModel: ['TRADFRI bulb E26 CWS 800lm', 'TRADFRI bulb E27 CWS 806lm', 'TRADFRI bulb E26 CWS 806lm'],
|
|
461
461
|
model: 'LED1924G9',
|
|
462
462
|
vendor: 'IKEA',
|
|
463
463
|
description: 'TRADFRI bulb E26/E27 CWS 800/806 lumen, dimmable, color, opal white',
|
package/devices/kwikset.js
CHANGED
|
@@ -55,15 +55,16 @@ module.exports = [
|
|
|
55
55
|
model: '99140-031',
|
|
56
56
|
vendor: 'Kwikset',
|
|
57
57
|
description: 'SmartCode traditional electronic deadbolt',
|
|
58
|
-
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery],
|
|
59
|
-
toZigbee: [tz.lock],
|
|
58
|
+
fromZigbee: [fz.lock, fz.lock_operation_event, fz.battery, fz.lock_programming_event, fz.lock_pin_code_response],
|
|
59
|
+
toZigbee: [tz.lock, tz.pincode_lock],
|
|
60
|
+
meta: {pinCodeCount: 30},
|
|
60
61
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
61
62
|
const endpoint = device.getEndpoint(2);
|
|
62
63
|
await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
|
|
63
64
|
await reporting.lockState(endpoint);
|
|
64
65
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
65
66
|
},
|
|
66
|
-
exposes: [e.lock(), e.battery(), e.lock_action(), e.lock_action_source_name(), e.lock_action_user()],
|
|
67
|
+
exposes: [e.lock(), e.battery(), e.pincode(), e.lock_action(), e.lock_action_source_name(), e.lock_action_user()],
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
70
|
zigbeeModel: ['SMARTCODE_DEADBOLT_5'],
|
package/devices/ledvance.js
CHANGED
|
@@ -175,4 +175,53 @@ module.exports = [
|
|
|
175
175
|
extend: extend.ledvance.light_onoff_brightness(),
|
|
176
176
|
ota: ota.ledvance,
|
|
177
177
|
},
|
|
178
|
+
{
|
|
179
|
+
zigbeeModel: ['B40 DIM T'],
|
|
180
|
+
model: '4058075729063',
|
|
181
|
+
vendor: 'LEDVANCE',
|
|
182
|
+
description: 'SMART+ Classic B40 E14 dimmable white',
|
|
183
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
184
|
+
ota: ota.ledvance,
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
zigbeeModel: ['PAR16 DIM T'],
|
|
188
|
+
model: '4058075729148',
|
|
189
|
+
vendor: 'LEDVANCE',
|
|
190
|
+
description: 'SMART+ Spot PAR16 50 GU10 dimmable white',
|
|
191
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
192
|
+
ota: ota.ledvance,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
zigbeeModel: ['P40 DIM T'],
|
|
196
|
+
model: '4058075729100',
|
|
197
|
+
vendor: 'LEDVANCE',
|
|
198
|
+
description: 'SMART+ Classic P40 E14 dimmable white',
|
|
199
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
200
|
+
ota: ota.ledvance,
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
zigbeeModel: ['A60 FIL DIM T'],
|
|
204
|
+
model: '4058075729209',
|
|
205
|
+
vendor: 'LEDVANCE',
|
|
206
|
+
description: 'SMART+ Filament Classic A 52 E27 Amber dimmable',
|
|
207
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
208
|
+
ota: ota.ledvance,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
zigbeeModel: ['EDISON60 FIL DIM T'],
|
|
212
|
+
model: '4058075729223',
|
|
213
|
+
vendor: 'LEDVANCE',
|
|
214
|
+
description: 'SMART+ Filament Edison 52 E27 Amber dimmable',
|
|
215
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
216
|
+
ota: ota.ledvance,
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
zigbeeModel: ['GLOBE60 FIL DIM T'],
|
|
220
|
+
model: '4058075729247',
|
|
221
|
+
vendor: 'LEDVANCE',
|
|
222
|
+
description: 'SMART+ Filament Globe125 52 E27 Amber dimmable',
|
|
223
|
+
extend: extend.ledvance.light_onoff_brightness(),
|
|
224
|
+
ota: ota.ledvance,
|
|
225
|
+
},
|
|
226
|
+
|
|
178
227
|
];
|
package/devices/legrand.js
CHANGED
|
@@ -174,9 +174,10 @@ module.exports = [
|
|
|
174
174
|
vendor: 'Legrand',
|
|
175
175
|
description: 'Wired switch without neutral',
|
|
176
176
|
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
177
|
-
fromZigbee: [fz.brightness, fz.identify, fz.on_off, fz.lighting_ballast_configuration, fz.legrand_cluster_fc01
|
|
177
|
+
fromZigbee: [fz.brightness, fz.identify, fz.on_off, fz.lighting_ballast_configuration, fz.legrand_cluster_fc01,
|
|
178
|
+
fz.power_on_behavior],
|
|
178
179
|
toZigbee: [tz.light_onoff_brightness, tz.legrand_settingEnableLedInDark, tz.legrand_settingEnableLedIfOn,
|
|
179
|
-
tz.legrand_deviceMode, tz.legrand_identify, tz.ballast_config],
|
|
180
|
+
tz.legrand_deviceMode, tz.legrand_identify, tz.ballast_config, tz.power_on_behavior],
|
|
180
181
|
exposes: [e.light_brightness(),
|
|
181
182
|
exposes.numeric('ballast_minimum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
182
183
|
.withDescription('Specifies the minimum brightness value'),
|
|
@@ -185,7 +186,8 @@ module.exports = [
|
|
|
185
186
|
exposes.binary('device_mode', ea.ALL, 'dimmer_on', 'dimmer_off').withDescription('Allow the device to change brightness'),
|
|
186
187
|
exposes.binary('led_in_dark', ea.ALL, 'ON', 'OFF').withDescription(`Enables the LED when the light is turned off, allowing to
|
|
187
188
|
see the switch in the dark`),
|
|
188
|
-
exposes.binary('led_if_on', ea.ALL, 'ON', 'OFF').withDescription('Enables the LED when the light is turned on')
|
|
189
|
+
exposes.binary('led_if_on', ea.ALL, 'ON', 'OFF').withDescription('Enables the LED when the light is turned on'),
|
|
190
|
+
e.power_on_behavior()],
|
|
189
191
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
190
192
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
191
193
|
const endpoint = device.getEndpoint(1);
|
|
@@ -201,10 +203,14 @@ module.exports = [
|
|
|
201
203
|
vendor: 'Legrand',
|
|
202
204
|
ota: ota.zigbeeOTA,
|
|
203
205
|
description: 'Power socket with power consumption monitoring',
|
|
204
|
-
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement],
|
|
205
|
-
toZigbee: [tz.on_off, tz.legrand_settingEnableLedInDark, tz.legrand_identify, tz.legrand_settingEnableLedIfOn
|
|
206
|
+
fromZigbee: [fz.identify, fz.on_off, fz.electrical_measurement, fz.power_on_behavior],
|
|
207
|
+
toZigbee: [tz.on_off, tz.legrand_settingEnableLedInDark, tz.legrand_identify, tz.legrand_settingEnableLedIfOn,
|
|
208
|
+
tz.power_on_behavior],
|
|
206
209
|
exposes: [e.switch(), e.action(['identify']), e.power(),
|
|
207
|
-
exposes.binary('
|
|
210
|
+
exposes.binary('led_in_dark', ea.ALL, 'ON', 'OFF').withDescription(`Enables the LED when the power socket is turned off,
|
|
211
|
+
allowing to see it in the dark`),
|
|
212
|
+
exposes.binary('led_if_on', ea.ALL, 'ON', 'OFF').withDescription('Enables the LED when the device is turned on'),
|
|
213
|
+
e.power_on_behavior()],
|
|
208
214
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
209
215
|
const endpoint = device.getEndpoint(1);
|
|
210
216
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'haElectricalMeasurement']);
|
|
@@ -326,12 +332,14 @@ module.exports = [
|
|
|
326
332
|
model: '064882',
|
|
327
333
|
vendor: 'Legrand',
|
|
328
334
|
description: 'Cable outlet with pilot wire and consumption measurement',
|
|
329
|
-
fromZigbee: [fz.legrand_cluster_fc01, fz.legrand_cable_outlet_mode, fz.on_off, fz.electrical_measurement],
|
|
330
|
-
toZigbee: [tz.legrand_deviceMode, tz.legrand_cableOutletMode, tz.on_off, tz.electrical_measurement_power],
|
|
335
|
+
fromZigbee: [fz.legrand_cluster_fc01, fz.legrand_cable_outlet_mode, fz.on_off, fz.electrical_measurement, fz.power_on_behavior],
|
|
336
|
+
toZigbee: [tz.legrand_deviceMode, tz.legrand_cableOutletMode, tz.on_off, tz.electrical_measurement_power, tz.power_on_behavior],
|
|
331
337
|
exposes: [exposes.binary('device_mode', ea.ALL, 'pilot_on', 'pilot_off'),
|
|
332
338
|
exposes.enum('cable_outlet_mode', ea.ALL, ['comfort', 'comfort-1', 'comfort-2', 'eco', 'frost_protection', 'off']),
|
|
333
339
|
exposes.switch().withState('state', true, 'Works only when the pilot wire is deactivated'),
|
|
334
|
-
e.power().withAccess(ea.STATE_GET)
|
|
340
|
+
e.power().withAccess(ea.STATE_GET),
|
|
341
|
+
e.power_on_behavior().withDescription(`Controls the behavior when the device is powered on. Works only when the pilot wire is
|
|
342
|
+
deactivated`)],
|
|
335
343
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
336
344
|
const endpoint = device.getEndpoint(1);
|
|
337
345
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'manuSpecificLegrandDevices2']);
|
package/devices/owon.js
CHANGED
|
@@ -227,4 +227,51 @@ module.exports = [
|
|
|
227
227
|
exposes.numeric('reactive_power_l3', ea.STATE).withUnit('VAr').withDescription('Phase 3 reactive power'),
|
|
228
228
|
],
|
|
229
229
|
},
|
|
230
|
+
{
|
|
231
|
+
zigbeeModel: ['PCT504'],
|
|
232
|
+
model: 'PCT504',
|
|
233
|
+
vendor: 'OWON',
|
|
234
|
+
description: 'HVAC fan coil',
|
|
235
|
+
fromZigbee: [fz.fan, fz.thermostat, fz.humidity, fz.occupancy, fz.legacy.hvac_user_interface],
|
|
236
|
+
toZigbee: [tz.fan_mode, tz.thermostat_system_mode,
|
|
237
|
+
tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
238
|
+
tz.thermostat_occupied_cooling_setpoint, tz.thermostat_unoccupied_cooling_setpoint,
|
|
239
|
+
tz.thermostat_min_heat_setpoint_limit, tz.thermostat_max_heat_setpoint_limit,
|
|
240
|
+
tz.thermostat_min_cool_setpoint_limit, tz.thermostat_max_cool_setpoint_limit,
|
|
241
|
+
tz.thermostat_local_temperature, tz.thermostat_running_state,
|
|
242
|
+
tz.thermostat_keypad_lockout],
|
|
243
|
+
exposes: [e.local_temperature(), e.humidity(), e.occupancy(),
|
|
244
|
+
exposes.climate().withSystemMode(['off', 'heat', 'cool', 'fan_only']).withRunningState(['idle', 'heat', 'cool', 'fan_only'])
|
|
245
|
+
.withSetpoint('occupied_heating_setpoint', 5, 30, 0.5).withSetpoint('unoccupied_heating_setpoint', 5, 30, 0.5)
|
|
246
|
+
.withSetpoint('occupied_cooling_setpoint', 7, 35, 0.5).withSetpoint('unoccupied_cooling_setpoint', 7, 35, 0.5),
|
|
247
|
+
e.fan().withModes(['low', 'medium', 'high', 'on', 'auto']), e.keypad_lockout(),
|
|
248
|
+
e.max_heat_setpoint_limit(5, 30, 0.5), e.min_heat_setpoint_limit(5, 30, 0.5),
|
|
249
|
+
e.max_cool_setpoint_limit(7, 35, 0.5), e.min_cool_setpoint_limit(7, 35, 0.5)],
|
|
250
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
251
|
+
const endpoint = device.getEndpoint(1);
|
|
252
|
+
const binds = ['genBasic', 'genIdentify', 'genGroups', 'hvacThermostat', 'hvacUserInterfaceCfg', 'hvacFanCtrl',
|
|
253
|
+
'msTemperatureMeasurement', 'msOccupancySensing'];
|
|
254
|
+
await reporting.bind(endpoint, coordinatorEndpoint, binds);
|
|
255
|
+
await reporting.fanMode(endpoint);
|
|
256
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['hvacThermostat']);
|
|
257
|
+
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
258
|
+
await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
|
|
259
|
+
await reporting.thermostatOccupiedCoolingSetpoint(endpoint);
|
|
260
|
+
await reporting.thermostatUnoccupiedCoolingSetpoint(endpoint);
|
|
261
|
+
await reporting.thermostatTemperature(endpoint, {min: 60, max: 600, change: 0.1});
|
|
262
|
+
await reporting.thermostatSystemMode(endpoint);
|
|
263
|
+
await reporting.humidity(endpoint, {min: 60, max: 600, change: 1});
|
|
264
|
+
await reporting.thermostatKeypadLockMode(endpoint);
|
|
265
|
+
|
|
266
|
+
await endpoint.read('hvacThermostat', ['systemMode', 'runningState', 'occupiedHeatingSetpoint', 'unoccupiedHeatingSetpoint',
|
|
267
|
+
'occupiedCoolingSetpoint', 'unoccupiedCoolingSetpoint', 'localTemp'],
|
|
268
|
+
'minHeatSetpointLimit', 'maxHeatSetpointLimit', 'minCoolSetpointLimit', 'maxCoolSetpointLimit');
|
|
269
|
+
await endpoint.read('msRelativeHumidity', ['measuredValue']);
|
|
270
|
+
|
|
271
|
+
const endpoint2 = device.getEndpoint(2);
|
|
272
|
+
await reporting.bind(endpoint2, coordinatorEndpoint, ['msOccupancySensing']);
|
|
273
|
+
await reporting.occupancy(endpoint2, {min: 1, max: 600, change: 1});
|
|
274
|
+
await endpoint2.read('msOccupancySensing', ['occupancy']);
|
|
275
|
+
},
|
|
276
|
+
},
|
|
230
277
|
];
|
package/devices/philips.js
CHANGED
|
@@ -329,6 +329,13 @@ module.exports = [
|
|
|
329
329
|
description: 'Hue White ambiance Pillar spotlight',
|
|
330
330
|
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
331
331
|
},
|
|
332
|
+
{
|
|
333
|
+
zigbeeModel: ['929003046001'],
|
|
334
|
+
model: '5309031P8',
|
|
335
|
+
vendor: 'Philips',
|
|
336
|
+
description: 'Hue White ambiance Runner spot white (1 spot)',
|
|
337
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
338
|
+
},
|
|
332
339
|
{
|
|
333
340
|
zigbeeModel: ['929002376301'],
|
|
334
341
|
model: '929002376301',
|
|
@@ -87,7 +87,12 @@ module.exports = [
|
|
|
87
87
|
ota: ota.salus,
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
|
-
zigbeeModel: [
|
|
90
|
+
zigbeeModel: [
|
|
91
|
+
'SS909ZB',
|
|
92
|
+
'PS600\u0000\u0000 �\u0001 ��\u0000\u0000\t\u0001@\u0011�u\u0000\u0000\u0018&\n\u0005\u0000B',
|
|
93
|
+
'PS600\u0000\u0000 �\u0001 ��\u0000\u0000\t\u0001@\u0011�u\u0000\u0000\u0018\u0006\n\u0005\u0000',
|
|
94
|
+
'PS600\u0000\u0000 �\u0001 ��\u0000\u0000\t\u0001@\u0011�u\u0000\u0000\u0018\u0006\n\u0005\u0000B',
|
|
95
|
+
],
|
|
91
96
|
model: 'PS600',
|
|
92
97
|
vendor: 'Salus Controls',
|
|
93
98
|
description: 'Pipe temperature sensor',
|
package/devices/smartwings.js
CHANGED
|
@@ -12,7 +12,7 @@ module.exports = [
|
|
|
12
12
|
description: 'Roller shade',
|
|
13
13
|
fromZigbee: [fz.cover_position_tilt, fz.battery],
|
|
14
14
|
toZigbee: [tz.cover_state, tz.cover_position_tilt],
|
|
15
|
-
meta: {battery: {dontDividePercentage: true}},
|
|
15
|
+
meta: {battery: {dontDividePercentage: true}, coverInverted: true},
|
|
16
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
17
17
|
const endpoint = device.getEndpoint(1);
|
|
18
18
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'closuresWindowCovering']);
|
package/devices/tuya.js
CHANGED
|
@@ -336,6 +336,16 @@ const fzLocal = {
|
|
|
336
336
|
return fz.battery.convert(model, msg, publish, options, meta);
|
|
337
337
|
},
|
|
338
338
|
},
|
|
339
|
+
TS0201_humidity: {
|
|
340
|
+
...fz.humidity,
|
|
341
|
+
convert: (model, msg, publish, options, meta) => {
|
|
342
|
+
const result = fz.humidity.convert(model, msg, publish, options, meta);
|
|
343
|
+
if (meta.device.manufacturerName === '_TZ3000_ywagc4rj') {
|
|
344
|
+
result.humidity = result.humidity * 10;
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
},
|
|
348
|
+
},
|
|
339
349
|
TS0222: {
|
|
340
350
|
cluster: 'manuSpecificTuya',
|
|
341
351
|
type: ['commandDataResponse', 'commandDataReport'],
|
|
@@ -1326,7 +1336,7 @@ module.exports = [
|
|
|
1326
1336
|
vendor: 'TuYa',
|
|
1327
1337
|
description: 'Temperature & humidity sensor with display',
|
|
1328
1338
|
whiteLabel: [{vendor: 'BlitzWolf', model: 'BW-IS4'}],
|
|
1329
|
-
fromZigbee: [fzLocal.TS0201_battery, fz.temperature,
|
|
1339
|
+
fromZigbee: [fzLocal.TS0201_battery, fz.temperature, fzLocal.TS0201_humidity],
|
|
1330
1340
|
toZigbee: [],
|
|
1331
1341
|
exposes: [e.battery(), e.temperature(), e.humidity(), e.battery_voltage()],
|
|
1332
1342
|
configure: async (device, coordinatorEndpoint, logger) => {
|
package/lib/constants.js
CHANGED
package/lib/exposes.js
CHANGED
|
@@ -588,6 +588,10 @@ module.exports = {
|
|
|
588
588
|
lock_action: () => new Enum('action', access.STATE, ['unknown', 'lock', 'unlock', 'lock_failure_invalid_pin_or_id', 'lock_failure_invalid_schedule', 'unlock_failure_invalid_pin_or_id', 'unlock_failure_invalid_schedule', 'one_touch_lock', 'key_lock', 'key_unlock', 'auto_lock', 'schedule_lock', 'schedule_unlock', 'manual_lock', 'manual_unlock', 'non_access_user_operational_event']).withDescription('Triggered action on the lock'),
|
|
589
589
|
lock_action_source_name: () => new Enum('action_source_name', access.STATE, ['keypad', 'rfid', 'manual', 'rf']).withDescription('Source of the triggered action on the lock'),
|
|
590
590
|
lock_action_user: () => new Numeric('action_user', access.STATE).withDescription('ID of user that triggered the action on the lock'),
|
|
591
|
+
max_cool_setpoint_limit: (min, max, step) => new Numeric('max_cool_setpoint_limit', access.ALL).withUnit('°C').withDescription('Maximum Cooling set point limit').withValueMin(min).withValueMax(max).withValueStep(step),
|
|
592
|
+
min_cool_setpoint_limit: (min, max, step) => new Numeric('min_cool_setpoint_limit', access.ALL).withUnit('°C').withDescription('Minimum Cooling point limit').withValueMin(min).withValueMax(max).withValueStep(step),
|
|
593
|
+
max_heat_setpoint_limit: (min, max, step) => new Numeric('max_heat_setpoint_limit', access.ALL).withUnit('°C').withDescription('Maximum Heating set point limit').withValueMin(min).withValueMax(max).withValueStep(step),
|
|
594
|
+
min_heat_setpoint_limit: (min, max, step) => new Numeric('min_heat_setpoint_limit', access.ALL).withUnit('°C').withDescription('Minimum Heating set point limit').withValueMin(min).withValueMax(max).withValueStep(step),
|
|
591
595
|
max_temperature: () => new Numeric('max_temperature', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature').withValueMin(15).withValueMax(35),
|
|
592
596
|
max_temperature_limit: () => new Numeric('max_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature limit').withValueMin(0).withValueMax(35),
|
|
593
597
|
min_temperature: () => new Numeric('min_temperature', access.STATE_SET).withUnit('°C').withDescription('Minimum temperature').withValueMin(1).withValueMax(15),
|
|
@@ -608,7 +612,7 @@ module.exports = {
|
|
|
608
612
|
power_outage_memory: () => new Binary('power_outage_memory', access.ALL, true, false).withDescription('Enable/disable the power outage memory, this recovers the on/off mode after power failure'),
|
|
609
613
|
presence: () => new Binary('presence', access.STATE, true, false).withDescription('Indicates whether the device detected presence'),
|
|
610
614
|
pressure: () => new Numeric('pressure', access.STATE).withUnit('hPa').withDescription('The measured atmospheric pressure'),
|
|
611
|
-
programming_operation_mode: () => new Enum('programming_operation_mode', access.ALL, ['setpoint', 'schedule']).withDescription('Controls how programming affects the thermostat. Possible values: setpoint (only use specified setpoint), schedule (follow programmed setpoint schedule). Changing this value does not clear programmed schedules.'),
|
|
615
|
+
programming_operation_mode: () => new Enum('programming_operation_mode', access.ALL, ['setpoint', 'schedule', 'eco']).withDescription('Controls how programming affects the thermostat. Possible values: setpoint (only use specified setpoint), schedule (follow programmed setpoint schedule). Changing this value does not clear programmed schedules.'),
|
|
612
616
|
smoke: () => new Binary('smoke', access.STATE, true, false).withDescription('Indicates whether the device detected smoke'),
|
|
613
617
|
soil_moisture: () => new Numeric('soil_moisture', access.STATE).withUnit('%').withDescription('Measured soil moisture value'),
|
|
614
618
|
sos: () => new Binary('sos', access.STATE, true, false).withDescription('SOS alarm'),
|
package/lib/tuya.js
CHANGED
|
@@ -595,6 +595,8 @@ const dataPoints = {
|
|
|
595
595
|
dinrailPowerMeterCurrent: 18,
|
|
596
596
|
dinrailPowerMeterPower: 19,
|
|
597
597
|
dinrailPowerMeterVoltage: 20,
|
|
598
|
+
dinrailPowerMeterTotalEnergy2: 101,
|
|
599
|
+
dinrailPowerMeterPower2: 103,
|
|
598
600
|
// tuya smart air box
|
|
599
601
|
tuyaSabCO2: 2,
|
|
600
602
|
tuyaSabTemp: 18,
|