From b008f524bf1622c66932f0ea493c2a06d7c9807f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Thu, 18 Nov 2021 23:38:52 +0100 Subject: [PATCH] Retry on read error --- solar_ble.py | 88 ++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/solar_ble.py b/solar_ble.py index 3c843b1..234624b 100755 --- a/solar_ble.py +++ b/solar_ble.py @@ -6,7 +6,7 @@ import struct import sys import time from io import RawIOBase -from typing import Collection, Optional, cast +from typing import Callable, Collection, Optional, cast from bluepy import btle from libscrc import modbus @@ -293,6 +293,27 @@ class Periodical: return False +def try_read_parse( + dev: BTLEUart, + address: int, + words: int = 1, + parser: Callable = None, + attempts=5, +) -> Optional[dict]: + while attempts: + attempts -= 1 + res = readMemory(dev, address, words) + if res: + try: + if parser: + return parser(res) + except struct.error as e: + log(e) + log("0x0100 Unpack error:", len(res), res) + log("Flushed from read buffer; ", dev.read(timeout=0.5)) + return None + + if __name__ == "__main__": conf = get_config() consumers = get_consumers(conf) @@ -304,7 +325,7 @@ if __name__ == "__main__": while True: try: log("Connecting...") - with BTLEUart(MAC, timeout=10) as dev: + with BTLEUart(MAC, timeout=5) as dev: log("Connected.") # write(dev, construct_request(0, 32)) @@ -314,58 +335,45 @@ if __name__ == "__main__": # log(f"Reading 0x{address:04X}...") # write(wd, construct_request(address, 16)) days = 7 - res = readMemory(dev, 0x010B, 21) + res = try_read_parse(dev, 0x010B, 21, parse_historical_entry) if res: - d = parse_historical_entry(res) - log(d) + log(res) for consumer in consumers: - consumer.write(d) - days = cast(int, d.get("run_days", 7)) + consumer.write(res) + days = cast(int, res.get("run_days", 7)) for i in range(days): - res = readMemory(dev, 0xF000 + i, 10) + res = try_read_parse( + dev, 0xF000 + i, 10, parse_historical_entry + ) if res: - d = parse_historical_entry(res) - log({i: d}) + log({i: res}) for consumer in consumers: - consumer.write({str(i): d}) + consumer.write({str(i): res}) while True: now = time.time() + if per_voltages(now): - # CMD_GET_BATTERY_STATE + CMD_GET_PANEL_STATUS - res = readMemory(dev, 0x0100, 11) - if res: - try: - d = parse_battery_state(res) - log(d) - for consumer in consumers: - consumer.write(d) - except struct.error as e: - log(e) - log("0x0100 Unpack error:", len(res), res) - log( - "Flushed from read buffer; ", - dev.read(timeout=0.5), - ) + data = try_read_parse(dev, 0x0100, 11, parse_battery_state) + if data: + log(data) + for consumer in consumers: + consumer.write(data) + if per_current_hist(now): - res = readMemory(dev, 0x010B, 21) - if res: - try: - d = parse_historical_entry(res) - log(d) - for consumer in consumers: - consumer.write(d) - except struct.error as e: - log(e) - log("0x010B Unpack error:", len(res), res) - log( - "Flushed from read buffer; ", - dev.read(timeout=0.5), - ) + data = try_read_parse( + dev, 0x010B, 21, parse_historical_entry + ) + if data: + log(data) + for consumer in consumers: + consumer.write(data) + # print(".") for consumer in consumers: consumer.poll() + time.sleep(max(0, 1 - time.time() - now)) # if STATUS.get('load_enabled'):