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_rightTrailer Manufacturer Connected Trailer Platform

Trailer Manufacturer Connected Trailer Platform

Trailer Manufacturer Connected Trailer Platform 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/connected_trailer_platform/ so it can learn how the device works and help you adapt it to your hardware.

This project is a connected-trailer platform for trailer OEM integration, aimed at manufacturers who want to own the cellular and satellite connectivity layer on refrigerated trailers from day one. It continuously reports the operational signals a fleet operator actually checks back to the OEM's cloud: cargo-air temperature at two points inside the trailer, rear-door open/close events, GPS position, and, with vendor-specific decode work, reefer setpoint and tire pressure. That reporting keeps going across the cellular dead zones common on long rural hauls and at intermodal rail yards. When cellular coverage isn't available, the device falls back automatically to the Skylo non-terrestrial satellite network, so the cold-chain record stays continuous through coverage gaps. The hardware is a Blues Notecarrier CX paired with a Notecard for Skylo (§4 has the BOM). The firmware ships three sensor paths fully implemented today (cargo temperature, door, GPS) and two as integration-point stubs waiting on vendor engineering: J2497 reefer telemetry and TPMS tire pressure. You'll find all five paths summarized in the implementation-status callout below.

1. Project Overview

The problem. A refrigerated trailer is a one-time sale that lasts a decade or more. After it leaves the factory, the manufacturer's recurring revenue depends entirely on the services it can sell over that trailer's lifetime, and telematics is the obvious candidate. The trouble is that this fight is already underway on every refrigerated trailer on the road. Thermo King and Carrier, the two dominant reefer (refrigeration unit) OEMs, ship their own fleet connectivity built around the reefer unit's proprietary data ports, and aftermarket platform vendors layer on top of those. By the time a trailer reaches a fleet operator's yard, two or three telematics competitors are already reading its temperature and location, and every one of them has a head start.

A trailer OEM that wants to own the connectivity layer, instead of handing it to the reefer OEM, needs a hardware-and-software platform that's on the trailer from day one. That platform has to read everything the fleet operator actually cares about: the reefer setpoint and actual temperature from the refrigeration unit itself, body-air temperature at two points in the cargo space, tire pressure on every axle, rear-door events, and GPS for asset location and route compliance. The body-air readings are the data the shipper trusts at delivery time (not the reefer unit's own sensor), and the door events tell the cold-chain story. It also has to survive 10–15 years of operation across regions, carriers, and signal environments. That includes long rural hauls, intermodal drayage moves, and multi-day DC (distribution center) dwells where the trailer sits disconnected from the tractor for days at a stretch, often somewhere with unreliable cellular coverage.

Why Notecard. A trailer OEM can't commit to a modem it might have to re-source in year four of a ten-year program. Notecard for Skylo handles that at the module level. It combines LTE-M/NB-IoT cellular and Skylo satellite (via NTN, Non-Terrestrial Network, meaning communication through geostationary satellites instead of cell towers) in a single pre-certified M.2 form-factor module, with an embedded SIM, 500 MB of cellular data, and 10 years of service included. The OEM installs one hardware SKU, flashes one firmware image, and ships trailers into any regional market with no per-unit carrier activation, no SIM swaps, and no per-site recurring data-plan negotiation. When a trailer crosses into a cellular dead zone, like a mountain pass, a rural cold-storage depot, or a remote intermodal rail yard, Notecard for Skylo moves over to the Skylo satellite network on its own, so the cold-chain record and the TPMS safety log stay continuous. The Blues Notehub cloud service gives the OEM's cloud a single API endpoint no matter which radio delivered a given message. Pre-certified global cellular and satellite with included data, all in one module with a credible long-term roadmap, is the program-level assurance a trailer manufacturer needs to compete on the data layer instead of conceding it to the reefer OEM by default.

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.

Deployment scenario. A weatherproof enclosure mounts on the trailer's nose wall (the forward interior wall, next to the reefer unit). Notecard for Skylo's Skylo-certified flat-patch antenna mounts outside on the trailer roof with a clear view of the sky, and the GPS antenna goes on the roof too.

SAE J2497 (also marketed as PLC4TRUCKS) is the SAE standard for power-line communications over the existing power conductors in commercial-vehicle trailer wiring. The J2497 PLC signal rides on the J560 pin 7 circuit, which is the always-hot auxiliary/battery feed on the SAE J560 North American seven-pin trailer connector, not a stop-lamp or brake circuit. This reference build includes a documented integration point for a future J2497 coupling interface on that circuit, and the firmware scaffolding routes a POC placeholder through the data pipeline, but this is not a delivered sensor path. One practical caveat: J2497's dominant production use is trailer ABS warning-lamp telemetry, not reefer data. Most reefer-OEM telemetry in the field comes over vendor-proprietary serial diagnostic ports (Carrier Transicold DataLink, Thermo King DSR/DSR2) or J1939 over CAN, not over J2497. The firmware UART (Serial1) is the same interface either way. Only the decode function changes, so you can re-target the reference assumption to a different transport without rearchitecting the platform. §10 Limitations compares the alternative transports and covers the engineering it takes to activate any of them. Regional note: SAE J560 is the North American 7-pin standard. European trailers use ISO 1185 (7-pin) or ISO 3731 (13-pin) connectors with different pinouts, and J2497 PLC is deployed on the equivalent auxiliary circuit in those standards.

Two encapsulated NTC thermistors hang inside the cargo space, front and rear, and provide the independent body-air readings shippers use to verify cold-chain integrity at delivery. The build also includes a documented integration point for a future TPMS (Tire Pressure Monitoring System) gateway receiver. Firmware scaffolding and note-template fields for four tire positions are in place, but this isn't a delivered sensor path either, and real tire pressure data needs the vendor-specific engineering described in §10 Limitations. A magnetic reed switch on the rear door reports open/close state. The Notecarrier CX and its onboard STM32 host run the trailer state machine, while Notecard for Skylo handles all radio management, GNSS positioning, and Notehub data delivery.

While the tractor is connected, power comes from the trailer's 12 V auxiliary/battery circuit, J560 pin 7 (the always-hot auxiliary feed, separate from the stop-lamp and brake circuits). During DC dwells when the tractor is disconnected, a power-priority switching circuit automatically transfers to the reefer unit's own 12 V battery (integral to every refrigerated trailer), which keeps the power path alive through the dwell. Between sample cycles the host sleeps in STM32 STOP2 (a few µA) until the Notecard's ATTN pin wakes it via card.attn. That's what makes multi-day DC-dwell operation achievable within a practical reefer battery budget, and §7 has the details of the power architecture.

note

Platform sensor paths: implementation status

Fully implemented and buildable today:

  • Two NTC cargo-air thermistors with β-equation ADC conversion and window-aggregate min/max/mean statistics
  • Rear-door reed switch with open-time accumulation and distinct event counting
  • GPS asset tracking through Notecard's built-in GNSS, with motion-state detection and cadence switching
  • Notecard for Skylo (NOTE-NBGLWX) with automatic LTE-M/NB-IoT cellular → Skylo NTN satellite fallback
  • Templated binary summary Notes (trailer_summary.qo) and immediate-sync alert Notes (trailer_alert.qo)
  • Threshold and sync-cadence configuration driven by Notehub environment variables, updateable over the air
  • Dwell-capable host sleep via card.attn and STM32 STOP2. The host sleeps at a few µA between sample cycles until the Notecard's ATTN pin wakes it, so the only static draw during sleep is the Notecard's radio-idle floor (~8–18 µA) plus ~1–2 µA for the host

Integration-point stubs (require additional vendor engineering to activate):

  • Reefer telemetry over a serial UART (reference assumption: J2497 PLC): The firmware reserves Serial1 for a future reefer-telemetry source and runs a simplified POC frame through the full alert/summary pipeline. The reference design assumes a power-line-carrier link based on SAE J2497 / PLC4TRUCKS with a Yitran IT700 modem. Know going in that J2497's dominant deployed use is trailer ABS warning-lamp telemetry, and reefer telemetry over J2497 is uncommon in production. Most reefer telemetry in the field rides on vendor-proprietary serial diagnostic ports (Carrier Transicold DataLink over RS-232/RS-485, Thermo King Direct Smart Reefer / DSR2) or J1939 over CAN. You can re-target the firmware UART to any of those by replacing the decode function in drainReeferUart(). Only the transport changes, and the data pipeline stays the same. Activating any path takes (a) choosing the transport, (b) the matching application-layer stack and reefer-OEM message mapping, and (c) field validation. The reefer_sensor_loss alert is gated so it doesn't fire on a build with no reefer-telemetry source connected. See §10.
  • TPMS tire pressure: The firmware parses a generic POC packet format and routes pressures through the alert/summary pipeline, but production firmware has to replace the parser with the chosen vendor's proprietary decode library. See §10.

2. System Architecture

System architecture: 2 cargo NTC thermistors, rear-door reed, GPS via Notecard (plus J2497 + TPMS stubs) → Notecarrier CX with STM32 host and NOTE-NBGLWX → cellular or Skylo NTN satellite → Notehub → dispatch / cold chain / alerts

Device-side responsibilities. Each time the Notecard's ATTN signal wakes the STM32L433 host, the host reads the three fully implemented sensor inputs: both cargo-air thermistors (12-bit ADC with β-equation conversion), the rear-door reed switch, and the GPS position from the Notecard's built-in GNSS. Then it services the two UART stub channels, Serial1 for the J2497 reefer path and tpmsSerial for the TPMS path. Both UART parsers handle simplified POC frame formats, and neither produces real trailer data without the extra engineering described in §10. On every sample the host runs the threshold rules locally and decides whether the cycle calls for an immediate alert or just feeds the running summary accumulator. Between cycles it sleeps in STM32 STOP2, drawing a few microamps with RAM intact, until the Notecard's ATTN pin wakes it (see §7 Low-power strategy). All of the accumulated window state just stays in the PersistState struct in RAM. On each wake, before the sample cycle starts, the host gives both UART channels a 250 ms drain to catch frames arriving around the wake boundary. It drains them again between each blocking Notecard I²C transaction, so a long radio call doesn't shadow an incoming UART frame. All Notecard communication runs over I²C through the Notecarrier CX's internal routing, and the host never touches the radio or the cellular session.

Notecard responsibilities. From there, Notecard for Skylo keeps Notes in its on-device queue, picks between the cellular and satellite radios automatically, and flushes the queue on the hub.set outbound cadence the firmware sets for the current trailer state. That cadence is shorter in transit and longer during DC dwells. Notecard for Skylo ships with satellite fallback turned off, so the firmware sets card.transport to cell-ntn at power-up. Alert Notes marked sync:true skip the outbound timer entirely and bring up a radio session right away. GNSS is the Notecard's job too, and it automatically tags every Note that leaves the device with the last known position. Environment variables pushed from Notehub come back the other way over the same channel, so fleet operators can retune thresholds and sync cadences across an entire customer's trailers without anyone touching firmware.

Notehub responsibilities. The data lands in Notehub. Notes arrive over the internet, Notehub stores every event, and project-level routes send them on to wherever the OEM's cloud needs them. Fleet-level environment variables let the same firmware image handle very different cargo types. A frozen-goods customer and a produce customer differ only in the reefer temperature bands their fleet encodes, and they run the same device build. Smart Fleets let the OEM slice the installed base by customer, cargo class, or route region without ever forking the firmware.

Routing to the cloud (high level). Notehub can route to HTTP, MQTT, AWS, Azure, GCP, Snowflake, and other destinations. Route setup depends on your project, and this one doesn't ship a specific downstream endpoint. The Notehub routing docs cover the details.

3. Technical Summary

What you'll have when you're done: A Notecarrier CX sending templated sensor data to Notehub's cloud, with temperature and door-open alerts firing as soon as thresholds trip. You won't have J2497 reefer or TPMS data yet, since those are integration stubs, but the three fully implemented paths (cargo temperature, door, GPS) are ready for you to validate the platform on real hardware.

Time estimate: 30 minutes to flash and commission on the bench, plus 15 minutes if you're wiring thermistors for the first time.

  1. Install firmware dependencies.

    arduino-cli core install STMicroelectronics:stm32
    arduino-cli lib install "Blues Wireless Notecard" "STM32duino Low Power" "STM32duino RTC"
  2. Get your ProductUID and paste it into the sketch.

    • Sign up at notehub.io, create a project, and copy your ProductUID.
    • Open firmware/connected_trailer_platform/connected_trailer_platform.ino and paste the ProductUID into the empty PRODUCT_UID string at the top.
  3. Flash the sketch to Notecarrier CX.

    • Fit a jumper between the Notecarrier CX's ATTN and D10 pins so the Notecard can wake the host (see §5 Wiring).
    • With the Notecarrier CX's USB-C DIP switch in HST, plug the board (with Notecard for Skylo seated in the M.2 slot) into your computer and put the host in its DFU bootloader (hold BOOT, tap RST).
    • Build and upload:
      arduino-cli compile -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none --upload firmware/connected_trailer_platform/
      The usb=none board option turns off the USB CDC stack, which has to be off for the host to sleep (see §7). firmware/connected_trailer_platform/sketch.yaml sets the same board options, so running arduino-cli compile in that directory without -b picks them up too.
  4. Apply power and watch Notehub for data.

    • For bench testing, plug a 5 V USB power supply into the Notecarrier's USB-C port. Field units draw power from the 12 V trailer supply through the DC-DC converter.
    • Open Notehub and go to Devices. The Notecard associates itself automatically on first power-up.
    • Within 1–5 minutes (depending on cellular coverage), a _session.qo Note shows up to confirm the device's cellular registration.
    • Every 60 minutes (default summary_interval_min), the firmware queues a trailer_summary.qo Note with the temperature and door fields filled in. A bench unit counts as parked, so it syncs on the 240-minute outbound_parked_min cadence and summaries arrive in batches. If the thermistors aren't wired, the temperature fields show −9999.
  5. Wire the three sensors (optional for bench demo).

    • Two 10 kΩ NTC thermistors with 10 kΩ 1% series resistors on ADC pins A0 and A1 (see §5 Wiring for the voltage-divider schematic).
    • A magnetic door reed switch on GPIO D9 (pull-up enabled in firmware).
    • GPS and cellular/satellite antennas: already included with Notecard for Skylo.

    Once the sensors are wired, trailer_summary.qo reports real air_t1_* and air_t2_* fields and tracks door_open_min and door_event_count.

  6. Configure fleet environment variables (optional, defaults work out of the box).

    • In Notehub, go to Fleets and create one (or use the default).
    • Assign your device to the fleet.
    • Add Environment Variables to tune the thresholds and sync cadences (see §6 Notehub Setup, step 4 for the full variable list).
    • Changes reach the device on the next inbound sync, with no re-flash needed.

Here's a sample Note from this device:

{
  "reefer_set_f":      -9999.0,
  "reefer_min_f":      -9999.0,
  "reefer_max_f":      -9999.0,
  "reefer_mean_f":     -9999.0,
  "air_t1_min_f":      35.6,
  "air_t1_max_f":      37.2,
  "air_t1_mean_f":     36.3,
  "air_t2_min_f":      35.1,
  "air_t2_max_f":      36.8,
  "air_t2_mean_f":     35.9,
  "door_open_min":      0.0,
  "door_event_count":     0,
  "tpms_0_psi":      -9999.0,
  "tpms_1_psi":      -9999.0,
  "tpms_2_psi":      -9999.0,
  "tpms_3_psi":      -9999.0,
  "tpms_0_age":           1,
  "tpms_1_age":           1,
  "tpms_2_age":           1,
  "tpms_3_age":           1,
  "trailer_state":        2,
  "sample_count":        12
}

4. Hardware Requirements

PartQtyRationale
Notecarrier CX1Integrated carrier with an embedded STM32L433 host, so you don't need a separate MCU. Notecard for Skylo seats in its M.2 slot. The host sleeps in STOP2 between sample cycles until the Notecard's ATTN pin wakes it.
Notecard for Skylo (NOTE-NBGLWX)1LTE-M/NB-IoT cellular + Skylo NTN satellite + integrated GNSS in one pre-certified module. One SKU covers any region. Once the firmware sets card.transport to cell-ntn at power-up, cellular-to-satellite fallback happens automatically without the host getting involved.
Blues Mojo1Coulomb counter for checking the power envelope during bench commissioning.
10 kΩ NTC thermistor, β≈3950, encapsulated probe (Adafruit 372)2Cargo-air temperature at two points, front and rear of the trailer. These are the independent readings shippers use to verify cold-chain integrity at delivery, separate from the reefer unit's own sensor.
10 kΩ 1% resistor2Voltage-divider series resistor for each thermistor on A0 and A1.
Magnetic door sensor, N.C., panel-mount (Adafruit 375)1Rear door open/close state on D9. When the door is closed, the magnet holds the N.C. contact open and the pull-up drives the pin HIGH (doorOpen = false). When the door opens, the magnet moves away, and the N.C. contact closes to GND and pulls the pin LOW (doorOpen = true).
Skylo-certified flat-patch antenna with u.FL lead (included with Notecard for Skylo)1Connects to the MAIN u.FL port on Notecard for Skylo. This one included antenna covers both LTE-M/NB-IoT cellular and Skylo NTN satellite (S-Band/L-Band, B23/B255/B256), so you don't need or install a separate cellular antenna. Mount it outside on the roof, flat face toward the sky, with ≥10 mm clearance on all edges. Replacing or modifying this antenna, or adding RF connectors to the antenna lead, voids the Skylo network certification and may get the device blocked by Skylo. Route the included lead through an IP68-rated cable gland (see §5), not through an added RF connector or bulkhead adapter.
Passive GPS/GNSS antenna, u.FL, exterior-mount (Taoglas AA.162 passive patch, −40 to +85 °C)1Connects to the GPS u.FL port on Notecard for Skylo. This build uses a passive (un-amplified) antenna, so it needs no bias wiring. An active antenna also works if you jumper the Notecarrier CX's VGPS_OUT pin to VGPS_IN to power its LNA. Mount it on the roof with a clear sky view, and route the coax through a weatherproof u.FL-to-SMA bulkhead feedthrough.
DC-DC converter, 9–36 V input, 5 V/3 A output (Mean Well DDR-15G-5)1Steps the 12 V supply (from the tractor auxiliary line when connected, or the reefer battery during DC dwells) down to the 5 V rail that powers the Notecarrier CX. The DDR-15G-5's 36 V maximum input leaves margin for the trailer's normal transient envelope above 12 V nominal. It's a DIN-rail unit, so mount it on a short rail section inside the enclosure.
Power-priority OR circuit: ON Semi MBRS340T3G automotive Schottky diode, 3 A / 40 V2One diode per 12 V input leg (tractor aux and reefer battery), with anodes to their own inputs and cathodes joined at a common output node that feeds the DC-DC converter VIN. It passes whichever source has the higher voltage with no host involvement, and the Schottky's reverse blocking also protects each input against polarity reversal. Forward drop is ~0.4 V at full load, which is fine for a 12 V rail. In production, a low-drop ideal-diode controller (e.g., TI LM74700-Q1, AEC-Q100) cuts forward drop to millivolts but adds FETs and layout complexity. Do not use low-voltage power mux ICs (e.g., TPS2116, max 5.5 V), because trailer supply and load-dump transients far exceed their rating.
IP68 polycarbonate enclosure, ≥160×120×60 mm (Hammond 1555H2GY, 180×120×60 mm, light gray, IP68)1Nose-wall mount, rated against refrigeration condensation and high-pressure washing during trailer cleaning. Look for IP67 or better, a polycarbonate or ABS body (survives trailer wash-down chemicals), continuous service to −40 °C, ≥160 mm internal length to fit the Notecarrier CX with antenna feedthrough headers, and cable-gland knockouts on at least one long face.
Weatherproof inline blade fuse holder + 7.5 A slow-blow ATC/ATO automotive blade fuse2One per 12 V input leg (J560 pin 7 tractor aux and reefer battery). Put the fuse as close to the source as practical, ahead of every other component on that leg. The slow-blow rating rides through DC-DC converter inrush.
Automotive transient protection, Stage 1: Bourns MOV-20D330K metal-oxide varistor, 20 V RMS, 26 V DC, 23 J energy rating (8/20 µs), 20 mm disc, radial leads, THT2One per 12 V input leg (tractor-aux and reefer-battery), installed from the fused hot wire to chassis GND just before each OR-circuit Schottky diode anode. An ISO 7637-2 pulse 5b load dump at a 12 V system's nominal 4 Ω source impedance can deliver up to ≈ 190 J per event, far more than the MOV's 23 J rating, so a single MOV can't be counted on to absorb a worst-case load dump. Measure against your tractors' actual load-dump behavior before production, and add the LM74721-Q1 third stage described in the next row if the margin isn't there. The 7.5 A slow-blow fuse on each leg limits peak surge current into the MOV. Keep the fuse-to-MOV wiring as short as practical to keep lead inductance low.
Automotive transient protection, Stage 2: Vishay SMBJ26CA bidirectional TVS diode, 26 V standoff, 600 W peak, DO-214AA (SMB package)1Installed from the OR-circuit common cathode output node to chassis GND, between the Schottky cathode junction and the DDR-15G-5 VIN. It clips fast inductive-kick transients (µs timescale) that the MOV's finite reaction time doesn't fully stop. Together with the two upstream MOVs, this two-stage design keeps the DDR-15G-5 VIN within its 36 V maximum input under typical 12 V trailer ISO 7637-2 conditions. Some installations have very short, low-resistance wiring to a high-output alternator, where source impedance is well below 4 Ω. For those, verify the MOV peak surge-current margin against the Bourns MOV-20D330K datasheet, and if it's warranted, add a TI LM74721-Q1 (AEC-Q100) surge-stopper IC with an external ≥ 100 V N-channel MOSFET as a third stage between the Stage 1 and Stage 2 elements.
IP68 cable gland sized for the Skylo flat-patch antenna lead (e.g., M16 or M20 IP68 nylon cable gland)1Gets the included Skylo-certified antenna lead through the enclosure wall without adding any RF connector to the certified cable path. Thread the lead through the gland and tighten it against the cable jacket. Do not use a u.FL-to-SMA bulkhead adapter or any other RF connector on this lead. Adding connectors to the certified cable/antenna assembly changes the approved RF path and voids Skylo certification.
u.FL to SMA panel-mount bulkhead feedthrough adapter, IP67, stainless steel or nickel-plated brass body, with SMA-to-u.FL pigtail1Only for the GPS passive patch antenna coax (Notecard for Skylo GPS port). The GPS antenna isn't part of the Skylo RF certification, so a standard weatherproof RF feedthrough is fine here. Do not use this kind of assembly on the Skylo flat-patch antenna lead (MAIN port).
SAE J560 pin 7 wire tap: weatherproof butt-splice or ring terminal, rated for 10–12 AWG wire1Taps the trailer's existing pin 7 (blue, auxiliary/battery circuit) wire at or near the nose-wall J560 socket to feed the inline fuse holder and then OR circuit Input A. Use a crimp-sealed weatherproof butt-splice connector or a ring terminal on the right stud. Don't use insulation-displacement taps on trailer supply wiring.

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.

Future Integration Hardware

These items are not part of this reference build, so don't buy or assemble them until the matching integration engineering is done. The firmware includes stub parsers for both paths as placeholders, and §10 covers the full engineering scope needed before either one produces real trailer data.

PartQtyNotes
J2497 PLC modem custom board: Microchip (Yitran) IT700 (note: IT700 is legacy; Microchip's IT900A is the current backward-compatible successor) PLC modem IC + Bourns PT60234PEL bus-coupling transformer + bus-clamping TVS diodes and ferrite filter on a custom PCB1No off-the-shelf J2497 module with UART output exists, and the custom board only solves the physical modem layer. Three more engineering layers have to be in place before any reefer data flows: (a) a licensed J2497 application-layer protocol stack, (b) reefer-OEM message mapping under a vendor agreement, and (c) field validation. See §10 and Future Integration: J2497.
TPMS OEM gateway: PressurePro CORE OEM Module (or equivalent), 315 MHz, 12 V DC, serial data output1Built for trailer OEM integration, with a serial data port. The firmware's TPMS parser is a POC stub that models a generic one-frame-per-tire format no commercial gateway actually produces, so production firmware has to replace it with the chosen vendor's protocol decode library. See §10 and Future Integration: TPMS Receiver Path.

5. Wiring and Assembly

Wiring: 2 NTC thermistors to A0/A1, rear-door reed to D9 INPUT_PULLUP, ATTN → D10 jumper so the Notecard can wake the host from STOP2, MAIN antenna to u.FL (cell + Skylo sat), passive GPS antenna to GPS u.FL; dual 12 V input through OR-circuit and transient protection → DC-DC 5 V → +VBAT

Inside the nose-wall enclosure, everything traces back to the Notecarrier CX and its dual 16-pin headers. Notecard for Skylo seats in the carrier's M.2 slot, and the rest of the trailer-side wiring (thermistor leads, door reed, the ATTN-to-D10 sleep jumper, the J560-pin-7 supply, and antenna pigtails) comes back to that header from around the box. Two routing rules are easy to get wrong, so here they are up front. The GPS antenna coax leaves the enclosure through the weatherproof u.FL-to-SMA bulkhead feedthrough. The Skylo MAIN antenna lead, on the other hand, must pass through an IP68 cable gland only, and never through a bulkhead adapter or any other RF connector (see the BOM and the MAIN u.FL bullet below). During bench power validation, the Mojo sits inline between the DC-DC converter's 5V output and the Notecarrier's +VBAT pad. Remove it from the field unit once commissioning is done, or leave it in place if you want fleet-level energy telemetry. In field installations, the DC-DC converter's VIN comes from the power-priority switching module described in the power chain below, not straight from J560 pin 7.

Pin-by-pin:

  • 12V trailer supply chain (power inputs, field installation). J560 pin 7 (trailer auxiliary/battery circuit, always-hot when tractor is connected; SAE J560 North American standard) → 7.5 A slow-blow inline fuse + fuse holder → Bourns MOV-20D330K to chassis GND (Stage 1 transient clamp, one per leg) → OR circuit Input A (the MBRS340T3G Schottky diode in the OR circuit inherently blocks reverse-polarity on this input). OR circuit Input B: reefer unit battery positive → 7.5 A slow-blow inline fuse + fuse holder → cable run to nose-wall enclosure → Bourns MOV-20D330K to chassis GND (Stage 1, Input B leg) → OR circuit Input B. The reefer battery is the only Input B source documented in this design. Some field deployments use a standalone dedicated telematics battery instead, but that needs a charge controller, float charger, and low-voltage disconnect. Don't substitute a bare battery without those, or it will eventually fail from deep cycling. OR circuit common cathode output → Vishay SMBJ26CA to chassis GND (Stage 2 TVS, fast inductive-spike clamp) → DDR-15G-5 VIN. DC-DC converter VOUT (5 V) → Mojo BAT → Mojo LOAD → Notecarrier CX +VBAT.
  • MAIN u.FL port (Notecard for Skylo) → the included Skylo-certified flat-patch antenna lead. This single antenna covers both LTE-M/NB-IoT cellular and Skylo NTN satellite (S-Band/L-Band, B23/B255/B256), so you don't need a separate cellular antenna. Thread the included lead through an IP68 cable gland (see BOM) in the enclosure wall, and cinch the gland against the cable jacket to keep the IP68 enclosure rating. Lay the flat-patch antenna face-up on the trailer roof with ≥10 mm clearance on all sides. Do not insert a u.FL-to-SMA adapter, SMA bulkhead, pigtail, or any other RF connector into this antenna lead. Adding connectors to the certified cable/antenna assembly changes the approved RF path and voids Skylo network certification.
  • GPS u.FL port (Notecard for Skylo) → passive GPS/GNSS antenna lead, routed through the u.FL-to-SMA bulkhead feedthrough (see BOM) to an exterior roof-mount passive patch antenna (e.g. Taoglas AA.162). The GPS port only gets DC bias if you jumper the CX's VGPS_OUT pin to VGPS_IN, so an active (amplified) antenna won't work without that jumper. Mount it with an unobstructed sky view.
  • +3V3 (out) → high-side lead of each NTC thermistor probe. There are two separate voltage dividers, one per probe, wired +3V3 → NTC probe → ADC node → 10 kΩ series resistor → GND. The NTC sits on the high side so the firmware's β-equation formula, R = R_series × (ADC_MAX / raw − 1), computes the correct thermistor resistance. When a J2497 custom board is eventually built, its IT700 logic VCC also comes from this +3V3 rail, which keeps that current on the Mojo trace. See the Future Integration: J2497 PLC Modem Path subsection below.
  • GND → low side of each 10 kΩ series resistor (divider low leg) and one lead of the door sensor. Keep signal grounds away from the trailer's chassis ground to avoid noise pickup on the UART channels.
  • A0 → wiper of thermistor 1 voltage divider (front probe, suspended midway up the nose wall, away from the reefer discharge coil).
  • A1 → wiper of thermistor 2 voltage divider (rear probe, suspended midway up the rear door jamb).
  • D5 / D6 → (future integration, no external connection required on the current reference build) The firmware initializes SoftwareSerial TX/RX on these pins as integration-point stubs for the TPMS receiver. With no gateway connected, they receive no data and every TPMS position reports −9999. See Future Integration: TPMS Receiver Path below for the wiring once you add a TPMS gateway.
  • D9 → one lead of the magnetic door sensor (the other lead ties to GND). The firmware enables the STM32's internal pull-up. When the door is closed, the magnet holds the N.C. contact open, so there's no GND path and the pull-up drives the pin HIGH (doorOpen = false). When the door opens, the magnet moves away and the N.C. contact returns to its closed (conducting) state, which creates a GND path that pulls the pin LOW (doorOpen = true).
  • D10 → ATTN (host sleep jumper). Fit a short jumper between the ATTN and D10 pins on the Notecarrier CX header. Both are on the same 16-pin header as D5/D6/D9. D5 is the usual choice for this jumper, but here D5/D6 carry the TPMS SoftwareSerial and D9 the door reed, so the firmware uses D10 via CX_ATTN_PIN. The Notecard pulls ATTN low while the host sleeps and raises it when the next sample is due, and the rising edge on D10 wakes the host from STOP2. Leave the Notecarrier CX EN pin 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.
  • SDA / SCL → routed internally on the Notecarrier CX between the STM32 host and the Notecard, so I²C needs no external wiring.
  • +VBAT → Mojo LOAD output (bench commissioning), with the Mojo BAT input ← 5V from the DC-DC converter VOUT. The power inputs bullet above shows the full supply path from trailer 12V to +VBAT.

Mount the enclosure on the nose wall high enough that every connector sits above the refrigerant condensation zone and the floor wash zone (typically ≥300 mm above the floor). Hang the thermistor probes from nylon tie-mounts anchored to the interior wall studs, with T1 at the front quarter of the trailer and T2 at the rear quarter near the door jamb, both clear of any cargo contact. Route the GPS antenna coax through the enclosure wall with the u.FL-to-SMA bulkhead feedthrough. The Skylo MAIN antenna lead goes through the IP68 cable gland only, never through the bulkhead feedthrough or any RF connector. Lay the Skylo flat-patch antenna face-up on the trailer roof with ≥10 mm clearance on all sides. Don't run antenna coax parallel to 12 V DC supply wires. Keep ≥50 mm of separation, or cross at 90° where they can't avoid being close.

Power input protection. Commercial trailer wiring is electrically harsh. J560 load-dump transients can reach 87 V peak under ISO 7637-2 pulse 5b conditions, and polarity reversal is a common field error. The fuse holders + 7.5 A slow-blow fuses and the MBRS340T3G OR-circuit Schottky diodes (which also block reverse polarity on each input leg) in the §4 BOM are non-negotiable. That Schottky OR circuit handles dual-source priority selection and reverse-polarity protection, but it isn't a transient clamp. Transient suppression comes from the two-stage protection specified in §4. One Bourns MOV-20D330K per input leg (installed from the fused hot wire to chassis GND before the Schottky anode) takes the first hit of load-dump energy. At 4 Ω source impedance a pulse 5b event can deliver up to ≈ 190 J, far more than the MOV's 23 J rating, so check that margin on real tractors before production. The Vishay SMBJ26CA bidirectional TVS on the common OR-circuit cathode output node then clamps the leftover fast inductive-kick transients before they reach the DDR-15G-5 VIN (36 V maximum input). The two stages are meant to hold the converter input within its rating in the nominal 4 Ω source-impedance scenario, but only if that MOV margin holds up. For installations with very short, low-impedance wiring near a high-output alternator, check the MOV peak surge-current margin against the Bourns datasheet, and see the TI LM74721-Q1 application notes if you need an active third stage.

Future Integration: Reefer Telemetry UART (Reference: J2497 PLC Modem Path)

warning

This subsection documents future integration work, not the current reference build. The firmware reserves Serial1 for a reefer-telemetry source. The reference assumption is a J2497 PLC modem because it keeps the physical interface to the trailer J560-only. That said, the IT700 coupling board doesn't exist and the J2497 application stack isn't licensed, so only add this wiring once both of those pieces are in place.

Before committing to J2497, read the alternatives. J2497 / PLC4TRUCKS is the SAE standard for trailer power-line communications, but its dominant deployed use is ABS warning-lamp telemetry. Production reefer telemetry usually rides on a vendor-proprietary serial diagnostic port (Carrier Transicold DataLink over RS-232/RS-485, Thermo King DSR/DSR2 over serial) or J1939 over CAN. Either one is mechanically simpler than building a PLC coupling board and better documented at the protocol level. The firmware's Serial1 channel and drainReeferUart() decode function don't care which interface you use. Any 9600-baud serial source whose decode produces setpoint_f and actual_f values into g_sensors will run through the rest of the alert/summary pipeline unchanged. §10 Limitations has the side-by-side comparison.

Once a J2497 custom board is built, it connects to the Notecarrier CX like this:

  • +3V3 (out) → J2497 custom board logic VCC (IT700 runs at 3.3 V logic). That puts the J2497 board's active-mode current on the Notecarrier +3V3 rail and on the Mojo +VBAT trace, so include it in the bench power budget.
  • GND → J2497 board logic GND. Keep signal ground separate from the trailer chassis ground stud.
  • RX (Serial1) → UART TX of the J2497 custom board (the IT700 host interface at 9600 baud, 8N1; match the protocol-stack or modem-IC datasheet). Without an application-layer stack, this line carries raw PLC modem bytes, not decoded reefer frames. Level-shift to 3.3 V if the board's logic level is 5 V.
  • TX (Serial1) → UART RX of the J2497 custom board (for polling commands the host sends to the modem).
  • J560 pin 7 coupling: The IT700's modulator/demodulator output couples to the J560 pin 7 (AUX) bus through the Bourns PT60234PEL coupling transformer. It's an AC-coupled signal path. The transformer primary connects to the 12 V bus for PLC signal injection/detection but draws negligible DC from that rail. Keep the transformer primary side and the J560 bus-facing circuitry isolated from the Notecarrier's +3V3 and GND rails. The Bourns PT60234PEL datasheet and the Microchip IT700 PLC Design Guide cover the schematic, PCB layout, and bus-protection requirements. Don't try to breadboard this signal path.

Interface summary (for when the board is built):

SignalDirectionNotecarrier CX pinJ2497 board pinNotes
Logic VCC→ board+3V3VCC (IT700)~2–15 mA active (bench-measure)
Logic GNDcommonGNDGNDSignal ground; isolated from chassis
UART RX data← boardRX (Serial1)TX (IT700 host)9600 baud 8N1; level-shift if 5 V
UART TX cmd→ boardTX (Serial1)RX (IT700 host)9600 baud 8N1
PLC bus← J560 pin 7NoneCoupling xfmrAC-coupled via PT60234PEL

Future Integration: TPMS Receiver Path

warning

This subsection documents future integration work, not the current reference build. The SoftwareSerial channel on D5/D6 is compiled into the firmware as a placeholder for a TPMS receiver. Don't buy or connect a gateway until you've picked a specific vendor and that vendor's protocol decode library has replaced the stub parser in trailer_sensors.cpp. With no gateway connected, all four TPMS positions report −9999 in every summary Note.

Once a TPMS OEM gateway (e.g., PressurePro CORE OEM Module) is integrated, it connects to the Notecarrier CX like this:

  • D6 → TPMS gateway UART TX output (SoftwareSerial RX on the host side). 9600 baud, 8N1 is typical, but match the gateway's datasheet. Level-shift to 3.3 V logic if the gateway runs at 5 V.
  • D5 → TPMS gateway UART RX input (SoftwareSerial TX on the host side, used for any poll commands the host sends to the gateway if the vendor protocol needs them).
  • 12 V supply rail → TPMS gateway VCC (the PressurePro CORE OEM module runs at 12 V DC, but check the chosen module's datasheet). Power it from the same fused 12 V rail as the DC-DC converter VIN, not through the Notecarrier's +3V3 or +5V pins. TPMS gateway GND → enclosure ground bus (shared with thermistor GND, and kept separate from the trailer chassis ground stud so UART noise stays out).

Production firmware change required: replace drainTpmsUart() in trailer_sensors.cpp with the vendor's message decode library. The POC stub parses a generic 6-byte frame format that no commercial gateway produces, so a real gateway connected without this replacement won't give you any valid data.

6. Notehub Setup

  1. Create a project. Sign up at notehub.io and create a project. Copy the ProductUID and paste it into firmware/connected_trailer_platform/connected_trailer_platform.ino as PRODUCT_UID.

  2. Provision the Notecard. Power the unit. The Notecard associates itself with your project automatically on its first cellular or satellite session, and the device shows up in Notehub under the Notecard's DeviceUID, ready for fleet assignment.

  3. Create fleets by customer or cargo class. Fleets group devices for shared configuration. The natural unit here is one fleet per OEM customer or cargo type. Frozen-goods trailers and produce trailers run different reefer temperature bands, and fleet-level environment variables capture those differences without separate firmware builds. Smart Fleets can assign trailers to fleets automatically, based on device attributes set at provisioning time.

  4. Set environment variables. All variables are optional. The firmware's compile-time defaults apply until an override arrives from Notehub, and overrides reach the device on the next inbound sync with no firmware reflash. The firmware registers all ten names with env.template, which is what lets overrides arrive over satellite as well as cellular.

    To set variables in Notehub: Go to Fleets → select your fleet → Environment tab. Add each variable as a key-value pair (e.g., key sample_interval_sec, value 300). Notehub pushes changes to assigned devices on the next inbound sync.

    Active on this build (fully-implemented sensor paths):

    VariableDefaultPurpose
    door_open_transit_sec300Door-open duration (seconds) in transit above which door_open_transit fires, flagging a cargo security or seal-integrity event.
    sample_interval_sec300Seconds between sensor sample cycles. Raise it to 900 or more during long DC dwells to cut host activity.
    summary_interval_min60Minutes between templated window-aggregate summary Notes sent to trailer_summary.qo. Each Note spans all sample cycles within the window.
    outbound_transit_min60Notehub outbound sync cadence (minutes) while the trailer is in transit.
    outbound_parked_min240Notehub outbound sync cadence (minutes) during DC dwells and parked periods.
    alert_cooldown_sec1800Minimum seconds between alerts of the same type. The 30-minute default prevents alert floods during a long excursion.

    Integration stub variables, not active against real trailer hardware. These thresholds are compiled in and take effect once the matching sensor path is implemented with a real J2497 modem and TPMS gateway. On a build without that hardware, the related sensor fields stay at −9999 and no reefer or TPMS alerts fire.

    VariableDefaultPurpose
    reefer_max_f40.0Reefer actual temperature (°F) above which reefer_temp_high fires because the cargo is at risk. Evaluates against J2497 stub data only until the real J2497 path is implemented.
    reefer_min_f28.0Reefer actual temperature (°F) below which reefer_temp_low fires, signaling freeze risk for temperature-sensitive loads. Evaluates against J2497 stub data only.
    tpms_min_psi95.0Tire pressure (PSI) below which tpms_pressure_low fires as a blowout precursor. Evaluates against TPMS stub data only until the vendor decode library is implemented.
    tpms_max_psi130.0Tire pressure (PSI) above which tpms_pressure_high fires on over-inflation or thermal runaway. Evaluates against TPMS stub data only.
  5. Configure routes. Add one route for trailer_alert.qo (low-volume, real-time delivery to the OEM's fleet management system or on-call endpoint) and a second for trailer_summary.qo (higher-volume, batched delivery to a cold-chain compliance archive or time-series store). Since the Notefiles are separate at the source, each one can go to a different destination at a different urgency without any filter logic in the route.

7. Firmware Design

The firmware is split across four files (orchestration, shared types, sensor helpers, and host-sleep mechanics), so each concern has a clear home:

FileRole
connected_trailer_platform.inoMain sketch: setup() runs once at power-up (hardware init → Notecard configuration → door interrupt → ATTN wake armed); loop() runs one wake (env-var fetch → UART drain window → sample cycle) and sleeps the host in STOP2 via cxSleepUntilAttn(). It also holds the trailer state machine, alert evaluation, and summary-Note assembly.
trailer_sensors.hShared header: pin assignments, protocol constants, compile-time defaults, Config / Sensors / TempAccum / PersistState struct definitions, and extern declarations for all globals and helper function prototypes. Included by both translation units.
trailer_sensors.cppSensor helpers: door-edge ISR and setupDoorInterrupt(), drainReeferUart(), drainTpmsUart(), updateReeferMissCount(), readThermistors() (16-sample β-equation ADC), and accumulateSampleStats().
cx_sleep.hHost sleep: card.attn request, STOP2 entry, ATTN wake.

Dependencies:

  • Arduino core for STM32 (stm32duino/Arduino_Core_STM32).
  • Blues Wireless Notecard (the note-arduino library). Install it from the Arduino Library Manager by searching for Blues Wireless Notecard and picking the latest version, or from the CLI with arduino-cli lib install "Blues Wireless Notecard". Check the note-arduino releases page for updates before you build.
  • SoftwareSerial (included in the STM32 Arduino core) for the TPMS receiver on D5/D6.
  • STM32duino Low Power and its dependency STM32duino RTC. Install them from the Library Manager or with arduino-cli lib install "STM32duino Low Power" "STM32duino RTC". They provide the STOP2 entry and ATTN-pin wake used in cx_sleep.h.

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 (trailer power, 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 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).

Modules

ResponsibilityFunction
Host sleep (STOP2 until the Notecard raises ATTN on D10)cx_sleep.h: cxSleepBegin() in setup(), cxSleepUntilAttn() in loop()
Application state (held in RAM across sleep cycles)PersistState (g_ps)
Notecard configuration (hub.set, card.transport, env.template, templates, GPS mode), power-up onlynotecardInit(), defineTemplate()
Sync cadence switching on state transitionapplyHubSetIfChanged()
Environment variable fetch and application, every wakefetchEnvOverrides()
Post-wake UART drain window (WAKE_UART_DRAIN_MS)inline in loop(), calls drainReeferUart() / drainTpmsUart()
J2497 UART drain, frame latch, j2497Commissioned gatedrainReeferUart()
Reefer miss-counter assessment (j2497Commissioned gated)updateReeferMissCount()
Thermistor ADC read and β-equation conversionreadThermistors(), adcToF()
TPMS UART drain, pressure latch, tpmsPsiLast mirrordrainTpmsUart()
Per-sample window accumulation (temps, door)accumulateSampleStats()
Trailer state machine (parked / loading / in transit)updateTrailerState()
Alert threshold evaluation and cooldown trackingevaluateAlerts(), sendAlert()
Windowed summary Note (min/max/mean aggregates) + epoch window advancesendSummary()

Sensor reading strategy

  • Reefer temperature (J2497 UART). drainReeferUart() runs during the WAKE_UART_DRAIN_MS window at wakeup and between blocking Notecard I²C calls in the sample cycle. It scans Serial1 for the two-byte header (0xAA 0x55) and verifies the XOR checksum before latching the setpoint and actual-temperature fields (signed 16-bit, 0.1 °F resolution) into g_sensors. At each wakeup, updateReeferMissCount() checks whether a valid frame was latched since the last wakeup. Three consecutive wakeup cycles without a valid frame trigger reefer_sensor_loss, but only after g_ps.j2497Commissioned is true (it's set on the first accepted frame). A build with no J2497 modem connected never sets this flag and never fires reefer_sensor_loss. Keep in mind that this path models a simplified POC frame format. A production J2497 data path needs a full application-layer protocol stack and reefer-OEM message mapping before it can decode actual reefer data (see §10 Limitations).
  • Thermistors. The firmware averages 16 reads from the 12-bit ADC on A0 and A1, converts the result to resistance with the 10 kΩ divider equation, then converts that to °F with the Steinhart-Hart β approximation (β = 3950 K). Averaging 16 samples smooths out short-term ADC noise and fluctuations from refrigeration discharge-air currents near the probes.
  • TPMS. drainTpmsUart() runs during the WAKE_UART_DRAIN_MS window and between Notecard I²C calls in the sample cycle. SoftwareSerial needs an active CPU, so it doesn't receive anything while the host is in STOP2. The most recent valid pressure for each position is latched in both g_sensors.tpmsPsi[] and g_ps.tpmsPsiLast[]. Both stay in RAM through the sleep interval, so sendSummary() always reports the correct last-known value. Each sendSummary() call reports the last-known pressure for all four positions plus a per-position tpms_N_age field (the number of summary windows since the last valid frame for that position). A position that hasn't reported for TPMS_STALE_COUNT (2) or more consecutive summary windows sends the −9999 sentinel in its pressure field.
  • Door state. digitalRead(PIN_DOOR) with INPUT_PULLUP. When the door is closed, the magnet holds the N.C. contact open and the pull-up drives the pin HIGH (doorOpen = false). When the door opens, the magnet moves away and the N.C. contact closes to GND, pulling the pin LOW (doorOpen = true). The firmware maps digitalRead(PIN_DOOR) == LOW → doorOpen = true. A hardware interrupt (CHANGE) is attached once in setup() and latches the last stable pin state, so rapid transitions within one sample interval resolve correctly at sample time. That interrupt is an EXTI line, which means a door edge also wakes the host from STOP2. The firmware runs a sample cycle right away (capturing the new door state) and then re-arms the ATTN sleep for a full sample_interval_sec. Door open duration (door_open_min) and event count (door_event_count) are computed at sample_interval_sec granularity. Only transitions observed at consecutive sample-cycle boundaries get captured, and an open/close event that starts and ends inside a single interval isn't counted.

UART acquisition window. The firmware drains both UART channels during the WAKE_UART_DRAIN_MS (250 milliseconds) window at the start of each wakeup, and again between each major Notecard I²C call in the sample cycle (env.get, card.time, card.location, note.add). At 9600 baud, the STM32L433's 64-byte hardware UART ring buffer fills in roughly 67 milliseconds, which is shorter than some Notecard transaction latencies under radio load. Draining between calls helps by clearing the hardware buffer between transactions. Even so, frames can still get lost during a multi-alert burst (up to six consecutive note.add calls) or a slow Notecard response. The most recent valid frame from each channel is latched in g_sensors (and in g_ps.tpmsPsiLast[] for TPMS), and the sample cycle reads those latched values. On the TPMS channel, SoftwareSerial's bit-banging needs the CPU to be active. For a high-rate TPMS gateway, or a production deployment where frame loss is unacceptable, move TPMS to a second hardware UART if the target board has one.

Event payload design

trailer_summary.qo is template-backed, so its Notes encode as fixed-length binary records instead of free-form JSON, which cuts wire size roughly 3–5× compared to unformatted JSON. It's a compact template on port 50, which is what lets summaries go over Skylo NTN when cellular isn't available. Over 10 years of hourly summaries across a multi-trailer fleet, that adds up to real savings against the included 500 MB data plan. Each summary Note carries window-aggregate statistics for the completed summary_interval_min interval, not a point-in-time snapshot. It includes min/max/mean actual temperature for the reefer and both cargo-air probes (the key cold-chain record), cumulative door-open minutes and the distinct open event count, last-known tire pressure per TPMS position plus a per-position age field (summary windows since the last frame arrived), and a sample count showing how many cycles went into the window.

trailer_alert.qo has its own compact template on port 51, so alerts can go out over satellite too. Every alert Note carries the same fields no matter the alert type, so one template covers all six: alert name, reefer set and actual temperature, both air-probe temperatures, door state, and all four TPMS pressure readings (−9999 for positions with no current data).

Prototype output: what a bench build actually produces. With no real J2497 source or TPMS gateway connected, the reefer temperature fields and all tpms_N_psi fields read −9999 in every Note. The tpms_N_age fields start at 0 on a fresh boot and go up by 1 at each summary boundary where that position got no data, so they read 1 after the first window, 2 after the second, and so on. Before it resets the window, the firmware's sendSummary() increments the stale counter for every position not marked tpmsSeenThisWindow. A TPMS position only reports age 0 when a valid frame for it arrived during the summary window that just closed. The real-sensor fields (air_t*, door_*, trailer_state, sample_count) come from hardware on every cycle.

Example trailer_summary.qo body, bench build with real cargo-air thermistors and door sensor, no J2497 or TPMS hardware (12-sample window):

{
  "reefer_set_f":      -9999.0,
  "reefer_min_f":      -9999.0,
  "reefer_max_f":      -9999.0,
  "reefer_mean_f":     -9999.0,
  "air_t1_min_f":      35.6,
  "air_t1_max_f":      37.2,
  "air_t1_mean_f":     36.3,
  "air_t2_min_f":      35.1,
  "air_t2_max_f":      36.8,
  "air_t2_mean_f":     35.9,
  "door_open_min":      0.0,
  "door_event_count":     0,
  "tpms_0_psi":      -9999.0,
  "tpms_1_psi":      -9999.0,
  "tpms_2_psi":      -9999.0,
  "tpms_3_psi":      -9999.0,
  "tpms_0_age":           1,
  "tpms_1_age":           1,
  "tpms_2_age":           1,
  "tpms_3_age":           1,
  "trailer_state":        0,
  "sample_count":        12
}

tpms_N_age starts at 0 on boot and goes up by 1 at each summary boundary with no data, so age 1 above is correct for the first window on a build with no TPMS gateway. After a second window with no data, the ages read 2 (= TPMS_STALE_COUNT). From then on the pressure field is already at −9999 from initialization, and the age counter keeps climbing as a diagnostic. A position that reported data in the window that just closed always shows age 0, whatever its history. The full-platform example below shows that case.

Alert payload, example trailer_alert.qo (sent immediately when the door_open_transit threshold is exceeded, with the full sensor snapshot):

{
  "alert":           "door_open_transit",
  "reefer_actual_f": -9999.0,
  "reefer_set_f":    -9999.0,
  "air_t1_f":        36.8,
  "air_t2_f":        36.2,
  "door_open":       true,
  "tpms_0_psi":      -9999.0,
  "tpms_1_psi":      -9999.0,
  "tpms_2_psi":      -9999.0,
  "tpms_3_psi":      -9999.0
}

Compact templates drop the Notecard's usual time and location metadata, so both templates add _time, _lat, and _lon back. The Notecard fills them in with the Note's creation time and its last known GPS position, and Notehub restores them to the event's usual time and location fields. Both Notes are added with full:true, so zero values (like trailer_state: 0 for parked, or door_open: false) reach Notehub instead of being dropped. Alerts go out with sync: true, which triggers an immediate radio session. Delivery takes seconds over cellular and a few minutes over Skylo NTN satellite.

Full-platform output: expected shape once J2497 and TPMS integrations are complete. Once a real J2497 source and TPMS gateway are connected and the vendor decode libraries are in place, the same template produces a fully populated record. The fields marked (stub) below stay at −9999 until the matching integration is done.

Example trailer_summary.qo body, full platform, chilled-food transit (12-sample window):

{
  "reefer_set_f":      34.0,   // stub until J2497 path is implemented
  "reefer_min_f":      34.8,   // stub
  "reefer_max_f":      36.1,   // stub
  "reefer_mean_f":     35.2,   // stub
  "air_t1_min_f":      35.6,
  "air_t1_max_f":      37.2,
  "air_t1_mean_f":     36.3,
  "air_t2_min_f":      35.1,
  "air_t2_max_f":      36.8,
  "air_t2_mean_f":     35.9,
  "door_open_min":      0.0,
  "door_event_count":     0,
  "tpms_0_psi":       105.0,   // stub until TPMS vendor library is implemented
  "tpms_1_psi":       103.0,   // stub
  "tpms_2_psi":       108.0,   // stub
  "tpms_3_psi":       107.0,   // stub
  "tpms_0_age":           0,
  "tpms_1_age":           0,
  "tpms_2_age":           0,
  "tpms_3_age":           0,
  "trailer_state":        2,
  "sample_count":        12
}

Example trailer_alert.qo body (sent immediately with sync:true) for a door_open_transit from a real door event:

{
  "alert":           "door_open_transit",
  "reefer_actual_f": 35.6,
  "reefer_set_f":    34.0,
  "air_t1_f":        36.3,
  "air_t2_f":        35.9,
  "door_open":       true,
  "tpms_0_psi":      105.0,
  "tpms_1_psi":      103.0,
  "tpms_2_psi":      108.0,
  "tpms_3_psi":      107.0
}

Low-power strategy

Dwell-capable host sleep via card.attn and STOP2. After each sample cycle, loop() calls cxSleepUntilAttn() (in cx_sleep.h). That function sends a card.attn sleep request for sampleIntervalSec seconds, waits for the Notecard to pull ATTN low, and puts the STM32L433 into STOP2. STOP2 draws a few microamps with RAM intact, so all that's left on the +VBAT rail is the Notecard's own radio-idle floor plus ~1–2 µA for the host. When the interval is up, the Notecard raises ATTN. The rising edge on D10 wakes the host, and execution picks up on the next line of loop(), which runs one complete sample cycle before sleeping again. Because the host resumes in place instead of cold-booting, PersistState just lives in RAM. Nothing gets serialized to the Notecard, and setup() runs only once per power-up. A door edge on D9 also exits STOP2, so a door transition triggers a sample cycle right away instead of waiting for the next interval.

Here are the key power budget figures:

Phase+VBAT drawDuration
Host asleep in STOP2 (Notecard idle between sessions)~8–18 µA Notecard idle (Blues-published; see Blues low-power design guide) plus ~1–2 µA for the STM32L433 in STOP2Most of the 24-hour day
Host awake: sample cycle + Notecard I²C callsBench-measure with Mojo. STM32L433 active current dominates, and no Blues-published spec exists~1–3 seconds per sampleIntervalSec cycle
Notecard cellular sessionNo Blues-published specification for NOTE-NBGLWX session current, so bench-measure with MojoPer outbound cadence
Notecard Skylo NTN satellite sessionNo Blues-published specification for NOTE-NBGLWX NTN session current, so bench-measure with MojoOnly when cellular unavailable

Base DC-dwell battery sizing on bench-measured Mojo data, not component-level estimates. §9 Validation and Testing has the measurement procedure.

UART acquisition during sleep. Both UART peripherals stop while the host is in STOP2 (their clocks are gated), so any frame that arrives between wakes is lost. On each wake, loop() drains both Serial1 (J2497) and tpmsSerial (TPMS) for WAKE_UART_DRAIN_MS (250 milliseconds) before the sample cycle. At 9600 baud, 250 milliseconds is room for ~30 complete J2497 frames. The host then stays awake for the whole sample cycle (typically 1–5 seconds including Notecard I²C calls) and drains both channels between each blocking call. On the J2497 path, frames that arrive during a Notecard I²C call land in the STM32's 64-byte hardware UART ring buffer, and they're only lost if a single Notecard call takes longer than ~67 milliseconds (a full buffer at 9600 baud). The TPMS path uses SoftwareSerial, which needs an active CPU, so it only captures bytes that arrive while the host is awake. TPMS gateways that buffer the latest frame and re-transmit it periodically are the most compatible. Gateways that only transmit when pressure changes may miss the wakeup windows during stable-pressure dwell periods.

TPMS pressure continuity across wakes. g_ps.tpmsPsiLast[] in PersistState mirrors the most recent valid pressure for each position. It and g_sensors.tpmsPsi[] both stay in RAM through STOP2, so sendSummary() always reports the correct last-known pressure, even if no fresh frame came in during the current wake's drain window. The stale counter (tpmsStaleCounts[]) keeps advancing each summary window and correctly ages silent positions out to the −9999 sentinel.

Fallback when ATTN doesn't reach the host. If the ATTN→D10 jumper is missing, or the Notecard doesn't accept the card.attn request, cxSleepUntilAttn() returns false and loop() falls through to a delay() that keeps the sample cadence going. In this mode the host draws continuous active current (~5–15 mA, bench-measure). The debug output on the ST-LINK serial port tells you which path is active, so look for [sleep] ATTN sleep failed — waiting out the interval awake.

Notecard for Skylo manages its own radio sleep independently. In periodic mode it idles at ~8–18 µA between sessions, then wakes briefly for a cellular or satellite burst on the configured outbound cadence. The sync cadence switches automatically on every trailer state transition, using outbound_transit_min (default 60 minutes) while moving and outbound_parked_min (default 240 minutes) during DC dwells. Every time the cadence changes, the host re-issues hub.set, so the Notecard tracks the current schedule exactly.

During long parked dwells, operators can stretch sample_interval_sec with an environment variable (for example, from 300 seconds to 900 seconds) to cut the host's active duty cycle while cargo temperature is stable.

Retry and error handling

  • fetchEnvOverrides() does a full env.get on every sample cycle. Once the Notecard answers, it resets g_cfg to the compiled defaults before applying the response, so any variable removed from Notehub reverts to its compiled default in the same cycle that receives the inbound sync. If the env.get itself fails, the previous values stay in place. applyHubSetIfChanged() applies sync cadence changes immediately. It guards the I²C round trip behind an equality check and only updates local state after the Notecard confirms the new setting.
  • The J2497 parse failure counter fires the reefer_sensor_loss alert after three consecutive wakeup cycles without a valid frame, but only if g_ps.j2497Commissioned is true (the flag is set on the first accepted frame). On a build with no J2497 modem the flag is never set and the alert never fires, so bench validation doesn't produce spurious loss alerts. The TPMS position-silence tracker ages stale positions to −9999 in summaries after two missed windows, but it does not fire a separate alert. A silent TPMS sensor shows up as missing data in trailer_summary.qo, not as an immediate trailer_alert.qo event.
  • Alert de-duplication through alert_cooldown_sec (default 30 minutes per alert type) keeps a slowly drifting temperature sensor from paging the fleet manager on every 5-minute sample cycle.
  • Every requestAndResponse() call checks for both a NULL return value and an err field on the response object before trusting the data.

Key code snippet 1: host sleep across wakes

setup() runs once and arms the ATTN wake, and each pass through loop() is one wake. At the end of the pass, cxSleepUntilAttn() asks the Notecard to hold ATTN low for sampleIntervalSec seconds, confirms the pin has gone low, and puts the STM32 into STOP2. Because the host stays alive, the card.attn call is a request whose result gets checked, not a fire-and-forget command. All the context between samples (accumulators, alert cooldowns, door state, TPMS pressures, and the summary window epoch) stays in PersistState in RAM. The TPMS UART and the door reed take D5/D6/D9, so the sketch defines CX_ATTN_PIN as D10 before including cx_sleep.h.

// D5/D6 (TPMS) and D9 (door) are taken, so the ATTN jumper lands on D10.
#define CX_ATTN_PIN D10
#include "cx_sleep.h"

// ...

void setup() {
    // ...
    // Zero-initialise state and configure the Notecard.
    memset(&g_ps, 0, sizeof(g_ps));
    // ...
    notecardInit();
    // ...

    // Attach the door interrupt once. Note that this EXTI line also wakes the
    // host from STOP2, so a door edge runs a sample cycle early.
    setupDoorInterrupt();

    // Wake from STOP2 on the ATTN rising edge (ATTN jumpered to D10).
    cxSleepBegin();
}

void loop() {
    // ...
    fetchEnvOverrides();

    // Post-wake UART drain window. Both UART peripherals were stopped while
    // the host was in STOP2; this window captures frames arriving in the first
    // WAKE_UART_DRAIN_MS milliseconds after wake.
    {
        uint32_t drainUntil = millis() + WAKE_UART_DRAIN_MS;
        while (millis() < drainUntil) {
            drainReeferUart();
            drainTpmsUart();
        }
    }

    uint32_t nowEpoch = notecardEpoch();
    // ...
    if (g_ps.summaryWindowStartEpoch == 0 && nowEpoch != 0)
        g_ps.summaryWindowStartEpoch = nowEpoch;

    runSampleCycle(nowEpoch);

    // Final drain before sleeping: captures any bytes that arrived during or
    // after runSampleCycle().
    drainReeferUart();
    drainTpmsUart();

    // ...
    if (!cxSleepUntilAttn(notecard, g_cfg.sampleIntervalSec, NULL, &usbSerial)) {
        // ...
        // The Notecard didn't take the sleep request, or ATTN never went low
        // (check the ATTN -> D10 jumper). The delay() keeps the sample cadence
        // but the host remains fully awake, drawing continuous active current
        // (~5–15 mA). Not suitable for extended DC-dwell operation.
        // ...
        delay(g_cfg.sampleIntervalSec * 1000UL);
    }
}

Key code snippet 2: hub.set cadence switching on state transition

When the trailer switches between parked and in-transit, the host re-issues hub.set with the new outbound cadence. If the cadence hasn't changed, the guard clause skips the I²C round trip.

static bool applyHubSetIfChanged(uint32_t newOutboundMin) {
    if (newOutboundMin == g_ps.currentOutboundMin) return true;
    J *req = notecard.newRequest("hub.set");
    if (!req) return false;
    JAddStringToObject(req, "mode",     "periodic");
    JAddNumberToObject(req, "outbound", (int)newOutboundMin);
    JAddNumberToObject(req, "inbound",  (int)newOutboundMin * 2);
    J *rsp = notecard.requestAndResponse(req);
    if (!rsp) return false;
    bool ok = !notecard.responseError(rsp);
    notecard.deleteResponse(rsp);
    if (ok) g_ps.currentOutboundMin = newOutboundMin;  // update only on success
    return ok;
}

Key code snippet 3: immediate-sync temperature alert

sync:true tells the Notecard to skip the next scheduled outbound window and open a radio session immediately. Over cellular that usually gets the alert delivered within seconds. On Skylo NTN satellite the first acquisition may take a few minutes, but the alert is queued and delivered even when cellular coverage isn't available. The epoch cooldown stamp survives sleep. The millis() stamp only covers the current wake, for the stretch before the Notecard has a time lock.

// Queue an immediate-sync alert note. Cooldown epoch stamped only after the
// Notecard confirms receipt so a failed send doesn't suppress the alert for
// the full cooldown window.
static void sendAlert(uint8_t idx, uint32_t nowEpoch) {
    if (!alertCooldownOk(idx, nowEpoch)) return;
    J *req = notecard.newRequest("note.add");
    if (!req) return;
    JAddStringToObject(req, "file", NOTE_ALERT);
    JAddBoolToObject(req,   "sync", true);
    JAddBoolToObject(req,   "full", true);  // keep door_open:false and 0 values
    J *body = JAddObjectToObject(req, "body");
    JAddStringToObject(body, "alert",           kAlertNames[idx]);
    JAddNumberToObject(body, "reefer_actual_f", g_sensors.reeferActualF);
    JAddNumberToObject(body, "reefer_set_f",    g_sensors.reeferSetF);
    JAddNumberToObject(body, "air_t1_f",        g_sensors.airT1F);
    JAddNumberToObject(body, "air_t2_f",        g_sensors.airT2F);
    JAddBoolToObject(body,   "door_open",       g_sensors.doorOpen);
    JAddNumberToObject(body, "tpms_0_psi",      g_sensors.tpmsPsi[0]);
    JAddNumberToObject(body, "tpms_1_psi",      g_sensors.tpmsPsi[1]);
    JAddNumberToObject(body, "tpms_2_psi",      g_sensors.tpmsPsi[2]);
    JAddNumberToObject(body, "tpms_3_psi",      g_sensors.tpmsPsi[3]);
    J *rsp = notecard.requestAndResponse(req);
    if (!rsp) return;
    bool ok = !notecard.responseError(rsp);
    notecard.deleteResponse(rsp);
    if (ok) {
        // Stamp both clocks on confirmed delivery.
        if (nowEpoch != 0) g_ps.lastAlertEpoch[idx] = nowEpoch;
        g_lastAlertMs[idx] = millis();
    }
}

Key code snippet 4: Note template for bandwidth efficiency

Templated Notes store each summary as a fixed-width binary record, where 14.1 encodes a 4-byte float and 12 encodes a 2-byte signed integer. The 22 data fields are 15 floats (4 bytes each) and 7 int16 values (2 bytes each), 74 bytes of user payload. Setting format to "compact" and giving the template a port is what lets the record travel over Skylo NTN. Compact format also drops the Notecard's own time and location metadata, so _time, _lat, and _lon add them back for 12 more bytes, 86 in all before any per-record Notecard overhead, well under Skylo's 256-byte packet limit. defineTemplate() then registers trailer_alert.qo the same way on port 51. Equivalent free-form JSON would need several hundred bytes for the same field set. Over a 10-year, multi-trailer deployment on the included 500 MB data plan, that difference adds up.

// Define the binary summary and alert note templates. Returns true on success.
// Both are compact with a port, which Skylo NTN requires. Compact drops the
// Note's time and location metadata, so _time/_lat/_lon add them back.
static bool defineTemplate() {
    J *req = notecard.newRequest("note.template");
    if (!req) return false;
    JAddStringToObject(req, "file", NOTE_SUMMARY);
    JAddNumberToObject(req, "port", TEMPLATE_PORT);
    JAddStringToObject(req, "format", "compact");
    J *body = JAddObjectToObject(req, "body");
    JAddNumberToObject(body, "reefer_set_f",     14.1);
    JAddNumberToObject(body, "reefer_min_f",     14.1);
    JAddNumberToObject(body, "reefer_max_f",     14.1);
    JAddNumberToObject(body, "reefer_mean_f",    14.1);
    JAddNumberToObject(body, "air_t1_min_f",     14.1);
    JAddNumberToObject(body, "air_t1_max_f",     14.1);
    JAddNumberToObject(body, "air_t1_mean_f",    14.1);
    JAddNumberToObject(body, "air_t2_min_f",     14.1);
    JAddNumberToObject(body, "air_t2_max_f",     14.1);
    JAddNumberToObject(body, "air_t2_mean_f",    14.1);
    JAddNumberToObject(body, "door_open_min",    14.1);
    JAddNumberToObject(body, "door_event_count", 12);
    JAddNumberToObject(body, "tpms_0_psi",       14.1);
    JAddNumberToObject(body, "tpms_1_psi",       14.1);
    JAddNumberToObject(body, "tpms_2_psi",       14.1);
    JAddNumberToObject(body, "tpms_3_psi",       14.1);
    JAddNumberToObject(body, "tpms_0_age",       12);
    JAddNumberToObject(body, "tpms_1_age",       12);
    JAddNumberToObject(body, "tpms_2_age",       12);
    JAddNumberToObject(body, "tpms_3_age",       12);
    JAddNumberToObject(body, "trailer_state",    12);
    JAddNumberToObject(body, "sample_count",     12);
    JAddNumberToObject(body, "_time",            14);
    JAddNumberToObject(body, "_lat",             14.1);
    JAddNumberToObject(body, "_lon",             14.1);
    J *rsp = notecard.requestAndResponse(req);
    if (!rsp) return false;
    bool ok = !notecard.responseError(rsp);
    // ...
    notecard.deleteResponse(rsp);
    // ...
}

Key code snippet 5: GPS-based motion detection

Instead of relying on a dedicated speed field from the GNSS module, the firmware compares consecutive GPS positions. If the squared position delta between two 5-minute samples is greater than 4.0×10⁻⁷ degree² (about 50 m per axis at mid-latitudes when both axes contribute equally), the trailer counts as moving. The check also needs a valid prior fix (hasPrev), so the first GPS acquisition after power-up can never falsely trigger a state change. When there's no GPS fix (a GNSS gap, an error response, or a first boot with no prior position), the firmware keeps the previous trailer state unchanged. Reclassifying on door state alone would wrongly demote an in-transit trailer during a temporary outage and would suppress door_open_transit alerts.

static void updateTrailerState(uint32_t nowEpoch) {
    (void)nowEpoch;
    J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
    if (!rsp) return;

    const char *errStr = JGetString(rsp, "err");
    bool hasErr = (errStr && errStr[0] != '\0');

    float lat = (float)JGetNumber(rsp, "lat");
    float lon = (float)JGetNumber(rsp, "lon");
    notecard.deleteResponse(rsp);

    bool validFix = !hasErr && (lat != 0.0f || lon != 0.0f);
    bool hasPrev  = (g_ps.lastLat != 0.0f || g_ps.lastLon != 0.0f);

    if (validFix && hasPrev) {
        float dL = lat - g_ps.lastLat, dO = lon - g_ps.lastLon;
        bool moving = (dL * dL + dO * dO) > 4.0e-7f;  // ≈ (50 m)² threshold
        g_ps.trailerState = moving             ? STATE_IN_TRANSIT :
                            g_sensors.doorOpen ? STATE_LOADING : STATE_PARKED;
    }
    // No valid fix (GNSS gap, first boot, or error): preserve the current
    // trailer state. Reclassifying from door state alone would incorrectly
    // demote an in-transit trailer to parked or loading cadence during a
    // temporary GNSS outage and would suppress door_open_transit alerts.
    if (validFix) { g_ps.lastLat = lat; g_ps.lastLon = lon; }

    applyHubSetIfChanged(
        g_ps.trailerState == STATE_IN_TRANSIT ? g_cfg.outboundTransitMin
                                              : g_cfg.outboundParkedMin);
}

8. Data Flow

Data flow: per-cycle sample of cargo °C, door state, GPS → threshold rules (cargo high/low, door_open_long, motion/dwell) → trailer_alert.qo (sync:true with 30-min cooldown) and trailer_summary.qo (window aggregate, templated) → Notehub routes

The Notecard's card.attn wakes the host from STOP2 every sample_interval_sec (default 300 seconds / 5 minutes), and a rear-door edge wakes it early. On each wake the host drains both UART channels for 250 milliseconds, reads every sensor input, accumulates window statistics, checks the threshold rules, and may send one or more immediate alerts before going back to sleep. Every summary_interval_min (default 60 minutes), it sends one templated summary Note with aggregated statistics for the completed window instead of a point-in-time snapshot.

Collected on each wake cycle:

  • Front and rear cargo-air temperature (°F) from two NTC thermistors: fully implemented
  • Rear door state (open / closed) from the reed switch: fully implemented
  • Trailer state (parked / loading / in transit) derived from Notecard GNSS position delta: fully implemented
  • Reefer setpoint and actual temperature (°F) parsed from a simplified POC UART frame: integration-point stub that needs a J2497 protocol stack and reefer-OEM mapping to produce real data (see §10)
  • Four tire-position pressures (PSI) parsed from a simplified POC UART packet: integration-point stub that needs a vendor-specific TPMS decode library (see §10)

Transmitted:

  • trailer_summary.qo: one template-encoded window-aggregate record every summary_interval_min (default 24 per day per trailer), carrying reefer and cargo-air min/max/mean temperatures, door-open minutes and event count, TPMS last-known pressures and per-position ages, and a sample count. It's queued in the Notecard and flushed on the configured outbound cadence.
  • trailer_alert.qo: sent only when a threshold trips, with sync:true for immediate delivery and subject to the 30-minute per-type cooldown window.

GPS. card.location.mode is set to periodic with a 300-second interval. In periodic mode, the Notecard only powers up the GNSS module if its onboard accelerometer has detected motion since the last fix attempt. The GPS radio stays off during stationary DC dwells and only turns on after the trailer moves (see Sampling GPS Readings with Periodic Mode). Every outbound Note also gets tagged with the last known position automatically.

Routed. Notehub sends trailer_alert.qo to the OEM's real-time fleet management or on-call system, and trailer_summary.qo to a cold-chain compliance archive or time-series data store for trend analysis and FSMA (Food Safety Modernization Act) recordkeeping.

Triggers for alerts:

Fully implemented sensor paths that fire against actual hardware:

  • door_open_transit: rear door open longer than door_open_transit_sec while the trailer is classified in-transit, which points to a cargo security event or seal integrity concern.

Integration stub paths that compile and evaluate in firmware but only fire against simulated POC frames. They aren't active on real trailer hardware until the matching integration is done:

  • reefer_temp_high: reefer actual temp above reefer_max_f (default 40 °F). Fires against J2497 stub data only.
  • reefer_temp_low: reefer actual temp below reefer_min_f (default 28 °F), a freeze risk. Fires against J2497 stub data only.
  • reefer_sensor_loss: three consecutive wake cycles with no valid J2497 frame, pointing to a PLC bus or reefer unit communication fault. Gated by j2497Commissioned, so it only fires after at least one valid J2497 frame has been accepted since the last boot. A build with no J2497 modem connected never sets this flag, so the bench never sees spurious loss alerts.
  • tpms_pressure_low: any tire below tpms_min_psi, a blowout precursor. Fires against TPMS stub data only.
  • tpms_pressure_high: any tire above tpms_max_psi, pointing to over-inflation or heat buildup. Fires against TPMS stub data only.

9. Validation and Testing

Expected steady-state behavior, bench build with thermistors and door only (no J2497 or TPMS hardware). A powered build sends one trailer_summary.qo event per hour. The air_t* and door_* fields are populated, every reefer_* and tpms_N_psi field reads −9999, and tpms_N_age reads 1 after the first summary window, 2 after the second, and keeps climbing each window. The stale counter isn't capped. Since the pressure field is already at −9999 from initialization, the age serves as a diagnostic count of windows since the last reception. trailer_state stays at 0 (parked) until GPS gets a fix and detects motion. Zero trailer_alert.qo events is the correct baseline. The reefer_sensor_loss alert is gated behind j2497Commissioned, which only gets set when the first valid J2497 frame is accepted, so it never fires on a build with no J2497 modem connected, no matter how many wakeup cycles go by without a frame. On the bench, door_open_transit is the only alert that can fire against real hardware. After a door open/close event, you'll see door_open_min > 0 and door_event_count: 1 in the next summary Note. The door_open boolean field only appears in trailer_alert.qo, never in the templated summary Note.

Power validation with Mojo.

Measurement point. Splice the Mojo inline on the Notecarrier CX +VBAT rail. That captures Notecard for Skylo, the STM32L433 host, and any peripherals on the 3.3 V rail, including the J2497 custom board's IT700 logic VCC (sourced from the Notecarrier +3V3) once that board is built. The TPMS gateway runs directly off the 12 V trailer rail, upstream of the DC-DC converter, so it does not appear in the Mojo trace. For a complete DC-dwell energy budget, add a second measurement at the DC-DC converter's 12 V input rail with a bench current probe or a dedicated meter.

Blues-published reference figures for the NOTE-NBGLWX on +VBAT.

StateRailPublished figureSource
Notecard idle (radio off, between syncs)+VBAT~8–18 µABlues-published, from the Blues low-power design guide

The Notecard idle figure is the only Blues-published power specification for the NOTE-NBGLWX on this rail. None of the other operating states (host-awake sample cycles, LTE-M/NB-IoT cellular sessions, and Skylo NTN satellite sessions) have Blues-published figures for this SKU. Measure each state on your bench with the Mojo before using any figure in a power design or a DC-dwell battery sizing calculation. Don't use modem-IC datasheet figures as stand-ins for Notecard-level current, because they don't account for the Notecard's own regulators, baseband, and power management overhead.

StateMeasurement pointWhat to do
Host awake: sample cycle (ADC reads + Notecard I²C calls)+VBATBench-measure with Mojo. There's no Blues-published spec, and it varies with STM32 clock rate, active peripherals, and Notecard I²C latency.
Notecard LTE-M/NB-IoT cellular session+VBATBench-measure with Mojo. No Blues-published NOTE-NBGLWX cellular session current.
Notecard Skylo NTN satellite session+VBATBench-measure with Mojo in a real outdoor satellite-coverage location. No Blues-published NOTE-NBGLWX NTN session current exists. Allow several minutes for initial satellite acquisition.
Host asleep (STM32 in STOP2, waiting for ATTN)+VBATNotecard idle dominates at ~8–18 µA (Blues-published), plus ~1–2 µA for the host in STOP2. This is the figure that makes DC-dwell operation viable.
TPMS gateway (12 V, future integration)12 V rail, upstream of DC-DC, not on MojoPer vendor datasheet, so confirm it on the bench. It doesn't appear in the Mojo trace.
J2497 custom board logic (future integration, 3.3 V)+VBAT via Notecarrier +3V3, so it will appear on Mojo traceBench-measure once the custom board is built. Don't estimate it.

What to look for on the Mojo trace. Run the unit for 24 hours with all antennas attached. With ATTN-driven host sleep working, the Mojo trace should show a near-floor baseline of ~10–20 µA (Notecard idle plus the host in STOP2), brief periodic spikes for host-awake sample cycles, and larger spikes at the configured outbound cadence for radio sessions. If the baseline never drops to the µA floor, the host isn't entering STOP2. Check the ATTN→D10 jumper, confirm the firmware was built with USB support set to None (usb=none), and make sure the debug console isn't showing a [sleep] ATTN sleep failed message. To confirm sleep is working, power-cycle the unit and watch the first sleep interval on the Mojo trace. The host-awake spike from setup() and the first loop() pass should be followed by a drop to the µA floor before the next scheduled wake.

DC-dwell battery sizing. The host draws only a few microamps in STOP2 (the Notecard's ~8–18 µA floor dominates), so multi-day DC-dwell survival is achievable within a reasonable reefer battery budget. Only use bench-measured Mojo data in a dwell sizing formula, specifically the 24-hour average current at the Mojo measurement point. Then apply dwell_days = (battery_Ah × 1000) / (I_avg_mA × 24). Take a separate measurement at the 12 V input rail to capture TPMS gateway draw and DC-DC converter quiescent loss, since neither one shows up in the +VBAT Mojo trace.

Threshold simulation, real sensors. To check that the door_open_transit alert path works end to end, open the rear door while the unit is in transit (or while simulating transit by setting outbound_transit_min to 1 and waiting for a GPS fix). Leave the door open longer than door_open_transit_sec (default 5 minutes). A trailer_alert.qo Note with "alert": "door_open_transit" should show up in Notehub within one cellular session-establishment window.

Threshold simulation, integration stubs. The reefer and TPMS alert paths evaluate against the stub parsers, not real hardware. Unless a device is injecting POC-format frames over Serial1 or D6, g_sensors.reeferActualF and g_sensors.tpmsPsi[] stay at −9999, and no reefer or TPMS alerts fire regardless of the threshold settings. To exercise those code paths on the bench, (a) set reefer_max_f in Notehub to a value above −9999 (any positive threshold works, since injected stub values would be real-looking numbers). Then (b) connect a USB-to-serial adapter to Serial1 and send a valid 8-byte POC frame at 9600 baud (0xAA 0x55 header, big-endian signed 16-bit setpoint and actual temp in 0.1 °F units, status byte, XOR checksum of bytes 2–6). The next sample cycle that latches the frame checks the threshold and fires reefer_temp_high if the injected actual temperature exceeds reefer_max_f. This exercises the firmware's threshold-evaluation and note.add path, but it doesn't validate any J2497 physical-layer or protocol-layer behavior.

Satellite fallback validation. Commission the unit somewhere with cellular coverage first. The Notecard needs one cellular sync so Notehub learns both templates before any Note can go over satellite. Then take the powered unit, with all antennas properly attached, to an outdoor location that has confirmed no LTE-M cellular coverage but a clear, unobstructed sky view. A rural field, open parking area, or rooftop site with verified weak or no LTE-M coverage is ideal (check the carrier's coverage map before the trip). Do not use a basement, building interior, or enclosed metal container. Those block the satellite signal as well as cellular, which leaves the Notecard with no radio path at all, and nothing gets delivered. Don't disconnect a u.FL connector while the unit is powered, because the resulting open-circuit impedance mismatch can damage the modem front end. With all antennas connected and no cell signal available, Notecard for Skylo exhausts its cellular registration attempts and moves to the Skylo NTN satellite path automatically. A pending summary Note should eventually show up in Notehub. Allow several minutes for the initial satellite acquisition, though later sessions are faster once the modem has acquired the satellite ephemeris.

To confirm satellite delivery: in Notehub, go to Events, filter on your device, and open the _session.qo system Note created for the same session as your delivered event (see the system notefiles reference). For a cellular session, the _session.qo event carries the fields Notecard reports in its session handshake, including voltage, rssi, bars, and iccid. In a Skylo NTN satellite session, Notecard never opens a connection to Notehub, so there's no handshake and Notehub leaves out every one of those fields. Checking for a missing voltage is the simplest reliable test.

Don't use the tower_id/tower_lat/tower_lon fields for this. Notehub copies them from its stored record of the device instead of from the session, and nothing clears them when the unit falls back to satellite. On a cell-ntn device like this one, they stay populated with the tower from the last cellular session and will make a satellite session look cellular.

10. Limitations and Next Steps

This reference platform delivers the three sensor paths a trailer OEM can stand up against real hardware on day one (cargo-air temperature, door, and GPS). It also includes firmware scaffolding for the two paths whose engineering work really does fall outside the scope of a reference design.

Outside This Reference Build's Scope

Here's an honest list of the work still in front of any OEM that wants to ship this as a commercial product. It's organized around transport and protocol choices, and it makes no apologies for them.

Reefer telemetry transport: pick one of three, then implement. The firmware reserves Serial1 for a reefer-telemetry source and ships with a simplified POC decode in drainReeferUart(). The reference assumption is J2497 PLC, but in practice there are three realistic transports, and which one you pick changes the engineering effort a lot. Whichever you choose, the firmware's note.add pipeline is identical for all three. Only the decode function in drainReeferUart() and the upstream physical interface differ.

TransportPhysical interfaceProsConsEngineering required
SAE J2497 / PLC4TRUCKS (reference assumption)Power-line carrier on J560 pin 7, via Yitran IT700 modem and Bourns coupling transformerNo additional connector to the reefer unit, since it rides the existing trailer power lineCustom coupling board; licensed J2497 application stack; reefer-OEM proprietary message mapping; uncommon for reefer in production (ABS is the dominant deployed J2497 use)Build IT700 coupling board (PT60234PEL transformer + bus protection); license/integrate Microchip/Yitran J2497 stack; obtain reefer-OEM message map under integration agreement; field-validate per reefer model
Vendor-proprietary serial (Carrier Transicold DataLink, Thermo King DSR / DSR2)RS-232 or RS-485 diagnostic port on the reefer unit (typically a 9-pin or RJ-style connector)Mechanically simple; documented (under NDA) at the protocol level by the OEM; most production reefer telematics use this path todayRequires a connector pass-through to the reefer chassis; protocol details are typically available only under an OEM integration agreement; per-OEM, not unifiedAdd an RS-232 or RS-485 transceiver between Serial1 and the diagnostic port; obtain the protocol spec from Carrier or Thermo King; replace drainReeferUart() decode
J1939 over CANCAN bus on the reefer unit (where exposed)Standardized PGN-based message structure; richer telemetry (fault codes, run hours, fuel) than serial diagnostics; same bus standard widely used elsewhere on the vehicleRequires a host with an accessible CAN controller (the STM32L433 in this build does not break out CAN on the Notecarrier CX headers. See the dedicated J1939/CAN limitation below); automotive-qualified CAN transceiver; J1939 PGN decodeConfirm host CAN pin availability or change host; add AEC-Q100 transceiver (e.g., TJA1051T/3/1J); implement J1939 PGN decode for the reefer's message set

For a first prototype against an actual reefer unit, the vendor-proprietary serial path is the lowest-risk first milestone. It lands on the same Serial1 UART the reference build already exercises, and most modern reefers (Thermo King SLXe, Carrier X4 7700) expose it. J2497 is a credible long-term option if power-line carrier is a strategic constraint (no chassis-side connector, multi-OEM unification on a single physical interface). Just expect to fund a multi-quarter effort across coupling-board hardware, stack licensing, and OEM message mapping before it produces any real data.

TPMS protocol is vendor-specific. The firmware models four tire positions with a simplified generic packet format. Commercial trailer TPMS systems (PressurePro, Doran 360, Continental VDO, TST 507) each use their own proprietary 315/433 MHz message structures, with different tire ID encoding, pressure scaling, and checksum algorithms. Production firmware has to implement the chosen vendor's message decode library.

Four tire positions are tracked. A 53-foot refrigerated trailer typically runs 10 or more tires on dual rear axles, but the POC only supports four positions. Covering the full tire set takes a larger TPMS position array and a wider Note template.

GPS-position-delta state detection is approximate. Comparing GPS positions 5 minutes apart can give ambiguous results under a poor sky or during slow dock maneuvering. A production implementation should combine the GPS position delta with the Notecard's built-in accelerometer (card.motion.mode) for reliable motion detection that doesn't depend on GNSS fix quality.

No J1939/CAN integration. Modern reefer units expose richer telemetry than temperature over J1939 CAN, including fault codes, fuel consumption, run hours, and setpoint history. Adding CAN to this platform takes more than a transceiver: (a) confirm that the STM32L433's CAN peripheral pins (CAN_TX/CAN_RX) are accessible on the Notecarrier CX headers, and if they aren't, plan on a board redesign or an alternate host with CAN pins broken out; (b) once you have a host with accessible CAN pins, add an automotive-qualified CAN transceiver (e.g., TJA1051T/3/1J, AEC-Q100-qualified) between the host CAN controller and the J1939 bus; and (c) implement J1939 PGN (Parameter Group Number, the J1939 message identifier) decode in firmware, for example with an mcp_can-style library or a raw CAN driver targeting the host's bxCAN peripheral. A transceiver alone is not sufficient without a host that exposes a compatible CAN controller.

Skylo NTN satellite latency. Setting up a satellite session can take several minutes on initial power-up, and the Skylo NTN network has tighter message-size and throughput limits than a typical cellular session. That means alert Notes sent via satellite will arrive in Notehub with higher latency than cellular. Plan your monitoring workflows around that. Notecard for Skylo prefers cellular and falls back to satellite automatically, so this latency only applies in real coverage gaps.

No host over-the-air firmware update. Notecard Outboard DFU needs SWD/BOOT pin access that the Notecarrier CX headers don't expose in this standard configuration. Production boards should route the BOOT and NRST signals through a DFU header, which allows fleet-wide host firmware updates without a service visit.

Mojo is bench tooling. The firmware doesn't read the Mojo's LTC2959 coulomb counter over Qwiic. Adding a cumulative-mAh field to the summary Note is a straightforward extension, and it would give you fleet-level power telemetry for DC dwell energy auditing.

Production Next Steps

With the three day-one sensor paths running against real hardware, these extensions move the platform toward a commercial product you can ship.

Full J2497 integration takes four pieces: (1) coupling board hardware (IT700, Bourns bus-coupling transformer, bus protection), (2) a J2497 application-layer protocol stack from Microchip/Yitran or equivalent, (3) reefer-OEM message mapping per target reefer model under an integration agreement, and (4) field validation on target reefer-unit hardware to confirm J560 bus data availability.

Vendor-specific TPMS decode libraries would cover every tire position on the OEM's chosen sensor brand.

A J1939 CAN interface means verifying that CAN_TX/CAN_RX are accessible on the Notecarrier CX (or redesigning around a host with CAN pins exposed), adding an AEC-Q100 automotive CAN transceiver (e.g., TJA1051T/3/1J), and implementing J1939 PGN decode for full reefer-unit telemetry (fault codes, fuel, hours).

Accelerometer-augmented motion detection (card.motion.mode) gives you reliable parked/transit classification.

Full 10-tire TPMS coverage handles the 53-foot dual-rear-axle configuration.

USDA and FDA FSMA-compliant temperature logging adds cryptographically signed records with a chain-of-custody audit trail.

Host ODFU wiring allows fleet-wide firmware updates from Notehub without a truck roll.

Humidity and CO₂ sensors suit high-value perishable loads (fresh produce, pharmaceutical).

11. Summary

The trailer manufacturer who used to watch reefer OEMs and aftermarket platforms quietly claim the connectivity layer on every trailer it shipped now has a credible platform on the trailer from day one. It's one hardware SKU for every regional market and every carrier, with satellite covering the gaps automatically and 10 years of included service, so nobody has to have a mid-program re-sourcing conversation. The Notecarrier CX with a Notecard for Skylo delivers three fully implemented sensor paths today (cargo-air temperature, door, GPS), plus the firmware scaffolding for the two vendor-gated paths (J2497 reefer telemetry and TPMS), so the platform is ready the moment that engineering lands. Between cycles the host sleeps in STOP2 until card.attn wakes it, adding only a few µA to the Notecard's ~8–18 µA idle floor on the trailer's reefer battery. In transit the device shortens its sync cadence on its own, and in a coverage hole it falls back to Skylo NTN without the host ever noticing. Notehub turns all of that into a single API endpoint the OEM's cloud can route wherever it needs to go (cold-chain compliance archive, TPMS safety alerts, GPS dispatch feed) over a 10–15 year trailer lifecycle, without touching firmware. With that footprint, a trailer OEM can own the data layer instead of conceding it.

On This Page

  • 1. Project Overview
  • 2. System Architecture
  • 3. Technical Summary
  • 4. Hardware Requirements
    • Future Integration Hardware
  • 5. Wiring and Assembly
    • Future Integration: Reefer Telemetry UART (Reference: J2497 PLC Modem Path)
    • Future Integration: TPMS Receiver Path
  • 6. Notehub Setup
  • 7. Firmware Design
    • Modules
    • Sensor reading strategy
    • Event payload design
    • Low-power strategy
    • Retry and error handling
    • Key code snippet 1: host sleep across wakes
    • Key code snippet 2: hub.set cadence switching on state transition
    • Key code snippet 3: immediate-sync temperature alert
    • Key code snippet 4: Note template for bandwidth efficiency
    • Key code snippet 5: GPS-based motion detection
  • 8. Data Flow
  • 9. Validation and Testing
  • 10. Limitations and Next Steps
    • Outside This Reference Build's Scope
    • Production Next Steps
  • 11. Summary

Resources

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