iobroker.wifilight
Advanced tools
Comparing version 1.3.4 to 1.3.5
{ | ||
"common": { | ||
"name": "wifilight", | ||
"version": "1.3.4", | ||
"version": "1.3.5", | ||
"news": { | ||
"1.3.4": { | ||
"1.3.5": { | ||
"en": "Formatting of the code", | ||
@@ -8,0 +8,0 @@ "de": "Formatierung des Codes", |
@@ -13,4 +13,2 @@ const VARS = { | ||
exports.VARS = VARS; | ||
const programNames = { | ||
@@ -40,3 +38,3 @@ 97: 'none', | ||
exports.knownDeviceNames = { | ||
const knownDeviceNames = { | ||
'HF-LPB100-ZJ200': { type: 'LD382A' /*, port: 5577*/ }, | ||
@@ -50,3 +48,3 @@ 'HF-LPB100-ZJ002': { type: 'LD382' }, | ||
exports.LW12 = { | ||
const LW12 = { | ||
useCheckSum: false, | ||
@@ -66,4 +64,3 @@ port: 5577, | ||
programNames: programNames, | ||
decodeResponse: function (data) { | ||
decodeResponse: data => { | ||
if (data[0] !== 0x66 || data[1] !== 0x01) { | ||
@@ -89,6 +86,6 @@ return [11, null]; | ||
exports.LD382A = { | ||
const LD382A = { | ||
useCheckSum: true, | ||
port: 5577, | ||
//onlyConnectOnWrite: true, | ||
// onlyConnectOnWrite: true, | ||
@@ -133,3 +130,3 @@ delay: 10, | ||
exports.LD686 = { | ||
const LD686 = { | ||
useCheckSum: true, | ||
@@ -174,6 +171,6 @@ port: 5577, | ||
exports.LD382 = Object.assign({}, exports.LD382A, { // not tested | ||
const LD382 = Object.assign({}, LD382A, { // not tested | ||
}); | ||
exports.UFO = Object.assign({}, exports.LD382A, { // not tested | ||
const UFO = Object.assign({}, LD382A, { // not tested | ||
on: [0x71, 0x23], | ||
@@ -190,3 +187,3 @@ off: [0x71, 0x24], | ||
//LimitlessLED | ||
exports.MiLight = { | ||
const MiLight = { | ||
//http://www.limitlessled.com/dev/ | ||
@@ -324,3 +321,3 @@ port: 8899, | ||
exports.MiLightRGB = Object.assign ({}, exports.MiLight, { | ||
const MiLightRGB = Object.assign ({}, MiLight, { | ||
g: 2, | ||
@@ -340,4 +337,4 @@ dimSteps: 9, | ||
_bri: function(percent) { | ||
const bri = Math.floor(2 + (((percent||0) / 100) * this.dimSteps)); | ||
_bri: percent => { | ||
const bri = Math.floor(2 + (((percent || 0) / 100) * this.dimSteps)); | ||
const cmd = [].concat(this.on); | ||
@@ -350,3 +347,3 @@ for (let i = 0; i < bri; i++) { | ||
exports.MiLightW = Object.assign ({}, exports.MiLight, { | ||
const MiLightW = Object.assign({}, MiLight, { | ||
g: 2, | ||
@@ -356,1 +353,14 @@ dimSteps: 11, | ||
}); | ||
module.exports = { | ||
VARS, | ||
MiLightW, | ||
knownDeviceNames, | ||
LW12, | ||
LD382A, | ||
LD686, | ||
LD382, | ||
UFO, | ||
MiLight, | ||
MiLightRGB, | ||
}; |
const dgram = require('node:dgram'); | ||
const os = require('node:os'); | ||
const Netmask = require('netmask').Netmask; | ||
const { Netmask } = require('netmask'); | ||
const BROADCAST_PORT = 48899; | ||
exports.scanForDevices = function (checkCb, cb) { | ||
const BC_ID = 'HF-A11ASSISTHREAD'; //V6 API | ||
function scanForDevices(checkCb, cb) { | ||
const BC_ID = 'HF-A11ASSISTHREAD'; // V6 API | ||
const msg = new Buffer(BC_ID); | ||
@@ -31,5 +31,8 @@ const broadcasts = []; | ||
} | ||
if (result.include(s)) { | ||
if (!result) { | ||
return; | ||
} | ||
if (result.includes(s)) { | ||
return; | ||
} | ||
result.push(s); | ||
@@ -46,3 +49,3 @@ }); | ||
for (let i=0; i<result.length; i++) { | ||
for (let i = 0; i < result.length; i++) { | ||
const ar = result[i].split(','); | ||
@@ -75,5 +78,5 @@ result[i] = { | ||
}, 2500); | ||
}; | ||
} | ||
exports.scanForMiLightDevices = function scanForMiLightDevices (checkCb, cb) { | ||
function scanForMiLightDevices (checkCb, cb) { | ||
const port = 48899; | ||
@@ -95,2 +98,5 @@ const ip = '255.255.255.255'; | ||
msg = msg.toString(); | ||
if (!result) { | ||
return; | ||
} | ||
if (result.includes(msg)) { | ||
@@ -124,8 +130,7 @@ return; | ||
}, 2000); | ||
} | ||
}; | ||
exports.scanForAllDevices = function scanForAllDevices(checkCb, cb) { | ||
exports.scanForDevices(checkCb, function (result) { | ||
exports.scanForMiLightDevices(checkCb, function (result2) { | ||
function scanForAllDevices(checkCb, cb) { | ||
scanForDevices(checkCb, result => { | ||
scanForMiLightDevices(checkCb, result2 => { | ||
if (cb) { | ||
@@ -136,2 +141,6 @@ cb(result.concat(result2)); | ||
}); | ||
} | ||
module.exports = { | ||
scanForAllDevices, | ||
}; |
1362
main.js
const net = require('node:net'); | ||
const discovery = require('./lib/discovery'); | ||
const {rgb2hsv, roundRGB, ct2rgb, hsv2rgb} = require('./lib/colors'); | ||
const { rgb2hsv, roundRGB, ct2rgb, hsv2rgb } = require('./lib/colors'); | ||
const soef = require('./lib/dontBeSoSoef'); | ||
@@ -55,10 +55,15 @@ | ||
function arrayToHexEx(ar, len) { | ||
const s = []; | ||
if (len === undefined) { | ||
len = ar.length; | ||
} | ||
for (let i = 0; i < len; i++) { | ||
s.push(ar[i].toString(16).padStart(2, '0')); | ||
} | ||
return s.join(' '); | ||
} | ||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
soef.extendAll(); | ||
const hex = soef.arrayToHex; | ||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
const adapter = soef.Adapter( | ||
@@ -69,3 +74,3 @@ main, | ||
onUnload, | ||
{name: 'wifilight'}, | ||
{ name: 'wifilight' }, | ||
); | ||
@@ -86,3 +91,3 @@ | ||
discovery.scanForAllDevices( | ||
function (entry) { | ||
entry => { | ||
const ret = !adapter.config.devices.some(e => e.ip === entry.ip); | ||
@@ -92,3 +97,3 @@ if (ret) { | ||
entry.type = dev ? dev.type : ''; | ||
entry.port = dev && dev.port ? dev.port : 5577; | ||
entry.port = dev?.port ? dev.port : 5577; | ||
entry.pollIntervall = 30; | ||
@@ -98,3 +103,3 @@ } | ||
}, | ||
function (result) { | ||
result => { | ||
if (obj.callback) { | ||
@@ -182,3 +187,2 @@ adapter.sendTo(obj.from, obj.command, JSON.stringify(result), obj.callback); | ||
function onStateChange(id, state) { | ||
@@ -206,785 +210,783 @@ const ar = id.split('.'); | ||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
const WifiLight = function (config, zone, cb) { | ||
if (!(this instanceof WifiLight)) { | ||
return new WifiLight(config, zone, cb); | ||
} | ||
if (!config) { | ||
return this; | ||
} | ||
this.config = config; | ||
this.isOnline = false; | ||
this.cmds = cmds[config.type]; | ||
this.prgTimer = soef.Timer(); | ||
}; | ||
WifiLight.prototype.run = function (cb) { | ||
if (!this.cmds) { | ||
adapter.log.error(`wrong device type. ${this.config.type} not yet supported!`); | ||
if (cb) { | ||
cb(-1); | ||
class WifiLight { | ||
constructor(config) { | ||
if (!config) { | ||
throw new Error('no configuration'); | ||
} | ||
return null; | ||
this.config = config; | ||
this.isOnline = false; | ||
this.cmds = cmds[config.type]; | ||
this.prgTimer = soef.Timer(); | ||
} | ||
if (this.cmds.vmax === undefined) { | ||
this.cmds.vmax = 255; | ||
} | ||
this.cmds.g = this.cmds.g || 1; | ||
this.createDevice(function (/* err */) { | ||
this.setOnline(false); | ||
if (this.cmds.onlyConnectOnWrite) { | ||
this.USE_SOCKET_ONCE = true; | ||
this.setOnline('on demand'); | ||
run(cb) { | ||
if (!this.cmds) { | ||
adapter.log.error(`wrong device type. ${this.config.type} not yet supported!`); | ||
if (cb) { | ||
cb(-1); | ||
} | ||
return null; | ||
} | ||
this.queue = []; | ||
this.dataBuffer = new Uint8Array(200); | ||
this.dataBuffer.pos = 0; | ||
this.states = {red: 0, green: 0, blue: 0}; | ||
this.start(cb); | ||
}.bind(this)); | ||
if (this.cmds.vmax === undefined) { | ||
this.cmds.vmax = 255; | ||
} | ||
this.cmds.g = this.cmds.g || 1; | ||
return this; | ||
}; | ||
this.createDevice((/* err */) => { | ||
this.setOnline(false); | ||
WifiLight.prototype.log = function (msg) { | ||
adapter.log.debug(`[${this.config.ip}] ${msg}`); | ||
}; | ||
if (this.cmds.onlyConnectOnWrite) { | ||
this.USE_SOCKET_ONCE = true; | ||
this.setOnline('on demand'); | ||
} | ||
this.queue = []; | ||
this.dataBuffer = new Uint8Array(200); | ||
this.dataBuffer.pos = 0; | ||
this.states = { red: 0, green: 0, blue: 0 }; | ||
this.start(cb); | ||
}); | ||
WifiLight.prototype.createDevice = function (cb) { | ||
this.dev = new devices.CDevice(0, ''); | ||
this.dev.setDevice(this.config.ip, { | ||
common: { | ||
name: this.config.name, | ||
role: 'device', | ||
}, | ||
native: { | ||
type: this.config.type, | ||
intervall: this.config.pollIntervall, | ||
}, | ||
}); | ||
if (this.zone !== undefined) { | ||
this.dev.setChannel(this.zone.toString(), ['All Zones', 'Zone 1', 'Zone 2', 'Zone 3', 'Zone 4'][this.zone]); | ||
return this; | ||
} | ||
wifi[this.dev.getFullId()] = this; | ||
log(msg) { | ||
adapter.log.debug(`[${this.config.ip}] ${msg}`); | ||
} | ||
for (const j in usedStateNames) { | ||
if (j === 'white' && this.cmds.rgbw === undefined) { | ||
continue; | ||
createDevice(cb) { | ||
this.dev = new devices.CDevice(0, ''); | ||
this.dev.setDevice(this.config.ip, { | ||
common: { | ||
name: this.config.name, | ||
role: 'device', | ||
}, | ||
native: { | ||
type: this.config.type, | ||
intervall: this.config.pollIntervall, | ||
}, | ||
}); | ||
if (this.zone !== undefined) { | ||
this.dev.setChannel(this.zone.toString(), ['All Zones', 'Zone 1', 'Zone 2', 'Zone 3', 'Zone 4'][this.zone]); | ||
} | ||
const st = Object.assign({}, usedStateNames[j]); | ||
if ((j === 'progNo' || j === 'disco') && this.cmds.programNames) { | ||
st.common.states = this.cmds.programNames; | ||
wifi[this.dev.getFullId()] = this; | ||
for (const j in usedStateNames) { | ||
if (j === 'white' && this.cmds.rgbw === undefined) { | ||
continue; | ||
} | ||
const st = Object.assign({}, usedStateNames[j]); | ||
if ((j === 'progNo' || j === 'disco') && this.cmds.programNames) { | ||
st.common.states = this.cmds.programNames; | ||
} | ||
// eslint-ignore-next-line | ||
if (st.g & this.cmds.g) { | ||
this.dev.createNew(st.n, st); | ||
} | ||
} | ||
if (st.g & this.cmds.g) { | ||
this.dev.createNew(st.n, st); | ||
} | ||
devices.update(cb); | ||
} | ||
devices.update(cb); | ||
}; | ||
WifiLight.prototype.onStateChange = function (channel, stateName, val) { | ||
let transitionTime = this.getval(channel, usedStateNames.transition.n, 0); | ||
this.clearQueue(); | ||
let co; | ||
switch (stateName) { | ||
case usedStateNames.transition.n: | ||
this.dev.setraw(usedStateNames.transition.n, val); | ||
break; | ||
case 'onTime': | ||
this.onTime(channel, val); | ||
break; | ||
case 'on': | ||
this.on_off(channel, !!(val >> 0)); | ||
break; | ||
case 'rgbw': | ||
case 'rgb': | ||
co = parseHexColors(val); | ||
this.color(channel, co); | ||
break; | ||
case 'r': | ||
case 'g': | ||
case 'b': | ||
case 'w': | ||
case 'sat': | ||
if (typeof val === 'string' && val[0] === '#') { | ||
onStateChange(channel, stateName, val) { | ||
let transitionTime = this.getval(channel, usedStateNames.transition.n, 0); | ||
this.clearQueue(); | ||
let co; | ||
switch (stateName) { | ||
case usedStateNames.transition.n: | ||
this.dev.setraw(usedStateNames.transition.n, val); | ||
break; | ||
case 'onTime': | ||
this.onTime(channel, val); | ||
break; | ||
case 'on': | ||
this.on_off(channel, !!(val >> 0)); | ||
break; | ||
case 'rgbw': | ||
case 'rgb': | ||
co = parseHexColors(val); | ||
} else { | ||
co = this.getRGBStates(channel); | ||
co[stateName] = val >> 0; | ||
this.color(channel, co); | ||
break; | ||
case 'r': | ||
case 'g': | ||
case 'b': | ||
case 'w': | ||
case 'sat': | ||
if (typeof val === 'string' && val[0] === '#') { | ||
co = parseHexColors(val); | ||
} else { | ||
co = this.getRGBStates(channel); | ||
co[stateName] = val >> 0; | ||
} | ||
this.color(channel, co); | ||
break; | ||
case usedStateNames.refresh.n: | ||
this.refresh(); | ||
this.dev.set(usedStateNames.refresh.n, false); | ||
this.dev.update(); | ||
break; | ||
case usedStateNames.bri.n: | ||
this.bri(channel, val >> 0, transitionTime); | ||
break; | ||
case usedStateNames.ct.n: | ||
this.ct(channel, val >> 0, transitionTime); | ||
break; | ||
case usedStateNames.progSpeed.n: { | ||
const progNo = this.get(channel, usedStateNames.progNo.n).val; | ||
this.addToQueue(channel, this.cmds.progNo, progNo, val); | ||
break; | ||
} | ||
this.color(channel, co); | ||
break; | ||
case usedStateNames.refresh.n: | ||
this.refresh(); | ||
this.dev.set(usedStateNames.refresh.n, false); | ||
this.dev.update(); | ||
break; | ||
case usedStateNames.bri.n: | ||
this.bri(channel, val >> 0, transitionTime); | ||
break; | ||
case usedStateNames.ct.n: | ||
this.ct(channel, val >> 0, transitionTime); | ||
break; | ||
case usedStateNames.progSpeed.n: { | ||
const progNo = this.get(channel, usedStateNames.progNo.n).val; | ||
this.addToQueue(channel, this.cmds.progNo, progNo, val); | ||
break; | ||
} | ||
case usedStateNames.progNo.n: { | ||
let speed; | ||
if (typeof val === 'string') { | ||
let ar = val.split(' '); | ||
if (!ar || ar.lengt < 2) { | ||
ar = val.split(','); | ||
case usedStateNames.progNo.n: { | ||
let speed; | ||
if (typeof val === 'string') { | ||
let ar = val.split(' '); | ||
if (!ar || ar.lengt < 2) { | ||
ar = val.split(','); | ||
} | ||
if (ar && ar.length >= 2) { | ||
speed = parseInt(ar[1]); | ||
val = parseInt(ar[0]); | ||
} | ||
} else { | ||
speed = this.getval(channel, usedStateNames.progSpeed.n, 30); | ||
} | ||
if (ar && ar.length >= 2) { | ||
speed = parseInt(ar[1]); | ||
val = parseInt(ar[0]); | ||
// if (this.cmds._setProgNo) _setProgNo(this, channel, val >> 0); else | ||
this.addToQueue(channel, this.cmds.progNo, val >> 0, speed); | ||
break; | ||
} | ||
case usedStateNames.progOn.n: | ||
this.addToQueue(channel, val ? this.cmds.progOn : this.cmds.progOff); | ||
break; | ||
case usedStateNames.command.n: { | ||
let v = val.replace(/(^on$|red|green|blue|transition|bri|off)/g, match => { | ||
return { | ||
'#': '#', | ||
off: 'off:1', | ||
on: 'on:1', | ||
red: 'r', | ||
green: 'g', | ||
blue: 'b', | ||
white: 'w', | ||
transition: 'x', | ||
bri: 'l', | ||
//, off: 'on:0' | ||
}[match]; | ||
}); | ||
v = v | ||
.replace(/\s|"|;$|,$/g, '') | ||
.replace(/=/g, ':') | ||
.replace(/;/g, ',') | ||
.replace(/true/g, 1) | ||
.replace(/((on|off),{1})/g, '$2:1,') | ||
.replace(/#((\d|[a-f]|[A-F]|[.])*)/g, 'h:"$1"') | ||
.replace(/(r|g|b|w|x|l|sat|off|on|ct|h|p)/g, '"$1"') | ||
.replace(/^\{?(.*?)}?$/, '{$1}'); | ||
let colors; | ||
try { | ||
colors = JSON.parse(v); | ||
} catch (e) { | ||
adapter.log.error(`on Command: ${e.message}: state.val="${val}"`); | ||
return; | ||
} | ||
} else { | ||
speed = this.getval(channel, usedStateNames.progSpeed.n, 30); | ||
if (colors.p) { | ||
setTimeout(this.runJsonProgram.bind(this), 10, channel, colors.p); | ||
return; | ||
} | ||
if (colors.h) { | ||
Object.assign(colors, parseHexColors(colors.h)); | ||
delete colors.h; | ||
} | ||
if (!colors || typeof colors !== 'object') { | ||
return; | ||
} | ||
if (colors.off !== undefined) { | ||
this.color(channel, { r: 0, g: 0, b: 0, w: colors.w !== undefined ? 0 : undefined }); | ||
this.states.red = 0; | ||
this.states.green = 0; | ||
this.states.blue = 0; | ||
if (this.states.white !== undefined) { | ||
this.states.white = 0; | ||
} | ||
} | ||
const o = fullExtendEx(this.getRGBStates(channel), colors); | ||
adapter.log.debug(JSON.stringify(o)); | ||
if (o.x !== undefined) { | ||
transitionTime = o.x >> 0; | ||
} | ||
if (o['on'] !== undefined) { | ||
this.on_off(channel, !!(o.on >> 0)); | ||
} | ||
if (colors.r !== undefined || colors.g !== undefined || colors.b !== undefined || colors.w !== undefined || colors.sat !== undefined) { | ||
this.fade(channel, o, transitionTime); | ||
} | ||
if (o['ct'] !== undefined) { | ||
this.ct(channel, o.ct >> 0, transitionTime); | ||
} | ||
if (o['l'] !== undefined) { | ||
this.bri(channel, o.l >> 0, transitionTime); | ||
} | ||
break; | ||
} | ||
// if (this.cmds._setProgNo) _setProgNo(this, channel, val >> 0); else | ||
this.addToQueue(channel, this.cmds.progNo, val >> 0, speed); | ||
break; | ||
default: | ||
return; | ||
} | ||
case usedStateNames.progOn.n: | ||
this.addToQueue(channel, val ? this.cmds.progOn : this.cmds.progOff); | ||
break; | ||
case usedStateNames.command.n: { | ||
let v = val.replace(/(^on$|red|green|blue|transition|bri|off)/g, match => { | ||
return { | ||
'#': '#', | ||
off: 'off:1', | ||
on: 'on:1', | ||
red: 'r', | ||
green: 'g', | ||
blue: 'b', | ||
white: 'w', | ||
transition: 'x', | ||
bri: 'l', | ||
//, off: 'on:0' | ||
}[match]; | ||
}); | ||
} | ||
v = v | ||
.replace(/\s|"|;$|,$/g, '') | ||
.replace(/=/g, ':') | ||
.replace(/;/g, ',') | ||
.replace(/true/g, 1) | ||
.replace(/((on|off),{1})/g, '$2:1,') | ||
.replace(/#((\d|[a-f]|[A-F]|[.])*)/g, 'h:"$1"') | ||
.replace(/(r|g|b|w|x|l|sat|off|on|ct|h|p)/g, '"$1"') | ||
.replace(/^\{?(.*?)}?$/, '{$1}'); | ||
let colors; | ||
try { | ||
colors = JSON.parse(v); | ||
} catch (e) { | ||
adapter.log.error(`on Command: ${e.message}: state.val="${val}"`); | ||
stopRunningProgram() { | ||
this.prgTimer.clear(); | ||
this.refreshPaused = 0; | ||
this.clearQueue(); | ||
} | ||
runJsonProgram(channel, cmds) { | ||
let i = -1; | ||
const self = this; | ||
const lastCo = {red: self.states.red, green: self.states.green, blue: self.states.blue}; | ||
this.prgTimer.clear(); | ||
self.clearQueue(); | ||
function doIt() { | ||
if (self.queue.length > 0) { | ||
setTimeout(doIt, self.queue.length * 2); | ||
return; | ||
} | ||
if (colors.p) { | ||
setTimeout(this.runJsonProgram.bind(this), 10, channel, colors.p); | ||
return; | ||
if (++i >= cmds.length) { | ||
i = 0; | ||
} | ||
if (colors.h) { | ||
Object.assign(colors, parseHexColors(colors.h)); | ||
delete colors.h; | ||
const cmd = cmds[i]; | ||
if (cmd.x === undefined) { | ||
cmd.x = 0; | ||
} | ||
if (!colors || typeof colors !== 'object') { | ||
const delay = Math.abs(cmd.x); | ||
if (cmd.r !== undefined) { | ||
Object.assign(self.states, lastCo); | ||
self.fade(channel, cmd, delay); | ||
lastCo.red = cmd.r; | ||
lastCo.green = cmd.g; | ||
lastCo.blue = cmd.b; | ||
} | ||
if (cmd.x < 0) { | ||
return; | ||
} | ||
if (colors.off !== undefined) { | ||
this.color(channel, {r: 0, g: 0, b: 0, w: colors.w !== undefined ? 0 : undefined}); | ||
this.states.red = 0; | ||
this.states.green = 0; | ||
this.states.blue = 0; | ||
if (this.states.white !== undefined) this.states.white = 0; | ||
} | ||
const o = fullExtendEx(this.getRGBStates(channel), colors); | ||
adapter.log.debug(JSON.stringify(o)); | ||
if (o.x !== undefined) { | ||
transitionTime = o.x >> 0; | ||
} | ||
if (o['on'] !== undefined) { | ||
this.on_off(channel, !!(o.on >> 0)); | ||
} | ||
if (colors.r !== undefined || colors.g !== undefined || colors.b !== undefined || colors.w !== undefined || colors.sat !== undefined) { | ||
this.fade(channel, o, transitionTime); | ||
} | ||
if (o['ct'] !== undefined) { | ||
this.ct(channel, o.ct >> 0, transitionTime); | ||
} | ||
if (o['l'] !== undefined) { | ||
this.bri(channel, o.l >> 0, transitionTime); | ||
} | ||
break; | ||
self.prgTimer.set(doIt, 10 + delay * 10); | ||
} | ||
default: | ||
return; | ||
if (cmds.length > 0) { | ||
this.refreshPaused = true; | ||
doIt(); | ||
} else { | ||
this.stopRunningProgram(); | ||
} | ||
} | ||
}; | ||
WifiLight.prototype.stopRunningProgram = function () { | ||
this.prgTimer.clear(); | ||
this.refreshPaused = 0; | ||
this.clearQueue(); | ||
}; | ||
reconnect(cb, timeout) { | ||
if (cb && typeof cb != 'function') { | ||
timeout = cb; | ||
cb = undefined; | ||
} | ||
if (this.client) { | ||
this.destroyClient(); | ||
setTimeout(() => this.start(cb), timeout === undefined ? 5000 : timeout); | ||
} | ||
} | ||
WifiLight.prototype.runJsonProgram = function (channel, cmds) { | ||
let i = -1; | ||
const self = this; | ||
const lastCo = {red: self.states.red, green: self.states.green, blue: self.states.blue}; | ||
this.prgTimer.clear(); | ||
self.clearQueue(); | ||
_write(data, cb) { | ||
if (this.USE_SOCKET_ONCE) { | ||
this.writeOnce(data, cb); | ||
} else { | ||
this.client.write(data, cb); | ||
} | ||
} | ||
function doIt() { | ||
if (self.queue.length > 0) { | ||
setTimeout(doIt, self.queue.length * 2); | ||
return; | ||
start(cb) { | ||
this.destroyClient(); | ||
if (debug) { | ||
this.ts = Date.now(); | ||
} | ||
if (++i >= cmds.length) { | ||
i = 0; | ||
this.client = new net.Socket(); | ||
this.client.on('data', data => this.onData(data)); | ||
this.client.on('close', hasError => { | ||
this.setOnline(false); | ||
const ts = debug ? `(${Math.round((Date.now() - this.ts) / 1000)} sec) ` : ''; | ||
this.log(`onClose ${ts}hasError=${hasError} client=${this.client}`); | ||
}); | ||
this.client.on('error', error => { | ||
const ts = debug ? `(${Math.round((Date.now() - this.ts) / 1000)} sec) ` : ''; | ||
this.log(`onError: ${ts}${error.code !== undefined ? error.code : ''} ${error.message}`); | ||
switch (error.errno) { //error.code | ||
case 'ECONNRESET': | ||
case 'ETIMEDOUT': | ||
case 'EPIPE': | ||
this.reconnect(5000); | ||
break; | ||
} | ||
this.setOnline(false); | ||
}); | ||
this.client.connect(this.config.port, this.config.ip, () => { | ||
this.log(`${this.config.ip} connected`); | ||
this.setOnline(true); | ||
this.runUpdateTimer(); | ||
adapter.log.debug('self.client.connect: connected'); | ||
if (typeof cb == 'function') { | ||
cb(); | ||
} | ||
}); | ||
} | ||
destroyClient() { | ||
if (this.updateTimer) { | ||
clearTimeout(this.updateTimer); | ||
this.updateTimer = null; | ||
} | ||
const cmd = cmds[i]; | ||
if (cmd.x === undefined) { | ||
cmd.x = 0; | ||
if (this.client) { | ||
this.client.destroy(); | ||
this.client = null; | ||
} | ||
const delay = Math.abs(cmd.x); | ||
if (cmd.r !== undefined) { | ||
Object.assign(self.states, lastCo); | ||
self.fade(channel, cmd, delay); | ||
lastCo.red = cmd.r; | ||
lastCo.green = cmd.g; | ||
lastCo.blue = cmd.b; | ||
} | ||
if (cmd.x < 0) { | ||
} | ||
writeOnce(data, cb) { | ||
if (this.client) { | ||
this.client.write(data, cb); | ||
return; | ||
} | ||
self.prgTimer.set(doIt, 10 + delay * 10); | ||
} | ||
this.client = new net.Socket(); | ||
if (cmds.length > 0) { | ||
this.refreshPaused = true; | ||
doIt(); | ||
} else this.stopRunningProgram(); | ||
}; | ||
this.client.on('data', data => { | ||
this.onData(data); | ||
this.client.end(); | ||
this.client = null; | ||
}); | ||
this.client.on('error', (/* error */) => this.destroyClient()); | ||
this.client.connect(this.config.port, this.config.ip, () => | ||
this.client.write(data, cb)); | ||
} | ||
WifiLight.prototype.reconnect = function (cb, timeout) { | ||
if (cb && typeof cb != 'function') { | ||
timeout = cb; | ||
cb = undefined; | ||
get(channel, state) { | ||
return this.dev.get(channel, state); | ||
} | ||
if (this.client) { | ||
this.destroyClient(); | ||
setTimeout(() => this.start(cb), timeout === undefined ? 5000 : timeout); | ||
} | ||
}; | ||
WifiLight.prototype._write = function (data, cb) { | ||
this.client.write(data, cb); | ||
}; | ||
WifiLight.prototype.start = function (cb) { | ||
if (this.USE_SOCKET_ONCE) { | ||
if (this.__proto__._write === WifiLight.prototype._write) { | ||
WifiLight.prototype._write = this.writeOnce; | ||
getval(channel, state, def) { | ||
const o = this.dev.get(channel, state); | ||
if (o && o.val !== undefined) { | ||
return o.val; | ||
} | ||
return cb && cb(0); | ||
return def; | ||
} | ||
const self = this; | ||
self.destroyClient(); | ||
if (debug) { | ||
this.ts = Date.now(); | ||
} | ||
self.client = new net.Socket(); | ||
self.client.on('data', data => self.onData(data)); | ||
self.client.on('close', function (hasError) { | ||
self.setOnline(false); | ||
const ts = debug ? `(${parseInt((Date.now() - self.ts) / 1000)} sec) ` : ''; | ||
self.log(`onClose ${ts}hasError=${hasError} client=${self.client}`); | ||
}); | ||
self.client.on('error', function (error) { | ||
const ts = debug ? `(${parseInt((Date.now() - self.ts) / 1000)} sec) ` : ''; | ||
self.log(`onError: ${ts}${error.code !== undefined ? error.code : ''} ${error.message}`); | ||
switch (error.errno) { //error.code | ||
case 'ECONNRESET': | ||
case 'ETIMEDOUT': | ||
case 'EPIPE': | ||
self.reconnect(5000); | ||
break; | ||
close() { | ||
this.clearQueue(); | ||
this.destroyClient(); | ||
if (this.writeTimeout) { | ||
clearTimeout(this.writeTimeout); | ||
this.writeTimeout = null; | ||
} | ||
self.setOnline(false); | ||
}); | ||
self.client.connect(self.config.port, self.config.ip, function () { | ||
self.log(`${self.config.ip} connected`); | ||
self.setOnline(true); | ||
self.runUpdateTimer(); | ||
adapter.log.debug('self.client.connect: connected'); | ||
if (typeof cb == 'function') { | ||
cb(); | ||
if (this.onTimerObject) { | ||
clearTimeout(this.onTimerObject); | ||
this.onTimerObject = null; | ||
} | ||
}); | ||
}; | ||
WifiLight.prototype.destroyClient = function () { | ||
if (this.updateTimer) { | ||
clearTimeout(this.updateTimer); | ||
this.updateTimer = null; | ||
this.prgTimer.clear(); | ||
} | ||
if (this.client) { | ||
this.client.destroy(); | ||
this.client = null; | ||
} | ||
}; | ||
WifiLight.prototype.writeOnce = function (data, cb) { | ||
if (this.client) { | ||
this.client.write(data, cb); | ||
return; | ||
} | ||
this.client = new net.Socket(); | ||
runUpdateTimer() { | ||
if (!this.cmds.decodeResponse) { | ||
return; | ||
} | ||
const self = this; | ||
this.client.on('data', function (data) { | ||
self.onData(data); | ||
self.client.end(); | ||
self.client = null; | ||
}); | ||
this.client.on('error', function (/* error */) { | ||
self.destroyClient(); | ||
}); | ||
this.refresh(); | ||
this.client.connect(this.config.port, this.config.ip, function () { | ||
self.client.write(data, cb); | ||
}); | ||
}; | ||
WifiLight.prototype.get = function (channel, state) { | ||
return this.dev.get(channel, state); | ||
}; | ||
WifiLight.prototype.getval = function (channel, state, def) { | ||
const o = this.dev.get(channel, state); | ||
if (o && o.val !== undefined) return o.val; | ||
return def; | ||
}; | ||
WifiLight.prototype.close = function () { | ||
this.clearQueue(); | ||
this.destroyClient(); | ||
if (this.writeTimeout) { | ||
clearTimeout(this.writeTimeout); | ||
this.writeTimeout = null; | ||
if (this.config.pollIntervall > 0) { | ||
this.updateTimer = setTimeout(() => this.runUpdateTimer(), | ||
this.config.pollIntervall * 1000); | ||
} | ||
} | ||
if (this.onTimerObject) { | ||
clearTimeout(this.onTimerObject); | ||
this.onTimerObject = null; | ||
} | ||
this.prgTimer.clear(); | ||
}; | ||
WifiLight.prototype.runUpdateTimer = function () { | ||
if (!this.cmds.decodeResponse) { | ||
return; | ||
setOnline(val) { | ||
this.isOnline = val; | ||
if ((this.cmds.g & usedStateNames.online.g) === 0) { | ||
return; | ||
} | ||
this.dev.set(usedStateNames.online.n, val); | ||
devices.update(); | ||
} | ||
this.refresh(); | ||
if (this.config.pollIntervall > 0) { | ||
this.updateTimer = setTimeout(this.runUpdateTimer.bind(this), this.config.pollIntervall * 1000); | ||
} | ||
}; | ||
WifiLight.prototype.setOnline = function (val) { | ||
this.isOnline = val; | ||
if ((this.cmds.g & usedStateNames.online.g) === 0) { | ||
return; | ||
directRefresh(channel) { | ||
if (!this.cmds.statusRequest || this.refreshPaused) { | ||
return; | ||
} | ||
this.log('sending refresh...'); | ||
this.write(channel, this.cmds.statusRequest); | ||
} | ||
this.dev.set(usedStateNames.online.n, val); | ||
devices.update(); | ||
}; | ||
WifiLight.prototype.directRefresh = function (channel) { | ||
if (!this.cmds.statusRequest || this.refreshPaused) { | ||
return; | ||
refresh(channel, ctrl) { | ||
if (!this.cmds.statusRequest || this.refreshPaused) { | ||
return; | ||
} | ||
this.addToQueue(channel, this.cmds.statusRequest, { ctrl: ctrl === undefined ? true : ctrl }); | ||
} | ||
this.log('sending refresh...'); | ||
this.write(channel, this.cmds.statusRequest); | ||
}; | ||
WifiLight.prototype.refresh = function (channel, ctrl) { | ||
if (!this.cmds.statusRequest || this.refreshPaused) { | ||
return; | ||
} | ||
this.addToQueue(channel, this.cmds.statusRequest, {ctrl: ctrl === undefined ? true : ctrl}); | ||
}; | ||
WifiLight.prototype.write = function (channel, cmd, cb) { | ||
let buf; | ||
if (this.cmds.useCheckSum) { | ||
buf = Buffer.alloc(cmd.length + 1); | ||
let sum = 0; | ||
for (let i = 0; i < cmd.length; i++) { | ||
buf[i] = cmd[i]; | ||
sum += buf[i]; | ||
write(channel, cmd, cb) { | ||
let buf; | ||
if (this.cmds.useCheckSum) { | ||
buf = Buffer.alloc(cmd.length + 1); | ||
let sum = 0; | ||
for (let i = 0; i < cmd.length; i++) { | ||
buf[i] = cmd[i]; | ||
sum += buf[i]; | ||
} | ||
buf[buf.length - 1] = sum & 0xFF; | ||
} else { | ||
buf = Buffer.from(cmd); | ||
} | ||
buf[buf.length - 1] = sum & 0xFF; | ||
} else { | ||
buf = Buffer.from(cmd); | ||
//const s = buf.inspect(); | ||
//this.log('writing: ' + buf.toString('hex').match(/.{2}/g).join(' ')); | ||
this.log(`write: ${arrayToHexEx(buf)}`); | ||
if (!this.isOnline /*&& !this.USE_SOCKET_ONCE*/) { | ||
this.reconnect(() => this._write(buf, cb), 0); | ||
return; | ||
} | ||
this._write(buf, cb); | ||
} | ||
//const s = buf.inspect(); | ||
//this.log('writing: ' + buf.toString('hex').match(/.{2}/g).join(' ')); | ||
this.log(`write: ${hex(buf)}`); | ||
if (!this.isOnline /*&& !this.USE_SOCKET_ONCE*/) { | ||
this.reconnect(() => this._write(buf, cb), 0); | ||
return; | ||
} | ||
this._write(buf, cb); | ||
}; | ||
WifiLight.prototype.clearQueue = function () { | ||
this.queue.length = 0; | ||
}; | ||
WifiLight.prototype.addToQueue = function (...args) { | ||
let channel = ''; | ||
let idx = 0; | ||
let cmd = []; | ||
if (!(args[0] instanceof Array)) { | ||
channel = args[0]; | ||
idx = 1; | ||
clearQueue() { | ||
this.queue.length = 0; | ||
} | ||
if (!(args[idx] instanceof Array)) { | ||
return; | ||
} | ||
let j = idx + 1; | ||
if (args.length > j) { | ||
for (let i = 0; i < args[idx].length; i++) { | ||
cmd[i] = args[idx][i] < 0 && args[idx][i] !== cmds.VARS.separator && args[idx][i] !== cmds.VARS.sepNoDelay ? args[j++] : args[idx][i]; | ||
addToQueue(...args) { | ||
let channel = ''; | ||
let idx = 0; | ||
let cmd = []; | ||
if (!(args[0] instanceof Array)) { | ||
channel = args[0]; | ||
idx = 1; | ||
} | ||
} else { | ||
cmd = args[idx]; | ||
} | ||
let opt; | ||
if (args.length >= j && typeof args[j] == 'object') { | ||
opt = args[j]; | ||
} | ||
if (!(args[idx] instanceof Array)) { | ||
return; | ||
} | ||
let _cmd = []; | ||
const last = cmd.length - 1; | ||
cmd.forEach((c, i) => { | ||
let sep = 0; | ||
switch (c) { | ||
case cmds.VARS.separator: | ||
sep = 1; | ||
break; | ||
case cmds.VARS.sepNoDelay: | ||
sep = 2; | ||
break; | ||
default: | ||
_cmd.push(c); | ||
let j = idx + 1; | ||
if (args.length > j) { | ||
for (let i = 0; i < args[idx].length; i++) { | ||
cmd[i] = args[idx][i] < 0 && args[idx][i] !== cmds.VARS.separator && args[idx][i] !== cmds.VARS.sepNoDelay ? args[j++] : args[idx][i]; | ||
} | ||
} else { | ||
cmd = args[idx]; | ||
} | ||
if (sep || i === last) { | ||
this.queue.push({ | ||
cmd: _cmd, | ||
ctrl: !!opt?.ctrl, | ||
channel: channel, | ||
delay: sep & 2 ? 0 : opt && opt.delay !== undefined ? opt.delay : this.cmds.delay !== undefined ? this.cmds.delay : 10, | ||
ts: 0, | ||
inProcess: 0, | ||
}); | ||
_cmd = []; | ||
let opt; | ||
if (args.length >= j && typeof args[j] == 'object') { | ||
opt = args[j]; | ||
} | ||
}); | ||
if (this.queue.length && this.queue[0].inProcess === 1) { | ||
return; | ||
} | ||
let _cmd = []; | ||
const last = cmd.length - 1; | ||
cmd.forEach((c, i) => { | ||
let sep = 0; | ||
switch (c) { | ||
case cmds.VARS.separator: | ||
sep = 1; | ||
break; | ||
case cmds.VARS.sepNoDelay: | ||
sep = 2; | ||
break; | ||
default: | ||
_cmd.push(c); | ||
} | ||
if (sep || i === last) { | ||
this.queue.push({ | ||
cmd: _cmd, | ||
ctrl: !!opt?.ctrl, | ||
channel: channel, | ||
delay: sep & 2 ? 0 : opt && opt.delay !== undefined ? opt.delay : this.cmds.delay !== undefined ? this.cmds.delay : 10, | ||
ts: 0, | ||
inProcess: 0, | ||
}); | ||
_cmd = []; | ||
} | ||
}); | ||
this.exec(); | ||
}; | ||
WifiLight.prototype.exec = function () { | ||
let akt; | ||
while (true) { | ||
if (this.queue.length <= 0) { | ||
if (this.queue.length && this.queue[0].inProcess === 1) { | ||
return; | ||
} | ||
akt = this.queue[0]; | ||
if (!(akt.inProcess || (!akt.ctrl && akt.ts && akt.ts < new Date().getTime()))) { | ||
break; | ||
} | ||
if (this.queue.length <= 1 && !akt.cmd.eq(this.cmds.statusRequest)) { | ||
this.directRefresh(akt.channel); | ||
} | ||
this.queue.shift(); | ||
this.exec(); | ||
} | ||
this.write(akt.channel, akt.cmd, () => | ||
this.writeTimeout = setTimeout(() => this.exec(), akt.delay)); | ||
exec() { | ||
let akt; | ||
do { | ||
if (this.queue.length <= 0) { | ||
return; | ||
} | ||
akt = this.queue[0]; | ||
if (!(akt.inProcess || (!akt.ctrl && akt.ts && akt.ts < Date.now()))) { | ||
break; | ||
} | ||
if (this.queue.length <= 1 && !akt.cmd.eq(this.cmds.statusRequest)) { | ||
this.directRefresh(akt.channel); | ||
} | ||
this.queue.shift(); | ||
} while(this.queue.length); | ||
akt.inProcess = 1; | ||
}; | ||
this.write(akt.channel, akt.cmd, () => | ||
this.writeTimeout = setTimeout(() => this.exec(), akt.delay)); | ||
WifiLight.prototype.on_off = function (channel, state) { | ||
this.addToQueue(channel, state ? this.cmds.on : this.cmds.off); | ||
}; | ||
akt.inProcess = 1; | ||
} | ||
WifiLight.prototype.fade = function (channel, rgbw, transitionTime) { | ||
if (!transitionTime) { | ||
this.color(channel, rgbw); | ||
return; | ||
on_off(channel, state) { | ||
this.addToQueue(channel, state ? this.cmds.on : this.cmds.off); | ||
} | ||
const co = { | ||
r: this.states.red, | ||
g: this.states.green, | ||
b: this.states.blue, | ||
w: this.states.white, | ||
}; | ||
const dif = { | ||
r: rgbw.r - co.r, | ||
g: rgbw.g - co.g, | ||
b: rgbw.b - co.b, | ||
}; | ||
dif.w = rgbw.w !== undefined && co.w !== undefined ? rgbw.w - co.w : 0; | ||
fade(channel, rgbw, transitionTime) { | ||
if (!transitionTime) { | ||
this.color(channel, rgbw); | ||
return; | ||
} | ||
let maxSteps = Math.max(Math.abs(dif.r), Math.abs(dif.g), Math.abs(dif.b), Math.abs(dif.w), 1); | ||
const co = { | ||
r: this.states.red, | ||
g: this.states.green, | ||
b: this.states.blue, | ||
w: this.states.white, | ||
}; | ||
const dif = { | ||
r: rgbw.r - co.r, | ||
g: rgbw.g - co.g, | ||
b: rgbw.b - co.b, | ||
}; | ||
maxSteps = Math.min((transitionTime * 100) / this.cmds.delay, maxSteps); | ||
dif.w = rgbw.w !== undefined && co.w !== undefined ? rgbw.w - co.w : 0; | ||
dif.r /= maxSteps; | ||
dif.g /= maxSteps; | ||
dif.b /= maxSteps; | ||
dif.w /= maxSteps; | ||
let maxSteps = Math.max(Math.abs(dif.r), Math.abs(dif.g), Math.abs(dif.b), Math.abs(dif.w), 1); | ||
const steps = maxSteps; | ||
const delay = parseInt(transitionTime * 100 / maxSteps); | ||
maxSteps = Math.min((transitionTime * 100) / this.cmds.delay, maxSteps); | ||
for (let i = 0; i < steps; i++) { | ||
co.r += dif.r; | ||
co.g += dif.g; | ||
co.b += dif.b; | ||
if (co.w !== undefined) { | ||
co.w += dif.w; | ||
dif.r /= maxSteps; | ||
dif.g /= maxSteps; | ||
dif.b /= maxSteps; | ||
dif.w /= maxSteps; | ||
const steps = maxSteps; | ||
const delay = parseInt(transitionTime * 100 / maxSteps); | ||
for (let i = 0; i < steps; i++) { | ||
co.r += dif.r; | ||
co.g += dif.g; | ||
co.b += dif.b; | ||
if (co.w !== undefined) { | ||
co.w += dif.w; | ||
} | ||
this.color(channel, roundRGB(co, true), { delay }); | ||
} | ||
this.color(channel, roundRGB(co, true), {delay}); | ||
} | ||
}; | ||
WifiLight.prototype.color = function (channel, rgbw, opt) { | ||
rgbw.w === undefined ? | ||
this.addToQueue(channel, this.cmds.rgb, rgbw.r, rgbw.g, rgbw.b, opt) : | ||
this.addToQueue(channel, this.cmds.rgbw, rgbw.r, rgbw.g, rgbw.b, rgbw.w, opt); | ||
}; | ||
color(channel, rgbw, opt) { | ||
rgbw.w === undefined ? | ||
this.addToQueue(channel, this.cmds.rgb, rgbw.r, rgbw.g, rgbw.b, opt) : | ||
this.addToQueue(channel, this.cmds.rgbw, rgbw.r, rgbw.g, rgbw.b, rgbw.w, opt); | ||
} | ||
WifiLight.prototype.ct = function (channel, temp, transitionTime) { | ||
let co = ct2rgb(temp); | ||
const hsv = rgb2hsv(co); | ||
// hsv.v = this.get(channel, 'bri').val; | ||
const v = this.get(channel, 'bri').val; | ||
if (v) { | ||
hsv.v = v; | ||
ct(channel, temp, transitionTime) { | ||
let co = ct2rgb(temp); | ||
const hsv = rgb2hsv(co); | ||
// hsv.v = this.get(channel, 'bri').val; | ||
const v = this.get(channel, 'bri').val; | ||
if (v) { | ||
hsv.v = v; | ||
} | ||
co = hsv2rgb(hsv); | ||
this.fade(channel, co, transitionTime); | ||
} | ||
co = hsv2rgb(hsv); | ||
this.fade(channel, co, transitionTime); | ||
}; | ||
WifiLight.prototype.temperature = WifiLight.prototype.ct; | ||
WifiLight.prototype.getRGBStates = function (/* channel */) { | ||
return { | ||
r: this.states.red, | ||
g: this.states.green, | ||
b: this.states.blue, | ||
w: this.states.white, | ||
}; | ||
}; | ||
temperature(channel, temp, transitionTime) { | ||
return this.ct(channel, temp, transitionTime); | ||
} | ||
WifiLight.prototype.bri = function (channel, bri, transitionTime) { | ||
let co = this.getRGBStates(channel); | ||
const hsv = rgb2hsv(co); | ||
hsv.v = Math.max(Math.min(bri, 100), 0); | ||
co = hsv2rgb(hsv); | ||
this.fade(channel, co, transitionTime); | ||
}; | ||
getRGBStates(/* channel */) { | ||
return { | ||
r: this.states.red, | ||
g: this.states.green, | ||
b: this.states.blue, | ||
w: this.states.white, | ||
}; | ||
} | ||
WifiLight.prototype.onTime = function (channel, val) { | ||
if (this.onTimerObject) { | ||
clearTimeout(this.onTimerObject); | ||
this.onTimerObject = null; | ||
bri(channel, bri, transitionTime) { | ||
let co = this.getRGBStates(channel); | ||
const hsv = rgb2hsv(co); | ||
hsv.v = Math.max(Math.min(bri, 100), 0); | ||
co = hsv2rgb(hsv); | ||
this.fade(channel, co, transitionTime); | ||
} | ||
let timeout = val >> 0; | ||
let cmd = '#00000000;x10'; | ||
if (typeof val == 'string') { | ||
const ar = val.split(';'); | ||
timeout = parseInt(ar.shift()); | ||
cmd = ar.join(';'); | ||
} | ||
if (timeout && timeout > 0) { | ||
this.onTimerObject = setTimeout(this.onStateChange.bind(this), timeout * 100, channel, 'command', cmd); | ||
} | ||
}; | ||
WifiLight.prototype.onData = function (data) { | ||
if (adapter.common.loglevel === 'debug') { | ||
adapter.log.debug(`raw data length: ${data.length}`); | ||
adapter.log.debug(`raw data: ${hex(data)}`); | ||
} | ||
const newPos = this.dataBuffer.pos + data.length; | ||
if (newPos > this.dataBuffer.length) { | ||
const b = new Uint8Array(newPos + 200); | ||
//const b = new Buffer(newPos + 200); | ||
for (let i = 0; i < this.dataBuffer.pos; i++) { | ||
b [i] = this.dataBuffer[i]; | ||
onTime(channel, val) { | ||
if (this.onTimerObject) { | ||
clearTimeout(this.onTimerObject); | ||
this.onTimerObject = null; | ||
} | ||
b.pos = this.dataBuffer.pos; | ||
this.dataBuffer = b; | ||
let timeout = val >> 0; | ||
let cmd = '#00000000;x10'; | ||
if (typeof val == 'string') { | ||
const ar = val.split(';'); | ||
timeout = parseInt(ar.shift()); | ||
cmd = ar.join(';'); | ||
} | ||
if (timeout && timeout > 0) { | ||
this.onTimerObject = setTimeout(this.onStateChange.bind(this), timeout * 100, channel, 'command', cmd); | ||
} | ||
} | ||
this.dataBuffer.set(data, this.dataBuffer.pos); | ||
this.dataBuffer.pos += data.length; | ||
while (this.dataBuffer.pos >= this.cmds.responseLen || this.dataBuffer.pos >= this.cmds.responseLen2) { | ||
const [lengthRead, states] = this.cmds.decodeResponse(this.dataBuffer); | ||
this.log(`onData: raw: ${hex(this.dataBuffer, lengthRead)}`); | ||
this.dataBuffer.copyWithin(0, lengthRead, this.dataBuffer.pos); | ||
this.dataBuffer.pos -= lengthRead; | ||
if (!states) { | ||
break; | ||
onData(data) { | ||
if (adapter.common.loglevel === 'debug') { | ||
adapter.log.debug(`raw data length: ${data.length}`); | ||
adapter.log.debug(`raw data: ${arrayToHexEx(data)}`); | ||
} | ||
this.states = states; | ||
this.log(`onData: ${JSON.stringify(this.states)}`); | ||
if (this.states) { | ||
//set(usedStateNames.status.n, this.states.power); | ||
this.dev.set(usedStateNames.on.n, this.states.on); | ||
this.dev.set(usedStateNames.red.n, this.states.red); | ||
this.dev.set(usedStateNames.green.n, this.states.green); | ||
this.dev.set(usedStateNames.blue.n, this.states.blue); | ||
this.dev.set(usedStateNames.progNo.n, this.states.progNo); | ||
this.dev.set(usedStateNames.progOn.n, this.states.progOn); | ||
this.dev.set(usedStateNames.progSpeed.n, this.states.progSpeed); | ||
this.dev.set(usedStateNames.white.n, this.states.white); | ||
let rgb = `#${this.states.red.toHex()}${this.states.green.toHex()}${this.states.blue.toHex()}`; | ||
if (this.states.white !== undefined) { | ||
rgb += this.states.white.toHex(); | ||
const newPos = this.dataBuffer.pos + data.length; | ||
if (newPos > this.dataBuffer.length) { | ||
const b = new Uint8Array(newPos + 200); | ||
//const b = new Buffer(newPos + 200); | ||
for (let i = 0; i < this.dataBuffer.pos; i++) { | ||
b [i] = this.dataBuffer[i]; | ||
} | ||
this.dev.set(usedStateNames.rgb.n, rgb); | ||
devices.update(); | ||
b.pos = this.dataBuffer.pos; | ||
this.dataBuffer = b; | ||
} | ||
this.dataBuffer.set(data, this.dataBuffer.pos); | ||
this.dataBuffer.pos += data.length; | ||
while (this.dataBuffer.pos >= this.cmds.responseLen || this.dataBuffer.pos >= this.cmds.responseLen2) { | ||
const [lengthRead, states] = this.cmds.decodeResponse(this.dataBuffer); | ||
this.log(`onData: raw: ${arrayToHexEx(this.dataBuffer, lengthRead)}`); | ||
this.dataBuffer.copyWithin(0, lengthRead, this.dataBuffer.pos); | ||
this.dataBuffer.pos -= lengthRead; | ||
if (!states) { | ||
break; | ||
} | ||
this.states = states; | ||
this.log(`onData: ${JSON.stringify(this.states)}`); | ||
if (this.states) { | ||
//set(usedStateNames.status.n, this.states.power); | ||
this.dev.set(usedStateNames.on.n, this.states.on); | ||
this.dev.set(usedStateNames.red.n, this.states.red); | ||
this.dev.set(usedStateNames.green.n, this.states.green); | ||
this.dev.set(usedStateNames.blue.n, this.states.blue); | ||
this.dev.set(usedStateNames.progNo.n, this.states.progNo); | ||
this.dev.set(usedStateNames.progOn.n, this.states.progOn); | ||
this.dev.set(usedStateNames.progSpeed.n, this.states.progSpeed); | ||
this.dev.set(usedStateNames.white.n, this.states.white); | ||
let rgb = `#${this.states.red.toHex()}${this.states.green.toHex()}${this.states.blue.toHex()}`; | ||
if (this.states.white !== undefined) { | ||
rgb += this.states.white.toHex(); | ||
} | ||
this.dev.set(usedStateNames.rgb.n, rgb); | ||
devices.update(); | ||
} | ||
} | ||
return this.states; | ||
} | ||
return this.states; | ||
}; | ||
} | ||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
const MiLight = function MiLight(config, zone /* , cb */) { | ||
WifiLight.call(this, config); | ||
if (!this.cmds) { | ||
return; | ||
class MiLight extends WifiLight { | ||
constructor(config, zone) { | ||
super(config); | ||
if (!this.cmds) { | ||
return; | ||
} | ||
this.zone = zone; | ||
this.cmds = cloneEx(this.cmds); | ||
this.cmds.setZone(this.zone); | ||
this.states = { on: 0, red: 0, green: 0, blue: 0, white: 0 }; | ||
this.writeTimer = soef.Timer(); | ||
this.isOnline = 'on demand'; | ||
} | ||
this.zone = zone; | ||
this.cmds = cloneEx(this.cmds); | ||
this.cmds.setZone(this.zone); | ||
this.states = {on: 0, red: 0, green: 0, blue: 0, white: 0}; | ||
this.writeTimer = soef.Timer(); | ||
this.isOnline = 'on demand'; | ||
}; | ||
MiLight.prototype = new WifiLight; | ||
MiLight.prototype.construcor = WifiLight; | ||
// writeUdp | ||
_write(data, cb) { | ||
if (!this.client) { | ||
const dgram = require('node:dgram'); | ||
this.client = dgram.createSocket('udp4'); | ||
this.client.on('listening', (error) => { | ||
if (error) { | ||
return cb && cb(error); | ||
} | ||
if (this.config.ip === '255.255.255.255') { | ||
this.client.setBroadcast(true); | ||
} | ||
}); | ||
this.client.on('message', (/* data, rinfo */) => {}); | ||
this.client.on('error', (/* error */) => {}); | ||
this.client.on('close', (/* error */) => { | ||
this.client = null; | ||
adapter.log.debug('UDP socked closed'); | ||
}); | ||
} | ||
MiLight.prototype._write = function writeUdp(data, cb) { | ||
if (!this.client) { | ||
const dgram = require('node:dgram'); | ||
this.client = dgram.createSocket('udp4'); | ||
this.client.on('listening', (error) => { | ||
if (error) { | ||
return cb && cb(error); | ||
} | ||
if (this.config.ip === '255.255.255.255') { | ||
this.client.setBroadcast(true); | ||
} | ||
this.client.send(data, 0, data.length, this.config.port, this.config.ip, (/* error, bytes */) => { | ||
this.writeTimer.set(() => this?.client?.close(), 2000); | ||
cb && cb(); | ||
}); | ||
this.client.on('message', (/* data, rinfo */) => { | ||
}); | ||
this.client.on('error', (/* error */) => { | ||
}); | ||
this.client.on('close', (/* error */) => { | ||
this.client = null; | ||
adapter.log.debug('udp socked closed'); | ||
}); | ||
} | ||
this.client.send(data, 0, data.length, this.config.port, this.config.ip, (/* error, bytes */) => { | ||
this.writeTimer.set(() => { | ||
if (this && this.client) { | ||
this.client.close(); | ||
} | ||
}, 2000); | ||
cb && cb(); | ||
}); | ||
}; | ||
bri(channel, bri /* , transitionTime */) { | ||
this.addToQueue(channel, this.cmds._bri(bri)); | ||
} | ||
MiLight.prototype.bri = function (channel, bri /* , transitionTime */) { | ||
this.addToQueue(channel, this.cmds._bri(bri)); | ||
}; | ||
color(channel, rgbw /* , opt */) { | ||
if (rgbw.w !== undefined) { | ||
this.addToQueue(channel, this.cmds._white((rgbw.w * 100 / 255) >> 0)); | ||
return; | ||
} | ||
const hsv = rgb2hsv(rgbw); | ||
if (hsv.h === 0 && hsv.v === 0) { | ||
this.on_off(channel, false); | ||
return; | ||
} | ||
const color = (256 + 176 - Math.floor(Number(hsv.h) / 360.0 * 255.0)) % 256; | ||
MiLight.prototype.color = function (channel, rgbw /* , opt */) { | ||
if (rgbw.w !== undefined) { | ||
this.addToQueue(channel, this.cmds._white((rgbw.w * 100 / 255) >> 0)); | ||
return; | ||
this.addToQueue(channel, this.cmds.on); | ||
this.addToQueue(channel, this.cmds._color(color)); | ||
this.addToQueue(channel, this.cmds._bri(hsv.v)); | ||
} | ||
const hsv = rgb2hsv(rgbw); | ||
if (hsv.h === 0 && hsv.v === 0) { | ||
this.on_off(channel, false); | ||
return; | ||
pair(channel) { | ||
for (let i = 0; i < 3; i++) { | ||
this.addToQueue(channel, this.pair, { delay: 1000 }); | ||
} | ||
} | ||
const color = (256 + 176 - Math.floor(Number(hsv.h) / 360.0 * 255.0)) % 256; | ||
this.addToQueue(channel, this.cmds.on); | ||
this.addToQueue(channel, this.cmds._color(color)); | ||
this.addToQueue(channel, this.cmds._bri(hsv.v)); | ||
}; | ||
MiLight.prototype.pair = function (channel) { | ||
for (let i = 0; i < 3; i++) { | ||
this.addToQueue(channel, this.pair, {delay: 1000}); | ||
unPair(channel) { | ||
for (let i = 0; i < 15; i++) { | ||
this.addToQueue(channel, this.unPair, { delay: 200 }); | ||
} | ||
} | ||
}; | ||
MiLight.prototype.unPair = function (channel) { | ||
for (let i = 0; i < 15; i++) { | ||
this.addToQueue(channel, this.unPair, {delay: 200}); | ||
} | ||
}; | ||
MiLight.prototype.onStateChange = function (channel, stateName, val) { | ||
switch (stateName) { | ||
case 'disco': { | ||
val = val >> 0; | ||
if (val === 0) { | ||
this.addToQueue(channel, this.cmds.off); | ||
return; | ||
onStateChange(channel, stateName, val) { | ||
switch (stateName) { | ||
case 'disco': { | ||
val = val >> 0; | ||
if (val === 0) { | ||
this.addToQueue(channel, this.cmds.off); | ||
return; | ||
} | ||
// const bri = this.getval(channel, 'bri'); | ||
let cmd = this.cmds._white(10).cc(this.cmds.on); | ||
while (val--) { | ||
cmd = cmd.cc(this.cmds.discoMode); | ||
} | ||
this.addToQueue(channel, cmd /*, {delay: 50}*/); | ||
break; | ||
} | ||
// const bri = this.getval(channel, 'bri'); | ||
let cmd = this.cmds._white(10).cc(this.cmds.on); | ||
while (val--) { | ||
cmd = cmd.cc(this.cmds.discoMode); | ||
} | ||
this.addToQueue(channel, cmd /*, {delay: 50}*/); | ||
break; | ||
default: | ||
WifiLight.prototype.onStateChange.call(this, channel, stateName, val); | ||
break; | ||
} | ||
default: | ||
WifiLight.prototype.onStateChange.call(this, channel, stateName, val); | ||
break; | ||
} | ||
}; | ||
} | ||
function checkDeletedDevices(cb) { | ||
adapter.getDevices(function (err, res) { | ||
adapter.getDevices((err, res) => { | ||
if (err || !res || res.length <= 0) { | ||
@@ -995,3 +997,3 @@ return cb && cb(); | ||
const toDelete = []; | ||
res.forEach(function (obj) { | ||
res.forEach(obj => { | ||
const ar = obj._id.split('.'); | ||
@@ -1004,2 +1006,3 @@ const ip = ar[2].replace(reIp, '.'); | ||
}); | ||
toDelete.forEachCallback((next, id) => dcs.del(id, next), cb); | ||
@@ -1024,3 +1027,3 @@ }); | ||
let err = `config.device.type "${d.type}" (${d.name}) is not a known device type. Skipping this device!`; | ||
if (!types.length) Object.keys(cmds).forEach(function (n) { | ||
if (!types.length) Object.keys(cmds).forEach(n => { | ||
if (typeof cmds[n] === 'object' && cmds[n].on) { | ||
@@ -1038,3 +1041,5 @@ types.push(n); | ||
} | ||
d.pollIntervall = parseInt(d.pollIntervall, 10) || 0; | ||
if (d.pollIntervall && d.pollIntervall < 5) { | ||
@@ -1045,3 +1050,3 @@ d.pollIntervall = 5; | ||
d.port = parseInt(d.port) || (c && c.port ? c.port : dev && dev.port ? dev.port : 5577); | ||
Object.keys(d).forEach(function (key) { | ||
Object.keys(d).forEach(key => { | ||
changed = changed || d[key] !== old[key]; | ||
@@ -1059,4 +1064,3 @@ }); | ||
} | ||
checkDeletedDevices((/* err */) => { | ||
}); | ||
checkDeletedDevices((/* err */) => {}); | ||
normalizeConfig(adapter.config); | ||
@@ -1075,5 +1079,3 @@ | ||
const wifiLight = new WifiLight(adapter.config.devices[i]); | ||
wifiLight.run(() => { | ||
}); | ||
wifiLight.bri('aaa', 100); | ||
wifiLight.run(() => {}); | ||
} | ||
@@ -1080,0 +1082,0 @@ } |
{ | ||
"name": "iobroker.wifilight", | ||
"version": "1.3.4", | ||
"version": "1.3.5", | ||
"description": "WiFi Light Adapter", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -54,3 +54,3 @@ ![Logo](admin/wifilight.png) | ||
--> | ||
### 1.3.4 (2024-09-03) | ||
### 1.3.5 (2024-09-04) | ||
* (bluefox) Formatting of the code | ||
@@ -57,0 +57,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
148569
3172