Node-RED Dashboard2 (Flowfuse) Alarm Management (Basic + Trigger Example)

🚨 Node-RED Alarm Flow

Ein flexibles Alarm- und Meldesystem für Node-RED mit MySQL-Anbindung, Dashboard-Anzeige und sicherer Eingabebehandlung.
Der Flow verwaltet automatisch aktive Alarme, zeigt sie im Dashboard an und bietet eine Glockenanzeige mit Zähler.

Alarm_example --- ## 🖼️ Vorschau

Alarm_Example


✨ Features

  • ✅ Sichere SQL-Inserts mit Filterung
  • 🧩 Subflow für zentrale Alarm-Erstellung (info, warnung, alarm)
  • 🗄️ Automatisches Löschen alter Einträge
  • 🔔 Glocke oben im Dashboard mit Badge (aktive Alarme)
  • 📋 Übersicht aller Alarme mit klickbaren Details (Akkordeon-Ansicht)
  • 🎨 Farbige Icons je nach Alarmtyp
  • ⚙️ Einfach integrierbar in bestehende Node-RED-Projekte

🧩 Flow-Übersicht

Flow 1: Alarm Basics (Logik)

Enthält die komplette Logik für Datenbank, Dashboard und Alarm-Verwaltung.

Bestandteile:

  • 🧱 create Table – Erstellt einmalig die Tabelle alarms.
  • 🗄️ MySQL get Alarme – Liest aktive Alarme aus und löscht alte Einträge.
  • 🛠️ Prepare & sanitize SQL – Bereinigt und validiert Eingaben, bevor sie in die Datenbank geschrieben werden.
  • 💾 MySQL Insert Alarm – Fügt neue Einträge in die Datenbank ein.
  • 🎨 AlarmListe (UI-Template) – Zeigt aktive Alarme im Dashboard an, inkl. Typ, Text, Zeitstempel und Detailansicht.
  • 🔔 Globale Alarm-Glocke mit Badge – Zeigt oben im Dashboard die Anzahl aktiver Alarme an.
  • set_inactive – Setzt Alarme auf inaktiv, wenn im Dashboard auf OK geklickt wird.

Flow 2: Alarm Trigger Example

Beispiel-Flow zum Testen des Systems.

Trigger:

  • 🔴 „Trigger Alarm“ → erstellt einen Eintrag vom Typ alarm
  • 🟠 „Trigger Warnung“ → erstellt einen Eintrag vom Typ warnung
  • 🔵 „Trigger Info“ → erstellt einen Eintrag vom Typ info

Diese Trigger senden Nachrichten an den Hauptflow „Alarm Basics“
und fügen automatisch Datensätze in die MySQL-Tabelle ein.


⚙️ Einrichtung

  1. MySQL-Datenbank anlegen (z. B. NodeRedAlarms)
  2. MySQL-Verbindung in Node-RED konfigurieren (Alarm_DB)
  3. Flow importieren
  4. Den „create Table“-Button einmal ausführen
  5. Dashboard öffnen → http://IP_ADRESS:1880/dashboard/
  6. Test-Trigger aktivieren – neue Alarme erscheinen automatisch (Glocke mit Badge)
  7. Bei Klick auf die Glocke öffnet Alarmseite mit der Liste

💬 Dashboard-Features

  • 🔔 Glocke oben mittig mit Badge-Zähler (z. B. „3“ für aktive Alarme)
  • 📋 Alarm-Liste mit:
    • Farbigen Icons (alarm = 🔴, warnung = 🟠, info = 🔵)
    • Zeitformat DD.MM.YY HH:mm
    • Klickbare Details (Akkordeon-Effekt)
    • OK-Button zum Deaktivieren einzelner Alarme

🧠 Hinweise

  • Alle SQL-Befehle werden validiert und bereinigt.
  • Ungültige Alarmtypen werden automatisch als alarm behandelt.
  • Alte Alarme werden nach konfigurierbarer Zeitspanne gelöscht.
  • Der Subflow kann beliebig oft wiederverwendet werden.

👤 Autor

Maik S. alias beabel/kunigunde

[{"id":"7c1ba471189902e3","type":"tab","label":"Alarm Basics","disabled":false,"info":"","env":[]},{"id":"e85cb47078505bcb","type":"group","z":"7c1ba471189902e3","name":"Kann nach dem erstellen der Tabelle gelöscht werden","style":{"fill":"#ffC000","label":true,"label-position":"n","color":"#ff0000"},"nodes":["8a556f75c9afe357","a7cf060bdf0402d6","9faf523dbdc76428","a576336383ea8d2c"],"x":174,"y":39,"w":592,"h":122},{"id":"855108af5bb8e73a","type":"group","z":"7c1ba471189902e3","name":"Einstellungen","style":{"fill":"#7fb7df","label":true,"label-position":"n","color":"#000000"},"nodes":["dc8d5f868b43c648","7c116009efdb0f79"],"x":174,"y":199,"w":292,"h":122},{"id":"dbcdf910da794ee0","type":"ui-template","z":"7c1ba471189902e3","group":"","page":"","ui":"4608d75616216429","name":"Globale Alarm-Glocke mit Badge","order":1,"width":"","height":"","format":"<template>\n  <v-btn\n    v-if=\"showBell\"\n    id=\"globalBell\"\n    icon\n    color=\"white\"\n    style=\"position: fixed; top: 8px; left: 50%; transform: translateX(-50%); z-index: 9999;\"\n    @click=\"send({ payload: pageName })\"\n  >\n    <v-icon size=\"28\">mdi-bell</v-icon>\n    <span v-if=\"count>0\" class=\"badge\">{{ count }}</span>\n  </v-btn>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      showBell: false,\n      count: 0,\n      pageName: \"default\" // Standardwert, falls msg.pagename nicht übergeben wird\n    }\n  },\n  watch: {\n    msg(n) {\n      if (!n) return;\n\n      // Sichtbarkeit & Badge-Zahl\n      const val = Number(n.payload);\n      if (val > 0) {\n        this.showBell = true;\n        this.count = val;\n      } else {\n        this.showBell = false;\n        this.count = 0;\n      }\n\n      // Seitenname setzen, falls übergeben\n      if (n.pagename) {\n        this.pageName = n.pagename;\n      }\n    }\n  }\n}\n</script>\n\n<style>\n.badge {\n  background:red;\n  color:white;\n  border-radius:50%;\n  padding:2px 6px;\n  font-size:12px;\n  margin-left:-10px;\n  margin-top:-10px;\n  position: absolute;\n}\n</style>\n","storeOutMessages":true,"passthru":false,"templateScope":"widget:ui","className":"","x":530,"y":560,"wires":[["32371874d53b1b72"]]},{"id":"32371874d53b1b72","type":"ui-control","z":"7c1ba471189902e3","name":"","ui":"4608d75616216429","events":"all","x":740,"y":560,"wires":[[]]},{"id":"59bc67a30147518f","type":"mysql","z":"7c1ba471189902e3","mydb":"585b6e322b26eb05","name":"MySQL get Alarme","x":790,"y":280,"wires":[["141681c221e8e4c9"]]},{"id":"ae7db77e003302d6","type":"function","z":"7c1ba471189902e3","name":"SQL aktive Alarme","func":"// Zeitlimit holen (Standard: 7 Tage)\nlet max_age_days = msg.max_age || 7; // Standard: 7 Tage\nlet deleteOlderThan = new Date(Date.now() - max_age_days * 24 * 60 * 60 * 1000);\n\n// Formatieren für SQL (z. B. '2025-10-22 08:30:00')\nlet sqlDate = deleteOlderThan.toISOString().slice(0, 19).replace('T', ' ');\n\nmsg.topic = `\n  DELETE FROM alarms WHERE time < '${sqlDate}';\n  SELECT * FROM alarms WHERE active = TRUE ORDER BY time DESC;\n`;\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":280,"wires":[["59bc67a30147518f"]]},{"id":"dc8d5f868b43c648","type":"change","z":"7c1ba471189902e3","g":"855108af5bb8e73a","name":"Speicherdauer+AlarmSeite","rules":[{"t":"set","p":"max_age","pt":"msg","to":"7","tot":"num"},{"t":"set","p":"pagename","pt":"flow","to":"Alarmseite","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":280,"wires":[["ae7db77e003302d6"]]},{"id":"f8d91cca98aa41f0","type":"change","z":"7c1ba471189902e3","name":"set count active_alarms","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload[1][0].active_count","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1150,"y":280,"wires":[["5e50e2df0f4bf644","cfed687940eaae00"]]},{"id":"7c116009efdb0f79","type":"comment","z":"7c1ba471189902e3","g":"855108af5bb8e73a","name":"Settings","info":"Hier werden Die Speicherdauer in der DB hinterlegt.\nEs wird in Tagen gezählt, alles was älter ist als hier eingestellt wird gelöscht.\n\nAußerdem ist hier der Name der Seite hinterlegt, auf welcher die Alarmliste angezeigt werden soll.","x":260,"y":240,"wires":[]},{"id":"cfed687940eaae00","type":"change","z":"7c1ba471189902e3","name":"","rules":[{"t":"set","p":"pagename","pt":"msg","to":"pagename","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":560,"wires":[["dbcdf910da794ee0"]]},{"id":"141681c221e8e4c9","type":"function","z":"7c1ba471189902e3","name":"function 3","func":"let results = msg.payload;\n\n// 1. Ergebnis = DELETE-Ergebnis (ignorieren)\n// 2. Ergebnis = aktive Alarme\nlet alarms = results[1];\n\nflow.set(\"alarms\", alarms);\nflow.set(\"alarm_count\", alarms.length);\n\nmsg.payload = alarms.length; // Zahl weitergeben\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":960,"y":280,"wires":[["f8d91cca98aa41f0"]]},{"id":"5e50e2df0f4bf644","type":"function","z":"7c1ba471189902e3","name":"flow_alarms->payload","func":"msg.payload = flow.get(\"alarms\") || [];\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":380,"wires":[["d5f2908e6ba6ec92"]]},{"id":"275905aecd6e40f1","type":"function","z":"7c1ba471189902e3","name":"set_inactive","func":"if (msg.payload && msg.payload.action === \"deactivate\") {\n    let id = msg.payload.id;\n\n    // SQL-Befehl, um Alarm inaktiv zu setzen\n    msg.topic = `UPDATE alarms SET active = FALSE WHERE id = ${id}`;\n    return msg;\n}\nreturn null;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":630,"y":380,"wires":[["802716a7508badcc"]]},{"id":"802716a7508badcc","type":"mysql","z":"7c1ba471189902e3","mydb":"585b6e322b26eb05","name":"MySQL set_inactive","x":820,"y":380,"wires":[["dc8d5f868b43c648"]]},{"id":"d5f2908e6ba6ec92","type":"ui-template","z":"7c1ba471189902e3","group":"4833815e103744cd","page":"","ui":"","name":"AlarmListe","order":2,"width":"0","height":"0","head":"","format":"<template>\n  <div style=\"max-width:700px;margin:auto;background:#333;padding:10px;border-radius:10px;color:#fff;\">\n\n    <div v-if=\"alarms.length === 0\" style=\"background:#2e7d32;padding:10px;border-radius:5px;\">\n      <span class=\"mdi mdi-thumb-up-outline\"></span>\n      Keine aktiven Alarme\n      <span class=\"mdi mdi-thumb-up-outline\"></span>\n    </div>\n\n    <table v-else style=\"width:100%;border-collapse:collapse;margin-top:10px;\">\n      <tbody>\n        <template v-for=\"alarm in alarms\" :key=\"alarm.id\">\n          <!-- Hauptzeile -->\n          <tr style=\"border-bottom:1px solid #555;cursor:pointer;\" @click=\"toggle(alarm.id)\">\n            <td style=\"padding:5px;\">\n              <i :class=\"getIcon(alarm.type)\" :style=\"{ color: getColor(alarm.type), fontSize: '20px' }\" class=\"me-2\"></i>\n            </td>\n            <td style=\"padding:5px;\">{{ alarm.text }}</td>\n            <td style=\"padding:5px;\">{{ formatTime(alarm.time) }}</td>\n            <td style=\"padding:5px;\">\n              <button @click.stop=\"deactivate(alarm.id)\" style=\"background:#2e7d32;border:none;color:white;padding:4px 8px;border-radius:4px;cursor:pointer;\">OK</button>\n            </td>\n          </tr>\n          <!-- Detailzeile -->\n          <tr v-if=\"alarm.expanded\" style=\"background:#444;\">\n            <td colspan=\"4\" style=\"padding:5px;\">\n              {{ alarm.details }}\n            </td>\n          </tr>\n        </template>\n      </tbody>\n    </table>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      alarms: []\n    }\n  },\n  mounted() {\n    if (this.msg && Array.isArray(this.msg.payload)) {\n      this.alarms = this.msg.payload.map(a => ({ ...a, expanded: false }));\n    }\n  },\n  watch: {\n    msg: {\n      deep: true,\n      immediate: true,\n      handler(n) {\n        if (!n) return;\n        if (Array.isArray(n.payload)) {\n          this.alarms = n.payload.map(a => ({ ...a, expanded: false }));\n        } else {\n          this.alarms = [];\n        }\n      }\n    }\n  },\nmethods: {\ndeactivate(id) {\nthis.send({ payload: { action: \"deactivate\", id } });\n},\ntoggle(id) {\nthis.alarms = this.alarms.map(a => {\nif (a.id === id) {\nreturn { ...a, expanded: !a.expanded }; // ausgewählten umschalten\n} else {\nreturn { ...a, expanded: false }; // alle anderen schließen\n}\n});\n},\ngetColor(type) {\nswitch (type) {\ncase \"alarm\": return \"red\";\ncase \"warnung\": return \"orange\";\ncase \"info\": return \"blue\";\ndefault: return \"grey\";\n}\n},\ngetIcon(type) {\nswitch (type) {\ncase \"alarm\": return \"mdi mdi-alert-octagon\";\ncase \"warnung\": return \"mdi mdi-alert-outline\";\ncase \"info\": return \"mdi mdi-information-outline\";\ndefault: return \"mdi mdi-bell\";\n}\n},\nformatTime(t) {\ntry {\nconst d = new Date(t);\nconst day = String(d.getDate()).padStart(2, \"0\");\nconst month = String(d.getMonth() + 1).padStart(2, \"0\");\nconst year = String(d.getFullYear()).slice(-2);\nconst hour = String(d.getHours()).padStart(2, \"0\");\nconst minute = String(d.getMinutes()).padStart(2, \"0\");\nreturn `${day}.${month}.${year} ${hour}:${minute}`;\n} catch {\nreturn t;\n}\n}\n}\n}\n</script>\n","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":470,"y":380,"wires":[["275905aecd6e40f1"]]},{"id":"41e1bf0d1961bd2b","type":"function","z":"7c1ba471189902e3","name":"Prepare & sanitize SQL","func":"// Validate and sanitize inputs before building SQL\n// Allowed types\nconst allowedTypes = ['info','warnung','alarm'];\n\n// Helper: ensure value is string\nfunction toStr(v){ return (v===null||v===undefined)?'':String(v); }\n\n// get type, default to 'alarm' if invalid\nlet t = toStr(msg.type).toLowerCase().trim();\nif (!allowedTypes.includes(t)) { t = 'alarm'; }\n\n// sanitize text/details: remove control chars, limit length, escape single quotes\nfunction sanitize(s, maxLen){\n  s = toStr(s);\n  // remove control chars except newline/tab, and remove null\n  s = s.replace(/\\x00/g, '');\n  s = s.replace(/[\\x00-\\x1F\\x7F]/g, '');\n  // trim\n  s = s.trim();\n  // limit length\n  if (maxLen && s.length > maxLen) s = s.slice(0, maxLen);\n  // simple removal of SQL comment/terminator tokens that could be abused\n  s = s.replace(/;+/g, '');\n  s = s.replace(/--+/g, '');\n  s = s.replace(/\\/\\*+/g, '');\n  s = s.replace(/\\*+\\//g, '');\n  // escape single quotes for SQL (doubling single quotes)\n  s = s.replace(/'/g, \"''\");\n  return s;\n}\n\nconst text = sanitize(msg.text || msg.payload || '', 1000);\nconst details = sanitize(msg.details || '', 4000);\n\n// Build SQL topic (INSERT). We escape single quotes by doubling above.\nmsg.topic = `INSERT INTO alarms (type, text, details) VALUES ('${t}','${text}','${details}');`;\n// Attach some meta for debugging\nmsg._safe = { type: t, text_len: text.length, details_len: details.length };\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":290,"y":440,"wires":[["dd0c16b766429c84"]]},{"id":"dd0c16b766429c84","type":"mysql","z":"7c1ba471189902e3","mydb":"585b6e322b26eb05","name":"MySQL Insert Alarm","x":520,"y":440,"wires":[["dc8d5f868b43c648"]]},{"id":"39bf0f0fde62af9b","type":"link in","z":"7c1ba471189902e3","name":"set_DB_Entry","links":["2fd6d32ffd4ac30b"],"x":145,"y":440,"wires":[["41e1bf0d1961bd2b"]]},{"id":"8a556f75c9afe357","type":"function","z":"7c1ba471189902e3","g":"e85cb47078505bcb","name":"create Table","func":"// SQL-Statement zum Erstellen der Tabelle (nur wenn sie noch nicht existiert)\nmsg.topic = `\nCREATE TABLE IF NOT EXISTS alarms (\n  id INT AUTO_INCREMENT PRIMARY KEY,\n  type ENUM('alarm','warnung','info') NOT NULL DEFAULT 'alarm',\n  text VARCHAR(255) NOT NULL,\n  details TEXT,\n  time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  active TINYINT(1) NOT NULL DEFAULT 1\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n`;\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":120,"wires":[["a7cf060bdf0402d6"]]},{"id":"a7cf060bdf0402d6","type":"mysql","z":"7c1ba471189902e3","g":"e85cb47078505bcb","mydb":"585b6e322b26eb05","name":"MySQL create Table","x":640,"y":120,"wires":[[]]},{"id":"9faf523dbdc76428","type":"inject","z":"7c1ba471189902e3","g":"e85cb47078505bcb","name":"Trigger","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":270,"y":120,"wires":[["8a556f75c9afe357"]]},{"id":"a576336383ea8d2c","type":"comment","z":"7c1ba471189902e3","g":"e85cb47078505bcb","name":"erstelle Tabelle","info":"Dies ist nur einmalig nötig.\nKann danach komplett gelöscht werden.","x":280,"y":80,"wires":[],"icon":"node-red/alert.svg"},{"id":"7fa69801ddbdc8bb","type":"inject","z":"7c1ba471189902e3","name":"10sec","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"10","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":80,"y":280,"wires":[["dc8d5f868b43c648"]]},{"id":"440b855f518962bc","type":"tab","label":"Alarm Trigger Example","disabled":false,"info":"","env":[]},{"id":"42a86d417858844b","type":"inject","z":"440b855f518962bc","name":"Trigger Alarm","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":60,"wires":[["a4f70122e68da214"]]},{"id":"bb4b4ab94146bb89","type":"inject","z":"440b855f518962bc","name":"Trigger Warnung","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":120,"wires":[["42b6eb9a3173088e"]]},{"id":"c15b0fc355446a84","type":"inject","z":"440b855f518962bc","name":"Trigger Info","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":150,"y":180,"wires":[["25b466f77823efb1"]]},{"id":"a4f70122e68da214","type":"change","z":"440b855f518962bc","name":"Trigger Alarm","rules":[{"t":"set","p":"type","pt":"msg","to":"alarm","tot":"str"},{"t":"set","p":"text","pt":"msg","to":"Alarm Text hier","tot":"str"},{"t":"set","p":"details","pt":"msg","to":"Detail Text hier rein","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":60,"wires":[["2fd6d32ffd4ac30b"]]},{"id":"42b6eb9a3173088e","type":"change","z":"440b855f518962bc","name":"Trigger Warnung","rules":[{"t":"set","p":"type","pt":"msg","to":"warnung","tot":"str"},{"t":"set","p":"text","pt":"msg","to":"Alarm Text hier","tot":"str"},{"t":"set","p":"details","pt":"msg","to":"Detail Text hier rein","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":120,"wires":[["2fd6d32ffd4ac30b"]]},{"id":"25b466f77823efb1","type":"change","z":"440b855f518962bc","name":"Trigger Info","rules":[{"t":"set","p":"type","pt":"msg","to":"info","tot":"str"},{"t":"set","p":"text","pt":"msg","to":"Alarm Text hier","tot":"str"},{"t":"set","p":"details","pt":"msg","to":"Detail Text hier rein","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":180,"wires":[["2fd6d32ffd4ac30b"]]},{"id":"2fd6d32ffd4ac30b","type":"link out","z":"440b855f518962bc","name":"Trigger_Alarm_Entry","mode":"link","links":["39bf0f0fde62af9b"],"x":615,"y":120,"wires":[]},{"id":"4608d75616216429","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"temporary","titleBarStyle":"fixed","showReconnectNotification":true,"notificationDisplayTime":1,"showDisconnectNotification":true,"allowInstall":true},{"id":"585b6e322b26eb05","type":"MySQLdatabase","name":"DB_Config","host":"127.0.0.1","port":"3306","db":"database","tz":"","charset":"UTF8"},{"id":"4833815e103744cd","type":"ui-group","name":"Alarmgruppe","page":"5bafd888f0ad9546","width":6,"height":1,"order":1,"showTitle":false,"className":"","visible":"false","disabled":"false","groupType":"default"},{"id":"5bafd888f0ad9546","type":"ui-page","name":"Alarmseite","ui":"4608d75616216429","path":"/alarmpage","icon":"home","layout":"grid","theme":"cb568b163406e608","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"cb568b163406e608","type":"ui-theme","name":"Theme Name","colors":{"surface":"#0094ce","primary":"#0094ce","bgPage":"#111111","groupBg":"#333333","groupOutline":"#cccccc"},"sizes":{"density":"default","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}},{"id":"7a4733f806061b5d","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.29.0","node-red-node-mysql":"2.0.0"}}]

Flow Info

Created 8 months, 2 weeks ago
Rating: 5 1

Owner

Actions

Rate:

Node Types

Core
  • change (x6)
  • comment (x2)
  • function (x6)
  • inject (x5)
  • link in (x1)
  • link out (x1)
Other

Tags

  • dashboard2
  • Alarm
  • Notification
  • DB
  • Badge
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option