diff --git a/src/devices/danfoss.ts b/src/devices/danfoss.ts index 9072956730c6b..a7b66a6ca781f 100644 --- a/src/devices/danfoss.ts +++ b/src/devices/danfoss.ts @@ -229,27 +229,32 @@ const definitions: Definition[] = [ ], model: 'Icon', vendor: 'Danfoss', - description: 'Icon floor heating (regulator, Zigbee module & thermostats)', + description: 'Icon Main Controller with Zigbee Module, Room Thermostat', fromZigbee: [ - fz.danfoss_icon_regulator, - fz.danfoss_thermostat, fz.danfoss_icon_battery, - fz.thermostat], + fz.thermostat, + fz.danfoss_thermostat, + fz.danfoss_icon_regulator, + fz.danfoss_icon_floor_sensor, + fz.temperature, + ], toZigbee: [ tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, - tz.thermostat_system_mode, - tz.thermostat_running_state, tz.thermostat_min_heat_setpoint_limit, tz.thermostat_max_heat_setpoint_limit, - tz.danfoss_output_status, + tz.thermostat_system_mode, tz.danfoss_room_status_code, - tz.danfoss_system_status_water, + tz.danfoss_output_status, + tz.danfoss_floor_sensor_mode, + tz.danfoss_floor_min_setpoint, + tz.danfoss_floor_max_setpoint, + tz.temperature, tz.danfoss_system_status_code, + tz.danfoss_system_status_water, tz.danfoss_multimaster_role, ], meta: {multiEndpoint: true, thermostat: {dontMapPIHeatingDemand: true}}, - // ota: ota.zigbeeOTA, endpoint: (device) => { return { 'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5, @@ -259,40 +264,84 @@ const definitions: Definition[] = [ }, exposes: [].concat(((endpointsCount) => { const features = []; + for (let i = 1; i <= endpointsCount; i++) { const epName = `l${i}`; - if (i!=16) { + + if (i < 16) { features.push(e.battery().withEndpoint(epName)); + features.push(e.climate().withSetpoint('occupied_heating_setpoint', 5, 35, 0.5) - .withLocalTemperature().withRunningState(['idle', 'heat']).withSystemMode(['heat']).withEndpoint(epName)); + .withLocalTemperature() + .withSystemMode(['heat']) + .withRunningState(['idle', 'heat'], ea.STATE) + .withEndpoint(epName)); + features.push(e.numeric('abs_min_heat_setpoint_limit', ea.STATE) - .withUnit('°C').withEndpoint(epName) + .withUnit('°C') + .withEndpoint(epName) .withDescription('Absolute min temperature allowed on the device')); features.push(e.numeric('abs_max_heat_setpoint_limit', ea.STATE) - .withUnit('°C').withEndpoint(epName) + .withUnit('°C') + .withEndpoint(epName) .withDescription('Absolute max temperature allowed on the device')); + features.push(e.numeric('min_heat_setpoint_limit', ea.ALL) - .withValueMin(4).withValueMax(35).withValueStep(0.5).withUnit('°C') - .withEndpoint(epName).withDescription('Min temperature limit set on the device')); + .withValueMin(4) + .withValueMax(35) + .withValueStep(0.5) + .withUnit('°C') + .withEndpoint(epName) + .withDescription('Min temperature limit set on the device')); features.push(e.numeric('max_heat_setpoint_limit', ea.ALL) - .withValueMin(4).withValueMax(35).withValueStep(0.5).withUnit('°C') - .withEndpoint(epName).withDescription('Max temperature limit set on the device')); + .withValueMin(4) + .withValueMax(35) + .withValueStep(0.5) + .withUnit('°C') + .withEndpoint(epName) + .withDescription('Max temperature limit set on the device')); + features.push(e.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally']) .withEndpoint(epName)); + features.push(e.enum('output_status', ea.STATE_GET, ['inactive', 'active']) - .withEndpoint(epName).withDescription('Danfoss Output Status [Active vs Inactive])')); - features.push(e.enum('room_status_code', ea.STATE_GET, ['no_error', 'missing_rt', - 'rt_touch_error', 'floor_sensor_short_circuit', 'floor_sensor_disconnected']) - .withEndpoint(epName).withDescription('Thermostat status')); + .withEndpoint(epName) + .withDescription('Actuator status')); + + features.push(e.enum('room_status_code', ea.STATE_GET, ['no_error', 'missing_rt', 'rt_touch_error', + 'floor_sensor_short_circuit', 'floor_sensor_disconnected']) + .withEndpoint(epName) + .withDescription('Thermostat status')); + + features.push(e.enum('room_floor_sensor_mode', ea.STATE_GET, ['comfort', 'floor_only', 'dual_mode']) + .withEndpoint(epName) + .withDescription('Floor sensor mode')); + features.push(e.numeric('floor_min_setpoint', ea.ALL) + .withValueMin(18).withValueMax(35).withValueStep(0.5).withUnit('°C') + .withEndpoint(epName) + .withDescription('Min floor temperature')); + features.push(e.numeric('floor_max_setpoint', ea.ALL) + .withValueMin(18).withValueMax(35).withValueStep(0.5).withUnit('°C') + .withEndpoint(epName) + .withDescription('Max floor temperature')); + + features.push(e.numeric('temperature', ea.STATE_GET) + .withUnit('°C') + .withEndpoint(epName) + .withDescription('Floor temperature')); } else { features.push(e.enum('system_status_code', ea.STATE_GET, ['no_error', 'missing_expansion_board', 'missing_radio_module', 'missing_command_module', 'missing_master_rail', 'missing_slave_rail_no_1', 'missing_slave_rail_no_2', 'pt1000_input_short_circuit', 'pt1000_input_open_circuit', - 'error_on_one_or_more_output']).withEndpoint('l16').withDescription('Regulator Status')); + 'error_on_one_or_more_output']) + .withEndpoint('l16') + .withDescription('Main Controller Status')); features.push(e.enum('system_status_water', ea.STATE_GET, ['hot_water_flow_in_pipes', 'cool_water_flow_in_pipes']) - .withEndpoint('l16').withDescription('Water Status of Regulator')); + .withEndpoint('l16') + .withDescription('Main Controller Water Status')); features.push(e.enum('multimaster_role', ea.STATE_GET, ['invalid_unused', 'master', 'slave_1', 'slave_2']) - .withEndpoint('l16').withDescription('Regulator role (Master vs Slave)')); + .withEndpoint('l16') + .withDescription('Main Controller Role')); } } @@ -303,50 +352,56 @@ const definitions: Definition[] = [ for (let i = 1; i <= 15; i++) { const endpoint = device.getEndpoint(i); + if (typeof endpoint !== 'undefined') { - await reporting.bind(endpoint, coordinatorEndpoint, - ['genPowerCfg', 'hvacThermostat', 'hvacUserInterfaceCfg']); - await reporting.batteryPercentageRemaining(endpoint, - {min: constants.repInterval.HOUR, max: 43200, change: 1}); - await reporting.thermostatTemperature(endpoint, - {min: 0, max: constants.repInterval.MINUTES_10, change: 10}); - await reporting.thermostatOccupiedHeatingSetpoint(endpoint, - {min: 0, max: constants.repInterval.MINUTES_10, change: 10}); + await reporting.bind(endpoint, coordinatorEndpoint, [ + 'genPowerCfg', + 'hvacThermostat', + ]); + + await reporting.batteryPercentageRemaining(endpoint); + await reporting.thermostatTemperature(endpoint); + await reporting.thermostatOccupiedHeatingSetpoint(endpoint); + await reporting.temperature(endpoint, {change: 10}); await endpoint.configureReporting('hvacThermostat', [{ attribute: 'danfossOutputStatus', - minimumReportInterval: constants.repInterval.MINUTE, - maximumReportInterval: constants.repInterval.MINUTES_10, + minimumReportInterval: 0, + maximumReportInterval: constants.repInterval.HOUR, reportableChange: 1, }], options); - // Danfoss Icon Thermostat Specific + await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']); + await endpoint.read('hvacThermostat', [ + 'localTemp', + 'occupiedHeatingSetpoint', + 'setpointChangeSource', + 'absMinHeatSetpointLimit', + 'absMaxHeatSetpointLimit', + 'minHeatSetpointLimit', + 'maxHeatSetpointLimit', + 'systemMode', + ]); await endpoint.read('hvacThermostat', [ + 'danfossRoomStatusCode', 'danfossOutputStatus', - 'danfossRoomStatusCode'], options); - - // Standard Thermostat - await endpoint.read('hvacThermostat', ['localTemp']); - await endpoint.read('hvacThermostat', ['occupiedHeatingSetpoint']); - await endpoint.read('hvacThermostat', ['systemMode']); - await endpoint.read('hvacThermostat', ['setpointChangeSource']); - await endpoint.read('hvacThermostat', ['absMinHeatSetpointLimit']); - await endpoint.read('hvacThermostat', ['absMaxHeatSetpointLimit']); - await endpoint.read('hvacThermostat', ['minHeatSetpointLimit']); - await endpoint.read('hvacThermostat', ['maxHeatSetpointLimit']); - await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']); + 'danfossRoomFloorSensorMode', + 'danfossFloorMinSetpoint', + 'danfossFloorMaxSetpoint', + ], options); } } - // Danfoss Icon Regulator Specific - const endpoint232 = device.getEndpoint(232); + // Danfoss Icon Main Controller Specific Endpoint + const mainController = device.getEndpoint(232); - await reporting.bind(endpoint232, coordinatorEndpoint, ['haDiagnostic']); + await reporting.bind(mainController, coordinatorEndpoint, ['haDiagnostic']); - await endpoint232.read('haDiagnostic', [ + await mainController.read('haDiagnostic', [ 'danfossSystemStatusCode', 'danfossSystemStatusWater', - 'danfossMultimasterRole'], options); + 'danfossMultimasterRole', + ], options); }, }, { @@ -419,7 +474,7 @@ const definitions: Definition[] = [ features.push(e.enum('output_status', ea.STATE_GET, ['inactive', 'active']) .withEndpoint(epName) - .withDescription('Actuator status)')); + .withDescription('Actuator status')); features.push(e.enum('room_status_code', ea.STATE_GET, ['no_error', 'missing_rt', 'rt_touch_error', 'floor_sensor_short_circuit', 'floor_sensor_disconnected']) @@ -462,6 +517,7 @@ const definitions: Definition[] = [ .withDescription('Main Controller Role')); } } + return features; })(16)), configure: async (device, coordinatorEndpoint) => { @@ -520,7 +576,7 @@ const definitions: Definition[] = [ }], options); await endpoint.read('hvacThermostat', ['setpointChangeSource']); - await endpoint.read('hvacThermostat', ['danfossOutputStatus', 'danfossRoomStatusCode'], options); + await endpoint.read('hvacThermostat', ['danfossRoomStatusCode', 'danfossOutputStatus'], options); } }