Refractor to use feasycom_ble

This commit is contained in:
Odd Stråbø 2021-11-05 06:51:35 +01:00
parent 30246b9355
commit c91c819a42

View file

@ -5,10 +5,13 @@ import datetime
import struct
import sys
import time
from io import RawIOBase
from bluepy import btle
from libscrc import modbus
from feasycom_ble import BTLEUart
MAC = "DC:0D:30:9C:61:BA"
INTERVAL = 15
@ -158,72 +161,51 @@ CMD_ = b"\xff\x78\x00\x00\x00\x01"
STATUS = {}
def parsePacket(data):
timestamp = datetime.datetime.utcnow().isoformat(" ")
# prefix = data[0]
operation = data[1]
cc = data[2]
res = None
if operation == 3:
if cc == 0x0E: # GET_BATTERY_STATE
res = dict(
zip(
(
"battery_charge",
"battery_voltage",
"battery_current",
"_internal_temperature?",
"battery_temperature",
"load_voltage",
"load_current",
"load_power",
),
struct.unpack("!xxxHHHbbHHHxx", data),
)
)
res["battery_voltage"] /= 10
res["battery_current"] /= 100
res["load_voltage"] /= 10
res["load_current"] /= 100
STATUS.update(res)
# GET_BATTERY_STATE
def parse_battery_state(data: bytes) -> dict:
res = dict(
zip(
(
"battery_charge",
"battery_voltage",
"battery_current",
"_internal_temperature?",
"battery_temperature",
"load_voltage",
"load_current",
"load_power",
),
struct.unpack("!HHHbbHHH", data),
)
)
res["battery_voltage"] /= 10
res["battery_current"] /= 100
res["load_voltage"] /= 10
res["load_current"] /= 100
STATUS.update(res)
elif cc == 0x08: # GET_PANEL_STATUS (OR version)
res = dict(
zip(
("panel_voltage", "panel_current", "panel_power", "load_enabled"),
struct.unpack("!xxxHHHx?xx", data),
)
)
res["panel_voltage"] /= 10
res["panel_current"] /= 100
STATUS.update(res)
elif operation == 6 and cc == 1:
res = dict(zip(("load_enabled",), struct.unpack("!xxxxx?xx", data)))
STATUS.update(res)
if res:
print(timestamp, res)
return res
print(timestamp, data)
sys.stdout.flush()
log(str(res))
return res
class Delegate(btle.DefaultDelegate):
data = bytearray()
# GET_PANEL_STATUS
def parse_panel_status(data: bytes) -> dict:
res = dict(
zip(
("panel_voltage", "panel_current", "panel_power", "load_enabled"),
struct.unpack("!HHHx?", data),
)
)
res["panel_voltage"] /= 10
res["panel_current"] /= 100
STATUS.update(res)
def handleNotification(self, cHandle, data):
# print(cHandle, data, dlen)
# elif operation == 6 and cc == 1:
# res = dict(zip(("load_enabled",), struct.unpack("!xxxxx?xx", data)))
# STATUS.update(res)
self.data.extend(data)
c_crc = modbus(bytes(self.data[:-2]))
# byte order is inverted in regards to libscrc output
d_crc = self.data[-1] << 8 | self.data[-2]
# print(hex(c_crc), hex(d_crc))
if c_crc == d_crc:
parsePacket(self.data)
self.data.clear()
log(str(res))
return res
def write(fh, data):
@ -238,18 +220,6 @@ def construct_request(address, words=1, action=ACTION_READ, marker=0xFF):
return struct.pack("!BBHH", marker, action, address, words)
def poll(dev: btle.Peripheral, timeout: float = 1) -> bool:
start = time.time()
while not dev.waitForNotifications(0.2):
if time.time() < start + timeout:
return False
while dev.waitForNotifications(0.2):
pass
return True
def log(string: str):
print(datetime.datetime.utcnow().isoformat(" "), string)
sys.stdout.flush()
@ -275,51 +245,50 @@ def parse_packet(data):
return payload
def readMemory(fh: RawIOBase, address: int, words: int = 1):
write(fh, construct_request(address, words=words))
header = fh.read(3)
if header and len(header) == 3:
tag, operation, size = header
data = fh.read(size)
_crc = fh.read(2)
if data and _crc:
crc = struct.unpack_from("<H", _crc)[0]
calculated_crc = modbus(bytes([tag, operation, size, *data]))
if crc == calculated_crc:
return data
if __name__ == "__main__":
dlgt = Delegate()
prev = time.time() - INTERVAL
while True:
try:
log("Connecting...")
with btle.Peripheral(MAC).withDelegate(dlgt) as dev:
from feasycom_ble import WRITE_DEVICE
wd = dev.getCharacteristics(uuid=WRITE_DEVICE)[0]
with BTLEUart(MAC, timeout=10) as dev:
log("Connected.")
poll(dev)
write(wd, construct_request(0, 32))
poll(dev)
poll(dev)
poll(dev)
# write(dev, construct_request(0, 32))
# Memory dump
# for address in range(0, 0x10000, 16):
# log(f"Reading 0x{address:04X}...")
# write(wd, construct_request(address, 16))
# poll(dev)
# poll(dev)
# poll(dev)
# poll(dev)
# poll(dev)
while True:
poll(dev)
now = time.time()
diff = now - prev
if diff >= INTERVAL:
prev += INTERVAL
write(wd, construct_request(0x0107, 4)) # CMD_GET_PANEL_STATUS
poll(dev)
res = readMemory(dev, 0x0107, 4) # CMD_GET_PANEL_STATUS
if res:
parse_panel_status(res)
write(wd, construct_request(0x0100, 7)) # CMD_GET_BATTERY_STATE
poll(dev)
res = readMemory(dev, 0x0100, 7) # CMD_GET_BATTERY_STATE
if res:
parse_battery_state(res)
# if STATUS.get('load_enabled'):
# write(wd, CMD_DISABLE_LOAD)