attempt at cell
This commit is contained in:
parent
6bc9f9c36c
commit
50ddf2c72e
|
@ -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.
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue