A bit of cleanup. StreamWrapper still isn't working properly

This commit is contained in:
Jono Targett 2026-03-15 18:14:25 +10:30
parent b7bd9af807
commit 81791d67a9
2 changed files with 52 additions and 31 deletions

View File

@ -10,6 +10,7 @@ from ubxhandler import UBXHandler
BAUD = 115200 BAUD = 115200
async def main(): async def main():
handler_id = "example-gps" handler_id = "example-gps"
mqtt_host = "127.0.0.1" mqtt_host = "127.0.0.1"
@ -24,10 +25,10 @@ async def main():
) )
serial_port = aioserial.AioSerial( serial_port = aioserial.AioSerial(
port="/tmp/ttyV0", port="/tmp/ttyV0",
baudrate=BAUD, baudrate=BAUD,
timeout=0.05, # 50 ms timeout=0.05, # 50 ms
) )
handler = UBXHandler(mqtt_client, "example-gps", serial_port) handler = UBXHandler(mqtt_client, "example-gps", serial_port)
await handler.run() await handler.run()

View File

@ -7,36 +7,48 @@ from command import command
from handler import MQTTHandler, task from handler import MQTTHandler, task
class StreamWrapper:
def __init__(self):
self.buffer = bytearray()
def read(self, n=1):
if not self.buffer:
raise BlockingIOError
out = self.buffer[:n]
del self.buffer[:n]
return bytes(out)
def readline(self):
"""Return bytes up to and including the first newline."""
newline_index = self.buffer.find(b"\n")
if newline_index == -1:
# No newline yet, mimic non-blocking behavior
raise BlockingIOError
# Include the newline
line = self.buffer[: newline_index + 1]
del self.buffer[: newline_index + 1]
return bytes(line)
def extend(self, chunk):
self.buffer.extend(chunk)
class UBXHandler(MQTTHandler): class UBXHandler(MQTTHandler):
def __init__( def __init__(
self, self,
mqtt_client: aiomqtt.Client, mqtt_client: aiomqtt.Client,
handler_id: str, handler_id: str,
serial_port: aioserial.AioSerial serial_port: aioserial.AioSerial,
): ):
super().__init__(mqtt_client, handler_id) super().__init__(mqtt_client, handler_id)
self.serial_port = serial_port self.serial_port = serial_port
@command({"type": "number"}, description="An example command") async def read_serial(self):
async def example_cmd(args): buffer = StreamWrapper()
print(f"Executing command with args {args}") ubr = pyubx2.UBXReader(buffer, parsing=True)
async def parse_serial(self):
buffer = bytearray()
class StreamWrapper:
def read(inner_self, n=1):
if not buffer:
raise BlockingIOError
out = buffer[:n]
del buffer[:n]
return bytes(out)
ubr = pyubx2.UBXReader(StreamWrapper(), parsing=True)
while True: while True:
chunk = await self.serial_port.read_async(200) chunk = await self.serial_port.read_async(256)
if chunk: if chunk:
buffer.extend(chunk) buffer.extend(chunk)
@ -45,18 +57,26 @@ class UBXHandler(MQTTHandler):
raw, parsed = ubr.read() raw, parsed = ubr.read()
if raw is None: if raw is None:
break break
yield raw, parsed yield parsed
except (pyubx2.UBXStreamError, BlockingIOError, Exception): except BlockingIOError:
pass pass # ordinary behaviour
except (pyubx2.UBXStreamError, Exception) as e:
print("Some kinda error: ", type(e), e)
else: else:
await asyncio.sleep(0) await asyncio.sleep(0)
@task @task
async def serial_reader_task(self): async def handle_ubx_messages(self):
async for raw, parsed in self.parse_serial(): async for message in self.read_serial():
if isinstance(parsed, pyubx2.UBXMessage): if isinstance(message, pyubx2.UBXMessage):
for name, value in vars(parsed).items(): for name, value in vars(message).items():
# Skip 'private' members
if name.startswith("_"): if name.startswith("_"):
continue continue
topic = f"{self.topic_base}/{parsed.identity}/{name}"
topic = f"{self.topic_base}/{message.identity}/{name}"
await self.mqtt_client.publish(topic, value, qos=1, retain=True) await self.mqtt_client.publish(topic, value, qos=1, retain=True)
@command({"type": "number"}, description="An example command")
async def example_cmd(args):
print(f"Executing command with args {args}")