UNPKG

node-red-contrib-pixelit

Version:
452 lines (410 loc) 19.9 kB
//@ts-check "use strict"; const tools = require("./lib/tools"); const axios = require("axios").default; const errorImage = '[64512,0,0,0,0,0,0,64512,0,64512,0,0,0,0,64512,0,0,0,64512,0,0,64512,0,0,0,0,0,64512,64512,0,0,0,0,0,0,64512,64512,0,0,0,0,0,64512,0,0,64512,0,0,0,64512,0,0,0,0,64512,0,64512,0,0,0,0,0,0,64512]'; module.exports = (red) => { // Core function core(config) { red.nodes.createNode(this, config); const context = this.context(); const node = this; this.on("input", async (msg) => { let sleepModeActive = context.get("sleepModeActive") || false; let sendOverHTTPActive = true; let mqttMasterTopic = tools.getValue(red, config.masterTopic, msg) || ""; // Clean Master Topic if (mqttMasterTopic.substr(mqttMasterTopic.length - 1) === "/") { mqttMasterTopic = mqttMasterTopic.slice(0, -1); } // Check is IP Config?! if (!config.ip || config.ip === "") { sendOverHTTPActive = false; } // This topic sent by all providers to update the data in the context if (msg.topic === "screen_data_update") { if (msg.screenName && msg.duration) { tools.cleanDisplayMSG(msg); context.set(msg.screenName, msg); node.status({ fill: "blue", shape: "ring", text: `Screen [${msg.screenName}] stored`, }); } else { node.status({ fill: "red", shape: "dot", text: "Screen data cannot store!", }); } } // Check is SleepMode Aktiv?! (Ab hier ist dann schluß! :-) ) if (sleepModeActive == true && msg.sleepMode == undefined) { node.status({ fill: "yellow", shape: "ring", text: "Sleep Mode Active!", }); return; } // This topic sent by all providers to update the data in the context if (msg.topic === "matrix_control") { node.status({ fill: "grey", shape: "ring", text: "Matrix Control send", }); // SleepMode Steuerung if (msg.sleepMode != undefined && tools.booleanConvert(msg.sleepMode) == true) { clearTimeout(context.get("timeout")); sleepModeActive = true; context.set("sleepModeActive", sleepModeActive); node.status({ fill: "yellow", shape: "ring", text: "Sleep Mode Active!", }); sendToPixelItScreen(await createScreenJson(msg)); } else if (msg.sleepMode != undefined && tools.booleanConvert(msg.sleepMode) == false) { sleepModeActive = false; context.set("sleepModeActive", sleepModeActive); sendToPixelItScreen(await createScreenJson(msg)); getNextScreen(); } else if (sleepModeActive == false) { sendToPixelItScreen(await createScreenJson(msg)); } } // This topic sent by all providers to update the data in the context if (msg.topic === "matrix_config") { // Key whitelist const keyWhiteList = ["matrixtBrightness", "matrixType", "matrixTempCorrection", "ntpServer", "clockTimeZone", "scrollTextDefaultDelay", "bootScreenAktiv", "mqttAktiv", "mqttServer", "mqttMasterTopic", "mqttPort", "mqttUser", "mqttPassword"]; // Clean Obj for (const key in msg) { if (!keyWhiteList.includes(key)) { delete msg[key]; } } node.status({ fill: "grey", shape: "ring", text: "Matrix Config send", }); sendToPixelItConfig(createConfigJson(msg)); } // This topic is sent when the play is updated if (msg.topic === "playlist_update") { if (msg.payload[0].screenName) { context.set("screenPlayList", msg.payload); node.status({ fill: "green", shape: "ring", text: "New Playlist stored", }); context.set("nextScreenNumber", 0); await getNextScreen(); } else { node.status({ fill: "red", shape: "dot", text: "New Playlist cannot store!", }); } } if (msg.topic === "alert_screen") { if (context.get("timeout")) { clearTimeout(context.get("timeout")); } let status = "Displaying alert [No Named] now!"; if (msg.screenName != null) { status = `Displaying alert [${msg.screenName}] now!`; } tools.cleanDisplayMSG(msg); context.set("timeout", setTimeout(getNextScreen, msg.duration * 1000)); node.status({ fill: "yellow", shape: "ring", text: status, }); sendToPixelItScreen(await createScreenJson(msg)); } async function getNextScreen() { const screenPlayList = context.get("screenPlayList"); // Wurde keine ScreenPlaylist gespeichert? if (!screenPlayList) { return; } const screenPlayListCount = screenPlayList.length; // Sind keine Screens in der ScreenPlaylist? if (screenPlayListCount === 0) { return; } // currentScreenNumber laden (ist die Number die angeziegt werden soll!) let nextScreenNumber = context.get("nextScreenNumber") || 0; // Prüfen ob wir 'out of index' laufen if (nextScreenNumber >= screenPlayListCount) { nextScreenNumber = 0; } const nextScreenPlayListItem = screenPlayList[nextScreenNumber]; const nextScreen = context.get(nextScreenPlayListItem.screenName); // Wenn ein Screen nicht gefunden oder nicht gezeigt werden soll if (!nextScreen || (nextScreen && nextScreen.show != undefined && tools.booleanConvert(nextScreen.show) == false)) { // nextScreenNumber hochzählen für die next Round nextScreenNumber++; context.set("nextScreenNumber", nextScreenNumber); // Short Timeout für den nächsten Screen. Ohne Timeout geht nicht, // Könnte sehr hohe CPU usage veruhrsachen wenn kein screen gefunden würde! if (context.get("timeout")) { clearTimeout(context.get("timeout")); } context.set("timeout", setTimeout(getNextScreen, 200)); return; } // nextScreenNumber hochzählen für die next Round nextScreenNumber++; context.set("nextScreenNumber", nextScreenNumber); node.status({ fill: "green", shape: "ring", text: `Displaying [${nextScreenPlayListItem.screenName}] now`, }); if (context.get("timeout")) { clearTimeout(context.get("timeout")); } context.set("timeout", setTimeout(getNextScreen, nextScreen.duration * 1000)); try { const nextScreenJson = await createScreenJson(nextScreen); sendToPixelItScreen(nextScreenJson); } catch (error) { node.error(error); node.status({ fill: "red", shape: "dot", text: `Screen ${nextScreen.screenName} cannot send to Pixel It!`, }); } } async function createScreenJson(msg) { // Remove Object Ref. const jsonObj = JSON.parse(JSON.stringify(msg)); // SleepMode Overrides if (jsonObj.sleepMode != undefined) { jsonObj.sleepMode = tools.booleanConvert(jsonObj.sleepMode); } // Show Overrides if (jsonObj.show != undefined) { jsonObj.show = tools.booleanConvert(jsonObj.show); } // Brightness Overrides if (jsonObj.brightness) { jsonObj.brightness = Number(jsonObj.brightness); } // SwitchAnimation Overrides if (jsonObj.switchAnimation != undefined) { jsonObj.switchAnimation.aktiv = tools.booleanConvert(jsonObj.switchAnimation.aktiv); if (jsonObj.switchAnimation.data) { jsonObj.switchAnimation.data = JSON.parse(await getBitMap(jsonObj.switchAnimation.data)); jsonObj.switchAnimation.width = Number(jsonObj.switchAnimation.width); } if (jsonObj.switchAnimation.color) { jsonObj.switchAnimation.color.r = Number(jsonObj.switchAnimation.color.r); jsonObj.switchAnimation.color.g = Number(jsonObj.switchAnimation.color.g); jsonObj.switchAnimation.color.b = Number(jsonObj.switchAnimation.color.b); } } // Bitmap Overrides if (jsonObj.bitmap) { try { jsonObj.bitmap.data = JSON.parse(await getBitMap(jsonObj.bitmap.data)); } catch (error) { jsonObj.bitmap.data = JSON.parse(errorImage);; } if (jsonObj.bitmap.position) { jsonObj.bitmap.position.x = Number(jsonObj.bitmap.position.x); jsonObj.bitmap.position.y = Number(jsonObj.bitmap.position.y); } if (jsonObj.bitmap.size) { jsonObj.bitmap.size.width = Number(jsonObj.bitmap.size.width); jsonObj.bitmap.size.height = Number(jsonObj.bitmap.size.height); } } // BitmapAnimation Overrides if (jsonObj.bitmapAnimation) { if (!jsonObj.bitmapAnimation.limitLoops) { jsonObj.bitmapAnimation.limitLoops = 0; } jsonObj.bitmapAnimation.limitLoops = Number(jsonObj.bitmapAnimation.limitLoops); try { jsonObj.bitmapAnimation.data = JSON.parse(`[${await getBitMap(jsonObj.bitmapAnimation.data)}]`); } catch (error) { jsonObj.bitmapAnimation.data = JSON.parse(`[${errorImage}]`); } jsonObj.bitmapAnimation.animationDelay = Number(jsonObj.bitmapAnimation.animationDelay); } // Sound Overrides if (jsonObj.sound) { if (jsonObj.sound.volume) { jsonObj.sound.volume = Number(jsonObj.sound.volume); } if (jsonObj.sound.control) { if (jsonObj.sound.control == "play") { if (jsonObj.sound.folder) { jsonObj.sound.folder = Number(jsonObj.sound.folder); } if (jsonObj.sound.file) { jsonObj.sound.file = Number(jsonObj.sound.file); } } } } // Text Overrides if (jsonObj.text) { if (jsonObj.text.scrollText != undefined) { if (jsonObj.text.scrollText != "auto") { jsonObj.text.scrollText = tools.booleanConvert(jsonObj.text.scrollText); } else { jsonObj.text.scrollText = jsonObj.text.scrollText; } } if (jsonObj.text.scrollTextDelay) { jsonObj.text.scrollTextDelay = Number(jsonObj.text.scrollTextDelay); } if (jsonObj.text.centerText != undefined) { jsonObj.text.centerText = tools.booleanConvert(jsonObj.text.centerText); } if (jsonObj.text.position) { jsonObj.text.position.x = Number(jsonObj.text.position.x); jsonObj.text.position.y = Number(jsonObj.text.position.y); } if (jsonObj.text.color) { jsonObj.text.color.r = Number(jsonObj.text.color.r); jsonObj.text.color.g = Number(jsonObj.text.color.g); jsonObj.text.color.b = Number(jsonObj.text.color.b); } } // Clock Overrides if (jsonObj.clock) { jsonObj.clock.show = tools.booleanConvert(jsonObj.clock.show); jsonObj.clock.switchAktiv = tools.booleanConvert(jsonObj.clock.switchAktiv); jsonObj.clock.withSeconds = tools.booleanConvert(jsonObj.clock.withSeconds); jsonObj.clock.switchSec = Number(jsonObj.clock.switchSec); if (jsonObj.clock.color) { jsonObj.clock.color.r = Number(jsonObj.clock.color.r); jsonObj.clock.color.g = Number(jsonObj.clock.color.g); jsonObj.clock.color.b = Number(jsonObj.clock.color.b); } } // Bar Overrides if (jsonObj.bar) { if (jsonObj.bar.position) { jsonObj.bar.position.x = Number(jsonObj.bar.position.x); jsonObj.bar.position.y = Number(jsonObj.bar.position.y); jsonObj.bar.position.x2 = Number(jsonObj.bar.position.x2); jsonObj.bar.position.y2 = Number(jsonObj.bar.position.y2); } if (jsonObj.bar.color) { jsonObj.bar.color.r = Number(jsonObj.bar.color.r); jsonObj.bar.color.g = Number(jsonObj.bar.color.g); jsonObj.bar.color.b = Number(jsonObj.bar.color.b); } } // Set GPIO Overrides if (jsonObj.setGpio) { jsonObj.setGpio.gpio = Number(jsonObj.setGpio.gpio); jsonObj.setGpio.set = tools.booleanConvert(jsonObj.setGpio.set); if (jsonObj.setGpio.duration) { jsonObj.setGpio.duration = Number(jsonObj.setGpio.duration); } } return JSON.stringify(jsonObj); } function createConfigJson(msg) { msg.matrixtBrightness = Number(msg.matrixtBrightness); msg.matrixType = Number(msg.matrixType); msg.bootScreenAktiv = tools.booleanConvert(msg.bootScreenAktiv); msg.mqttAktiv = tools.booleanConvert(msg.mqttAktiv); return msg; } async function sendToPixelItConfig(myjson) { const result = { topic: mqttMasterTopic + "/setConfig", payload: myjson, }; node.send(result); if (sendOverHTTPActive) { try { await axios.post(`http://${config.ip}/api/config`, myjson, { headers: { "User-Agent": "Node_Red_Core", "Content-type": "application/json; charset=utf-8", }, timeout: 1000, }); } catch (error) { node.status({ fill: "yellow", shape: "dot", text: "Cannot reach the Pixel It via http API..", }); } } } async function sendToPixelItScreen(myjson) { const result = { topic: mqttMasterTopic + "/setScreen", payload: myjson, }; node.send(result); if (sendOverHTTPActive) { try { await axios.post(`http://${config.ip}/api/screen`, myjson, { headers: { "User-Agent": "Node_Red_Core", "Content-type": "application/json; charset=utf-8", }, timeout: 1000, }); } catch (error) { node.status({ fill: "yellow", shape: "dot", text: "Cannot reach the Pixel It via http API..", }); } } } async function getBitMap(input) { let webBmp = errorImage; let webResult; if (input) { if (String(input).includes(",")) { return input; } input = parseInt(input); const bmp = context.get(`bmpCache_${input}`); if (bmp) { return bmp; } try { const res = await axios.get(`https://pixelit.bastelbunker.de/API/GetBMPByID/${input}`, { headers: { "User-Agent": "Node_Red_Core", "Content-type": "application/json; charset=utf-8", }, timeout: 1000, }); webResult = res.data; } catch (error) { webResult = undefined; } if (webResult && webResult.id && webResult.id != 0) { webBmp = webResult.rgB565Array; context.set(`bmpCache_${input}`, webBmp); } } return webBmp; } }); } red.nodes.registerType("Core", core); };