node-red-contrib-openbeken-subflow 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/openbeken.json +2 -2
  2. package/package.json +1 -1
package/openbeken.json CHANGED
@@ -54,7 +54,7 @@
54
54
  "meta": {
55
55
  "module": "node-red-contrib-openbeken-subflow",
56
56
  "type": "openbeken",
57
- "version": "1.3.1",
57
+ "version": "1.3.2",
58
58
  "author": "gparduino",
59
59
  "desc": "OpenBeken flashed module support",
60
60
  "keywords": "openbeken",
@@ -78,7 +78,7 @@
78
78
  "type": "function",
79
79
  "z": "287344f336f70f21",
80
80
  "name": "Process MQTT & UI",
81
- "func": "const topicBase = env.get(\"TOPIC_BASE\");\nconst syncGroup = env.get(\"SYNC_GROUP\");\n\n// Helper to create the status object for Port 3\nconst getStatus = (fill, shape, text) => ({ payload: { fill, shape, text } });\n\n// --- 1. WATCHDOG ---\nif (msg.topic === \"watchdog\") {\n const stat = { fill: \"red\", shape: \"ring\", text: \"Offline\" };\n node.status(stat);\n return [null, null, { payload: stat }]; // Status to Port 3\n}\n\n// --- 2. INCOMING MQTT (From Hardware) ---\nif (msg.topic === `${topicBase}/1/get`) {\n const isOn = (msg.payload == 1 || msg.payload === \"on\" || msg.payload === true);\n const contextKey = \"sync_\" + syncGroup;\n const lockKey = \"lock_\" + syncGroup;\n \n const lastKnown = global.get(contextKey);\n const isLocked = global.get(lockKey) || false;\n\n const stat = { fill: isOn ? \"green\" : \"grey\", shape: \"dot\", text: isOn ? \"On\" : \"Off\" };\n node.status(stat);\n\n if (syncGroup && isOn !== lastKnown && !isLocked) {\n global.set(contextKey, isOn);\n global.set(lockKey, true);\n \n setTimeout(() => { global.set(lockKey, false); }, 400);\n\n return [{ payload: isOn, source: \"from_hw\" }, null, { payload: stat }];\n }\n // Return status even if we don't propagate the message\n return [null, null, { payload: stat }];\n}\n\n// --- 3. COMMAND LOGIC (From UI or Sync Input) ---\nconst p = msg.payload;\nif (typeof p === \"boolean\" || p === \"on\" || p === \"off\" || p === \"1\" || p === \"0\") {\n const isTrue = (p === true || p === \"on\" || p === \"1\" || p === 1);\n const mqttMsg = { topic: `${topicBase}/1/set`, payload: isTrue ? 1 : 0 };\n\n // Maintain current status display during command\n const currentStat = { fill: isTrue ? \"green\" : \"grey\", shape: \"dot\", text: isTrue ? \"On\" : \"Off\" };\n\n if (msg.source === \"from_hw\") {\n return [null, mqttMsg, { payload: currentStat }];\n } \n \n return [null, mqttMsg, { payload: currentStat }];\n}\n\nreturn null;",
81
+ "func": "const topicBase = env.get(\"TOPIC_BASE\");\nconst syncGroup = env.get(\"SYNC_GROUP\");\n\n// Helper to create the status object for Port 3\nconst getStatus = (fill, shape, text) => ({ payload: { fill, shape, text } });\n\n// --- 1. WATCHDOG ---\nif (msg.topic === \"watchdog\") {\n const stat = { fill: \"red\", shape: \"ring\", text: \"Offline\" };\n node.status(stat);\n return [null, null, { payload: stat }];\n}\n\n// --- 2. INCOMING MQTT (From Hardware) ---\nif (msg.topic === `${topicBase}/1/get`) {\n const isOn = (msg.payload == 1 || msg.payload === \"on\" || msg.payload === true);\n const contextKey = \"sync_\" + syncGroup;\n \n const lastKnown = global.get(contextKey);\n\n const stat = { fill: isOn ? \"green\" : \"grey\", shape: \"dot\", text: isOn ? \"On\" : \"Off\" };\n node.status(stat);\n\n // Update Global State if in a group\n if (syncGroup && isOn !== lastKnown) {\n global.set(contextKey, isOn);\n }\n\n // FIX: Always output to Port 1 so Dashboard updates.\n // The \"loop prevention\" is now handled in Section 3 of the RECEIVING node.\n return [{ payload: isOn, source: \"from_hw\" }, null, { payload: stat }];\n}\n\n// --- 3. COMMAND LOGIC (From UI or Sync Input) ---\nconst p = msg.payload;\nif (typeof p === \"boolean\" || p === \"on\" || p === \"off\" || p === \"1\" || p === \"0\") {\n const isTrue = (p === true || p === \"on\" || p === \"1\" || p === 1);\n const mqttMsg = { topic: `${topicBase}/1/set`, payload: isTrue ? 1 : 0 };\n const contextKey = \"sync_\" + syncGroup;\n\n // Maintain current status display during command\n const currentStat = { fill: isTrue ? \"green\" : \"grey\", shape: \"dot\", text: isTrue ? \"On\" : \"Off\" };\n\n if (msg.source === \"from_hw\") {\n // FIX: Anti-Loop Logic moved here.\n // If we are in a Sync Group, and the Global State already matches the request,\n // it means another node already updated the state. DO NOT fire MQTT to device.\n if (syncGroup) {\n const currentGlobal = global.get(contextKey);\n if (currentGlobal === isTrue) {\n // Loop detected: Stop propagation.\n return [null, null, { payload: currentStat }];\n }\n }\n \n // If legitimate sync request, send MQTT but DO NOT echo back to Port 1\n return [null, mqttMsg, { payload: currentStat }];\n } \n \n // If from Dashboard (no source tag), send MQTT and allow loopback if needed\n return [null, mqttMsg, { payload: currentStat }];\n}\n\nreturn null;",
82
82
  "outputs": 3,
83
83
  "timeout": "",
84
84
  "noerr": 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-openbeken-subflow",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Optimized OpenBeken support for Node-RED with Dashboard 2.0 dynamic UI updates",
5
5
  "main": "openbeken.js",
6
6
  "node-red": {