node-red-dashboard-2-t86
Version:
Set of Node-RED nodes to controll home automation based on Unipi Patron and DALI.
263 lines (262 loc) • 9.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = main;
const editor_prase_helper_1 = require("../editor-prase-helper");
var InputEvent;
(function (InputEvent) {
InputEvent["Push"] = "in.push";
InputEvent["Release"] = "in.release";
InputEvent["Invalid"] = "in.invalid";
})(InputEvent || (InputEvent = {}));
var OutputEvent;
(function (OutputEvent) {
OutputEvent["ShortPress"] = "out.short";
OutputEvent["DoubleShortPress"] = "out.dblshort";
OutputEvent["LongPressStart"] = "out.long.start";
OutputEvent["ShortLongPressStart"] = "out.shortlong.start";
OutputEvent["LongPressEnd"] = "out.long.end";
OutputEvent["ShortLongPressEnd"] = "out.shortlong.end";
})(OutputEvent || (OutputEvent = {}));
var State;
(function (State) {
State["Ready"] = "stat.ready";
State["PushedOnce"] = "stat.pushedOnce";
State["LongInProgress"] = "stat.longInProgress";
State["WaitingAnotherPush"] = "stat.waitingAnotherPush";
State["PushedTwice"] = "stat.pushedTwice";
State["ShortLongInProgress"] = "stat.shortLongInProgress";
})(State || (State = {}));
function parseEditorConfig(config) {
return {
shortPressLimitMs: parseInt(config.shortpresslimitms),
nextPressWaitMs: parseInt(config.nextpresswaitms),
inputKeyPath: config.inputkeypath,
pushValue: (0, editor_prase_helper_1.typedStrToValue)(config.pushvalue, config.pushvalueType),
releaseValue: (0, editor_prase_helper_1.typedStrToValue)(config.releasevalue, config.releasevalueType),
enabled: {
short: config.shortenabled,
dblShort: config.dblshortenabled,
long: config.longenabled,
shortLong: config.shortlongenabled
},
warn: config.warn,
debug: config.debug
};
}
class MultiButton {
constructor(RED, node, config) {
this.state = State.Ready;
this.RED = RED;
this.node = node;
RED.nodes.createNode(node, config);
this.pConf = parseEditorConfig(config);
this.node.on('input', this.onInput.bind(this));
this.node.on('close', this.onClose.bind(this));
}
onInput(msg, send, done) {
this.latestSendFn = { send, done, msg };
const evt = this.eventWithMsg(msg);
switch (evt) {
case InputEvent.Push:
this.onPush();
break;
case InputEvent.Release:
this.onRelease();
break;
case InputEvent.Invalid: this.pConf.warn && this.node.warn(`Invalid event in message, ${msg}`);
}
if (done)
done();
}
onPush() {
this.debug(`onPush`);
switch (this.state) {
case State.Ready:
this.goPushedOnce();
return;
case State.WaitingAnotherPush:
this.goPushedTwice();
return;
}
this.invalidTransition('onPush');
}
onRelease() {
this.debug(`onRelease`);
switch (this.state) {
case State.PushedOnce:
this.goWaitAnotherPush();
return;
case State.PushedTwice:
this.finalizeDoubleShort();
return;
case State.LongInProgress:
this.finalizeLong();
return;
case State.ShortLongInProgress:
this.finalizeShortLong();
return;
}
this.invalidTransition('onRelease');
}
onShortPushTo() {
this.debug(`onShortPushTo`);
switch (this.state) {
case State.PushedOnce:
this.goLongStart();
return;
case State.PushedTwice:
this.goShortLongStart();
return;
}
this.invalidTransition('onShortPushTo');
}
onWaitAnotherPushTo() {
this.debug(`onWaitAnotherPushTo`);
switch (this.state) {
case State.WaitingAnotherPush:
this.finalizeShort();
return;
}
this.invalidTransition('onWaitAnotherPushTo');
}
onClose() {
if (this.shortPushTo)
clearTimeout(this.shortPushTo);
if (this.waitAnotherPushTo)
clearTimeout(this.waitAnotherPushTo);
this.shortPushTo = undefined;
this.waitAnotherPushTo = undefined;
}
goPushedOnce() {
this.debug(`goPushedOnce -> State.PushedOnce\n setting short push TO`);
this.storedSend();
this.resetTimeouts();
this.shortPushTo = setTimeout(this.onShortPushTo.bind(this), this.pConf.shortPressLimitMs);
this.state = State.PushedOnce;
}
goPushedTwice() {
this.debug(`goPushedTwice -> State.PushedTwice\n setting short push TO`);
this.resetTimeouts();
this.shortPushTo = setTimeout(this.onShortPushTo.bind(this), this.pConf.shortPressLimitMs);
this.state = State.PushedTwice;
}
goWaitAnotherPush() {
this.state = State.WaitingAnotherPush;
this.resetTimeouts();
// If there is no dbl press event enabled it's pointless to wait
if (!this.pConf.enabled.dblShort && !this.pConf.enabled.shortLong) {
this.debug(`goWaitAnotherPush -> State.WaitingAnotherPush\n not waiting`);
this.onWaitAnotherPushTo();
return;
}
// There is dbl press event enabled. Let's wait if second push is comming
this.debug(`goWaitAnotherPush -> State.WaitingAnotherPush\n setting wait TO`);
this.waitAnotherPushTo = setTimeout(this.onWaitAnotherPushTo.bind(this), this.pConf.nextPressWaitMs);
}
goLongStart() {
this.debug(`goLongStart -> State.LongInProgress`);
this.resetTimeouts();
this.longPushStart = new Date();
this.sendOutEvent(OutputEvent.LongPressStart);
this.storedSend();
this.state = State.LongInProgress;
}
goShortLongStart() {
this.debug(`goShortLongStart -> State.ShortLongInProgress`);
this.resetTimeouts();
this.longPushStart = new Date();
this.sendOutEvent(OutputEvent.ShortLongPressStart);
this.storedSend();
this.state = State.ShortLongInProgress;
}
finalizeShort() {
this.debug(`finalizeShort -> State.Ready`);
this.sendOutEvent(OutputEvent.ShortPress);
this.resetTimeouts();
this.state = State.Ready;
}
finalizeDoubleShort() {
this.debug(`finalizeDoubleShort -> State.Ready`);
this.sendOutEvent(OutputEvent.DoubleShortPress);
this.resetTimeouts();
this.state = State.Ready;
}
finalizeLong() {
this.debug(`finalizeLong -> State.Ready`);
this.sendOutEvent(OutputEvent.LongPressEnd, {
start: this.longPushStart?.getTime(),
duration: (new Date()).getTime() - (this.longPushStart?.getTime() || 0)
});
this.resetTimeouts();
this.state = State.Ready;
}
finalizeShortLong() {
this.debug(`finalizeShortLong -> State.Ready`);
this.sendOutEvent(OutputEvent.ShortLongPressEnd, {
start: this.longPushStart?.getTime(),
duration: (new Date()).getTime() - (this.longPushStart?.getTime() || 0)
});
this.resetTimeouts();
this.state = State.Ready;
}
invalidTransition(event) {
this.pConf.warn && this.node.warn(`Invalid transition ${this.state} -> ${event} -> X`);
}
sendOutEvent(outEvent, val) {
if (!this.pConf.enabled.short && outEvent === OutputEvent.ShortPress)
return;
if (!this.pConf.enabled.dblShort && outEvent === OutputEvent.DoubleShortPress)
return;
if (!this.pConf.enabled.long
&& (outEvent === OutputEvent.LongPressStart || outEvent === OutputEvent.LongPressEnd))
return;
if (!this.pConf.enabled.shortLong
&& (outEvent === OutputEvent.ShortLongPressStart || outEvent === OutputEvent.ShortLongPressEnd))
return;
this.debug(`Sending event ${outEvent} value: ${val}`);
if (this.storedSendFn) {
this.storedSendFn.msg.payload = { event: outEvent };
if (val !== undefined) {
this.storedSendFn.msg.payload.value = val;
}
this.storedSendFn.send(this.storedSendFn.msg);
if (this.storedSendFn.done)
this.storedSendFn.done();
this.storedSendFn = undefined;
}
}
resetTimeouts() {
this.debug(`resetTimeouts SPTO ${this.shortPushTo}; WAPTO ${this.waitAnotherPushTo}`);
clearTimeout(this.shortPushTo);
clearTimeout(this.waitAnotherPushTo);
this.shortPushTo = undefined;
this.waitAnotherPushTo = undefined;
this.longPushStart = undefined;
}
storedSend() {
this.storedSendFn = this.latestSendFn;
}
eventWithMsg(msg) {
const kp = this.pConf.inputKeyPath.split('.');
let sub = msg;
for (const part of kp) {
if (!sub)
return InputEvent.Invalid;
sub = sub[part];
}
if (sub === this.pConf.pushValue)
return InputEvent.Push;
if (sub === this.pConf.releaseValue)
return InputEvent.Release;
return InputEvent.Invalid;
}
debug(msg) {
this.pConf.debug && this.node.debug(msg);
}
}
// Register constructor function with Node-RED
function main(RED) {
RED.nodes.registerType('multibutton', function (config) {
new MultiButton(RED, this, config);
});
}