attempt at cell

This commit is contained in:
Cyberes 2024-06-30 15:20:43 -06:00
parent 6bc9f9c36c
commit 50ddf2c72e
2 changed files with 138 additions and 41 deletions

View File

@ -9,4 +9,5 @@ cp build/mpy-cross <project root>
``` ```
The `upload.sh` script will manage building this MicroPython project. If you get an error on the `Erase` step, that's The `upload.sh` script will manage building this MicroPython project. If you get an error on the `Erase` step, that's
fine and due to the files not existing to be erased. fine and due to the files not existing to be erased. Make sure you aren't connected to the device's serial port when
running the script.

View File

@ -5,7 +5,7 @@ import time
import machine import machine
from machine import Pin from machine import Pin
from config import CELLULAR_APN, CELLULAR_STARTUP_TIMEOUT from config import CELLULAR_APN, CELLULAR_STARTUP_TIMEOUT, TRACCAR_CONN_MODE
from lib.logging import logger, LogLevel from lib.logging import logger, LogLevel
from lib.runtime import timeout, uTimeoutError, run_with_timeout from lib.runtime import timeout, uTimeoutError, run_with_timeout
@ -15,7 +15,6 @@ PIN_BEE_UART_TXD = 2
bee_power_pin = Pin(PIN_BEE_POWER, Pin.OUT) bee_power_pin = Pin(PIN_BEE_POWER, Pin.OUT)
bee_power_pin.value(0) bee_power_pin.value(0)
time.sleep(0.5)
bee_power_pin.value(1) bee_power_pin.value(1)
@ -43,7 +42,7 @@ class CellularModem:
if not res: if not res:
raise OSError("Modem not responding") raise OSError("Modem not responding")
async def send_command(self, command, require_ok: bool = False) -> tuple: async def send_command(self, command, require_ok: bool = False, expecing_plus: bool = False, read_until: bytes = None, clean_lines: bool = True) -> tuple:
lines = [] lines = []
async with self._lock: async with self._lock:
while self.uart.any(): while self.uart.any():
@ -56,9 +55,20 @@ class CellularModem:
lines.append(raw_line) lines.append(raw_line)
if raw_line == b'ERROR\r\n': if raw_line == b'ERROR\r\n':
raise ModemErrorResponse(code=(command, lines)) raise ModemErrorResponse(code=(command, lines))
if len(lines) and lines[-1] == b'OK\r\n': if len(lines):
print(raw_line)
if expecing_plus:
if lines[-1].decode().startswith('+'):
break break
elif read_until:
if lines[-1] == read_until:
break
elif lines[-1] == b'OK\r\n':
break
if clean_lines:
response = tuple(x for x in [x.decode().strip('\r\n') for x in lines] if len(x)) response = tuple(x for x in [x.decode().strip('\r\n') for x in lines] if len(x))
else:
response = lines
if require_ok: if require_ok:
if response[-1] != 'OK': if response[-1] != 'OK':
raise ModemErrorResponse(code=(command, lines)) raise ModemErrorResponse(code=(command, lines))
@ -70,7 +80,7 @@ cellular = CellularModem()
def _parse_csq(csq_value: int): def _parse_csq(csq_value: int):
if csq_value == 99: if csq_value == 99:
return 'disconnected' return 'unknown'
elif csq_value == 31: elif csq_value == 31:
return '51 dBm or greater' return '51 dBm or greater'
elif csq_value == 0: elif csq_value == 0:
@ -84,7 +94,7 @@ def _parse_csq(csq_value: int):
async def cellular_wake_modem(): async def cellular_wake_modem():
i = 5 i = 2
while i > 0: while i > 0:
resp = await cellular.send_command('AT') resp = await cellular.send_command('AT')
if len(resp) == 1 and resp[0] == 'OK': if len(resp) == 1 and resp[0] == 'OK':
@ -98,7 +108,11 @@ async def cellular_wake_modem():
async def cellular_wait_cpsi(): async def cellular_wait_cpsi():
while True: while True:
cpsi_resp = await cellular.send_command('AT+CPSI?') cpsi_resp = await cellular.send_command('AT+CPSI?')
try:
parts = cpsi_resp[0].lstrip('+CPSI: ').split(',') parts = cpsi_resp[0].lstrip('+CPSI: ').split(',')
except:
print(cpsi_resp)
raise
if parts[1] == 'Online': if parts[1] == 'Online':
return True, parts return True, parts
elif parts[1] == 'Low Power Mode': elif parts[1] == 'Low Power Mode':
@ -140,21 +154,14 @@ async def cellular_signal_strength():
return signal_strength return signal_strength
async def cellular_ip(): async def cellular_ip() -> str:
@timeout(3)
async def inner():
try: try:
await cellular.send_command('AT+IPADDR') ip_resp = await cellular.send_command('AT+IPADDR')
except ModemErrorResponse as e: if ip_resp[0].startswith('+IPADDR: '):
if 'Network not opened' in e.lines[0]: return ip_resp[0].strip('+IPADDR: ')
except ModemErrorResponse:
return '0.0.0.0' return '0.0.0.0'
try:
ip = await inner()
except uTimeoutError:
ip = '0.0.0.0'
return ip
async def cellular_check_service_ready(): async def cellular_check_service_ready():
resp = await cellular.send_command('AT+CGATT?') resp = await cellular.send_command('AT+CGATT?')
@ -165,10 +172,6 @@ async def cellular_check_service_ready():
async def restart_modem(): async def restart_modem():
async def reset():
await cellular.send_command('ATZ', require_ok=True)
await run_with_timeout(func=reset, timeout_sec=2)
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
bee_power_pin.value(0) bee_power_pin.value(0)
time.sleep(0.5) time.sleep(0.5)
@ -192,8 +195,17 @@ async def cellular_check_connected():
@timeout(CELLULAR_STARTUP_TIMEOUT) @timeout(CELLULAR_STARTUP_TIMEOUT)
async def start_modem(): async def start_modem():
while True: while True:
if (await run_with_timeout(func=cellular_wake_modem, timeout_sec=30)).failure: failures = -1
try:
if (await run_with_timeout(func=cellular_wake_modem, timeout_sec=5)).failure:
logger('Modem wake-up timed out', source='CELL', level=LogLevel.error) logger('Modem wake-up timed out', source='CELL', level=LogLevel.error)
failures += 1
if failures == 11:
machine.reset()
await restart_modem()
continue
except ModemErrorResponse:
# Sporadic ERROR responses
await restart_modem() await restart_modem()
continue continue
@ -239,24 +251,108 @@ async def start_modem():
await restart_modem() await restart_modem()
continue continue
try:
await cellular.send_command(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"', require_ok=True) await cellular.send_command(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"', require_ok=True)
await cellular.send_command('AT+CSOCKSETPN=1', require_ok=True) await cellular.send_command('AT+CSOCKSETPN=1', require_ok=True)
await cellular.send_command('AT+CIPMODE=0', require_ok=True) await cellular.send_command('AT+CIPMODE=0', require_ok=True)
# await cellular.send_command('AT+CNMP=38', require_ok=True)
await cellular.send_command('AT+NETOPEN', require_ok=True) await cellular.send_command('AT+NETOPEN', require_ok=True)
break break
except ModemErrorResponse as e:
print(e)
await restart_modem()
break
ip_get = await run_with_timeout(func=cellular_ip, timeout_sec=3)
if not ip_get.failure:
logger(f'IP: {ip_get.result}', source='CELL')
else:
logger(f'IP: 0.0.0.0', source='CELL')
logger(f'IP: {await cellular_ip()}', source='CELL')
logger(f'Signal strength: {await cellular_signal_strength()}', source='CELL') logger(f'Signal strength: {await cellular_signal_strength()}', source='CELL')
logger('Modem initialized', source='CELL')
async def cellular_start_http():
try:
await cellular.send_command('AT+HTTPINIT')
return True
except ModemErrorResponse:
return False
async def start_modem_task(): async def start_modem_task():
logger('Initalizing modem', source='CELL') logger('Initalizing modem', source='CELL')
async def inner():
while True: while True:
try: try:
gc.collect() gc.collect()
await start_modem() await start_modem()
break
except uTimeoutError: except uTimeoutError:
await asyncio.sleep(10) await asyncio.sleep(10)
continue
if TRACCAR_CONN_MODE == 'http':
await asyncio.sleep(0.5)
success = False
for i in range(30):
httpinit = await run_with_timeout(func=cellular_start_http, timeout_sec=5)
if httpinit.failure:
logger('AT+HTTPINIT timeout', source='CELL', level=LogLevel.error)
await restart_modem()
continue
if not httpinit.result:
logger('AT+HTTPINIT failure', source='CELL', level=LogLevel.error)
await restart_modem()
continue
else:
success = True
if not success:
continue
break
while True:
x = await run_with_timeout(func=inner, timeout_sec=300)
if not x.failure:
break
gc.collect() gc.collect()
await cellular_send_http('http://postman-echo.com/ip', 'get')
# TODO: loop to reconnect modem # TODO: loop to reconnect modem
@timeout(10)
async def cellular_send_http(url: str, method: str, data: str = None):
m = method.upper()
if m == 'GET':
mode = 0
elif m == 'POST':
if not data:
raise Exception
mode = 1
else:
raise Exception
await cellular.send_command(f'AT+HTTPPARA="URL","{url}"')
_, resp = await cellular.send_command(f'AT+HTTPACTION={mode}', expecing_plus=True)
_, status_code, data_len = resp.strip('+HTTPACTION: ').split(',')
if status_code != '200':
logger(f'HTTP {m} failed: {status_code}', source='CELL', level=LogLevel.error)
return
data = await cellular.send_command(f'AT+HTTPREAD={data_len}', read_until=b'+HTTPREAD:0\r\n', clean_lines=False)
if data[0] != b'OK\r\n':
raise Exception
data = list(data)
del data[0]
del data[0]
del data[-1]
print(data)
asyncio.run(start_modem_task())