zigbee-herdsman-converters 14.0.680 → 14.0.681
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/toZigbee.js +6 -0
- package/devices/alecto.js +1 -0
- package/devices/leviton.js +13 -0
- package/devices/lonsonho.js +0 -72
- package/devices/sinope.js +54 -62
- package/devices/sonoff.js +1 -1
- package/devices/tuya.js +68 -13
- package/index.js +10 -3
- package/lib/exposes.js +0 -1
- package/lib/tuya.js +0 -2
- package/package.json +1 -1
package/converters/toZigbee.js
CHANGED
|
@@ -4260,6 +4260,9 @@ const converters = {
|
|
|
4260
4260
|
await entity.write('hvacThermostat', {SinopeOccupancy});
|
|
4261
4261
|
return {state: {'thermostat_occupancy': value}};
|
|
4262
4262
|
},
|
|
4263
|
+
convertGet: async (entity, key, meta) => {
|
|
4264
|
+
await entity.read('hvacThermostat', ['SinopeOccupancy']);
|
|
4265
|
+
},
|
|
4263
4266
|
},
|
|
4264
4267
|
sinope_thermostat_backlight_autodim_param: {
|
|
4265
4268
|
key: ['backlight_auto_dim'],
|
|
@@ -4269,6 +4272,9 @@ const converters = {
|
|
|
4269
4272
|
await entity.write('hvacThermostat', {SinopeBacklight});
|
|
4270
4273
|
return {state: {'backlight_auto_dim': value}};
|
|
4271
4274
|
},
|
|
4275
|
+
convertGet: async (entity, key, meta) => {
|
|
4276
|
+
await entity.read('hvacThermostat', ['SinopeBacklight']);
|
|
4277
|
+
},
|
|
4272
4278
|
},
|
|
4273
4279
|
sinope_thermostat_enable_outdoor_temperature: {
|
|
4274
4280
|
key: ['enable_outdoor_temperature'],
|
package/devices/alecto.js
CHANGED
|
@@ -63,6 +63,7 @@ module.exports = [
|
|
|
63
63
|
fingerprint: [
|
|
64
64
|
{modelID: 'daqwrsj\u0000', manufacturerName: '_TYST11_8daqwrsj'},
|
|
65
65
|
{modelID: 'TS0601', manufacturerName: '_TZE200_qtbrwrfv'},
|
|
66
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_8daqwrsj'},
|
|
66
67
|
],
|
|
67
68
|
model: 'SMART-HEAT10',
|
|
68
69
|
vendor: 'Alecto',
|
package/devices/leviton.js
CHANGED
|
@@ -47,6 +47,19 @@ module.exports = [
|
|
|
47
47
|
await reporting.onOff(endpoint);
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
zigbeeModel: ['DG3HL'],
|
|
52
|
+
model: 'DG3HL-1BW',
|
|
53
|
+
vendor: 'Leviton',
|
|
54
|
+
description: 'Indoor Decora smart Zigbee 3.0 certified plug-in dimmer',
|
|
55
|
+
extend: extend.light_onoff_brightness({disableEffect: true, noConfigure: true}),
|
|
56
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
57
|
+
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
58
|
+
const endpoint = device.getEndpoint(1);
|
|
59
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
60
|
+
await reporting.onOff(endpoint);
|
|
61
|
+
},
|
|
62
|
+
},
|
|
50
63
|
{
|
|
51
64
|
zigbeeModel: ['DG15A'],
|
|
52
65
|
model: 'DG15A-1BW',
|
package/devices/lonsonho.js
CHANGED
|
@@ -4,47 +4,9 @@ const tz = require('../converters/toZigbee');
|
|
|
4
4
|
const reporting = require('../lib/reporting');
|
|
5
5
|
const extend = require('../lib/extend');
|
|
6
6
|
const tuya = require('../lib/tuya');
|
|
7
|
-
const utils = require('../lib/utils');
|
|
8
7
|
const e = exposes.presets;
|
|
9
8
|
const ea = exposes.access;
|
|
10
9
|
|
|
11
|
-
const fzLocal = {
|
|
12
|
-
TS110E_switch_type: {
|
|
13
|
-
cluster: 'genLevelCtrl',
|
|
14
|
-
type: ['attributeReport', 'readResponse'],
|
|
15
|
-
convert: (model, msg, publish, options, meta) => {
|
|
16
|
-
const property = 0xfc02;
|
|
17
|
-
if (msg.data.hasOwnProperty(property)) {
|
|
18
|
-
const value = msg.data[property];
|
|
19
|
-
const lookup = {0: 'momentary', 1: 'toggle', 2: 'state'};
|
|
20
|
-
if (lookup.hasOwnProperty(value)) {
|
|
21
|
-
const propertyName = utils.postfixWithEndpointName('switch_type', msg, model, meta);
|
|
22
|
-
return {[propertyName]: lookup[value]};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const tzLocal = {
|
|
30
|
-
TS110E_switch_type: {
|
|
31
|
-
key: ['switch_type'],
|
|
32
|
-
convertSet: async (entity, key, value, meta) => {
|
|
33
|
-
value = value.toLowerCase();
|
|
34
|
-
const lookup = {'momentary': 0, 'toggle': 1, 'state': 2};
|
|
35
|
-
|
|
36
|
-
utils.validateValue(value, Object.keys(lookup));
|
|
37
|
-
const payload = lookup[value];
|
|
38
|
-
|
|
39
|
-
await entity.write('genLevelCtrl', {0xfc02: {value: payload, type: 0x20}});
|
|
40
|
-
return {state: {switch_type: value}};
|
|
41
|
-
},
|
|
42
|
-
convertGet: async (entity, key, meta) => {
|
|
43
|
-
await entity.read('genLevelCtrl', [0xfc02]);
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
10
|
module.exports = [
|
|
49
11
|
{
|
|
50
12
|
fingerprint: [{modelID: 'TS130F', manufacturerName: '_TZ3000_vd43bbfq'}, {modelID: 'TS130F', manufacturerName: '_TZ3000_fccpjz5z'}],
|
|
@@ -260,38 +222,4 @@ module.exports = [
|
|
|
260
222
|
exposes.binary('calibration', ea.ALL, 'ON', 'OFF'), exposes.binary('motor_reversal', ea.ALL, 'ON', 'OFF'),
|
|
261
223
|
exposes.numeric('calibration_time', ea.STATE).withUnit('S').withDescription('Calibration time')],
|
|
262
224
|
},
|
|
263
|
-
{
|
|
264
|
-
fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_zxbtub8r'}],
|
|
265
|
-
model: 'TS110E_1gang',
|
|
266
|
-
vendor: 'Lonsonho',
|
|
267
|
-
description: 'Zigbee smart dimmer module 1 gang with neutral',
|
|
268
|
-
extend: extend.light_onoff_brightness(),
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_wdexaypg'}, {modelID: 'TS110E', manufacturerName: '_TZ3210_3mpwqzuu'}],
|
|
272
|
-
model: 'TS110E_2gang',
|
|
273
|
-
vendor: 'Lonsonho',
|
|
274
|
-
description: 'Zigbee smart dimmer module 2 gang with neutral',
|
|
275
|
-
fromZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
276
|
-
.fromZigbee.concat([tuya.fz.power_outage_memory, fzLocal.TS110E_switch_type]),
|
|
277
|
-
toZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
278
|
-
.toZigbee.concat([tuya.tz.power_on_behavior, tzLocal.TS110E_switch_type]),
|
|
279
|
-
meta: {multiEndpoint: true},
|
|
280
|
-
exposes: [
|
|
281
|
-
e.light_brightness().withEndpoint('l1'),
|
|
282
|
-
e.light_brightness().withEndpoint('l2'),
|
|
283
|
-
exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore']).withDescription('Recover state after power outage')
|
|
284
|
-
.withEndpoint('l1'),
|
|
285
|
-
exposes.presets.switch_type_2().withEndpoint('l1'),
|
|
286
|
-
exposes.presets.switch_type_2().withEndpoint('l2'),
|
|
287
|
-
],
|
|
288
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
289
|
-
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
290
|
-
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
291
|
-
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
292
|
-
},
|
|
293
|
-
endpoint: (device) => {
|
|
294
|
-
return {l1: 1, l2: 2};
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
225
|
];
|
package/devices/sinope.js
CHANGED
|
@@ -14,26 +14,30 @@ module.exports = [
|
|
|
14
14
|
vendor: 'Sinopé',
|
|
15
15
|
description: 'Zigbee line volt thermostat',
|
|
16
16
|
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
17
|
-
fromZigbee: [
|
|
18
|
-
fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
17
|
+
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
19
18
|
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_thermostat],
|
|
20
|
-
toZigbee: [
|
|
21
|
-
tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
19
|
+
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
22
20
|
tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
|
23
|
-
tz.
|
|
24
|
-
tz.
|
|
21
|
+
tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time, tz.sinope_thermostat_enable_outdoor_temperature,
|
|
22
|
+
tz.sinope_thermostat_outdoor_temperature, tz.thermostat_pi_heating_demand, tz.sinope_thermostat_occupancy,
|
|
23
|
+
tz.electrical_measurement_power],
|
|
25
24
|
exposes: [
|
|
26
25
|
exposes.climate()
|
|
27
26
|
.withSetpoint('occupied_heating_setpoint', 5, 30, 0.5)
|
|
28
27
|
.withSetpoint('unoccupied_heating_setpoint', 5, 30, 0.5)
|
|
29
28
|
.withLocalTemperature()
|
|
30
|
-
.withSystemMode(['off', 'heat']
|
|
31
|
-
.withPiHeatingDemand()
|
|
32
|
-
|
|
29
|
+
.withSystemMode(['off', 'heat'], ea.ALL, 'Mode of the thermostat')
|
|
30
|
+
.withPiHeatingDemand(ea.STATE_GET)
|
|
31
|
+
.withRunningState(['idle', 'heat']),
|
|
32
|
+
exposes.enum('thermostat_occupancy', ea.ALL, ['unoccupied', 'occupied'])
|
|
33
33
|
.withDescription('Occupancy state of the thermostat'),
|
|
34
|
-
exposes.enum('backlight_auto_dim', ea.
|
|
34
|
+
exposes.enum('backlight_auto_dim', ea.ALL, ['on demand', 'sensing'])
|
|
35
35
|
.withDescription('Control backlight dimming behavior'),
|
|
36
|
-
|
|
36
|
+
exposes.enum('keypad_lockout', ea.ALL, ['unlock', 'lock1'])
|
|
37
|
+
.withDescription('Enables or disables the device’s buttons'),
|
|
38
|
+
e.power().withAccess(ea.STATE_GET), e.current(), e.voltage(), e.energy(),
|
|
39
|
+
],
|
|
40
|
+
|
|
37
41
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
38
42
|
const endpoint = device.getEndpoint(1);
|
|
39
43
|
const binds = [
|
|
@@ -44,36 +48,26 @@ module.exports = [
|
|
|
44
48
|
await reporting.thermostatTemperature(endpoint);
|
|
45
49
|
await reporting.thermostatPIHeatingDemand(endpoint);
|
|
46
50
|
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
47
|
-
|
|
48
51
|
try {
|
|
49
52
|
await reporting.thermostatSystemMode(endpoint);
|
|
50
53
|
} catch (error) {/* Not all support this */}
|
|
51
|
-
|
|
52
54
|
try {
|
|
53
55
|
await reporting.thermostatRunningState(endpoint);
|
|
54
56
|
} catch (error) {/* Not all support this */}
|
|
55
57
|
|
|
56
58
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
57
59
|
await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
|
|
58
|
-
try {
|
|
59
|
-
await reporting.instantaneousDemand(endpoint, {min: 10, max: 304, change: 1});
|
|
60
|
-
} catch (error) {/* Do nothing*/}
|
|
61
|
-
|
|
62
60
|
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
63
61
|
try {
|
|
64
|
-
await
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
} catch (error) {/* Do nothing*/}
|
|
62
|
+
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
63
|
+
await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 1: 1W
|
|
64
|
+
} catch (error) {
|
|
65
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {'acPowerMultiplier': 1, 'acPowerDivisor': 1});
|
|
66
|
+
}
|
|
67
|
+
await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 100}); // divider 1000: 0.1Arms
|
|
68
|
+
await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 5}); // divider 10: 0.5Vrms
|
|
72
69
|
|
|
73
|
-
// Disable default reporting
|
|
74
|
-
await reporting.temperature(endpoint, {min: 1, max: 0xFFFF});
|
|
75
|
-
await endpoint.configureReporting('msTemperatureMeasurement', [
|
|
76
|
-
{attribute: 'tolerance', minimumReportInterval: 1, maximumReportInterval: 0xFFFF, reportableChange: 1}]);
|
|
70
|
+
await reporting.temperature(endpoint, {min: 1, max: 0xFFFF}); // Disable default reporting
|
|
77
71
|
},
|
|
78
72
|
},
|
|
79
73
|
{
|
|
@@ -82,26 +76,30 @@ module.exports = [
|
|
|
82
76
|
vendor: 'Sinopé',
|
|
83
77
|
description: 'Zigbee line volt thermostat',
|
|
84
78
|
meta: {thermostat: {dontMapPIHeatingDemand: true}},
|
|
85
|
-
fromZigbee: [
|
|
86
|
-
fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
79
|
+
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement, fz.metering,
|
|
87
80
|
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_thermostat],
|
|
88
|
-
toZigbee: [
|
|
89
|
-
tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
81
|
+
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
90
82
|
tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
|
91
|
-
tz.
|
|
92
|
-
tz.
|
|
83
|
+
tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time, tz.sinope_thermostat_enable_outdoor_temperature,
|
|
84
|
+
tz.sinope_thermostat_outdoor_temperature, tz.thermostat_pi_heating_demand, tz.sinope_thermostat_occupancy,
|
|
85
|
+
tz.electrical_measurement_power],
|
|
93
86
|
exposes: [
|
|
94
87
|
exposes.climate()
|
|
95
88
|
.withSetpoint('occupied_heating_setpoint', 5, 30, 0.5)
|
|
96
89
|
.withSetpoint('unoccupied_heating_setpoint', 5, 30, 0.5)
|
|
97
90
|
.withLocalTemperature()
|
|
98
|
-
.withSystemMode(['off', 'heat']
|
|
99
|
-
.withPiHeatingDemand()
|
|
100
|
-
|
|
91
|
+
.withSystemMode(['off', 'heat'], ea.ALL, 'Mode of the thermostat')
|
|
92
|
+
.withPiHeatingDemand(ea.STATE_GET)
|
|
93
|
+
.withRunningState(['idle', 'heat']),
|
|
94
|
+
exposes.enum('thermostat_occupancy', ea.ALL, ['unoccupied', 'occupied'])
|
|
101
95
|
.withDescription('Occupancy state of the thermostat'),
|
|
102
|
-
exposes.enum('backlight_auto_dim', ea.
|
|
96
|
+
exposes.enum('backlight_auto_dim', ea.ALL, ['on demand', 'sensing'])
|
|
103
97
|
.withDescription('Control backlight dimming behavior'),
|
|
104
|
-
|
|
98
|
+
exposes.enum('keypad_lockout', ea.ALL, ['unlock', 'lock1'])
|
|
99
|
+
.withDescription('Enables or disables the device’s buttons'),
|
|
100
|
+
e.power().withAccess(ea.STATE_GET), e.current(), e.voltage(), e.energy(),
|
|
101
|
+
],
|
|
102
|
+
|
|
105
103
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
106
104
|
const endpoint = device.getEndpoint(1);
|
|
107
105
|
const binds = [
|
|
@@ -112,32 +110,26 @@ module.exports = [
|
|
|
112
110
|
await reporting.thermostatTemperature(endpoint);
|
|
113
111
|
await reporting.thermostatPIHeatingDemand(endpoint);
|
|
114
112
|
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
115
|
-
|
|
113
|
+
try {
|
|
114
|
+
await reporting.thermostatSystemMode(endpoint);
|
|
115
|
+
} catch (error) {/* Not all support this */}
|
|
116
116
|
try {
|
|
117
117
|
await reporting.thermostatRunningState(endpoint);
|
|
118
118
|
} catch (error) {/* Not all support this */}
|
|
119
119
|
|
|
120
120
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
121
121
|
await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
|
|
122
|
-
try {
|
|
123
|
-
await reporting.instantaneousDemand(endpoint, {min: 10, max: 304, change: 1});
|
|
124
|
-
} catch (error) {/* Do nothing*/}
|
|
125
|
-
|
|
126
122
|
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
127
123
|
try {
|
|
128
|
-
await
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} catch (error) {/* Do nothing*/}
|
|
124
|
+
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
125
|
+
await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 1: 1W
|
|
126
|
+
} catch (error) {
|
|
127
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {'acPowerMultiplier': 1, 'acPowerDivisor': 1});
|
|
128
|
+
}
|
|
129
|
+
await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 100}); // divider 1000: 0.1Arms
|
|
130
|
+
await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 5}); // divider 10: 0.5Vrms
|
|
136
131
|
|
|
137
|
-
// Disable default reporting
|
|
138
|
-
await reporting.temperature(endpoint, {min: 1, max: 0xFFFF});
|
|
139
|
-
await endpoint.configureReporting('msTemperatureMeasurement', [
|
|
140
|
-
{attribute: 'tolerance', minimumReportInterval: 1, maximumReportInterval: 0xFFFF, reportableChange: 1}]);
|
|
132
|
+
await reporting.temperature(endpoint, {min: 1, max: 0xFFFF}); // Disable default reporting
|
|
141
133
|
},
|
|
142
134
|
},
|
|
143
135
|
{
|
|
@@ -163,7 +155,7 @@ module.exports = [
|
|
|
163
155
|
.withSystemMode(['off', 'auto', 'heat'])
|
|
164
156
|
.withRunningState(['idle', 'heat'])
|
|
165
157
|
.withPiHeatingDemand(),
|
|
166
|
-
exposes.enum('backlight_auto_dim', ea.
|
|
158
|
+
exposes.enum('backlight_auto_dim', ea.ALL, ['on demand', 'sensing'])
|
|
167
159
|
.withDescription('Control backlight dimming behavior'),
|
|
168
160
|
e.keypad_lockout(), e.power(), e.current(), e.voltage()],
|
|
169
161
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
@@ -228,7 +220,7 @@ module.exports = [
|
|
|
228
220
|
.withSystemMode(['off', 'auto', 'heat'])
|
|
229
221
|
.withRunningState(['idle', 'heat'])
|
|
230
222
|
.withPiHeatingDemand(),
|
|
231
|
-
exposes.enum('backlight_auto_dim', ea.
|
|
223
|
+
exposes.enum('backlight_auto_dim', ea.ALL, ['on demand', 'sensing'])
|
|
232
224
|
.withDescription('Control backlight dimming behavior')],
|
|
233
225
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
234
226
|
const endpoint = device.getEndpoint(1);
|
|
@@ -264,7 +256,7 @@ module.exports = [
|
|
|
264
256
|
.withSystemMode(['off', 'auto', 'heat'])
|
|
265
257
|
.withRunningState(['idle', 'heat'])
|
|
266
258
|
.withPiHeatingDemand(),
|
|
267
|
-
exposes.enum('backlight_auto_dim', ea.
|
|
259
|
+
exposes.enum('backlight_auto_dim', ea.ALL, ['on demand', 'sensing'])
|
|
268
260
|
.withDescription('Control backlight dimming behavior')],
|
|
269
261
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
270
262
|
const endpoint = device.getEndpoint(1);
|
|
@@ -350,8 +342,8 @@ module.exports = [
|
|
|
350
342
|
vendor: 'Sinopé',
|
|
351
343
|
description: 'Zigbee smart plug',
|
|
352
344
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
|
|
353
|
-
toZigbee: [tz.on_off],
|
|
354
|
-
exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.
|
|
345
|
+
toZigbee: [tz.on_off, tz.frequency],
|
|
346
|
+
exposes: [e.switch(), e.power(), e.current(), e.voltage(), e.energy(), e.ac_frequency().withAccess(ea.STATE_GET)],
|
|
355
347
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
356
348
|
const endpoint = device.getEndpoint(1);
|
|
357
349
|
const binds = ['genBasic', 'genIdentify', 'genOnOff', 'haElectricalMeasurement', 'seMetering'];
|
package/devices/sonoff.js
CHANGED
|
@@ -199,7 +199,7 @@ module.exports = [
|
|
|
199
199
|
await reporting.batteryVoltage(endpoint);
|
|
200
200
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
201
201
|
},
|
|
202
|
-
exposes: [e.occupancy(), e.battery_low(), e.
|
|
202
|
+
exposes: [e.occupancy(), e.battery_low(), e.battery(), e.battery_voltage()],
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
205
|
zigbeeModel: ['S26R2ZB'],
|
package/devices/tuya.js
CHANGED
|
@@ -17,23 +17,24 @@ const globalStore = require('../lib/store');
|
|
|
17
17
|
|
|
18
18
|
const tzLocal = {
|
|
19
19
|
TS110E_options: {
|
|
20
|
-
key: ['min_brightness', 'max_brightness', 'light_type'],
|
|
20
|
+
key: ['min_brightness', 'max_brightness', 'light_type', 'switch_type'],
|
|
21
21
|
convertSet: async (entity, key, value, meta) => {
|
|
22
22
|
let payload = null;
|
|
23
23
|
if (key === 'min_brightness' || key == 'max_brightness') {
|
|
24
24
|
const id = key === 'min_brightness' ? 64515 : 64516;
|
|
25
25
|
payload = {[id]: {value: utils.mapNumberRange(value, 1, 255, 0, 1000), type: 0x21}};
|
|
26
|
-
} else if (key === 'light_type') {
|
|
27
|
-
const lookup = {led: 0, incandescent: 1, halogen: 2};
|
|
26
|
+
} else if (key === 'light_type' || key === 'switch_type') {
|
|
27
|
+
const lookup = key === 'light_type' ? {led: 0, incandescent: 1, halogen: 2} : {momentary: 0, toggle: 1, state: 2};
|
|
28
28
|
payload = {64514: {value: lookup[value], type: 0x20}};
|
|
29
29
|
}
|
|
30
30
|
await entity.write('genLevelCtrl', payload, utils.getOptions(meta.mapped, entity));
|
|
31
|
+
return {state: {[key]: value}};
|
|
31
32
|
},
|
|
32
33
|
convertGet: async (entity, key, meta) => {
|
|
33
34
|
let id = null;
|
|
34
35
|
if (key === 'min_brightness') id = 64515;
|
|
35
36
|
if (key === 'max_brightness') id = 64516;
|
|
36
|
-
if (key === 'light_type') id = 64514;
|
|
37
|
+
if (key === 'light_type' || key === 'switch_type') id = 64514;
|
|
37
38
|
await entity.read('genLevelCtrl', [id]);
|
|
38
39
|
},
|
|
39
40
|
},
|
|
@@ -337,12 +338,33 @@ const fzLocal = {
|
|
|
337
338
|
if (msg.data.hasOwnProperty('64516')) {
|
|
338
339
|
result['max_brightness'] = utils.mapNumberRange(msg.data['64516'], 0, 1000, 1, 255);
|
|
339
340
|
}
|
|
341
|
+
if (msg.data.hasOwnProperty('61440')) {
|
|
342
|
+
result['brightness'] = utils.mapNumberRange(msg.data['61440'], 0, 1000, 0, 254);
|
|
343
|
+
}
|
|
344
|
+
return result;
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
TS110E_light_type: {
|
|
348
|
+
cluster: 'genLevelCtrl',
|
|
349
|
+
type: ['attributeReport', 'readResponse'],
|
|
350
|
+
convert: (model, msg, publish, options, meta) => {
|
|
351
|
+
const result = {};
|
|
340
352
|
if (msg.data.hasOwnProperty('64514')) {
|
|
341
353
|
const lookup = {0: 'led', 1: 'incandescent', 2: 'halogen'};
|
|
342
354
|
result['light_type'] = lookup[msg.data['64514']];
|
|
343
355
|
}
|
|
344
|
-
|
|
345
|
-
|
|
356
|
+
return result;
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
TS110E_switch_type: {
|
|
360
|
+
cluster: 'genLevelCtrl',
|
|
361
|
+
type: ['attributeReport', 'readResponse'],
|
|
362
|
+
convert: (model, msg, publish, options, meta) => {
|
|
363
|
+
const result = {};
|
|
364
|
+
if (msg.data.hasOwnProperty('64514')) {
|
|
365
|
+
const lookup = {0: 'momentary', 1: 'toggle', 2: 'state'};
|
|
366
|
+
const propertyName = utils.postfixWithEndpointName('switch_type', msg, model, meta);
|
|
367
|
+
result[propertyName] = lookup[msg.data['64514']];
|
|
346
368
|
}
|
|
347
369
|
return result;
|
|
348
370
|
},
|
|
@@ -1178,7 +1200,7 @@ module.exports = [
|
|
|
1178
1200
|
fromZigbee: [tuya.fz.datapoints],
|
|
1179
1201
|
toZigbee: [tuya.tz.datapoints],
|
|
1180
1202
|
configure: tuya.configureMagicPacket,
|
|
1181
|
-
exposes: [tuya.exposes.lightBrightnessWithMinMax(),
|
|
1203
|
+
exposes: [tuya.exposes.lightBrightnessWithMinMax(), e.power_on_behavior(),
|
|
1182
1204
|
tuya.exposes.countdown(), tuya.exposes.lightType()],
|
|
1183
1205
|
meta: {
|
|
1184
1206
|
tuyaDatapoints: [
|
|
@@ -1734,7 +1756,7 @@ module.exports = [
|
|
|
1734
1756
|
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
1735
1757
|
device.save();
|
|
1736
1758
|
},
|
|
1737
|
-
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(),
|
|
1759
|
+
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.energy(), tuya.exposes.switchType(),
|
|
1738
1760
|
exposes.enum('power_outage_memory', ea.ALL, ['on', 'off', 'restore']).withDescription('Recover state after power outage')],
|
|
1739
1761
|
},
|
|
1740
1762
|
{
|
|
@@ -1756,7 +1778,7 @@ module.exports = [
|
|
|
1756
1778
|
device.save();
|
|
1757
1779
|
},
|
|
1758
1780
|
whiteLabel: [{vendor: 'Aubess', model: 'WDH02'}],
|
|
1759
|
-
exposes: [e.switch(), e.power(), e.voltage().withAccess(ea.STATE), e.energy(), e.power_on_behavior(),
|
|
1781
|
+
exposes: [e.switch(), e.power(), e.voltage().withAccess(ea.STATE), e.energy(), e.power_on_behavior(), tuya.exposes.switchType()],
|
|
1760
1782
|
},
|
|
1761
1783
|
{
|
|
1762
1784
|
zigbeeModel: ['TS0001'],
|
|
@@ -2324,7 +2346,7 @@ module.exports = [
|
|
|
2324
2346
|
},
|
|
2325
2347
|
{
|
|
2326
2348
|
fingerprint: [160, 69, 68, 65, 64].map((applicationVersion) => {
|
|
2327
|
-
return {modelID: 'TS011F', applicationVersion};
|
|
2349
|
+
return {modelID: 'TS011F', applicationVersion, priority: -1};
|
|
2328
2350
|
}),
|
|
2329
2351
|
model: 'TS011F_plug_3',
|
|
2330
2352
|
description: 'Smart plug (with power monitoring by polling)',
|
|
@@ -3483,23 +3505,56 @@ module.exports = [
|
|
|
3483
3505
|
],
|
|
3484
3506
|
},
|
|
3485
3507
|
},
|
|
3508
|
+
{
|
|
3509
|
+
fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_zxbtub8r'}],
|
|
3510
|
+
model: 'TS110E_1gang_1',
|
|
3511
|
+
vendor: 'TuYa',
|
|
3512
|
+
description: '1 channel dimmer',
|
|
3513
|
+
extend: extend.light_onoff_brightness(),
|
|
3514
|
+
},
|
|
3486
3515
|
{
|
|
3487
3516
|
fingerprint: tuya.fingerprint('TS110E', ['_TZ3210_ngqk6jia']),
|
|
3488
|
-
model: '
|
|
3517
|
+
model: 'TS110E_1gang_2',
|
|
3489
3518
|
vendor: 'TuYa',
|
|
3490
3519
|
description: '1 channel dimmer',
|
|
3491
3520
|
whiteLabel: [{vendor: 'RTX', model: 'QS-Zigbee-D02-TRIAC-LN'}],
|
|
3492
|
-
fromZigbee: [fzLocal.TS110E, tuya.fz.power_on_behavior, fz.on_off],
|
|
3521
|
+
fromZigbee: [fzLocal.TS110E, fzLocal.TS110E_light_type, tuya.fz.power_on_behavior, fz.on_off],
|
|
3493
3522
|
toZigbee: [tzLocal.TS110E_onoff_brightness, tzLocal.TS110E_options, tuya.tz.power_on_behavior, tz.light_brightness_move],
|
|
3494
3523
|
exposes: [
|
|
3495
3524
|
e.light_brightness().withMinBrightness().withMaxBrightness(),
|
|
3496
|
-
tuya.exposes.lightType().withAccess(ea.ALL),
|
|
3525
|
+
tuya.exposes.lightType().withAccess(ea.ALL), e.power_on_behavior().withAccess(ea.ALL)],
|
|
3497
3526
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
3498
3527
|
const endpoint = device.getEndpoint(1);
|
|
3499
3528
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
3500
3529
|
await reporting.onOff(endpoint);
|
|
3501
3530
|
},
|
|
3502
3531
|
},
|
|
3532
|
+
{
|
|
3533
|
+
fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_wdexaypg'}, {modelID: 'TS110E', manufacturerName: '_TZ3210_3mpwqzuu'}],
|
|
3534
|
+
model: 'TS110E_2gang',
|
|
3535
|
+
vendor: 'TuYa',
|
|
3536
|
+
description: '2 channel dimmer',
|
|
3537
|
+
fromZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
3538
|
+
.fromZigbee.concat([tuya.fz.power_on_behavior, fzLocal.TS110E_switch_type, fzLocal.TS110E]),
|
|
3539
|
+
toZigbee: extend.light_onoff_brightness({disablePowerOnBehavior: true, disableMoveStep: true, disableTransition: true})
|
|
3540
|
+
.toZigbee.concat([tuya.tz.power_on_behavior, tzLocal.TS110E_options]),
|
|
3541
|
+
meta: {multiEndpoint: true},
|
|
3542
|
+
exposes: [
|
|
3543
|
+
e.light_brightness().withMinBrightness().withMaxBrightness().withEndpoint('l1'),
|
|
3544
|
+
e.light_brightness().withMinBrightness().withMaxBrightness().withEndpoint('l2'),
|
|
3545
|
+
e.power_on_behavior(),
|
|
3546
|
+
tuya.exposes.switchType().withEndpoint('l1'),
|
|
3547
|
+
tuya.exposes.switchType().withEndpoint('l2'),
|
|
3548
|
+
],
|
|
3549
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
3550
|
+
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
3551
|
+
await reporting.bind(device.getEndpoint(1), coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
3552
|
+
await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
|
|
3553
|
+
},
|
|
3554
|
+
endpoint: (device) => {
|
|
3555
|
+
return {l1: 1, l2: 2};
|
|
3556
|
+
},
|
|
3557
|
+
},
|
|
3503
3558
|
{
|
|
3504
3559
|
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_nslr42tt']),
|
|
3505
3560
|
model: 'TS0601_3_phase_clamp_meter',
|
package/index.js
CHANGED
|
@@ -142,16 +142,23 @@ function findByDevice(device) {
|
|
|
142
142
|
return candidates[0];
|
|
143
143
|
} else {
|
|
144
144
|
// First try to match based on fingerprint, return the first matching one.
|
|
145
|
+
const fingerprintMatch = {priority: null, definition: null};
|
|
145
146
|
for (const candidate of candidates) {
|
|
146
147
|
if (candidate.hasOwnProperty('fingerprint')) {
|
|
147
148
|
for (const fingerprint of candidate.fingerprint) {
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
const priority = fingerprint.hasOwnProperty('priority') ? fingerprint.priority : 0;
|
|
150
|
+
if (isFingerprintMatch(fingerprint, device) && (!fingerprintMatch.definition || priority > fingerprintMatch.priority)) {
|
|
151
|
+
fingerprintMatch.definition = candidate;
|
|
152
|
+
fingerprintMatch.priority = priority;
|
|
150
153
|
}
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
157
|
|
|
158
|
+
if (fingerprintMatch.definition) {
|
|
159
|
+
return fingerprintMatch.definition;
|
|
160
|
+
}
|
|
161
|
+
|
|
155
162
|
// Match based on fingerprint failed, return first matching definition based on zigbeeModel
|
|
156
163
|
for (const candidate of candidates) {
|
|
157
164
|
if (candidate.hasOwnProperty('zigbeeModel') && candidate.zigbeeModel.includes(device.modelID)) {
|
|
@@ -163,7 +170,7 @@ function findByDevice(device) {
|
|
|
163
170
|
return null;
|
|
164
171
|
}
|
|
165
172
|
|
|
166
|
-
function
|
|
173
|
+
function isFingerprintMatch(fingerprint, device) {
|
|
167
174
|
let match =
|
|
168
175
|
(!fingerprint.applicationVersion || device.applicationVersion === fingerprint.applicationVersion) &&
|
|
169
176
|
(!fingerprint.manufacturerID || device.manufacturerID === fingerprint.manufacturerID) &&
|
package/lib/exposes.js
CHANGED
|
@@ -612,7 +612,6 @@ module.exports = {
|
|
|
612
612
|
sound_volume: () => new Enum('sound_volume', access.ALL, constants.lockSoundVolume).withDescription('Sound volume of the lock'),
|
|
613
613
|
switch: () => new Switch().withState('state', true, 'On/off state of the switch'),
|
|
614
614
|
switch_type: () => new Enum('switch_type', access.ALL, ['toggle', 'momentary']).withDescription('Wall switch type'),
|
|
615
|
-
switch_type_2: () => new Enum('switch_type', access.ALL, ['toggle', 'state', 'momentary']).withDescription('Switch type settings'),
|
|
616
615
|
tamper: () => new Binary('tamper', access.STATE, true, false).withDescription('Indicates whether the device is tampered'),
|
|
617
616
|
temperature: () => new Numeric('temperature', access.STATE).withUnit('°C').withDescription('Measured temperature value'),
|
|
618
617
|
temperature_sensor_select: (sensor_names) => new Enum('sensor', access.STATE_SET, sensor_names).withDescription('Select temperature sensor to use'),
|
package/lib/tuya.js
CHANGED
|
@@ -1117,8 +1117,6 @@ async function sendDataPointStringBuffer(entity, dp, value, cmd, seq=undefined)
|
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
1119
|
const tuyaExposes = {
|
|
1120
|
-
powerOnBehavior: () => exposes.enum('power_on_behavior', ea.STATE_SET, ['off', 'on', 'previous'])
|
|
1121
|
-
.withDescription('Controls the behavior when the device is powered on'),
|
|
1122
1120
|
lightType: () => exposes.enum('light_type', ea.STATE_SET, ['led', 'incandescent', 'halogen'])
|
|
1123
1121
|
.withDescription('Type of light attached to the device'),
|
|
1124
1122
|
lightBrightnessWithMinMax: () => e.light_brightness().withMinBrightness().withMaxBrightness()
|