UNPKG

matterbridge-shelly

Version:
204 lines (203 loc) 11.2 kB
import EventEmitter from 'node:events'; import { BLUE, CYAN, db, debugStringify, er, GREEN, GREY, YELLOW } from 'matterbridge/logger'; import { deepEqual, isValidArray, isValidNumber, isValidObject } from 'matterbridge/utils'; import { ShellyDevice } from './shellyDevice.js'; import { ShellyProperty } from './shellyProperty.js'; export function isLightComponent(component) { if (component === undefined) return false; return ['Light', 'Rgb', 'Rgbw', 'Cct'].includes(component.name); } export function isSwitchComponent(component) { if (component === undefined) return false; return ['Relay', 'Switch'].includes(component.name); } export function isCoverComponent(component) { if (component === undefined) return false; return ['Cover', 'Roller'].includes(component.name); } export class ShellyComponent extends EventEmitter { device; id; index; name; _properties = new Map(); constructor(device, id, name, data) { super(); this.id = id; this.index = id.includes(':') ? parseInt(id.split(':')[1]) : -1; this.name = name; this.device = device; for (const prop in data) { this.addProperty(new ShellyProperty(this, prop, data[prop])); if ((isSwitchComponent(this) || isLightComponent(this)) && (prop === 'ison' || prop === 'output')) this.addProperty(new ShellyProperty(this, 'state', data[prop])); if (isLightComponent(this) && prop === 'gain') this.addProperty(new ShellyProperty(this, 'brightness', data[prop])); } if (isSwitchComponent(this) || isLightComponent(this)) { this.On = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { turn: 'on' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, on: true }); }; this.Off = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { turn: 'off' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, on: false }); }; this.Toggle = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { turn: 'toggle' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Toggle`, { id: this.index }); }; } if (isLightComponent(this)) { this.Level = function (level) { if (!this.hasProperty('brightness')) return; const adjustedLevel = Math.min(Math.max(Math.round(level), 0), 100); if (device.gen === 1 && this.hasProperty('brightness')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { brightness: adjustedLevel }); if (device.gen === 1 && this.hasProperty('gain')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { gain: adjustedLevel }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, brightness: adjustedLevel }); }; this.ColorRGB = function (red, green, blue) { if (this.hasProperty('red') && this.hasProperty('green') && this.hasProperty('blue')) { red = Math.min(Math.max(Math.round(red), 0), 255); green = Math.min(Math.max(Math.round(green), 0), 255); blue = Math.min(Math.max(Math.round(blue), 0), 255); if (device.gen === 1 && this.hasProperty('mode')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { red, green, blue, mode: 'color' }); if (device.gen === 1 && !this.hasProperty('mode')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { red, green, blue }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, red, green, blue }); } if (this.hasProperty('rgb') && isValidArray(this.getValue('rgb'), 3, 3)) { red = Math.min(Math.max(Math.round(red), 0), 255); green = Math.min(Math.max(Math.round(green), 0), 255); blue = Math.min(Math.max(Math.round(blue), 0), 255); if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { red, green, blue }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, rgb: [red, green, blue] }); } }; this.ColorTemp = function (temperature) { if (isValidNumber(temperature, 2700, 6500)) { if (device.gen === 1 && this.hasProperty('temp') && this.hasProperty('mode')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { temp: temperature, mode: 'white' }); if (device.gen === 1 && this.hasProperty('temp') && !this.hasProperty('mode')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { temp: temperature }); if (device.gen !== 1 && this.hasProperty('ct')) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Set`, { id: this.index, ct: temperature }); } }; } if (isCoverComponent(this)) { this.Open = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { go: 'open' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Open`, { id: this.index }); }; this.Close = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { go: 'close' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Close`, { id: this.index }); }; this.Stop = function () { if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { go: 'stop' }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.Stop`, { id: this.index }); }; this.GoToPosition = function (pos) { pos = Math.min(Math.max(Math.round(pos), 0), 100); if (device.gen === 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${id.slice(0, id.indexOf(':'))}/${this.index}`, { go: 'to_pos', roller_pos: pos }); if (device.gen !== 1) ShellyDevice.fetch(device.shelly, device.log, device.host, `${this.name}.GoToPosition`, { id: this.index, pos: pos }); }; } } hasProperty(key) { return this._properties.has(key); } getProperty(key) { return this._properties.get(key); } addProperty(property) { this._properties.set(property.key, property); return this; } setValue(key, value) { const property = this.getProperty(key); if (property) { if (!deepEqual(property.value, value)) { this.device.log.debug(`*${CYAN}${this.id}:${key}${GREY} updated from ${isValidObject(property.value) ? debugStringify(property.value) : property.value}${GREY} to ${YELLOW}${isValidObject(value) ? debugStringify(value) : value}${GREY} in component ${GREEN}${this.id}${GREY} (${BLUE}${this.name}${GREY})`); this.device.emit('update', this.id, key, value); this.emit('update', this.id, key, value); property.value = value; } else { } } else { this.addProperty(new ShellyProperty(this, key, value)); this.device.log.debug(`*${CYAN}${this.id}:${key}${GREY} added with value ${YELLOW}${value !== null && typeof value === 'object' ? debugStringify(value) : value}${GREY} to component ${GREEN}${this.id}${GREY} (${BLUE}${this.name}${GREY})`); } return this; } getValue(key) { const property = this.getProperty(key); if (property) return property.value; else { this.device.log.error(`****Property ${CYAN}${key}${er} not found in component ${GREEN}${this.id}${er} (${BLUE}${this.name}${er})`); return undefined; } } get properties() { return Array.from(this._properties.values()); } *[Symbol.iterator]() { for (const [key, property] of this._properties.entries()) { yield [key, property]; } } update(componentData) { for (const key in componentData) { const property = this.getProperty(key); if (property) { property.value = componentData[key]; if (property.key === 'ison') { const state = this.getProperty('state'); if (state) state.value = componentData[key]; } if (property.key === 'output') { const state = this.getProperty('state'); if (state) state.value = componentData[key]; } } } } logComponent() { this.device.log.debug(`Component ${GREEN}${this.id}${db} (${BLUE}${this.name}${db}) has the following ${this._properties.size} properties:`); for (const [key, property] of this) { this.device.log.debug(`- ${key}: ${property.value && typeof property.value === 'object' ? debugStringify(property.value) : property.value}`); } return this._properties.size; } }