I build connected devices and the systems behind them. On the device side, that means ESP32 firmware that keeps reporting over cellular from rooms nobody visits. Behind the device, I build the pipelines that carry industrial data and the models and statistics that show whether a process change worked. I also design and run AI systems: I pick use cases worth building, prove them against a measured baseline, and put agents to work with evaluation and guardrails in place from the start.
I'm available for contract work and full-time roles. Email johnragonhall@gmail.com with what you are building and when you need it.
Portfolio and case studies · LinkedIn · United States
AI use cases that never leave the demo. I start from a business question and a measured baseline, then build the model or agent and prove it against that baseline. On a client computer vision project, the baseline audit put hand picking at 72.0% of orders fully correct, and camera auditing raised it to 94.1%. The scoping questionnaire, claim check, PRD, and pilot plan I use to choose and scope a use case are in engineering-templates.
AI systems a team can trust. I design agents with evaluation defined before a model is chosen. In twinflow, the agent has to back each answer with a statistical verdict, scored on grounding and calibrated abstention. I run AI coding agents the same way: claude-code-setup is my configuration with guard hooks, a self-test, and validators in CI, and performance-ladder-review makes an agent prove every optimization with a number. I am also building a desktop application for managing local and cloud AI models, kept private while in development.
Devices that drop offline in the field. I write firmware that reports its own health and recovers without a site visit: on-device self-tests, a recovery ladder, OTA updates, and cellular backoff with jitter and a circuit breaker. Read the recovery ladder and backoff samples, or how I worked out whether a field upload failure was a gateway stall or a firmware bug.
Telemetry nobody trusts. Plant data shows up late, out of order, duplicated, or corrupt. sparkplug-pipeline sends all of that on purpose, and an integration test checks where each message lands. spbconform holds an edge node to the Sparkplug B specification.
Models that fall apart on real process data. I validate a model the way it will be used: a time-ordered split, class imbalance handled, PR-AUC with bootstrap confidence intervals, and a label-shuffle test. In secom-spc, those checks showed a fail predictor that does not clearly beat chance, and the write-up says so. Process changes argued instead of tested. I settle the argument with SPC, hypothesis tests, designed experiments, and Lean Six Sigma, and I check first whether a control chart can be trusted at all. twinflow is the larger version of that idea: test a change on a simulated warehouse before anyone moves a shelf.
Firmware fixes for a fleet with no rollback. A bad update can cost a site visit, so I plan releases around that. Read how I shipped fixes to a fleet with no rollback, and see the gates I run on every merge in git-quality-gates.
twinflow is a warehouse digital twin I am building in the open. In the design, a discrete-event model of receiving and putaway drives a simulated MQTT device fleet. A Lean Six Sigma engine judges the telemetry and the model's own predictions, and an AI agent answers what-if questions with a statistical verdict. The deployment follows the Purdue model, with the broker bridge as the only path between the OT and IT segments. Version 0.1.0 is out and phase 1 is in progress. Read the docs.
sparkplug-pipeline carries Sparkplug B over MQTT into TimescaleDB and a dashboard, all from one docker compose up. Its simulator reorders, duplicates, and corrupts messages, wraps the sequence counter, and replays late data after an outage. Ingest ran at a median of 4,205 messages per second over four runs on a laptop.
spbconform turns the Eclipse Sparkplug B v3.0.0 specification into a test suite. It carries all 299 testable assertions, runs executable checks for 143, and records the reason for each of the other 156. I wrote it clean-room with zero dependencies, under MIT.
secom-spc applies statistical process control to the UCI SECOM semiconductor data with I-MR charts, Nelson rules, EWMA, and CUSUM. An autocorrelation check decides whether a chart can be trusted; one sensor flags 81% of runs because its readings are autocorrelated. The fail predictor scores a PR-AUC of 0.085 against a 0.055 no-skill baseline, and the write-up reports that it does not clearly beat chance.
Most of my production work is client firmware in private repositories, so I describe it here without names.
- Cellular RFID gateway. An ESP32 with an LTE modem reads an RFID reader over Ethernet and uploads through mbedTLS, managed with Azure IoT Hub device twins. It has OTA updates, on-device self-tests, a recovery ladder, native unit tests, libFuzzer harnesses, and GitHub Actions workflows for provisioning and deploys.
- IoT Network Check. A site network preflight and on-device connectivity self-test, built as a Windows and Linux CLI plus an ESP32 library in C++.
Case studies from client work, with names removed:
- Gateway or device: placing an upload failure
- Checking pick accuracy with a camera model
- Shipping firmware fixes to a fleet with no rollback
- A phone app and a TV display for an open-source radar sensor
- performance-ladder-review: a measure-first performance skill for AI coding agents, with a
PERF:marker on every decision. One twinflow fix went from 73.91 ms to 0.291 ms at n=2,000, and a desktop app's startup bundle shrank from 813.2 KB to 672.0 KB. - git-quality-gates: git hooks and CI gates for conventional commits, a regression test on every fix, comment and prose standards, and a copyleft license allowlist. Every bypass gets logged.
- claude-code-setup: a template Claude Code configuration with layered context, generated routing, guard hooks with a self-test, and validators.
- engineering-templates: document templates and a starter repo that run from discovery to production support, including PRD, ADR, FMEA, DOE, RCA, threat model, and release notes.
- sim7600-emulator: a SIM7600 AT-command emulator for bench-testing cellular firmware without a modem.
- rfid-reader-emulator: an HTTP/XML RFID reader emulator with seeded tags and fault injection.
Code samples: recovery ladder (C++17, boot-loop detection, no heap), cellular backoff (C++17, full jitter, circuit breaker), and a Nelson rules checker (Python, standard library only).
I write the test first, and every bug fix ships with a regression test. A number in my docs comes from a recorded run; until I measure something, it says TBD. My deliverables use permissive licenses and clean-room code, with no copyleft. And because nobody watches the devices I ship, the firmware reports its own health and recovers on its own.
| Area | What I do | Proof |
|---|---|---|
| AI systems and strategy | Choose AI use cases against a measured baseline, scope pilots, define evaluation before choosing a model, design agents that ground their answers and abstain when unsure, and run AI coding agents behind guardrails | Camera pilot took order accuracy from 72.0% to 94.1% (case study); agent evaluation design in twinflow; claude-code-setup passes 70 of 70 hook behavior tests |
| Machine learning | Supervised classification and computer vision, with time-ordered validation, class imbalance handling, PR-AUC with bootstrap intervals, label-shuffle tests, and honest reporting when a model is weak | secom-spc; computer vision model trained on 6,761 images across five versions (case study) |
| Data science and statistics | Python and R with pandas, NumPy, SciPy, statsmodels, scikit-learn, and Jupyter; SPC (I-MR, Nelson rules, EWMA, CUSUM), hypothesis testing, DOE, and Lean Six Sigma | secom-spc, twinflow |
| Industrial data engineering | MQTT, Sparkplug B, ISA-95 and the unified namespace, Purdue OT/IT segmentation, TimescaleDB, and pipelines that handle late, duplicate, and out-of-order data | sparkplug-pipeline at a median of 4,205 messages/s; spbconform covers all 299 testable Sparkplug B assertions |
| Embedded and connectivity | C and C++ on ESP32 with FreeRTOS and PlatformIO, mbedTLS, LTE modems, Azure IoT Hub device twins, OTA updates, and firmware that recovers on its own | Production gateway firmware (client work); recovery ladder and backoff samples; sim7600-emulator |
| Performance engineering | Measure-first optimization: profile, delete before tuning, and record every before and after | 73.91 ms to 0.291 ms in twinflow; 26.4 ms to 1.25 ms on a radar signal-processing step; a 813.2 KB to 672.0 KB startup bundle; performance-ladder-review |
| Mobile and edge devices | React Native and TypeScript, Bluetooth LE GATT with HMAC-SHA256 challenge pairing, React kiosk UI, embedded Linux, and Flask APIs | Radar sensor case study |
| Engineering quality | Tests first, libFuzzer, CI gates, conventional commits, copyleft license gates, and clean-room implementations | git-quality-gates; clean-room spbconform |
| Product and delivery | PRDs, roadmaps with evidence gates, ADRs, FMEA, release plans with QA gates, and root-cause analysis | twinflow PRD; engineering-templates; release case study |
Languages: C, C++, Python, R, TypeScript, PowerShell.