findyIoT module
The generic LTE node of the Findy Lab ecosystem: an ESP32-WROOM-32U with
a Quectel EG915R1 modem. It has no sensor front-end of its own - the
application in last.py decides what is measured and reported; the
framework provides the modem, the parameter database, the HiGPS protocol
and the over-the-air update.
Overview
ESP32-WROOM-32U (MicroPython v1.25), deep-sleep duty cycle
Quectel EG915R1 LTE modem on UART1, 115200 baud (
findylab.modem.eg915)Status LED on GPIO 2 - lit while the firmware is awake
Serving-cell diagnostics (bearer, RSSI, RSRQ, cell ID, MCC/MNC, SINR, LAC) refreshed before every report (parameters 230-238)
Zip-based, resumable OTA update with boot-time commit and a recovery image (Over-the-air update)
Round-boundary wakeups: the sleep timer is aligned to multiples of the measurement period (
findylab.core.fw.seconds_to_next_wakeup())
Pin map
Function |
GPIO |
Notes |
|---|---|---|
Modem power rail ( |
12 |
|
Modem PWRKEY ( |
32 |
|
Modem UART TX (ESP32 side) |
25 |
|
Modem UART RX (ESP32 side) |
26 |
|
Modem RESET_N ( |
27 |
|
Modem DTR |
33 |
|
Status LED |
2 |
Driven high when |
Peripheral power |
25 |
|
Note
Deep sleep on this module is a plain machine.deepsleep() with no
wakeup pin armed - only the timer (or a hardware reset) wakes it.
findylab.core.fw.prepareSleep() therefore takes a single
argument, prepareSleep(t), unlike Logger Pro’s
prepareSleep(t, trig).
Duty cycle
The reference start() in the module’s last.py:
Wake up (timer at a round boundary of parameter 421, or reset).
wakeCount = 522 + 1. If it reached the ratio 422/421, or the wakeup was an external alarm (machine.wake_reason() == 2):report(alarm, datalist)- power the modem, register, refresh parameters 230-238, senddatalistand execute any queued server commands. Otherwise just store the new count in 522.After a successful connection: 522 = 0, 443 = server-synchronized timestamp.
prepareSleep(t)withtfromseconds_to_next_wakeup()- modem off (AT+QPOWDand the power rail), modem pins released as inputs, deep sleep.
Parameters
The module registers the following IDs in databaseParams (see
System IDs for the entry format):
IDs |
Purpose |
|---|---|
200 |
IMEI |
421 / 422 |
Wakeup period / report period (s) |
522 / 443 |
Wakeups since the last report / timestamp of the last report |
230-238 |
Network status, written by |
51, 52, 53, 54, 55 |
OTA update (Over-the-air update) |
221 / 222 / 312 |
Restart / factory reset / send current settings |
429 |
|
Default report:
datalist = ['421','443','230','231','232','234','235','236','237','238']
Files on the device
boot.py, firmware_core.mpy, last.py (or last.mpy) and
base.py - see Getting started. There is no
ulp_main.bin on this module.
Application skeleton
import machine, time, utime
import firmware_core as core
from firmware_core import fw, database, modem, protocol, device, setError
databaseParams = {
"200": ["R", 1, 0, 0, "0", "R"], # IMEI
"421": ["W", 0, 0, 0, "900", "R"], # wakeup period (s)
"422": ["W", 0, 0, 0, "900", "R"], # report period (s)
"522": ["R", 0, 0, 0, "0", "R"],
"443": ["R", 0, 0, 0, "0", "R"],
# ... OTA (51-55), commands (221/222/312/429), network (230-238)
}
datalist = ['421', '443', '230', '231']
db = database(databaseParams) # created here, published back so
core.db = db # firmware_core methods see it as `db`
def start(self):
wakeCount = int(core.db.read('522')) + 1
every = float(core.db.read('422')) / float(core.db.read('421'))
if wakeCount >= every:
self.report(False, datalist)
else:
core.db.write('522', wakeCount)
if core.connectionSuccess:
core.db.write('522', '0')
core.db.write('443', device.getTimestamp())
t = self.seconds_to_next_wakeup(int(core.db.read('421')))
self.prepareSleep(t)
fw.start = start