zigbee-herdsman-converters 14.0.457 → 14.0.460

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.
@@ -44,6 +44,9 @@ const converters = {
44
44
  result[postfixWithEndpointName('local_temperature_calibration', msg, model)] =
45
45
  precisionRound(msg.data['localTemperatureCalibration'], 2) / 10;
46
46
  }
47
+ if (msg.data.hasOwnProperty('outdoorTemp')) {
48
+ result[postfixWithEndpointName('outdoor_temperature', msg, model)] = precisionRound(msg.data['outdoorTemp'], 2) / 100;
49
+ }
47
50
  if (msg.data.hasOwnProperty('occupancy')) {
48
51
  result[postfixWithEndpointName('occupancy', msg, model)] = (msg.data.occupancy % 2) > 0;
49
52
  }
@@ -3389,6 +3392,23 @@ const converters = {
3389
3392
  if (msg.data.hasOwnProperty('danfossLoadEstimate')) {
3390
3393
  result[postfixWithEndpointName('load_estimate', msg, model)] = msg.data['danfossLoadEstimate'];
3391
3394
  }
3395
+ if (msg.data.hasOwnProperty('danfossPreheatStatus')) {
3396
+ result[postfixWithEndpointName('preheat_status', msg, model)] = (msg.data['danfossPreheatStatus'] === 1);
3397
+ }
3398
+ if (msg.data.hasOwnProperty('danfossAdaptionRunStatus')) {
3399
+ result[postfixWithEndpointName('adaptation_run_status', msg, model)] =
3400
+ constants.danfossAdaptionRunStatus[msg.data['danfossAdaptionRunStatus']];
3401
+ }
3402
+ if (msg.data.hasOwnProperty('danfossAdaptionRunSettings')) {
3403
+ result[postfixWithEndpointName('adaptation_run_settings', msg, model)] = (msg.data['danfossAdaptionRunSettings'] === 1);
3404
+ }
3405
+ if (msg.data.hasOwnProperty('danfossAdaptionRunControl')) {
3406
+ result[postfixWithEndpointName('adaptation_run_control', msg, model)] =
3407
+ constants.danfossAdaptionRunControl[msg.data['danfossAdaptionRunControl']];
3408
+ }
3409
+ if (msg.data.hasOwnProperty('danfossRegulationSetpointOffset')) {
3410
+ result[postfixWithEndpointName('regulation_setpoint_offset', msg, model)] = msg.data['danfossRegulationSetpointOffset'];
3411
+ }
3392
3412
  // Danfoss Icon Converters
3393
3413
  if (msg.data.hasOwnProperty('danfossRoomStatusCode')) {
3394
3414
  result[postfixWithEndpointName('room_status_code', msg, model)] =
@@ -4983,6 +5003,12 @@ const converters = {
4983
5003
  case tuya.dataPoints.state:
4984
5004
  result.smoke = value === 0;
4985
5005
  break;
5006
+ case 14:
5007
+ // battery state, ignore
5008
+ break;
5009
+ case 15:
5010
+ result.battery = value;
5011
+ break;
4986
5012
  default:
4987
5013
  meta.logger.warn(`zigbee-herdsman-converters:tuya_smoke: Unrecognized DP #${ dp} with data ${JSON.stringify(dpValue)}`);
4988
5014
  }
@@ -5653,38 +5679,15 @@ const converters = {
5653
5679
  type: ['attributeReport', 'readResponse'],
5654
5680
  options: [exposes.options.invert_cover()],
5655
5681
  convert: (model, msg, publish, options, meta) => {
5656
- let running = false;
5657
-
5658
5682
  if (model.model === 'ZNCLDJ12LM' && msg.type === 'attributeReport' && [0, 2].includes(msg.data['presentValue'])) {
5659
5683
  // Incorrect reports from the device, ignore (re-read by onEvent of ZNCLDJ12LM)
5660
5684
  // https://github.com/Koenkk/zigbee-herdsman-converters/pull/1427#issuecomment-663862724
5661
5685
  return;
5662
5686
  }
5663
5687
 
5664
- if (msg.data['61440']) {
5665
- const value = msg.data['61440'];
5666
- // 63025664 comes from https://github.com/Koenkk/zigbee2mqtt/issues/5155#issuecomment-753344248
5667
- running = value !== 0 && value !== 63025664;
5668
- }
5669
-
5670
5688
  let position = precisionRound(msg.data['presentValue'], 2);
5671
5689
  position = options.invert_cover ? 100 - position : position;
5672
- return {position: position, running: running};
5673
- },
5674
- },
5675
- xiaomi_curtain_options: {
5676
- cluster: 'genBasic',
5677
- type: ['attributeReport', 'readResponse'],
5678
- convert: (model, msg, publish, options, meta) => {
5679
- const data = msg.data['1025'];
5680
- if (data) {
5681
- return {
5682
- options: { // next values update only when curtain finished initial setup and knows current position
5683
- reverse_direction: data[2]=='\u0001',
5684
- hand_open: data[5]=='\u0000',
5685
- },
5686
- };
5687
- }
5690
+ return {position};
5688
5691
  },
5689
5692
  },
5690
5693
  xiaomi_curtain_acn002_position: {
@@ -1242,6 +1242,12 @@ const converters = {
1242
1242
  await entity.read('hvacThermostat', ['localTemp']);
1243
1243
  },
1244
1244
  },
1245
+ thermostat_outdoor_temperature: {
1246
+ key: ['outdoor_temperature'],
1247
+ convertGet: async (entity, key, meta) => {
1248
+ await entity.read('hvacThermostat', ['outdoorTemp']);
1249
+ },
1250
+ },
1245
1251
  thermostat_local_temperature_calibration: {
1246
1252
  key: ['local_temperature_calibration'],
1247
1253
  convertSet: async (entity, key, value, meta) => {
@@ -2112,7 +2118,7 @@ const converters = {
2112
2118
  xiaomi_switch_power_outage_memory: {
2113
2119
  key: ['power_outage_memory'],
2114
2120
  convertSet: async (entity, key, value, meta) => {
2115
- if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
2121
+ if (['SP-EUC01', 'ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
2116
2122
  'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
2117
2123
  'QBKG31LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM'].includes(meta.mapped.model)) {
2118
2124
  await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
@@ -2135,7 +2141,7 @@ const converters = {
2135
2141
  return {state: {power_outage_memory: value}};
2136
2142
  },
2137
2143
  convertGet: async (entity, key, meta) => {
2138
- if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
2144
+ if (['SP-EUC01', 'ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
2139
2145
  'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
2140
2146
  'QBKG31LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM'].includes(meta.mapped.model)) {
2141
2147
  await entity.read('aqaraOpple', [0x0201]);
@@ -2848,6 +2854,53 @@ const converters = {
2848
2854
  await entity.read('hvacThermostat', ['danfossLoadEstimate'], manufacturerOptions.danfoss);
2849
2855
  },
2850
2856
  },
2857
+ danfoss_preheat_status: {
2858
+ key: ['preheat_status'],
2859
+ convertGet: async (entity, key, meta) => {
2860
+ await entity.read('hvacThermostat', ['danfossPreheatStatus'], manufacturerOptions.danfoss);
2861
+ },
2862
+ },
2863
+ danfoss_adaptation_status: {
2864
+ key: ['adaptation_run_status'],
2865
+ convertGet: async (entity, key, meta) => {
2866
+ await entity.read('hvacThermostat', ['danfossAdaptionRunStatus'], manufacturerOptions.danfoss);
2867
+ },
2868
+ },
2869
+ danfoss_adaptation_settings: {
2870
+ key: ['adaptation_run_settings'],
2871
+ convertSet: async (entity, key, value, meta) => {
2872
+ await entity.write('hvacThermostat', {'danfossAdaptionRunSettings': value}, manufacturerOptions.danfoss);
2873
+ return {readAfterWriteTime: 200, state: {'adaptation_run_settings': value}};
2874
+ },
2875
+
2876
+ convertGet: async (entity, key, meta) => {
2877
+ await entity.read('hvacThermostat', ['danfossAdaptionRunSettings'], manufacturerOptions.danfoss);
2878
+ },
2879
+ },
2880
+ danfoss_adaptation_control: {
2881
+ key: ['adaptation_run_control'],
2882
+ convertSet: async (entity, key, value, meta) => {
2883
+ const payload = {'danfossAdaptionRunControl': utils.getKey(constants.danfossAdaptionRunControl, value, value, Number)};
2884
+ await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
2885
+ return {readAfterWriteTime: 250, state: {'adaptation_run_control': value}};
2886
+ },
2887
+
2888
+ convertGet: async (entity, key, meta) => {
2889
+ await entity.read('hvacThermostat', ['danfossAdaptionRunControl'], manufacturerOptions.danfoss);
2890
+ },
2891
+ },
2892
+ danfoss_regulation_setpoint_offset: {
2893
+ key: ['regulation_setpoint_offset'],
2894
+ convertSet: async (entity, key, value, meta) => {
2895
+ const payload = {'danfossRegulationSetpointOffset': value};
2896
+ await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
2897
+ return {readAfterWriteTime: 250, state: {'regulation_setpoint_offset': value}};
2898
+ },
2899
+
2900
+ convertGet: async (entity, key, meta) => {
2901
+ await entity.read('hvacThermostat', ['danfossRegulationSetpointOffset'], manufacturerOptions.danfoss);
2902
+ },
2903
+ },
2851
2904
  danfoss_output_status: {
2852
2905
  key: ['output_status'],
2853
2906
  convertGet: async (entity, key, meta) => {
@@ -24,7 +24,8 @@ module.exports = [
24
24
  tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.danfoss_radiator_covered,
25
25
  tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean,
26
26
  tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_programming_operation_mode,
27
- tz.danfoss_window_open_feature],
27
+ tz.danfoss_window_open_feature, tz.danfoss_preheat_status, tz.danfoss_adaptation_status, tz.danfoss_adaptation_settings,
28
+ tz.danfoss_adaptation_control, tz.danfoss_regulation_setpoint_offset],
28
29
  exposes: [e.battery(), e.keypad_lockout(), e.programming_operation_mode(),
29
30
  exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
30
31
  .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
@@ -78,7 +79,19 @@ module.exports = [
78
79
  .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
79
80
  .withValueMin(-8000).withValueMax(2000),
80
81
  exposes.numeric('load_estimate', ea.STATE_GET)
81
- .withDescription('Load estimate on this radiator')],
82
+ .withDescription('Load estimate on this radiator'),
83
+ exposes.binary('preheat_status', ea.STATE_GET, true, false)
84
+ .withDescription('Specific for pre-heat running in Zigbee Weekly Schedule mode'),
85
+ exposes.enum('adaptation_run_status', ea.STATE_GET, ['none', 'in_progress', 'found', 'lost'])
86
+ .withDescription('Status of adaptation run: None (before first run), In Progress, Valve Characteristic Found, ' +
87
+ 'Valve Characteristic Lost'),
88
+ exposes.binary('adaptation_run_settings', ea.ALL, true, false)
89
+ .withDescription('Automatic adaptation run enabled (the one during the night)'),
90
+ exposes.enum('adaptation_run_control', ea.ALL, ['initate_adaptation', 'cancel_adaptation'])
91
+ .withDescription('Adaptation run control: Initiate Adaptation Run or Cancel Adaptation Run'),
92
+ exposes.numeric('regulation_setpoint_offset', ea.ALL)
93
+ .withDescription('Regulation SetPoint Offset in range -2.5°C to 2.5°C in steps of 0.1°C. Value 2.5°C = 25.')
94
+ .withValueMin(-25).withValueMax(25)],
82
95
  ota: ota.zigbeeOTA,
83
96
  configure: async (device, coordinatorEndpoint, logger) => {
84
97
  const endpoint = device.getEndpoint(1);
@@ -117,20 +130,41 @@ module.exports = [
117
130
  reportableChange: 1,
118
131
  }], options);
119
132
 
120
- await endpoint.read('hvacThermostat', [
121
- 'danfossWindowOpenFeatureEnable',
122
- 'danfossWindowOpenExternal',
123
- 'danfossDayOfWeek',
124
- 'danfossTriggerTime',
125
- 'danfossAlgorithmScaleFactor',
126
- 'danfossHeatAvailable',
127
- 'danfossMountedModeControl',
128
- 'danfossMountedModeActive',
129
- 'danfossExternalMeasuredRoomSensor',
130
- 'danfossRadiatorCovered',
131
- 'danfossLoadBalancingEnable',
132
- 'danfossLoadRoomMean',
133
- ], options);
133
+ await endpoint.configureReporting('hvacThermostat', [{
134
+ attribute: 'danfossPreheatStatus',
135
+ minimumReportInterval: constants.repInterval.MINUTE,
136
+ maximumReportInterval: constants.repInterval.MAX,
137
+ reportableChange: 1,
138
+ }], options);
139
+
140
+ await endpoint.configureReporting('hvacThermostat', [{
141
+ attribute: 'danfossAdaptionRunStatus',
142
+ minimumReportInterval: constants.repInterval.MINUTE,
143
+ maximumReportInterval: constants.repInterval.HOUR,
144
+ reportableChange: 1,
145
+ }], options);
146
+
147
+ try {
148
+ await endpoint.read('hvacThermostat', [
149
+ 'danfossWindowOpenFeatureEnable',
150
+ 'danfossWindowOpenExternal',
151
+ 'danfossDayOfWeek',
152
+ 'danfossTriggerTime',
153
+ 'danfossAlgorithmScaleFactor',
154
+ 'danfossHeatAvailable',
155
+ 'danfossMountedModeControl',
156
+ 'danfossMountedModeActive',
157
+ 'danfossExternalMeasuredRoomSensor',
158
+ 'danfossRadiatorCovered',
159
+ 'danfossLoadBalancingEnable',
160
+ 'danfossLoadRoomMean',
161
+ 'danfossAdaptionRunControl',
162
+ 'danfossAdaptionRunSettings',
163
+ 'danfossRegulationSetpointOffset',
164
+ ], options);
165
+ } catch (e) {
166
+ /* not supported by all https://github.com/Koenkk/zigbee2mqtt/issues/11872 */
167
+ }
134
168
 
135
169
  // read systemMode to have an initial value
136
170
  await endpoint.read('hvacThermostat', ['systemMode']);
package/devices/innr.js CHANGED
@@ -95,6 +95,14 @@ module.exports = [
95
95
  extend: extend.light_onoff_brightness(),
96
96
  meta: {turnsOffAtBrightness1: true},
97
97
  },
98
+ {
99
+ zigbeeModel: ['BY 266'],
100
+ model: 'BY 266',
101
+ vendor: 'Innr',
102
+ description: 'B22 (Bayonet) bulb, dimmable',
103
+ extend: extend.light_onoff_brightness(),
104
+ meta: {turnsOffAtBrightness1: true},
105
+ },
98
106
  {
99
107
  zigbeeModel: ['RB 266'],
100
108
  model: 'RB 266',
@@ -288,6 +296,14 @@ module.exports = [
288
296
  extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
289
297
  meta: {applyRedFix: true, turnsOffAtBrightness1: true},
290
298
  },
299
+ {
300
+ zigbeeModel: ['RB 249 T'],
301
+ model: 'RB 249 T',
302
+ vendor: 'Innr',
303
+ description: 'E14 candle, dimmable with, color temp',
304
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [200, 454]}),
305
+ meta: {turnsOffAtBrightness1: true},
306
+ },
291
307
  {
292
308
  zigbeeModel: ['RB 148 T'],
293
309
  model: 'RB 148 T',
package/devices/namron.js CHANGED
@@ -1,7 +1,10 @@
1
1
  const exposes = require('../lib/exposes');
2
2
  const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
+ const tz = require('../converters/toZigbee');
4
+ const constants = require('../lib/constants');
3
5
  const reporting = require('../lib/reporting');
4
6
  const extend = require('../lib/extend');
7
+ const ea = exposes.access;
5
8
  const e = exposes.presets;
6
9
 
7
10
  module.exports = [
@@ -255,4 +258,59 @@ module.exports = [
255
258
  meta: {turnsOffAtBrightness1: true},
256
259
  extend: extend.light_onoff_brightness_colortemp_color(),
257
260
  },
261
+ {
262
+ zigbeeModel: ['4512737'],
263
+ model: '4512737',
264
+ vendor: 'Namron',
265
+ description: 'Touch termostat',
266
+ fromZigbee: [fz.thermostat, fz.metering, fz.electrical_measurement, fz.hvac_user_interface],
267
+ toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint, tz.thermostat_occupancy,
268
+ tz.thermostat_local_temperature_calibration, tz.thermostat_local_temperature, tz.thermostat_outdoor_temperature,
269
+ tz.thermostat_system_mode, tz.thermostat_control_sequence_of_operation, tz.thermostat_running_state,
270
+ tz.thermostat_keypad_lockout],
271
+ exposes: [
272
+ e.local_temperature(),
273
+ exposes.numeric('outdoor_temperature', ea.STATE_GET).withUnit('°C')
274
+ .withDescription('Current temperature measured from the floor sensor'),
275
+ e.keypad_lockout(),
276
+ exposes.climate()
277
+ .withSetpoint('occupied_heating_setpoint', 5, 50, 0.01)
278
+ .withLocalTemperature()
279
+ .withLocalTemperatureCalibration(-30, 30, 0.1)
280
+ .withSystemMode(['off', 'auto', 'heat'])
281
+ .withRunningState(['idle', 'heat']),
282
+ e.power(), e.current(), e.voltage(), e.energy(),
283
+ ],
284
+ configure: async (device, coordinatorEndpoint, logger) => {
285
+ const endpoint = device.getEndpoint(1);
286
+ const binds = [
287
+ 'genBasic', 'genIdentify', 'genGroups', 'genScenes', 'hvacThermostat',
288
+ 'seMetering', 'haElectricalMeasurement', 'genAlarms', 'msOccupancySensing', 'genTime', 'hvacUserInterfaceCfg',
289
+ ];
290
+ await reporting.bind(endpoint, coordinatorEndpoint, binds);
291
+
292
+ // standard ZCL attributes
293
+ await reporting.thermostatTemperature(endpoint);
294
+ await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
295
+ await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
296
+ await reporting.thermostatKeypadLockMode(endpoint);
297
+
298
+ await endpoint.configureReporting('hvacThermostat', [{
299
+ attribute: 'ocupancy',
300
+ minimumReportInterval: 0,
301
+ maximumReportInterval: constants.repInterval.HOUR,
302
+ reportableChange: null,
303
+ }]);
304
+
305
+ await reporting.activePower(endpoint);
306
+ await reporting.currentSummDelivered(endpoint);
307
+ await reporting.readMeteringMultiplierDivisor(endpoint);
308
+ await reporting.rmsCurrent(endpoint);
309
+ await reporting.rmsVoltage(endpoint);
310
+ await reporting.readMeteringMultiplierDivisor(endpoint);
311
+
312
+ // Trigger read
313
+ await endpoint.read('hvacThermostat', ['systemMode', 'runningState', 'occupied_heating_setpoint']);
314
+ },
315
+ },
258
316
  ];
package/devices/niko.js CHANGED
@@ -11,17 +11,30 @@ module.exports = [
11
11
  model: '170-33505',
12
12
  vendor: 'Niko',
13
13
  description: 'Connected socket outlet',
14
- fromZigbee: [fz.on_off, fz.electrical_measurement],
15
- toZigbee: [tz.on_off, tz.electrical_measurement_power],
14
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
15
+ toZigbee: [tz.on_off, tz.electrical_measurement_power, tz.currentsummdelivered],
16
16
  configure: async (device, coordinatorEndpoint, logger) => {
17
17
  const endpoint = device.getEndpoint(1);
18
- await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
19
- await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
18
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
19
+ await reporting.onOff(endpoint);
20
+
21
+ // NOTE: we read them individually, acFrequency* is not supported
22
+ // so we cannot use readEletricalMeasurementMultiplierDivisors
23
+ await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
20
24
  await reporting.activePower(endpoint, {min: 5, max: 3600, change: 1000});
25
+ await endpoint.read('haElectricalMeasurement', ['acCurrentDivisor', 'acPowerMultiplier', 'acPowerDivisor']);
21
26
  await reporting.rmsCurrent(endpoint, {min: 5, max: 3600, change: 100});
27
+ await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor', 'acCurrentMultiplier']);
22
28
  await reporting.rmsVoltage(endpoint, {min: 5, max: 3600, change: 100});
29
+
30
+ await reporting.readMeteringMultiplierDivisor(endpoint);
31
+ await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
23
32
  },
24
- exposes: [e.switch(), e.power().withAccess(ea.STATE_GET), e.current(), e.voltage()],
33
+ exposes: [
34
+ e.switch(),
35
+ e.power().withAccess(ea.STATE_GET), e.current(), e.voltage(),
36
+ e.energy().withAccess(ea.STATE_GET),
37
+ ],
25
38
  },
26
39
  {
27
40
  zigbeeModel: ['Smart plug Zigbee PE'],
@@ -29,7 +42,7 @@ module.exports = [
29
42
  vendor: 'Niko',
30
43
  description: 'Smart plug with earthing pin',
31
44
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.power_on_behavior],
32
- toZigbee: [tz.on_off, tz.power_on_behavior, tz.electrical_measurement_power],
45
+ toZigbee: [tz.on_off, tz.power_on_behavior, tz.electrical_measurement_power, tz.currentsummdelivered],
33
46
  configure: async (device, coordinatorEndpoint, logger) => {
34
47
  const endpoint = device.getEndpoint(1);
35
48
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
@@ -41,7 +54,7 @@ module.exports = [
41
54
  await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
42
55
  },
43
56
  exposes: [
44
- e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(),
57
+ e.switch(), e.power().withAccess(ea.STATE_GET), e.energy().withAccess(ea.STATE_GET),
45
58
  exposes.enum('power_on_behavior', ea.ALL, ['off', 'previous', 'on'])
46
59
  .withDescription('Controls the behaviour when the device is powered on'),
47
60
  ],
@@ -694,4 +694,24 @@ module.exports = [
694
694
  },
695
695
  exposes: [e.battery(), e.illuminance(), e.illuminance_lux(), e.occupancy()],
696
696
  },
697
+ {
698
+ zigbeeModel: ['CH/Socket/2'],
699
+ model: '3025CSGZ',
700
+ vendor: 'Schneider Electric',
701
+ description: 'Dual connected smart socket',
702
+ extend: extend.switch(),
703
+ exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2')],
704
+ meta: {multiEndpoint: true},
705
+ endpoint: (device) => {
706
+ return {'l1': 1, 'l2': 2};
707
+ },
708
+ configure: async (device, coordinatorEndpoint, logger) => {
709
+ const endpoint1 = device.getEndpoint(1);
710
+ await reporting.bind(endpoint1, coordinatorEndpoint, ['genOnOff']);
711
+ await reporting.onOff(endpoint1);
712
+ const endpoint2 = device.getEndpoint(2);
713
+ await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
714
+ await reporting.onOff(endpoint2);
715
+ },
716
+ },
697
717
  ];
package/devices/tuya.js CHANGED
@@ -12,7 +12,7 @@ const utils = require('../lib/utils');
12
12
 
13
13
  const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
14
14
  '_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
15
- '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo'];
15
+ '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo', '_TZ3000_ksw8qtmt'];
16
16
 
17
17
  const tzLocal = {
18
18
  TS0504B_color: {
@@ -97,13 +97,14 @@ module.exports = [
97
97
  description: 'Door sensor',
98
98
  fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
99
99
  toZigbee: [],
100
- exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery()],
100
+ exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage()],
101
101
  whiteLabel: [{vendor: 'CR Smart Home', model: 'TS0203'}],
102
102
  configure: async (device, coordinatorEndpoint, logger) => {
103
103
  try {
104
104
  const endpoint = device.getEndpoint(1);
105
105
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
106
106
  await reporting.batteryPercentageRemaining(endpoint);
107
+ await reporting.batteryVoltage(endpoint);
107
108
  } catch (error) {/* Fails for some*/}
108
109
  },
109
110
  },
@@ -234,6 +235,7 @@ module.exports = [
234
235
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_jmiuubkz'},
235
236
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
236
237
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
238
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_it1u8ahz'},
237
239
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_k1pe6ibm'},
238
240
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'},
239
241
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_leyz4rju'},
@@ -1028,8 +1030,6 @@ module.exports = [
1028
1030
  toZigbee: [tz.tuya_cover_control, tz.tuya_cover_options],
1029
1031
  exposes: [
1030
1032
  e.cover_position().setAccess('position', ea.STATE_SET),
1031
- exposes.binary('running', ea.STATE, true, false)
1032
- .withDescription('Whether the motor is moving or not'),
1033
1033
  exposes.composite('options', 'options')
1034
1034
  .withFeature(exposes.numeric('motor_speed', ea.STATE_SET)
1035
1035
  .withValueMin(0)
@@ -1274,7 +1274,7 @@ module.exports = [
1274
1274
  description: 'Smart plug (with power monitoring)',
1275
1275
  vendor: 'TuYa',
1276
1276
  whiteLabel: [{vendor: 'LELLKI', model: 'TS011F_plug'}, {vendor: 'NEO', model: 'NAS-WR01B'},
1277
- {vendor: 'BlitzWolf', model: 'BW-SHP15'}],
1277
+ {vendor: 'BlitzWolf', model: 'BW-SHP15'}, {vendor: 'Nous', model: 'A1Z'}],
1278
1278
  ota: ota.zigbeeOTA,
1279
1279
  fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory,
1280
1280
  fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
@@ -1355,11 +1355,7 @@ module.exports = [
1355
1355
  description: 'Smoke sensor',
1356
1356
  fromZigbee: [fz.tuya_smoke],
1357
1357
  toZigbee: [],
1358
- configure: async (device, coordinatorEndpoint, logger) => {
1359
- const endpoint = device.getEndpoint(1);
1360
- await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
1361
- },
1362
- exposes: [e.smoke(), e.battery_low()],
1358
+ exposes: [e.smoke(), e.battery()],
1363
1359
  },
1364
1360
  {
1365
1361
  fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_byzdayie'},
@@ -1652,7 +1648,7 @@ module.exports = [
1652
1648
  },
1653
1649
  },
1654
1650
  {
1655
- zigbeeModel: ['HY0017'],
1651
+ zigbeeModel: ['HY0017', '005f0c3'],
1656
1652
  model: 'U86KCJ-ZP',
1657
1653
  vendor: 'TuYa',
1658
1654
  description: 'Smart 6 key scene wall switch',
package/devices/xiaomi.js CHANGED
@@ -1047,7 +1047,7 @@ module.exports = [
1047
1047
  vendor: 'Xiaomi',
1048
1048
  fromZigbee: [fz.on_off, fz.xiaomi_basic, fz.electrical_measurement, fz.metering,
1049
1049
  fz.aqara_opple, fz.xiaomi_power, fz.device_temperature],
1050
- toZigbee: [tz.on_off],
1050
+ toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory],
1051
1051
  configure: async (device, coordinatorEndpoint, logger) => {
1052
1052
  const endpoint = device.getEndpoint(1);
1053
1053
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
@@ -1096,7 +1096,7 @@ module.exports = [
1096
1096
  globalStore.putValue(device, 'interval', interval);
1097
1097
  }
1098
1098
  },
1099
- exposes: [e.switch(), e.power(), e.energy(),
1099
+ exposes: [e.switch(), e.power(), e.energy(), e.power_outage_memory(),
1100
1100
  e.device_temperature().withDescription('Device temperature (polled every 30 min)')],
1101
1101
  ota: ota.zigbeeOTA,
1102
1102
  },
@@ -1236,11 +1236,13 @@ module.exports = [
1236
1236
  model: 'ZNCLDJ11LM',
1237
1237
  description: 'Aqara curtain motor',
1238
1238
  vendor: 'Xiaomi',
1239
- fromZigbee: [fz.xiaomi_curtain_position, fz.cover_position_tilt, fz.xiaomi_curtain_options],
1239
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.cover_position_tilt],
1240
1240
  toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
1241
1241
  exposes: [e.cover_position().setAccess('state', ea.ALL),
1242
1242
  exposes.binary('running', ea.STATE, true, false)
1243
- .withDescription('Whether the motor is moving or not')],
1243
+ .withDescription('Whether the motor is moving or not'),
1244
+ exposes.enum('motor_state', ea.STATE, ['stopped', 'opening', 'closing'])
1245
+ .withDescription('Motor state')],
1244
1246
  ota: ota.zigbeeOTA,
1245
1247
  },
1246
1248
  {
@@ -1248,7 +1250,7 @@ module.exports = [
1248
1250
  model: 'SRSC-M01',
1249
1251
  description: 'Aqara roller shade motor',
1250
1252
  vendor: 'Xiaomi',
1251
- fromZigbee: [fz.xiaomi_curtain_position, fz.cover_position_tilt, fz.xiaomi_curtain_options],
1253
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.cover_position_tilt],
1252
1254
  toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
1253
1255
  exposes: [e.cover_position().setAccess('state', ea.ALL),
1254
1256
  exposes.binary('running', ea.STATE, true, false)
@@ -1259,8 +1261,8 @@ module.exports = [
1259
1261
  zigbeeModel: ['lumi.curtain.hagl04'],
1260
1262
  model: 'ZNCLDJ12LM',
1261
1263
  vendor: 'Xiaomi',
1262
- description: 'Aqara B1 curtain motor ',
1263
- fromZigbee: [fz.xiaomi_curtain_position, fz.battery, fz.cover_position_tilt, fz.ignore_basic_report, fz.xiaomi_curtain_options],
1264
+ description: 'Aqara B1 curtain motor',
1265
+ fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.battery, fz.cover_position_tilt],
1264
1266
  toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
1265
1267
  onEvent: async (type, data, device) => {
1266
1268
  // The position (genAnalogOutput.presentValue) reported via an attribute contains an invaid value
package/lib/constants.js CHANGED
@@ -97,6 +97,18 @@ const temperatureDisplayMode = {
97
97
  1: 'fahrenheit',
98
98
  };
99
99
 
100
+ const danfossAdaptationRunStatus= {
101
+ 0: 'none',
102
+ 1: 'in_progress',
103
+ 2: 'found',
104
+ 4: 'lost',
105
+ };
106
+
107
+ const danfossAdaptationRunControl = {
108
+ 1: 'initate_adaptation',
109
+ 2: 'cancel_adaptation',
110
+ };
111
+
100
112
  const danfossWindowOpen = {
101
113
  0: 'quarantine',
102
114
  1: 'closed',
@@ -267,6 +279,8 @@ module.exports = {
267
279
  dayOfWeek,
268
280
  fanMode,
269
281
  temperatureDisplayMode,
282
+ danfossAdaptationRunControl,
283
+ danfossAdaptationRunStatus,
270
284
  danfossWindowOpen,
271
285
  danfossRoomStatusCode,
272
286
  danfossOutputStatus,
package/lib/light.js CHANGED
@@ -19,24 +19,25 @@ function readColorAttributes(entity, meta, additionalAttributes=[]) {
19
19
  * Additionally when we get a get payload, only request the fields included.
20
20
  */
21
21
  const attributes = ['colorMode'];
22
+ if (meta && meta.message) {
23
+ if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('x'))) {
24
+ attributes.push('currentX');
25
+ }
26
+ if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('y'))) {
27
+ attributes.push('currentY');
28
+ }
22
29
 
23
- if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('x'))) {
24
- attributes.push('currentX');
25
- }
26
- if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('y'))) {
27
- attributes.push('currentY');
28
- }
29
-
30
- if (utils.getMetaValue(entity, meta.mapped, 'supportsHueAndSaturation', 'allEqual', true)) {
31
- if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('hue'))) {
32
- if (utils.getMetaValue(entity, meta.mapped, 'enhancedHue', 'allEqual', true)) {
33
- attributes.push('enhancedCurrentHue');
34
- } else {
35
- attributes.push('currentHue');
30
+ if (utils.getMetaValue(entity, meta.mapped, 'supportsHueAndSaturation', 'allEqual', true)) {
31
+ if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('hue'))) {
32
+ if (utils.getMetaValue(entity, meta.mapped, 'enhancedHue', 'allEqual', true)) {
33
+ attributes.push('enhancedCurrentHue');
34
+ } else {
35
+ attributes.push('currentHue');
36
+ }
37
+ }
38
+ if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('saturation'))) {
39
+ attributes.push('currentSaturation');
36
40
  }
37
- }
38
- if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('saturation'))) {
39
- attributes.push('currentSaturation');
40
41
  }
41
42
  }
42
43