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 (:class:`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 (:doc:`/guides/ota-update`) * Round-boundary wakeups: the sleep timer is aligned to multiples of the measurement period (:meth:`findylab.core.fw.seconds_to_next_wakeup`) Pin map ------- .. list-table:: :header-rows: 1 :widths: 30 15 55 * - Function - GPIO - Notes * - Modem power rail (``GSM On/Off``) - 12 - ``P_Power_GSM`` - held through deep sleep * - Modem PWRKEY (``GSM PWR Key``) - 32 - ``P_PWRKey`` - power-on pulse, up to three attempts * - Modem UART TX (ESP32 side) - 25 - ``P_RXGSM`` - ``Rx GSM`` net, modem RX * - Modem UART RX (ESP32 side) - 26 - ``P_TxGSM`` - ``Tx GSM`` net, modem TX * - Modem RESET_N (``PON_TRIG``) - 27 - ``P_RESET_GSM`` - via an NPN inverter; defined but not driven, :meth:`~findylab.modem.eg915.reset` power-cycles the rail instead * - Modem DTR - 33 - ``P_DTR`` - slow-clock (sleep) control * - Status LED - 2 - Driven high when ``firmware_core`` is imported * - Peripheral power - 25 - ``PperipherialPower`` - constant inherited from Logger Pro, not used by this module's firmware. It shares GPIO 25 with the modem UART line: check the schematic before driving it. .. 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. :meth:`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, send ``datalist`` and 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)`` with ``t`` from :meth:`~findylab.core.fw.seconds_to_next_wakeup` - modem off (``AT+QPOWD`` and the power rail), modem pins released as inputs, deep sleep. Parameters ---------- The module registers the following IDs in ``databaseParams`` (see :doc:`/datatypes/system-ids` for the entry format): .. list-table:: :header-rows: 1 :widths: 22 78 * - 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 :meth:`~findylab.core.fw.getGSMInfo` * - 51, 52, 53, 54, 55 - OTA update (:doc:`/guides/ota-update`) * - 221 / 222 / 312 - Restart / factory reset / send current settings * - 429 - ``resetCount1()`` - on this module resets and re-registers the modem (there are no pulse counters) 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 :doc:`/guides/getting-started`. There is no ``ulp_main.bin`` on this module. Application skeleton -------------------- .. code-block:: python 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 Related pages ------------- * :doc:`/guides/getting-started` * :doc:`/guides/ota-update` * :doc:`/datatypes/system-ids` * API: :doc:`/api/modem`, :doc:`/api/findyiot`, :doc:`/api/database`, :doc:`/api/ota`