Skip to content

Instantly share code, notes, and snippets.

@9zigen
Last active February 18, 2024 17:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 9zigen/5219085e6d06eb53bfffc3cd064e5308 to your computer and use it in GitHub Desktop.
Save 9zigen/5219085e6d06eb53bfffc3cd064e5308 to your computer and use it in GitHub Desktop.
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const {} = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;
const bind = async (endpoint, target, clusters) => {
for await (const cluster of clusters) {
await endpoint.bind(cluster, target);
}
};
const fzLocal = {
ph_measurement: {
cluster: 'pHMeasurement',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
let response = {};
if (msg.data.hasOwnProperty('measuredValue')) {
response.ph_measurement = parseFloat(msg.data['measuredValue']) / 100.0;
}
if (msg.data.hasOwnProperty('4112')) {
response.probe_raw = parseFloat(msg.data["4112"]);
}
if (msg.data.hasOwnProperty('4113')) {
response.probe_ntc = parseFloat(msg.data["4113"]) / 100.0;
}
return response
}
},
alab_ph_sensor: {
cluster: 'pHMeasurement',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
let response = {};
if (msg.data[0x1000]) {
response.scan_interval = parseFloat(msg.data[0x1000]);
}
if (msg.data[0x1001]) {
response.calibration_low = parseFloat(msg.data[0x1001]);
}
if (msg.data[0x1002]) {
response.calibration_mid = parseFloat(msg.data[0x1002]);
}
if (msg.data[0x1003]) {
response.calibration_high = parseFloat(msg.data[0x1003]);
}
return response;
},
},
};
const tzLocal = {
alab_ph_calibration: {
key: ['scan_interval', 'calibration_low', 'calibration_mid', 'calibration_high', 'probe_raw', 'probe_ntc'],
convertSet: async (entity, key, value, meta) => {
const payloads = {
'scan_interval': {0x1000: {value, type: 0x21}},
'calibration_low': {0x1001: {value, type: 0x21}},
'calibration_mid': {0x1002: {value, type: 0x21}},
'calibration_high': {0x1003: {value, type: 0x21}}
}
await entity.write('pHMeasurement', payloads[key]);
},
convertGet: async (entity, key, meta) => {
const payloads = {
'scan_interval': 0x1000,
'calibration_low': 0x1001,
'calibration_mid': 0x1002,
'calibration_high': 0x1003
};
return await entity.read('pHMeasurement', [payloads[key]]);
}
},
}
const definition = {
zigbeeModel: ['Alab-PhSensor-1.0'],
model: 'Alab-PhSensor-1.0',
vendor: 'Alab',
description: '[DiY Wireless PH Sensor](https://github.com/9zigen/zigbee-ph-sensor)',
supports: 'temperature, humidity',
fromZigbee: [
fz.temperature,
fz.humidity,
fz.battery,
fzLocal.ph_measurement,
fzLocal.alab_ph_sensor
],
toZigbee: [tz.factory_reset, tzLocal.alab_ph_calibration],
meta: {
configureKey: 1,
timeout: 10000,
},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(10);
await bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
await bind(endpoint, coordinatorEndpoint, ['pHMeasurement']);
await bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement']);
await bind(endpoint, coordinatorEndpoint, ['msRelativeHumidity']);
// await reporting.bind(endpoint, coordinatorEndpoint, ['pHMeasurement', 'genPowerCfg']);
// await endpoint.read('genPowerCfg', ['batteryVoltage']);
// await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']);
// await reporting.batteryPercentageRemaining(endpoint);
// await reporting.temperature(endpoint, { min: 0, change: 0 });
// await reporting.humidity(endpoint, { min: 0, change: 0 });
/* pH Reporting */
// const payload = [{
// attribute: 'measuredValue',
// minimumReportInterval: 0,
// maximumReportInterval: 3600,
// reportableChange: 0
// }];
// await endpoint.configureReporting('pHMeasurement', payload);
},
exposes: [
e.battery(),
e.battery_voltage(),
exposes.numeric('ph_measurement', ea.STATE).withUnit('pH'),
exposes.numeric('probe_raw', ea.STATE).withUnit('mV').withDescription('RAW value from pH electrode'),
exposes.numeric('probe_ntc', ea.STATE).withUnit('°C').withDescription('Temperature measured by Probe'),
exposes.numeric('temperature', ea.STATE).withUnit('°C').withDescription('Temperature measured by onboard sensor'),
exposes.numeric('humidity', ea.STATE).withUnit('%').withDescription('Humidity measured by onboard sensor'),
//device options
exposes.numeric('scan_interval', ea.ALL).withUnit('seconds'),
exposes.numeric('calibration_low', ea.ALL).withUnit('pH (x100)'),
exposes.numeric('calibration_mid', ea.ALL).withUnit('pH (x100)'),
exposes.numeric('calibration_high', ea.ALL).withUnit('pH (x100)'),
],
};
module.exports = definition;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment