UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

1,083 lines 80 kB
"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 m = __importStar(require("../lib/modernExtend")); const reporting = __importStar(require("../lib/reporting")); const utils = __importStar(require("../lib/utils")); const utils_1 = require("../lib/utils"); const e = exposes.presets; const ea = exposes.access; const setTime = async (device) => { const endpoint = device.getEndpoint(1); const time = Math.round((Date.now() - constants.OneJanuary2000) / 1000); // Time-master + synchronised const values = { timeStatus: 1, time: time, timeZone: new Date().getTimezoneOffset() * -1 * 60 }; await endpoint.write("genTime", values); }; const danfossExtend = { addDanfossHvacThermostatCluster: () => m.deviceAddCustomCluster("hvacThermostat", { name: "hvacThermostat", ID: zigbee_herdsman_1.Zcl.Clusters.hvacThermostat.ID, attributes: { danfossWindowOpenInternal: { name: "danfossWindowOpenInternal", ID: 0x4000, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossWindowOpenExternal: { name: "danfossWindowOpenExternal", ID: 0x4003, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossDayOfWeek: { name: "danfossDayOfWeek", ID: 0x4010, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossTriggerTime: { name: "danfossTriggerTime", ID: 0x4011, type: zigbee_herdsman_1.Zcl.DataType.UINT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xffff, }, danfossMountedModeActive: { name: "danfossMountedModeActive", ID: 0x4012, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossMountedModeControl: { name: "danfossMountedModeControl", ID: 0x4013, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossThermostatOrientation: { name: "danfossThermostatOrientation", ID: 0x4014, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossExternalMeasuredRoomSensor: { name: "danfossExternalMeasuredRoomSensor", ID: 0x4015, type: zigbee_herdsman_1.Zcl.DataType.INT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -32768, max: 32767, }, danfossRadiatorCovered: { name: "danfossRadiatorCovered", ID: 0x4016, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossAlgorithmScaleFactor: { name: "danfossAlgorithmScaleFactor", ID: 0x4020, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossHeatAvailable: { name: "danfossHeatAvailable", ID: 0x4030, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossHeatRequired: { name: "danfossHeatRequired", ID: 0x4031, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossLoadBalancingEnable: { name: "danfossLoadBalancingEnable", ID: 0x4032, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossLoadRoomMean: { name: "danfossLoadRoomMean", ID: 0x4040, type: zigbee_herdsman_1.Zcl.DataType.INT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -32768, max: 32767, }, danfossLoadEstimate: { name: "danfossLoadEstimate", ID: 0x404a, type: zigbee_herdsman_1.Zcl.DataType.INT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -32768, max: 32767, }, danfossRegulationSetpointOffset: { name: "danfossRegulationSetpointOffset", ID: 0x404b, type: zigbee_herdsman_1.Zcl.DataType.INT8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -128, max: 127, }, danfossAdaptionRunControl: { name: "danfossAdaptionRunControl", ID: 0x404c, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossAdaptionRunStatus: { name: "danfossAdaptionRunStatus", ID: 0x404d, type: zigbee_herdsman_1.Zcl.DataType.BITMAP8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossAdaptionRunSettings: { name: "danfossAdaptionRunSettings", ID: 0x404e, type: zigbee_herdsman_1.Zcl.DataType.BITMAP8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossPreheatStatus: { name: "danfossPreheatStatus", ID: 0x404f, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossPreheatTime: { name: "danfossPreheatTime", ID: 0x4050, type: zigbee_herdsman_1.Zcl.DataType.UINT32, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossWindowOpenFeatureEnable: { name: "danfossWindowOpenFeatureEnable", ID: 0x4051, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossRoomStatusCode: { name: "danfossRoomStatusCode", ID: 0x4100, type: zigbee_herdsman_1.Zcl.DataType.BITMAP16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossOutputStatus: { name: "danfossOutputStatus", ID: 0x4110, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossRoomFloorSensorMode: { name: "danfossRoomFloorSensorMode", ID: 0x4120, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossFloorMinSetpoint: { name: "danfossFloorMinSetpoint", ID: 0x4121, type: zigbee_herdsman_1.Zcl.DataType.INT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -32768, max: 32767, }, danfossFloorMaxSetpoint: { name: "danfossFloorMaxSetpoint", ID: 0x4122, type: zigbee_herdsman_1.Zcl.DataType.INT16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, min: -32768, max: 32767, }, danfossScheduleTypeUsed: { name: "danfossScheduleTypeUsed", ID: 0x4130, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossIcon2PreHeat: { name: "danfossIcon2PreHeat", ID: 0x4131, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossIcon2PreHeatStatus: { name: "danfossIcon2PreHeatStatus", ID: 0x414f, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, }, commands: { danfossSetpointCommand: { name: "danfossSetpointCommand", ID: 0x40, parameters: [ { name: "setpointType", type: zigbee_herdsman_1.Zcl.DataType.ENUM8, max: 0xff }, { name: "setpoint", type: zigbee_herdsman_1.Zcl.DataType.INT16, min: -32768, max: 32767 }, ], }, }, commandsResponse: {}, }), addDanfossHvacUserInterfaceCfgCluster: () => m.deviceAddCustomCluster("hvacUserInterfaceCfg", { name: "hvacUserInterfaceCfg", ID: zigbee_herdsman_1.Zcl.Clusters.hvacUserInterfaceCfg.ID, attributes: { danfossViewingDirection: { name: "danfossViewingDirection", ID: 0x4000, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, }, commands: {}, commandsResponse: {}, }), addDanfossHaDiagnosticCluster: () => m.deviceAddCustomCluster("haDiagnostic", { name: "haDiagnostic", ID: zigbee_herdsman_1.Zcl.Clusters.haDiagnostic.ID, attributes: { danfossSystemStatusCode: { name: "danfossSystemStatusCode", ID: 0x4000, type: zigbee_herdsman_1.Zcl.DataType.BITMAP16, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, }, danfossHeatSupplyRequest: { name: "danfossHeatSupplyRequest", ID: 0x4031, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossSystemStatusWater: { name: "danfossSystemStatusWater", ID: 0x4200, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossMultimasterRole: { name: "danfossMultimasterRole", ID: 0x4201, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossIconApplication: { name: "danfossIconApplication", ID: 0x4210, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, danfossIconForcedHeatingCooling: { name: "danfossIconForcedHeatingCooling", ID: 0x4220, type: zigbee_herdsman_1.Zcl.DataType.ENUM8, manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, write: true, max: 0xff, }, }, commands: {}, commandsResponse: {}, }), absMaxHeatSetpointLimit: (args) => m.numeric({ name: "abs_max_heat_setpoint_limit", cluster: "hvacThermostat", attribute: "absMaxHeatSetpointLimit", description: "Absolute Maximum Heating Setpoint Limit.", unit: "°C", scale: 100, entityCategory: "diagnostic", access: "STATE_GET", ...args, }), keypadLockout: (args) => m.enumLookup({ name: "keypad_lockout", cluster: "hvacUserInterfaceCfg", attribute: "keypadLockout", description: "Enables/disables physical input on the device", lookup: { unlock: 0, lock: 1, }, access: "ALL", entityCategory: "config", fzConvert: (model, msg, publish, options, meta) => { const result = {}; if ("keypadLockout" in msg.data) { result[(0, utils_1.postfixWithEndpointName)("keypad_lockout", msg, model, meta)] = msg.data.keypadLockout > 0 ? "lock" : "unlock"; } return result; }, ...args, }), danfossMountedModeActive: (args) => m.binary({ name: "mounted_mode_active", cluster: "hvacThermostat", attribute: "danfossMountedModeActive", description: "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)", valueOn: [true, 1], valueOff: [false, 0], access: "STATE_GET", entityCategory: "diagnostic", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossMountedModeControl: (args) => m.binary({ name: "mounted_mode_control", cluster: "hvacThermostat", attribute: "danfossMountedModeControl", description: "Set the unit mounting mode. `false` Go to Mounted Mode or `true` Go to Mounting Mode", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossThermostatOrientation: (args) => m.binary({ name: "thermostat_vertical_orientation", cluster: "hvacThermostat", attribute: "danfossThermostatOrientation", description: "Thermostat Orientation. This is important for the PID in how it assesses temperature.", valueOn: ["vertical", 1], valueOff: ["horizontal", 0], access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossViewingDirection: (args) => m.binary({ name: "viewing_direction", cluster: "hvacUserInterfaceCfg", attribute: "danfossViewingDirection", description: "Viewing/display direction", valueOn: ["upside-down", true], valueOff: ["normal", false], access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossHeatAvailable: (args) => m.binary({ name: "heat_available", cluster: "hvacThermostat", attribute: "danfossHeatAvailable", description: "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).", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossHeatRequired: (args) => m.binary({ name: "heat_required", cluster: "hvacThermostat", attribute: "danfossHeatRequired", description: "Whether or not the unit needs warm water.", valueOn: [true, 1], valueOff: [false, 0], access: "STATE_GET", entityCategory: "diagnostic", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), setpointChangeSource: (args) => m.enumLookup({ name: "setpoint_change_source", cluster: "hvacThermostat", attribute: "setpointChangeSource", description: "Values observed", access: "STATE", lookup: { manual: 0, schedule: 1, externally: 2, }, entityCategory: "diagnostic", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), occupiedHeatingSetpointScheduled: (args) => m.numeric({ name: "occupied_heating_setpoint_scheduled", cluster: "hvacThermostat", attribute: "occupiedHeatingSetpoint", description: "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)", access: "ALL", unit: "°C", valueMin: 5, valueMax: 35, valueStep: 0.5, scale: 100, // fzConvert: zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossExternalMeasuredRoomSensor: (args) => m.numeric({ name: "external_measured_room_sensor", cluster: "hvacThermostat", attribute: "danfossExternalMeasuredRoomSensor", description: "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).", valueMin: -8000, valueMax: 3500, zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossRadiatorCovered: (args) => m.binary({ name: "radiator_covered", cluster: "hvacThermostat", attribute: "danfossRadiatorCovered", description: "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.", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossWindowOpenFeatureEnable: (args) => m.binary({ name: "window_open_feature", cluster: "hvacThermostat", attribute: "danfossWindowOpenFeatureEnable", description: "Whether or not the window open feature is enabled", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossWindowOpenInternal: (args) => m.enumLookup({ name: "window_open_internal", cluster: "hvacThermostat", attribute: "danfossWindowOpenInternal", description: "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", lookup: { quarantine: 0, closed: 1, hold: 2, open: 3, external_open: 4, }, access: "STATE_GET", entityCategory: "diagnostic", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossWindowOpenExternal: (args) => m.binary({ name: "window_open_external", cluster: "hvacThermostat", attribute: "danfossWindowOpenExternal", description: "Set if the window is open or closed. This setting will trigger a change in the internal window and heating demand.", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossDayOfWeek: (args) => m.enumLookup({ name: "day_of_week", cluster: "hvacThermostat", attribute: "danfossDayOfWeek", lookup: { sunday: 0, monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, away_or_vacation: 7, }, description: "Exercise day of week: 0=Sun...6=Sat, 7=undefined", access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossTriggerTime: (args) => m.numeric({ name: "trigger_time", cluster: "hvacThermostat", attribute: "danfossTriggerTime", description: "Exercise trigger time. Minutes since midnight (65535=undefined). Range 0 to 1439", valueMin: 0, valueMax: 1439, access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossTriggerTime2: () => { return { isModernExtend: true, exposes: [ e .text("trigger_time", ea.ALL) .withDescription("Exercise trigger time. Format: 'HH:MM' (e.g., '14:30'). Send 'undefined' to disable.") .withCategory("config"), ], fromZigbee: [ { cluster: "hvacThermostat", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { if (msg.data.danfossTriggerTime !== undefined) { const val = msg.data.danfossTriggerTime; if (val === 65535) { return { trigger_time: "undefined" }; } const hours = Math.floor(val / 60) .toString() .padStart(2, "0"); const mins = (val % 60).toString().padStart(2, "0"); return { trigger_time: `${hours}:${mins}` }; } }, }, ], toZigbee: [ { key: ["trigger_time"], convertSet: async (entity, key, value, meta) => { let val = 65535; // Default to undefined (65535) if (typeof value === "string" && value.toLowerCase() !== "undefined") { const [hours, mins] = value.split(":").map(Number); if (!Number.isNaN(hours) && !Number.isNaN(mins)) { val = hours * 60 + mins; } else { throw new Error(`Invalid time format for trigger_time: '${value}'. Please use 'HH:MM'.`); } } await entity.write("hvacThermostat", { danfossTriggerTime: val }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }); return { state: { trigger_time: value } }; }, convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossTriggerTime"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, ], }; }, danfossAlgorithmScaleFactor: (args) => m.numeric({ name: "algorithm_scale_factor", cluster: "hvacThermostat", attribute: "danfossAlgorithmScaleFactor", description: 'Scale factor of setpoint filter timeconstant ("aggressiveness" of control algorithm) 1= Quick ... 5=Moderate ... 10=Slow', valueMin: 1, valueMax: 10, access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossLoadBalancingEnable: (args) => m.binary({ name: "load_balancing_enable", cluster: "hvacThermostat", attribute: "danfossLoadBalancingEnable", description: "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.", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossLoadRoomMean: (args) => m.numeric({ name: "load_room_mean", cluster: "hvacThermostat", attribute: "danfossLoadRoomMean", description: "Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)", valueMin: -8000, valueMax: 3600, access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossLoadEstimate: (args) => m.numeric({ name: "load_estimate", cluster: "hvacThermostat", attribute: "danfossLoadEstimate", description: "Load estimate on this radiator", valueMin: -8000, valueMax: 3600, access: "STATE_GET", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossPreheatStatus: (args) => m.binary({ name: "preheat_status", cluster: "hvacThermostat", attribute: "danfossPreheatStatus", description: "Specific for pre-heat running in Zigbee Weekly Schedule mode", valueOn: [true, 1], valueOff: [false, 0], access: "STATE_GET", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossAdaptionRunStatus: (args) => m.enumLookup({ name: "adaptation_run_status", cluster: "hvacThermostat", attribute: "danfossAdaptionRunStatus", description: "Status of adaptation run: None (before first run), In Progress, Valve Characteristic Found, Valve Characteristic Lost", lookup: { none: 0, in_progress: 1, found: 2, lost: 3, lost_in_progress: 4, }, access: "STATE_GET", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossAdaptionRunSettings: (args) => m.binary({ name: "adaptation_run_settings", cluster: "hvacThermostat", attribute: "danfossAdaptionRunSettings", description: "Automatic adaptation run enabled (the one during the night)", valueOn: [true, 1], valueOff: [false, 0], access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossAdaptionRunControl: (args) => m.enumLookup({ name: "adaptation_run_control", cluster: "hvacThermostat", attribute: "danfossAdaptionRunControl", description: "Adaptation run control: Initiate Adaptation Run or Cancel Adaptation Run", lookup: { none: 0, initiate_adaptation: 1, cancel_adaptation: 2, }, access: "ALL", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossRegulationSetpointOffset: (args) => m.numeric({ name: "regulation_setpoint_offset", cluster: "hvacThermostat", attribute: "danfossRegulationSetpointOffset", description: "Regulation SetPoint Offset in range -2.5°C to 2.5°C in steps of 0.1°C.", valueMin: -2.5, valueMax: 2.5, valueStep: 0.1, scale: 10, unit: "°C", access: "ALL", entityCategory: "config", zigbeeCommandOptions: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }, ...args, }), danfossThermostat: (options) => { const extend = m.thermostat(options); const danfossSetpointConverter = { key: ["occupied_heating_setpoint", "occupied_heating_setpoint_scheduled"], convertSet: async (entity, key, value, meta) => { utils.assertNumber(value, key); const isScheduled = key === "occupied_heating_setpoint_scheduled"; const payload = { setpointType: isScheduled ? 0 : 1, // 0 for scheduled, 1 for aggressive setpoint: Math.round(value * 2) * 50, }; // Send the command await entity.command("hvacThermostat", "danfossSetpointCommand", payload, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }); if (!isScheduled) { await entity.command("hvacThermostat", "danfossSetpointCommand", payload, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }); } }, convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["occupiedHeatingSetpoint"]); }, }; extend.toZigbee.unshift(danfossSetpointConverter); const climateExpose = extend.exposes.find((exp) => typeof exp !== "function" && "type" in exp && exp.type === "climate"); if (climateExpose) { climateExpose.withRunningState(["idle", "heat"]); const runningStateFeature = climateExpose.features.find((f) => typeof f !== "function" && "name" in f && f.name === "running_state"); if (runningStateFeature) { runningStateFeature.withDescription("Running state based on danfossOutputStatus and danfossHeatRequired"); } } extend.exposes.push(e .numeric("occupied_heating_setpoint_scheduled", ea.ALL) .withValueMin(5) .withValueMax(35) .withValueStep(0.5) .withUnit("°C") .withDescription("Scheduled change of the setpoint. Alternative method for changing the setpoint. In contrast to occupied heating setpoint it does not trigger an aggressive response from the actuator. (more suitable for scheduled changes)")); extend.fromZigbee.push({ cluster: "hvacThermostat", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if ("danfossHeatRequired" in msg.data || "danfossOutputStatus" in msg.data) { const isHeating = (msg.data.danfossOutputStatus ?? msg.data.danfossHeatRequired) === 1; result.running_state = isHeating ? "heat" : "idle"; } if ("occupiedHeatingSetpoint" in msg.data) { const value = (0, utils_1.precisionRound)(msg.data.occupiedHeatingSetpoint, 2) / 100; result[(0, utils_1.postfixWithEndpointName)("occupied_heating_setpoint", msg, model, meta)] = value; result[(0, utils_1.postfixWithEndpointName)("occupied_heating_setpoint_scheduled", msg, model, meta)] = value; } return result; }, }); extend.configure.push(m.setupConfigureForReading("hvacThermostat", ["systemMode"]), m.setupConfigureForReading("hvacUserInterfaceCfg", ["keypadLockout"]), async (device, coordinatorEndpoint) => { await setTime(device); }); return extend; }, }; const tzLocal = { danfoss_output_status: { key: ["output_status"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossOutputStatus"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_room_status_code: { key: ["room_status_code"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossRoomStatusCode"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_floor_sensor_mode: { key: ["room_floor_sensor_mode"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossRoomFloorSensorMode"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_floor_min_setpoint: { key: ["floor_min_setpoint"], convertSet: async (entity, key, value, meta) => { utils.assertNumber(value, key); const danfossFloorMinSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100; await entity.write("hvacThermostat", { danfossFloorMinSetpoint }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }); return { state: { floor_min_setpoint: value } }; }, convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossFloorMinSetpoint"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_floor_max_setpoint: { key: ["floor_max_setpoint"], convertSet: async (entity, key, value, meta) => { utils.assertNumber(value, key); const danfossFloorMaxSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100; await entity.write("hvacThermostat", { danfossFloorMaxSetpoint }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S }); return { state: { floor_max_setpoint: value } }; }, convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossFloorMaxSetpoint"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_schedule_type_used: { key: ["schedule_type_used"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossScheduleTypeUsed"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_icon2_pre_heat: { key: ["icon2_pre_heat"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossIcon2PreHeat"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_icon2_pre_heat_status: { key: ["icon2_pre_heat_status"], convertGet: async (entity, key, meta) => { await entity.read("hvacThermostat", ["danfossIcon2PreHeatStatus"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_system_status_code: { key: ["system_status_code"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossSystemStatusCode"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_heat_supply_request: { key: ["heat_supply_request"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossHeatSupplyRequest"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_system_status_water: { key: ["system_status_water"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossSystemStatusWater"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_multimaster_role: { key: ["multimaster_role"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossMultimasterRole"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_icon_application: { key: ["icon_application"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossIconApplication"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, danfoss_icon_forced_heating_cooling: { key: ["icon_forced_heating_cooling"], convertGet: async (entity, key, meta) => { await entity.read("haDiagnostic", ["danfossIconForcedHeatingCooling"], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S, }); }, }, }; const fzLocal = { danfoss_thermostat: { cluster: "hvacThermostat", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; // Danfoss Icon Converters if (msg.data.danfossRoomStatusCode !== undefined) { result[(0, utils_1.postfixWithEndpointName)("room_status_code", msg, model, meta)] = constants.danfossRoomStatusCode[msg.data.danfossRoomStatusCode] !== undefined ? constants.danfossRoomStatusCode[msg.data.danfossRoomStatusCode] : msg.data.danfossRoomStatusCode; } if (msg.data.danfossOutputStatus !== undefined) { if (msg.data.danfossOutputStatus === 1) { result[(0, utils_1.postfixWithEndpointName)("output_status", msg, model, meta)] = "active"; result[(0, utils_1.postfixWithEndpointName)("running_state", msg, model, meta)] = "heat"; } else { result[(0, utils_1.postfixWithEndpointName)("output_status", msg, model, meta)] = "inactive"; result[(0, utils_1.postfixWithEndpointName)("running_state", msg, model, meta)] = "idle"; } } return result; }, }, danfoss_hvac_ui: { cluster: "hvacUserInterfaceCfg", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.danfossViewingDirection !== undefined) { result[(0, utils_1.postfixWithEndpointName)("viewing_direction", msg, model, meta)] = msg.data.danfossViewingDirection === 1; } return result; }, }, danfoss_icon_floor_sensor: { cluster: "hvacThermostat", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.danfossRoomFloorSensorMode !== undefined) { result[(0, utils_1.postfixWithEndpointName)("room_floor_sensor_mode", msg, model, meta)] = constants.danfossRoomFloorSensorMode[msg.data.danfossRoomFloorSensorMode] !== undefined ? constants.danfossRoomFloorSensorMode[msg.data.danfossRoomFloorSensorMode] : msg.data.danfossRoomFloorSensorMode; } if (msg.data.danfossFloorMinSetpoint !== undefined) { const value = (0, utils_1.precisionRound)(msg.data.danfossFloorMinSetpoint, 2) / 100; if (value >= -273.15) { result[(0, utils_1.postfixWithEndpointName)("floor_min_setpoint", msg, model, meta)] = value; } } if (msg.data.danfossFloorMaxSetpoint !== undefined) { const value = (0, utils_1.precisionRound)(msg.data.danfossFloorMaxSetpoint, 2) / 100; if (value >= -273.15) { result[(0, utils_1.postfixWithEndpointName)("floor_max_setpoint", msg, model, meta)] = value; } } if (msg.data.danfossScheduleTypeUsed !== undefined) { result[(0, utils_1.postfixWithEndpointName)("schedule_type_used", msg, model, meta)] = constants.danfossScheduleTypeUsed[msg.data.danfossScheduleTypeUsed] !== undefined ? constants.danfossScheduleTypeUsed[msg.data.danfossScheduleTypeUsed] : msg.data.danfossScheduleTypeUsed; } if (msg.data.danfossIcon2PreHeat !== undefined) { result[(0, utils_1.postfixWithEndpointName)("icon2_pre_heat", msg, model, meta)] = constants.danfossIcon2PreHeat[msg.data.danfossIcon2PreHeat] !== undefined ? constants.danfossIcon2PreHeat[msg.data.danfossIcon2PreHeat] : msg.data.danfossIcon2PreHeat; } if (msg.data.danfossIcon2PreHeatStatus !== undefined) { result[(0, utils_1.postfixWithEndpointName)("icon2_pre_heat_status", msg, model, meta)] = constants.danfossIcon2PreHeatStatus[msg.data.danfossIcon2PreHeatStatus] !== undefined ? constants.danfossIcon2PreHeatStatus[msg.data.danfossIcon2PreHeatStatus] : msg.data.danfossIcon2PreHeatStatus; } return result; }, }, danfoss_icon_battery: { cluster: "genPowerCfg", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.batteryPercentageRemaining !== undefined) { // Some devices do not comply to the ZCL and report a // batteryPercentageRemaining of 100 when the battery is full (should be 200). const dontDividePercentage = model.meta?.battery?.dontDividePercentage; let percentage = msg.data.batteryPercentageRemaining; percentage = dontDividePercentage ? percentage : percentage / 2; result[(0, utils_1.postfixWithEndpointName)("battery", msg, model, meta)] = (0, utils_1.precisionRound)(percentage, 2); } return result; }, }, danfoss_icon_regulator: { cluster: "haDiagnostic", type: ["attributeReport", "readResponse"], convert: (model, msg, publish, options, meta) => { const result = {}; if (msg.data.danfossSystemStatusCode !== undefined) { result[(0, utils_1.postfixWithEndpointName)("system_status_code", msg, model, meta)] = constants.danfossSystemStatusCode[msg.data.danfossSystemStatusCode] !== undefined ? constants.danfossSystemStatusCode[msg.data.danfossSystemStatusCode] : ms