Use Your AI Agent to Talk to Your Products with Notehub IQ

Blues Developers
What’s New
Resources
API Reference
Notecard and Notehub API documentation
Blog
Technical articles for developers
Connected Product Guidebook
In-depth guides for connected product development
Developer Certification
Get certified on wireless connectivity with Blues
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Webinars
Listing of Blues technical webinars
Blues.comNotehub
Shop
Docs
Help
Support DocsNotehub StatusSecurity AdvisoriesVisit our Forum
Sign In
Docs Home
What’s New
Resources
API Reference
Notecard and Notehub API documentation
Blog
Technical articles for developers
Connected Product Guidebook
In-depth guides for connected product development
Developer Certification
Get certified on wireless connectivity with Blues
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Webinars
Listing of Blues technical webinars
Blues.comNotehub
Shop
Docs
Example Apps
Samples
Building a Simple Asset Tracker
Building Edge AI Applications
Continuous Asset Tracking with External GPS and Immediate Location Sync
Controlling Device State and Receiving Acknowledgment
Managing a Notecard's WiFi Network Remotely
Putting a Host to Sleep Between Sensor Readings
Routing Data from Notehub to a Custom Cloud Endpoint
Using LEDs and NeoPixels to Monitor Notecard Status
Accelerators
Asset Location Tracking
Heavy Equipment Hours-of-Use & Utilization Tracker
Returnable Container / Tote Pool Tracker
Untethered Trailer and Chassis Fleet Tracker
Asset Performance Optimization
Legacy Diesel Generator Fleet Performance Uplift
Solar Array String-Level Performance Dashboard
Battery Management Systems
Aerial Lift / Rental Equipment Battery Health Monitor
Off-Grid Solar Battery Site Controller
Remote Cabinet Backup Battery Sentinel
Downtime Prevention
Municipal Wastewater Lift Station Monitor
Rooftop HVAC Predictive Maintenance
VFD Pump Predictive Maintenance
Energy Monitoring Solutions
Commercial Tenant Sub-Metering Bridge
EV Charger Session & Utilization Monitor
Utility Distribution Transformer Load Monitor
Energy Savings
Commercial Plug-Load & After-Hours Waste Dashboard
Demand-Response Solar + Battery Dispatcher
Multi-Site Walk-In Cooler Energy & Setpoint Monitor
Industrial Equipment Monitoring
CNC Machine Spindle Load and Cycle Time Tracker
Injection Molding Shot-to-Shot Process Monitor
Trailer Manufacturer Connected Trailer Platform
Loss Prevention
Construction Equipment Anti-Theft Tracker with Immobilizer
Reefer Trailer Cold-Chain & Door-Event Monitor
Remote Patient Monitoring
Cellular Medication Adherence Pillbox
Post-Discharge Vitals Relay Hub
Remotely Monitored Assets
Off-Grid Livestock Water Tank Monitor
Remote Apiary Hive Health Monitor
Safety Assurance
Construction Site Environmental & Noise Exposure Monitor
Lone Worker Panic and Fall Detection Beacon
Regulatory-Grade Pharmacy and Lab Cold Storage Audit Monitor
Supply Chain Tracking
Pallet-Attached Cold Chain Logger
Rail Car Condition & Interchange Tracker
Truck Roll Reduction
Commercial Grease Interceptor Level Monitor
Propane / LPG Tank Fill Telemetry
homechevron_rightExample Appschevron_rightAcceleratorschevron_rightReefer Trailer Cold-Chain & Door-Event Monitor

Reefer Trailer Cold-Chain & Door-Event Monitor

Reefer Trailer Cold-Chain & Door-Event Monitor banner
note

This reference application is here to give you ideas and help you get started quickly. It's built on specific hardware that may not match yours, so focus on the sections that fit your use case. If you'd like to talk through your project and whether it's a good fit for Blues, reach out.

Building with an AI assistant? Point it at this accelerator's firmware in firmware/reefer_cold_chain_monitor/ so it can learn how the device works and help you adapt it to your hardware.

This project is a loss prevention reference design that keeps continuous watch over refrigerated (reefer) trailers. It catches temperature excursions before a load spoils and logs every door event before a pallet walks out the back. Two DS18B20 temperature probes and a magnetic door reed switch feed a Blues Notecarrier CX, which packages the sensor events and hands them to a Notecard for Skylo. The Notecard delivers them over whichever network it can reach, cellular when a tower is in range and Skylo satellite when it isn't.

What you'll have when you're done: a weatherproof, trailer-powered monitor that samples cargo temperature every minute. Each sample queues locally and goes to the Blues Notehub cloud service on the next outbound session, so samples reach the cloud/Notehub in batches (once per hour by default). When a door opens or a temperature threshold is breached, the monitor fires an alert on the next sample cycle (up to ~60 seconds after the event, plus network-establishment time). It also ships hourly compliance summaries to Notehub over cellular or WiFi. Per-sample logs and hourly summaries go in cellular/WiFi-only Notefiles, and the Notecard discards their queued Notes when it connects over NTN, so they never eat into the bundled satellite data budget. NTN sessions only happen when terrestrial coverage is unavailable, and on those periodic hub sessions only pending alert Notes carry payload data over the satellite link.

Energy footprint: steady-state draw from a 12 V trailer supply is roughly 30–60 mAh per 24 h, and most of that is one hourly cellular session of ~15–45 seconds at ~250 mA average. NTN satellite sessions use more energy per event because the link takes longer to establish, but sending only alerts over satellite keeps the 10 KB data budget intact. During commissioning you confirm the real consumption with Blues Mojo (see §9).

1. Project Overview

The problem. A refrigerated trailer hauling fresh produce, pharmaceuticals, or frozen food is one of the more valuable assets in ground transportation. A typical load runs $40,000 to $80,000 before you even count the trailer itself. Most of the loss comes from two failure modes:

  • Temperature excursion. A reefer unit that loses refrigerant, trips a setpoint, or runs out of fuel can let a frozen or fresh cargo hold warm up into the danger zone. Often nobody discovers the spoilage until delivery, when it's too late to re-route the load. If you catch the excursion within the first hour, while there are still options, you can save the load instead of writing it off.
  • Door theft. Drop-stop cargo theft follows a familiar pattern. A thief follows a trailer to a fuel stop or rest area, opens the rear doors, and removes full pallets in minutes. The most reliable early warning is a door opening at a place or time nobody expected.

Both failure modes have the same root cause, which is that nobody can see inside the trailer while it's moving.

Scope note. This design only uses direct inputs from temperature probes and a door switch. There's no OEM reefer unit or tractor integration, no J1939 CAN, and no proprietary reefer telemetry (Carrier DataLink, Thermo King DSR, etc.). It's a point-instrumentation retrofit for fleets with a mix of reefer makes and models that want a universal, non-invasive monitor.

Why Notecard for Skylo. A trailer is always on the move, so its connectivity keeps changing. Urban routes have dense cellular coverage, while rural interstates can have big gaps and cross-border hauls hand off between carrier networks. Port staging areas that face the ocean can sit outside terrestrial coverage entirely. A fixed cellular SIM handles the urban case but quietly drops offline everywhere else, which is exactly when unsupervised, high-value loads are most exposed.

New to Blues?

Learn what we do in this 3-minute video that walks you through how we simplify wireless connectivity.

Learn what we do in this 3-minute video that walks you through how we simplify wireless connectivity.

Notecard for Skylo (NOTE-NBGLWX) (see the datasheet) handles all of this in a single 30 × 42 mm module. It has LTE-M, NB-IoT, and GPRS for terrestrial cellular, Skylo NTN (non-terrestrial network) satellite as an automatic fallback, and WiFi through an onboard antenna. The firmware turns on this multi-RAT behavior with a single card.transport request (method:"wifi-cell-ntn") that it sends once. After that the Notecard handles network selection itself, and the application never needs to know which radio carried a given message. If a door opens at a rural rest stop, the alert goes out over cellular when a tower is in range and over satellite when it isn't, with no radio-selection logic in the application. A mobile asset can't choose its coverage, so this automatic multi-RAT (radio access technology) failover is the main reason to use Notecard here.

Deployment scenario. The electronics go in a weatherproof NEMA 4X enclosure that's strapped or screwed to the inside trailer wall or an exterior chassis rail. It runs off the trailer's 12 V DC supply (or the nose-box connector, if there is one). Two stainless steel DS18B20 probes thread through grommets into the cargo compartment, one near the front (forward air) and one near the rear return-air panel. The reed switch mounts on the door frame, with its matching magnet on the door itself.

2. System Architecture

System Architecture

Device-side responsibilities. While the trailer rolls down the highway at 65 mph, the STM32 host on the Notecarrier CX sleeps in STM32 STOP2 (a few µA) until the Notecard's ATTN pin wakes it through card.attn. Every 60 seconds it wakes just long enough to read both DS18B20 probes and the door pin, check the threshold rules locally, and hand any resulting Notes to the Notecard over I²C. The host resumes in place with its RAM intact, so the running state (temperature averages, the door open/close timestamp, the alert deduplication epoch) just stays in the AppState struct across sleep cycles. Nothing gets serialized to the Notecard or lost, and the trailer's 12 V supply only sees a few seconds of MCU draw per minute.

Notecard responsibilities. Notecard for Skylo takes care of everything involved in getting the message off the trailer. It queues Notes locally and runs the WiFi → cellular → NTN fallback policy that the firmware sets up once at first boot with card.transport (method:"wifi-cell-ntn"). It opens a session on the configured hub.set outbound cadence (60 minutes by default), and when the host calls hub.sync it sends pending alerts right away over whatever network is available. It also pulls environment variables down from Notehub, so dispatch can retune thresholds without a reflash. Notecard for Skylo has an integrated GNSS radio too, so the firmware turns on card.location.mode periodic (600-second interval, motion-gated per the API docs). Every trailer_alert.qo then carries the last known latitude and longitude, which tells you where the trailer was when the alert fired without any extra hardware.

Notehub responsibilities. Everything the Notecard sends, whether over cellular, satellite, or WiFi, lands in Notehub, which ingests and stores it and applies the project's routes. Alerts, per-sample logs, and hourly summaries live in separate Notefiles. Dispatch routes can send the alerts straight to the TMS or on-call channel while the per-sample and summary streams flow into a long-term cold-chain compliance store. The trailer_alert.qo payload is compact+port-encoded, so it works the same way over cellular and NTN, and Notehub session metadata records which transport carried each event. Smart Fleets group trailers by lane, customer, or cargo type and push fleet-specific threshold overrides without touching any individual device's config.

Routing to the cloud (high level). Notehub routes to HTTP, MQTT, AWS, Azure, GCP, Snowflake, and other destinations. Setup varies by project, and this one doesn't include a specific downstream endpoint, so start with the Notehub routing docs.

3. Technical Summary

  1. Notehub: create a Notehub project and copy its ProductUID.
  2. Wire the bench rig: Notecarrier CX + Notecard for Skylo + two DS18B20 probes (VDD to +3V3, GND to GND, data to A0 with 4.7 kΩ pull-up to +3V3) + reed switch on A1 + a jumper from the Notecarrier CX's ATTN pin to D5 so the Notecard can wake the host. The full pinout is in §5.
  3. Edit one line of firmware/reefer_cold_chain_monitor/reefer_cold_chain_monitor_helpers.h to set PRODUCT_UID to your project's value.
  4. Flash with arduino-cli:
    arduino-cli core install STMicroelectronics:stm32
    arduino-cli lib install "Blues Wireless Notecard" "STM32duino Low Power" "STM32duino RTC" OneWire DallasTemperature
    
    # Compile and upload (substitute your port)
    arduino-cli compile -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none firmware/reefer_cold_chain_monitor/
    arduino-cli upload -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none -p /dev/cu.usbmodem* firmware/reefer_cold_chain_monitor/
    The usb=none board option turns off the USB CDC stack, which has to be off for the host to sleep. §7.1 has the full dependency list and build settings.
  5. Watch: open Notehub → your project → Events. You should see _session.qo within 1 minute. On the next outbound window (default ~60 minutes) you'll get a batch of trailer_log_cell.qo Notes (one per 60-second sample) and trailer_summary_cell.qo (hourly), and any alerts show up as trailer_alert.qo (immediate sync).

Here's a sample Note this device emits:

{ "t1_c": -1.4, "t2_c": -0.8, "door_open": false }

4. Hardware Requirements

PartQtyRationale
Notecarrier CX1Integrated carrier with an onboard STM32L433 host, so there's no separate MCU board to buy. The host sleeps in STOP2 between samples, and the Notecard's ATTN pin wakes it. See the datasheet.
Notecard for Skylo (NOTE-NBGLWX)1Cellular (LTE-M / NB-IoT / GPRS) + Skylo NTN satellite module with built-in GNSS and an onboard WiFi antenna (Quectel BG95-S5 cellular/satellite modem + Silicon Labs WFM200S WiFi). Network selection is automatic and needs no firmware changes. It bundles 500 MB of cellular data over 10 years plus 10 KB of satellite data, with no activation fees. See the datasheet.
Blues Mojo1Coulomb counter on the power rail. You need it during commissioning and validation for ground-truth energy measurement (see §9). Remove Mojo and the Qwiic cable before production deployment, because the field doesn't need their inline current draw and quiescent load. See the datasheet.
Adafruit DS18B20 Waterproof Temperature Sensor (#381)21-Wire stainless-steel probe with a −55 °C to +125 °C range and ±0.5 °C from −10 °C to +85 °C. Includes a 4.7 kΩ pull-up resistor. Put one probe near the front evaporator and one near the rear return-air panel.
Adafruit Magnetic Contact Switch (#375)1Normally-open reed switch in a plastic housing that activates within 15 mm of its matching magnet. The switch mounts on the door frame and the magnet on the door leaf.
Pololu D24V22F5 5 V Step-Down Regulator (#2858)15.3–36 V input, 5 V / 2.5 A output. It converts the trailer's 12 V DC (or nose-box 12 V) to 5 V for the Notecarrier CX, and it's compact and efficient (85–95%).
NEMA 4X enclosure, ~6 × 4 × 2 in1Weatherproof housing rated for wash-down and condensation, which suits the inside of a reefer trailer.
Skylo-certified cellular / NTN flexible antenna (included with NOTE-NBGLWX)1Ships in the NOTE-NBGLWX kit and connects to the Notecard MAIN u.FL port. Covers LTE-M / NB-IoT / GPRS cellular and Skylo S-Band / L-Band NTN (B23, B255, B256). Must not be substituted. Any other antenna on the MAIN port decertifies the device on Skylo's network, and the device may get blocked. If a production design needs a different antenna, you'll need a delta EIRP test report from a CTIA/OTA-authorized lab. The Blues Antenna Guide has the full certification policy. Route the included flexible antenna cable through a sealed IP68 cable gland in the NEMA 4X enclosure wall so the antenna sits outside the metal structure.
Passive GPS/GNSS flexible antenna (included with NOTE-NBGLWX)1Ships in the NOTE-NBGLWX kit and connects to the Notecard GPS u.FL port. Covers GPS/GNSS L1 (1559–1610 MHz). Route the cable through a sealed cable gland to the outside of the NEMA 4X enclosure, where it has a clear, unobstructed view of the sky, and mount the antenna on the trailer roof or an exterior wall, away from the refrigeration unit. If the included antenna gets damaged, a replacement u.FL passive GNSS antenna works too (e.g., the Blues accessories Quectel YCA001BA, covering 1560–1620 MHz, u.FL).
Sealed IP68 cable gland, M16, for the antenna cables2One per antenna cable (MAIN and GPS), through the NEMA 4X enclosure wall. They keep the IP/NEMA rating intact once the antenna cables pass through. Use a gland sized for the cable diameter of the included antenna pigtails (typically ~3–4 mm).
2-conductor stranded wire, 22 AWG, ~3 m1Extends the door sensor cable from the door frame to the enclosure. Ordinary alarm wire works.
Inline ATO/ATC blade fuse holder, 12–16 AWG leads1Goes inline on the trailer's 12 V positive feed, between the trailer source and the Pololu D24V22F5 VIN, so overcurrent protection sits as close to the source as practical (see the field installation caution in §5). Any automotive-grade in-line ATO/ATC holder with a lead wire gauge matched to the supply run will do.
3 A ATO/ATC automotive blade fuse1Fits the inline fuse holder above and is sized for the Pololu D24V22F5's 2.5 A rated output with some wiring headroom. Use only a 3 A fuse, and never swap in a higher rating. A blown fuse points to a wiring fault, so fix the fault before you replace the fuse.

All Blues hardware ships with an active SIM that includes 500 MB of data and 10 years of service, with no activation fees and no monthly commitment, so there's no separate SIM to buy or activate.

5. Wiring and Assembly

Wiring and Assembly: two DS18B20 probes on A0 with 4.7 kΩ pull-up; reed switch on A1; ATTN → D5 jumper so the Notecard can wake the host from STOP2; Skylo and GNSS antennas; 12 V → Pololu 5 V step-down → +VBAT with Mojo inline for bench

All host I/O lands on the dual 16-pin header of the Notecarrier CX. Notecard for Skylo seats into the M.2 slot, and u.FL leads run from it to the externally mounted cellular, satellite, and GNSS antennas. For bench validation, the Mojo sits inline between the 5 V supply and the Notecarrier's +VBAT pad and reports cumulative mAh to the Notecard over Qwiic (I²C).

Power (production, no Mojo):

  • Pololu D24V22F5 VIN → inline fuse holder (3 A ATO blade fuse fitted; see BOM) → trailer 12 V DC positive. Mount the fuse holder on the positive lead as close to the 12 V source as practical (see the field installation caution below).
  • Pololu GND → trailer chassis GND (circuit ground reference for the entire system)
  • Pololu VOUT (+5 V) → Notecarrier CX +VBAT
  • Pololu GND → Notecarrier CX GND (power-return path; must share the same chassis ground as the input side)

Power (bench validation, with Mojo inline):

  • Pololu VIN → bench 12 V supply positive
  • Pololu GND → bench supply GND (circuit ground reference)
  • Pololu VOUT (+5 V) → Mojo BAT
  • Mojo LOAD → Notecarrier CX +VBAT
  • Pololu GND → Mojo GND → Notecarrier CX GND (shared ground throughout the power chain)
  • Mojo Qwiic → Notecarrier CX Qwiic (I²C telemetry connection for bench energy measurement only; remove Mojo and the Qwiic cable in production)

DS18B20 temperature probes (1-Wire bus on A0):

  • Both probe VDD (red) wires → Notecarrier CX +3V3
  • Both probe GND (black) wires → Notecarrier CX GND
  • Both probe data (yellow) wires → Notecarrier CX A0
  • Notecarrier CX +3V3 → 4.7 kΩ resistor (included in Adafruit #381 bag) → Notecarrier CX A0 (pull-up)

Probe order. getTempCByIndex(0) returns whichever probe the library enumerates first at startup. To match each index to a physical location, power up with only one probe connected, note its reported temperature, label it, and then connect the second. You only have to do this once, on the bench.

Door reed switch (A1):

  • Adafruit #375 lead 1 → Notecarrier CX A1
  • Adafruit #375 lead 2 → Notecarrier CX GND
  • The firmware uses INPUT_PULLUP on A1, so no external resistor is needed.

Polarity: The Adafruit #375 is a normally-open (NO) switch, so the circuit is open when no magnet is nearby. Mount the plastic housing on the stationary door frame and the magnet on the moving door. As the door closes and the magnet approaches, the circuit closes and pulls A1 LOW. When the door opens, the circuit opens and the pull-up takes A1 HIGH. The firmware reads HIGH = door open.

ATTN-to-D5 jumper (host sleep):

  • Notecarrier CX ATTN → Notecarrier CX D5 with a short jumper. Both are on the same 16-pin header (ATTN at position 3, D5 at position 14).
  • Leave the Notecarrier CX EN pin unconnected.

The Notecard pulls ATTN low while the host sleeps and raises it when the next sample is due, and the rising edge on D5 wakes the host from STOP2. EN has to stay unconnected. On the CX it enables the shared 3.3 V VIO rail (host, Qwiic, 3V3_OUT, and Notecard I/O), so driving it from ATTN would brown out the whole board instead of putting the host to sleep. Putting a Host to Sleep Between Sensor Readings covers the full pattern.

Door sensor cable extension: The #375 comes with a 29 cm (≈ 11 in) pigtail. To reach from the door frame to the enclosure, splice 22 AWG 2-conductor wire on at the sensor housing terminals, and keep the join inside a weatherproof connector (e.g., a gel-filled butt splice).

Antennas:

  • Notecard MAIN u.FL → included Skylo-certified flexible antenna cable → through sealed IP68 cable gland in enclosure wall → antenna positioned outside with clear sky view
  • Notecard GPS u.FL → included passive GPS flexible antenna cable → through sealed IP68 cable gland in enclosure wall → antenna positioned outside with clear sky view (trailer roof or exterior wall, away from the refrigeration unit)

Antenna placement. Both antennas must sit outside the metal enclosure and any steel trailer structure, because steel badly attenuates cellular, NTN, and GNSS signals. Keep the GNSS antenna at least 20 cm from the cellular/NTN antenna and from reefer unit motors or inverters so it doesn't get desensitized. Seat every u.FL connector firmly before you route the cables, since these push-on connectors are fragile. Run the antenna cables through the IP68 cable glands before sealing, avoid sharp bends, and keep at least 10 mm (ideally 20 mm) of clearance between each antenna and nearby metal.

Skylo antenna substitution. The MAIN port antenna must be the Skylo-certified flexible antenna that comes with the NOTE-NBGLWX. Connecting any substitute, even a cellular/NTN whip that looks equivalent, decertifies the device on Skylo's network, and Skylo may block it from the NTN service. If a custom enclosure or mounting setup needs a different antenna, contact Blues about the delta EIRP certification process before you deploy.

warning

Field installation caution. Tap the 12 V feed from a dedicated trailer accessory circuit and fit a 3 A automotive blade fuse as close to the source as practical. Don't wire straight to the battery without overcurrent protection. Route all sensor and power cables away from refrigerant lines, the reefer unit wiring harness, and OEM trailer wiring, and don't share conduit with high-current circuits. Avoid penetrating insulated trailer panels where you can, and run cables through existing grommets or approved bulkhead fittings instead to preserve the trailer's thermal envelope. Seal any non-OEM penetrations with closed-cell foam tape and record them in the trailer maintenance log.

6. Notehub Setup

  1. Create a project. Sign up at notehub.io and create a project. Copy the ProductUID, which looks like com.your-company.your-name:reefer-monitor.

  2. Set the ProductUID in firmware. Open reefer_cold_chain_monitor_helpers.h and replace the empty string on the #define PRODUCT_UID "" line with your value.

  3. Claim the Notecard. Power up the assembled unit. The Notecard associates itself with your Notehub project on its first cellular (or satellite) connection, and the device shows up in your project's Devices tab within a minute or two.

  4. Create a Fleet per lane or customer. Fleets group devices for shared configuration and routing. A natural split here is one fleet per cargo type (fresh, frozen, pharmaceutical), because the temperature thresholds are very different for each. Smart Fleets can auto-assign trailers based on properties already in Notehub.

  5. Set environment variables. In the Notehub web console, select your Fleet (or an individual Device) → Settings → Environment tab, and enter each variable name and value below. Changes take effect on the next inbound sync over cellular or WiFi (default 120 minutes), with no reflash and no truck roll.

    VariableDefaultValid rangePurpose
    temp_max_c7.0−30.0 to 50.0 °CWarm excursion threshold in °C. An alert with alert:"temp_excursion" fires when either probe goes above it. 7 °C (45 °F) is a common fresh-produce limit, and frozen loads usually use −15 °C (5 °F). Values outside the range are silently ignored, and the current value stays.
    temp_min_c-25.0−60.0 to 20.0 °CCold / freeze protection threshold. An alert with alert:"temp_cold" fires when either probe drops below it. Useful for loads with a minimum-temperature requirement (e.g., live plants, some vaccines). Values outside the range, or a value ≥ temp_max_c, are silently ignored.
    door_alert_sec60030–86400 secondsSeconds the door can stay open before a door_open_long reminder fires. The default is 10 minutes, which is typical for a legitimate delivery stop.
    sample_interval_sec6010–3600 secondsSeconds between sensor samples and host sleep cycles.
    summary_interval_min601–1440 minutesMinutes between trailer_summary_cell.qo Notes. Changing it also re-applies hub.set outbound, so the Notecard's sync cadence follows the new value.
    alert_cooldown_sec180060–86400 secondsGlobal minimum seconds between any two temperature alerts, whatever the probe or excursion type. The firmware keeps a single last_temp_alert_epoch shared by all probes and alert types, so a warm-excursion alert from probe 1 resets the same timer that would suppress a later cold-excursion alert from probe 2. This prevents alert storms during slow-drift excursions, and 30 minutes is a reasonable floor for operational response time.
  6. Configure routes. Add routes for these Notefiles:

    • trailer_alert.qo: alert events (door state change, temperature excursion). They go out over the first available transport, with the Notecard picking cellular when it's in range and NTN satellite as a fallback. Route them to your TMS, dispatch system, or on-call channel for real-time delivery. Notehub session metadata shows the transport (cellular vs. satellite) for each event.
    • trailer_log_cell.qo: a per-sample record written every sample_interval_sec (default 60 seconds) with both probe temperatures and the door state. It's cellular/WiFi only and never goes over NTN. Route it to a cold-chain compliance archive or long-term data store. Expect gaps in this file during NTN-only coverage (see §10).
    • trailer_summary_cell.qo: an hourly compliance summary (mean/min/max per probe, door event count, current door state). Also cellular/WiFi only. Route it to the same cold-chain compliance destination as trailer_log_cell.qo.

    With alerts kept apart from the log and summary data, you can set up routes at different urgency levels without filter logic on either end.

What you should see in Notehub

  • _session.qo: Notecard housekeeping, one per cellular or satellite session. Seeing these events confirms the radio is reaching Notehub.
  • trailer_log_cell.qo: one Note queued per sample_interval_sec (default every 60 seconds), cellular/WiFi only. The Notes reach Notehub in batches on each outbound session (default 60 minutes, so expect up to 60 Notes per delivery). Sample body:
    { "t1_c": -1.4, "t2_c": -0.8, "door_open": false }
    A temperature field showing −127 means that probe wasn't responding when the sample was taken. Expect gaps in this file during long stretches of NTN-only coverage. Per-sample records pick up again once terrestrial connectivity returns.
  • trailer_summary_cell.qo: one per summary_interval_min (hourly by default), cellular/WiFi only. Expect gaps here too during long NTN-only stretches. Summary Notes queued while NTN is the active transport get discarded at sync time (the same delete:true mechanism as trailer_log_cell.qo), and they aren't kept for a later terrestrial upload. Sample body:
    {
      "t1_c": -1.4,
      "t2_c": -0.8,
      "t1_min_c": -2.1,
      "t1_max_c": -0.9,
      "t2_min_c": -1.6,
      "t2_max_c": -0.3,
      "door_events": 2,
      "door_open": false
    }
    A temperature field showing −127 means the probe wasn't responding. In a summary Note, it means no valid samples were recorded across the whole window. Alert Notes use the same −127 sentinel when a probe fails to respond at the moment the alert fires. In both Note types, treat −127 as a sensor-fault flag and never as a temperature near absolute zero.
  • trailer_alert.qo: generated on the next sample cycle after a threshold trip or door event, then sent immediately with hub.sync so the Notecard doesn't wait for the next outbound window. It goes out over the first available transport, cellular when in range and NTN satellite as a fallback. Sample bodies:
    { "alert": "temp_excursion", "t1_c": 9.2,  "t2_c": 8.7,  "door_open": true,  "door_open_sec": 0,   "lat": 41.8781, "lon": -87.6298 }
    { "alert": "door_open",      "t1_c": -1.4, "t2_c": -0.8, "door_open": true,  "door_open_sec": 0,   "lat": 41.8781, "lon": -87.6298 }
    { "alert": "door_close",     "t1_c": -1.4, "t2_c": -0.8, "door_open": false, "door_open_sec": 387, "lat": 41.8781, "lon": -87.6298 }
    lat and lon carry the last known GNSS fix at the moment the alert fired. Both are 0.0 when no fix has been acquired yet (e.g., on first power-on, before the GNSS antenna has had a clear view of the sky). Treat lat == 0.0 && lon == 0.0 as a no-fix sentinel in downstream analytics.

7. Firmware Design

The firmware is split across four files. reefer_cold_chain_monitor.ino has setup(), loop(), and the top-level sample-cycle driver. reefer_cold_chain_monitor_helpers.h defines the constants, AppState, clamp helpers, and function prototypes. reefer_cold_chain_monitor_helpers.cpp implements the sensor drivers, the door and temperature state machines, and all of the Notecard communication. Finally, cx_sleep.h holds the host-sleep helpers (the card.attn request, STOP2 entry, and ATTN wake).

7.1 Installing and flashing

Dependencies:

  • Arduino core for STM32: stm32duino/Arduino_Core_STM32. Add the index URL https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json under File → Preferences → Additional Boards Manager URLs, then install it from the Boards Manager (search "STM32 MCU based boards"). The Notecarrier CX's host uses the Cygnet board definition (see the build settings below).
  • Blues Wireless Notecard library: note-arduino. Install it through the Arduino Library Manager with arduino-cli lib install "Blues Wireless Notecard", or search for Blues Wireless Notecard in the IDE Library Manager and install the latest stable version. The note-arduino releases page lists the current stable release.
  • OneWire: PaulStoffregen/OneWire. Install it from the Library Manager.
  • DallasTemperature: milesburton/Arduino-Temperature-Control-Library. Install it from the Library Manager.
  • STM32duino Low Power (and its dependency STM32duino RTC): stm32duino/STM32LowPower. Install it from the Library Manager. It provides the STOP2 entry and ATTN-pin wake that cx_sleep.h uses.

Build settings: The Notecarrier CX's host is the same STM32L433 as the Blues Cygnet, so select Blues boards → Cygnet (pnum=CYGNET) and set USB support (if available) to None (usb=none). If the USB CDC stack is enabled and no USB host is attached (the trailer supply, or the Notecarrier CX USB-C switch in NC), the STM32's USB wakeup interrupt fires continuously and the host never stays in STOP2. Debug output (when DEBUG_MODE is defined in the .ino) goes to the LPUART on the Notecarrier CX debug jack instead, which an ST-LINK V3 exposes as a virtual COM port (see Serial Logging With STLINK).

Flashing with the Arduino IDE: Open reefer_cold_chain_monitor.ino, apply the build settings above, and hit Upload. With the Notecarrier CX's USB-C switch in HST, you can reach the host's DFU bootloader over the USB-C port (hold BOOT, tap RST). You can also upload over SWD with an ST-LINK on the debug jack.

Flashing with arduino-cli:

# Compile and upload — usb=none disables the USB CDC stack, which must be
# off for the host to sleep.
arduino-cli compile -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none \
                    firmware/reefer_cold_chain_monitor/
arduino-cli upload  -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none \
                    -p /dev/cu.usbmodem* firmware/reefer_cold_chain_monitor/

firmware/reefer_cold_chain_monitor/sketch.yaml sets the same board options, so arduino-cli compile picks them up too when you run it in that directory without -b. Replace /dev/cu.usbmodem* with your actual port (COMx on Windows, /dev/ttyACM* on Linux). With DEBUG_MODE defined, open a serial monitor on the ST-LINK virtual COM port at 115200 baud to watch the [boot], [sensor], [door], [temp], [summary], and [alert] log lines.

7.2 Template format codes (compact encoding)

The alert Notefile uses compact format, with fixed-width binary-encoded fields that keep satellite data use to a minimum. The note.template request names the field types: TFLOAT32 (4-byte IEEE-754), TINT16 (2-byte signed), TUINT32 (4-byte unsigned), and TBOOL (boolean). These are note-c constants for the numeric type hints the Notecard reads: TFLOAT32 = 14.1, TINT16 = 12, TUINT32 = 24, and TBOOL = true. The alert Notefile's compact+port encoding drops the standard JSON envelope and delivers only the declared body fields as binary records, which is critical with a 10 KB satellite data budget. Cellular fully supports the same format, so the firmware doesn't need any special handling.

7.3 Modules

ResponsibilityFunction
First-boot Notecard config (hub.set, card.transport, card.location.mode)hubConfigure
Re-sync hub.set outbound when summary interval changesapplyHubSetIfChanged
Compact Note template definitiondefineTemplates
Environment-variable refresh (each wake)fetchEnvOverrides
DS18B20 temperature reading (1-Wire)readTemperatures
Door reed switch readingreadDoorState
Door open/close/long-open state machinecheckDoorEvents
Temperature excursion detection + dedupcheckTemperatureExcursion
Rolling window accumulationaccumulateSummary
Hourly summary NotesendSummary
Immediate-sync alert NotesendAlert
Epoch time from Notecard RTCgetEpochTime
Host sleep (STOP2 until the Notecard raises ATTN)cx_sleep.h: cxSleepBegin, cxSleepUntilAttn
Application state (held in RAM across sleep cycles)AppState

7.4 Sensor reading strategy

DS18B20 probes. Both sensors share the single 1-Wire bus on A0. probes.requestTemperatures() starts a conversion on both sensors at once and blocks for ~750 milliseconds at 12-bit resolution (0.0625 °C steps). Then getTempCByIndex(0) and getTempCByIndex(1) return the two readings. The DallasTemperature library returns DEVICE_DISCONNECTED_C (−127 °C) for any probe that doesn't respond. The firmware treats readings below TEMP_INVALID + 1.0 as invalid and leaves them out of the summary averages, without affecting the other probe's accumulation.

Door reed switch. Each sample is a simple digitalRead(DOOR_PIN). The Adafruit #375 is a normally-open switch, and with INPUT_PULLUP and the switch between A1 and GND, a closed door reads LOW and an open door reads HIGH. Instantaneous reads are fine here, because a real trailer door stays in each state for seconds to minutes.

7.5 Event payload design

The firmware writes its data to three template-backed Notefiles. The alert Notefile (trailer_alert.qo) uses compact format with a port assignment. Compact encoding drops the standard Note metadata envelope and stores only the declared body fields as fixed-length binary records, which is critical with a 10 KB satellite data budget, and NTN (satellite) mode requires a port number. Cellular fully supports compact+port too, so the same Notefile gets delivered correctly over either transport.

The cellular/WiFi-only Notefiles (trailer_log_cell.qo and trailer_summary_cell.qo) are template-backed so their schema stays consistent, but they use standard JSON encoding without a port, and they carry delete:true. According to the Blues Satellite Best Practices documentation, a cellular/WiFi-only Notefile template (no format or port) with delete:true makes the Notecard discard its queued Notes at sync time when NTN is the active transport. These Notefiles are never transmitted over satellite, so they don't consume the bundled satellite data budget. (The _cell suffix in their names marks them as terrestrial-only, and they never go over NTN.)

trailer_log_cell.qo: per-sample, queued, cellular/WiFi only:

{ "t1_c": -1.4, "t2_c": -0.8, "door_open": false }

trailer_summary_cell.qo: hourly, queued, cellular/WiFi only:

{
  "t1_c": -1.4,
  "t2_c": -0.8,
  "t1_min_c": -2.1, "t1_max_c": -0.9,
  "t2_min_c": -1.6, "t2_max_c": -0.3,
  "door_events": 2,
  "door_open": false
}

trailer_alert.qo: immediate, enqueued then hub.sync, cellular or NTN transport:

{
  "alert": "temp_excursion",
  "t1_c": 9.2, "t2_c": 8.7,
  "door_open": true,
  "door_open_sec": 0,
  "lat": 41.8781, "lon": -87.6298
}

For every alert, the firmware adds a Note to the alert Notefile (without sync:true) and then sends a hub.sync request to wake the radio. Keeping the sync trigger separate from the enqueue avoids a race where sync:true on the note.add could start a sync before the Note is fully committed. The Notecard picks cellular when it's in range and falls back to NTN satellite otherwise, so the firmware doesn't need any radio-selection logic.

Alert type values: door_open (door just opened), door_close (door just closed, and door_open_sec carries the open duration), door_open_long (door still open past door_alert_sec), temp_excursion (probe above temp_max_c), and temp_cold (probe below temp_min_c).

The door_open_sec field is a TUINT32 (4-byte unsigned integer) in the template, so it can hold door-open durations up to ~136 years. A probe that fails to respond shows up as −127 in the temperature fields of any Note type (trailer_log_cell.qo, trailer_summary_cell.qo, and trailer_alert.qo alike). Treat that as a sensor-fault flag, not a real temperature. Door-event alerts (door_open, door_close, door_open_long) include live probe readings sampled at the moment the alert fires, so a −127 in a door alert means the probe really was unresponsive at that instant, not that the temperatures were left out on purpose. lat and lon are TFLOAT32 fields that carry the last GNSS fix. Both are 0.0 when no fix is available, so treat that pair as a no-fix sentinel.

7.6 Power and sync strategy

The trailer has a 12 V supply, but keeping the host MCU asleep between samples still cuts the heat in the enclosure dramatically, and it lets the firmware structure port cleanly to a battery-backed variant (Scoop or otherwise). setup() runs once at power-up, and each pass through loop() is one sample cycle. After each cycle the host calls cxSleepUntilAttn() (in cx_sleep.h). That sends a card.attn sleep request for sample_interval_sec seconds, waits for the Notecard to pull ATTN low, and enters STM32 STOP2, where the host draws a few microamps and keeps its RAM intact. When the interval is up, the Notecard raises ATTN, the rising edge on D5 wakes the host, and execution picks up on the next line of loop(). The host resumes in place instead of cold-booting, so the AppState struct just lives in RAM and nothing gets serialized to the Notecard. If the sleep request fails or ATTN never goes low (a missing jumper), loop() waits out the interval awake and tries again on the next cycle, so the sample cadence holds either way.

The Notecard itself idles at ~8–18 µA between sessions. Per-sample log Notes and hourly summary Notes pile up in its on-device queue and go out together in a single outbound session. Door and temperature alerts get enqueued and then trigger a hub.sync request. That skips the outbound timer and wakes the radio right away on whatever network is available, cellular if it's in range and NTN satellite otherwise.

Sampling and transmission are deliberately decoupled. The sensors sample every 60 seconds, but the radio only connects once per hour (plus on demand for alerts). Fresh environment variables come down on the inbound cadence (default 120 minutes). When cellular is unavailable and the Notecard uses NTN for a periodic session, trailer_log_cell.qo and trailer_summary_cell.qo Notes get discarded at sync time. Their cellular/WiFi-only delete:true templates make the Notecard clear those queues instead of sending them over satellite, so only pending alert Notes carry payload data over the satellite link. Every NTN session still has session-establishment overhead (Skylo protocol + housekeeping), whatever the alert payload. Inbound checks cost satellite data too, about 50 bytes each per Satellite Best Practices, so the 120-minute inbound cadence spends roughly 600 bytes a day while a trailer is on NTN. Environment variables aren't templated, so they only arrive over cellular or WiFi anyway. For trailers that spend long stretches on satellite, set the _sync_inbound_mins_ntn reserved environment variable to a much longer interval.

7.7 Retry and error handling

  • If hubConfigure or template registration fails at power-up, loop() retries the full first-boot configuration on every wake and skips the sample cycle until it succeeds.
  • readTemperatures excludes any probe returning DEVICE_DISCONNECTED_C from all accumulation. If both probes fail for the whole summary window, all six temperature fields in the summary carry the −127 sentinel instead of a misleading mean of zero.
  • fetchEnvOverrides silently skips missing variables and keeps the current firmware default, so a Notehub project with no environment variables set is always valid.
  • Alert deduplication: temperature alerts are rate-limited by alert_cooldown_sec (default 30 minutes) so a slow-drifting probe doesn't flood the downstream on-call channel.
  • The door open-long reminder fires once per open event (the door_long_alert_sent flag in AppState). A door that stays open across several sleep cycles produces exactly one reminder, not one per sample.

7.8 Key code snippet 1: compact template definition

The templates registered at first boot make each Note a fixed-length binary record built for satellite transport. The "compact" format and port assignment on the alert Notefile meet the NTN requirements, and cellular fully supports them too, so the same file gets delivered correctly over either transport. The cellular/WiFi-only Notefiles skip compact format and the port, and they carry delete:true. When NTN is the active transport at sync time, the Notecard discards queued Notes from those cellular/WiFi-only Notefiles (see Blues Satellite Best Practices). defineTemplates() uses constants from reefer_cold_chain_monitor_helpers.h: NOTEFILE_ALERT is trailer_alert.qo on port 51 (TEMPLATE_PORT_ALERT), NOTEFILE_LOG is trailer_log_cell.qo, and NOTEFILE_SUMMARY is trailer_summary_cell.qo. Each request's response is checked, and any failure makes defineTemplates() return false so the next wake retries.

// ── Alert template (NTN-compatible, delivered over any transport) ─────────
{
    J *req = notecard.newRequest("note.template");
    if (req == NULL) return false;
    JAddStringToObject(req, "file",   NOTEFILE_ALERT);
    JAddNumberToObject(req, "port",   TEMPLATE_PORT_ALERT);
    JAddStringToObject(req, "format", "compact");
    // No delete:true — alert notes are never purged; they are delivered over
    // whichever transport (cellular or NTN) is available when hub.sync fires.
    J *body = JAddObjectToObject(req, "body");
    // String field: exemplar length = longest expected value
    // ("temp_excursion", 14 chars — ties "door_open_long" at 14 chars).
    JAddStringToObject(body, "alert",         "temp_excursion");
    JAddNumberToObject(body, "t1_c",           TFLOAT32);
    JAddNumberToObject(body, "t2_c",           TFLOAT32);
    JAddBoolToObject(body,   "door_open",      TBOOL);
    JAddNumberToObject(body, "door_open_sec",  TUINT32);
    JAddNumberToObject(body, "lat",            TFLOAT32);
    JAddNumberToObject(body, "lon",            TFLOAT32);
    J *rsp = notecard.requestAndResponse(req);
    // ...
}

// ── Per-sample log template (cellular/WiFi only) ──────────────────────────
{
    J *req = notecard.newRequest("note.template");
    if (req == NULL) return false;
    JAddStringToObject(req, "file",   NOTEFILE_LOG);
    JAddBoolToObject(req,   "delete", true);
    J *body = JAddObjectToObject(req, "body");
    JAddNumberToObject(body, "t1_c",      TFLOAT32);
    JAddNumberToObject(body, "t2_c",      TFLOAT32);
    JAddBoolToObject(body,   "door_open", TBOOL);
    // ...
}

// ── Hourly summary template (cellular/WiFi only) ──────────────────────────
{
    J *req = notecard.newRequest("note.template");
    if (req == NULL) return false;
    JAddStringToObject(req, "file",   NOTEFILE_SUMMARY);
    JAddBoolToObject(req,   "delete", true);
    J *body = JAddObjectToObject(req, "body");
    JAddNumberToObject(body, "t1_c",        TFLOAT32);
    JAddNumberToObject(body, "t2_c",        TFLOAT32);
    JAddNumberToObject(body, "t1_min_c",    TFLOAT32);
    JAddNumberToObject(body, "t1_max_c",    TFLOAT32);
    JAddNumberToObject(body, "t2_min_c",    TFLOAT32);
    JAddNumberToObject(body, "t2_max_c",    TFLOAT32);
    JAddNumberToObject(body, "door_events", TINT16);
    JAddBoolToObject(body,   "door_open",   TBOOL);
    // ...
}

7.9 Key code snippet 2: immediate-sync alert

The alert Note is enqueued without sync:true, and once the enqueue succeeds, a hub.sync call wakes the radio right away. On the NOTE-NBGLWX, the Notecard picks cellular when it has coverage and falls back to the Skylo satellite radio otherwise, and the firmware never needs to know which. The detection code (checkDoorEvents() or checkTemperatureExcursion()) reads the last GNSS fix with getLocation() when it latches the event and passes lat and lon in, so every alert is geo-stamped where the event happened, even on a retry after the trailer has moved.

The firmware treats hub.sync as part of the critical alert path. sendAlert() checks the response for NULL and responseError(), and it only returns true once the sync itself succeeds. If the sync fails, the pending-alert latch in AppState stays set and the next wake retries the sync, using the done flag to skip the note.add call that already queued the Note.

// ── Enqueue alert note ────────────────────────────────────────────────────
// Skip if already successfully enqueued on a prior wake (retry path).
if (!done) {
    J *req = notecard.newRequest("note.add");
    if (req != NULL) {
        JAddStringToObject(req, "file", NOTEFILE_ALERT);
        J *body = JAddObjectToObject(req, "body");
        JAddStringToObject(body, "alert",         type);
        JAddNumberToObject(body, "t1_c",          (double)t1);
        JAddNumberToObject(body, "t2_c",          (double)t2);
        JAddBoolToObject(body,   "door_open",     doorOpen);
        JAddNumberToObject(body, "door_open_sec", (double)openSec);
        JAddNumberToObject(body, "lat",           (double)lat);
        JAddNumberToObject(body, "lon",           (double)lon);
        J *rsp = notecard.requestAndResponse(req);
        if (rsp != NULL) {
            if (!notecard.responseError(rsp)) { done = true; }
            notecard.deleteResponse(rsp);
        }
    }
}

// ── Immediate sync ────────────────────────────────────────────────────────
// ...
bool sync_ok = false;
if (done) {
    J *req = notecard.newRequest("hub.sync");
    if (req != NULL) {
        J *rsp = notecard.requestAndResponse(req);
        if (rsp != NULL) {
            if (!notecard.responseError(rsp)) {
                sync_ok = true;
            } else {
                DEBUG_PRINTLN(F("[alert] hub.sync returned error — will retry"));
            }
            notecard.deleteResponse(rsp);
        }
        // ...
    }
}

bool ok = done && sync_ok;
// ...
return ok;

7.10 Key code snippet 3: sleeping until the Notecard raises ATTN

cxSleepUntilAttn() asks the Notecard to hold ATTN low for exactly g_sampleIntervalSec seconds, confirms the pin has gone low, and puts the STM32 into STOP2. The host stays alive, so the firmware checks the result of the card.attn request instead of firing it off and forgetting about it. The Notecard's ATTN pin brings the host back on schedule, and loop() carries on with the next sample, with the door timestamps, accumulator sums, and alert epochs all still in AppState.

void setup() {
    // ...
    // ── Arm the ATTN wake: the Notecard raises ATTN (D5) to end each sleep ────
    cxSleepBegin();
}

void loop() {
    // ...
    if (g_state.configured) {
        runSampleCycle();
    }
    // ...
    if (!cxSleepUntilAttn(notecard, g_sampleIntervalSec, NULL, log)) {
        // The Notecard didn't take the sleep request, or ATTN never went low
        // (check the ATTN -> D5 jumper). Keep the sample cadence and try again.
        DEBUG_PRINTLN(F("[warn] ATTN sleep failed — waiting out the interval awake"));
        delay(g_sampleIntervalSec * 1000UL);
    }
}

8. Data Flow

Data Flow

Every 60 seconds the firmware wakes up, reads both temperature probes and the door pin, and runs two independent checks (the door state machine and temperature excursion). Then it logs the raw sample, adds the data to the rolling hourly window, and goes back to sleep. Because the checks are independent, a door event and a temperature excursion at the same moment each produce their own alert.

Measured each sample cycle (every 60 seconds): forward-air temperature °C (probe 1), return-air temperature °C (probe 2), and door state (open/closed). Each sample gets its own entry in trailer_log_cell.qo (cellular/WiFi only, and discarded when the Notecard connects over NTN). The readings also feed a rolling hourly summary window (mean, min, max per probe). The Notecard tracks GNSS position on its own in the background (card.location.mode periodic, 600-second interval, motion-gated). The host MCU doesn't query location on every sample cycle. It only reads the last known fix when it detects an alert event, so every alert is geo-stamped at event-detection time without a per-sample GNSS query.

Transmitted:

  • trailer_alert.qo: evaluated and queued during the next sample cycle (up to sample_interval_sec after the event, default 60 seconds), then sent immediately with hub.sync (skipping the outbound timer) when a door opens, a door closes, a door stays open past door_alert_sec, a probe exceeds temp_max_c, or a probe drops below temp_min_c. It goes out over the first available transport (cellular preferred, NTN satellite as the fallback). Temperature alerts are rate-limited by alert_cooldown_sec.
  • trailer_log_cell.qo: one Note per sample cycle (default every 60 seconds), cellular/WiFi only, queued and shipped on the next outbound sync. Expect gaps during NTN-only coverage (see §10).
  • trailer_summary_cell.qo: one Note per summary_interval_min (default 60 minutes), cellular/WiFi only, queued and shipped on the next outbound sync. It holds the mean, min, and max for each probe plus the door-open count and the current door state.

Location. hubConfigure calls card.location.mode with mode:"periodic" and seconds:600, and from then on the Notecard tracks location by itself in the background. In periodic mode it only samples at the configured interval when it detects motion, so the GNSS radio comes on roughly every 10 minutes while the trailer is moving and stays off while it's stationary. The host MCU doesn't poll card.location on each 60-second sample cycle. Instead, checkDoorEvents and checkTemperatureExcursion make a single card.location request when they latch an alert event, and sendAlert embeds that fix as the lat/lon fields (a retry reuses the latched fix). Every alert gets geo-stamped with the trailer's position at event-detection time, and the routine sample cycle never has to make a GNSS query. When no fix has been acquired yet (first power-on, or an obstructed GNSS antenna), both fields are 0.0. The GNSS antenna needs an unobstructed view of the sky, so mount it on the trailer roof or an exterior wall, away from the refrigeration unit, as described in §5.

Routing. All three Notefiles land in Notehub, and routes send them on to downstream systems from there. A typical setup sends trailer_alert.qo to a TMS or messaging gateway (real-time dispatch), and sends trailer_log_cell.qo and trailer_summary_cell.qo to a cold-chain compliance database.

Alert triggers (all in trailer_alert.qo, delivered over cellular or NTN satellite):

  • door_open: the door went from closed to open. Syncs immediately.
  • door_close: the door went from open to closed, and door_open_sec carries how long it was open.
  • door_open_long: the door is still open after door_alert_sec seconds (default 10 minutes). Fires once per open event.
  • temp_excursion: either probe is above temp_max_c. Subject to alert_cooldown_sec dedup.
  • temp_cold: either probe is below temp_min_c. Subject to alert_cooldown_sec dedup.

9. Validation and Testing

Expected steady-state cadence. A healthy, closed, in-range trailer produces trailer_log_cell.qo Notes every 60 seconds (queued locally and arriving in Notehub on the hourly outbound session, up to 60 per batch), one trailer_summary_cell.qo per hour, and zero alert events. The first batch of log Notes reaches Notehub at the first outbound session (default 60 minutes). Alerts show up in trailer_alert.qo within one sample cycle (sample_interval_sec, default 60 seconds) of the event, plus network-establishment time.

Functional validation. You can confirm the alert flow without waiting for a real excursion:

  • Temperature (warm-excursion path): On a room-temperature bench the probes already read well above the 7 °C default, so the first sample after power-up fires a temp_excursion alert without anyone touching the probes. While they stay warm, another follows each time alert_cooldown_sec (default 30 minutes) runs out. The [sensor] lines in the serial output show the readings that tripped it.
  • Temperature (cold-excursion path): Put one probe in an ice-water bath (~0 °C) and temporarily raise temp_min_c to 5.0 in the Fleet environment variables. Also raise temp_max_c above room temperature (e.g., 30.0), because the firmware checks the warm threshold first and the room-temperature probe would otherwise keep winning. Once the next inbound sync pulls the new values and the cooldown has run out, the next sample with the iced probe triggers a temp_cold alert. After you've confirmed the alert, set temp_min_c back to -25.0 and temp_max_c back to your operational value.
  • Door: Pull the door sensor magnet away from the housing, and a door_open alert should appear within the next sample cycle. Bring the magnet back and check that door_close arrives with a non-zero door_open_sec.
  • Threshold tuning: Lower temp_max_c to 0.0 in the Fleet's environment variables. The next inbound sync pulls the new value, and the next sample cycle with any probe above 0 °C fires the alert.
  • Location: Make sure the GNSS antenna has a clear view of the sky outdoors. After at least one full card.location.mode fix interval (≤ 10 minutes on a moving or recently moved unit), trigger a door or temperature alert and check that lat and lon are non-zero in the resulting trailer_alert.qo Note body in Notehub. A (0.0, 0.0) pair means no fix has been acquired yet, so give it more time or check that the GPS antenna cable and connector are seated.

Power validation with Mojo. The published figures for Notecard for Skylo are ~8–18 µA idle (radio off between syncs) and ~250 mA average during cellular transmit, with millisecond spikes approaching 2 A in regions that need GSM. Satellite sessions have a similar current envelope but last longer.

Put the Mojo inline between the 5 V supply and the Notecarrier CX +VBAT pad. In steady state, expect a trace like this:

PhaseExpected current
Host in STOP2 + Notecard idle between samples~20–30 µA (Notecard ~8 µA + host ~1–2 µA, plus Notecarrier CX regulator quiescent)
Host awake (sensor reads + Notecard I²C)~5–15 mA for ~1–2 seconds per sample
Notecard cellular session (hourly)~250 mA average, 15–45 seconds
Notecard satellite session (NTN)~200–400 mA average, usually longer than LTE-M

With the defaults (60-second samples, 60-minute summaries, no alerts), a useful bench target is roughly 30–60 mAh per 24 h on cellular, most of it from the once-an-hour radio burst. Satellite-only operation uses more per session because the link takes longer to establish.

Measurement scope. Mojo sits on the 5 V output side of the Pololu regulator, so it only measures the downstream Notecarrier + Notecard draw at 5 V. The real draw from the 12 V trailer battery will be higher, because the Pololu adds its own quiescent current and conversion losses (the D24V22F5 is rated 85–95 % efficient under load, and it draws quiescent current even with no load). If parked-trailer battery drain is a concern, pair Mojo's 5 V measurement with an upstream current measurement on the 12 V feed. For a unit that will sit parked for long periods, consider a step-down regulator with lower quiescent current.

Two anomaly patterns jump out on a Mojo trace:

  • Host never sleeping: A flat, continuous 10–30 mA baseline means the host isn't entering STOP2. Check the ATTN→D5 jumper (without it the firmware waits out each interval awake and logs [warn] ATTN sleep failed), and confirm the firmware was built with USB support set to None (usb=none). With the USB CDC stack enabled, the host leaves STOP2 within a millisecond.
  • Excessive hourly bursts: Each session runs 2–3 minutes instead of 15–45 seconds. That's usually weak signal or frequent satellite fallback, so check the antenna routing and site coverage.

Mojo is a bench and commissioning tool, and production units don't need it.

A Notecarrier CX and a Notecard for Skylo team up with two DS18B20 probes and a magnetic reed switch to watch for the two failure modes behind most reefer trailer cargo loss, temperature excursion and unauthorized door access. The firmware samples every minute and queues each raw sample locally for Notehub delivery on the next outbound session (trailer_log_cell.qo). When any threshold trips, it fires an alert on the next sample cycle (up to ~60 seconds) over whatever radio is available (trailer_alert.qo, delivered automatically over cellular or NTN satellite). It also ships a compact hourly summary (trailer_summary_cell.qo) for compliance and trending. Thanks to the cellular + satellite multi-RAT design, the monitor stays connected as the trailer moves from an urban distribution center through rural interstates to a port staging yard, and nobody has to configure networks, swap SIMs, or negotiate with carriers.

The same firmware structure makes a good starting point for pharmaceutical cold chain, cross-border intermodal containers, or any mobile insulated enclosure where a temperature log and a door audit trail carry regulatory or financial weight.

10. Troubleshooting

SymptomLikely CauseWhat to Check
Device never appears in NotehubPRODUCT_UID is still the empty default, or the unit hasn't established a session on any radio yet.Confirm that PRODUCT_UID in reefer_cold_chain_monitor_helpers.h matches the value shown in your Notehub project. Watch the serial monitor at 115200 baud for [boot] and _session.qo lines. If any radio is in range, a session usually completes within a few minutes of first power-on. If only NTN coverage is available, expect the first session to take longer, and confirm the GNSS and MAIN antennas have an unobstructed view of the sky.
One or both DS18B20 probes report -127Probe wiring fault, missing 4.7 kOhm pull-up on the 1-Wire bus, or a damaged probe lead.Check that VDD goes to +3V3, GND to GND, and data to A0 on every probe. Confirm the 4.7 kOhm pull-up (included in the Adafruit #381 bag) sits between +3V3 and A0. Power-cycle with one probe at a time to find the failing lead. The firmware treats -127 as a sensor-fault sentinel, so one failed probe doesn't corrupt the other probe's summary average.
Implausible temperature readings (e.g. +85 then drifting)The DS18B20 reads +85 at power-on until the first conversion completes, and long unshielded cable runs can also pick up noise.Wait at least one full sample cycle before trusting a probe reading. Keep probe leads away from reefer wiring harnesses and inverter motors. If the problem continues, shorten the cable run or switch to a shielded extension.
Door state stuck false (closed) when the door is openThe magnet is still close to the reed switch, or the housing and magnet are mounted in reversed positions.The Adafruit #375 is normally-open, so a closed door (magnet near switch) reads LOW and an open door reads HIGH. Mount the housing on the stationary frame and the magnet on the moving leaf, not the other way around. Check that the gap closes to within 15 mm when the door shuts.
Door state stuck true (open)Cut or pinched 22 AWG extension cable, oxidized splice, or a failed reed switch.Continuity-test the extension wire end to end with the magnet held against the housing. Re-seat any butt splices, and reseal them with a gel-filled connector if water has reached the joint.
Cellular sessions succeed but no NTN sessions ever fireTerrestrial coverage satisfies the default selection, so NTN never gets exercised.That's expected with the wifi-cell-ntn policy, because NTN is a fallback and not a parallel path. To confirm NTN is healthy, take the unit to a known cellular dead zone or temporarily disable the cellular and WiFi paths with card.transport on the Notecard. Then watch for _session.qo entries that report an ntn transport in their session metadata.
Temperature alerts firing on a healthy loadThe threshold values don't match the actual cargo class, or one probe sits against a cold or warm spot inside the trailer.Open the Fleet's environment variables and confirm temp_max_c and temp_min_c match the cargo (fresh produce, frozen, or pharmaceutical). Compare both probe values in trailer_log_cell.qo. If one consistently disagrees with the other by several degrees, move it away from the evaporator outlet, the door seal, or direct return-air flow.
Hourly summaries and per-sample logs stop arriving for hoursThe trailer is parked in NTN-only coverage, so trailer_log_cell.qo and trailer_summary_cell.qo Notes are discarded at sync time and only alerts ride the satellite link.This is the documented behavior that protects the satellite budget. Once terrestrial coverage returns, per-sample logging and summaries resume on the next outbound session. The Notes discarded during the gap don't come back.
Battery / power loss after long parked dwellThe host isn't sleeping (missing ATTN→D5 jumper, or firmware built with USB support enabled), the Pololu D24V22F5's quiescent draw is on the 12 V trailer battery, or the regulator is wired ahead of an always-on circuit instead of an accessory feed.Use a Mojo trace to confirm the host enters STOP2 between samples. A flat 10–30 mA baseline means it doesn't, so check the ATTN→D5 jumper (§5) and the usb=none build option (§7.1). Tap the 12 V supply from a switched accessory circuit so the unit drops out when the trailer is fully parked. For installations that have to run continuously, budget for the regulator's own quiescent current on top of the Notecard's idle draw, and consider a lower-quiescent step-down regulator (see the measurement-scope note in §9).
GNSS fields stuck at 0.0, 0.0The GNSS antenna doesn't have a clear view of the sky, the u.FL connector isn't seated, or the trailer hasn't moved long enough to satisfy card.location.mode's motion-gated periodic sample.Reseat both u.FL connectors on the Notecard and reroute the GNSS antenna to the trailer roof or exterior wall, away from the refrigeration unit. Drive the trailer for at least one full 600-second interval, then confirm the next alert carries a non-zero fix.
Antenna or sky-view problems on SkyloAntenna substituted with a non-Skylo-certified part, or MAIN antenna mounted inside a metal enclosure.Confirm that the included Skylo-certified flexible antenna is on the MAIN port, since swapping in a different cellular or NTN whip decertifies the device on Skylo's network. Route the antenna outside the NEMA 4X enclosure and any steel trailer structure through a sealed IP68 cable gland. See §5 and the Blues Antenna Guide.

If your problem isn't covered above, search or post on the Blues community forum.

11. Limitations and Next Steps

The design covers the two failure modes behind most refrigerated cargo loss (excursion and unauthorized door access) with direct sensor input and no OEM reefer integration, so it works across mixed fleets. Humidity, multi-zone mapping, J1939 telemetry, and geofence logic were left out on purpose, to be added where a deployment calls for them.

Simplified for the POC

The POC keeps things simple in the places below, and that's deliberate. Once the basic excursion-and-door monitor has proven itself in the field, a real fleet deployment will want to add another sensor, finer placement guidance, or an OEM integration at each of them.

Two probes only. A 53 foot trailer can stratify by several degrees from front to rear and from floor to ceiling. This design puts one DS18B20 near the forward evaporator and one near the rear return-air panel. That's enough to catch a reefer failure or a gross excursion, but it's not a full thermal map of the cargo zone.

No humidity or dew-point sensor. Some loads, like leafy greens, certain pharmaceuticals, and paper goods, are sensitive to humidity as well as temperature, but the current Notes only carry temperature.

Coarse probe placement guidance. Section 4 specifies forward and rear positions, but it doesn't lay out an evaporator-vs-cargo-zone placement scheme calibrated to a particular load type or trailer geometry. Operators are expected to refine probe placement during their first commissioning runs.

Reed switch is binary, not multi-state. The Adafruit #375 only reports open or closed. It can't tell a door cracked an inch from one swung wide open, and on a split-rear configuration it has no way of knowing which door (left or right) was actuated.

No driver or dispatcher app integration. Notehub routes alerts to whatever downstream destination you configure, and this project doesn't ship a mobile app for the driver or a dashboard for dispatch.

No reefer ECU integration. The design is intentionally OEM-agnostic, so it can't read setpoint, defrost cycle, refrigerant pressure, fuel level, or alarm codes from the reefer controller itself. Operators see the cargo-zone temperature but not the reefer's health.

Single 12 V feed assumption. The wiring assumes a standard trailer accessory circuit. Battery-only installations, or ones that have to survive a fully parked trailer for days, would do better with a different power architecture, including an upstream regulator with lower quiescent draw.

Production Next Steps

After the basic monitor is running across a real fleet, these extensions are the natural next moves. They're listed roughly from most immediately useful to most dependent on outside integration.

Add humidity (and dew point) sensing by wiring an SHT41 to the Qwiic bus and adding rh_pct and dewpoint_c fields to the per-sample, summary, and alert Notes. The compact alert template has room for the extra fields without breaking the satellite data budget.

Multi-zone temperature mapping goes from two probes to four or six DS18B20s on the same 1-Wire bus (the library and template can scale) and reports per-zone min, mean, and max in the hourly summary. That helps with high-value loads, where a hot spot in one corner of the trailer is the early warning.

Reefer ECU integration adds a J1939 or CAN tap for fleets with homogeneous reefer units, so setpoint, defrost, fuel level, and alarm codes ride along with the cargo-zone telemetry. Add it alongside the existing Notes instead of replacing them.

Geofence-aware alerting uses the lat and lon fields already on every alert to quiet door-open events at known authorized stops (yard, customer DC, fuel network) and escalate door events at unexpected locations. That logic is best run in Notehub or downstream, not on the device.

Notecard Outboard DFU means turning on Outboard DFU, which the Notecarrier CX supports with no extra wiring, so threshold logic updates and bug fixes can ship over the air whenever the trailer has cellular or WiFi coverage. Firmware updates don't go over NTN, which is far too low-bandwidth for a firmware image.

Compliance reporting for FSMA-Cold and HACCP adds a Notehub route into a compliance archive that rolls the per-sample logs and hourly summaries up into per-shipment PDF reports. Those reports work for FSMA Sanitary Transportation rule audits and HACCP records at food shippers, or for pharma cold-chain release decisions.

12. Summary

The fleet dispatcher now has the two signals that matter most. One is a geo-stamped alert within roughly a minute when a door opens at an unexpected location, and the other is a temperature excursion caught while the load can still be re-routed. Notecard for Skylo picks cellular, NTN satellite, or WiFi at every moment of a haul without any firmware logic. It keeps the bundled satellite data budget intact by discarding the per-sample and hourly summary Notefiles at sync time when NTN is the active transport, and alerts ride the satellite link regardless. For shippers under FSMA Sanitary Transportation rules or HACCP records, and for pharmaceutical cold-chain operators on GDP terms, those same per-sample logs and hourly summaries double as the independent condition record that audits and freight claims demand.

The same skeleton carries over to pharma cold chain, cross-border intermodal containers, frozen-food long-haul, or any mobile insulated enclosure where a temperature log and a door audit trail have regulatory or financial weight.

On This Page

  • 1. Project Overview
  • 2. System Architecture
  • 3. Technical Summary
  • 4. Hardware Requirements
  • 5. Wiring and Assembly
  • 6. Notehub Setup
    • What you should see in Notehub
  • 7. Firmware Design
    • 7.1 Installing and flashing
    • 7.2 Template format codes (compact encoding)
    • 7.3 Modules
    • 7.4 Sensor reading strategy
    • 7.5 Event payload design
    • 7.6 Power and sync strategy
    • 7.7 Retry and error handling
    • 7.8 Key code snippet 1: compact template definition
    • 7.9 Key code snippet 2: immediate-sync alert
    • 7.10 Key code snippet 3: sleeping until the Notecard raises ATTN
  • 8. Data Flow
  • 9. Validation and Testing
  • 10. Troubleshooting
  • 11. Limitations and Next Steps
    • Simplified for the POC
    • Production Next Steps
  • 12. Summary

Resources

  • GitHub
  • Request More Info
Can we improve this page? Send us feedback
© 2026 Blues Inc.
© 2026 Blues Inc.
AboutDocsAPI ReferenceTermsPrivacy