mirror of
https://github.com/AkitaEngineering/Akita-Meshtastic-Meshcore-Bridge.git
synced 2026-05-07 22:04:44 +02:00
132 lines
5.1 KiB
Python
132 lines
5.1 KiB
Python
# ammb/bridge.py
|
|
"""
|
|
Main Bridge orchestrator class.
|
|
"""
|
|
|
|
import logging
|
|
import threading
|
|
from queue import Queue
|
|
import time
|
|
from typing import Union, Optional
|
|
|
|
from .config_handler import BridgeConfig
|
|
from .meshtastic_handler import MeshtasticHandler
|
|
from .meshcore_handler import MeshcoreHandler
|
|
from .mqtt_handler import MQTTHandler
|
|
|
|
ExternalHandler = Union[MeshcoreHandler, MQTTHandler]
|
|
|
|
class Bridge:
|
|
"""Orchestrates the Meshtastic-External Network bridge operation."""
|
|
|
|
def __init__(self, config: BridgeConfig):
|
|
self.logger = logging.getLogger(__name__)
|
|
self.config = config
|
|
self.shutdown_event = threading.Event()
|
|
|
|
self.to_meshtastic_queue = Queue(maxsize=config.queue_size)
|
|
self.to_external_queue = Queue(maxsize=config.queue_size)
|
|
self.logger.info(f"Message queues initialized with max size: {config.queue_size}")
|
|
|
|
self.logger.info("Initializing network handlers...")
|
|
self.meshtastic_handler: Optional[MeshtasticHandler] = None
|
|
self.external_handler: Optional[ExternalHandler] = None
|
|
self.handlers = []
|
|
|
|
try:
|
|
self.meshtastic_handler = MeshtasticHandler(
|
|
config=config,
|
|
to_external_queue=self.to_external_queue,
|
|
from_external_queue=self.to_meshtastic_queue,
|
|
shutdown_event=self.shutdown_event
|
|
)
|
|
self.handlers.append(self.meshtastic_handler)
|
|
|
|
if config.external_transport == 'serial':
|
|
self.logger.info("Selected external transport: Serial")
|
|
self.external_handler = MeshcoreHandler(
|
|
config=config,
|
|
to_meshtastic_queue=self.to_meshtastic_queue,
|
|
from_meshtastic_queue=self.to_external_queue,
|
|
shutdown_event=self.shutdown_event
|
|
)
|
|
self.handlers.append(self.external_handler)
|
|
elif config.external_transport == 'mqtt':
|
|
self.logger.info("Selected external transport: MQTT")
|
|
self.external_handler = MQTTHandler(
|
|
config=config,
|
|
to_meshtastic_queue=self.to_meshtastic_queue,
|
|
from_meshtastic_queue=self.to_external_queue,
|
|
shutdown_event=self.shutdown_event
|
|
)
|
|
self.handlers.append(self.external_handler)
|
|
else:
|
|
raise ValueError(f"Invalid external_transport configured: {config.external_transport}")
|
|
|
|
self.logger.info(f"All required handlers initialized successfully.")
|
|
|
|
except (ValueError, Exception) as e:
|
|
self.logger.critical(f"Failed to initialize handlers: {e}. Bridge cannot start.", exc_info=True)
|
|
self.stop()
|
|
self.external_handler = None
|
|
|
|
|
|
def run(self):
|
|
self.logger.info("Starting AMMB run sequence...")
|
|
|
|
if not self.meshtastic_handler or not self.external_handler:
|
|
self.logger.error("One or more handlers failed to initialize. Bridge cannot run.")
|
|
self.stop()
|
|
return
|
|
|
|
self.logger.info("Attempting initial network connections...")
|
|
if not self.meshtastic_handler.connect():
|
|
self.logger.critical("Failed to connect to Meshtastic device on startup. Bridge cannot start.")
|
|
self.stop()
|
|
return
|
|
|
|
if not self.external_handler.connect():
|
|
handler_type = type(self.external_handler).__name__
|
|
self.logger.warning(f"Failed to initiate connection for {handler_type} initially. Handler will keep trying in background.")
|
|
|
|
self.logger.info("Starting handler background tasks/threads...")
|
|
try:
|
|
self.meshtastic_handler.start_sender()
|
|
if isinstance(self.external_handler, MeshcoreHandler):
|
|
self.external_handler.start_threads()
|
|
elif isinstance(self.external_handler, MQTTHandler):
|
|
self.external_handler.start_publisher()
|
|
|
|
except Exception as e:
|
|
self.logger.critical(f"Failed to start handler background tasks: {e}", exc_info=True)
|
|
self.stop()
|
|
return
|
|
|
|
self.logger.info("Bridge background tasks started. Running... (Press Ctrl+C to stop)")
|
|
|
|
try:
|
|
while not self.shutdown_event.is_set():
|
|
time.sleep(1)
|
|
|
|
except Exception as e:
|
|
self.logger.critical(f"Unexpected error in main bridge loop: {e}", exc_info=True)
|
|
finally:
|
|
self.logger.info("Main loop exiting. Initiating shutdown sequence...")
|
|
self.stop()
|
|
|
|
def stop(self):
|
|
if self.shutdown_event.is_set():
|
|
return
|
|
|
|
self.logger.info("Signaling shutdown to all components...")
|
|
self.shutdown_event.set()
|
|
|
|
self.logger.info(f"Stopping {len(self.handlers)} handlers...")
|
|
for handler in reversed(self.handlers):
|
|
try:
|
|
handler.stop()
|
|
except Exception as e:
|
|
self.logger.error(f"Error stopping handler: {e}", exc_info=True)
|
|
|
|
self.logger.info("Bridge shutdown sequence complete.")
|