Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Floor sensor support for Danfoss Icon #7566

Merged
merged 3 commits into from
May 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 110 additions & 54 deletions src/devices/danfoss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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'));
}
}

Expand All @@ -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);
},
},
{
Expand Down Expand Up @@ -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'])
Expand Down Expand Up @@ -462,6 +517,7 @@ const definitions: Definition[] = [
.withDescription('Main Controller Role'));
}
}

return features;
})(16)),
configure: async (device, coordinatorEndpoint) => {
Expand Down Expand Up @@ -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);
}
}

Expand Down
Loading