UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

363 lines (357 loc) • 19.3 kB
const exposes = require('../lib/exposes'); const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee}; const tz = require('../converters/toZigbee'); const globalStore = require('../lib/store'); const constants = require('../lib/constants'); const reporting = require('../lib/reporting'); const extend = require('../lib/extend'); const e = exposes.presets; const ea = exposes.access; module.exports = [ { zigbeeModel: ['MOT003'], model: 'MOT003', vendor: 'Hive', description: 'Motion sensor', fromZigbee: [fz.temperature, fz.ias_occupancy_alarm_1_with_timeout, fz.battery, fz.ignore_basic_report, fz.ignore_iaszone_statuschange, fz.ignore_iaszone_attreport], toZigbee: [], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(6); const binds = ['msTemperatureMeasurement', 'genPowerCfg']; await reporting.bind(endpoint, coordinatorEndpoint, binds); await reporting.temperature(endpoint); await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']); await reporting.batteryPercentageRemaining(endpoint); }, exposes: [e.temperature(), e.occupancy(), e.battery_low(), e.tamper(), e.battery()], }, { zigbeeModel: ['DWS003'], model: 'DWS003', vendor: 'Hive', description: 'Contact sensor', fromZigbee: [fz.temperature, fz.ias_contact_alarm_1, fz.battery], toZigbee: [], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(6); const binds = ['msTemperatureMeasurement', 'genPowerCfg']; await reporting.bind(endpoint, coordinatorEndpoint, binds); await reporting.temperature(endpoint); await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']); await reporting.batteryPercentageRemaining(endpoint); }, exposes: [e.temperature(), e.contact(), e.battery_low(), e.tamper(), e.battery()], }, { zigbeeModel: ['FWBulb01'], model: 'HALIGHTDIMWWE27', vendor: 'Hive', description: 'Active smart bulb white LED (E27)', extend: extend.light_onoff_brightness(), }, { zigbeeModel: ['FWCLBulb01UK'], model: 'HALIGHTDIMWWE14', vendor: 'Hive', description: 'Active smart bulb white LED (E14)', extend: extend.light_onoff_brightness(), }, { zigbeeModel: ['FWBulb02UK'], model: 'HALIGHTDIMWWB22', vendor: 'Hive', description: 'Active smart bulb white LED (B22)', extend: extend.light_onoff_brightness(), }, { zigbeeModel: ['TWBulb02UK'], model: 'HV-GSCXZB229B', vendor: 'Hive', description: 'Active light, warm to cool white (E27 & B22)', extend: extend.light_onoff_brightness_colortemp(), }, { zigbeeModel: ['SLP2', 'SLP2b', 'SLP2c'], model: '1613V', vendor: 'Hive', description: 'Active plug', fromZigbee: [fz.on_off, fz.metering, fz.temperature], toZigbee: [tz.on_off], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(9); await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']); await reporting.onOff(endpoint); await reporting.readMeteringMultiplierDivisor(endpoint); await reporting.instantaneousDemand(endpoint); }, exposes: [e.switch(), e.power(), e.energy(), e.temperature()], }, { zigbeeModel: ['TWBulb01US'], model: 'HV-GSCXZB269', vendor: 'Hive', description: 'Active light cool to warm white (E26) ', extend: extend.light_onoff_brightness_colortemp(), }, { zigbeeModel: ['TWBulb01UK'], model: 'HV-GSCXZB279_HV-GSCXZB229_HV-GSCXZB229K', vendor: 'Hive', description: 'Active light, warm to cool white (E27 & B22)', extend: extend.light_onoff_brightness_colortemp(), }, { zigbeeModel: ['TWGU10Bulb01UK'], model: 'HV-GUCXZB5', vendor: 'Hive', description: 'Active light, warm to cool white (GU10)', extend: extend.light_onoff_brightness_colortemp(), }, { zigbeeModel: ['TRV001'], model: 'UK7004240', vendor: 'Hive', description: 'Radiator valve based on Danfos Ally', fromZigbee: [fz.battery, fz.legacy.thermostat_att_report, fz.hvac_user_interface, fz.danfoss_thermostat], toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active, tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor, tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time, tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate, tz.danfoss_viewing_direction, tz.thermostat_keypad_lockout], exposes: [e.battery(), e.keypad_lockout(), exposes.binary('mounted_mode_active', ea.STATE_GET, true, false) .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' + 'the radiator) or `true` for not mounted (after factory reset)'), exposes.binary('mounted_mode_control', ea.ALL, true, false) .withDescription('Set the unit mounting mode. `false` Go to Mounted Mode or `true` Go to Mounting Mode'), exposes.binary('thermostat_vertical_orientation', ea.ALL, true, false) .withDescription('Thermostat Orientation. This is important for the PID in how it assesses temperature. ' + '`false` Horizontal or `true` Vertical'), exposes.numeric('viewing_direction', ea.ALL).withValueMin(0).withValueMax(1) .withDescription('Viewing/Display Direction. `0` Horizontal or `1` Vertical'), exposes.binary('heat_available', ea.ALL, true, false) .withDescription('Not clear how this affects operation. `false` No Heat Available or `true` Heat Available'), exposes.binary('heat_required', ea.STATE_GET, true, false) .withDescription('Whether or not the unit needs warm water. `false` No Heat Request or `true` Heat Request'), exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 32, 0.5).withLocalTemperature().withPiHeatingDemand(), exposes.numeric('window_open_internal', ea.STATE_GET).withValueMin(0).withValueMax(4) .withDescription('0=Quarantine, 1=Windows are closed, 2=Hold - Windows are maybe about to open, ' + '3=Open window detected, 4=In window open state from external but detected closed locally'), exposes.binary('window_open_external', ea.ALL, true, false) .withDescription('Set if the window is open or close. This setting will trigger a change in the internal ' + 'window and heating demand. `false` (windows are closed) or `true` (windows are open)'), exposes.numeric('day_of_week', ea.ALL).withValueMin(0).withValueMax(7) .withDescription('Exercise day of week: 0=Sun...6=Sat, 7=undefined'), exposes.numeric('trigger_time', ea.ALL).withValueMin(0).withValueMax(65535) .withDescription('Exercise trigger time. Minutes since midnight (65535=undefined). Range 0 to 1439'), exposes.numeric('algorithm_scale_factor', ea.ALL).withValueMin(1).withValueMax(10) .withDescription('Scale factor of setpoint filter timeconstant ("aggressiveness" of control algorithm) '+ '1= Quick ... 5=Moderate ... 10=Slow'), exposes.numeric('load_estimate', ea.STATE_GET) .withDescription('Load estimate on this radiator')], configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(1); const options = {manufacturerCode: 0x1246}; await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'hvacThermostat']); // standard ZCL attributes await reporting.batteryPercentageRemaining(endpoint, {min: constants.repInterval.HOUR, max: 43200, change: 1}); await reporting.thermostatTemperature(endpoint, {min: 0, max: constants.repInterval.MINUTES_10, change: 25}); await reporting.thermostatPIHeatingDemand(endpoint, {min: 0, max: constants.repInterval.MINUTES_10, change: 1}); await reporting.thermostatOccupiedHeatingSetpoint(endpoint, {min: 0, max: constants.repInterval.MINUTES_10, change: 25}); // danfoss attributes await endpoint.configureReporting('hvacThermostat', [{ attribute: 'danfossMountedModeActive', minimumReportInterval: constants.repInterval.MINUTE, maximumReportInterval: 43200, reportableChange: 1, }], options); await endpoint.configureReporting('hvacThermostat', [{ attribute: 'danfossWindowOpenInternal', minimumReportInterval: constants.repInterval.MINUTE, maximumReportInterval: constants.repInterval.HOUR, reportableChange: 1, }], options); await endpoint.configureReporting('hvacThermostat', [{ attribute: 'danfossHeatRequired', minimumReportInterval: constants.repInterval.MINUTE, maximumReportInterval: constants.repInterval.MINUTES_10, reportableChange: 1, }], options); await endpoint.read('hvacThermostat', [ 'danfossWindowOpenExternal', 'danfossDayOfWeek', 'danfossTriggerTime', 'danfossAlgorithmScaleFactor', 'danfossHeatAvailable', 'danfossMountedModeControl', 'danfossMountedModeActive', ], options); // read keypadLockout, we don't need reporting as it cannot be set physically on the device await endpoint.read('hvacUserInterfaceCfg', ['keypadLockout']); // Seems that it is bug in Danfoss, device does not asks for the time with binding // So, we need to write time during configure (same as for HEIMAN devices) const time = Math.round(((new Date()).getTime() - constants.OneJanuary2000) / 1000); // Time-master + synchronised const values = {timeStatus: 3, time: time, timeZone: ((new Date()).getTimezoneOffset() * -1) * 60}; endpoint.write('genTime', values); }, }, { zigbeeModel: ['SLR1b'], model: 'SLR1b', vendor: 'Hive', description: 'Heating thermostat', fromZigbee: [fz.legacy.thermostat_att_report, fz.legacy.thermostat_weekly_schedule_rsp], toZigbee: [tz.thermostat_local_temperature, tz.thermostat_system_mode, tz.thermostat_running_state, tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_temperature_setpoint_hold, tz.thermostat_temperature_setpoint_hold_duration], exposes: [exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature() .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand()], meta: {disableDefaultResponse: true}, configure: async (device, coordinatorEndpoint, logger) => { const endpoint = device.getEndpoint(5); const binds = ['genBasic', 'genIdentify', 'genAlarms', 'genTime', 'hvacThermostat']; await reporting.bind(endpoint, coordinatorEndpoint, binds); await reporting.thermostatTemperature(endpoint, {min: 0, max: constants.repInterval.HOUR, change: 1}); await reporting.thermostatRunningState(endpoint); await reporting.thermostatOccupiedHeatingSetpoint(endpoint); await reporting.thermostatTemperatureSetpointHold(endpoint); await reporting.thermostatTemperatureSetpointHoldDuration(endpoint); }, }, { zigbeeModel: ['SLR2'], model: 'SLR2', vendor: 'Hive', description: 'Dual channel heating and hot water thermostat', fromZigbee: [fz.legacy.thermostat_att_report, fz.legacy.thermostat_weekly_schedule_rsp], toZigbee: [tz.thermostat_local_temperature, tz.thermostat_system_mode, tz.thermostat_running_state, tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_temperature_setpoint_hold, tz.thermostat_temperature_setpoint_hold_duration], endpoint: (device) => { return {'heat': 5, 'water': 6}; }, meta: {disableDefaultResponse: true, multiEndpoint: true}, configure: async (device, coordinatorEndpoint, logger) => { const heatEndpoint = device.getEndpoint(5); const waterEndpoint = device.getEndpoint(6); const binds = [ 'genBasic', 'genIdentify', 'genAlarms', 'genTime', 'hvacThermostat', ]; await reporting.bind(heatEndpoint, coordinatorEndpoint, binds); await reporting.thermostatTemperature(heatEndpoint, 0, constants.repInterval.HOUR, 1); await reporting.thermostatRunningState(heatEndpoint); await reporting.thermostatOccupiedHeatingSetpoint(heatEndpoint); await reporting.thermostatTemperatureSetpointHold(heatEndpoint); await reporting.thermostatTemperatureSetpointHoldDuration(heatEndpoint); await reporting.bind(waterEndpoint, coordinatorEndpoint, binds); await reporting.thermostatRunningState(waterEndpoint); await reporting.thermostatOccupiedHeatingSetpoint(waterEndpoint); await reporting.thermostatTemperatureSetpointHold(waterEndpoint); await reporting.thermostatTemperatureSetpointHoldDuration(waterEndpoint); }, exposes: [ exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature() .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand().withEndpoint('heat'), exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature() .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand().withEndpoint('water')], }, { zigbeeModel: ['SLR2b'], model: 'SLR2b', vendor: 'Hive', description: 'Dual channel heating and hot water thermostat', fromZigbee: [fz.thermostat, fz.thermostat_weekly_schedule], toZigbee: [tz.thermostat_local_temperature, tz.thermostat_system_mode, tz.thermostat_running_state, tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_temperature_setpoint_hold, tz.thermostat_temperature_setpoint_hold_duration], endpoint: (device) => { return {'heat': 5, 'water': 6}; }, meta: {disableDefaultResponse: true, multiEndpoint: true}, configure: async (device, coordinatorEndpoint, logger) => { const heatEndpoint = device.getEndpoint(5); const waterEndpoint = device.getEndpoint(6); const binds = [ 'genBasic', 'genIdentify', 'genAlarms', 'genTime', 'hvacThermostat', ]; await reporting.bind(heatEndpoint, coordinatorEndpoint, binds); await reporting.thermostatTemperature(heatEndpoint, 0, constants.repInterval.HOUR, 1); await reporting.thermostatRunningState(heatEndpoint); await reporting.thermostatOccupiedHeatingSetpoint(heatEndpoint); await reporting.thermostatTemperatureSetpointHold(heatEndpoint); await reporting.thermostatTemperatureSetpointHoldDuration(heatEndpoint); await reporting.bind(waterEndpoint, coordinatorEndpoint, binds); await reporting.thermostatRunningState(waterEndpoint); await reporting.thermostatOccupiedHeatingSetpoint(waterEndpoint); await reporting.thermostatTemperatureSetpointHold(waterEndpoint); await reporting.thermostatTemperatureSetpointHoldDuration(waterEndpoint); }, exposes: [ exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature() .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand().withEndpoint('heat'), exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 1).withLocalTemperature() .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand().withEndpoint('water')], }, { zigbeeModel: ['WPT1'], model: 'WPT1', vendor: 'Hive', description: 'Heating thermostat remote control', fromZigbee: [], toZigbee: [], exposes: [], }, { zigbeeModel: ['SLT2'], model: 'SLT2', vendor: 'Hive', description: 'Heating thermostat remote control', fromZigbee: [], toZigbee: [], exposes: [], }, { zigbeeModel: ['SLT3'], model: 'SLT3', vendor: 'Hive', description: 'Heating thermostat remote control', fromZigbee: [], toZigbee: [], exposes: [], }, { zigbeeModel: ['SLT3B'], model: 'SLT3B', vendor: 'Hive', description: 'Heating thermostat remote control', fromZigbee: [], toZigbee: [], exposes: [], }, { zigbeeModel: ['SLB2'], model: 'SLB2', vendor: 'Hive', description: 'Signal booster', toZigbee: [], fromZigbee: [fz.linkquality_from_basic], onEvent: async (type, data, device) => { if (type === 'stop') { clearInterval(globalStore.getValue(device, 'interval')); globalStore.clearValue(device, 'interval'); } else if (!globalStore.hasValue(device, 'interval')) { const interval = setInterval(async () => { try { await device.endpoints[0].read('genBasic', ['zclVersion']); } catch (error) { // Do nothing } }, 1000 * 60 * 30); // Every 30 minutes globalStore.putValue(device, 'interval', interval); } }, exposes: [], }, ];