mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-08-14 13:50:06 +00:00
New: stable/test update channels with an opt-in "Get test builds (beta)" toggle on OTA devices (switches both the update check and what you install); experimental opt-in MQTT bridge (consent-gated, payload encryption, direct messages off by default); Portugal (Narrow) region preset (#74); saved-contacts counter in the Contacts overflow menu (#72). Fixed: the signal probe is now strictly zero-hop so a repeater can't re-flood it; the contact list sorts before capping so the most relevant contacts show, with a "+N more — search to narrow" footer (#73); the blocked-users list opened from Contacts shows the two-line title bar with a back button; the Contacts overflow popup fits the screen again. Also lands the two-channel release tooling (scripts/release.sh stable/beta modes + gen-flasher-meta channel arg), the docs site, and the MQTT reference decryptor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Reference subscriber + decryptor for the wadamesh MQTT bridge.
|
|
|
|
The bridge publishes received mesh messages to:
|
|
wadamesh/{node_hex}/msg/dm direct / signed messages (only if DM publish is ON)
|
|
wadamesh/{node_hex}/msg/ch channel messages
|
|
wadamesh/{node_hex}/status "online" / "offline" (retained LWT)
|
|
|
|
Payload:
|
|
- No encryption key set on the device -> payload is plain UTF-8 JSON.
|
|
- Encryption key (PSK) set -> payload is
|
|
base64( nonce[12] || ciphertext || tag[16] ), AES-256-GCM,
|
|
key = SHA-256(psk).
|
|
Set PSK below to the same passphrase you typed on the device.
|
|
|
|
Requires: pip install paho-mqtt cryptography
|
|
"""
|
|
import base64, hashlib, json
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
BROKER = "homeassistant.local"
|
|
PORT = 1883
|
|
PSK = "" # same passphrase as Settings -> MQTT -> Encryption key; "" = plaintext
|
|
|
|
|
|
def decode(payload: bytes) -> dict:
|
|
"""Return the message dict, decrypting if a PSK is configured."""
|
|
if not PSK:
|
|
return json.loads(payload)
|
|
key = hashlib.sha256(PSK.encode()).digest() # 32-byte AES-256 key
|
|
blob = base64.b64decode(payload)
|
|
nonce, ct_and_tag = blob[:12], blob[12:] # GCM tag is the trailing 16 bytes
|
|
plain = AESGCM(key).decrypt(nonce, ct_and_tag, None)
|
|
return json.loads(plain)
|
|
|
|
|
|
def main():
|
|
import paho.mqtt.client as mqtt
|
|
|
|
def on_connect(c, *_):
|
|
c.subscribe("wadamesh/+/msg/#")
|
|
print("subscribed to wadamesh/+/msg/#")
|
|
|
|
def on_message(_c, _u, msg):
|
|
try:
|
|
data = decode(msg.payload)
|
|
print(f"{msg.topic}: {data}")
|
|
except Exception as e:
|
|
print(f"{msg.topic}: <undecodable: {e}>")
|
|
|
|
c = mqtt.Client()
|
|
c.on_connect, c.on_message = on_connect, on_message
|
|
c.connect(BROKER, PORT, 60)
|
|
c.loop_forever()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|