178 lines
7.2 KiB
Python
178 lines
7.2 KiB
Python
# import paho.mqtt.client as mqtt
|
|
# import uuid
|
|
# import time
|
|
# import threading
|
|
# import socket
|
|
|
|
# class MqttClient:
|
|
# """
|
|
# Handles the connection and message processing for a single MQTT station.
|
|
# This is a standard Python class, with no GUI dependencies.
|
|
# """
|
|
# def __init__(self, broker, port, user, password, station_id, on_message_callback):
|
|
# self.broker = broker
|
|
# self.port = port
|
|
# self.user = user
|
|
# self.password = password
|
|
# self.station_id = station_id
|
|
# self.on_message_callback = on_message_callback
|
|
|
|
# unique_id = str(uuid.uuid4())
|
|
# self.client_id = f"WebApp-Backend-{self.station_id}-{unique_id}"
|
|
|
|
# self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, self.client_id)
|
|
|
|
# # Assign callback functions
|
|
# self.client.on_connect = self.on_connect
|
|
# self.client.on_message = self.on_message
|
|
# self.client.on_disconnect = self.on_disconnect
|
|
|
|
# if self.user and self.password:
|
|
# self.client.username_pw_set(self.user, self.password)
|
|
|
|
# self.is_connected = False
|
|
# self.reconnect_delay = 1
|
|
# self.max_reconnect_delay = 60
|
|
# self.stop_thread = False
|
|
|
|
# # --- CORRECTED CALLBACK SIGNATURES ---
|
|
# def on_connect(self, client, userdata, flags, reason_code, properties):
|
|
# """Callback for when the client connects to the broker."""
|
|
# if reason_code == 0:
|
|
# self.is_connected = True
|
|
# self.reconnect_delay = 1
|
|
# print(f"Successfully connected to MQTT broker for station: {self.station_id}")
|
|
# topic_base = f"VEC/batterySmartStation/v100/{self.station_id}/#"
|
|
# # topic_base = f"VEC/batterySmartStation/v100/+/+"
|
|
# self.client.subscribe(topic_base)
|
|
# print(f"Subscribed to: {topic_base}")
|
|
# else:
|
|
# print(f"Failed to connect to MQTT for station {self.station_id}, return code {reason_code}")
|
|
|
|
# def on_disconnect(self, client, userdata, disconnect_flags, reason_code, properties):
|
|
# """Callback for when the client disconnects."""
|
|
# print(f"Disconnected from MQTT for station {self.station_id}. Will attempt to reconnect...")
|
|
|
|
# def on_message(self, client, userdata, msg):
|
|
# """Callback for when a message is received from the broker."""
|
|
# try:
|
|
# self.on_message_callback(self.station_id, msg.topic, msg.payload)
|
|
# except Exception as e:
|
|
# print(f"Error processing message in callback for topic {msg.topic}: {e}")
|
|
|
|
# def connect(self):
|
|
# """Connects the client to the MQTT broker."""
|
|
# print(f"Attempting to connect to {self.broker}:{self.port} with client ID: {self.client_id}")
|
|
# try:
|
|
# self.client.connect(self.broker, self.port, 60)
|
|
# except Exception as e:
|
|
# print(f"Error connecting to MQTT for station {self.station_id}: {e}")
|
|
|
|
# def start(self):
|
|
# """Starts the MQTT client's network loop in a separate thread."""
|
|
# self.connect()
|
|
# self.client.loop_start()
|
|
|
|
# def stop(self):
|
|
# """Stops the MQTT client's network loop."""
|
|
# print(f"Stopping MQTT client for station: {self.station_id}")
|
|
# self.client.loop_stop()
|
|
|
|
|
|
|
|
|
|
|
|
import paho.mqtt.client as mqtt
|
|
import uuid
|
|
import time
|
|
import threading
|
|
import socket
|
|
|
|
class MqttClient:
|
|
"""
|
|
Handles the connection and message processing for a single MQTT station.
|
|
This is a standard Python class, with no GUI dependencies.
|
|
"""
|
|
def __init__(self, broker, port, user, password, station_id, on_message_callback):
|
|
self.broker = broker
|
|
self.port = port
|
|
self.user = user
|
|
self.password = password
|
|
self.station_id = station_id
|
|
self.on_message_callback = on_message_callback
|
|
|
|
unique_id = str(uuid.uuid4())
|
|
self.client_id = f"WebApp-Backend-{self.station_id}-{unique_id}"
|
|
|
|
self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, self.client_id)
|
|
|
|
# Assign callback functions
|
|
self.client.on_connect = self.on_connect
|
|
self.client.on_message = self.on_message
|
|
self.client.on_disconnect = self.on_disconnect
|
|
|
|
if self.user and self.password:
|
|
self.client.username_pw_set(self.user, self.password)
|
|
|
|
self.is_connected = False
|
|
self.stop_thread = False # <-- We will use this flag
|
|
|
|
# --- (Your on_connect, on_disconnect, and on_message methods stay the same) ---
|
|
def on_connect(self, client, userdata, flags, reason_code, properties):
|
|
"""Callback for when the client connects to the broker."""
|
|
if reason_code == 0:
|
|
self.is_connected = True
|
|
print(f"Successfully connected to MQTT broker for station: {self.station_id}")
|
|
topic_base = f"VEC/batterySmartStation/v100/{self.station_id}/#"
|
|
self.client.subscribe(topic_base)
|
|
print(f"Subscribed to: {topic_base}")
|
|
else:
|
|
print(f"Failed to connect to MQTT for station {self.station_id}, return code {reason_code}")
|
|
|
|
def on_disconnect(self, client, userdata, disconnect_flags, reason_code, properties):
|
|
"""Callback for when the client disconnects."""
|
|
self.is_connected = False
|
|
# Only print reconnect message if it wasn't a deliberate stop
|
|
if not self.stop_thread:
|
|
print(f"Disconnected from MQTT for station {self.station_id}. Will attempt to reconnect...")
|
|
else:
|
|
print(f"Intentionally disconnected from MQTT for station {self.station_id}.")
|
|
|
|
|
|
def on_message(self, client, userdata, msg):
|
|
"""Callback for when a message is received from the broker."""
|
|
try:
|
|
self.on_message_callback(self.station_id, msg.topic, msg.payload)
|
|
except Exception as e:
|
|
print(f"Error processing message in callback for topic {msg.topic}: {e}")
|
|
|
|
def run(self):
|
|
"""A blocking loop that handles connection and reconnection."""
|
|
while not self.stop_thread:
|
|
try:
|
|
print(f"Attempting to connect to {self.broker}:{self.port} for station {self.station_id}")
|
|
self.client.connect(self.broker, self.port, 60)
|
|
self.client.loop_forever() # This is a blocking call
|
|
break # Exit loop if loop_forever finishes cleanly
|
|
except socket.error as e:
|
|
print(f"Connection error for {self.station_id}: {e}. Retrying in 5 seconds...")
|
|
time.sleep(5)
|
|
except Exception as e:
|
|
print(f"An unexpected error occurred for {self.station_id}: {e}. Retrying in 5 seconds...")
|
|
time.sleep(5)
|
|
|
|
def start(self):
|
|
"""Starts the MQTT client's network loop in a separate thread."""
|
|
# --- CHANGED ---
|
|
# We now run our custom `run` method in a thread
|
|
main_thread = threading.Thread(target=self.run)
|
|
main_thread.daemon = True
|
|
main_thread.start()
|
|
|
|
def stop(self):
|
|
"""Stops the MQTT client's network loop."""
|
|
# --- CHANGED ---
|
|
# This is the complete, correct way to stop the client
|
|
print(f"Stopping MQTT client for station: {self.station_id}")
|
|
self.stop_thread = True
|
|
self.client.disconnect() # This tells the client to disconnect gracefully |