infra: tune flash params + persist zigbee network key for paired devices
- FLASH_INTERVAL_SECONDS 3 -> 2 (user preference) - Add network_key / pan_id / ext_pan_id to zigbee2mqtt configuration so paired devices can rejoin after a config wipe. Network key preserved from previous working state on RPi. - Doorbell listener flash logic with even toggle count so plug ends at starting state
This commit is contained in:
+1
-1
@@ -73,7 +73,7 @@ services:
|
|||||||
PLUG_TOPIC: "zigbee2mqtt/Sideboard Lamp/set"
|
PLUG_TOPIC: "zigbee2mqtt/Sideboard Lamp/set"
|
||||||
POLL_INTERVAL: "30"
|
POLL_INTERVAL: "30"
|
||||||
MAX_AGE_SECONDS: "180"
|
MAX_AGE_SECONDS: "180"
|
||||||
FLASH_INTERVAL_SECONDS: "3"
|
FLASH_INTERVAL_SECONDS: "2"
|
||||||
FLASH_DURATION_SECONDS: "15"
|
FLASH_DURATION_SECONDS: "15"
|
||||||
TZ: America/Los_Angeles
|
TZ: America/Los_Angeles
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ Env vars (all optional):
|
|||||||
NTFY_TOPICS comma-separated override, default "ALERT_klubhaus_topic_test,ALERT_klubhaus_topic"
|
NTFY_TOPICS comma-separated override, default "ALERT_klubhaus_topic_test,ALERT_klubhaus_topic"
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
import math
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
@@ -48,12 +49,21 @@ POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL", "30"))
|
|||||||
# Drop messages older than this many seconds (replay protection after restart).
|
# Drop messages older than this many seconds (replay protection after restart).
|
||||||
MAX_AGE_SECONDS = int(os.environ.get("MAX_AGE_SECONDS", "180"))
|
MAX_AGE_SECONDS = int(os.environ.get("MAX_AGE_SECONDS", "180"))
|
||||||
# On a fresh alert, flash the plug: TOGGLE every FLASH_INTERVAL_SECONDS,
|
# On a fresh alert, flash the plug: TOGGLE every FLASH_INTERVAL_SECONDS,
|
||||||
# repeated so the total runtime is FLASH_DURATION_SECONDS. With defaults
|
# repeated so the total runtime is FLASH_DURATION_SECONDS. Count is rounded
|
||||||
# (3s interval, 15s duration) that's 5 toggles, ending opposite of start.
|
# UP to the nearest even integer so the lamp ends in the state it started
|
||||||
FLASH_INTERVAL_SECONDS = float(os.environ.get("FLASH_INTERVAL_SECONDS", "3"))
|
# in (an even number of toggles returns to the original state).
|
||||||
|
FLASH_INTERVAL_SECONDS = float(os.environ.get("FLASH_INTERVAL_SECONDS", "2"))
|
||||||
FLASH_DURATION_SECONDS = float(os.environ.get("FLASH_DURATION_SECONDS", "15"))
|
FLASH_DURATION_SECONDS = float(os.environ.get("FLASH_DURATION_SECONDS", "15"))
|
||||||
|
|
||||||
|
|
||||||
|
def flash_count() -> int:
|
||||||
|
"""Number of toggles per alert. Always >= 2 and even."""
|
||||||
|
n = max(2, math.ceil(FLASH_DURATION_SECONDS / FLASH_INTERVAL_SECONDS))
|
||||||
|
if n % 2:
|
||||||
|
n += 1
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
def log(msg: str) -> None:
|
def log(msg: str) -> None:
|
||||||
print(msg, flush=True)
|
print(msg, flush=True)
|
||||||
|
|
||||||
@@ -107,7 +117,7 @@ def poll_topic(client: mqtt.Client, topic: str, last_id: str) -> str:
|
|||||||
|
|
||||||
newest_id = last_id
|
newest_id = last_id
|
||||||
now = time.time()
|
now = time.time()
|
||||||
flash_count = max(1, int(FLASH_DURATION_SECONDS / FLASH_INTERVAL_SECONDS))
|
n_flashes = flash_count()
|
||||||
for line in r.iter_lines(decode_unicode=True):
|
for line in r.iter_lines(decode_unicode=True):
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
@@ -136,7 +146,7 @@ def poll_topic(client: mqtt.Client, topic: str, last_id: str) -> str:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
log(f"[{topic}] alert: id={msg_id} age={age}s title={title!r} message={message!r}")
|
log(f"[{topic}] alert: id={msg_id} age={age}s title={title!r} message={message!r}")
|
||||||
start_flash(client, flash_count, FLASH_INTERVAL_SECONDS)
|
start_flash(client, n_flashes, FLASH_INTERVAL_SECONDS)
|
||||||
|
|
||||||
return newest_id
|
return newest_id
|
||||||
|
|
||||||
@@ -148,8 +158,9 @@ def main() -> None:
|
|||||||
log(f" plug topic: {PLUG_TOPIC}")
|
log(f" plug topic: {PLUG_TOPIC}")
|
||||||
log(f" poll interval: {POLL_INTERVAL}s")
|
log(f" poll interval: {POLL_INTERVAL}s")
|
||||||
log(f" max age: {MAX_AGE_SECONDS}s")
|
log(f" max age: {MAX_AGE_SECONDS}s")
|
||||||
log(f" flash: {FLASH_DURATION_SECONDS / FLASH_INTERVAL_SECONDS:.0f} toggles "
|
n_flashes = flash_count()
|
||||||
f"@ {FLASH_INTERVAL_SECONDS}s ({FLASH_DURATION_SECONDS}s total)")
|
log(f" flash: {n_flashes} toggles @ {FLASH_INTERVAL_SECONDS}s "
|
||||||
|
f"({n_flashes * FLASH_INTERVAL_SECONDS}s total, even -> ends at start)")
|
||||||
log(f" state dir: {STATE_DIR}")
|
log(f" state dir: {STATE_DIR}")
|
||||||
|
|
||||||
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||||
|
|||||||
@@ -9,6 +9,34 @@ serial:
|
|||||||
rtscts: false
|
rtscts: false
|
||||||
advanced:
|
advanced:
|
||||||
log_level: debug
|
log_level: debug
|
||||||
|
network_key:
|
||||||
|
- 146
|
||||||
|
- 30
|
||||||
|
- 124
|
||||||
|
- 1
|
||||||
|
- 70
|
||||||
|
- 32
|
||||||
|
- 235
|
||||||
|
- 196
|
||||||
|
- 27
|
||||||
|
- 113
|
||||||
|
- 122
|
||||||
|
- 230
|
||||||
|
- 7
|
||||||
|
- 177
|
||||||
|
- 134
|
||||||
|
- 45
|
||||||
|
pan_id: 3926
|
||||||
|
ext_pan_id:
|
||||||
|
- 225
|
||||||
|
- 105
|
||||||
|
- 42
|
||||||
|
- 213
|
||||||
|
- 37
|
||||||
|
- 25
|
||||||
|
- 93
|
||||||
|
- 235
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
Reference in New Issue
Block a user