iobroker.yeelight-2
Version:
1,117 lines (1,040 loc) • 42.5 kB
JavaScript
/* eslint-disable jsdoc/require-param-description */
/* jshint -W097 */ // jshint strict:false
/*jslint node: true */
;
// The adapter-core module gives you access to the core ioBroker functions
const utils = require('@iobroker/adapter-core');
const scenen = require(`${__dirname}/lib/scenen`);
const YeelightSearch = require(`${__dirname}/yeelight-wifi/build/index`);
let Yeelights;
let gthis = null; // global to 'this' of Yeelight2 main instance
//just for test
const JSON = require('circular-json');
let timeOutInterval;
let ConfigDevices = [];
let ObjDevices = [];
const initializedLights = [];
let discoveryTimeout = null;
class Yeelight2 extends utils.Adapter {
constructor(options) {
super({
...options,
name: 'yeelight-2',
});
this.on('ready', this.onReady.bind(this));
this.on('stateChange', this.onStateChange.bind(this));
this.on('objectChange', this.onObjectChange.bind(this));
this.on('message', this.onMessage.bind(this));
this.on('unload', this.onUnload.bind(this));
// eslint-disable-next-line @typescript-eslint/no-this-alias
gthis = this;
}
/**
* Is called when databases are connected and adapter received configuration.
*/
async onReady() {
this.main();
this.log.debug(`DEVICES IN CONFIG: ${JSON.stringify(this.config.devices)}`);
ConfigDevices = this.config.devices;
}
/**
* Is called when adapter shuts down - callback has to be called under any circumstances!
*
* @param callback
*/
onUnload(callback) {
try {
clearInterval(timeOutInterval);
clearTimeout(discoveryTimeout);
initializedLights.forEach(light => {
try {
light.disconnect();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
// ignore
}
});
this.log.info('cleaned everything up...');
callback();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
callback();
}
}
// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
/**
* Is called if a subscribed object changes
*
* @param id
* @param obj
*/
onObjectChange(id, obj) {
// Warning, obj can be null if it was deleted
this.log.info(`objectChange ${id} ${JSON.stringify(obj)}`);
}
/**
* Is called if a subscribed state changes
*
* @param id
* @param state
*/
onStateChange(id, state) {
if (state && !state.ack) {
const changeState = id.split('.');
const sid = `${this.namespace}.${changeState[2]}`;
// search id in config
const findlight = ConfigDevices.find(device => device.name === changeState[2]);
if (findlight) {
if (changeState[3] !== 'info' && changeState[3] !== 'scenen') {
if (!state.ack) {
this.uploadState(findlight.id, changeState[4], state.val, sid);
}
} else if (changeState[3] === 'scenen') {
if (!state.ack) {
this._sendscene(findlight.id, changeState[4], state.val);
}
}
} else {
this.log.error(`LIGHT: ${changeState[2]} NOT FOUND IN CONFIG!`);
}
}
}
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
/**
* Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
* Using this method requires "common.messagebox" property to be set to true in io-package.json
*
* @param obj
*/
onMessage(obj) {
this.log.debug(`here is a Message: ${JSON.stringify(obj)}`);
if (!obj) {
return;
}
function reply(result) {
gthis.sendTo(obj.from, obj.command, JSON.stringify(result), obj.callback);
}
switch (obj.command) {
case 'discovery': {
const deviceDiscovered = [];
this.initYeelight();
Yeelights.refresh();
const foundHandler = Yeelights.on('found', light => {
deviceDiscovered.push({
model: light.model,
host: light.hostname,
port: light.port,
id: light.getId(),
});
this.log.debug(
`Found Light {id: ${light.getId()}, name: ${light.name}, model: ${light.model}, \nsupports: ${light.supports}}`,
);
});
discoveryTimeout = setTimeout(() => {
Yeelights && Yeelights.removeEventListener && Yeelights.removeEventListener('found', foundHandler);
reply(deviceDiscovered);
}, 5000);
return true;
}
default:
this.log.debug(`Unknown command: ${obj.command}`);
break;
}
}
initYeelight() {
if (Yeelights) {
return;
}
Yeelights = new YeelightSearch();
Yeelights.on('error', err => {
gthis.log.error(`Yeelight Error: ${err}`);
});
}
uploadState(id, parameter, value, sid) {
if (!Yeelights) {
return;
}
let checkHex = null;
this.log.debug(`SEND STATE: id:${id}, state: ${parameter}, value: ${value}`);
const aktYeelight = Yeelights.getYeelightById(id);
if (aktYeelight) {
switch (parameter) {
case 'set_scene':
aktYeelight
.setScene(JSON.parse(value))
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'power':
if (value) {
aktYeelight
.turnOn()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
}
aktYeelight
.turnOff()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'bg_power':
if (value) {
aktYeelight
.turnOnBg()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
}
aktYeelight
.turnOffBg()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'active_bright':
aktYeelight
.setBrightness(value)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'bg_bright':
aktYeelight
.setBrightnessBg(value)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'ct':
aktYeelight
.setColorTemperature(value)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'bg_ct':
aktYeelight
.setColorTemperatureBg(value)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'moon_mode':
if (value) {
aktYeelight
.moonMode()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
}
aktYeelight
.defaultMode()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
case 'rgb':
checkHex = /^#[0-9A-F]{6}$/i.test(value);
if (checkHex) {
aktYeelight
.setRGB(value, 'sudden', 400)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
} else {
this.log.warn('Please enter a Hex Format like: "#FF22AA"');
}
break;
case 'bg_rgb':
checkHex = /^#[0-9A-F]{6}$/i.test(value);
if (checkHex) {
aktYeelight
.setRGBBg(value)
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
} else {
this.log.warn('Please enter a Hex Format like: "#FF22AA"');
}
break;
case 'hue':
// TODO catch NAN an 1-360;
this.getState(`${sid}.control.sat`, function (err, state) {
if (!state) {
return;
}
const saturation = state.val;
aktYeelight
.setHSV((value || '').toString(), (saturation || '').toString())
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
});
break;
case 'bg_hue':
this.getState(`${sid}.control.bg_sat`, function (err, state) {
if (!state) {
return;
}
const saturation = state.val;
aktYeelight
.setHSVBg((value || '').toString(), (saturation || '').toString())
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
});
break;
case 'sat':
// TODO catch NAN an 1-100;
this.getState(`${sid}.control.hue`, function (err, state) {
if (!state) {
return;
}
const hue = state.val;
aktYeelight
.setHSV((hue || '').toString(), (value || '').toString())
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
});
break;
case 'bg_sat':
this.getState(`${sid}.control.bg_hue`, function (err, state) {
if (!state) {
return;
}
const hue = state.val;
aktYeelight
.setHSVBg((hue || '').toString(), (value || '').toString())
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
});
break;
case 'color_mode':
if (value) {
aktYeelight
.colorMode()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
}
aktYeelight
.defaultMode()
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
break;
default:
this.log.warn('State not found');
}
}
}
_sendscene(id, parameter, value) {
if (!Yeelights) {
return;
}
this.log.debug(`SEND SCENE: id:${id}, state: ${parameter}, value: ${value}`);
const aktYeelight = Yeelights.getYeelightById(id);
if (aktYeelight) {
aktYeelight
.setScene(scenen[parameter])
.catch(err => this.generateWarnMessageForUploadState(parameter, value, id, err));
}
}
_createscenen(sid) {
for (const key in scenen) {
this.setObjectNotExists(`${sid}.scenen.${key}`, {
common: {
name: key,
role: 'button.scenen',
write: true,
read: false,
type: 'boolean',
},
type: 'state',
native: {},
});
}
}
checkChanges(callback) {
this.getForeignObjects(`${this.namespace}.*`, 'device', async function (err, list) {
if (err) {
this.log.error(err);
} else {
ObjDevices = list;
gthis.log.debug(`DEVICES IN OBJECTS: ${JSON.stringify(ObjDevices)}`);
const count = Object.keys(ObjDevices).length;
gthis.log.debug(`DEVICES IN OBJECTS FOUND: ${count}`);
//check every device
for (let j = 0; j < count; j++) {
const element = Object.keys(ObjDevices)[j];
gthis.log.debug(`OBJ_ELEMENT: ${element}`);
const oldConfig = await getastate(element);
await ifinConfig(element, oldConfig);
}
gthis.subscribeStates('*');
callback && callback();
}
});
async function getastate(element) {
const state = await gthis.getStateAsync(`${element}.info.com`);
gthis.log.debug(`OLD CONF. FROM OBJ: ${state && state.val}`);
try {
return JSON.parse(state.val);
} catch (err) {
gthis.log.error(`Could not parse ${`${element}.info.com`}: ${err.message}`);
return '';
}
}
async function ifinConfig(element, oldConfig) {
const sid = ObjDevices[element].native.sid;
const type = ObjDevices[element].native.type;
let isThere = false;
for (let i = 0; i < ConfigDevices.length; i++) {
if (ConfigDevices[i].name == sid && ConfigDevices[i].type == type) {
isThere = true;
gthis.log.debug(`SMARTNAME: ${ConfigDevices[i].smart_name}`);
if (ConfigDevices[i].ip !== oldConfig.ip) {
await gthis.setStateAsync(`${element}.info.IPAdress`, ConfigDevices[i].ip, true);
await gthis.setStateAsync(`${element}.info.com`, JSON.stringify(ConfigDevices[i]), true);
}
if (ConfigDevices[i].port !== oldConfig.port) {
await gthis.setStateAsync(`${element}.info.Port`, parseInt(ConfigDevices[i].port), true);
await gthis.setStateAsync(`${element}.info.com`, JSON.stringify(ConfigDevices[i]), true);
}
if (ConfigDevices[i].smart_name !== oldConfig.smart_name) {
await changeSmartName(element, ConfigDevices[i].smart_name);
await gthis.setStateAsync(`${element}.info.com`, JSON.stringify(ConfigDevices[i]), true);
}
}
if (i === ConfigDevices.length - 1 && isThere === false) {
await delDev(element.split('.')[2]);
gthis.log.debug(`object: ${ObjDevices[element]._id} deleted`);
}
}
}
async function changeSmartName(element, newSm) {
const Names = ['power', 'ct', 'active_bright', 'hue', 'sat'];
try {
const list = await gthis.getForeignObjectsAsync(`${element}.*`);
for (let i = 0; i < Names.length; i++) {
if (typeof list[`${element}.control.${Names[i]}`] !== 'undefined') {
await gthis.extendObjectAsync(`${element}.control.${Names[i]}`, {
common: {
smartName: {
de: newSm,
},
},
});
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
// ignore
}
gthis.log.debug(`changed ${Names.length} smartname to : ${newSm}`);
}
async function delDev(id) {
gthis.log.warn(`DEL: ${id}`);
try {
await gthis.deleteDevice(id);
} catch (err) {
gthis.log.warn(err.message);
}
}
}
createDevices() {
if (typeof ConfigDevices === 'undefined') {
return;
}
for (let i = 0; i < ConfigDevices.length; i++) {
const deviceSId = `${gthis.namespace}.${ConfigDevices[i].name}`;
const deviceName = ConfigDevices[i].name;
const deviceType = ConfigDevices[i].type;
gthis.log.debug(`CREATE DEVICE: ${deviceSId}`);
const deviceObj = {
type: 'device',
common: {
statusStates: {
onlineId: `${deviceSId}.info.connect`,
},
name: deviceType,
icon: `/icons/${deviceType}.png`,
},
native: {
sid: deviceName,
type: deviceType,
},
};
gthis.extendObject(deviceName, deviceObj);
const deviceInfoObj = {
type: 'channel',
common: {
name: 'info',
},
native: {},
};
gthis.setObjectNotExists(`${deviceName}.info`, deviceInfoObj);
const deviceControlObj = {
type: 'channel',
common: {
name: 'control',
},
native: {},
};
gthis.setObjectNotExists(`${deviceName}.control`, deviceControlObj);
const devicesScenesObj = {
type: 'channel',
common: {
name: 'scenen',
},
native: {},
};
gthis.extendObject(`${deviceName}.scenen`, devicesScenesObj);
gthis._createscenen(deviceSId);
gthis.setObjectNotExists(
`${deviceSId}.info.com`,
{
common: {
name: 'Command',
role: 'state',
write: false,
read: true,
type: 'string',
},
type: 'state',
native: {},
},
() => gthis.setStateChanged(`${deviceSId}.info.com`, JSON.stringify(ConfigDevices[i]), true),
);
gthis.setObjectNotExists(`${deviceSId}.info.connect`, {
common: {
name: 'Connect',
role: 'indicator.connected',
write: false,
read: true,
type: 'boolean',
},
type: 'state',
native: {},
});
gthis.setObjectNotExists(
`${deviceSId}.info.IPAdress`,
{
common: {
name: 'IP',
role: 'state',
write: false,
read: true,
type: 'string',
},
type: 'state',
native: {},
},
() => gthis.setStateChanged(`${deviceSId}.info.IPAdress`, ConfigDevices[i].ip, true),
);
gthis.setObjectNotExists(
`${deviceSId}.info.Port`,
{
common: {
name: 'Port',
role: 'state',
write: false,
read: true,
type: 'number',
},
type: 'state',
native: {},
},
() => gthis.setStateChanged(`${deviceSId}.info.Port`, parseInt(ConfigDevices[i].port), true),
);
if (i === ConfigDevices.length - 1) {
gthis.listener();
}
}
}
checkOnline() {
if (!Yeelights) {
return;
}
const lights = Yeelights.yeelights;
if (lights.length !== 0) {
lights.forEach(element => {
const device = ConfigDevices.find(device => device.id === element.id);
if (device) {
const sid = device.name;
if (element.status !== 3) {
//turn off
this.setState(`${sid}.info.connect`, false, true);
this.log.debug(`YEELIGHT OFFLINE: ${element.id}`);
} else {
//turn on
this.setState(`${sid}.info.connect`, true, true);
}
}
});
}
}
listener() {
this.initYeelight();
ConfigDevices.forEach((element, index) => setTimeout(() => Yeelights.addInitLights(element), index * 300));
timeOutInterval = setInterval(() => {
this.checkOnline();
}, 60 * 1000);
Yeelights.on('found', light => {
if (initializedLights.find(l => l.id === light.id)) {
this.log.debug(
`YEELIGHT FOUND (but already initialized): ${light.hostname}:${light.port} id: ${light.getId()} model: ${light.model}`,
);
return;
}
initializedLights.push(light);
this.log.debug(
`YEELIGHT FOUND: ${light.hostname}:${light.port} id: ${light.getId()} model: ${light.model}`,
);
light
.getValues(
'power',
'bright',
'rgb',
'color_mode',
'ct',
'active_bright',
'active_mode',
'hue',
'sat',
'flowing',
'main_power',
'bg_power',
'bg_color_mode',
'bg_bright',
'bg_hue',
'bg_sat',
'bg_rgb',
'bg_ct',
)
.then(() => {
light['initinalid'] = 1;
})
.catch(err => {
this.log.error(`Exception at calling getValues() for light ${light.id}: ${err.toString()}`);
});
light.on('error', function (id, ex, err) {
gthis.log.debug(`ERROR YEELIGHT CONNECTION: ${id}: ${ex}: ${err}`);
});
light.on('notification', message => {
gthis.log.debug(`NOTIFY MESSAGE: from: ${light.getId()}, message: ${JSON.stringify(message)}`);
//gthis.log.debug(JSON.stringify(Yeelights))
if (message.method === 'props' && message.params) {
gthis.setStateDevice(light, message.params);
}
});
light.on('response', (id, result) => {
gthis.log.debug(`RESPONSE MESSAGE: from: ${light.getId()}, id: ${id}, result:[${result}]}`);
//gthis.log.debug(JSON.stringify(light))
if (result && result[0] !== 'ok') {
if (id === light.initinalid) {
gthis.log.debug(`INITINAL ID FOUND FOR: ${light.model}-${light.getId()}`);
gthis.initObj(light, result);
} else {
gthis.setResponse(light, result);
}
}
});
});
}
setResponse(aktYeelight, result) {
const device = ConfigDevices.find(device => device.id === aktYeelight.getId());
//result:[off,100,16711680,2,4000]};
if (device) {
let sid = device.name;
this.setState(`${sid}.info.connect`, true, true);
sid = `${sid}.control`;
this.log.debug(`DEVICE FOUND IN CONFIG: ${JSON.stringify(device)}`);
if (result) {
if (!(result[0] === '')) {
switch (result[0]) {
case 'on':
this.setState(`${sid}.power`, true, true);
break;
case 'off':
this.setState(`${sid}.power`, false, true);
break;
}
}
if (!(result[1] === '')) {
this.setState(`${sid}.active_bright`, parseInt(result[1]), true);
}
if (!(result[2] === '')) {
this.setState(`${sid}.rgb`, this.dec2hex(result[2]), true);
}
if (!(result[3] === '')) {
switch (+result[3]) {
case 1:
this.setState(`${sid}.color_mode`, true, true);
break;
case 2:
this.setState(`${sid}.color_mode`, false, true);
break;
}
}
if (!(result[4] === '')) {
this.setState(`${sid}.ct`, parseInt(result[4]), true);
}
} else {
this.log.warn('EMPTY RESPONSE');
}
} else {
this.log.warn(`NEW DEVICE FOUND, PLEASE ADD TO CONFIG: ${aktYeelight.model}, id: ${aktYeelight.getId()}`);
}
}
main() {
this.checkChanges(this.createDevices);
this.subscribeStates('*');
}
generateWarnMessageForUploadState(parameter, value, id, err) {
this.log.warn(`Could not set state (${parameter}) to value (${value}) for device: ${id}. Error: ${err}`);
}
async initObj(aktYeelight, result) {
//search light in Config
const device = ConfigDevices.find(device => device.id === aktYeelight.getId());
//result = ["off", "1", "4000", "", "0", "2", "1", "", "", "0", "off", "off", "", "40", "180", "100", "65535", "4000"];
if (device) {
let sid = device.name;
this.setState(`${sid}.info.connect`, true, true);
sid = `${sid}.control`;
this.log.debug(`DEVICE FOUND IN AND CONFIG: ${JSON.stringify(device)}`);
if (result) {
if (!(result[0] == '')) {
await this.addState(sid, 'set_scene', '', device);
switch (result[0]) {
case 'on':
await this.addState(sid, 'power', true, device);
break;
case 'off':
await this.addState(sid, 'power', false, device);
break;
}
}
if (!(result[5] == '')) {
await this.addState(sid, 'active_bright', Number(result[5]), device);
} else {
await this.addState(sid, 'active_bright', Number(result[1]), device);
}
if (!(result[4] == '')) {
await this.addState(sid, 'ct', Number(result[4]), device);
}
if (!(result[2] == '')) {
await this.addState(sid, 'rgb', result[2], device);
}
if (!(result[6] == '')) {
switch (+result[6]) {
case 0:
await this.addState(sid, 'moon_mode', false, device);
break;
case 1:
await this.addState(sid, 'moon_mode', true, device);
break;
}
}
if (!(result[3] == '')) {
switch (+result[3]) {
case 1:
await this.addState(sid, 'color_mode', true, device);
break;
case 2:
await this.addState(sid, 'color_mode', false, device);
break;
}
}
if (!(result[7] == '')) {
await this.addState(sid, 'hue', Number(result[7]), device);
}
if (!(result[8] == '')) {
await this.addState(sid, 'sat', Number(result[8]), device);
}
if (!(result[10] == '')) {
switch (result[10]) {
case 'on':
await this.addState(sid, 'main_power', true, device);
break;
case 'off':
await this.addState(sid, 'main_power', false, device);
break;
}
}
if (!(result[11] == '')) {
switch (result[11]) {
case 'on':
await this.addState(sid, 'bg_power', true, device);
break;
case 'off':
await this.addState(sid, 'bg_power', false, device);
break;
}
}
if (!(result[13] == '')) {
await this.addState(sid, 'bg_bright', result[13], device);
}
if (!(result[14] == '')) {
await this.addState(sid, 'bg_hue', result[14], device);
}
if (!(result[15] == '')) {
await this.addState(sid, 'bg_sat', result[15], device);
}
if (!(result[16] == '')) {
await this.addState(sid, 'bg_rgb', result[16], device);
}
if (!(result[17] == '')) {
await this.addState(sid, 'bg_ct', result[17], device);
}
} else {
this.log.warn('EMPTY INITINAL RESPONSE');
}
} else {
this.log.warn(`NEW DEVICE FOUND, PLEASE ADD TO CONFIG: ${aktYeelight.model}, id: ${aktYeelight.getId()}`);
}
}
async addState(id, state, val, device) {
let ct_min = 1700;
const ct_max = 6500;
let smartname = '';
if (typeof device.type !== 'undefined') {
if (device.type === 'ceiling1') {
ct_min = 2500;
}
// change ct for pedant
if (device.type === 'ceiling10' && state.substring(0, 2) !== 'bg_') {
ct_min = 2500;
}
}
if (typeof device.smart_name !== 'undefined') {
if (device.smart_name !== '') {
smartname = device.smart_name;
}
//this.log.warn(device.smart_name);
}
switch (state) {
case 'power':
case 'bg_power':
case 'main_power':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'switch',
write: true,
read: true,
type: 'boolean',
smartName: {
de: smartname,
smartType: 'LIGHT',
},
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, !!val, true);
break;
case 'set_scene':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'json',
write: true,
read: true,
type: 'string',
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, val, true);
break;
case 'color_mode':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'switch.mode.color',
write: true,
read: true,
type: 'boolean',
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, !!val, true);
break;
case 'moon_mode':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'switch.mode.moon',
write: true,
read: true,
type: 'boolean',
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, !!val, true);
break;
case 'ct':
case 'bg_ct':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'level.color.temperature',
write: true,
read: true,
type: 'number',
min: ct_min,
max: ct_max,
unit: 'K',
smartName: {
de: smartname,
smartType: 'LIGHT',
},
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, parseInt(val), true);
break;
case 'active_bright':
case 'bg_bright':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'level.dimmer',
write: true,
read: true,
type: 'number',
min: 0,
max: 100,
unit: '%',
smartName: {
de: smartname,
smartType: 'LIGHT',
byON: '-',
},
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, parseInt(val), true);
break;
case 'hue':
case 'bg_hue':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'level.color.hue',
write: true,
read: true,
type: 'number',
min: 0,
max: 360,
smartName: {
de: smartname,
smartType: 'LIGHT',
},
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, parseInt(val), true);
break;
case 'sat':
case 'bg_sat':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: 'level.color.saturation',
write: true,
read: true,
type: 'number',
min: 0,
max: 100,
smartName: {
de: smartname,
smartType: 'LIGHT',
},
},
native: {},
});
await this.setStateAsync(`${id}.${state}`, parseInt(val), true);
break;
case 'rgb':
case 'bg_rgb':
await this.setObjectNotExistsAsync(`${id}.${state}`, {
type: 'state',
common: {
name: state,
role: `level.${state}`,
write: true,
read: true,
type: 'string',
},
native: {},
});
val = this.dec2hex(val);
await this.setStateAsync(`${id}.${state}`, val, true);
break;
}
}
setStateDevice(aktYeelight, state) {
//search light in Config
const device = ConfigDevices.find(device => device.id === aktYeelight.getId());
if (device) {
let sid = device.name;
this.setState(`${sid}.info.connect`, true, true);
sid = `${sid}.control`;
this.log.debug(`DEVICE FOUND SET NOTIFY STATE: ${JSON.stringify(device)}`);
for (const key in state) {
switch (key) {
case 'power':
case 'main_power':
case 'bg_power':
switch (state[key]) {
case 'on':
this.setState(`${sid}.${key}`, true, true);
break;
case 'off':
this.setState(`${sid}.${key}`, false, true);
break;
}
break;
case 'bright':
case 'active_bright':
case 'ct':
case 'bg_bright':
case 'bg_ct':
case 'bg_hue':
case 'bg_sat':
case 'sat':
case 'hue':
if (key == 'bright') {
this.setState(`${sid}.active_bright`, +parseInt(state[key]), true);
}
this.setState(`${sid}.${key}`, parseInt(state[key]), true);
break;
case 'rgb':
case 'bg_rgb':
this.setState(`${sid}.${key}`, this.dec2hex(state[key]), true);
break;
case 'active_mode':
switch (+state[key]) {
case 0:
this.setState(`${sid}.moon_mode`, false, true);
break;
case 1:
this.setState(`${sid}.moon_mode`, true, true);
break;
}
break;
case 'color_mode':
//modeVal = state[key];
switch (+state[key]) {
case 1:
this.setState(`${sid}.color_mode`, true, true);
break;
case 2:
this.setState(`${sid}.color_mode`, false, true);
break;
}
break;
}
}
} else {
this.log.debug(
`NEW DEVICE FOUND IN NOTIFY, PLEASE ADD TO CONFIG: ${aktYeelight.model}, id: ${aktYeelight.getId()}`,
);
}
}
dec2hex(dec) {
const template = '#000000';
const hexstring = dec.toString(16);
return template.substring(0, 7 - hexstring.length) + hexstring;
}
}
if (require.main !== module) {
// Export the constructor in compact mode
/**
* @param [options]
*/
module.exports = options => new Yeelight2(options);
} else {
// otherwise start the instance directly
new Yeelight2();
}