+1
-125
@@ -37,117 +37,6 @@ def make_broker_node(name, cfg):
|
||||
return node
|
||||
|
||||
|
||||
def build_plugs(flow_def, doc, broker_map, group_map):
|
||||
"""Expand a declarative `plugs:` list into state-in/out/widget nodes and wiring.
|
||||
|
||||
Each plug entry: {id, name, channels?}.
|
||||
- single channel: widget shows {{msg.payload.state}}
|
||||
- multi-channel (channels: [1, 2]): a mapper function is emitted before the
|
||||
plug-out so the device toggles per-channel, and the widget shows each state_N.
|
||||
|
||||
single_plugs / hold_plugs are lists of plug ids driven by the function nodes
|
||||
named single_filter / hold_filter respectively.
|
||||
"""
|
||||
if "plugs" not in flow_def:
|
||||
return [], {}
|
||||
|
||||
_flow_order["text-order-counter"] = 0
|
||||
|
||||
plug_cfg = {p["id"]: p for p in flow_def["plugs"]}
|
||||
|
||||
def state_keys(p):
|
||||
return [int(k) for k in p.get("channels", [])] if p.get("channels") else []
|
||||
|
||||
nodes = []
|
||||
wires = {}
|
||||
|
||||
def wire(src, target):
|
||||
wires.setdefault(src, []).append(target)
|
||||
|
||||
def channel_mapper_id(pid):
|
||||
return f"mapper-{pid}"
|
||||
|
||||
for key in ("single_plugs", "hold_plugs"):
|
||||
filter_id = flow_def.get("single_filter" if key == "single_plugs" else "hold_filter")
|
||||
if not filter_id:
|
||||
raise ValueError(f"flow missing {'single_filter' if key == 'single_plugs' else 'hold_filter'} for {key}")
|
||||
for pid in flow_def.get(key, []):
|
||||
p = plug_cfg[pid]
|
||||
name = p["name"]
|
||||
keys = state_keys(p)
|
||||
|
||||
sid = f"zigbee-state-{pid}"
|
||||
oid = f"plug-out-{pid}"
|
||||
tid = f"text-{pid}"
|
||||
|
||||
nodes.append({
|
||||
"id": sid, "type": "mqtt in", "wires": [], "name": "",
|
||||
"broker": broker_map[_broker(flow_def, doc)],
|
||||
"topic": f"zigbee2mqtt/{name}", "qos": "0", "datatype": "auto",
|
||||
})
|
||||
|
||||
fmt = "{{msg.payload.state}}"
|
||||
if keys:
|
||||
parts = [f"{{{{msg.payload.state_{k}}}}}" for k in keys]
|
||||
fmt = " / ".join(parts)
|
||||
nodes.append({
|
||||
"id": tid, "type": "ui-text", "wires": [], "name": name,
|
||||
"group": group_map[_group(flow_def)],
|
||||
"width": "6", "height": "2", "order": _order(flow_def),
|
||||
"label": name, "format": fmt, "layout": "row-spread", "className": "",
|
||||
})
|
||||
|
||||
target = oid
|
||||
if keys:
|
||||
mid = channel_mapper_id(pid)
|
||||
code = ", ".join(f"state_{k}: 'TOGGLE'" for k in keys)
|
||||
nodes.append({
|
||||
"id": mid, "type": "function", "wires": [], "name": "Toggle each outlet",
|
||||
"func": f"msg.payload = {{{code}}};\nreturn msg;",
|
||||
"outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [],
|
||||
})
|
||||
wire(filter_id, mid)
|
||||
wire(mid, oid)
|
||||
else:
|
||||
wire(filter_id, target)
|
||||
|
||||
nodes.append({
|
||||
"id": oid, "type": "mqtt out", "wires": [], "name": "",
|
||||
"broker": broker_map[_broker(flow_def, doc)],
|
||||
"topic": f"zigbee2mqtt/{name}/set", "qos": "2", "retain": False,
|
||||
})
|
||||
|
||||
wire(sid, tid)
|
||||
|
||||
return nodes, wires
|
||||
|
||||
|
||||
def _broker(flow_def, doc):
|
||||
# broker used by generated plug nodes: first broker referenced by any node, else first defined
|
||||
for nd in flow_def.get("nodes", []):
|
||||
if nd.get("broker"):
|
||||
return nd["broker"]
|
||||
brokers = list(doc.get("brokers", {}))
|
||||
if not brokers:
|
||||
raise ValueError("no broker defined")
|
||||
return brokers[0]
|
||||
|
||||
|
||||
def _group(flow_def):
|
||||
for nd in flow_def.get("nodes", []):
|
||||
if nd.get("group"):
|
||||
return nd["group"]
|
||||
raise ValueError("no dashboard group defined")
|
||||
|
||||
|
||||
_flow_order = {"text-order-counter": 0}
|
||||
|
||||
|
||||
def _order(flow_def):
|
||||
_flow_order["text-order-counter"] += 1
|
||||
return _flow_order["text-order-counter"]
|
||||
|
||||
|
||||
def make_node(nd, col, row, broker_map, group_map):
|
||||
ntype = nd["type"]
|
||||
nid = nd.get("id", new_id())
|
||||
@@ -265,17 +154,6 @@ def build_flow(doc, flow_def, node_positions):
|
||||
"env": [],
|
||||
})
|
||||
|
||||
plug_nodes, plug_wires = build_plugs(flow_def, doc, broker_map, group_map)
|
||||
renum = 0
|
||||
for pn in plug_nodes:
|
||||
pn["z"] = FLOW_ID
|
||||
col = {"mqtt in": 0, "function": 1, "mqtt out": 2, "ui-text": 2}.get(
|
||||
pn.get("type"), 0)
|
||||
pn["x"] = COLUMNS[col]
|
||||
pn["y"] = 80 + (renum * ROW_HEIGHT // 2)
|
||||
renum += 1
|
||||
nodes.append(pn)
|
||||
|
||||
for i, nd in enumerate(flow_def["nodes"]):
|
||||
col, row = node_positions.get(nd["id"], (0, i))
|
||||
node = make_node(nd, col, row, broker_map, group_map)
|
||||
@@ -285,9 +163,7 @@ def build_flow(doc, flow_def, node_positions):
|
||||
node["label"] = nd.get("label", nd.get("name", ""))
|
||||
nodes.append(node)
|
||||
|
||||
wires = dict(flow_def.get("wires", {}))
|
||||
for k, v in plug_wires.items():
|
||||
wires.setdefault(k, []).extend(v)
|
||||
wires = flow_def.get("wires", {})
|
||||
for src_id, targets in wires.items():
|
||||
src = next((n for n in nodes if n["id"] == src_id), None)
|
||||
if src:
|
||||
|
||||
Reference in New Issue
Block a user