Top view · connector and outline geometry read from the R.2 PCB file; component blocks simplified. SC = supercapacitor.
findy IoT Module
The generic LTE + GNSS node of the findy Lab ecosystem. No sensor front-end — you decide what it measures, in MicroPython, on 16 GPIO brought out to headers.
| Qty | 1 pc | 10–99 | 100–499 | 500+ |
|---|---|---|---|---|
| Price | €82.00 | €61.50 | €49.20 | €41.00 |
+ €25 / device / year — findy IoT Platform, global LTE SIM, OTA updates, support.
No sensor front-end is fitted, so every bus is yours to assign. Left: what you connect. Right: what the board brings. Colour indicates type.
Every pin below is a physical pad on the R.2 board. Fifteen are free for your application; one carries the on-board supply-voltage divider. Pins that talk to the modem are not brought out — the framework owns them.
J7 — 10-pin
Analog inputs + UART2| 1 | IO36 | ADC1_0 · input only RTC |
| 2 | IO17 | UART2 TX |
| 3 | IO16 | UART2 RX |
| 4 | IO39 | ADC1_3 · input only RTC |
| 5 | IO34 | ADC1_6 · input only RTC |
| 6 | IO35 | Supply-voltage sense — divider fitted |
| 7–10 | GND | Four ground pads for sensor returns |
J11 — 10-pin
Digital + SPI| 1 | IO22 | I²C SCL (default) |
| 2 | IO19 | SPI MISO |
| 3 | IO5 | SPI CS strap |
| 4 | IO23 | SPI MOSI |
| 5 | — | Not connected |
| 6 | IO18 | SPI SCK |
| 7 | IO4 | Touch, ADC2 RTC |
| 8 | IO2 | Touch, ADC2 RTCstrap |
| 9 | IO15 | Touch, ADC2 RTCstrap |
| 10 | IO13 | Touch, ADC2 RTC |
J10, power & debug
The rest of the edge| J10 | GND ×2 | Pads 1 and 2 |
| J10 | IO21 | I²C SDA (default) · pad 3 |
| J8/J9 | +BAT | 3.7–4.2 V supply in, ×2 headers with GND |
| J5 | +5 V | External 5 V in, diode-OR'd with USB-C |
| J1 | Serial | GND, EN, TX0, RX0, IO0 — REPL and flashing |
| J2 | Modem USB | GND, VBUS, D+, D−, boot — modem diagnostics |
machine.deepsleep(), so they can hold a state or wake the module.Mechanical, radio and consumption figures as published on findyiot.com; pin, connector and power-path figures read from the R.2 schematic and PCB.
The framework is shared with the LTE Logger Pro and Lite, so anything you learn here carries across the range.
On the device filesystem
boot.pyArms the watchdog, commits a staged update, starts the application — and falls back if it will not import.firmware_core.mpyModem driver, parameter database, findyIoT protocol, OTA. Precompiled, shipped as-is.last.pyYour application: parameters, report contents, the measurement cycle.base.pyRecovery image. Keeps the device reachable and updatable when last.py is broken.What happens each wakeup
- Wake on a round boundary. The RTC fires at a multiple of the measurement period, so a whole fleet reports in the same wall-clock slots.
- Measure, count the wakeup. Below the report threshold (ID 422) the module goes straight back to sleep.
- Report. Modem up, register, refresh the network diagnostics, send the parameters, run any queued command — settings, restart, factory reset, OTA.
- Sync and sleep. Server timestamp into the RTC (ID 443), modem powered down, pins released, deep sleep until the next slot.
Updates that cannot brick it
download1460-byte chunks over the modem socket, resumable from the last complete chunk.verifyCRC32 per archive entry before the package is marked ready.commitStaged files copied on the next boot, before the application starts. Idempotent — a power cut mid-update is safe.fall backIf the new application will not import, base.py takes over, reports the failure and accepts a corrected package.boot.py and firmware_core.mpy stay as shipped. You edit last.py: what the device measures, what it reports, and how long it sleeps.
# Default report of the findy IoT Module —
# wakeup period, last timestamp, network diagnostics.
datalist = ['421', '443', '230', '231', '232',
'234', '235', '236', '237', '238']
def start(self):
self.measure()
self.report(False, datalist) # alarm=False
self.prepareSleep(int(core.db.read('421')), True)
fw.start = start# I2C sensor on the default pins: SDA on J10 pad 3, SCL on J11 pad 1.
import machine
i2c = machine.SoftI2C(
scl=machine.Pin(22), sda=machine.Pin(21), freq=100000)
# Register your own parameter, then report it by ID.
databaseParams["900"] = ["W", 0, 0, 0, "0", "W"]
def measure(self):
raw = i2c.readfrom_mem(0x44, 0x00, 2)
core.db.write('900', str(int.from_bytes(raw, 'big')))
fw.measure = measure
datalist.append('900')# UART2 is free — UART0 is the USB console, UART1 belongs to the modem.
# TX on J7 pad 2, RX on J7 pad 3.
import machine
port = machine.UART(2, baudrate=9600, tx=17, rx=16,
timeout=500)
def measure(self):
port.write(b'READ\r\n')
line = port.readline()
if line:
core.db.write('900', line.decode().strip())
fw.measure = measure
The UI is generated from your config file. Parameter 900 below is a custom measurement; everything else is a system parameter the framework fills in without any code from you.
Your sensors
I²C · UART2 · SPI · 3 × ADC1 on the headers
findy IoT Module
Your measure() runs here — MicroPython v1.25
LTE Cat 1 bis / 2G
Global findy SIM, embedded
findy IoT Platform
Measurements, settings, commands — by parameter ID
Your system
API, webhooks, export
Each one runs on the free pins and the framework as shipped — no extra hardware on the module itself.
Ready-made solutions
Complete deployments built on findy hardware — metering, environmental monitoring, asset tracking — delivered and supported end to end.
View solutionsHave your own system?
We supply the module and the SIM. You take the data from the platform API into the infrastructure you already run.
Talk to our team →Write your own logic
You're here. Flash it over USB-C, edit one file, deploy the next version over the air.
Can't do it? Enterprise team →