matterbridge-zigbee2mqtt 2.4.5-dev.1 → 2.4.5-dev.3

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/CHANGELOG.md CHANGED
@@ -12,7 +12,7 @@ All notable changes to this project will be documented in this file.
12
12
 
13
13
  ### Fixed
14
14
 
15
- - [endpoint]: Fix thermostat bug.
15
+ - [endpoint]: Fix thermostat bug (thanks https://github.com/robvanoostenrijk).
16
16
 
17
17
  <a href="https://www.buymeacoffee.com/luligugithub">
18
18
  <img src="./yellow-button.png" alt="Buy me a coffee" width="120">
package/dist/entity.js CHANGED
@@ -135,6 +135,12 @@ export class ZigbeeEntity extends EventEmitter {
135
135
  this.updateAttributeIfChanged(this.bridgedDevice, undefined, WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', position);
136
136
  }
137
137
  }
138
+ if (key === 'current_heating_setpoint' && 'system_mode' in payload && payload['system_mode'] === 'heat' && isValidNumber(value)) {
139
+ this.updateAttributeIfChanged(this.bridgedDevice, undefined, Thermostat.Cluster.id, 'occupiedHeatingSetpoint', value * 100);
140
+ }
141
+ if (key === 'current_heating_setpoint' && 'system_mode' in payload && payload['system_mode'] === 'cool' && isValidNumber(value)) {
142
+ this.updateAttributeIfChanged(this.bridgedDevice, undefined, Thermostat.Cluster.id, 'occupiedCoolingSetpoint', value * 100);
143
+ }
138
144
  if (key === 'color_temp' && 'color_mode' in payload && payload['color_mode'] === 'color_temp') {
139
145
  this.updateAttributeIfChanged(this.bridgedDevice, undefined, ColorControl.Cluster.id, 'colorMode', ColorControl.ColorMode.ColorTemperatureMireds);
140
146
  this.updateAttributeIfChanged(this.bridgedDevice, undefined, ColorControl.Cluster.id, 'colorTemperatureMireds', Math.max(147, Math.min(500, typeof value === 'number' ? value : 0)));
@@ -173,12 +179,18 @@ export class ZigbeeEntity extends EventEmitter {
173
179
  });
174
180
  }
175
181
  destroy() {
182
+ this.removeAllListeners();
176
183
  if (this.colorTimeout)
177
184
  clearTimeout(this.colorTimeout);
178
185
  this.colorTimeout = undefined;
179
186
  if (this.thermostatTimeout)
180
187
  clearTimeout(this.thermostatTimeout);
181
188
  this.thermostatTimeout = undefined;
189
+ this.device = undefined;
190
+ this.group = undefined;
191
+ this.bridgedDevice = undefined;
192
+ this.mutableDevice.clear();
193
+ this.propertyMap.clear();
182
194
  }
183
195
  addBridgedDeviceBasicInformation() {
184
196
  if (!this.bridgedDevice)
@@ -431,6 +443,7 @@ export class ZigbeeGroup extends ZigbeeEntity {
431
443
  zigbeeGroup.bridgedDevice.addRequiredClusterServers();
432
444
  if (!zigbeeGroup.bridgedDevice || !zigbeeGroup.verifyMutableDevice(zigbeeGroup.bridgedDevice))
433
445
  return zigbeeGroup;
446
+ zigbeeGroup.mutableDevice.clear();
434
447
  zigbeeGroup.logPropertyMap();
435
448
  if (isSwitch || isLight) {
436
449
  if (isSwitch && !isLight)
@@ -559,7 +572,7 @@ export class ZigbeeGroup extends ZigbeeEntity {
559
572
  zigbeeGroup.bridgedDevice.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (newValue, oldValue) => {
560
573
  zigbeeGroup.bridgedDevice?.log.info(`Thermostat occupiedCoolingSetpoint changed from ${oldValue / 100} to ${newValue / 100}`);
561
574
  zigbeeGroup.bridgedDevice?.log.info(`Setting thermostat occupiedCoolingSetpoint to ${newValue / 100}`);
562
- zigbeeGroup.publishCommand('CurrentCoolingSetpoint', group.friendly_name, { current_cooling_setpoint: Math.round(newValue / 100) });
575
+ zigbeeGroup.publishCommand('CurrentCoolingSetpoint', group.friendly_name, { current_heating_setpoint: Math.round(newValue / 100) });
563
576
  zigbeeGroup.publishCommand('OccupiedCoolingSetpoint', group.friendly_name, { occupied_cooling_setpoint: Math.round(newValue / 100) });
564
577
  zigbeeGroup.noUpdate = true;
565
578
  zigbeeGroup.thermostatTimeout = setTimeout(() => {
@@ -588,10 +601,11 @@ export const z2ms = [
588
601
  { type: 'cover', name: 'position', property: 'position', deviceType: coverDevice, cluster: WindowCovering.Cluster.id, attribute: 'currentPositionLiftPercent100ths' },
589
602
  { type: 'lock', name: 'state', property: 'state', deviceType: doorLockDevice, cluster: DoorLock.Cluster.id, attribute: 'lockState', converter: (value) => { return value === 'LOCK' ? DoorLock.LockState.Locked : DoorLock.LockState.Unlocked; } },
590
603
  { type: 'climate', name: 'local_temperature', property: 'local_temperature', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'localTemperature', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
591
- { type: 'climate', name: 'current_heating_setpoint', property: 'current_heating_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedHeatingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
592
- { type: 'climate', name: 'current_cooling_setpoint', property: 'current_cooling_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedCoolingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
604
+ { type: 'climate', name: 'current_heating_setpoint', property: 'current_heating_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedHeatingSetpoint' },
593
605
  { type: 'climate', name: 'occupied_heating_setpoint', property: 'occupied_heating_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedHeatingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
594
606
  { type: 'climate', name: 'occupied_cooling_setpoint', property: 'occupied_cooling_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedCoolingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
607
+ { type: 'climate', name: 'unoccupied_heating_setpoint', property: 'unoccupied_heating_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedHeatingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
608
+ { type: 'climate', name: 'unoccupied_cooling_setpoint', property: 'unoccupied_cooling_setpoint', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'occupiedCoolingSetpoint', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
595
609
  { type: 'climate', name: 'running_state', property: 'running_state', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'thermostatRunningMode', valueLookup: ['idle', '', '', 'cool', 'heat'] },
596
610
  { type: 'climate', name: 'system_mode', property: 'system_mode', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'systemMode', valueLookup: ['off', 'auto', '', 'cool', 'heat'] },
597
611
  { type: '', name: 'min_temperature_limit', property: 'min_temperature_limit', deviceType: thermostatDevice, cluster: Thermostat.Cluster.id, attribute: 'minHeatSetpointLimit', converter: (value) => { return Math.max(-5000, Math.min(5000, value * 100)); } },
@@ -920,25 +934,28 @@ export class ZigbeeDevice extends ZigbeeEntity {
920
934
  }
921
935
  }
922
936
  if (mainEndpoint.clusterServersIds.includes(Thermostat.Cluster.id)) {
923
- const heat = zigbeeDevice.propertyMap.get('occupied_heating_setpoint') || zigbeeDevice.propertyMap.get('current_heating_setpoint');
924
- const cool = zigbeeDevice.propertyMap.get('occupied_cooling_setpoint') || zigbeeDevice.propertyMap.get('current_cooling_setpoint');
937
+ const system_mode = zigbeeDevice.propertyMap.get('system_mode');
938
+ const system_mode_values = system_mode?.values;
939
+ const heat = zigbeeDevice.propertyMap.get('occupied_heating_setpoint') || zigbeeDevice.propertyMap.get('unoccupied_heating_setpoint');
940
+ const cool = zigbeeDevice.propertyMap.get('occupied_cooling_setpoint') || zigbeeDevice.propertyMap.get('unoccupied_cooling_setpoint');
925
941
  const minHeating = heat && heat.value_min !== undefined && !isNaN(heat.value_min) ? heat.value_min : 0;
926
942
  const maxHeating = heat && heat.value_max !== undefined && !isNaN(heat.value_max) ? heat.value_max : 50;
927
943
  const minCooling = cool && cool.value_min !== undefined && !isNaN(cool.value_min) ? cool.value_min : 0;
928
944
  const maxCooling = cool && cool.value_max !== undefined && !isNaN(cool.value_max) ? cool.value_max : 50;
929
- zigbeeDevice.log.debug(`Configuring device ${zigbeeDevice.ien}${device.friendly_name}${rs}${db} Thermostat cluster with heating ${CYAN}${heat ? 'supported' : 'not supported'}${db} cooling ${CYAN}${cool ? 'supported' : 'not supported'}${db} ` +
945
+ zigbeeDevice.log.debug(`Configuring device ${zigbeeDevice.ien}${device.friendly_name}${rs}${db} Thermostat cluster with heating ${CYAN}${heat ? 'supported' : '(un)occupied not supported'}${db} cooling ${CYAN}${cool ? 'supported' : '(un)occupied not supported'}${db} ` +
946
+ `system_mode ${CYAN}${system_mode_values ?? 'not supported'}${db} ` +
930
947
  `minHeating ${CYAN}${minHeating}${db} maxHeating ${CYAN}${maxHeating}${db} minCooling ${CYAN}${minCooling}${db} maxCooling ${CYAN}${maxCooling}${db}`);
931
- if (heat && !cool) {
948
+ if ((heat && !cool) || (!system_mode_values?.includes('auto') && system_mode_values?.includes('heat'))) {
932
949
  zigbeeDevice.propertyMap.delete('running_state');
933
950
  zigbeeDevice.bridgedDevice.createDefaultHeatingThermostatClusterServer(undefined, undefined, minHeating, maxHeating);
934
951
  mainEndpoint.clusterServersIds.splice(mainEndpoint.clusterServersIds.indexOf(Thermostat.Cluster.id), 1);
935
952
  }
936
- else if (!heat && cool) {
953
+ else if ((!heat && cool) || (!system_mode_values?.includes('auto') && system_mode_values?.includes('cool'))) {
937
954
  zigbeeDevice.propertyMap.delete('running_state');
938
955
  zigbeeDevice.bridgedDevice.createDefaultCoolingThermostatClusterServer(undefined, undefined, minCooling, maxCooling);
939
956
  mainEndpoint.clusterServersIds.splice(mainEndpoint.clusterServersIds.indexOf(Thermostat.Cluster.id), 1);
940
957
  }
941
- else if (heat && cool) {
958
+ else {
942
959
  zigbeeDevice.bridgedDevice.createDefaultThermostatClusterServer(undefined, undefined, undefined, undefined, minHeating, maxHeating, minCooling, maxCooling);
943
960
  mainEndpoint.clusterServersIds.splice(mainEndpoint.clusterServersIds.indexOf(Thermostat.Cluster.id), 1);
944
961
  }
@@ -1169,23 +1186,19 @@ export class ZigbeeDevice extends ZigbeeEntity {
1169
1186
  const setpoint = Math.round(t / 100 + request.amount / 10);
1170
1187
  if (zigbeeDevice.propertyMap.has('current_heating_setpoint')) {
1171
1188
  zigbeeDevice.publishCommand('OccupiedHeatingSetpoint', device.friendly_name, { current_heating_setpoint: setpoint });
1172
- zigbeeDevice.log.debug('Command setpointRaiseLower sent:', debugStringify({ current_heating_setpoint: setpoint }));
1173
1189
  }
1174
1190
  else if (zigbeeDevice.propertyMap.has('occupied_heating_setpoint')) {
1175
1191
  zigbeeDevice.publishCommand('OccupiedHeatingSetpoint', device.friendly_name, { occupied_heating_setpoint: setpoint });
1176
- zigbeeDevice.log.debug('Command setpointRaiseLower sent:', debugStringify({ occupied_heating_setpoint: setpoint }));
1177
1192
  }
1178
1193
  }
1179
1194
  if (request.mode === Thermostat.SetpointRaiseLowerMode.Cool || request.mode === Thermostat.SetpointRaiseLowerMode.Both) {
1180
1195
  const t = zigbeeDevice.bridgedDevice?.getAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', zigbeeDevice.log);
1181
1196
  const setpoint = Math.round(t / 100 + request.amount / 10);
1182
- if (zigbeeDevice.propertyMap.has('current_cooling_setpoint')) {
1183
- zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { current_cooling_setpoint: setpoint });
1184
- zigbeeDevice.log.debug('Command setpointRaiseLower sent:', debugStringify({ current_cooling_setpoint: setpoint }));
1197
+ if (zigbeeDevice.propertyMap.has('current_heating_setpoint')) {
1198
+ zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { current_heating_setpoint: setpoint });
1185
1199
  }
1186
1200
  else if (zigbeeDevice.propertyMap.has('occupied_cooling_setpoint')) {
1187
1201
  zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { occupied_cooling_setpoint: setpoint });
1188
- zigbeeDevice.log.debug('Command setpointRaiseLower sent:', debugStringify({ occupied_cooling_setpoint: setpoint }));
1189
1202
  }
1190
1203
  }
1191
1204
  });
@@ -1213,8 +1226,8 @@ export class ZigbeeDevice extends ZigbeeEntity {
1213
1226
  if (zigbeeDevice.bridgedDevice.hasAttributeServer(ThermostatCluster.id, 'occupiedCoolingSetpoint'))
1214
1227
  zigbeeDevice.bridgedDevice.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', async (value) => {
1215
1228
  zigbeeDevice.log.debug(`Subscribe occupiedCoolingSetpoint called for ${zigbeeDevice.ien}${device.friendly_name}${rs}${db} with:`, value);
1216
- if (zigbeeDevice.propertyMap.has('current_cooling_setpoint'))
1217
- zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { current_cooling_setpoint: Math.round(value / 100) });
1229
+ if (zigbeeDevice.propertyMap.has('current_heating_setpoint'))
1230
+ zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { current_heating_setpoint: Math.round(value / 100) });
1218
1231
  else if (zigbeeDevice.propertyMap.has('occupied_cooling_setpoint'))
1219
1232
  zigbeeDevice.publishCommand('OccupiedCoolingSetpoint', device.friendly_name, { occupied_cooling_setpoint: Math.round(value / 100) });
1220
1233
  zigbeeDevice.noUpdate = true;
package/dist/platform.js CHANGED
@@ -223,7 +223,7 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
223
223
  this.z2m.on('device_interview', async (friendly_name, ieee_address, status, supported) => {
224
224
  this.log.info(`zigbee2MQTT sent device_interview device: ${friendly_name} ieee_address: ${ieee_address} status: ${status} supported: ${supported}`);
225
225
  if (status === 'successful' && supported) {
226
- if (!this.validateDeviceWhiteBlackList(friendly_name))
226
+ if (!this.validateDevice(friendly_name))
227
227
  return;
228
228
  this.log.info(`Registering device: ${friendly_name}`);
229
229
  const bridgedDevice = this.z2mBridgeDevices?.find((device) => device.friendly_name === friendly_name);
@@ -243,7 +243,7 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
243
243
  });
244
244
  this.z2m.on('group_add', async (friendly_name, id, status) => {
245
245
  this.log.info(`zigbee2MQTT sent group_add friendly_name: ${friendly_name} id ${id} status ${status}`);
246
- if (!this.validateDeviceWhiteBlackList(friendly_name))
246
+ if (!this.validateDevice(friendly_name))
247
247
  return;
248
248
  this.log.info(`Registering group: ${friendly_name}`);
249
249
  const bridgedGroup = this.z2mBridgeGroups?.find((group) => group.friendly_name === friendly_name);
@@ -479,6 +479,7 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
479
479
  if (entity) {
480
480
  this.log.info(`Removing device: ${friendly_name}`);
481
481
  await this.unregisterDevice(entity.bridgedDevice);
482
+ entity.destroy();
482
483
  this.zigbeeEntities = this.zigbeeEntities.filter((entity) => entity.entityName !== friendly_name);
483
484
  this.bridgedDevices = this.bridgedDevices.filter((device) => device.deviceName !== friendly_name);
484
485
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge-zigbee2mqtt",
3
- "version": "2.4.5-dev.1",
3
+ "version": "2.4.5-dev.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge-zigbee2mqtt",
9
- "version": "2.4.5-dev.1",
9
+ "version": "2.4.5-dev.3",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "moment": "2.30.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-zigbee2mqtt",
3
- "version": "2.4.5-dev.1",
3
+ "version": "2.4.5-dev.3",
4
4
  "description": "Matterbridge zigbee2mqtt plugin",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",