matterbridge-shelly
Version:
Matterbridge shelly plugin
204 lines (203 loc) • 11.2 kB
JavaScript
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;
}
}