175 lines
5.3 KiB
Python
175 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import uuid
|
|
|
|
# Read flows.json
|
|
with open('/home/mdares/.node-red/flows.json', 'r') as f:
|
|
flows = json.load(f)
|
|
|
|
# Read startup recovery function
|
|
with open('/home/mdares/.node-red/startup_recovery_function.js', 'r') as f:
|
|
recovery_code = f.read()
|
|
|
|
# Read stop reason UI template
|
|
with open('/home/mdares/.node-red/stop_reason_ui_template.html', 'r') as f:
|
|
stop_reason_ui = f.read()
|
|
|
|
# Find DB config and existing dashboard group
|
|
db_config_id = None
|
|
home_group_id = None
|
|
|
|
for node in flows:
|
|
if node.get('type') == 'MySQLdatabase':
|
|
db_config_id = node['id']
|
|
if node.get('type') == 'ui_group' and 'home' in node.get('name', '').lower():
|
|
home_group_id = node['id']
|
|
|
|
# If no home group found, use first ui_group
|
|
if not home_group_id:
|
|
for node in flows:
|
|
if node.get('type') == 'ui_group':
|
|
home_group_id = node['id']
|
|
break
|
|
|
|
print(f"DB config ID: {db_config_id}")
|
|
print(f"Home group ID: {home_group_id}")
|
|
|
|
# ============================================================================
|
|
# CREATE STARTUP RECOVERY TAB AND FLOW
|
|
# ============================================================================
|
|
|
|
recovery_tab_id = str(uuid.uuid4()).replace('-', '')[:16]
|
|
recovery_inject_id = str(uuid.uuid4()).replace('-', '')[:16]
|
|
recovery_function_id = str(uuid.uuid4()).replace('-', '')[:16]
|
|
recovery_mysql_id = str(uuid.uuid4()).replace('-', '')[:16]
|
|
|
|
# Create recovery tab
|
|
recovery_tab = {
|
|
"id": recovery_tab_id,
|
|
"type": "tab",
|
|
"label": "Startup Recovery",
|
|
"disabled": False,
|
|
"info": "Automatic session recovery on Node-RED startup"
|
|
}
|
|
|
|
# Create inject node (runs 5 seconds after startup)
|
|
recovery_inject = {
|
|
"id": recovery_inject_id,
|
|
"type": "inject",
|
|
"z": recovery_tab_id,
|
|
"name": "Check on Startup",
|
|
"props": [
|
|
{
|
|
"p": "mode",
|
|
"v": "check",
|
|
"vt": "str"
|
|
}
|
|
],
|
|
"repeat": "",
|
|
"crontab": "",
|
|
"once": True,
|
|
"onceDelay": "5",
|
|
"topic": "",
|
|
"x": 150,
|
|
"y": 100,
|
|
"wires": [[recovery_function_id]]
|
|
}
|
|
|
|
# Create recovery function node
|
|
recovery_function = {
|
|
"id": recovery_function_id,
|
|
"type": "function",
|
|
"z": recovery_tab_id,
|
|
"name": "Startup Recovery",
|
|
"func": recovery_code,
|
|
"outputs": 2,
|
|
"noerr": 0,
|
|
"initialize": "",
|
|
"finalize": "",
|
|
"libs": [],
|
|
"x": 360,
|
|
"y": 100,
|
|
"wires": [
|
|
[], # Output 1: notifications (not wired for now)
|
|
[recovery_mysql_id] # Output 2: database queries
|
|
]
|
|
}
|
|
|
|
# Create MySQL node for recovery
|
|
recovery_mysql = {
|
|
"id": recovery_mysql_id,
|
|
"type": "mysql",
|
|
"z": recovery_tab_id,
|
|
"mydb": db_config_id,
|
|
"name": "Recovery DB Query",
|
|
"x": 570,
|
|
"y": 100,
|
|
"wires": [[]] # Results can be processed later if needed
|
|
}
|
|
|
|
# Add recovery flow nodes
|
|
flows.extend([recovery_tab, recovery_inject, recovery_function, recovery_mysql])
|
|
|
|
print("\n✅ Added Startup Recovery flow:")
|
|
print(f" - New tab: 'Startup Recovery'")
|
|
print(f" - Inject node (runs 5s after startup)")
|
|
print(f" - Recovery function with crash recovery logic")
|
|
print(f" - MySQL node for querying session_state")
|
|
|
|
# ============================================================================
|
|
# ADD STOP REASON UI TEMPLATE
|
|
# ============================================================================
|
|
|
|
if home_group_id:
|
|
stop_reason_ui_id = str(uuid.uuid4()).replace('-', '')[:16]
|
|
|
|
stop_reason_template = {
|
|
"id": stop_reason_ui_id,
|
|
"type": "ui_template",
|
|
"z": None, # Will be set based on where home group is
|
|
"group": home_group_id,
|
|
"name": "Stop Reason Prompt",
|
|
"order": 99, # Place at end
|
|
"width": 0,
|
|
"height": 0,
|
|
"format": stop_reason_ui,
|
|
"storeOutMessages": True,
|
|
"fwdInMessages": True,
|
|
"resendOnRefresh": False,
|
|
"templateScope": "local",
|
|
"x": 0,
|
|
"y": 0,
|
|
"wires": [[]] # Output wires back to Work Order buttons (manual wiring needed)
|
|
}
|
|
|
|
# Find the tab/flow where the home group belongs
|
|
for node in flows:
|
|
if node.get('type') == 'ui_group' and node.get('id') == home_group_id:
|
|
stop_reason_template['z'] = node.get('z')
|
|
break
|
|
|
|
flows.append(stop_reason_template)
|
|
|
|
print("\n✅ Added Stop Reason UI Template:")
|
|
print(f" - ui_template node added to Home dashboard")
|
|
print(f" - Modal prompt for planned/unplanned stops")
|
|
print(f" - ID: {stop_reason_ui_id}")
|
|
print("\n⚠️ NOTE: You need to manually wire:")
|
|
print(" - Work Order buttons Output 2 → Stop Reason UI (for stop-prompt)")
|
|
print(" - Stop Reason UI output → Work Order buttons input (for stop-reason action)")
|
|
else:
|
|
print("\n⚠️ WARNING: No Home dashboard group found. Stop Reason UI not added.")
|
|
print(" You'll need to create this manually in the Node-RED editor.")
|
|
|
|
# Write updated flows
|
|
with open('/home/mdares/.node-red/flows.json', 'w') as f:
|
|
json.dump(flows, f, indent=4)
|
|
|
|
print("\n✅ flows.json updated successfully!")
|
|
print("\n📝 Summary of all changes:")
|
|
print(" ✓ Machine cycles function updated (2→4 outputs)")
|
|
print(" ✓ Work Order buttons function updated (4→5 outputs)")
|
|
print(" ✓ 3 MySQL nodes added (State Backup, Anomaly, Session)")
|
|
print(" ✓ Startup Recovery flow added (new tab)")
|
|
print(" ✓ Stop Reason UI template added")
|