diff --git a/converters/fromZigbee.js b/converters/fromZigbee.js index be7f523a96b22..2e141d653a086 100644 --- a/converters/fromZigbee.js +++ b/converters/fromZigbee.js @@ -158,6 +158,68 @@ const converters = { return {occupancy: true}; }, }, + bitron_battery: { + cid: 'genPowerCfg', + type: 'attReport', + convert: (model, msg, publish, options) => { + const battery = {max: 3200, min: 2500}; + const voltage = msg.data.data['batteryVoltage'] * 100; + return { + battery: toPercentage(voltage, battery.min, battery.max), + voltage: voltage, + }; + }, + }, + bitron_thermostat_att_report: { + cid: 'hvacThermostat', + type: 'attReport', + convert: (model, msg, publish, options) => { + const result = {}; + if (typeof msg.data.data['localTemp'] == 'number') { + result.local_temperature = precisionRound(msg.data.data['localTemp'], 2) / 100; + } + if (typeof msg.data.data['localTemperatureCalibration'] == 'number') { + result.local_temperature_calibration = + precisionRound(msg.data.data['localTemperatureCalibration'], 2) / 10; + } + if (typeof msg.data.data['occupiedHeatingSetpoint'] == 'number') { + result.occupied_heating_setpoint = + precisionRound(msg.data.data['occupiedHeatingSetpoint'], 2) / 100; + } + if (typeof msg.data.data['runningState'] == 'number') { + result.running_state = msg.data.data['runningState']; + } + if (typeof msg.data.data['batteryAlarmState'] == 'number') { + result.battery_alarm_state = msg.data.data['batteryAlarmState']; + } + return result; + }, + }, + bitron_thermostat_dev_change: { + cid: 'hvacThermostat', + type: 'devChange', + convert: (model, msg, publish, options) => { + const result = {}; + if (typeof msg.data.data['localTemp'] == 'number') { + result.local_temperature = precisionRound(msg.data.data['localTemp'], 2) / 100; + } + if (typeof msg.data.data['localTemperatureCalibration'] == 'number') { + result.local_temperature_calibration = + precisionRound(msg.data.data['localTemperatureCalibration'], 2) / 10; + } + if (typeof msg.data.data['occupiedHeatingSetpoint'] == 'number') { + result.occupied_heating_setpoint = + precisionRound(msg.data.data['occupiedHeatingSetpoint'], 2) / 100; + } + if (typeof msg.data.data['runningState'] == 'number') { + result.running_state = msg.data.data['runningState']; + } + if (typeof msg.data.data['batteryAlarmState'] == 'number') { + result.battery_alarm_state = msg.data.data['batteryAlarmState']; + } + return result; + }, + }, smartthings_contact: { cid: 'ssIasZone', type: 'statusChange', diff --git a/converters/toZigbee.js b/converters/toZigbee.js index 1aff14ac99195..2fe3d0084e955 100644 --- a/converters/toZigbee.js +++ b/converters/toZigbee.js @@ -305,7 +305,7 @@ const converters = { zclData: [{ attrId: zclId.attr(cid, attrId).value, dataType: zclId.attrType(cid, attrId).value, - attrData: Math.round(value) * 100, + attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100, }], cfg: cfg.default, }; @@ -333,7 +333,7 @@ const converters = { zclData: [{ attrId: zclId.attr(cid, attrId).value, dataType: zclId.attrType(cid, attrId).value, - attrData: Math.round(value) * 100, // TODO: Lookup in Zigbee documentation + attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100, }], cfg: cfg.default, }; @@ -573,6 +573,44 @@ const converters = { }; }, }, + thermostat_running_state: { + key: 'running_state', + convert: (key, value, message, type) => { + const cid = 'hvacThermostat'; + const attrId = 'runningState'; + if (type === 'get') { + return { + cid: cid, + cmd: 'read', + cmdType: 'foundation', + zclData: [{attrId: zclId.attr(cid, attrId).value}], + cfg: cfg.default, + }; + } + }, + }, + thermostat_temperature_display_mode: { + key: 'temperature_display_mode', + convert: (key, value, message, type) => { + const cid = 'hvacUserInterfaceCfg'; + const attrId = 'tempDisplayMode'; + if (type === 'set') { + return { + cid: cid, + cmd: 'write', + cmdType: 'foundation', + zclData: [{ + // 0x00 Temperature in °C + // 0x01 Temperature in °F + attrId: zclId.attr(cid, attrId).value, + dataType: zclId.attrType(cid, attrId).value, + attrData: value, + }], + cfg: cfg.default, + }; + } + }, + }, /* * Note when send the command to set sensitivity, press button on the device * to make it wakeup diff --git a/devices.js b/devices.js index 2cc6e0bfb5d7d..880c48d7b1bb4 100644 --- a/devices.js +++ b/devices.js @@ -1862,6 +1862,42 @@ const devices = [ execute(device, actions, callback); }, }, + { + zigbeeModel: ['902010/32'], + model: 'AV2010/32', + vendor: 'Bitron', + description: 'Wireless wall thermostat with relay', + supports: 'temperature, heating/cooling system control', + fromZigbee: [ + fz.ignore_basic_change, fz.bitron_thermostat_att_report, + fz.bitron_thermostat_dev_change, fz.bitron_battery, + ], + toZigbee: [ + tz.thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature_calibration, + tz.thermostat_local_temperature, tz.thermostat_running_state, + tz.thermostat_temperature_display_mode, + ], + configure: (ieeeAddr, shepherd, coordinator, callback) => { + const device = shepherd.find(ieeeAddr, 1); + const actions = [ + (cb) => device.bind('genBasic', coordinator, cb), + (cb) => device.bind('genPowerCfg', coordinator, cb), + (cb) => device.bind('genIdentify', coordinator, cb), + (cb) => device.bind('genTime', coordinator, cb), + (cb) => device.bind('genPollCtrl', coordinator, cb), + (cb) => device.bind('hvacThermostat', coordinator, cb), + (cb) => device.bind('hvacUserInterfaceCfg', coordinator, cb), + (cb) => device.report('hvacThermostat', 'localTemp', 300, 3600, 0, cb), + (cb) => device.report('hvacThermostat', 'localTemperatureCalibration', 1, 0, 0, cb), + (cb) => device.report('hvacThermostat', 'occupiedHeatingSetpoint', 1, 0, 1, cb), + (cb) => device.report('hvacThermostat', 'runningState', 1, 0, 0, cb), + (cb) => device.report('genPowerCfg', 'batteryVoltage', 1800, 43200, 0, cb), + (cb) => device.report('genPowerCfg', 'batteryAlarmState', 1, 0, 1, cb), + ]; + + execute(device, actions, callback); + }, + }, // Iris {