UNPKG

zigbee-herdsman-converters

Version:

Collection of device converters to be used with zigbee-herdsman

1,301 lines (1,300 loc) 78.8 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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fromZigbee_1 = __importDefault(require("../converters/fromZigbee")); const toZigbee_1 = __importDefault(require("../converters/toZigbee")); const exposes = __importStar(require("../lib/exposes")); const globalStore = __importStar(require("../lib/store")); const reporting = __importStar(require("../lib/reporting")); const ota = __importStar(require("../lib/ota")); const utils = __importStar(require("../lib/utils")); const e = exposes.presets; const ea = exposes.access; const clickLookup = { 0: 'single', 1: 'release', 2: 'held', 3: 'double', 4: 'triple', 5: 'quadruple', 6: 'quintuple', }; const buttonLookup = { 1: 'down', 2: 'up', 3: 'config', 4: 'aux_down', 5: 'aux_up', 6: 'aux_config', }; const ledEffects = { off: 0, solid: 1, fast_blink: 2, slow_blink: 3, pulse: 4, chase: 5, open_close: 6, small_to_big: 7, aurora: 8, slow_falling: 9, medium_falling: 10, fast_falling: 11, slow_rising: 12, medium_rising: 13, fast_rising: 14, medium_blink: 15, slow_chase: 16, fast_chase: 17, fast_siren: 18, slow_siren: 19, clear_effect: 255, }; const individualLedEffects = { off: 0, solid: 1, fast_blink: 2, slow_blink: 3, pulse: 4, chase: 5, falling: 6, rising: 7, aurora: 8, clear_effect: 255, }; const fanModes = { low: 2, smart: 4, medium: 86, high: 170, on: 255 }; const breezemodes = ['off', 'low', 'medium', 'high']; const UINT8 = 32; const BOOLEAN = 16; const UINT16 = 33; const INOVELLI = 0x122f; // Converts brightness level to a fan mode const intToFanMode = (value) => { let selectedMode = 'low'; if (value >= fanModes.low) { selectedMode = 'low'; } if (value >= fanModes.medium) { selectedMode = 'medium'; } if (value >= fanModes.high) { selectedMode = 'high'; } if (value == 4) { selectedMode = 'smart'; } return selectedMode; }; /** * Convert speed string to int needed for breeze mode calculation. * @param speedIn - speed string * @returns low = 1, medium = 2, high = 3, off = 0 */ const speedToInt = (speedIn) => { switch (speedIn) { case 'low': return 1; case 'medium': return 2; case 'high': return 3; default: return 0; } }; // Create Expose list with Inovelli Parameters definitions const attributesToExposeList = (ATTRIBUTES, exposesList) => { Object.keys(ATTRIBUTES).forEach((key) => { if (ATTRIBUTES[key].displayType === 'enum') { const enumE = e .enum(key, ATTRIBUTES[key].readOnly ? ea.STATE_GET : ea.ALL, Object.keys(ATTRIBUTES[key].values)) .withDescription(ATTRIBUTES[key].description); exposesList.push(enumE); } else if (ATTRIBUTES[key].displayType === 'binary' || ATTRIBUTES[key].displayType === 'switch') { exposesList.push(e .binary(key, ATTRIBUTES[key].readOnly ? ea.STATE_GET : ea.ALL, // @ts-expect-error ATTRIBUTES[key].values.Enabled, ATTRIBUTES[key].values.Disabled) .withDescription(ATTRIBUTES[key].description)); } else { const numeric = e .numeric(key, ATTRIBUTES[key].readOnly ? ea.STATE_GET : ea.ALL) .withValueMin(ATTRIBUTES[key].min) .withValueMax(ATTRIBUTES[key].max); if (ATTRIBUTES[key].values) { Object.keys(ATTRIBUTES[key].values).forEach((value) => { numeric.withPreset(value, ATTRIBUTES[key].values[value], ''); }); } if (ATTRIBUTES[key].unit) { numeric.withUnit(ATTRIBUTES[key].unit); } numeric.withDescription(ATTRIBUTES[key].description); exposesList.push(numeric); } }); }; /** * Common Attributes * * These attributes are shared between all devices with the manufacturer specific Inovelli cluster * Some of the descriptions, max, min or value properties may be overridden for each device */ const COMMON_ATTRIBUTES = { dimmingSpeedUpRemote: { ID: 1, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light dims up when controlled from the hub. ' + 'A setting of 0 turns the light immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 25 (2.5s)', }, dimmingSpeedUpLocal: { ID: 2, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light dims up when controlled at the switch. ' + 'A setting of 0 turns the light immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, rampRateOffToOnRemote: { ID: 3, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light turns on when controlled from the hub. ' + 'A setting of 0 turns the light immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, rampRateOffToOnLocal: { ID: 4, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light turns on when controlled at the switch. ' + 'A setting of 0 turns the light immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, dimmingSpeedDownRemote: { ID: 5, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light dims down when controlled from the hub. ' + 'A setting of 0 turns the light immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, dimmingSpeedDownLocal: { ID: 6, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light dims down when controlled at the switch. ' + 'A setting of 0 turns the light immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpLocal setting.', }, rampRateOnToOffRemote: { ID: 7, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light turns off when controlled from the hub. ' + 'A setting of \'instant\' turns the light immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with rampRateOffToOnRemote setting.', }, rampRateOnToOffLocal: { ID: 8, dataType: UINT8, min: 0, max: 127, description: 'This changes the speed that the light turns off when controlled at the switch. ' + 'A setting of \'instant\' turns the light immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with rampRateOffToOnLocal setting.', }, minimumLevel: { ID: 9, dataType: UINT8, min: 1, max: 253, description: 'The minimum level that the dimmer allows the bulb to be dimmed to. ' + 'Useful when the user has an LED bulb that does not turn on or flickers at a lower level.', }, maximumLevel: { ID: 10, dataType: UINT8, min: 2, max: 254, description: 'The maximum level that the dimmer allows the bulb to be dimmed to.' + 'Useful when the user has an LED bulb that reaches its maximum level before the ' + 'dimmer value of 99 or when the user wants to limit the maximum brightness.', }, invertSwitch: { ID: 11, dataType: BOOLEAN, displayType: 'enum', values: { Yes: 1, No: 0 }, min: 0, max: 1, description: 'Inverts the orientation of the switch.' + ' Useful when the switch is installed upside down. Essentially up becomes down and down becomes up.', }, autoTimerOff: { ID: 12, min: 0, max: 32767, dataType: UINT16, unit: 'seconds', values: { Disabled: 0 }, description: 'Automatically turns the switch off after this many seconds.' + ' When the switch is turned on a timer is started. When the timer expires, the switch is turned off. 0 = Auto off is disabled.', }, defaultLevelLocal: { ID: 13, dataType: UINT8, min: 0, max: 255, description: 'Default level for the load when it is turned on at the switch.' + ' A setting of 255 means that the switch will return to the level that it was on before it was turned off.', }, defaultLevelRemote: { ID: 14, dataType: UINT8, min: 0, max: 255, description: 'Default level for the load when it is turned on from the hub.' + ' A setting of 255 means that the switch will return to the level that it was on before it was turned off.', }, stateAfterPowerRestored: { ID: 15, dataType: UINT8, min: 0, max: 255, description: 'The state the switch should return to when power is restored after power failure. 0 = off, 1-254 = level, 255 = previous.', }, loadLevelIndicatorTimeout: { ID: 17, dataType: UINT8, description: 'Shows the level that the load is at for x number of seconds after the load is adjusted' + ' and then returns to the Default LED state. 0 = Stay Off, 1-10 = seconds, 11 = Stay On.', displayType: 'enum', values: { 'Stay Off': 0, '1 Second': 1, '2 Seconds': 2, '3 Seconds': 3, '4 Seconds': 4, '5 Seconds': 5, '6 Seconds': 6, '7 Seconds': 7, '8 Seconds': 8, '9 Seconds': 9, '10 Seconds': 10, 'Stay On': 11, }, min: 0, max: 11, }, powerType: { ID: 21, dataType: BOOLEAN, displayType: 'enum', values: { 'Non Neutral': 0, 'Neutral': 1 }, min: 0, max: 1, readOnly: true, description: 'Set the power type for the device.', }, switchType: { ID: 22, dataType: UINT8, displayType: 'enum', values: { 'Single Pole': 0, '3-Way Dumb Switch': 1, '3-Way Aux Switch': 2, 'Single-Pole Full Sine Wave': 3 }, min: 0, max: 3, description: 'Set the switch configuration.', }, internalTemperature: { ID: 32, dataType: UINT8, min: 0, max: 127, readOnly: true, description: 'The temperature measured by the temperature sensor inside the chip, in degrees Celsius', }, overheat: { ID: 33, dataType: BOOLEAN, displayType: 'enum', values: { 'No Alert': 0, 'Overheated': 1 }, min: 0, max: 1, readOnly: true, description: 'Indicates if the internal chipset is currently in an overheated state.', }, buttonDelay: { ID: 50, dataType: UINT8, values: { '0ms': 0, '100ms': 1, '200ms': 2, '300ms': 3, '400ms': 4, '500ms': 5, '600ms': 6, '700ms': 7, '800ms': 8, '900ms': 9, }, displayType: 'enum', min: 0, max: 9, description: 'This will set the button press delay. 0 = no delay (Disables Button Press Events),' + 'Default = 500ms.', }, deviceBindNumber: { ID: 51, dataType: UINT8, readOnly: true, description: 'The number of devices currently bound (excluding gateways) and counts one group as two devices', }, smartBulbMode: { ID: 52, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Smart Bulb Mode': 1 }, description: 'For use with Smart Bulbs that need constant power and are controlled via commands rather than power.', }, doubleTapUpToParam55: { ID: 53, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Enabled': 1 }, description: 'Enable or Disable setting level to parameter 55 on double-tap UP.', }, doubleTapDownToParam56: { ID: 54, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Enabled': 1 }, description: 'Enable or Disable setting level to parameter 56 on double-tap DOWN.', }, brightnessLevelForDoubleTapUp: { ID: 55, dataType: UINT8, min: 2, max: 255, description: 'Set this level on double-tap UP (if enabled by P53). 255 = send ON command.', }, brightnessLevelForDoubleTapDown: { ID: 56, dataType: UINT8, min: 0, max: 255, description: 'Set this level on double-tap DOWN (if enabled by P54). 255 = send OFF command.', }, ledColorWhenOn: { ID: 95, dataType: UINT8, min: 0, max: 255, values: { Red: 0, Orange: 21, Yellow: 42, Green: 85, Cyan: 127, Blue: 170, Violet: 212, Pink: 234, White: 255, }, description: 'Set the color of the LED Indicator when the load is on.', }, ledColorWhenOff: { ID: 96, dataType: UINT8, min: 0, max: 255, values: { Red: 0, Orange: 21, Yellow: 42, Green: 85, Cyan: 127, Blue: 170, Violet: 212, Pink: 234, White: 255, }, description: 'Set the color of the LED Indicator when the load is off.', }, ledIntensityWhenOn: { ID: 97, dataType: UINT8, min: 0, max: 100, description: 'Set the intensity of the LED Indicator when the load is on.', }, ledIntensityWhenOff: { ID: 98, dataType: UINT8, min: 0, max: 100, description: 'Set the intensity of the LED Indicator when the load is off.', }, singleTapBehavior: { ID: 120, dataType: UINT8, displayType: 'enum', values: { 'Old Behavior': 0, 'New Behavior': 1, 'Down Always Off': 2 }, description: 'Behavior of single tapping the on or off button. Old behavior turns the switch on or off. ' + 'New behavior cycles through the levels set by P131-133. Down Always Off is like the new behavior but ' + 'down always turns the switch off instead of going to next lower speed.', }, fanTimerMode: { ID: 121, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Enabled': 1 }, description: 'Enable or disable advanced timer mode to have the switch act like a bathroom fan timer', }, fanControlMode: { ID: 130, dataType: UINT8, displayType: 'enum', values: { 'Disabled': 0, 'Multi Tap': 1, 'Cycle': 2 }, description: 'Which mode to use when binding EP3 (config button) to another device (like a fan module).', }, lowLevelForFanControlMode: { ID: 131, dataType: UINT8, min: 2, max: 254, description: 'Level to send to device bound to EP3 when set to low.', }, mediumLevelForFanControlMode: { ID: 132, dataType: UINT8, min: 2, max: 254, description: 'Level to send to device bound to EP3 when set to medium.', }, highLevelForFanControlMode: { ID: 133, dataType: UINT8, min: 2, max: 254, description: 'Level to send to device bound to EP3 when set to high.', }, ledColorForFanControlMode: { ID: 134, dataType: UINT8, min: 0, max: 255, values: { Red: 0, Orange: 21, Yellow: 42, Green: 85, Cyan: 127, Blue: 170, Violet: 212, Pink: 234, White: 255, }, description: 'LED color used to display fan control mode.', }, auxSwitchUniqueScenes: { ID: 123, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Enabled': 1 }, description: 'Have unique scene numbers for scenes activated with the aux switch.', }, bindingOffToOnSyncLevel: { ID: 125, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled': 0, 'Enabled': 1 }, description: 'Send Move_To_Level using Default Level with Off/On to bound devices.', }, localProtection: { ID: 256, dataType: BOOLEAN, values: { Disabled: 0, Enabled: 1 }, description: 'Ability to control switch from the wall.', displayType: 'enum', }, remoteProtection: { ID: 257, dataType: BOOLEAN, values: { Disabled: 0, Enabled: 1 }, readOnly: true, description: 'Ability to control switch from the hub.', displayType: 'enum', }, onOffLedMode: { ID: 259, min: 0, max: 1, values: { All: 0, One: 1 }, dataType: BOOLEAN, description: 'When the device is in On/Off mode, use full LED bar or just one LED.', displayType: 'enum', }, firmwareUpdateInProgressIndicator: { ID: 260, dataType: BOOLEAN, values: { Disabled: 0, Enabled: 1 }, description: 'Display progress on LED bar during firmware update.', displayType: 'enum', }, defaultLed1ColorWhenOn: { ID: 60, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed1ColorWhenOff: { ID: 61, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed1IntensityWhenOn: { ID: 62, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed1IntensityWhenOff: { ID: 63, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed2ColorWhenOn: { ID: 65, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed2ColorWhenOff: { ID: 66, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed2IntensityWhenOn: { ID: 67, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed2IntensityWhenOff: { ID: 68, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed3ColorWhenOn: { ID: 70, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed3ColorWhenOff: { ID: 71, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed3IntensityWhenOn: { ID: 72, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed3IntensityWhenOff: { ID: 73, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed4ColorWhenOn: { ID: 75, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed4ColorWhenOff: { ID: 76, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed4IntensityWhenOn: { ID: 77, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed4IntensityWhenOff: { ID: 78, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed5ColorWhenOn: { ID: 80, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed5ColorWhenOff: { ID: 81, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed5IntensityWhenOn: { ID: 82, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed5IntensityWhenOff: { ID: 83, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed6ColorWhenOn: { ID: 85, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed6ColorWhenOff: { ID: 86, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed6IntensityWhenOn: { ID: 87, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed6IntensityWhenOff: { ID: 88, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed7ColorWhenOn: { ID: 90, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed7ColorWhenOff: { ID: 91, dataType: UINT8, min: 0, max: 255, description: '0-254:This is the color of the LED strip in a hex representation. 255:Synchronization with default all LED strip color parameter.', }, defaultLed7IntensityWhenOn: { ID: 92, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when on. 101 = Synchronized with default all LED strip intensity parameter.', }, defaultLed7IntensityWhenOff: { ID: 93, dataType: UINT8, min: 0, max: 101, description: 'Intesity of LED strip when off. 101 = Synchronized with default all LED strip intensity parameter.', }, outputMode: { ID: 258, min: 0, max: 1, values: { 'Dimmer': 0, 'On/Off': 1 }, dataType: BOOLEAN, description: 'Use device as a Dimmer or an On/Off switch.', displayType: 'enum', }, doubleTapClearNotifications: { ID: 262, dataType: BOOLEAN, min: 0, max: 1, description: 'Double-Tap the Config button to clear notifications.', values: { 'Enabled (Default)': 0, 'Disabled': 1 }, displayType: 'enum', }, fanLedLevelType: { ID: 263, dataType: UINT8, min: 0, max: 10, values: { 'Limitless (like VZM31)': 0, 'Adaptive LED': 10 }, description: 'Level display of the LED Strip', }, }; const VZM31_ATTRIBUTES = { ...COMMON_ATTRIBUTES, activePowerReports: { ID: 18, dataType: UINT8, min: 0, max: 100, description: 'Percent power level change that will result in a new power report being sent. 0 = Disabled', }, periodicPowerAndEnergyReports: { ID: 19, min: 0, max: 32767, dataType: UINT16, description: 'Time period between consecutive power & energy reports being sent (in seconds). The timer is reset after each report is sent.', }, activeEnergyReports: { ID: 20, dataType: UINT16, min: 0, max: 32767, description: 'Energy reports Energy level change which will result in sending a new energy report.' + '0 = disabled, 1-32767 = 0.01kWh-327.67kWh. Default setting: 10 (0.1 kWh)', }, quickStartTime: { ID: 23, dataType: UINT8, min: 0, max: 60, description: 'Duration of full power output while lamp tranisitions from Off to On. In 60th of second. 0 = disable, 1 = 1/60s, 60 = 1s', }, quickStartLevel: { ID: 24, dataType: UINT8, min: 1, max: 254, description: 'Level of power output during Quick Start Light time (P23).', }, higherOutputInNonNeutral: { ID: 25, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled (default)': 0, 'Enabled': 1 }, min: 0, max: 1, description: 'Increase level in non-neutral mode', }, ledBarScaling: { ID: 100, dataType: BOOLEAN, displayType: 'enum', values: { 'Gen3 method (VZM-style)': 0, 'Gen2 method (LZW-style)': 1 }, description: 'Method used for scaling.', }, relayClick: { ID: 261, dataType: BOOLEAN, min: 0, max: 1, description: 'In neutral on/off setups, the default is to have a clicking sound to notify you that the relay ' + 'is open or closed. You may disable this sound by creating a, “simulated” on/off where the switch ' + 'only will turn onto 100 or off to 0.', values: { 'Disabled (Click Sound On)': 0, 'Enabled (Click Sound Off)': 1 }, displayType: 'enum', }, }; const VZM35_ATTRIBUTES = { ...COMMON_ATTRIBUTES, minimumLevel: { ...COMMON_ATTRIBUTES.minimumLevel, description: '1-84: The level corresponding to the fan is Low, Medium, High. ' + '85-170: The level corresponding to the fan is Medium, Medium, High. ' + '170-254: The level corresponding to the fan is High, High, High ', }, maximumLevel: { ...COMMON_ATTRIBUTES.maximumLevel, description: '2-84: The level corresponding to the fan is Low, Medium, High.', }, switchType: { ...COMMON_ATTRIBUTES.switchType, values: { 'Single Pole': 0, 'Aux Switch': 1 }, max: 1, }, smartBulbMode: { ...COMMON_ATTRIBUTES.smartBulbMode, description: 'For use with Smart Fans that need constant power and are controlled via commands rather than power.', values: { 'Disabled': 0, 'Smart Fan Mode': 1 }, }, quickStartTime: { ID: 23, dataType: UINT8, min: 0, max: 60, description: 'Duration of full power output while fan tranisitions from Off to On. In 60th of second. 0 = disable, 1 = 1/60s, 60 = 1s', }, nonNeutralAuxMediumGear: { ID: 30, dataType: UINT8, min: 42, max: 135, description: 'Identification value in Non-nuetral, medium gear, aux switch', }, nonNeutralAuxLowGear: { ID: 31, dataType: UINT8, min: 42, max: 135, description: 'Identification value in Non-nuetral, low gear, aux switch', }, outputMode: { ...COMMON_ATTRIBUTES.outputMode, values: { 'Ceiling Fan (3-Speed)': 0, 'Exhaust Fan (On/Off)': 1 }, description: 'Use device in ceiling fan (3-Speed) or in exhaust fan (On/Off) mode.', }, }; const VZM36_ATTRIBUTES = { dimmingSpeedUpRemote_1: { ...COMMON_ATTRIBUTES.dimmingSpeedUpRemote }, rampRateOffToOnRemote_1: { ...COMMON_ATTRIBUTES.rampRateOffToOnRemote }, dimmingSpeedDownRemote_1: { ...COMMON_ATTRIBUTES.dimmingSpeedDownRemote }, rampRateOnToOffRemote_1: { ...COMMON_ATTRIBUTES.rampRateOnToOffRemote }, minimumLevel_1: { ...COMMON_ATTRIBUTES.minimumLevel }, maximumLevel_1: { ...COMMON_ATTRIBUTES.maximumLevel }, autoTimerOff_1: { ...COMMON_ATTRIBUTES.autoTimerOff, description: 'Automatically turns the light off after this many seconds.' + ' When the light is turned on a timer is started. When the timer expires, the light is turned off. 0 = Auto off is disabled.', }, defaultLevelRemote_1: { ...COMMON_ATTRIBUTES.defaultLevelRemote, description: 'Default level for the light when it is turned on from the hub.' + ' A setting of 255 means that the light will return to the level that it was on before it was turned off.', }, stateAfterPowerRestored_1: { ...COMMON_ATTRIBUTES.stateAfterPowerRestored, description: 'The state the light should return to when power is restored after power failure. 0 = off, 1-254 = level, 255 = previous.', }, higherOutputInNonNeutral_1: { ID: 25, dataType: BOOLEAN, displayType: 'enum', values: { 'Disabled (default)': 0, 'Enabled': 1 }, min: 0, max: 1, description: 'Increase level in non-neutral mode for light.', }, quickStartTime_1: { ID: 23, dataType: UINT8, min: 0, max: 60, description: 'Duration of full power output while lamp tranisitions from Off to On. In 60th of second. 0 = disable, 1 = 1/60s, 60 = 1s', }, quickStartLevel_1: { ID: 24, dataType: UINT8, min: 1, max: 254, description: 'Level of power output during Quick Start Light time (P23).', }, smartBulbMode_1: { ...COMMON_ATTRIBUTES.smartBulbMode }, ledColorWhenOn_1: { ...COMMON_ATTRIBUTES.ledColorWhenOn }, ledIntensityWhenOn_1: { ...COMMON_ATTRIBUTES.ledIntensityWhenOn }, // remote protection is readonly... outputMode_1: { ...COMMON_ATTRIBUTES.outputMode }, // Endpoint 2 (Fan) dimmingSpeedUpRemote_2: { ...COMMON_ATTRIBUTES.dimmingSpeedUpRemote, description: 'This changes the speed that the fan ramps up when controlled from the hub. ' + 'A setting of 0 turns the fan immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 25 (2.5s)', }, rampRateOffToOnRemote_2: { ...COMMON_ATTRIBUTES.rampRateOffToOnRemote, description: 'This changes the speed that the fan turns on when controlled from the hub. ' + 'A setting of 0 turns the fan immediately on. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, dimmingSpeedDownRemote_2: { ...COMMON_ATTRIBUTES.dimmingSpeedDownRemote, description: 'This changes the speed that the fan ramps down when controlled from the hub. ' + 'A setting of 0 turns the fan immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with dimmingSpeedUpRemote setting.', }, rampRateOnToOffRemote_2: { ...COMMON_ATTRIBUTES.rampRateOnToOffRemote, description: 'This changes the speed that the fan turns off when controlled from the hub. ' + 'A setting of \'instant\' turns the fan immediately off. Increasing the value slows down the transition speed. ' + 'Every number represents 100ms. Default = 127 - Keep in sync with rampRateOffToOnRemote setting.', }, minimumLevel_2: { ...COMMON_ATTRIBUTES.minimumLevel, description: 'The minimum level that the fan can be set to.', }, maximumLevel_2: { ...COMMON_ATTRIBUTES.maximumLevel, description: 'The maximum level that the fan can be set to.', }, autoTimerOff_2: { ...COMMON_ATTRIBUTES.autoTimerOff, description: 'Automatically turns the fan off after this many seconds.' + ' When the fan is turned on a timer is started. When the timer expires, the switch is turned off. 0 = Auto off is disabled.', }, defaultLevelRemote_2: { ...COMMON_ATTRIBUTES.defaultLevelRemote, description: 'Default level for the fan when it is turned on from the hub.' + ' A setting of 255 means that the fan will return to the level that it was on before it was turned off.', }, stateAfterPowerRestored_2: { ...COMMON_ATTRIBUTES.stateAfterPowerRestored, description: 'The state the fan should return to when power is restored after power failure. 0 = off, 1-254 = level, 255 = previous.', }, quickStartTime_2: { ID: 23, dataType: UINT8, min: 0, max: 60, description: 'Duration of full power output while fan tranisitions from Off to On. In 60th of second. 0 = disable, 1 = 1/60s, 60 = 1s', }, // power type readonly // internal temp readonly // overheat readonly smartBulbMode_2: { ...COMMON_ATTRIBUTES.smartBulbMode, values: { 'Disabled': 0, 'Smart Fan Mode': 1 }, description: 'For use with Smart Fans that need constant power and are controlled via commands rather than power.', }, // remote protection readonly.. outputMode_2: { ...COMMON_ATTRIBUTES.outputMode, values: { 'Ceiling Fan (3-Speed)': 0, 'Exhaust Fan (On/Off)': 1 }, description: 'Use device in ceiling fan (3-Speed) or in exhaust fan (On/Off) mode.', }, }; const tzLocal = { inovelli_parameters: (ATTRIBUTES) => ({ key: Object.keys(ATTRIBUTES).filter((a) => !ATTRIBUTES[a].readOnly), convertSet: async (entity, key, value, meta) => { // Check key to see if there is an endpoint postfix for the VZM36 const keysplit = key.split('_'); let entityToUse = entity; if (keysplit.length === 2) { entityToUse = meta.device.getEndpoint(Number(keysplit[1])); } if (!(key in ATTRIBUTES)) { return; } const payload = { [ATTRIBUTES[key].ID]: { value: ATTRIBUTES[key].displayType === 'enum' ? // @ts-expect-error ATTRIBUTES[key].values[value] : value, type: ATTRIBUTES[key].dataType, }, }; await entityToUse.write('manuSpecificInovelli', payload, { manufacturerCode: INOVELLI, }); return { state: { [key]: value, }, }; }, convertGet: async (entity, key, meta) => { // Check key to see if there is an endpoint postfix for the VZM36 const keysplit = key.split('_'); let entityToUse = entity; let keyToUse = key; if (keysplit.length === 2) { entityToUse = meta.device.getEndpoint(Number(keysplit[1])); keyToUse = keysplit[0]; } await entityToUse.read('manuSpecificInovelli', [keyToUse], { manufacturerCode: INOVELLI, }); }, }), inovelli_parameters_readOnly: (ATTRIBUTES) => ({ key: Object.keys(ATTRIBUTES).filter((a) => ATTRIBUTES[a].readOnly), convertGet: async (entity, key, meta) => { // Check key to see if there is an endpoint postfix for the VZM36 const keysplit = key.split('_'); let entityToUse = entity; let keyToUse = key; if (keysplit.length === 2) { entityToUse = meta.device.getEndpoint(Number(keysplit[1])); keyToUse = keysplit[0]; } await entityToUse.read('manuSpecificInovelli', [keyToUse], { manufacturerCode: INOVELLI, }); }, }), inovelli_led_effect: { key: ['led_effect'], convertSet: async (entity, key, values, meta) => { await entity.command('manuSpecificInovelli', 'ledEffect', { // @ts-expect-error effect: ledEffects[values.effect], // @ts-expect-error color: Math.min(Math.max(0, values.color), 255), // @ts-expect-error level: Math.min(Math.max(0, values.level), 100), // @ts-expect-error duration: Math.min(Math.max(0, values.duration), 255), }, { disableResponse: true, disableDefaultResponse: true }); return { state: { [key]: values } }; }, }, inovelli_individual_led_effect: { key: ['individual_led_effect'], convertSet: async (entity, key, values, meta) => { await entity.command('manuSpecificInovelli', 'individualLedEffect', { // @ts-expect-error led: Math.min(Math.max(0, parseInt(values.led)), 7), // @ts-expect-error effect: individualLedEffects[values.effect], // @ts-expect-error color: Math.min(Math.max(0, values.color), 255), // @ts-expect-error level: Math.min(Math.max(0, values.level), 100), // @ts-expect-error duration: Math.min(Math.max(0, values.duration), 255), }, { disableResponse: true, disableDefaultResponse: true }); return { state: { [key]: values } }; }, }, /** * Inovelli VZM31SN has a default transition property that the device should * fallback to if a transition is not specified by passing 0xffff */ light_onoff_brightness_inovelli: { key: ['state', 'brightness', 'brightness_percent'], convertSet: async (entity, key, value, meta) => { const { message } = meta; const transition = utils.getTransition(entity, 'brightness', meta); const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false); let state = message.hasOwnProperty('state') ? // @ts-expect-error message.state.toLowerCase() : undefined; let brightness = undefined; if (message.hasOwnProperty('brightness')) { brightness = Number(message.brightness); } else if (message.hasOwnProperty('brightness_percent')) { brightness = utils.mapNumberRange(Number(message.brightness_percent), 0, 100, 0, 255); } if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 255)) { // Allow 255 value, changing this to 254 would be a breaking change. throw new Error(`Brightness value of message: '${JSON.stringify(message)}' invalid, must be a number >= 0 and =< 254`); } if (state !== undefined && ['on', 'off', 'toggle'].includes(state) === false) { throw new Error(`State value of message: '${JSON.stringify(message)}' invalid, must be 'ON', 'OFF' or 'TOGGLE'`); } if (state === 'toggle' || state === 'off' || (brightness === undefined && state === 'on')) { if (transition.specified && transition.time > 0) { if (state === 'toggle') { state = meta.state.state === 'ON' ? 'off' : 'on'; } if (state === 'off' && meta.state.brightness && meta.state.state === 'ON') { // https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633 // We need to remember the state before turning the device off as we need to restore // it once we turn it on again. // We cannot rely on the meta.state as when reporting is enabled the bulb will reports // it brightness while decreasing the brightness. globalStore.putValue(entity, 'brightness', meta.state.brightness); globalStore.putValue(entity, 'turnedOffWithTransition', true); } const fallbackLevel = utils.getObjectProperty(meta.state, 'brightness', 254); let level = state === 'off' ? 0 : globalStore.getValue(entity, 'brightness', fallbackLevel); if (state === 'on' && level === 0) { level = turnsOffAtBrightness1 ? 2 : 1; } const payload = { level, transtime: transition.time }; await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', payload, utils.getOptions(meta.mapped, entity)); const result = { state: { state: state.toUpperCase() } }; // @ts-expect-error if (state === 'on') result.state.brightness = level; return result; } else { // Store brightness where the bulb was turned off with as we need it when the bulb is turned on // with transition. if (meta.state.hasOwnProperty('brightness') && state === 'off') { globalStore.putValue(entity, 'brightness', meta.state.brightness); globalStore.putValue(entity, 'turnedOffWithTransition', true); } const result = await inovelliOnOffConvertSet(entity, 'state', state, meta); // @ts-expect-error result.readAfterWriteTime = 0; if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) { // @ts-expect-error result.state.brightness = 1; } return result; } } else { brightness = Math.min(254, brightness); if (brightness === 1 && turnsOffAtBrightness1) { brightness = 2; } globalStore.putValue(entity, 'brightness', brightness); await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: Number(brightness), transtime: !transition.specified ? 0xffff : transition.time, }, utils.getOptions(meta.mapped, entity)); const defaultTransitionTime = await entity.read('manuSpecificInovelli', ['rampRateOnToOffRemote']); return { state: { state: brightness === 0 ? 'OFF' : 'ON', brightness: Number(brightness), }, readAfterWriteTime: transition.time === 0 ? // @ts-expect-error defaultTransitionTime.rampRateOnToOffRemote * 100 : transition.time * 100, // need on speed }; } }, convertGet: async (entity, key, meta) => { if (key === 'brightness') { await entity.read('genLevelCtrl', ['currentLevel']); } else if (key === 'state') { await toZigbee_1.default.on_off.convertGet(entity, key, meta); } }, }, fan_mode: { key: ['fan_mode'], convertSet: async (entity, key, value, meta) => { await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: fanModes[value], transtime: 0xffff, }, utils.getOptions(meta.mapped, entity)); return { state: { [key]: value, state: 'ON', }, }; }, convertGet: async (entity, key, meta) => { await entity.read('genLevelCtrl', ['currentLevel']); }, }, fan_state: { key: ['fan_state'], convertSet: async (entity, key, value, meta) => { const state = meta.message.hasOwnProperty('fan_state') ? meta.message.fan_state.toString().toLowerCase() : null; utils.validateValue(state, ['toggle', 'off', 'on']); await entity.command('genOnOff', state, {}, utils.getOptions(meta.mapped, entity)); if (state === 'toggle') { const currentState = meta.state[`state${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`]; return currentState ? { state: { fan_state: currentState === 'OFF' ? 'ON' : 'OFF' } } : {}; } else { return { state: { fan_state: state.toString().toUpperCase() } }; } }, convertGet: async (entity, key, meta) => { await entity.read('genOnOff', ['onOff']); }, }, vzm36_fan_mode: { key: ['fan_mode'], convertSet: async (entity, key, value, meta) => { const endpoint = meta.device.getEndpoint(2); await endpoint.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: fanModes[value], transtime: 0xffff, }, utils.getOptions(meta.mapped, entity)); meta.state[key] = value; return { state: { [key]: value, fan_state: 'ON', }, }; }, convertGet: async (entity, key, meta) => {