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_rightMulti-Site Walk-In Cooler Energy & Setpoint Monitor

Multi-Site Walk-In Cooler Energy & Setpoint Monitor

Multi-Site Walk-In Cooler Energy & Setpoint Monitor banner
note

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

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

This project is a cellular energy savings reference design for walk-in coolers. It gives corporate operations teams a live view of the temperature, compressor runtime, and door behavior of every walk-in cooler in their fleet, and it never touches a single franchisee's or operator's WiFi network.

1. Project Overview

The problem. For a chain QSR (quick-service restaurant), convenience store, or grocery operator, the walk-in cooler is one of the most expensive assets in a store and one of the least visible. Per location, energy costs more than anything except labor, and a big share of that energy budget runs through the compressor of one or more walk-in boxes. Operators who can see compressor runtime, door discipline, and temperature trends across their fleet can make a real dent in energy spend. A door held open five minutes too long during a busy lunch rush costs real money in wasted refrigeration. Then there's the compressor that runs six hours a day instead of four because box air temperature has quietly drifted 2 °F above the corporate temperature target. At scale, that costs even more.

The harder problem is that an operator running 800 locations has 800 different network environments. Franchisees are on consumer ISPs, independent operators run POS (point-of-sale) systems their IT vendors won't let anyone touch, and convenience stores have back-office networks that rule out any new guest devices. Getting corporate visibility through all of that is what keeps most energy-monitoring pilots from turning into fleet-wide programs. The pilot sites get instrumented, and then the rollout stalls at 50.

This device is built to get past that barrier. It's a single cellular-connected SKU that doesn't need an IT ticket. Stick a temperature probe inside the box, clamp a split-core current transformer on the compressor hot leg, and mount a magnetic reed switch on the door. You get a per-unit compressor energy proxy, door-open events, and temperature-to-target deviation, all delivered to the Blues Notehub cloud service and routed wherever corporate needs them. The energy proxy is compressor apparent kWh per summary window, and per-day totals come from summing kwh_window records downstream.

Why Notecard. Corporate energy management can't touch 800 independent-operator or franchisee WiFi networks, because each one would be its own ticket. A cellular Notecard is one SKU the field can plug in without asking anyone for a WiFi password. That's what separates a program that deploys at fleet scale from one that never leaves the pilot. Cellular also keeps the energy-monitoring data stream entirely off the POS network. That matters for network security, and it matters because POS downtime is the one side effect of an energy program that nobody will accept. Notecard Cell+WiFi keeps WiFi as an opportunistic fallback for the occasional site that can offer it, and the deployment model stays cellular-first.

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 small weatherproof enclosure mounts in or near the cooler's refrigeration cabinet or mechanical room. It runs off the cooler's dedicated circuit, which is typically 120VAC for single-phase residential-style units, though many commercial condensing units run on 208/240VAC (see Limitations). Three sensor leads run into the box. The first is a waterproof DS18B20 temperature probe in open box air at mid-box height or along the return-air path, where it reads representative box air temperature away from the evaporator and door. A split-core CT clamps onto one hot leg of the compressor's dedicated circuit, and a two-wire reed switch mounts on the door frame with a magnet on the door itself. You don't need the OEM's cooperation, any changes to the cooler, or any network integration.

2. System Architecture

System architecture: walk-in cooler sensors (box temp, compressor CT, door reed) → Notecarrier CX with STM32 host and Notecard MBGLW → cellular/WiFi → Notehub → energy ops / BI / alerts

Device-side responsibilities. Inside the cooler's mechanical-room enclosure, the Notecarrier CX's STM32 host wakes every sample_interval_sec seconds (default 60), reads all three sensors, updates the per-window accumulators (kWh proxy, compressor runtime, door open seconds and event count), and runs the two alert rules. Then it either queues a summary Note for the next window or goes straight back to sleep. Between wakes the host sleeps in STM32 STOP2 (a few µA) using card.attn. The Notecard holds its ATTN pin low for the interval and raises it to wake the host when the next sample is due.

Notecard responsibilities. The Notecard handles whatever the host queues. Notes wait in the on-device queue until the hub.set outbound cadence (60 minutes by default) opens a cellular (or opportunistic WiFi) session and flushes them in one batch. Anything tagged sync:true skips the queue, and the radio comes up right away. On every inbound sync, the Notecard also pulls environment variables from Notehub, so you can tune setpoint targets, alert timers, and cadences from a browser without a firmware update or a field visit.

Notehub responsibilities. Events travel over the Notecard's embedded global SIM to Blues Notehub, which ingests and stores every one and runs the project-level routes to your cloud application of choice. Summaries and alerts go to separate JSON-based Notefiles on purpose. cooler_summary.qo carries the hourly telemetry that flows to BI or a long-term store, and cooler_alert.qo carries the immediate notifications that need to land on a phone or a Slack channel. The routes need no filter logic, since they're just two streams pointed at the right destinations. Fleets and Smart Fleets make it easy to set a corporate temperature target per banner or region and still override it for the one flagship that runs tighter.

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

3. Technical Summary

First Event in 30 Minutes

  1. Assemble the hardware (Section 4–5): Notecarrier CX + Notecard Cell+WiFi, DS18B20 temperature probe, SCT-013-030 current transformer, reed switch door sensor, and 5V/2A power supply in a NEMA 4X enclosure.

  2. Create a Notehub project and copy your ProductUID.

  3. Flash the firmware:

    git clone https://github.com/blues/app-accelerators.git
    cd app-accelerators/54-multi-site-walk-in-cooler-energy-setpoint-monitor/firmware/cooler_monitor
    # Edit cooler_monitor_helpers.h: paste your ProductUID into the PRODUCT_UID constant
    arduino-cli core install "STMicroelectronics:stm32"
    arduino-cli lib install "Blues Wireless Notecard" "STM32duino Low Power" "STM32duino RTC" "OneWire" "DallasTemperature"
    arduino-cli compile -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none .
    arduino-cli upload -b STMicroelectronics:stm32:Blues:pnum=CYGNET,usb=none -p /dev/ttyACM0 .

    The usb=none board option disables the USB CDC stack, which has to be off for the host to sleep (see Section 7). sketch.yaml in that directory sets the same board options, so arduino-cli compile without -b picks them up too.

  4. Power the device, then in Notehub open your project → Events tab. The first cooler_summary.qo event (hourly telemetry) arrives once the first 60-minute summary window closes and the next outbound sync runs, so allow up to about two hours. cooler_alert.qo (threshold events) only shows up when an alert fires, which step 6 forces. A typical summary event looks like this:

    {
      "temp_f": 35.4,
      "setpoint_f": 35.0,
      "compressor_amps": 3.5,
      "compressor_run_min": 32.0,
      "door_opens": 5,
      "door_open_sec": 300,
      "kwh_window": 0.42,
      "window_sec": 3600
    }
  5. Set threshold environment variables in Notehub (Fleet → Environment → click a row, edit the JSON):

    • temp_alert_f: 40 (fires when box temp exceeds this, default 40 °F)
    • door_open_alert_sec: 300 (fires when the door stays open continuously for this many seconds, default 5 minutes)
    • Other optional vars: sample_interval_sec, summary_interval_min, temp_setpoint_f, compressor_on_amps, volts_nominal
  6. Trigger a test alert: Open the cooler door, leave it open for >5 minutes, and wait for the next sample cycle. A door_open_long alert shows up in cooler_alert.qo with sync:true (immediate delivery, not queued).

What You'll Have When You're Done

When you've finished, you'll have deployed a complete cellular-connected walk-in cooler monitoring system made up of:

  1. Three non-invasive sensors mounted on the cooler (temperature probe in the box, current transformer clamp on the compressor hot leg, magnetic reed switch on the door). They need no electrical changes and no cooperation from the cooler's OEM.

  2. A local enclosure (Notecarrier CX with onboard STM32 host, Notecard Cell+WiFi, power supply, and bias/pull-up circuits) that samples all three sensors every 60 seconds and automatically sleeps in STOP2 between samples.

  3. Notehub as your cloud backend, storing and routing two streams of data:

    • Telemetry: One summary event per hour per cooler, with averages (temperature, compressor amps) and totals (runtime minutes, door-open events, apparent kWh, window duration).
    • Alerts: Immediate notifications whenever the door is held open > 5 minutes or box temperature exceeds 40 °F, delivered through Notehub routes to your ops/facilities team.
  4. No WiFi required. Cellular connectivity removes the IT ticket bottleneck that has stopped energy programs at hundreds of multi-location operators. It works on franchisee sites, POS-restricted networks, and anywhere there's a cell signal.

  5. Configuration without reflashing. You can tune threshold temperatures, alert timers, and sample/summary cadences with Notehub environment variables, and changes take effect on the device's next inbound sync.

Here's a sample Note this device emits:

{
  "file": "cooler_summary.qo",
  "body": {
    "temp_f": 35.4,
    "setpoint_f": 35.0,
    "compressor_amps": 3.5,
    "compressor_run_min": 32.0,
    "door_opens": 5,
    "door_open_sec": 300,
    "kwh_window": 0.42,
    "window_sec": 3600
  }
}

4. Hardware Requirements

PartQtyRationale
Notecarrier CX1Integrated carrier with an onboard STM32L433 host, so this three-sensor combination doesn't need a separate MCU. The host sleeps in STOP2 between samples until the Notecard's ATTN pin wakes it.
Notecard Cell+WiFi (MBGLW) (datasheet)1Cellular-first connectivity that skips site WiFi entirely, with WiFi fallback for the occasional cooperative site.
Blues Mojo1Inline coulomb counter for checking sleep/wake current profiles on the bench before field deployment.
Adafruit Waterproof DS18B20 Temperature Sensor (product 381)1Calibrated digital 1-Wire temperature probe (±0.5 °C accuracy) in a stainless steel enclosure, built for wet food-service environments where a bare thermistor would corrode.
4.7 kΩ resistor, ¼W1Required pull-up for the DS18B20 1-Wire data line. Without it, the bus hangs.
YHDC SCT-013-030 split-core CT, 30A / 1V RMS (the voltage-output version, with a built-in burden resistor, so you don't add one)1Non-invasive current measurement that clamps over the compressor hot leg without breaking the circuit. The 30A rating matches the single-phase condensing units in most walk-in box installations.
TRRS 3.5 mm breakout (e.g., SparkFun BOB-11570)1The SCT-013's output lead ends in a 3.5 mm three-conductor plug with the signal on tip and sleeve, and this breakout turns it into solderable pads.
10 kΩ 1% resistor (CT bias pair)2Voltage-divider bias circuit that centers the CT's AC signal at Vcc/2 (1.65 V) so the ADC only sees positive voltages.
10 µF electrolytic capacitor1Decouples the bias node so the CT signal can't modulate the divider mid-point.
Adafruit Magnetic Contact Switch / Door Sensor (product 375)1Normally-open reed switch in a pre-wired ABS enclosure. It screws to the door frame, and the included magnet mounts on the door itself. It closes below 13 mm separation and opens above it, and it holds up over millions of cycles with no moving parts to wear out.
10 kΩ resistor, ¼W1External pull-up for the reed switch GPIO (supplements or replaces the internal STM32 pull-up for noise immunity).
AC/DC supply, 5V/2A (e.g., MeanWell IRM-10-5)1Supplies 5V/2A (10 W) DC from the cooler's dedicated circuit. The IRM-10-5 accepts 85–264VAC wide-range input, so it covers both 120VAC and 208/240VAC single-phase supplies. During a cellular session the MBGLW's Quectel EG916Q-GL modem averages ~250 mA (LTE Cat-1 bis). Where the modem falls back to GSM coverage, it can spike to ~2 A for a few milliseconds, and the supply's output bulk capacitance absorbs that burst within its 2 A continuous rating. Confirm the available supply voltage at the installation site before ordering. See Limitations for 24VAC/24VDC control-transformer installs.
External multiband LTE antenna, SMA male (e.g., SparkFun CEL-29622, 600 MHz–2.7 GHz hinged whip)1Mandatory for any metal-enclosure or metal mechanical-room installation. A Notecard antenna inside a steel NEMA 4X box can't radiate reliably. The 600 MHz–2.7 GHz pass-band covers every band the MBGLW's Quectel EG916Q-GL operates on (LTE Cat-1 bis B1/B2/B3/B4/B5/B7/B8/B12/B13/B18–B20/B25–B28/B66). Do not substitute a GPS/GNSS-only antenna (1.55–1.62 GHz), because it won't radiate on the cellular bands. Route the u.FL-to-SMA pigtail (next row) through a cable gland in the enclosure wall, then attach this external SMA antenna on the outside of the gland.
u.FL-to-SMA bulkhead pigtail cable, ~150 mm (e.g., Adafruit product 851)1Connects the Notecard's onboard u.FL antenna port to the external SMA panel-mount antenna. You need it whenever you use an external SMA antenna, since without this cable the antenna has no electrical path to the Notecard radio. A 150–200 mm length routes cleanly inside a ~6×4×2″ NEMA box without extra coiling.
NEMA 4X enclosure, ~6×4×2″1Moisture- and hose-down-rated housing that suits the cold, wet environment of a walk-in mechanical room.

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.

5. Wiring and Assembly

Wiring: DS18B20 1-Wire to D5; SCT-013 CT with V/2 bias to A0; door reed switch to D6 (PULLUP); ATTN → D9 jumper so the Notecard can wake the host from STOP2; external SMA antenna via u.FL pigtail; 120/240 VAC → IRM-10-5 → Mojo → +VBAT

warning

Safety: qualified personnel only. This assembly connects to mains-voltage AC power. A licensed electrician must install the AC/DC supply (wiring it to the cooler's dedicated circuit) in compliance with applicable electrical codes (NEC Articles 100 and 110 and local amendments). Apply lockout/tagout procedures to the circuit breaker before opening any conduit or junction box. Once installed, all three sensors (temperature probe, CT clamp, reed switch) are electrically non-invasive. The CT clamps over the wire without breaking the circuit and is isolated from the mains conductor, but the supply wiring itself is not. Don't energize the enclosure until all wiring is complete and the enclosure lid is secured.

All host I/O goes to the Notecarrier CX dual 16-pin header, and the Notecard Cell+WiFi seats in the carrier's M.2 slot. An external antenna is mandatory in a metal walk-in box or steel mechanical-room cabinet, because a Notecard antenna inside a metal enclosure can't radiate reliably. Route a short u.FL-to-SMA pigtail from the Notecard's u.FL port through a cable gland in the NEMA 4X enclosure wall and attach it to the panel-mount SMA whip antenna outside. For bench validation, Mojo sits inline between the 5V supply and the Notecarrier's +VBAT pad.

Pin-by-pin connections:

  • 3V3 → DS18B20 red wire (VDD); top of the upper 10 kΩ CT bias resistor (the divider's high leg); top of the 10 kΩ door-switch pull-up resistor.
  • GND → DS18B20 black wire (GND); bottom of the lower 10 kΩ CT bias resistor (the divider's low leg); 10 µF capacitor negative terminal; one terminal of the reed switch (either terminal, since it's just a switch).
  • D5 → DS18B20 yellow wire (data); 4.7 kΩ pull-up from D5 to 3V3 wired here.
  • A0 → CT TRRS breakout tip. Build the bias network as a series divider, with one 10 kΩ from +3V3 to the bias node and one 10 kΩ from the bias node to GND, so the bias node sits at Vref/2 ≈ 1.65 V. Connect the 10 µF capacitor from the bias node to GND (it decouples the bias rail to AC ground and is not in series with the signal). The breakout's sleeve lands on the bias node, so the CT sits between the bias node and A0 and neither CT lead goes to GND. A0 then sees 1.65 V DC plus the CT's AC swing (about ±1.41 V peak at 30 A), which stays within the 0–3.3 V ADC window. Don't wire the sleeve to GND. The CT's built-in burden (about 60 Ω) would pull the bias node down to roughly 20 mV, and the ADC would clip the negative half of every cycle.
  • D6 → one terminal of the reed switch; 10 kΩ pull-up from D6 to 3V3. The reed switch's other terminal goes to GND, so under INPUT_PULLUP the pin reads LOW when the door is closed and HIGH when it's open.
  • ATTN → D9 (host-sleep jumper). Fit a short jumper between the ATTN and D9 pins on the Notecarrier CX header. Both are on the same 16-pin header (ATTN at P1 pin 3, D9 at P1 pin 12). Other Notecarrier CX designs use D5 for this jumper, but the DS18B20 takes it here, so the firmware sets CX_ATTN_PIN to D9. The Notecard pulls ATTN low while the host sleeps and raises it when the next sample is due, and the rising edge on D9 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 walks through the full pattern.
  • SDA / SCL → Notecard I²C (Notecarrier CX routes these to the M.2 slot internally; no external wiring needed).
  • +VBAT → Mojo LOAD output (bench use only); Mojo BAT input ← 5V DC output of the MeanWell IRM-10-5 (or equivalent 5V/2A AC/DC supply), which is wired to the AC service conductors in the NEMA 4X enclosure.

CT installation note. The SCT-013-030 is a split-core clamp. Open the clamp and pass it over one hot leg of the compressor's circuit. Don't clamp both legs, because their magnetic fields cancel and you'll read zero. Route the TRRS lead back to the NEMA 4X enclosure through a cable gland. The compressor circuit is line-voltage, so a qualified electrician must do the installation following applicable codes and lockout/tagout procedures. Once clamped, the CT itself is entirely non-contact and electrically isolated.

DS18B20 placement. For accurate air temperature, put the stainless probe tip in open box air at mid-box height or along the return-air path, away from both the evaporator fan discharge and the door. That spot gives the most representative reading of box air temperature. It's a useful proxy for stored-product conditions, but it isn't a direct product core-temperature measurement. Stay away from the evaporator fan discharge. It's the coldest zone in the box and reads several degrees below true representative air temperature, so a probe there biases temperature-to-target deviation calculations low and delays temp_high alerts. Skip the door zone too, since it gets warm infiltration air on every open cycle. Keep the probe away from direct coil contact for the same reason.

Reed switch installation. Mount the ABS switch body on the door frame and the magnet on the door, aligned so the two parts are within 10 mm of each other when the door is fully closed. Test continuity before you close the enclosure. In the debug log (ST-LINK virtual COM port, with DEBUG_SERIAL enabled), pin D6 should read LOW with the door closed and HIGH with it open.

6. Notehub Setup

  1. Create a project. Sign up at notehub.io and create a project. Copy the ProductUID and paste it into firmware/cooler_monitor/cooler_monitor_helpers.h as the PRODUCT_UID constant before flashing.

  2. Claim the Notecard. Power up the unit. The Notecard associates itself with your project on its first cellular connection.

  3. Create Fleets. The natural grouping for a multi-site cooler program is one Fleet per banner or region, since the stores in a given franchise territory usually share the same setpoint targets and alert thresholds. Smart Fleet rules can break out exceptions automatically (e.g., flagship stores with tighter temperature tolerances) without reassigning devices by hand.

  4. Set environment variables. Every variable below is optional, and the firmware defaults apply until you override them. Any variable you set in Notehub takes effect on the device's next inbound sync, with no reflash. To set a variable in Notehub: go to your project → Devices (or Fleet) → scroll down to Settings/Environment Variables → add or update the variable and save. The firmware sets the Notecard's inbound sync interval to 2 × summary_interval_min (120 minutes at the default summary_interval_min = 60), and that's when the Notecard pulls fresh env-var values from Notehub into its on-device cache. The host picks up the new values on its next 60-second wake. So the worst-case time from "save in Notehub" to "value applied on the device" is roughly the inbound interval (up to 120 minutes by default) plus one sample cycle (~60 seconds). To exercise the full path quickly during commissioning, lower summary_interval_min (the firmware keeps the inbound interval at twice that value) or trigger an immediate session with hub.sync from the Blues In-Browser Terminal.

    VariableDefaultPurpose
    sample_interval_sec60Seconds between sensor reads and state updates.
    summary_interval_min60Minutes between cooler_summary.qo Notes. Also re-applies hub.set outbound to keep cellular cadence in sync. The kwh_window field reflects energy accumulated across the scheduled sample intervals within this window.
    temp_setpoint_f35.0Target box temperature (°F). It goes out in every summary Note as setpoint_f, so the corporate dashboard can compute drift = temp_f − setpoint_f without a separate lookup.
    temp_alert_f40.0Box temperature (°F) above which a temp_high alert fires.
    door_open_alert_sec300How many continuous seconds the door can stay open before a door_open_long alert fires (default 5 minutes).
    compressor_on_amps2.0Amps threshold above which the compressor counts as running for runtime and kWh accumulation.
    volts_nominal120.0Nominal line voltage (V) used in the apparent-power kWh estimate.
  5. Configure routes. Add one route for cooler_alert.qo (real-time delivery to a store-ops or facilities channel) and a second for cooler_summary.qo (to a long-term analytics store or BI tool). Because the two Notefiles are separate at the source, they can go to entirely different destinations without any filter logic inside the route.

7. Firmware Design

The firmware is a main sketch plus helper files: firmware/cooler_monitor/cooler_monitor.ino (entry point and sample cycle), firmware/cooler_monitor/cooler_monitor_helpers.cpp (Notecard config, sensor reads, and Note emission), and firmware/cooler_monitor/cooler_monitor_helpers.h (shared constants, types, and declarations). Host sleep (the card.attn request, STOP2 entry, and ATTN wake) lives in firmware/cooler_monitor/cx_sleep.h.

Dependencies:

  • Arduino core for STM32 (stm32duino/Arduino_Core_STM32).
  • Blues Wireless Notecard (note-arduino library). Install it from the Arduino Library Manager or with arduino-cli lib install "Blues Wireless Notecard".
  • STM32duino Low Power and its dependency STM32duino RTC, both from the Library Manager. This library provides the STOP2 entry and ATTN-pin wake used in cx_sleep.h.
  • OneWire library, from the Arduino Library Manager.
  • DallasTemperature library, also from the Arduino Library Manager.

Build settings: The Notecarrier CX's host is the same STM32L433 as the Blues Cygnet, so select Blues boards → Cygnet (pnum=CYGNET) and set USB support (if available) to None (usb=none). If the USB CDC stack is enabled and no USB host is attached (the Notecarrier CX USB-C switch in NC, or no cable at all), the STM32's USB wakeup interrupt fires continuously and the host never stays in STOP2. Debug output (when DEBUG_SERIAL is defined in cooler_monitor_helpers.h) 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

ResponsibilityWhere
Notecard hub.set configuration (power-up in setup() + every wake in loop() until confirmed)hubConfigure()
Template registration for both NotefilesdefineTemplates()
Env-variable fetch and clamp on every wakefetchEnvOverrides()
Re-apply hub.set if summary_interval_min changedapplyHubSetIfChanged()
DS18B20 temperature read (timeout-polled, NaN sentinel)readBoxTempF()
CT two-pass RMS current readreadCompressorAmps()
Reed-switch door-state readreadDoorOpen()
Accumulation, alert evaluation, summary triggerrunSampleCycle()
Immediate-sync alert emissionsendAlert()
Queued summary emissionsendSummary()
Host sleep (STOP2 until the Notecard raises ATTN on D9)cx_sleep.h: cxSleepBegin(), cxSleepUntilAttn() in loop()
Application state (held in RAM across sleep cycles)AppState

Sensor reading strategy

DS18B20. The firmware configures the probe in non-blocking mode (setWaitForConversion(false)). After requestTemperatures(), it polls isConversionComplete() in an 850 millisecond timeout loop instead of calling delay(750). The host stays awake for the whole conversion. It's a timeout-polled read within one wake cycle, not a conversion pipelined across sleeps, but polling keeps the firmware from hanging forever if the sensor is slow to respond. If the probe is disconnected or returns a value below –55 °C or at 85 °C or above (including the 85.0 °C power-up sentinel the DS18B20 can emit on a bus fault), readBoxTempF() returns NAN. The summary then emits –9999 as a sentinel instead of a misleading zero, so downstream analytics can tell "sensor failed" apart from a real measurement.

Current transformer. The SCT-013-030 outputs an AC signal centered at 0 V. A two-resistor 10 kΩ voltage divider from 3V3 to GND, with a 10 µF decoupling capacitor, puts a stable 1.65 V DC offset (Vcc/2) on the ADC pin. The firmware uses a two-pass algorithm. Pass one samples the ADC continuously for 150 milliseconds to compute the DC mean, and pass two samples for another 150 milliseconds and computes the RMS of the AC component around that mean. At 60 Hz one mains cycle is 16.7 milliseconds, so a 150 millisecond window covers about nine complete cycles. That's enough of the actual mains waveform for a well-conditioned RMS result. The firmware floors readings below 0.15 A to zero to suppress ADC noise when the compressor is off.

Reed switch. The firmware reads it with a simple digitalRead and INPUT_PULLUP. The switch is normally open, and it closes (pulling D6 LOW) only when the door is shut and the magnet is within 13 mm of the sensor. Door-open events are edge-detected, so a transition from prevDoorOpen = 0 to doorOpen = 1 increments the event count.

Event payload design

The firmware writes to two template-backed Notefiles. Templates let the Notecard store Notes as fixed-length binary records instead of free-form JSON, which shrinks on-wire payload size by roughly 3–5×. At 24 summary Notes per box per day across a thousand-store fleet, that difference grows quickly. In Notehub's Events tab, the events still show up as human-readable JSON, because the binary template format is internal storage only.

Template type encoding (used by the firmware in defineTemplates()): 14.1 = IEEE 754 4-byte float; 14 = 4-byte signed integer; 12 = 2-byte signed integer. You specify these when you register a template with the Notecard, so it knows how to pack and unpack each field.

cooler_summary.qo (per summary window, queued):

{
  "file": "cooler_summary.qo",
  "body": {
    "temp_f": 35.4,
    "setpoint_f": 35.0,
    "compressor_amps": 3.5,
    "compressor_run_min": 32.0,
    "door_opens": 5,
    "door_open_sec": 300,
    "kwh_window": 0.42,
    "window_sec": 3600
  }
}

Here's what the fields mean. temp_f and compressor_amps are window averages (sum of valid readings ÷ valid-reading count), while compressor_run_min, door_open_sec, door_opens, and kwh_window are window totals. window_sec is the sum of the scheduled sample intervals that elapsed during the window. It counts sleep time only and leaves out the awake time spent sampling. If sample_interval_sec doesn't divide evenly into summary_interval_min × 60, the window overshoots by at most one sample period. Downstream tools should use window_sec as the denominator for any energy-rate or duty-cycle calculation (e.g. average watts = kwh_window / window_sec × 3 600 000), keeping in mind that actual wall-clock time runs marginally longer than window_sec because of the excluded awake time. setpoint_f carries the current Notehub-configured corporate target (not a value read from the cooler controller), so a dashboard can compute deviation = temp_f − setpoint_f per record without a separate lookup. A –9999 in temp_f signals a sensor fault (e.g. probe disconnected).

cooler_alert.qo (immediate, sync:true bypasses outbound cadence):

{
  "file": "cooler_alert.qo",
  "body": {
    "alert": "door_open_long",
    "temp_f": 38.1,
    "amps": 10.4,
    "door_open_sec": 300
  },
  "sync": true
}

Low-power strategy

The sampling cadence (every 60 seconds by default) and the transmission cadence (every 60 minutes) are independent of each other. setup() runs once at power-up to configure the Notecard and the sensors, and each pass through loop() is one sample cycle. After the cycle, cxSleepUntilAttn() (in cx_sleep.h) sends a card.attn sleep request for sample_interval_sec seconds, waits for the Notecard to pull ATTN low, and puts the STM32 host into STOP2, where it draws a few microamps and keeps its RAM intact. When the interval is up, the Notecard raises ATTN. The rising edge on D9 wakes the host, execution resumes on the next line of loop(), and because the AppState struct lives in RAM, nothing needs to be serialized to the Notecard. If the sleep request fails or ATTN never goes low (jumper missing), loop() waits out the interval awake and tries again on the next cycle.

Between cellular sessions, the Notecard idles in its own low-power mode. The walk-in cooler runs on 120VAC, so the absolute mAh budget isn't the constraint here. The sleep pattern still matters for enclosure thermal management and for porting the design to future battery-assisted variants.

Retry and error handling

  • hub.set is retried on every wake until confirmed. hubConfigure() returns bool. The first call runs in setup() at power-up and stores its result in state.hubSetConfirmed. If that call fails, every later pass through loop() hits an if (!state.hubSetConfirmed) branch that retries hubConfigure() unconditionally, whether or not env.get succeeds. Once hubSetConfirmed is set, the device switches to the lighter applyHubSetIfChanged() path, which re-issues hub.set only when summary_interval_min changes. That way the device can't stay permanently unassociated while it quietly piles up Notes in its local queue.
  • env.get checks the err field on the response before it touches body, so a failed request leaves the current values in place instead of corrupting the config.
  • The two alert types carry independent cooldown timers (doorAlertCooldownSec, tempAlertCooldownSec) measured in wall-clock seconds, so timing stays accurate when sample_interval_sec changes. Each alert can fire at most once per 30-minute window, which keeps a door left open for a while or a sluggish compressor from firing dozens of identical alerts on consecutive wakes.
  • If a Notehub env var changes summary_interval_min, applyHubSetIfChanged() re-issues hub.set with the updated outbound cadence, so the Notecard's cellular session timing follows the new summary period instead of drifting. This path only runs after hubSetConfirmed is true.

Key code snippet 1: template definition

Template type hints tell the Notecard how to pack each field (see "Template type encoding" above). door_open_sec and window_sec use 14 (4-byte signed integer) instead of 12 (2-byte signed integer, max ~9 hours), because long summary intervals or a stuck door can pile up values that overflow a 2-byte integer. door_opens, on the other hand, uses 12 (2-byte signed, up to ~32k events), since a realistic window rarely tops 50 door cycles. The Blues template data-type guide has the complete field-type reference. FILE_SUMMARY is cooler_summary.qo, defined in cooler_monitor_helpers.h.

J *req = notecard.newRequest("note.template");
// ...
JAddStringToObject(req, "file", FILE_SUMMARY);
J *body = JAddObjectToObject(req, "body");
JAddNumberToObject(body, "temp_f",              14.1);
JAddNumberToObject(body, "setpoint_f",          14.1);
JAddNumberToObject(body, "compressor_amps",     14.1);
JAddNumberToObject(body, "compressor_run_min",  14.1);
JAddNumberToObject(body, "door_opens",          12);
// ...
JAddNumberToObject(body, "door_open_sec",       14);
JAddNumberToObject(body, "kwh_window",          14.1);
// ...
JAddNumberToObject(body, "window_sec",          14);
J *rsp = notecard.requestAndResponse(req);
if (!rsp || notecard.responseError(rsp)) {
    DBG_PRINTLN("[tmpl] summary template registration failed");
    ok = false;
}
if (rsp) notecard.deleteResponse(rsp);

Key code snippet 2: immediate-sync alert

sync:true skips the outbound cadence, so the Notecard wakes the radio immediately. runSampleCycle() calls sendAlert() with door_open_long or temp_high, and arms that alert's 30-minute cooldown only when it returns true.

bool sendAlert(const char *alert, float tempF, float amps, uint32_t doorSec) {
    J *req = notecard.newRequest("note.add");
    // ...
    JAddStringToObject(req, "file", FILE_ALERT);
    JAddBoolToObject(req, "sync", true);
    J *body = JAddObjectToObject(req, "body");
    JAddStringToObject(body, "alert",         alert);
    JAddNumberToObject(body, "temp_f",        (double)tempF);
    JAddNumberToObject(body, "amps",          (double)amps);
    JAddNumberToObject(body, "door_open_sec", (int32_t)doorSec);
    J *rsp = notecard.requestAndResponse(req);
    if (!rsp) {
        DBG_PRINT("[alert] no response for: "); DBG_PRINTLN(alert);
        return false;
    }
    bool ok = !notecard.responseError(rsp);
    if (!ok) { DBG_PRINT("[alert] note.add error for: "); DBG_PRINTLN(alert); }
    notecard.deleteResponse(rsp);
    return ok;
}

Key code snippet 3: sleeping until the Notecard raises ATTN

cxSleepUntilAttn() asks the Notecard to hold ATTN low for cfgSampleSec seconds, confirms the pin has gone low, and puts the STM32 into STOP2. Since the host stays alive, the firmware checks the result of the card.attn call instead of treating it as fire-and-forget. The DS18B20 occupies D5, so this sketch overrides the wake pin before including the header.

#define CX_ATTN_PIN D9   // D5 is the DS18B20 data line; wake on D9 instead
#include "cx_sleep.h"

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

void loop() {
    // ...
    runSampleCycle(state);

    // Sleep until the Notecard raises ATTN cfgSampleSec from now.
    // ...
    if (!cxSleepUntilAttn(notecard, cfgSampleSec, NULL, log)) {
        // The Notecard didn't take the sleep request, or ATTN never went low
        // (check the ATTN -> D9 jumper). Keep the sample cadence and try again.
        DBG_PRINTLN("[sleep] ATTN sleep failed — waiting out the interval awake");
        delay(cfgSampleSec * 1000UL);
    }
}

8. Data Flow

Data flow: 60s sample of box temp/compressor amps/door state → two rules (door_open_long, temp_high) with 30-min cooldowns → cooler_alert.qo (sync:true) and cooler_summary.qo (hourly templated) → Notehub routes

Collected every sample_interval_sec (60 seconds by default): box air temperature (°F), compressor RMS amps, and door open/closed state.

Accumulated within each summary window: compressor apparent kWh (V × I × t / 1000, compressor hot leg only), compressor runtime minutes, total door-open seconds, and door-open event count (rising-edge transitions).

Transmitted:

  • cooler_summary.qo: one record per summary_interval_min (about once an hour by default), queued locally and flushed during the Notecard's scheduled outbound cellular session. temp_f and compressor_amps are window averages (mean over all valid reads during the window). compressor_run_min, door_open_sec, door_opens, and kwh_window are window totals. window_sec is the sum of scheduled sample intervals for the window, so use it as the denominator for energy-rate calculations. It counts sleep time only, and actual wall-clock elapsed time is marginally longer because awake time is excluded. setpoint_f carries the current Notehub-configured corporate target, so downstream tools can compute deviation = temp_f − setpoint_f per record without a separate lookup. –9999 signals a sensor fault for temp_f, where NAN would be meaningless in JSON.
  • cooler_alert.qo: sent only when a threshold trips, with sync:true to skip the outbound timer. The alert cooldown allows no more than one alert per type per 30-minute window.

Routed. Both Notefiles arrive at Notehub and go from there to whatever downstream routes the project configures. The two filenames are different on purpose, so each can go to its own destination with its own urgency and no route-level filtering.

Alert triggers:

  • door_open_long: the door has been open continuously for at least door_open_alert_sec seconds (default 5 minutes). While the door stays open, it fires again at most once per 30-minute cooldown window. One page-out every half hour is enough for store ops to investigate.
  • temp_high: box temperature exceeds temp_alert_f (default 40 °F). The alert carries the current amps reading, so the responder can see right away whether the compressor is running (equipment issue) or off (power outage, breaker trip).

9. Validation and Testing

Expected steady-state cadence. A healthy cooler sends one cooler_summary.qo event about every summary_interval_min (60 minutes by default) and no cooler_alert.qo events unless a threshold is breached. As a rough reference, a mid-size commercial walk-in cooler (800–1200 cu ft) at a typical QSR might show:

  • Compressor runtime: 35–55% duty cycle (21–33 minutes per 60-minute window)
  • Compressor apparent kWh: 0.3–0.6 kWh per window
  • Door opens: a handful per window (depends on traffic). The firmware only counts an opening that's still open at a sample, so quick in-and-out trips between samples don't show up
  • Door open time: 60–300 seconds cumulative per window, in whole sample intervals (60 seconds each by default)
  • Temperature drift: 0–2 °F above setpoint (after stabilization)

These are order-of-magnitude benchmarks, and real figures vary a lot with box volume, insulation, ambient conditions, product load, and defrost cycle frequency. If temp_f runs consistently more than 3–4 °F above temp_setpoint_f, look into it no matter what the runtime figures say.

Simulating alerts during commissioning. There are two quick threshold tests. First, set temp_alert_f just below the current ambient in Notehub's environment-variable editor, wait one inbound sync (~120 minutes, or send hub.sync from the blues.dev In-Browser Terminal), and watch for a temp_high alert in the Events tab. Second, open the cooler door and leave it open past door_open_alert_sec to trigger door_open_long. Restore the original threshold after each test.

Using Mojo to validate power behavior. During bench testing, the Mojo sits inline between the 5V supply output and the Notecarrier CX +VBAT pin and reports cumulative mAh over its Qwiic I²C link. Mojo measures at the +VBAT rail, so it sees the whole assembly: the Notecard, Notecarrier CX, STM32 host, DS18B20, CT bias circuit, and reed switch, not just the Notecard.

(a) Published Notecard Cell+WiFi (MBGLW) current figures. The table below cites figures from the Blues low-power design documentation and the MBGLW datasheet. They're Notecard-only figures, and the Mojo reading will be higher because it includes the Notecarrier and sensors.

Operating modePublished current (Notecard only)Source
Idle, radio off (between syncs)~8–18 µA @ 5VBlues low-power docs
LTE Cat-1 bis session active (primary RAT)~250 mA average. The supply rail must handle brief current peaks, so see Blues cellular power-supply guidance for sizingMBGLW datasheet
GSM fallback (rare; areas without LTE coverage)Up to ~2 A for a few milliseconds during a GSM transmit burst, absorbed by the supply's output bulk capacitance within the IRM-10-5's 2 A continuous ratingMBGLW datasheet
Per-session energy (single queued Note, bench test)~0.3 mAhBlues low-power design tests
WiFi active (opportunistic fallback)Not specified separately in the MBGLW datasheet. The integrated Silicon Labs WFM200S WiFi module adds to the cellular idle baseline when active, so check the WFM200S transceiver datasheet for characterization dataMBGLW datasheet, hardware overview

(b) Expected Mojo trace (whole assembly at +VBAT). Your Mojo readings will sit above the Notecard-only floor because they include the Notecarrier CX regulator, the CT bias voltage divider (~165 µA continuous from the 3V3 rail), and the connected sensors' quiescent draw. Here's the expected pattern, with approximate ranges for each firmware phase:

PhaseApprox. whole-assembly current at +VBAT
Host in STOP2 between samples (card.attn sleep, Notecard idle)~0.5–1 mA, well above the Notecard-only µA floor. The host in STOP2 adds only ~1–2 µA, so the CT bias divider and Notecarrier CX regulator quiescent current dominate
Host active during sampling (~1–2 seconds per wake)~15–30 mA spike from the active STM32L433 host, the 750 millisecond DS18B20 conversion, and the 2 × 150 millisecond CT ADC passes
Cellular outbound session, LTE Cat-1 bis (~30–60 seconds per hour)~250–300 mA: the Notecard modem (~250 mA average) plus Notecarrier and sensor overhead. The 5V/2A supply handles this with plenty of headroom. In rare GSM-only coverage areas the modem bursts to ~2 A for a few ms, and the supply's output capacitance absorbs that within its 2 A rating.

The shape of the trace tells you as much as the absolute level. You want to see a stable sub-milliamp floor between wakes, a ~15–30 mA spike every 60 seconds lasting 1–2 seconds (one sample cycle), and a ~250–300 mA plateau once per summary window lasting tens of seconds (the LTE Cat-1 bis cellular session). A persistent multi-mA floor between wakes, above the ~0.5–1 mA sleep baseline, means the host isn't entering STOP2. Check the ATTN→D9 jumper and confirm the firmware was built with the usb=none board option. If cellular plateaus come more often than the configured summary cadence, an alert is firing and triggering sync:true sessions outside the normal schedule. Both of those draws are a negligible fraction of the 5V/2A supply's capacity. Where the bench measurement really pays off is in catching firmware regressions that accidentally leave the host awake all the time.

10. Troubleshooting

Device claims to Notehub but no events appear after 2+ hours.

  • Make sure the Notecard firmware is up to date. In Notehub, go to Devices → click your device → Device Info → Notecard version. If it's out of date, trigger a Notecard firmware update.
  • Confirm the ProductUID in the firmware matches your Notehub project. The Notecard won't transmit to the wrong project.
  • In the Blues In-Browser Terminal (top-right button), run hub.status to check the Notehub connection and card.wireless to check cellular signal (rssi in dBm and bars in its net object). If you see "status": "disconnected", wait 2–3 minutes and try again, since the first connection can take several cycles.
  • Check that the templates are registered. The Events tab only lists Notes that have arrived, so it can't show you an empty Notefile. Instead, send {"req":"note.template","file":"cooler_summary.qo","verify":true} from the In-Browser Terminal, which returns the template body if one is set. If it isn't, the defineTemplates() function failed, so check the firmware logs on the ST-LINK virtual COM port (Notecarrier CX debug jack) with DEBUG_SERIAL enabled.

Events appear but temp_f or compressor_amps show NaN or -9999.

  • temp_f = -9999: the DS18B20 probe is disconnected or shorted, or the 4.7 kΩ pull-up is missing or open. Check D5 connectivity and the probe's 1-Wire bus.
  • compressor_amps = 0.0: the CT is reading zero. Check that the CT clamp is around only one hot leg of the compressor circuit, because clamping both cancels the field. Make sure the TRRS connector is fully seated at the SCT-013 input, and check that the A0 bias-circuit voltage is ~1.65 V (measure with a multimeter between A0 and GND).

Door-open alerts keep firing (once per 30-minute cooldown) even when the door is closed.

  • D6 reads HIGH with the door shut, so the firmware thinks it's open. The magnet is out of range of the switch, the reed switch has failed open, or the D6 or GND lead is broken. Confirm the switch reads LOW on D6 when the door is physically closed and HIGH when it's open. You can check with a pin voltage meter, or upload a sketch that prints digitalRead(D6) to the ST-LINK virtual COM port.
  • Realign the magnet to within 10 mm of the switch. If D6 still reads HIGH with the magnet right against it, replace the switch.

Cellular sessions happen more frequently than expected (not just every summary_interval_min).

  • Alerts are firing and triggering sync:true sessions outside the normal cadence. Look for cooler_alert.qo in the Events tab. If it's there, one of the two alert rules is active, so check that the temp_alert_f and door_open_alert_sec thresholds aren't too tight for your operating environment.

Device wakes and samples but the Mojo trace never drops to the sleep floor between cycles.

  • The host isn't entering STOP2. Check the ATTN→D9 jumper on the Notecarrier CX header. Without it, cxSleepUntilAttn() sees that ATTN never goes low, waits out the interval awake, and retries. Also confirm the firmware was built with USB support set to None (usb=none), and verify I²C connectivity between the Notecarrier and Notecard. Make sure the firmware has no blocking delays or delay() calls outside of timeout-polled sensor reads (e.g., in loop() before cxSleepUntilAttn()).

11. Limitations and Next Steps

A reference design that has to drop onto 800 different walk-in boxes has to be modest, on purpose, about what it measures and what it concludes. The rest of this section spells out where this one draws those lines.

Simplified for this POC

Each simplification below was a deliberate scope choice. Once basic fleet visibility is paying for itself, these are the places a particular operator will want to add a sensor, calibrate a probe, or wire in a controller-side integration.

Sensor reads are sample-based, not interrupt-driven. The firmware polls all three sensors once per sample_interval_sec (60 seconds by default). Any door opening, door closing, or compressor start/stop that happens and finishes within one 60-second sleep interval goes undetected. That quantizes edge timing to the sample period, which directly affects door_opens, door_open_sec, compressor runtime, and kwh_window. Any of them can undercount if events are shorter than the sample period. door_open_long alert timing is quantized the same way. A door that opens just after one sample and closes just before the next may not trip the alert, even if it was physically open longer than door_open_alert_sec. Lowering sample_interval_sec with an environment variable improves resolution, but it increases host awake time and may increase alert frequency (more frequent checks catch alert conditions sooner and may trigger sync:true sessions more often). Scheduled outbound cellular sessions are still governed by summary_interval_min and don't increase with the sample interval alone.

AC supply voltage. The MeanWell IRM-10-5 in the BOM accepts 85–264VAC wide-range input and handles both 120VAC and 208/240VAC single-phase, which covers most walk-in condensing-unit installations. Some mechanical rooms only provide a 24VAC or 24VDC control-transformer rail instead of mains voltage. Those installs need a different converter (a 24VAC-input or 24VDC-input step-down regulator) in place of the AC/DC supply listed here. Always confirm the available supply with the field electrician before ordering components.

Compressor apparent energy only, not total cooler energy. The single CT clamps one hot leg of the compressor circuit, so evaporator fans, defrost heaters, door heaters, controls, lighting, and other loads on the cooler's electrical service aren't measured. kwh_window is a compressor-energy proxy, not total cooler or site energy consumption. If total box energy is the metric you want, you'd need a revenue-grade multifunction meter or more CT channels for the non-compressor loads. The estimate also uses apparent power (V × I) instead of real power (V × I × PF). A typical single-phase hermetic compressor motor has a power factor of 0.75–0.90, so the estimate will overstate actual compressor energy by 11–33 %. For billing-grade energy monitoring, use a calibrated kilowatt-hour meter with a pulse output. The single-CT apparent-power approach gives you a useful relative metric for comparing compressor behavior across units and tracking trends over time, not an absolute kWh figure.

Single-phase only. Larger walk-in boxes (over 4,000 cu ft) or walk-in freezers may run three-phase compressors, which need three CTs, more ADC channels, and firmware changes to sum the per-phase apparent power.

Temperature sensor without calibration offset. The DS18B20 probe is factory-calibrated to ±0.5 °C (±0.9 °F). For temperature-to-target deviation monitoring at ±1 °F precision, an in-situ calibration offset stored as an environment variable would remove the unit-to-unit spread.

Temperature-to-target deviation is a downstream-derived metric, not an on-device rule, and the cooler controller's thermostat setpoint is not observed. The device has no connection to the cooler's onboard controller or thermostat. setpoint_f in every summary Note is the corporate target temperature configured as a Notehub environment variable (temp_setpoint_f), not a value read from the cooler's electronic or mechanical controller. Monitoring the actual controller setpoint would take an integration with the cooler controller (over Modbus or a proprietary serial interface). A downstream dashboard can compute deviation (temp_f − setpoint_f) per record, but the firmware itself never compares temperature against setpoint_f. Its only on-device temperature alerting is the temp_high rule, which fires when temp_f exceeds the separate temp_alert_f threshold (default 40 °F). temp_high is a fixed threshold, not a setpoint-relative check, so a legitimate spike during a freight delivery (door held open 10 minutes) triggers the same alert as a genuine refrigerant problem. Gating the alert on compressor runtime and recent door activity would cut those false positives considerably.

No GNSS. Notecard Cell+WiFi includes a GNSS module, but this project doesn't use it, because a walk-in cooler box stays put. If mapping dashboards need the site's lat/lon, you can bootstrap a one-time site location from cellular tower triangulation with card.location.

Production Next Steps

With basic fleet visibility in place, these extensions are the usual next moves. They start with what's most immediately useful and end with the items that lean hardest on infrastructure.

A per-unit calibration offset for the DS18B20 (temp_offset_f env var, applied in readBoxTempF() at runtime) is the first refinement, and it tightens per-probe accuracy across the fleet.

A door_open_max_sec field on the summary payload would capture the longest single uninterrupted door-open event in the window. That helps tell a normal rapid-turnaround pattern apart from one sustained-open incident, which door_open_sec (total) can't show on its own.

Three-phase compressor support brings larger boxes into scope with three SCT-013-030 CTs on A0/A1/A2, RMS per leg, and summed apparent power.

kWh power-factor correction through a power_factor environment variable (0.80 default) lets ops dial in a correction for each unit type after a baseline period against a reference meter, which narrows the apparent-vs-real-power gap described above.

Notecard Outboard DFU adds over-the-air firmware updates, so threshold-algorithm improvements can roll out fleet-wide without truck rolls.

A cooler_config.qi inbound Notefile would let the ops team request a diagnostic dump, a full state snapshot on demand, without waiting for the next summary.

12. Summary

The corporate energy team that used to stall at the 50-store pilot now has a fleet-wide view of compressor apparent kWh per window, door-open seconds, and temperature drift against a setpoint they configure from a browser. It takes one cellular SKU and three sensors, and the field tech never has to ask anyone for a WiFi password. The outlier box running double the compressor-hours of its peers now shows up on a dashboard instead of in next month's utility bill.

On This Page

  • 1. Project Overview
  • 2. System Architecture
  • 3. Technical Summary
    • First Event in 30 Minutes
    • What You'll Have When You're Done
  • 4. Hardware Requirements
  • 5. Wiring and Assembly
  • 6. Notehub Setup
  • 7. Firmware Design
    • Modules
    • Sensor reading strategy
    • Event payload design
    • Low-power strategy
    • Retry and error handling
    • Key code snippet 1: template definition
    • Key code snippet 2: immediate-sync alert
    • Key code snippet 3: sleeping until the Notecard raises ATTN
  • 8. Data Flow
  • 9. Validation and Testing
  • 10. Troubleshooting
  • 11. Limitations and Next Steps
    • Simplified for this POC
    • Production Next Steps
  • 12. Summary

Resources

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