2 次代码提交 b31cd92caf ... 56a50038f2

作者 SHA1 备注 提交日期
  subDesTagesMitExtraKaese b31cd92caf fix unhandled exceptions on mqtt disconnect 1 年之前
  subDesTagesMitExtraKaese 20a4601f8d replace paho-mqtt with aiomqtt 1 年之前
共有 4 个文件被更改,包括 45 次插入37 次删除
  1. 1 1
      README.md
  2. 4 10
      bleclient.py
  3. 38 24
      main.py
  4. 2 2
      requirements.txt

+ 1 - 1
README.md

@@ -10,7 +10,7 @@ The application establishes a connection to the MQTT broker and the BLE device,
 
 - Python 3.7+
 - [Bleak](https://github.com/hbldh/bleak) - A BLE library for Python
-- [aiomqtt](https://github.com/sbtinstruments/aiomqtt) - A MQTT library for Python
+- [Paho MQTT](https://github.com/eclipse/paho.mqtt.python) - A MQTT library for Python
 
 ## Installation
 

+ 4 - 10
bleclient.py

@@ -14,7 +14,7 @@ class BleClient:
 
     def __init__(self, mac_address: str):
         self.client = BleakClient(mac_address)
-        self.details_queue = asyncio.Queue()  # Queue to store the received details
+        self.on_details_received = lambda v: print(v)  # Callback function to handle received details
 
     async def __aenter__(self):
         await self.client.connect()  # Connect to the BLE device
@@ -36,7 +36,7 @@ class BleClient:
         #print("write ", self.WRITE_UUID, data.hex())
         await self.client.write_gatt_char(self.WRITE_UUID, data)  # Write the data to the BLE device
 
-    async def notification_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray):
+    def notification_handler(self, characteristic: BleakGATTCharacteristic, data: bytearray):
         if characteristic.uuid != self.NOTIFY_UUID:
             return
         self.buffer += data  # Append the received data to the buffer
@@ -55,7 +55,7 @@ class BleClient:
             return
         if len(self.buffer) == 91:
             response = BleClient.parse_details_response(self.buffer)  # Parse the details response from the buffer
-            self.details_queue.put_nowait(response)  # Add the parsed response to the queue
+            self.on_details_received(response)  # Call the callback function with the parsed response
             self.buffer = bytearray()
         if len(self.buffer) >= 91:
             print(f"received too many bytes ({len(self.buffer)})")
@@ -78,13 +78,7 @@ class BleClient:
         return "".join(map(chr, device_name))
 
     async def request_details(self):
-        self.details_queue = asyncio.Queue()  # Clear the queue
-        i = 0
-        while self.details_queue.empty() and i < 10:
-            i += 1
-            await self.write(0xFE043030002bbf1a)  # Send a request for details to the BLE device
-            await asyncio.sleep(0.1)  # Wait for the response to be received
-        return await self.details_queue.get()  # Return the first item in the queue
+        await self.write(0xFE043030002bbf1a)  # Send a request for details to the BLE device
 
     @staticmethod
     def solar_panel_charge_state(v: int):

+ 38 - 24
main.py

@@ -5,15 +5,23 @@ import asyncio
 import signal
 import json
 
-import aiomqtt
+import paho.mqtt.client as mqtt
 from bleak.exc import BleakError, BleakDeviceNotFoundError
 
 from bleclient import BleClient
 
+client = mqtt.Client()
 send_config = True
-reconnect_interval = 5  # In seconds
 
-async def mqtt_publish(details: dict[str, any], client: aiomqtt.Client):
+def details_handler(details):
+    if details:
+        print(f"Battery: {details['battery_percentage']}% ({details['battery_voltage']}V)")
+        mqtt_publish(details, client)
+    else:
+        print("No values recieved")
+
+
+def mqtt_publish(details, client):
     global send_config
     # Define the base topic for MQTT Discovery
     base_topic = "homeassistant"
@@ -62,41 +70,47 @@ async def mqtt_publish(details: dict[str, any], client: aiomqtt.Client):
 
         # Publish the MQTT Discovery payload
         if send_config:
-            print(f"Publishing MQTT Discovery payload for {key}")
-            await client.publish(topic, payload=json.dumps(payload), retain=True)
+            client.publish(topic, payload=json.dumps(payload), retain=True)
 
         # Publish the entity state
-        await client.publish(state_topic, payload=str(value))
+        client.publish(state_topic, payload=str(value))
     send_config = False
     
 async def main(address, host, port, username, password):
+    client.username_pw_set(username, password)  # Set MQTT username and password
+
     async def run_mppt():
         while True:
             try:
-                async with aiomqtt.Client(hostname=host, port=port, username=username, password=password) as client:
-                    print(f"Connecting to MQTT broker at {host}:{port}")
+                client.connect(host, port)  # Connect to the MQTT broker
+                break  # Connection successful, exit the loop
+
+            except asyncio.CancelledError:
+                raise  # Re-raise the CancelledError to stop the task
+            except Exception as e:
+                print(f"An error occurred while connecting to MQTT broker: {e}")
+                await asyncio.sleep(5)  # Wait for 5 seconds before retrying
+
+        while True:
+            try:
+                async with BleClient(address) as mppt:
+                    mppt.on_details_received = details_handler
+                    await mppt.request_details()
+
                     while True:
+                        await asyncio.sleep(20.0)
                         try:
-                            async with BleClient(address) as mppt:
-                                while True:
-                                    details = await mppt.request_details()
-                                    if details:
-                                        print(f"Battery: {details['battery_percentage']}% ({details['battery_voltage']}V)")
-                                        await mqtt_publish(details, client)
-                                    else:
-                                        print("No values recieved")
-                                    await asyncio.sleep(20.0)
-
-                        except BleakDeviceNotFoundError:
-                            print(f"BLE device with address {address} was not found")
-                            await asyncio.sleep(5)  # Wait for 5 seconds before retrying
+                            await mppt.request_details()
                         except BleakError as e:
                             print(f"BLE error occurred: {e}")
-            except aiomqtt.MqttError as error:
-                print(f'Error "{error}". Reconnecting in {reconnect_interval} seconds.')
-                await asyncio.sleep(reconnect_interval)
+                            # Handle the BLE error accordingly, e.g., reconnect or terminate the task
+                            break
+
             except asyncio.CancelledError:
                 raise  # Re-raise the CancelledError to stop the task
+            except BleakDeviceNotFoundError:
+                print(f"BLE device with address {address} was not found")
+                await asyncio.sleep(5)  # Wait for 5 seconds before retrying
             except Exception as e:
                 print(f"An error occurred during BLE communication: {e}")
                 await asyncio.sleep(5)  # Wait for 5 seconds before retrying

+ 2 - 2
requirements.txt

@@ -1,2 +1,2 @@
-aiomqtt==1.2.1
-bleak==0.21.1
+paho-mqtt==1.6.1
+bleak==0.20.2