Getting started
This guide takes you from a blank board to a device that reports to the HiGPS server, and shows where to plug in your own logic.
Firmware layout
Every Findy device runs MicroPython (v1.25) with these files on its filesystem:
boot.pyRuns on every boot. Arms a watchdog, commits a staged over-the-air update if one is pending (see Over-the-air update) and then does:
from last import fw f = fw() f.start()
If
lastfails to import, it falls back to the recoverybaseimage, so a broken upload never bricks the device.firmware_core.mpyThe framework - everything documented under API Reference. You normally never edit it; deploy it compiled.
last.py(or compiledlast.mpy)Your file. It owns:
databaseParams- the parameter registry (see System IDs);datalist- which parameter IDs a report sends;start(self)- the device’s main cycle;measure(self)- what to measure on each wakeup (Logger Pro).
start/measureare plain functions attached to the framework class withfw.start = startandfw.measure = measure.base.pyRecovery firmware: the OTA commands and a minimal report, nothing else. It only runs when
lastcannot be imported. Never put application logic in it.
Warning
Anything firmware_core reassigns at runtime (db, Gimei,
connectionSuccess, timeOffset, registrationStart) must
be accessed from last.py as core.X (via
import firmware_core as core) - never through a plain
from firmware_core import X, which would capture a stale copy.
Flashing MicroPython
Once per board. Either from Thonny - Tools → Options → Interpreter, link Install or update MicroPython (esptool) at the bottom of the dialog - or from the command line:
esptool.py --chip esp32 erase_flash
esptool.py --chip esp32 write_flash -z 0x1000 ESP32_GENERIC-20250415-v1.25.0.bin
Compiling the framework
The device cannot compile large .py sources in RAM, so
firmware_core is always uploaded as bytecode. The mpy-cross version
must match the firmware (v1.25 loads bytecode format 6.3):
pip install "mpy-cross>=1.23"
python -m mpy_cross firmware_core.py
This produces firmware_core.mpy next to the source. last.py and
base.py are small enough to upload as source.
Uploading with Thonny
Thonny is the simplest way to put files on the board and to watch its serial output at the same time.
Download Thonny from https://thonny.org (Windows, macOS and Linux installers) and install it.
Connect the board over USB and start Thonny. Open Tools → Options → Interpreter, choose MicroPython (ESP32) and select the board’s serial port (or Try to detect port automatically). Click OK - the Shell pane shows the MicroPython prompt
>>>.Show the file panes with View → Files. The upper pane lists your computer, the lower pane (MicroPython device) the board’s flash filesystem.
In the upper pane browse to your firmware folder, select
boot.py,firmware_core.mpy,last.pyandbase.py(Logger Pro also needsulp_main.bin), right-click and choose Upload to /. Confirm overwriting the existing files.Press the board’s reset (EN) button or use Run → Stop/Restart backend (Ctrl+F2). The Shell shows the boot log.
Tip
The device deep-sleeps between cycles and Thonny cannot talk to a
sleeping board - you will see Device is busy or does not respond.
Press the board’s reset button and immediately click the red
Stop button (or press Ctrl+C in the Shell) to interrupt
boot.py before start() sends the board back to sleep. Once
the >>> prompt is back you can upload files and type commands
freely; the next reset runs the new firmware.
Note
Thonny uploads files as they are - it does not cross-compile.
Compile firmware_core.py on your computer first (previous
step) and upload the resulting .mpy. Uploading the .py
instead makes the device run out of memory while importing it.
Uploading from the command line
Any MicroPython file tool works; mpremote shown:
mpremote cp boot.py :
mpremote cp firmware_core.mpy :
mpremote cp last.py :
mpremote cp base.py :
mpremote cp ulp_main.bin : # Logger Pro only
Note
ulp_main.bin is the ULP co-processor program Logger Pro uses for
pulse counting. Without it every Logger Pro measure() fails with
[Errno 2] ENOENT. The findyIoT module does not use it.
First boot
Reset the board. On first boot the firmware reads the modem IMEI,
creates the parameter database with the defaults from
databaseParams and sends the defaults report to the server.
From then on the device follows the cycle described on its hardware
page (findyIoT module, Logger Pro).
Customizing a report
Pick which parameters go to the server by editing datalist in
last.py and passing it to report():
datalist = ['421', '443', '230', '231'] # what this device reports
def start(self):
self.report(False, datalist) # alarm=False
t = self.seconds_to_next_wakeup(int(core.db.read('421')))
self.prepareSleep(t) # Logger Pro: prepareSleep(t, True)
fw.start = start
On Logger Pro the pulse/analog extras (437/540, 439/541, 594/520, 570/595) are appended automatically when the matching enable flags (636-639) are set in the database.
Adding your own parameter
Add a row to databaseParams in last.py:
databaseParams["900"] = ["W", 0, 0, 0, "0", "W"] # my custom setting
then read/write it anywhere with core.db.read('900') /
core.db.write('900', value) and include '900' in datalist
to report it. The entry format is described in
System IDs.
Debugging on the device
Use Thonny’s Shell (or mpremote repl) and interrupt boot.py
with Stop / Ctrl+C. Useful moves:
import firmware_core as core # loads the compiled .mpy - no RAM issues
core.modem.turnOn()
core.modem.us('AT+CREG?') # raw AT command
core.modem.socketState(0) # 2 = HiGPS socket connected
core.db.read('421') # inspect a parameter
# Corrupted database (boot hangs in database.__init__):
import os, machine
os.remove('mydb')
machine.reset() # first boot recreates the defaults
Building this documentation
make html # bootstraps .venv/ and builds on first run
open _build/html/index.html
Or manually, with your own environment:
pip install -r requirements.txt
sphinx-build -b html . _build/html