Files
nr-flow-validator/flows/zigbee-monitor.yaml
T
david e5ed67a282 flow: add Dual Outlet - Couch to single-press button automation
Dual plug only responds to per-channel state_1/state_2 commands, not the
shared {state:TOGGLE} payload. Route single-filter through a couch-mapper
that emits {"state_1":"TOGGLE","state_2":"TOGGLE"} so both outlets flip.

Also adds state-in node, /set out node, and dashboard widget showing
state_1/state_2. Verified E2E + 567 Rego checks pass.

Refs: david/nr-flow-validator#2
2026-08-15 02:48:45 -07:00

195 lines
4.7 KiB
YAML

version: 1
brokers:
mosquitto:
host: mosquitto
port: 1883
# Plugs toggled on brief single press
single_plugs:
- Squiggle
- Sideboard Lamp
- Bamboo Lights
- Dual Outlet - Couch
# Plugs toggled on press-hold-release (action: "release" after a "hold")
hold_plugs:
- DJ Booth
dashboards:
- base: Dashboard
pages:
- page: Home
icon: home
path: /home
groups:
- name: Plugs
width: 6
flows:
- tab: Zigbee Monitor
description: Button dispatches single vs hold-release to different plug sets
nodes:
- id: zigbee-state-squiggle
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/Squiggle
qos: 0
- id: zigbee-state-sideboard
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/Sideboard Lamp
qos: 0
- id: zigbee-state-bamboo
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/Bamboo Lights
qos: 0
- id: zigbee-state-djbooth
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/DJ Booth
qos: 0
- id: zigbee-state-couch
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/Dual Outlet - Couch
qos: 0
- id: button-in
type: mqtt in
broker: mosquitto
topic: zigbee2mqtt/Door Button
qos: 0
- id: single-filter
type: function
name: Single click
code: |
const now = Date.now();
const last = context.get('lastTime') || 0;
if (now - last < 50) return null;
context.set('lastTime', now);
try {
const p = JSON.parse(msg.payload);
if (p.action === 'single') {
msg.payload = { state: 'TOGGLE' };
return msg;
}
} catch (e) {}
return null;
- id: hold-filter
type: function
name: Hold release
code: |
const now = Date.now();
const last = context.get('lastTime') || 0;
if (now - last < 50) return null;
context.set('lastTime', now);
try {
const p = JSON.parse(msg.payload);
if (p.action === 'release') {
msg.payload = { state: 'TOGGLE' };
return msg;
}
} catch (e) {}
return null;
- id: plug-out-squiggle
type: mqtt out
broker: mosquitto
topic: zigbee2mqtt/Squiggle/set
- id: plug-out-sideboard
type: mqtt out
broker: mosquitto
topic: zigbee2mqtt/Sideboard Lamp/set
- id: plug-out-bamboo
type: mqtt out
broker: mosquitto
topic: zigbee2mqtt/Bamboo Lights/set
- id: plug-out-djbooth
type: mqtt out
broker: mosquitto
topic: zigbee2mqtt/DJ Booth/set
- id: couch-mapper
type: function
name: Toggle both outlets
code: |
msg.payload = { state_1: 'TOGGLE', state_2: 'TOGGLE' };
return msg;
- id: plug-out-couch
type: mqtt out
broker: mosquitto
topic: zigbee2mqtt/Dual Outlet - Couch/set
- id: text-squiggle
type: ui-text
group: Plugs
label: Squiggle
format: "{{msg.payload.state}}"
order: 1
- id: text-sideboard
type: ui-text
group: Plugs
label: Sideboard Lamp
format: "{{msg.payload.state}}"
order: 2
- id: text-bamboo
type: ui-text
group: Plugs
label: Bamboo Lights
format: "{{msg.payload.state}}"
order: 3
- id: text-djbooth
type: ui-text
group: Plugs
label: DJ Booth
format: "{{msg.payload.state}}"
order: 4
- id: text-couch
type: ui-text
group: Plugs
label: Dual Outlet - Couch
format: "{{msg.payload.state_1}} / {{msg.payload.state_2}}"
order: 6
- id: permit-btn
type: ui-button
group: Plugs
label: Permit Join (60s)
topic: zigbee2mqtt/bridge/request/permit_join
payload:
value: true
time: 60
order: 5
- id: mqtt-out
type: mqtt out
broker: mosquitto
wires:
zigbee-state-squiggle: [text-squiggle]
zigbee-state-sideboard: [text-sideboard]
zigbee-state-bamboo: [text-bamboo]
zigbee-state-djbooth: [text-djbooth]
zigbee-state-couch: [text-couch]
button-in: [single-filter, hold-filter]
single-filter: [plug-out-squiggle, plug-out-sideboard, plug-out-bamboo, couch-mapper]
couch-mapper: [plug-out-couch]
hold-filter: [plug-out-djbooth]
permit-btn: [mqtt-out]