Skip to content

Commit

Permalink
Release 2.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
Luligu committed Jun 23, 2024
1 parent 263b9bd commit 59e1ab8
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 33 deletions.
13 changes: 3 additions & 10 deletions .github/workflows/build matterbridge plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,15 @@ jobs:
with:
node-version: ${{ matrix.node-version }}

- name: Install matterbridge
run: npm -g install matterbridge

- name: Install dependencies
run: npm install

- name: Install matterbridge
run: npm install --save-dev matterbridge

- name: Lint the project
run: npm run lint

- name: Build the project
run: npm run build

- name: List, audit, fix outdated dependencies and build again
run: |
npm list --outdated
npm audit || true # ignore failures
npm audit fix || true
npm list --outdated
npm run build
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

All notable changes to this project will be documented in this file.

## [2.1.3] - 2024-06-23

### Added

- [zigbee]: Added new properties: co - CarbonMonoxideConcentrationMeasurement, co2 - CarbonDioxideConcentrationMeasurement, formaldehyd - FormaldehydeConcentrationMeasurement, pm1 - Pm1ConcentrationMeasurement, pm25 - Pm25ConcentrationMeasurement, pm10 - Pm10ConcentrationMeasurement

### Changed

- [bridge/info]: Log error when advanced.output is set to 'attribute'.

### Fixed

- [bridge/info]: Fixed the issue when advanced.output is set 'attribute_and_json'. (Thanks copystring).
- [bridge/info]: Fixed the issue when include_device_information is set to true. (Thanks copystring).

<a href="https://www.buymeacoffee.com/luligugithub">
<img src="./yellow-button.png" alt="Buy me a coffee" width="120">
</a>

## [2.1.2] - 2024-06-21

### Added
Expand Down
53 changes: 47 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matterbridge-zigbee2mqtt",
"version": "2.1.2",
"version": "2.1.3",
"description": "Matterbridge zigbee2mqtt plugin",
"author": "https://github.com/Luligu",
"license": "Apache-2.0",
Expand Down Expand Up @@ -92,15 +92,16 @@
"@eslint/js": "^9.5.0",
"@types/eslint__js": "^8.42.3",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.7",
"@types/node": "^20.14.8",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"matterbridge": "file:../matterbridge",
"prettier": "^3.3.2",
"rimraf": "^5.0.7",
"ts-jest": "^29.1.5",
"typescript": "^5.5.2",
"typescript-eslint": "^7.13.1"
}
}
}
14 changes: 14 additions & 0 deletions src/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ import {
AttributeInitialValues,
powerSource,
bridgedNode,
CarbonDioxideConcentrationMeasurement,
CarbonMonoxideConcentrationMeasurement,
FormaldehydeConcentrationMeasurement,
Pm1ConcentrationMeasurement,
Pm25ConcentrationMeasurement,
Pm10ConcentrationMeasurement,
} from 'matterbridge';

import { AnsiLogger, TimestampFormat, gn, dn, ign, idn, rs, db, wr, debugStringify, hk, zb, or, nf } from 'node-ansi-logger';
Expand Down Expand Up @@ -519,6 +525,14 @@ export const z2ms: ZigbeeToMatter[] = [
{ type: '', name: 'pressure', property: 'pressure', deviceType: DeviceTypes.PRESSURE_SENSOR, cluster: PressureMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return value } },
{ type: '', name: 'air_quality', property: 'air_quality', deviceType: airQualitySensor, cluster: AirQuality.Cluster.id, attribute: 'airQuality', valueLookup: ['unknown', 'excellent', 'good', 'moderate', 'poor', 'unhealthy', 'out_of_range'] },
{ type: '', name: 'voc', property: 'voc', deviceType: airQualitySensor, cluster: TvocMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.min(65535, value) } },

{ type: '', name: 'co', property: 'co', deviceType: airQualitySensor, cluster: CarbonMonoxideConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },
{ type: '', name: 'co2', property: 'co2', deviceType: airQualitySensor, cluster: CarbonDioxideConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },
{ type: '', name: 'formaldehyd', property: 'formaldehyd',deviceType: airQualitySensor, cluster: FormaldehydeConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },
{ type: '', name: 'pm1', property: 'pm1', deviceType: airQualitySensor, cluster: Pm1ConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },
{ type: '', name: 'pm25', property: 'pm25', deviceType: airQualitySensor, cluster: Pm25ConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },
{ type: '', name: 'pm10', property: 'pm10', deviceType: airQualitySensor, cluster: Pm10ConcentrationMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value) } },

//{ type: '', name: 'action', property: 'action', deviceType: DeviceTypes.GENERIC_SWITCH, cluster: Switch.Cluster.id, attribute: 'currentPosition' },
{ type: '', name: 'cpu_temperature', property: 'temperature', deviceType: DeviceTypes.TEMPERATURE_SENSOR, cluster: TemperatureMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value * 100) }},
{ type: '', name: 'device_temperature', property: 'device_temperature', deviceType: DeviceTypes.TEMPERATURE_SENSOR, cluster: TemperatureMeasurement.Cluster.id, attribute: 'measuredValue', converter: (value) => { return Math.round(value * 100) } },
Expand Down
10 changes: 9 additions & 1 deletion src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
this.z2m.subscribe(this.z2m.mqttTopic + '/#');
});

this.z2m.on('mqtt_subscribed', () => {
this.log.info(`MQTT broker at ${this.z2m.mqttHost}:${this.z2m.mqttPort} subscribed to: ${this.z2m.mqttTopic + '/#'}`);
});

this.z2m.on('close', () => {
this.log.warn(`MQTT broker at ${this.z2m.mqttHost}:${this.z2m.mqttPort} closed the connection`);
});
Expand Down Expand Up @@ -256,6 +260,9 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
this.z2m.on('bridge-info', async (bridgeInfo: BridgeInfo) => {
this.z2mBridgeInfo = bridgeInfo;
this.log.info(`zigbee2MQTT version ${this.z2mBridgeInfo.version} zh version ${this.z2mBridgeInfo.zigbee_herdsman.version} zhc version ${this.z2mBridgeInfo.zigbee_herdsman_converters.version}`);
if (this.z2mBridgeInfo.config.advanced.output === 'attribute') this.log.error(`zigbee2MQTT advanced.output must be 'json' or 'attribute_and_json'. Now is ${this.z2mBridgeInfo.config.advanced.output}`);
if (this.z2mBridgeInfo.config.advanced.legacy_api === true) this.log.info(`zigbee2MQTT advanced.legacy_api is ${this.z2mBridgeInfo.config.advanced.legacy_api}`);
if (this.z2mBridgeInfo.config.advanced.legacy_availability_payload === true) this.log.info(`zigbee2MQTT advanced.legacy_availability_payload is ${this.z2mBridgeInfo.config.advanced.legacy_availability_payload}`);
});

this.z2m.on('bridge-devices', async (devices: BridgeDevice[]) => {
Expand Down Expand Up @@ -323,7 +330,8 @@ export class ZigbeePlatform extends MatterbridgeDynamicPlatform {
const hasDevices = await waiter('z2mBridgeDevices & z2mBridgeGroups', () => this.z2mBridgeDevices !== undefined || this.z2mBridgeGroups !== undefined);

if (!hasOnline || !hasInfo || !hasDevices) {
this.log.error('The plugin did not receive zigbee2mqtt bridge state or info or devices/groups. Check if zigbee2mqtt is running and connected to the MQTT broker.');
throw new Error('The plugin did not receive zigbee2mqtt bridge state or info or devices/groups. Check if zigbee2mqtt is running and connected to the MQTT broker.');
// this.log.error('The plugin did not receive zigbee2mqtt bridge state or info or devices/groups. Check if zigbee2mqtt is running and connected to the MQTT broker.');
return;
}

Expand Down
34 changes: 21 additions & 13 deletions src/zigbee2mqtt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @file zigbee2mqtt.ts
* @author Luca Liguori
* @date 2023-06-30
* @version 2.2.29
* @version 2.3.0
*
* Copyright 2023, 2024 Luca Liguori.
*
Expand Down Expand Up @@ -587,14 +587,20 @@ export class Zigbee2MQTT extends EventEmitter {
this.log.debug(`Message bridge/state online => ${this.z2mIsOnline}`);
} else if (topic.startsWith(this.mqttTopic + '/bridge/info')) {
const data = this.tryJsonParse(payload.toString());
// this.log.debug('classZigbee2MQTT=>Message bridge/info', data);
// this.log.info('classZigbee2MQTT=>Message bridge/info', data);
this.z2mPermitJoin = data.permit_join ? data.permit_join : false;
this.z2mPermitJoinTimeout = data.permit_join_timeout ? data.permit_join_timeout : 0;
this.z2mVersion = data.version ? data.version : '';
this.z2mIsAvailabilityEnabled = data.config.availability ? true : false;
this.log.debug(`Message bridge/info availability => ${this.z2mIsAvailabilityEnabled}`);
this.log.debug(`Message bridge/info version => ${this.z2mVersion}`);
this.log.debug(`Message bridge/info permit_join => ${this.z2mPermitJoin} timeout => ${this.z2mPermitJoinTimeout}`);
this.log.debug(`Message bridge/info advanced.output => ${data.config.advanced.output}`);
this.log.debug(`Message bridge/info advanced.legacy_api => ${data.config.advanced.legacy_api}`);
this.log.debug(`Message bridge/info advanced.legacy_availability_payload => ${data.config.advanced.legacy_availability_payload}`);
if (data.config.advanced.output === 'attribute') this.log.error(`Message bridge/info advanced.output must be 'json' or 'attribute_and_json'. Now is ${data.config.advanced.output}`);
if (data.config.advanced.legacy_api === true) this.log.info(`Message bridge/info advanced.legacy_api is ${data.config.advanced.legacy_api}`);
if (data.config.advanced.legacy_availability_payload === true) this.log.info(`Message bridge/info advanced.legacy_availability_payload is ${data.config.advanced.legacy_availability_payload}`);
this.emit('info', this.z2mVersion, this.z2mIsAvailabilityEnabled, this.z2mPermitJoin, this.z2mPermitJoinTimeout);
this.writeBufferJSON('bridge-info', payload);
this.emit('bridge-info', data);
Expand Down Expand Up @@ -779,7 +785,7 @@ export class Zigbee2MQTT extends EventEmitter {
return;
}
const data = this.tryJsonParse(payload.toString());
this.log.info(`Message topic: ${topic} payload:${rs}`, data);
this.log.debug(`Message topic: ${topic} payload:${rs}`, data);
/*
[05/09/2023, 20:35:26] [z2m] classZigbee2MQTT=>Message bridge/response zigbee2mqtt/bridge/response/group/add {
data: { friendly_name: 'Guest', id: 1 },
Expand Down Expand Up @@ -861,17 +867,17 @@ export class Zigbee2MQTT extends EventEmitter {
}

private handleDeviceMessage(deviceIndex: number, entity: string, service: string, payload: Buffer) {
// this.log.debug(`classZigbee2MQTT=>handleDeviceMessage ${id}#${deviceIndex + 1}${rs} entity ${dn}${entity}${rs} service ${zb}${service}${rs} payload ${pl}${payload}${rs}`);
// this.log.info(`classZigbee2MQTT=>handleDeviceMessage ${id}#${deviceIndex + 1}${rs} entity ${dn}${entity}${rs} service ${zb}${service}${rs} payload ${pl}${payload}${rs}`);
if (payload.length === 0 || payload === null) {
this.log.warn(`handleDeviceMessage ${id}#${deviceIndex + 1}${rs} entity ${dn}${entity}${rs} service ${zb}${service}${rs} payload null`);
// this.log.warn(`handleDeviceMessage ${id}#${deviceIndex + 1}${rs} entity ${dn}${entity}${rs} service ${zb}${service}${rs} payload null`);
return;
}
const payloadString = payload.toString();
let data: Payload = {};
if (payloadString.startsWith('{') && payloadString.endsWith('}')) {
data = this.tryJsonParse(payload.toString());
} else {
data = { state: payloadString };
data = { state: payloadString }; // Only state for availability
}
if (service === 'availability') {
if (data.state === 'online') {
Expand All @@ -888,28 +894,28 @@ export class Zigbee2MQTT extends EventEmitter {
}
} else if (service === 'get') {
// Do nothing
// this.log.warn(`handleDeviceMessage entity ${dn}${entity}${wr} service ${service} payload ${pl}${payload}${rs}`);
} else if (service === 'set') {
// Do nothing
// this.log.warn(`handleDeviceMessage entity ${dn}${entity}${wr} service ${service} payload ${pl}${payload}${rs}`);
} else {
} else if (service === undefined) {
// this.log.debug(`classZigbee2MQTT=>emitting message for device ${dn}${entity}${rs} payload ${pl}${payload}${rs}`);
this.emit('MESSAGE-' + entity, data);
} else {
// MQTT output attribute type
}
}

private handleGroupMessage(groupIndex: number, entity: string, service: string, payload: Buffer) {
// this.log.debug(`classZigbee2MQTT=>handleGroupMessage ${id}#${groupIndex+1}${rs} entity ${gn}${entity}${rs} service ${zb}${service}${rs} payload ${pl}${payload}${rs}`);
// this.log.info(`classZigbee2MQTT=>handleGroupMessage ${id}#${groupIndex + 1}${rs} entity ${gn}${entity}${rs} service ${zb}${service}${rs} payload ${pl}${payload}${rs}`);
if (payload.length === 0 || payload === null) {
this.log.warn(`handleGroupMessage ${id}#${groupIndex + 1}${rs} entity ${gn}${entity}${rs} service ${zb}${service}${rs} payload null`);
// this.log.warn(`handleGroupMessage ${id}#${groupIndex + 1}${rs} entity ${gn}${entity}${rs} service ${zb}${service}${rs} payload null`);
return;
}
const payloadString = payload.toString();
let data: Payload = {};
if (payloadString.startsWith('{') && payloadString.endsWith('}')) {
data = this.tryJsonParse(payload.toString());
} else {
data = { state: payloadString };
data = { state: payloadString }; // Only state for availability
}
data['last_seen'] = new Date().toISOString();
if (service === 'availability') {
Expand All @@ -927,9 +933,11 @@ export class Zigbee2MQTT extends EventEmitter {
// Do nothing
} else if (service === 'set') {
// Do nothing
} else {
} else if (service === undefined) {
// this.log.debug(`classZigbee2MQTT=>emitting message for group ${gn}${entity}${rs} payload ${pl}${payload}${rs}`);
this.emit('MESSAGE-' + entity, data);
} else {
// MQTT output attribute type
}
}

Expand Down

0 comments on commit 59e1ab8

Please sign in to comment.