m2m-python/m2m/misc/at_parser.py
2026-02-19 08:14:53 +01:00

69 lines
2.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Helper for parsing AT command responses.
"""
import logging
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from m2m.serial.serial_port import SerialPort
logger = logging.getLogger('atparser')
class AtParser:
"""
Parses responses from the serial port to determine command success/failure.
"""
def __init__(self, serial_port: 'SerialPort'):
self._port = serial_port
self._last_response = b''
@property
def last_response(self) -> bytes:
return self._last_response
def read_ok(self, timeout: float = 1.0) -> bool:
"""
Reads until a terminator is found and checks if it was 'OK'.
"""
self._last_response = self._port.read_until(terminator=b'OK', timeout=timeout)
# Check if the buffer *ends* with OK, or contains it on a line.
# Strict check:
lines = self._last_response.splitlines()
for line in reversed(lines):
line = line.strip()
if line == b'OK':
return True
if line == b'ERROR' or b'CME ERROR' in line:
return False
return False
def is_on(self, query_cmd: bytes, response_prefix: bytes, timeout: float = 1.0) -> bool:
"""
Sends a query and checks if the value is '1'.
Example: is_on(b'AT+CFUN?', b'+CFUN:')
"""
self._port.send_cmd(query_cmd)
response = self._port.read_until(timeout=timeout)
self._last_response = response
# Parse for prefix
for line in response.splitlines():
line = line.strip()
if line.startswith(response_prefix):
# +CFUN: 1
try:
# Remove prefix, then split by comma if multiple params
# We assume the first param is the status
payload = line[len(response_prefix):].strip()
# Handle cases like "1" or "1,0"
val_str = payload.split(b',')[0]
return int(val_str) == 1
except ValueError:
pass
return False