zigbee-herdsman-converters
Version:
Collection of device converters to be used with zigbee-herdsman
738 lines • 40.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.definitions = void 0;
const zigbee_herdsman_1 = require("zigbee-herdsman");
const fz = __importStar(require("../converters/fromZigbee"));
const tz = __importStar(require("../converters/toZigbee"));
const constants = __importStar(require("../lib/constants"));
const exposes = __importStar(require("../lib/exposes"));
const reporting = __importStar(require("../lib/reporting"));
const globalStore = __importStar(require("../lib/store"));
const e = exposes.presets;
const ea = exposes.access;
const setTime = async (device) => {
const endpoint = device.getEndpoint(1);
const time = Math.round((new Date().getTime() - constants.OneJanuary2000) / 1000);
// Time-master + synchronised
const values = { timeStatus: 1, time: time, timeZone: new Date().getTimezoneOffset() * -1 * 60 };
await endpoint.write("genTime", values);
};
exports.definitions = [
{
// eTRV0100 is the same as Hive TRV001 and Popp eT093WRO. If implementing anything, please consider
// changing those two too.
zigbeeModel: ["eTRV0100", "eTRV0101", "eTRV0103", "TRV001", "TRV003", "eT093WRO", "eT093WRG"],
model: "014G2461",
vendor: "Danfoss",
description: "Ally thermostat",
whiteLabel: [
{ vendor: "Danfoss", model: "014G2463" },
{ vendor: "Hive", model: "UK7004240", description: "Radiator valve", fingerprint: [{ modelID: "TRV001" }, { modelID: "TRV003" }] },
{ vendor: "Popp", model: "701721", description: "Smart thermostat", fingerprint: [{ modelID: "eT093WRO" }, { modelID: "eT093WRG" }] },
],
meta: { thermostat: { dontMapPIHeatingDemand: true } },
fromZigbee: [
fz.battery,
fz.thermostat,
fz.thermostat_weekly_schedule,
fz.hvac_user_interface,
fz.danfoss_thermostat,
fz.danfoss_thermostat_setpoint_scheduled,
],
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.danfoss_external_measured_room_sensor,
tz.danfoss_radiator_covered,
tz.thermostat_keypad_lockout,
tz.thermostat_system_mode,
tz.danfoss_load_balancing_enable,
tz.danfoss_load_room_mean,
tz.thermostat_weekly_schedule,
tz.thermostat_clear_weekly_schedule,
tz.thermostat_programming_operation_mode,
tz.danfoss_window_open_feature,
tz.danfoss_preheat_status,
tz.danfoss_adaptation_status,
tz.danfoss_adaptation_settings,
tz.danfoss_adaptation_control,
tz.danfoss_regulation_setpoint_offset,
tz.danfoss_thermostat_occupied_heating_setpoint_scheduled,
],
exposes: (device, options) => {
const maxSetpoint = ["TRV001", "TRV003"].includes(device?.modelID) ? 32 : 35;
return [
e.battery(),
e.keypad_lockout(),
e.programming_operation_mode(),
e
.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)"),
e
.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"),
e
.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"),
e.binary("viewing_direction", ea.ALL, true, false).withDescription("Viewing/display direction, `false` normal or `true` upside-down"),
e
.binary("heat_available", ea.ALL, true, false)
.withDescription("Not clear how this affects operation. However, it would appear that the device does not execute any " +
"motor functions if this is set to false. This may be a means to conserve battery during periods that the heating " +
"system is not energized (e.g. during summer). `false` No Heat Available or `true` Heat Available"),
e
.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"),
e
.enum("setpoint_change_source", ea.STATE, ["manual", "schedule", "externally"])
.withDescription("Values observed are `0` (manual), `1` (schedule) or `2` (externally)"),
e
.climate()
.withSetpoint("occupied_heating_setpoint", 5, maxSetpoint, 0.5)
.withLocalTemperature()
.withPiHeatingDemand()
.withSystemMode(["heat"])
.withRunningState(["idle", "heat"], ea.STATE),
e
.numeric("occupied_heating_setpoint_scheduled", ea.ALL)
.withValueMin(5)
.withValueMax(maxSetpoint)
.withValueStep(0.5)
.withUnit("°C")
.withDescription("Scheduled change of the setpoint. Alternative method for changing the setpoint. In the opposite " +
"to occupied_heating_setpoint it does not trigger an aggressive response from the actuator. " +
"(more suitable for scheduled changes)"),
e
.numeric("external_measured_room_sensor", ea.ALL)
.withDescription("The temperature sensor of the TRV is — due to its design — relatively close to the heat source " +
"(i.e. the hot water in the radiator). Thus there are situations where the `local_temperature` measured by the " +
"TRV is not accurate enough: If the radiator is covered behind curtains or furniture, if the room is rather big, or " +
"if the radiator itself is big and the flow temperature is high, then the temperature in the room may easily diverge " +
"from the `local_temperature` measured by the TRV by 5°C to 8°C. In this case you might choose to use an external " +
"room sensor and send the measured value of the external room sensor to the `External_measured_room_sensor` property. " +
"The way the TRV operates on the `External_measured_room_sensor` depends on the setting of the `Radiator_covered` " +
"property: If `Radiator_covered` is `false` (Auto Offset Mode): You *must* set the `External_measured_room_sensor` " +
"property *at least* every 3 hours. After 3 hours the TRV disables this function and resets the value of the " +
"`External_measured_room_sensor` property to -8000 (disabled). You *should* set the `External_measured_room_sensor` " +
"property *at most* every 30 minutes or every 0.1°C change in measured room temperature. " +
"If `Radiator_covered` is `true` (Room Sensor Mode): You *must* set the `External_measured_room_sensor` property *at " +
"least* every 30 minutes. After 35 minutes the TRV disables this function and resets the value of the " +
"`External_measured_room_sensor` property to -8000 (disabled). You *should* set the `External_measured_room_sensor` " +
"property *at most* every 5 minutes or every 0.1°C change in measured room temperature. " +
"The unit of this value is 0.01 `°C` (so e.g. 21°C would be represented as 2100).")
.withValueMin(-8000)
.withValueMax(3500),
e
.binary("radiator_covered", ea.ALL, true, false)
.withDescription("Controls whether the TRV should solely rely on an external room sensor or operate in offset mode. " +
"`false` = Auto Offset Mode (use this e.g. for exposed radiators) or `true` = Room Sensor Mode (use this e.g. for " +
"covered radiators). Please note that this flag only controls how the TRV operates on the value of " +
"`External_measured_room_sensor`; only setting this flag without setting the `External_measured_room_sensor` " +
"has no (noticeable?) effect."),
e.binary("window_open_feature", ea.ALL, true, false).withDescription("Whether or not the window open feature is enabled"),
e
.enum("window_open_internal", ea.STATE_GET, ["quarantine", "closed", "hold", "open", "external_open"])
.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"),
e
.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)"),
e
.enum("day_of_week", ea.ALL, ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "away_or_vacation"])
.withDescription("Exercise day of week: 0=Sun...6=Sat, 7=undefined"),
e
.numeric("trigger_time", ea.ALL)
.withValueMin(0)
.withValueMax(65535)
.withDescription("Exercise trigger time. Minutes since midnight (65535=undefined). Range 0 to 1439"),
e
.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"),
e
.binary("load_balancing_enable", ea.ALL, true, false)
.withDescription("Whether or not the thermostat acts as standalone thermostat or shares load with other " +
"thermostats in the room. The gateway must update load_room_mean if enabled."),
e
.numeric("load_room_mean", ea.ALL)
.withDescription("Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)")
.withValueMin(-8000)
.withValueMax(3600),
e.numeric("load_estimate", ea.STATE_GET).withDescription("Load estimate on this radiator").withValueMin(-8000).withValueMax(3600),
e.binary("preheat_status", ea.STATE_GET, true, false).withDescription("Specific for pre-heat running in Zigbee Weekly Schedule mode"),
e
.enum("adaptation_run_status", ea.STATE_GET, ["none", "in_progress", "found", "lost"])
.withDescription("Status of adaptation run: None (before first run), In Progress, Valve Characteristic Found, Valve Characteristic Lost"),
e
.binary("adaptation_run_settings", ea.ALL, true, false)
.withDescription("Automatic adaptation run enabled (the one during the night)"),
e
.enum("adaptation_run_control", ea.ALL, ["none", "initiate_adaptation", "cancel_adaptation"])
.withDescription("Adaptation run control: Initiate Adaptation Run or Cancel Adaptation Run"),
e
.numeric("regulation_setpoint_offset", ea.ALL)
.withDescription("Regulation SetPoint Offset in range -2.5°C to 2.5°C in steps of 0.1°C. Value 2.5°C = 25.")
.withValueMin(-25)
.withValueMax(25),
];
},
ota: true,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
const options = { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S };
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "hvacThermostat"]);
// standard ZCL attributes
await reporting.batteryPercentageRemaining(endpoint);
await reporting.thermostatTemperature(endpoint);
await reporting.thermostatPIHeatingDemand(endpoint);
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
// danfoss attributes
await endpoint.configureReporting("hvacThermostat", [
{
attribute: "danfossMountedModeActive",
minimumReportInterval: constants.repInterval.MINUTE,
maximumReportInterval: constants.repInterval.MAX,
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.HOUR,
reportableChange: 1,
},
], options);
await endpoint.configureReporting("hvacThermostat", [
{
attribute: "danfossExternalMeasuredRoomSensor",
minimumReportInterval: constants.repInterval.MINUTE,
maximumReportInterval: constants.repInterval.MAX,
reportableChange: 1,
},
], options);
await endpoint.configureReporting("hvacThermostat", [
{
attribute: "danfossAdaptionRunStatus",
minimumReportInterval: constants.repInterval.MINUTE,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: 1,
},
], options);
try {
await endpoint.configureReporting("hvacThermostat", [
{
attribute: "danfossPreheatStatus",
minimumReportInterval: constants.repInterval.MINUTE,
maximumReportInterval: constants.repInterval.MAX,
reportableChange: 1,
},
], options);
}
catch {
/* not supported by all */
}
try {
await endpoint.read("hvacThermostat", [
"danfossWindowOpenFeatureEnable",
"danfossWindowOpenExternal",
"danfossDayOfWeek",
"danfossTriggerTime",
"danfossAlgorithmScaleFactor",
"danfossHeatAvailable",
"danfossMountedModeControl",
"danfossMountedModeActive",
"danfossExternalMeasuredRoomSensor",
"danfossRadiatorCovered",
"danfossLoadBalancingEnable",
"danfossLoadRoomMean",
"danfossAdaptionRunControl",
"danfossAdaptionRunSettings",
"danfossRegulationSetpointOffset",
], options);
}
catch {
/* not supported by all https://github.com/Koenkk/zigbee2mqtt/issues/11872 */
}
// read systemMode to have an initial value
await endpoint.read("hvacThermostat", ["systemMode"]);
// 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)
await setTime(device);
},
onEvent: async (type, data, device) => {
if (type === "stop") {
clearInterval(globalStore.getValue(device, "interval"));
globalStore.clearValue(device, "interval");
}
else if (["deviceAnnounce", "start"].includes(type)) {
// The device might have lost its time, so reset it. It would be more proper to check if
// the danfossSystemStatusCode has bit 10 of the SW error code attribute (0x4000) in the
// diagnostics cluster (0x0b05) is set to indicate time lost, but setting it once too many
// times shouldn't hurt.
await setTime(device);
if (!globalStore.hasValue(device, "interval")) {
// Set up a timer to refresh the time once a week to mitigate timer drift, as described
// in the Danfoss documentation. Be careful to not bump this timer past the signed 32-bit
// integer limit of setInterval, which is roughly 24.8 days.
const interval = setInterval(async () => await setTime(device), 10080000);
globalStore.putValue(device, "interval", interval);
}
}
},
},
{
fingerprint: [
{ modelID: "0x0200", manufacturerName: "Danfoss" }, // Icon Basic Main Controller
{ modelID: "0x8020", manufacturerName: "Danfoss" }, // RT24V Display
{ modelID: "0x8021", manufacturerName: "Danfoss" }, // RT24V Display Floor sensor
{ modelID: "0x8030", manufacturerName: "Danfoss" }, // RTbattery Display
{ modelID: "0x8031", manufacturerName: "Danfoss" }, // RTbattery Display Infrared
{ modelID: "0x8034", manufacturerName: "Danfoss" }, // RTbattery Dial
{ modelID: "0x8035", manufacturerName: "Danfoss" }, // RTbattery Dial Infrared
],
model: "Icon",
vendor: "Danfoss",
description: "Icon Main Controller with Zigbee Module, Room Thermostat",
fromZigbee: [
fz.danfoss_icon_battery,
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_min_heat_setpoint_limit,
tz.thermostat_max_heat_setpoint_limit,
tz.thermostat_system_mode,
tz.danfoss_room_status_code,
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 } },
endpoint: (device) => {
return {
l1: 1,
l2: 2,
l3: 3,
l4: 4,
l5: 5,
l6: 6,
l7: 7,
l8: 8,
l9: 9,
l10: 10,
l11: 11,
l12: 12,
l13: 13,
l14: 14,
l15: 15,
l16: 232,
};
},
exposes: [].concat(((endpointsCount) => {
const features = [];
for (let i = 1; i <= endpointsCount; i++) {
const epName = `l${i}`;
if (i < 16) {
features.push(e.battery().withEndpoint(epName));
features.push(e
.climate()
.withSetpoint("occupied_heating_setpoint", 5, 35, 0.5)
.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)
.withDescription("Absolute min temperature allowed on the device"));
features.push(e
.numeric("abs_max_heat_setpoint_limit", ea.STATE)
.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"));
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"));
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("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("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("Main Controller Water Status"));
features.push(e
.enum("multimaster_role", ea.STATE_GET, ["invalid_unused", "master", "slave_1", "slave_2"])
.withEndpoint("l16")
.withDescription("Main Controller Role"));
}
}
return features;
})(16)),
configure: async (device, coordinatorEndpoint) => {
const options = { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S };
for (let i = 1; i <= 15; i++) {
const endpoint = device.getEndpoint(i);
if (typeof endpoint !== "undefined") {
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: 0,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: 1,
},
], options);
await endpoint.read("genPowerCfg", ["batteryPercentageRemaining"]);
await endpoint.read("hvacThermostat", [
"localTemp",
"occupiedHeatingSetpoint",
"setpointChangeSource",
"absMinHeatSetpointLimit",
"absMaxHeatSetpointLimit",
"minHeatSetpointLimit",
"maxHeatSetpointLimit",
"systemMode",
]);
await endpoint.read("hvacThermostat", [
"danfossRoomStatusCode",
"danfossOutputStatus",
"danfossRoomFloorSensorMode",
"danfossFloorMinSetpoint",
"danfossFloorMaxSetpoint",
], options);
}
}
// Danfoss Icon Main Controller Specific Endpoint
const mainController = device.getEndpoint(232);
await reporting.bind(mainController, coordinatorEndpoint, ["haDiagnostic"]);
await mainController.read("haDiagnostic", ["danfossSystemStatusCode", "danfossSystemStatusWater", "danfossMultimasterRole"], options);
},
},
{
fingerprint: [
{ modelID: "0x0210", manufacturerName: "Danfoss" }, // Icon2 Basic Main Controller
{ modelID: "0x0211", manufacturerName: "Danfoss" }, // Icon2 Advanced Main Controller
{ modelID: "0x8040", manufacturerName: "Danfoss" }, // Icon2 Room Thermostat
{ modelID: "0x8041", manufacturerName: "Danfoss" }, // Icon2 Featured (Infrared) Room Thermostat
{ modelID: "0x0042", manufacturerName: "Danfoss" }, // Icon2 Sensor
],
model: "Icon2",
vendor: "Danfoss",
description: "Icon2 Main Controller, Room Thermostat or Sensor",
fromZigbee: [
fz.danfoss_icon_battery,
fz.thermostat,
fz.danfoss_thermostat,
fz.danfoss_icon_floor_sensor,
fz.danfoss_icon_hvac_user_interface,
fz.temperature,
fz.humidity,
fz.danfoss_icon_regulator,
],
toZigbee: [
tz.thermostat_local_temperature,
tz.thermostat_occupied_heating_setpoint,
tz.thermostat_min_heat_setpoint_limit,
tz.thermostat_max_heat_setpoint_limit,
tz.thermostat_system_mode,
tz.danfoss_room_status_code,
tz.danfoss_output_status,
tz.danfoss_floor_sensor_mode,
tz.danfoss_floor_min_setpoint,
tz.danfoss_floor_max_setpoint,
tz.thermostat_keypad_lockout,
tz.temperature,
tz.humidity,
tz.danfoss_system_status_code,
tz.danfoss_system_status_water,
tz.danfoss_multimaster_role,
],
meta: { multiEndpoint: true, thermostat: { dontMapPIHeatingDemand: true } },
exposes: [].concat(((endpointsCount) => {
const features = [];
for (let i = 1; i <= endpointsCount; i++) {
if (i < 16) {
const epName = `${i}`;
features.push(e.battery().withEndpoint(epName));
features.push(e
.climate()
.withSetpoint("occupied_heating_setpoint", 5, 35, 0.5)
.withLocalTemperature()
.withSystemMode(["heat"])
.withRunningState(["idle", "heat"], ea.STATE)
.withEndpoint(epName));
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"));
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"));
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("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"));
features.push(e.numeric("humidity", ea.STATE_GET).withUnit("%").withEndpoint(epName).withDescription("Humidity"));
}
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("232")
.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("232")
.withDescription("Main Controller Water Status"));
features.push(e
.enum("multimaster_role", ea.STATE_GET, ["invalid_unused", "master", "slave_1", "slave_2"])
.withEndpoint("232")
.withDescription("Main Controller Role"));
}
}
return features;
})(16)),
configure: async (device, coordinatorEndpoint) => {
const options = { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S };
// Danfoss Icon2 Main Controller Specific Endpoint
const mainController = device.getEndpoint(232);
for (let i = 1; i <= 15; i++) {
const endpoint = device.getEndpoint(i);
if (typeof endpoint === "undefined") {
continue;
}
await reporting.bind(endpoint, coordinatorEndpoint, [
"genPowerCfg",
"hvacThermostat",
"hvacUserInterfaceCfg",
"msTemperatureMeasurement",
"msRelativeHumidity",
]);
await reporting.batteryPercentageRemaining(endpoint);
await reporting.thermostatTemperature(endpoint);
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
await reporting.temperature(endpoint, { change: 10 });
await reporting.humidity(endpoint);
await endpoint.read("genPowerCfg", ["batteryPercentageRemaining"]);
await endpoint.read("hvacThermostat", [
"localTemp",
"occupiedHeatingSetpoint",
"minHeatSetpointLimit",
"maxHeatSetpointLimit",
"systemMode",
]);
await endpoint.read("hvacThermostat", ["danfossRoomFloorSensorMode", "danfossFloorMinSetpoint", "danfossFloorMaxSetpoint"], options);
await endpoint.read("hvacUserInterfaceCfg", ["keypadLockout"]);
await endpoint.read("msTemperatureMeasurement", ["measuredValue"]);
await endpoint.read("msRelativeHumidity", ["measuredValue"]);
// Different attributes depending on if it's Main Сontroller or a single thermostat
if (typeof mainController === "undefined") {
await endpoint.read("genBasic", ["modelId", "powerSource"]);
}
else {
await endpoint.configureReporting("hvacThermostat", [
{
attribute: "danfossOutputStatus",
minimumReportInterval: 0,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: 1,
},
], options);
await endpoint.read("hvacThermostat", ["setpointChangeSource"]);
await endpoint.read("hvacThermostat", ["danfossRoomStatusCode", "danfossOutputStatus"], options);
}
}
// Danfoss Icon2 Main Controller Specific
if (typeof mainController !== "undefined") {
await reporting.bind(mainController, coordinatorEndpoint, ["genBasic", "haDiagnostic"]);
await mainController.read("genBasic", ["modelId", "powerSource", "appVersion", "stackVersion", "hwVersion", "dateCode"]);
await mainController.read("haDiagnostic", ["danfossSystemStatusCode", "danfossSystemStatusWater", "danfossMultimasterRole"], options);
}
},
},
];
//# sourceMappingURL=danfoss.js.map