make a mqtt ble bridge service for meterkast
This commit is contained in:
parent
62e0977c85
commit
6c2ad11d6a
221
mqtt_meterkast_bt_bridge.py
Normal file
221
mqtt_meterkast_bt_bridge.py
Normal file
@ -0,0 +1,221 @@
|
||||
import asyncio
|
||||
import paho.mqtt.client as mqtt
|
||||
from bleak import BleakClient, BleakScanner
|
||||
import time
|
||||
import sys
|
||||
from collections import deque # Efficiënte wachtrij voor de cach
|
||||
|
||||
MAX_CACHE_SIZE = 1000
|
||||
|
||||
# BLE CONFIGURATIE (Moet exact matchen met de ESP32)
|
||||
ble_pin = 341055
|
||||
ESP32_NAME = "ESP32_Meterkast_BLE"
|
||||
SERVICE_UUID = "538b94e9-d5a3-4f16-877f-d208af9e9db9"
|
||||
CHARACTERISTIC_TX_UUID = "637ce3a9-9203-42a6-87f0-bdbecf7b5b5e" # ESP32 -> PC
|
||||
CHARACTERISTIC_RX_UUID = "56e9ab79-d1a8-497e-b08e-19922f7eeacf" # PC -> ESP32
|
||||
|
||||
MQTT_PORT = 1883
|
||||
MQTT_BROKER = "192.168.200.26"
|
||||
MQTT_USER = "vlc_viewer"
|
||||
MQTT_PASSWORD = "vlc_viewer12"
|
||||
mqttClientId = "MeterKastController"
|
||||
|
||||
# Topics configureren
|
||||
# De PC luistert naar dit topic en stuurt ALLES wat hier binnenkomt door naar de ESP32 via BT
|
||||
mqttTopicBelVoorTest = "BelVoorTest"
|
||||
mqttTopicRestarCamera = "RestartCamera"
|
||||
mqttTopicDisableVAlarm = "DisableVAlarm"
|
||||
mqttTopicEnableVAlarm = "EnableVAlarm"
|
||||
mqttTopicActivateFan = "ActivateFanMeterkast"
|
||||
mqttTopicDeactivateFan = "DeactivateFanMeterkast"
|
||||
mqttTopicActivateBuzzer = "ActivateAlarmBuzzer"
|
||||
mqttTopicDeactivateBuzzer = "DeactivateAlarmBuzzer"
|
||||
mqttTopicAlarmLampAan = "AlarmLampAan"
|
||||
mqttTopicAlarmLampUit = "AlarmLAmpUit"
|
||||
|
||||
# mqttTopicDalVerbruikt = "DalVerbruikt_kwh"
|
||||
# mqttTopicPiekVerbruikt = "PiekVerbruikt_kwh"
|
||||
# mqttTopicDalGeleverd = "DalGeleverd_kwh"
|
||||
# mqttTopicPiekGeleverd = "PiekGeleverd_kwh"
|
||||
# mqttTopicHuidigVerbruik = "HuidigVerbruik_kw"
|
||||
# mqttTopicHuidigGeleverd = "HuidigGeleverd_kw"
|
||||
# mqttTopicGasTotaal = "gas_totaal_m3"
|
||||
#
|
||||
# mqttTopicTempMeterKast = "TempMeterKast"
|
||||
# mqttTopicTempThermostaat = "TempThermostaat"
|
||||
# mqttTopicTempBuiten = "TempBuiten"
|
||||
# mqttTopicTempKamer = "TempKamer"
|
||||
# mqttTopicTempOverloop = "TempOverloop"
|
||||
# mqttTopicTempMeterKastController = "TempMeterKastController"
|
||||
#
|
||||
# mqttTopicHcProtected = "HcProtected"
|
||||
# mqttTopicHcAlarm = "HcAlarm"
|
||||
# mqttTopicHcVAlarm = "HcVAlarm"
|
||||
# mqttTopicHcAlarmBuzzer = "HcAlarmBuzzer"
|
||||
# mqttTopicHcAlarmLamp = "HCLampAlarm"
|
||||
# mqttTopicFanMeterkast = "FanMeterKast"
|
||||
# mqttTopicAlarmStatus = "AlarmStatus"
|
||||
# mqttTopicP1Line = "P1Line"
|
||||
# mqttTopicP1InvalidLine = "P1InvalidLine"
|
||||
# mqttTopicSerialOutput = "SerialOutput"
|
||||
#
|
||||
# mqtt_temperature_topic = "BrievenbusTemperatuur"
|
||||
# mqtt_bel_topic = "BelVoor"
|
||||
# mqtt_bel_state_topic = "BelVoorStatus"
|
||||
# mqtt_test_topic = "BrievenbusTest"
|
||||
# mqtt_debug_topic = "BrievenbusDebug"
|
||||
# mqtt_box_state_topic = "BrievenbusStatus"
|
||||
# mqtt_box_opened_topic = "BrievenbusOpen"
|
||||
# mqtt_box_closed_topic = "BrievenbusDicht"
|
||||
# mqtt_info_topic = "BrievenbusInfo"
|
||||
# ======================================================
|
||||
|
||||
mqtt_client = None
|
||||
mqtt_connected = False
|
||||
message_cache = deque(maxlen=MAX_CACHE_SIZE)
|
||||
ble_client = None
|
||||
|
||||
|
||||
# --- CALLBACKS: MQTT STATUS EN ONTVANGST ---
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
"""Wordt aangeroepen als de verbinding met de MQTT broker slaagt of faalt."""
|
||||
global mqtt_connected
|
||||
if rc == 0:
|
||||
print("[MQTT] Succesvol ingelogd en verbonden met de broker!")
|
||||
mqtt_connected = True
|
||||
client.subscribe(mqttTopicBelVoorTest)
|
||||
client.subscribe(mqttTopicRestarCamera)
|
||||
client.subscribe(mqttTopicDisableVAlarm)
|
||||
client.subscribe(mqttTopicEnableVAlarm)
|
||||
client.subscribe(mqttTopicActivateFan)
|
||||
client.subscribe(mqttTopicDeactivateFan)
|
||||
client.subscribe(mqttTopicActivateBuzzer)
|
||||
client.subscribe(mqttTopicDeactivateBuzzer)
|
||||
client.subscribe(mqttTopicAlarmLampAan)
|
||||
client.subscribe(mqttTopicAlarmLampUit)
|
||||
print(f"[MQTT] Geabonneerd op topics")
|
||||
flush_cache()
|
||||
elif rc == 4:
|
||||
print("[MQTT Fout] Verbinding geweigerd: Verkeerde gebruikersnaam of wachtwoord!")
|
||||
mqtt_connected = False
|
||||
else:
|
||||
print(f"[MQTT Fout] Verbinding geweigerd met code: {rc}")
|
||||
mqtt_connected = False
|
||||
|
||||
def on_disconnect(client, userdata, rc):
|
||||
"""Wordt aangeroepen als de verbinding met de MQTT broker wegvalt."""
|
||||
global mqtt_connected
|
||||
mqtt_connected = False
|
||||
print("[MQTT] Verbinding verloren! Inkomende Bluetooth data wordt vanaf nu gecacht...")
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
"""Wordt geactiveerd als er een MQTT bericht binnenkomt voor de ESP32."""
|
||||
global ser
|
||||
try:
|
||||
payload = msg.payload.decode('utf-8')
|
||||
print(f"[MQTT -> BT] Ontvangen op {msg.topic}: {payload}")
|
||||
|
||||
if ble_client and ble_client.is_connected:
|
||||
# BLE vereist een asyncio-aanroep, paho-mqtt draait in een aparte thread.
|
||||
# We schrijven de data asynchroon weg via de loop.
|
||||
coro = ble_client.write_gatt_char(CHARACTERISTIC_RX_UUID, f"{msg.topic}\n".encode('utf-8'))
|
||||
asyncio.run_coroutine_threadsafe(coro, asyncio.get_event_loop())
|
||||
except Exception as e:
|
||||
print(f"[Fout] Probleem bij doorsturen naar Bluetooth: {e}")
|
||||
|
||||
# --- BLE NOTIFICATIE CALLBACK ---
|
||||
def ble_notification_handler(sender: int, data: bytearray):
|
||||
"""Wordt getriggerd als de ESP32 data pushed (ESP32 -> PC)"""
|
||||
global mqtt_connected, mqtt_client
|
||||
try:
|
||||
line = data.decode('utf-8').strip()
|
||||
if "|" in line:
|
||||
topic, value = line.split("|", 1)
|
||||
if mqtt_connected:
|
||||
print(f"[BLE -> MQTT] Publiceren op {topic}: {value}")
|
||||
mqtt_client.publish(topic, value)
|
||||
else:
|
||||
message_cache.append((topic, value))
|
||||
print(f"[Cache] MQTT offline. Opgeslagen: {topic} -> {value}")
|
||||
except Exception as e:
|
||||
print(f"[BLE Fout] Data verwerkingsfout: {e}")
|
||||
|
||||
# --- CACHE LOGICA ---
|
||||
def flush_cache():
|
||||
"""Stuurt alle opgeslagen berichten in de cache alsnog naar MQTT."""
|
||||
global mqtt_client, mqtt_connected
|
||||
if not message_cache:
|
||||
return
|
||||
|
||||
print(f"[Cache] MQTT hersteld. {len(message_cache)} berichten in de wachtrij verzenden...")
|
||||
|
||||
while message_cache and mqtt_connected:
|
||||
try:
|
||||
topic, value = message_cache.popleft()
|
||||
mqtt_client.publish(topic, value)
|
||||
time.sleep(0.02)
|
||||
except Exception as e:
|
||||
print(f"[Cache Fout] Kon gecacht bericht niet verzenden: {e}")
|
||||
break
|
||||
|
||||
if not message_cache:
|
||||
print("[Cache] Alle gecachte berichten succesvol verzonden!")
|
||||
|
||||
# ==================== HOOFDPROGRAMMA ====================
|
||||
async def main():
|
||||
global ser, mqtt_client, mqtt_connected
|
||||
|
||||
# 1. MQTT Client initialiseren en beveiliging instellen
|
||||
print("[MQTT] Initialiseren...")
|
||||
mqtt_client = mqtt.Client()
|
||||
mqtt_client.on_connect = on_connect
|
||||
mqtt_client.on_disconnect = on_disconnect
|
||||
mqtt_client.on_message = on_message
|
||||
|
||||
# Gebruikersnaam en wachtwoord koppelen aan de MQTT sessie
|
||||
if MQTT_USER and MQTT_PASSWORD:
|
||||
mqtt_client.username_pw_set(username=MQTT_USER, password=MQTT_PASSWORD)
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
try:
|
||||
mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
|
||||
except Exception as e:
|
||||
print(f"[MQTT Waarschuwing] Eerste broker-verbinding mislukt ({e}). Controleer inloggegevens en broker-status.")
|
||||
|
||||
print("[Systeem] Bridge opgestart. Starten van Bluetooth-verbinding...")
|
||||
|
||||
# 2. BLE Verbindings- en herstelloop
|
||||
print("[Systeem] BLE Bridge actief. Zoeken naar ESP32...")
|
||||
while True:
|
||||
try:
|
||||
# Zoek het apparaat op basis van de naam
|
||||
device = await BleakScanner.find_device_by_name(ESP32_NAME)
|
||||
if not device:
|
||||
print(f"[BLE] Apparaat '{ESP32_NAME}' niet gevonden. Opnieuw scannen in 5s...")
|
||||
await asyncio.sleep(5)
|
||||
continue
|
||||
|
||||
print(f"[BLE] Apparaat gevonden ({device.address}). Verbinden en authenticeren...")
|
||||
|
||||
async with BleakClient(device.address) as client:
|
||||
ble_client = client
|
||||
print("[BLE] Verbonden! Activeren van data-notificaties...")
|
||||
|
||||
# Start met luisteren naar de TX-characteristic van de ESP32
|
||||
await client.start_notify(CHARACTERISTIC_TX_UUID, ble_notification_handler)
|
||||
|
||||
# Blijf in deze loop zolang de BLE verbinding in stand blijft
|
||||
while client.is_connected:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[BLE Fout] Verbinding verbroken of geweigerd ({e}). Herstellen over 5s...")
|
||||
ble_client = None
|
||||
await asyncio.sleep(5)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
print("\n[Systeem] Gestopt.")
|
||||
Loading…
Reference in New Issue
Block a user