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
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
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.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.value(0)
time.sleep(0.5)
bee_power_pin.value(1)
@ -43,7 +42,7 @@ class CellularModem:
if not res:
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 = []
async with self._lock:
while self.uart.any():
@ -56,9 +55,20 @@ class CellularModem:
lines.append(raw_line)
if raw_line == b'ERROR\r\n':
raise ModemErrorResponse(code=(command, lines))
if len(lines) and lines[-1] == b'OK\r\n':
break
response = tuple(x for x in [x.decode().strip('\r\n') for x in lines] if len(x))
if len(lines):
print(raw_line)
if expecing_plus:
if lines[-1].decode().startswith('+'):
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))
else:
response = lines
if require_ok:
if response[-1] != 'OK':
raise ModemErrorResponse(code=(command, lines))
@ -70,7 +80,7 @@ cellular = CellularModem()
def _parse_csq(csq_value: int):
if csq_value == 99:
return 'disconnected'
return 'unknown'
elif csq_value == 31:
return '51 dBm or greater'
elif csq_value == 0:
@ -84,7 +94,7 @@ def _parse_csq(csq_value: int):
async def cellular_wake_modem():
i = 5
i = 2
while i > 0:
resp = await cellular.send_command('AT')
if len(resp) == 1 and resp[0] == 'OK':
@ -98,7 +108,11 @@ async def cellular_wake_modem():
async def cellular_wait_cpsi():
while True:
cpsi_resp = await cellular.send_command('AT+CPSI?')
parts = cpsi_resp[0].lstrip('+CPSI: ').split(',')
try:
parts = cpsi_resp[0].lstrip('+CPSI: ').split(',')
except:
print(cpsi_resp)
raise
if parts[1] == 'Online':
return True, parts
elif parts[1] == 'Low Power Mode':
@ -140,20 +154,13 @@ async def cellular_signal_strength():
return signal_strength
async def cellular_ip():
@timeout(3)
async def inner():
try:
await cellular.send_command('AT+IPADDR')
except ModemErrorResponse as e:
if 'Network not opened' in e.lines[0]:
return '0.0.0.0'
async def cellular_ip() -> str:
try:
ip = await inner()
except uTimeoutError:
ip = '0.0.0.0'
return ip
ip_resp = await cellular.send_command('AT+IPADDR')
if ip_resp[0].startswith('+IPADDR: '):
return ip_resp[0].strip('+IPADDR: ')
except ModemErrorResponse:
return '0.0.0.0'
async def cellular_check_service_ready():
@ -165,10 +172,6 @@ async def cellular_check_service_ready():
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)
bee_power_pin.value(0)
time.sleep(0.5)
@ -192,8 +195,17 @@ async def cellular_check_connected():
@timeout(CELLULAR_STARTUP_TIMEOUT)
async def start_modem():
while True:
if (await run_with_timeout(func=cellular_wake_modem, timeout_sec=30)).failure:
logger('Modem wake-up timed out', source='CELL', level=LogLevel.error)
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)
failures += 1
if failures == 11:
machine.reset()
await restart_modem()
continue
except ModemErrorResponse:
# Sporadic ERROR responses
await restart_modem()
continue
@ -239,24 +251,108 @@ async def start_modem():
await restart_modem()
continue
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+CIPMODE=0', require_ok=True)
await cellular.send_command('AT+NETOPEN', require_ok=True)
break
try:
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+CIPMODE=0', require_ok=True)
# await cellular.send_command('AT+CNMP=38', require_ok=True)
await cellular.send_command('AT+NETOPEN', require_ok=True)
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('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():
logger('Initalizing modem', source='CELL')
while True:
try:
gc.collect()
await start_modem()
async def inner():
while True:
try:
gc.collect()
await start_modem()
except uTimeoutError:
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
except uTimeoutError:
await asyncio.sleep(10)
while True:
x = await run_with_timeout(func=inner, timeout_sec=300)
if not x.failure:
break
gc.collect()
await cellular_send_http('http://postman-echo.com/ip', 'get')
# 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())