mirror of
https://github.com/formtapez/ZigUP.git
synced 2025-02-23 09:34:50 +01:00
fetched version from zigbee2mqtt-pullrequest
This commit is contained in:
@@ -30,6 +30,17 @@ const precisionRound = (number, precision) => {
|
||||
return Math.round(number * factor) / factor;
|
||||
};
|
||||
|
||||
const calibrateOptions = (number, options, type) => {
|
||||
const key = `${type}_calibration`;
|
||||
let calibrationOffset = options && options.hasOwnProperty(key) ? options[key] : 0;
|
||||
if (type == 'illuminance') {
|
||||
// linear calibration because measured value is zero based
|
||||
// +/- percent
|
||||
calibrationOffset = Math.round(number * calibrationOffset / 100);
|
||||
}
|
||||
return number + calibrationOffset;
|
||||
};
|
||||
|
||||
const toPercentage = (value, min, max) => {
|
||||
if (value > max) {
|
||||
value = max;
|
||||
@@ -447,7 +458,8 @@ const converters = {
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const temperature = parseFloat(msg.data.data['measuredValue']) / 100.0;
|
||||
return {temperature: precisionRoundOptions(temperature, options, 'temperature')};
|
||||
const calTemperature = calibrateOptions(temperature, options, 'temperature');
|
||||
return {temperature: precisionRoundOptions(calTemperature, options, 'temperature')};
|
||||
},
|
||||
},
|
||||
generic_temperature_change: {
|
||||
@@ -455,7 +467,8 @@ const converters = {
|
||||
type: 'devChange',
|
||||
convert: (model, msg, publish, options) => {
|
||||
const temperature = parseFloat(msg.data.data['measuredValue']) / 100.0;
|
||||
return {temperature: precisionRoundOptions(temperature, options, 'temperature')};
|
||||
const calTemperature = calibrateOptions(temperature, options, 'temperature');
|
||||
return {temperature: precisionRoundOptions(calTemperature, options, 'temperature')};
|
||||
},
|
||||
},
|
||||
xiaomi_temperature: {
|
||||
@@ -558,7 +571,7 @@ const converters = {
|
||||
return lookup[value] ? lookup[value] : null;
|
||||
},
|
||||
},
|
||||
xiaomi_humidity: {
|
||||
generic_humidity: {
|
||||
cid: 'msRelativeHumidity',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
@@ -671,7 +684,7 @@ const converters = {
|
||||
cid: 'genBasic',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
if (msg.data.data.hasOwnProperty('65281')) {
|
||||
if (msg.data.data.hasOwnProperty('65281') && msg.data.data['65281'].hasOwnProperty('100')) {
|
||||
return {contact: msg.data.data['65281']['100'] === 0};
|
||||
}
|
||||
},
|
||||
@@ -708,11 +721,11 @@ const converters = {
|
||||
result.color = {};
|
||||
|
||||
if (msg.data.data['currentX']) {
|
||||
result.color.x = precisionRound(msg.data.data['currentX'] / 65535, 3);
|
||||
result.color.x = precisionRound(msg.data.data['currentX'] / 65535, 4);
|
||||
}
|
||||
|
||||
if (msg.data.data['currentY']) {
|
||||
result.color.y = precisionRound(msg.data.data['currentY'] / 65535, 3);
|
||||
result.color.y = precisionRound(msg.data.data['currentY'] / 65535, 4);
|
||||
}
|
||||
|
||||
if (msg.data.data['currentSaturation']) {
|
||||
@@ -750,11 +763,11 @@ const converters = {
|
||||
result.color = {};
|
||||
|
||||
if (msg.data.data['currentX']) {
|
||||
result.color.x = precisionRound(msg.data.data['currentX'] / 65535, 3);
|
||||
result.color.x = precisionRound(msg.data.data['currentX'] / 65535, 4);
|
||||
}
|
||||
|
||||
if (msg.data.data['currentY']) {
|
||||
result.color.y = precisionRound(msg.data.data['currentY'] / 65535, 3);
|
||||
result.color.y = precisionRound(msg.data.data['currentY'] / 65535, 4);
|
||||
}
|
||||
|
||||
if (msg.data.data['currentSaturation']) {
|
||||
@@ -791,7 +804,10 @@ const converters = {
|
||||
cid: 'msIlluminanceMeasurement',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
return {illuminance: msg.data.data['measuredValue']};
|
||||
const illuminance = msg.data.data['measuredValue'];
|
||||
const calIlluminance = calibrateOptions(illuminance, options, 'illuminance');
|
||||
// calibration value in +/- percent!
|
||||
return {illuminance: calIlluminance};
|
||||
},
|
||||
},
|
||||
generic_pressure: {
|
||||
@@ -799,7 +815,8 @@ const converters = {
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const pressure = parseFloat(msg.data.data['measuredValue']);
|
||||
return {pressure: precisionRoundOptions(pressure, options, 'pressure')};
|
||||
const calPressure = calibrateOptions(pressure, options, 'pressure');
|
||||
return {pressure: precisionRoundOptions(calPressure, options, 'pressure')};
|
||||
},
|
||||
},
|
||||
WXKG02LM_click: {
|
||||
@@ -867,6 +884,15 @@ const converters = {
|
||||
return {water_leak: msg.data.zoneStatus === 1};
|
||||
},
|
||||
},
|
||||
SJCGQ11LM_water_leak_interval: {
|
||||
cid: 'genBasic',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
if (msg.data.data.hasOwnProperty('65281') && msg.data.data['65281'].hasOwnProperty('100')) {
|
||||
return {water_leak: msg.data.data['65281']['100'] === 1};
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
cid: 'genOnOff',
|
||||
type: ['attReport', 'readRsp'],
|
||||
@@ -1190,6 +1216,7 @@ const converters = {
|
||||
convert: (model, msg, publish, options) => {
|
||||
const batt = msg.data.data.batteryPercentageRemaining;
|
||||
const battLow = msg.data.data.batteryAlarmState;
|
||||
const voltage = msg.data.data.batteryVoltage;
|
||||
const results = {};
|
||||
if (batt != null) {
|
||||
const value = Math.round(batt/200.0*10000)/100; // Out of 200
|
||||
@@ -1202,6 +1229,9 @@ const converters = {
|
||||
results['battery_low'] = false;
|
||||
}
|
||||
}
|
||||
if (voltage != null) {
|
||||
results['voltage'] = voltage * 100;
|
||||
}
|
||||
return results;
|
||||
},
|
||||
},
|
||||
@@ -1449,12 +1479,12 @@ const converters = {
|
||||
'2': 'dig-in',
|
||||
};
|
||||
|
||||
var ds18b20_id = null;
|
||||
var ds18b20_value = null;
|
||||
if (msg.data.data['41368']) {
|
||||
ds18b20_id = msg.data.data['41368'].split(':')[0];
|
||||
ds18b20_value = precisionRound(msg.data.data['41368'].split(':')[1], 2);
|
||||
}
|
||||
let ds18b20Id = null;
|
||||
let ds18b20Value = null;
|
||||
if (msg.data.data['41368']) {
|
||||
ds18b20Id = msg.data.data['41368'].split(':')[0];
|
||||
ds18b20Value = precisionRound(msg.data.data['41368'].split(':')[1], 2);
|
||||
}
|
||||
|
||||
return {
|
||||
state: msg.data.data['onOff'] === 1 ? 'ON' : 'OFF',
|
||||
@@ -1465,7 +1495,7 @@ const converters = {
|
||||
adc_volt: precisionRound(msg.data.data['41365'], 3),
|
||||
dig_input: msg.data.data['41366'],
|
||||
reason: lookup[msg.data.data['41367']],
|
||||
[`${ds18b20_id}`]: ds18b20_value,
|
||||
[`${ds18b20Id}`]: ds18b20Value,
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -1889,6 +1919,34 @@ const converters = {
|
||||
};
|
||||
},
|
||||
},
|
||||
generic_ias_zone_occupancy_status_change_no_off_msg: {
|
||||
cid: 'ssIasZone',
|
||||
type: 'statusChange',
|
||||
convert: (model, msg, publish, options) => {
|
||||
const zoneStatus = msg.data.zoneStatus;
|
||||
const useOptionsTimeout = options && options.hasOwnProperty('occupancy_timeout');
|
||||
const timeout = useOptionsTimeout ? options.occupancy_timeout : occupancyTimeout;
|
||||
const deviceID = msg.endpoints[0].device.ieeeAddr;
|
||||
|
||||
if (store[deviceID]) {
|
||||
clearTimeout(store[deviceID]);
|
||||
store[deviceID] = null;
|
||||
}
|
||||
|
||||
if (timeout !== 0) {
|
||||
store[deviceID] = setTimeout(() => {
|
||||
publish({occupancy: false});
|
||||
store[deviceID] = null;
|
||||
}, timeout * 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
occupancy: (zoneStatus & 1) > 0, // Bit 0 = Alarm 1: Presence Indication
|
||||
tamper: (zoneStatus & 1<<2) > 0, // Bit 2 = Tamper status
|
||||
battery_low: (zoneStatus & 1<<3) > 0, // Bit 3 = Battery LOW indicator (trips around 2.4V)
|
||||
};
|
||||
},
|
||||
},
|
||||
generic_ias_zone_motion_dev_change: {
|
||||
cid: 'ssIasZone',
|
||||
type: 'devChange',
|
||||
@@ -2076,6 +2134,10 @@ const converters = {
|
||||
result.unoccupied_heating_setpoint =
|
||||
precisionRound(msg.data.data['unoccupiedHeatingSetpoint'], 2) / 100;
|
||||
}
|
||||
if (typeof msg.data.data['occupiedCoolingSetpoint'] == 'number') {
|
||||
result.occupied_cooling_setpoint =
|
||||
precisionRound(msg.data.data['occupiedCoolingSetpoint'], 2) / 100;
|
||||
}
|
||||
if (typeof msg.data.data['weeklySchedule'] == 'number') {
|
||||
result.weekly_schedule = msg.data.data['weeklySchedule'];
|
||||
}
|
||||
@@ -2136,6 +2198,10 @@ const converters = {
|
||||
result.unoccupied_heating_setpoint =
|
||||
precisionRound(msg.data.data['unoccupiedHeatingSetpoint'], 2) / 100;
|
||||
}
|
||||
if (typeof msg.data.data['occupiedCoolingSetpoint'] == 'number') {
|
||||
result.occupied_cooling_setpoint =
|
||||
precisionRound(msg.data.data['occupiedCoolingSetpoint'], 2) / 100;
|
||||
}
|
||||
if (typeof msg.data.data['weeklySchedule'] == 'number') {
|
||||
result.weekly_schedule = msg.data.data['weeklySchedule'];
|
||||
}
|
||||
@@ -2606,6 +2672,25 @@ const converters = {
|
||||
return {position: msg.data.data.currentPositionLiftPercentage};
|
||||
},
|
||||
},
|
||||
closuresWindowCovering_report_pos_and_tilt: {
|
||||
cid: 'closuresWindowCovering',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const result = {};
|
||||
// ZigBee officially expects "open" to be 0 and "closed" to be 100 whereas
|
||||
// HomeAssistant etc. work the other way round.
|
||||
// ubisys J1 will report 255 if lift or tilt positions are not known.
|
||||
if (msg.data.data.hasOwnProperty('currentPositionLiftPercentage')) {
|
||||
const liftPercentage = msg.data.data['currentPositionLiftPercentage'];
|
||||
result.position = liftPercentage <= 100 ? (100 - liftPercentage) : null;
|
||||
}
|
||||
if (msg.data.data.hasOwnProperty('currentPositionTiltPercentage')) {
|
||||
const tiltPercentage = msg.data.data['currentPositionTiltPercentage'];
|
||||
result.tilt = tiltPercentage <= 100 ? (100 - tiltPercentage) : null;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
},
|
||||
generic_fan_mode: {
|
||||
cid: 'hvacFanCtrl',
|
||||
type: 'attReport',
|
||||
@@ -2799,7 +2884,7 @@ const converters = {
|
||||
return result;
|
||||
},
|
||||
},
|
||||
ZNMS12LM_closuresDoorLock_report: {
|
||||
ZNMS12LM_ZNMS13LM_closuresDoorLock_report: {
|
||||
cid: 'closuresDoorLock',
|
||||
type: 'attReport',
|
||||
convert: (model, msg, publish, options) => {
|
||||
@@ -2821,6 +2906,7 @@ const converters = {
|
||||
14: 'change_language_to',
|
||||
15: 'finger_open',
|
||||
16: 'password_open',
|
||||
17: 'door_closed',
|
||||
};
|
||||
result.user = null;
|
||||
result.repeat = null;
|
||||
@@ -2828,34 +2914,68 @@ const converters = {
|
||||
// Convert data back to hex to decode
|
||||
const data = Buffer.from(msg.data.data['65526'], 'ascii').toString('hex');
|
||||
const command = data.substr(6, 4);
|
||||
if (command === '0301') {
|
||||
if (
|
||||
command === '0301' // ZNMS12LM
|
||||
|| command === '0341' // ZNMS13LM
|
||||
) {
|
||||
result.action = lockStatusLookup[4];
|
||||
result.state = 'UNLOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
} else if (command === '0311') {
|
||||
} else if (
|
||||
command === '0311' // ZNMS12LM
|
||||
|| command === '0351' // ZNMS13LM
|
||||
) {
|
||||
result.action = lockStatusLookup[4];
|
||||
result.state = 'LOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
} else if (command === '0205') {
|
||||
} else if (
|
||||
command === '0205' // ZNMS12LM
|
||||
|| command === '0245' // ZNMS13LM
|
||||
) {
|
||||
result.action = lockStatusLookup[3];
|
||||
result.state = 'UNLOCK';
|
||||
result.reverse = 'LOCK';
|
||||
} else if (command === '0215') {
|
||||
} else if (
|
||||
command === '0215' // ZNMS12LM
|
||||
|| command === '0255' // ZNMS13LM
|
||||
|| command === '1355' // ZNMS13LM
|
||||
) {
|
||||
result.action = lockStatusLookup[3];
|
||||
result.state = 'LOCK';
|
||||
result.reverse = 'LOCK';
|
||||
} else if (command === '0111') {
|
||||
} else if (
|
||||
command === '0111' // ZNMS12LM
|
||||
|| command === '1351' // ZNMS13LM locked from inside
|
||||
|| command === '1451' // ZNMS13LM locked from outside
|
||||
) {
|
||||
result.action = lockStatusLookup[5];
|
||||
result.state = 'LOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
} else if (command === '0b00') {
|
||||
} else if (
|
||||
command === '0b00' // ZNMS12LM
|
||||
|| command === '0640' // ZNMS13LM
|
||||
||command === '0600' // ZNMS13LM
|
||||
|
||||
) {
|
||||
result.action = lockStatusLookup[12];
|
||||
result.state = 'UNLOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
} else if (command === '0c00') {
|
||||
} else if (
|
||||
command === '0c00' // ZNMS12LM
|
||||
|| command === '2300' // ZNMS13LM
|
||||
|| command === '0540' // ZNMS13LM
|
||||
|| command === '0440' // ZNMS13LM
|
||||
) {
|
||||
result.action = lockStatusLookup[11];
|
||||
result.state = 'UNLOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
} else if (
|
||||
command === '2400' // ZNMS13LM door closed from insed
|
||||
|| command === '2401' // ZNMS13LM door closed from outside
|
||||
) {
|
||||
result.action = lockStatusLookup[17];
|
||||
result.state = 'UNLOCK';
|
||||
result.reverse = 'UNLOCK';
|
||||
}
|
||||
} else if (msg.data.data['65296']) { // finger/password success
|
||||
const data = Buffer.from(msg.data.data['65296'], 'ascii').toString('hex');
|
||||
@@ -2896,6 +3016,126 @@ const converters = {
|
||||
return result;
|
||||
},
|
||||
},
|
||||
DTB190502A1_parse: {
|
||||
cid: 'genOnOff',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const lookupKEY = {
|
||||
'0': 'KEY_SYS',
|
||||
'1': 'KEY_UP',
|
||||
'2': 'KEY_DOWN',
|
||||
'3': 'KEY_NONE',
|
||||
};
|
||||
const lookupLED = {
|
||||
'0': 'OFF',
|
||||
'1': 'ON',
|
||||
};
|
||||
return {
|
||||
cpu_temperature: precisionRound(msg.data.data['41361'], 2),
|
||||
key_state: lookupKEY[msg.data.data['41362']],
|
||||
led_state: lookupLED[msg.data.data['41363']],
|
||||
};
|
||||
},
|
||||
},
|
||||
konke_click: {
|
||||
cid: 'genOnOff',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const value = msg.data.data['onOff'];
|
||||
const lookup = {
|
||||
128: {click: 'single'}, // single click
|
||||
129: {click: 'double'}, // double and many click
|
||||
130: {click: 'long'}, // hold
|
||||
};
|
||||
|
||||
return lookup[value] ? lookup[value] : null;
|
||||
},
|
||||
},
|
||||
E1746_linkquality: {
|
||||
cid: 'genBasic',
|
||||
type: ['attReport', 'readRsp'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
return {linkquality: msg.linkquality};
|
||||
},
|
||||
},
|
||||
generic_change_batteryvoltage_3000_2500: {
|
||||
cid: 'genPowerCfg',
|
||||
type: ['devChange'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const battery = {max: 3000, min: 2500};
|
||||
const voltage = msg.data.data['batteryVoltage'] * 100;
|
||||
return {
|
||||
battery: toPercentage(voltage, battery.min, battery.max),
|
||||
voltage: voltage,
|
||||
};
|
||||
},
|
||||
},
|
||||
generic_device_temperature: {
|
||||
cid: 'genDeviceTempCfg',
|
||||
type: ['devChange'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
if (msg.data.data.hasOwnProperty('currentTemperature')) {
|
||||
return {temperature: msg.data.data.currentTemperature};
|
||||
}
|
||||
},
|
||||
},
|
||||
ptvo_switch_state: {
|
||||
cid: 'genOnOff',
|
||||
type: 'attReport',
|
||||
convert: (model, msg, publish, options) => {
|
||||
const ep = msg.endpoints[0];
|
||||
const key = `state_${getKey(model.ep(ep.device), ep.epId)}`;
|
||||
const payload = {};
|
||||
payload[key] = msg.data.data['onOff'] === 1 ? 'ON' : 'OFF';
|
||||
return payload;
|
||||
},
|
||||
},
|
||||
ptvo_switch_buttons: {
|
||||
cid: 'genMultistateInput',
|
||||
type: 'attReport',
|
||||
convert: (model, msg, publish, options) => {
|
||||
const ep = msg.endpoints[0];
|
||||
const button = getKey(model.ep(ep.device), ep.epId);
|
||||
const value = msg.data.data['presentValue'];
|
||||
|
||||
const actionLookup = {
|
||||
1: 'single',
|
||||
2: 'double',
|
||||
3: 'tripple',
|
||||
4: 'hold',
|
||||
};
|
||||
|
||||
const action = actionLookup[value];
|
||||
|
||||
if (button) {
|
||||
return {click: button + (action ? `_${action}` : '')};
|
||||
}
|
||||
},
|
||||
},
|
||||
keypad20states: {
|
||||
cid: 'genOnOff',
|
||||
type: ['devChange', 'attReport'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const ep = msg.endpoints[0];
|
||||
const button = getKey(model.ep(ep.device), ep.epId);
|
||||
const state = msg.data.data['onOff'] === 1 ? true : false;
|
||||
if (button) {
|
||||
return {[button]: state};
|
||||
}
|
||||
},
|
||||
},
|
||||
keypad20_battery: {
|
||||
cid: 'genPowerCfg',
|
||||
type: ['devChange', 'attReport'],
|
||||
convert: (model, msg, publish, options) => {
|
||||
const battery = {max: 3000, min: 2100};
|
||||
const voltage = msg.data.data['mainsVoltage'] /10;
|
||||
return {
|
||||
battery: toPercentage(voltage, battery.min, battery.max),
|
||||
voltage: voltage,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
// Ignore converters (these message dont need parsing).
|
||||
ignore_fan_change: {
|
||||
@@ -3015,7 +3255,7 @@ const converters = {
|
||||
},
|
||||
ignore_metering_change: {
|
||||
cid: 'seMetering',
|
||||
type: 'devChange',
|
||||
type: ['devChange', 'attReport'],
|
||||
convert: (model, msg, publish, options) => null,
|
||||
},
|
||||
ignore_electrical_change: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const utils = require('./utils');
|
||||
const common = require('./common');
|
||||
const zclId = require('zigbee-herdsman/dist/zcl-id');
|
||||
const Zcl = require('zigbee-herdsman/dist/zcl');
|
||||
|
||||
const cfg = {
|
||||
default: {
|
||||
@@ -31,8 +31,22 @@ const cfg = {
|
||||
manufSpec: 1,
|
||||
manufCode: 0x110c,
|
||||
},
|
||||
sinope: {
|
||||
manufSpec: 1,
|
||||
manufCode: 0x119C,
|
||||
},
|
||||
};
|
||||
|
||||
function getTransition(message, options) {
|
||||
if (message.hasOwnProperty('transition')) {
|
||||
return message.transition;
|
||||
} else if (options.hasOwnProperty('transition')) {
|
||||
return options.transition;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const converters = {
|
||||
/**
|
||||
* Generic
|
||||
@@ -75,7 +89,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -124,7 +138,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -170,12 +184,64 @@ const converters = {
|
||||
}
|
||||
},
|
||||
},
|
||||
cover_control: {
|
||||
key: ['state'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const zclCmdLookup = {
|
||||
'open': 'upOpen',
|
||||
'close': 'downClose',
|
||||
'stop': 'stop',
|
||||
'on': 'upOpen',
|
||||
'off': 'downClose',
|
||||
};
|
||||
|
||||
const zclCmd = zclCmdLookup[value.toLowerCase()];
|
||||
if (zclCmd) {
|
||||
return [{
|
||||
cid: 'closuresWindowCovering',
|
||||
cmdType: 'functional',
|
||||
cmd: zclCmd,
|
||||
zclData: {},
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
cover_gotopercentage: {
|
||||
key: ['position', 'tilt'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const isPosition = (key === 'position');
|
||||
const cid = 'closuresWindowCovering';
|
||||
const attrId = isPosition ? 'currentPositionLiftPercentage' : 'currentPositionTiltPercentage';
|
||||
// ZigBee officially expects "open" to be 0 and "closed" to be 100 whereas
|
||||
// HomeAssistant etc. work the other way round.
|
||||
value = 100 - value;
|
||||
|
||||
if (type === 'set') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmdType: 'functional',
|
||||
cmd: isPosition ? 'goToLiftPercentage' : 'goToTiltPercentage',
|
||||
zclData: isPosition ? {percentageliftvalue: value} : {percentagetiltvalue: value},
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
} else if (type === 'get') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmdType: 'foundation',
|
||||
cmd: 'read',
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
occupancy_timeout: {
|
||||
// set delay after motion detector changes from occupied to unoccupied
|
||||
key: ['occupancy_timeout'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 'msOccupancySensing'; // 1030
|
||||
const attrId = zclId.attr(cid, 'pirOToUDelay').value; // = 16
|
||||
const attrId = Zcl.getAttributeLegacy(cid, 'pirOToUDelay').value; // = 16
|
||||
|
||||
if (type === 'set') {
|
||||
return [{
|
||||
@@ -228,7 +294,7 @@ const converters = {
|
||||
cmdType: 'functional',
|
||||
zclData: {
|
||||
level: Number(value),
|
||||
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
|
||||
transtime: getTransition(message, options) * 10,
|
||||
},
|
||||
cfg: cfg.default,
|
||||
newState: {brightness: Number(value)},
|
||||
@@ -240,7 +306,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -255,7 +321,7 @@ const converters = {
|
||||
const brightnessValue = message.hasOwnProperty('brightness') ?
|
||||
message.brightness : message.brightness_percent;
|
||||
const hasState = message.hasOwnProperty('state');
|
||||
const hasTrasition = message.hasOwnProperty('transition');
|
||||
const hasTrasition = message.hasOwnProperty('transition') || options.hasOwnProperty('transition');
|
||||
const state = hasState ? message.state.toLowerCase() : null;
|
||||
|
||||
if (hasState && (state === 'off' || !hasBrightness) && !hasTrasition) {
|
||||
@@ -279,17 +345,19 @@ const converters = {
|
||||
brightness = Math.round(Number(message.brightness_percent) * 2.55).toString();
|
||||
}
|
||||
|
||||
const transition = getTransition(message, options);
|
||||
|
||||
return [{
|
||||
cid: 'genLevelCtrl',
|
||||
cmd: 'moveToLevelWithOnOff',
|
||||
cmdType: 'functional',
|
||||
zclData: {
|
||||
level: Number(brightness),
|
||||
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
|
||||
transtime: transition * 10,
|
||||
},
|
||||
cfg: options.disFeedbackRsp ? cfg.defaultdisFeedbackRsp : cfg.default,
|
||||
newState: {state: brightness === 0 ? 'OFF' : 'ON', brightness: Number(brightness)},
|
||||
readAfterWriteTime: message.hasOwnProperty('transition') ? message.transition * 1000 : 0,
|
||||
readAfterWriteTime: transition * 1000,
|
||||
}];
|
||||
}
|
||||
} else if (type === 'get') {
|
||||
@@ -298,14 +366,14 @@ const converters = {
|
||||
cid: 'genOnOff',
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr('genOnOff', 'onOff').value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy('genOnOff', 'onOff').value}],
|
||||
cfg: cfg.default,
|
||||
},
|
||||
{
|
||||
cid: 'genLevelCtrl',
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr('genLevelCtrl', 'currentLevel').value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy('genLevelCtrl', 'currentLevel').value}],
|
||||
cfg: cfg.default,
|
||||
},
|
||||
];
|
||||
@@ -332,7 +400,7 @@ const converters = {
|
||||
cmdType: 'functional',
|
||||
zclData: {
|
||||
colortemp: value,
|
||||
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
|
||||
transtime: getTransition(message, options) * 10,
|
||||
},
|
||||
cfg: cfg.default,
|
||||
newState: {color_temp: value},
|
||||
@@ -343,7 +411,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -383,7 +451,7 @@ const converters = {
|
||||
}
|
||||
|
||||
const zclData = {
|
||||
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
|
||||
transtime: getTransition(message, options) * 10,
|
||||
};
|
||||
|
||||
let newState = null;
|
||||
@@ -424,8 +492,8 @@ const converters = {
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [
|
||||
{attrId: zclId.attr(cid, 'currentX').value},
|
||||
{attrId: zclId.attr(cid, 'currentY').value},
|
||||
{attrId: Zcl.getAttributeLegacy(cid, 'currentX').value},
|
||||
{attrId: Zcl.getAttributeLegacy(cid, 'currentY').value},
|
||||
],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
@@ -460,9 +528,9 @@ const converters = {
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [
|
||||
{attrId: zclId.attr(cid, 'currentX').value},
|
||||
{attrId: zclId.attr(cid, 'currentY').value},
|
||||
{attrId: zclId.attr(cid, 'colorTemperature').value},
|
||||
{attrId: Zcl.getAttributeLegacy(cid, 'currentX').value},
|
||||
{attrId: Zcl.getAttributeLegacy(cid, 'currentY').value},
|
||||
{attrId: Zcl.getAttributeLegacy(cid, 'colorTemperature').value},
|
||||
],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
@@ -509,7 +577,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -526,8 +594,8 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: Math.round(value * 10),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -537,7 +605,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -553,7 +621,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -570,8 +638,8 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -581,7 +649,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -598,8 +666,8 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -609,7 +677,35 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
thermostat_occupied_cooling_setpoint: {
|
||||
key: 'occupied_cooling_setpoint',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 'hvacThermostat';
|
||||
const attrId = 'occupiedCoolingSetpoint';
|
||||
if (type === 'set') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
} else if (type === 'get') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -632,8 +728,8 @@ const converters = {
|
||||
// Bit 1 = 1 – outdoor temperature sensed remotely
|
||||
// Bit 2 = 0 – occupancy sensed internally
|
||||
// Bit 2 = 1 – occupancy sensed remotely
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: value, // TODO: Lookup in Zigbee documentation
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -643,7 +739,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -660,8 +756,8 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: utils.getKeyByValue(common.thermostatControlSequenceOfOperations, value, value),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -671,7 +767,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -688,8 +784,8 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: utils.getKeyByValue(common.thermostatSystemModes, value, value),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
@@ -700,7 +796,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -735,7 +831,7 @@ const converters = {
|
||||
cmd: 'setWeeklySchedule',
|
||||
cmdType: 'functional',
|
||||
zclData: {
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: value, // TODO: Combine attributes in attrData?
|
||||
temperature_setpoint_hold: value.temperature_setpoint_hold,
|
||||
temperature_setpoint_hold_duration: value.temperature_setpoint_hold_duration,
|
||||
@@ -825,7 +921,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -841,7 +937,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -858,9 +954,29 @@ const converters = {
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: zclId.attr(cid, attrId).value,
|
||||
dataType: zclId.attrType(cid, attrId).value,
|
||||
attrData: value,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: utils.getKeyByValue(common.temperatureDisplayMode, value, value),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
thermostat_keypad_lockout: {
|
||||
key: 'keypad_lockout',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 'hvacUserInterfaceCfg';
|
||||
const attrId = 'keypadLockout';
|
||||
if (type === 'set') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: utils.getKeyByValue(common.keypadLockoutMode, value, value),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
@@ -881,7 +997,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value, attrData: attrData, dataType: 48}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value, attrData: attrData, dataType: 48}],
|
||||
cfg: cfg.default,
|
||||
newState: {fan_mode: value, fan_state: value === 'off' ? 'OFF' : 'ON'},
|
||||
}];
|
||||
@@ -890,7 +1006,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -1062,7 +1178,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -1329,7 +1445,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -1361,7 +1477,7 @@ const converters = {
|
||||
cid: cid,
|
||||
cmd: 'read',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{attrId: zclId.attr(cid, attrId).value}],
|
||||
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
@@ -1380,7 +1496,7 @@ const converters = {
|
||||
gledopto_light_color_colortemp: {
|
||||
key: ['color', 'color_temp', 'color_temp_percent'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
if (message.hasOwnProperty('transition')) {
|
||||
if (message && message.hasOwnProperty('transition')) {
|
||||
message.transition = message.transition * 3.3;
|
||||
}
|
||||
|
||||
@@ -1390,7 +1506,7 @@ const converters = {
|
||||
gledopto_light_colortemp: {
|
||||
key: ['color_temp', 'color_temp_percent'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
if (message.hasOwnProperty('transition')) {
|
||||
if (message && message.hasOwnProperty('transition')) {
|
||||
message.transition = message.transition * 3.3;
|
||||
}
|
||||
|
||||
@@ -1532,6 +1648,195 @@ const converters = {
|
||||
},
|
||||
},
|
||||
|
||||
// Sinope
|
||||
sinope_thermostat_backlight_autodim_param: {
|
||||
key: 'backlight_auto_dim',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 'hvacThermostat';
|
||||
const attrId = 0x0402;
|
||||
if (type === 'set') {
|
||||
const sinopeBacklightAutoDimParam = {
|
||||
0: 'on demand',
|
||||
1: 'sensing',
|
||||
};
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x30,
|
||||
attrData: utils.getKeyByValue(sinopeBacklightAutoDimParam, value, value),
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
sinope_thermostat_enable_outdoor_temperature: {
|
||||
key: 'enable_outdoor_temperature',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 0xFF01;
|
||||
const attrId = 0x0011;
|
||||
if (type === 'set' && value.toLowerCase()=='on') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x21,
|
||||
// set outdoor temperature timer to 3 hours
|
||||
attrData: 10800,
|
||||
}],
|
||||
cfg: cfg.sinope,
|
||||
}];
|
||||
} else if (type === 'set' && value.toLowerCase()=='off') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x21,
|
||||
// set timer to 30sec in order to disable outdoor temperature
|
||||
attrData: 30,
|
||||
}],
|
||||
cfg: cfg.sinope,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
sinope_thermostat_outdoor_temperature: {
|
||||
key: 'thermostat_outdoor_temperature',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 0xFF01;
|
||||
const attrId = 0x0010;
|
||||
if (type === 'set' && value > -100 && value < 100) {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x29,
|
||||
attrData: value * 100,
|
||||
}],
|
||||
cfg: cfg.sinope,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
sinope_thermostat_time: {
|
||||
key: 'thermostat_time',
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
const cid = 0xFF01;
|
||||
const attrId = 0x0020;
|
||||
if (type === 'set' && value === '' ) {
|
||||
const thermostatDate = new Date();
|
||||
const thermostatTimeSec = thermostatDate.getTime() / 1000;
|
||||
const thermostatTimezoneOffsetSec = thermostatDate.getTimezoneOffset() * 60;
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x23,
|
||||
// Current time in second since 2000-01-01T00:00 in the current time zone
|
||||
attrData: Math.round(thermostatTimeSec - thermostatTimezoneOffsetSec - 946684800),
|
||||
}],
|
||||
cfg: cfg.sinope,
|
||||
}];
|
||||
} else if (type === 'set' && value !== '' ) {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: attrId,
|
||||
dataType: 0x23,
|
||||
attrData: value,
|
||||
}],
|
||||
cfg: cfg.sinope,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
DTB190502A1_LED: {
|
||||
key: ['LED'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
if (type === 'set') {
|
||||
if (value === 'default') {
|
||||
value = 1;
|
||||
}
|
||||
const lookup = {
|
||||
'OFF': '0',
|
||||
'ON': '1',
|
||||
};
|
||||
value = lookup[value];
|
||||
// Check for valid data
|
||||
if ( ((value >= 0) && value < 2) == false ) value = 0;
|
||||
return [{
|
||||
cid: 'genBasic',
|
||||
cmd: 'write',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
attrId: 0x4010,
|
||||
dataType: 0x21,
|
||||
attrData: value,
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
},
|
||||
},
|
||||
ptvo_switch_trigger: {
|
||||
key: ['trigger', 'interval'],
|
||||
convert: (key, value, message, type, postfix, options) => {
|
||||
console.log('ptvo_switch_trigger:', key, value, message, type, postfix);
|
||||
if (type === 'set') {
|
||||
value = parseInt(value);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cid = 'genOnOff';
|
||||
|
||||
if (key === 'trigger') {
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'onWithTimedOff',
|
||||
cmdType: 'functional',
|
||||
zclData: {
|
||||
ctrlbits: 0,
|
||||
ontime: value,
|
||||
offwaittime: 0,
|
||||
},
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
} else if (key === 'interval') {
|
||||
const attrId = 'onOff';
|
||||
return [{
|
||||
cid: cid,
|
||||
cmd: 'configReport',
|
||||
cmdType: 'foundation',
|
||||
zclData: [{
|
||||
direction: 0,
|
||||
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
|
||||
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
|
||||
attrData: value,
|
||||
minRepIntval: value,
|
||||
maxRepIntval: value,
|
||||
}],
|
||||
cfg: cfg.default,
|
||||
}];
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Ignore converters
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user