BIOS v2.6 — RepairmanRay Systems
Initializing kernel modules...
Mounting /home/ray .............. OK
Loading personality matrix ...... OK
System ready.
RepairmanRay
Repairman.  Builder.  Nerd.
ray@joplin:~$
scroll

About Me

I'm Ray — based in Joplin, MO. Repairman. Builder. Nerd.

I do apartment maintenance for a living, which mostly means the same things breaking in the same ways. Problem-solving is what I'm actually good at, and building is what I love. I have component-level electronics experience from back when people still got things repaired. Nobody does that anymore, but it turns out that background is a pretty good foundation for what's happening right now: ESP32s, Arduinos, Raspberry Pis, a flood of cheap sensors, and AI tools that mean I can build things I never could have written code for on my own. It's an embarrassment of riches and I'm spending every spare hour taking advantage of it.

I get why people are scared of AI. We don’t have a good track record lately of using technological improvements for the good of the many. But like it or not, the technology is here. The real question is what are we going to do with it? We as a society have a chance to shape things in a positive, as well as profitable direction for all.

My own experience has been astonishing: these tools let me build things I never could have built alone, and I work harder for it, not less. Nobody lost a job so I could do this — something new just got made that didn't exist before. Make the right choices as a society, and everyone gets to share in that kind of improvement without absorbing the downsides.

Location
Joplin, MO
Daily Driver OS
Linux
Current Obsession
ESP32 / LoRa mesh builds
Status
Online ▮

Projects

◌ Paused — Resuming
maintenance tool · ESP32 · self-calibrating acoustic positioning · adaptive noise rejection · paused, resuming 2026-09
Low-Battery Chirp Locator
A smoke detector in the building is chirping. This system pinpoints which unit it's coming from using two wireless mic nodes and radio-synced timing — no walking the hallway, no guessing, no wasted trip. Development paused in mid-July after detection and ranging both proved reliable on the bench; picking back up now. The engineering center of gravity has shifted: the two nodes' onboard buzzers don't reliably hear each other, but that only affects an optional self-test, not real chirp detection — the more interesting question right now is how much telemetry this hardware could carry for almost nothing extra.

The problem

In long apartment hallways, one chirp sounds exactly like another no matter where you're standing. Without a system, finding the dead battery means walking 200 feet of corridor and pressing your ear to every unit door — sometimes multiple passes, sometimes needing the tenant home. A 30-minute service call for a $3 battery.

How it works

A coordinator ESP32 broadcasts a radio timing pulse via ESP-NOW every second. Two sensor nodes — mounted at opposite ends of the hallway — each run an INMP441 digital microphone. When a chirp arrives, each node records the exact microsecond offset from the nearest coordinator pulse. The coordinator compares those two timestamps: the time difference, combined with the known node spacing, resolves which unit the chirp came from — logged live with unit position, timestamp, and confidence to a dashboard the technician can check from anywhere. No walking required.

Self-ranging — no manual measuring

The two nodes measure their own separation acoustically instead of requiring a tape measure at install time: the coordinator fires a buzzer pulse from one node, times how long its partner takes to hear it, then reverses the shot. The round-trip pair resolves both distance and clock offset. A boot-time and periodic (6-hour) auto-recalibration keeps the system accurate even if a node gets bumped or repositioned, with an outlier-rejecting median-of-several-shots average smoothing out single-measurement noise. Turns out to matter less than it first seemed, though — once nodes are permanently mounted, spacing is just measured by hand at install time. A later test also found the two nodes don't reliably hear each other's own onboard buzzer at all, even though it's audibly loud in person; since self-ranging isn't load-bearing for a real install, that's now a low-priority diagnostic curiosity, not something blocking progress. The buzzer exists for this self-test and nothing else — it plays no role in actual chirp detection.

Detecting the chirp itself

Each node runs the Goertzel algorithm — an efficient single-frequency detector — locked onto the measured chirp tone (~3,327 Hz) and a second "confuser" tone shared by common false alarms like microwaves. An adaptive noise floor (an exponential moving average that only updates while nothing is triggered) tracks the room's own background level instead of relying on one fixed number. Empirical tuning against a live HVAC-noise session found a clean separation — ambient noise topped out around 9–10x that floor, real chirps scored 15–68x — landing the detection threshold at 12x with zero false positives across a 90-minute confirmation run.

Auto-learned noise rejection

Rather than hand-writing a new rule every time a new confuser sound turns up, every trigger's underlying audio is independently re-analyzed against the chirp's actual full spectral fingerprint — frequency, duration, and spectral purity — pulled straight from the recorded audio stream, not just the live narrowband check. A same-instant hit on the confuser channel — the signature of a cough or a slammed door, not a pure tone — is rejected outright. Every result feeds a growing, automatically-labeled corpus of confirmed chirps versus confirmed noise that the system uses to retune its own thresholds instead of requiring another manual bench session.

Superhearing mode

When one node picks up a candidate chirp, it immediately broadcasts a prime signal to its partner via ESP-NOW. That node drops into high-sensitivity mode — tightened filter, lower detection threshold — ready for the next event. Low-battery chirps repeat on a fixed interval (typically every 30–60 seconds) and never stop, so the system learns exactly when to expect the next one, and confidence compounds with every confirmed pass.

Cheap expansion: more telemetry

Each node already has power, ESP-NOW connectivity, and a microphone doing double duty as an ambient-noise sensor. Motion (a $1–2 PIR add-on), temperature/humidity (a few-dollar I2C sensor), and ambient noise-level trending (the data's already flowing, it just isn't logged yet) are all telemetry the existing hardware could carry for next to nothing — worth designing in before the next hardware revision, even if chirp detection stays the primary job.

Field results

Deployed at real hallway distance (10–14 m node spacing, self-measured via the ranging system above) with 81 confirmed alarms fired live during testing and development. An initial bench test (37 chirp events, controlled conditions) measured ±2.5 ft positioning accuracy; ongoing field work is refining that further, including a from-scratch waveform cross-correlation mode (in development) that resolves timing directly from the recorded chirp shape instead of a simple threshold crossing. The noise-rejection corpus is already earning its keep — 1,500+ auto-labeled triggers in, it's shown that quiet-room calibration doesn't fully hold in a live, noisy hallway: real chirps are measuring lower spectral purity and longer duration under HVAC noise than the original bench numbers, which is exactly the kind of drift the corpus exists to catch and correct. Development paused 2026-07-16 to focus elsewhere; picking back up now means re-verifying the physical boards before trusting any of the above as current state — last known, both nodes were intentionally running a stripped diagnostic firmware build rather than production.

Two tracks, in parallel

The pipeline described above — networking, detection, pairing, ranging, OTA — works end-to-end on the bench. A second track, chirp_detect_lab, is a from-scratch offline rebuild of just the detection algorithm, started after the production firmware's tuning constants were found drifting undocumented across commits, with no clean way to test whether the algorithm itself actually recognizes a chirp in isolation. It scored four candidate detectors against a real recorded corpus and found recall low across all four (19–31%) — the working theory is corpus quality (no real physical detector recording yet, only speaker playback standing in for one), not a broken algorithm, but that's still unconfirmed.

The full re-entry checklist and open-issue tracking for picking this back up live on the resume board rather than here.

hardwareHeltec ESP32 · INMP441 I2S · 3-board arch
methodTDOA · ESP-NOW RF marker · µs timestamps
detectionGoertzel narrowband · adaptive EMA floor · empirical 12x threshold
rejectioncross-channel confuser check · auto-labeled spectral corpus
rangingself-calibrating · acoustic two-shot · auto-recal every 6h
accuracy±2.5 ft bench baseline · field-refinement in progress
statuspaused 2026-07-16 → resuming 2026-09-05
expansionmotion · temp/humidity · ambient noise — near-zero cost, planned
serverself-hosted · live dashboard · OTA
→ open the resume board → read the ChirpLocator overview
ESP32 INMP441 I2S ESP-NOW TDOA Signal Processing Goertzel FFT NumPy C++ Python OTA
● Active
rf · sdr · anomaly-hunting · self-hosted · privacy-aware
RF Hunter
An RTL-SDR dongle on a dedicated Raspberry Pi 3 — physically relocated to a quieter RF site in 2026-08, reachable only over Tailscale — continuously sweeps 24 MHz–1.7 GHz in 50 kHz bins, comparing each pass against a rolling per-hour statistical baseline. Anything that deviates enough triggers a raw IQ capture and a decode attempt against known protocols — rtl_433 for ISM-band devices, multimon-ng for pagers, rtl_adsb for aircraft transponders, redsea for FM RDS station call letters and genre. Pager hits are logged as "a transmission occurred" only — the real decoded message, third-party content picked up passively off the air, never leaves the acquisition side. Where a decoder resolves real content, the dashboard now shows it directly: rtl_433 temperature, humidity and soil-moisture readings, and TPMS tire pressure — deliberately pressure only, never the per-tire ID a passing car's own sensor broadcasts, since unlike Ray's own stationary sensors that's a persistent identifier for someone else's vehicle. rtl_adsb gained a from-scratch Mode S decoder (callsign, altitude, speed, heading, vertical rate) with real CRC-24 validation — the raw demodulator does no error-checking of its own and will happily emit noise shaped like a valid frame — plus a dedicated periodic listen at 1090 MHz, independent of the anomaly detector, which structurally can't catch a transponder burst that short — after zero genuine catches in over three weeks on the old sweep-triggered path, the very first listen under the new one caught a real aircraft. Because pure baseline deviation can never notice something that's been broadcasting the whole time, a one-time startup census and a daily recheck separately catalog everything continuously on-air, flag anything that's since gone quiet, and flag anything unusual enough to be worth a second look — right now that includes a strong signal sitting inside the protected radio-astronomy band. Identification runs on a separate server, not the field Pi — real decoder evidence first, then a lookup against 11M+ FCC license records for this region, then a static band-allocation table, then previously-identified signal fingerprints — falling through to a capped, text-only Claude guess only when nothing else resolves it. That server is the only thing with API keys or internet access of its own; the acquisition Pi can only ever push captures to it over one restricted upload channel, nothing more. A frequency×day activity heatmap tracks what this specific antenna and placement actually pick up, building up on its own as the sweep keeps running, and the dashboard's cluster list filters by content type — radio, aircraft, TPMS, sensors, licensed, or still-unidentified — with search and sort, instead of one long scroll.
hardwareRTL-SDR · RTL2838 · R820T tuner · Raspberry Pi 3
sweep24MHz–1.7GHz · rtl_power · 180s cycle
detectz-score vs. rolling per-hour baseline
decodertl_433 · multimon-ng · rtl_adsb · redsea
telemetrytemperature · humidity · soil moisture · TPMS pressure (no vehicle id)
aircraftMode S/ADS-B decode, CRC-24 validated · periodic 1090MHz listen
catalogstartup + daily census · gone-quiet + worth-a-look tracking
identifydecoder evidence → FCC license lookup → band table → fingerprint → Claude (capped)
serverCT 100 (Tailscale-linked) · Python · SQLite
signal clusters
spectrum history
worth a look
last new signal
→ open live dashboard → read the RF Hunter overview
RTL-SDR Python rtl_433 redsea NumPy SQLite Tailscale Claude
● Active
security · scan-traffic · self-hosted
Who's Knocking
Every public IP on the internet gets scanned constantly — WordPress exploit probes, leaked .env/.git credential hunts, router-botnet RCE checks, none of it targeted, all of it automated. This server was already classifying each request's source IP as residential vs. datacenter for its own logs; this panel makes that visible, names the ~30 specific exploit/scanner signatures being thrown at it, and tracks who's hosting the traffic — instead of letting it rot in a log file that rotates out after a few days.
classificationipinfo.io org lookup · cached per /24
signatures~30 named exploit/scanner patterns, live leaderboard
networkstop hosting ASNs via MaxMind GeoLite2
serverCT 100 · Python · SQLite
requests (24h)
spoofed crawlers caught
top attack signature
last knock
→ open live dashboard → read the Who's Knocking overview
Python SQLite ipinfo.io MaxMind GeoLite2-ASN
● Active
homelab
Beelink Proxmox Node
The hardware everything runs on. A Beelink Mini PC running Proxmox VE — webserver, Pi-hole, and Home Assistant all live here. No cloud, no rent, no monthly bill.
hostBeelink Mini PC
hypervisorProxmox VE
containersCT 100 webserver · CT 101 Pi-hole
vmVM 102 Home Assistant
egressCloudflare Tunnel · no open ports
Proxmox VE LXC Debian 13
◌ In Progress
home automation
Smart Home Stack
Home Assistant is up and running — locally hosted, no cloud account, no subscription. The foundation is solid. Zigbee, MQTT, and automations are next; this is the part of the stack that's actively being built out rather than just maintained.
platformHome Assistant OS · VM 102
hostinglocal-only · no cloud account
nextZigbee · MQTT · automations
Home Assistant HAOS Pi-hole local-first
● Active
networking
Pi-hole DNS
Network-wide ad blocking and DNS filtering for the whole home — LAN and IoT. The OpenWrt router pushes Pi-hole as the DNS server to every device on the network. 92,000+ domains blocked, no per-device configuration needed.
versionPi-hole v6
hostLXC CT 101 · Proxmox
scopeLAN + IoT · network-wide
domains blocked92,000+
routerOpenWrt · DHCP pushes Pi-hole
Pi-hole v6 LXC DNS OpenWrt
● Active
self-hosted · web
RepairmanRay.com
A personal site served from a home server over a Cloudflare Tunnel — no hosting provider, no managed platform. The terminal aesthetic fits the stack: plain HTML/CSS/JS, a Python HTTP server, and a self-hosted pipeline that gets the job done without a cloud bill.
serverCT 100 · Python HTTP
tunnelCloudflare · no open ports
stackHTML · CSS · JS
hosting cost$0
HTML CSS JS Python Cloudflare Tunnel
◌ In Progress
electronics · LoRa
LoRa Alarm Mesh
A LoRa mesh network for monitoring doors and passageways across an apartment complex — magnetic switches, PIR motion detectors, and temperature sensors feeding back through a network of nodes and repeaters. Alert outputs via piezo buzzers. No WiFi, no cloud, no subscriptions — the mesh handles its own routing within radio range. Off-grid capable by design.
mcuHeltec ESP32 LoRa V3
radioLoRa 915MHz · mesh
sensorsreed switches · PIR · temperature
alertspiezo · local, no cloud
poweroff-grid capable
ESP32 LoRa Reed Switches PIR C++
◑ Prototype
electronics
Outdoor Firepit Weather Interlock Controller
A WiFi-connected relay controller built on an ESP32. Fetches live wind speed and temperature from OpenWeatherMap, enforces user-defined operating hours via NTP scheduling, and controls a relay with fail-safe logic — if WiFi drops, data goes stale, or conditions exceed limits, the relay locks out. Configured through a built-in web dashboard with auto-refresh. Settings persist across reboots via ESP32 NVS. Field deployment would require hardened relay switching and proper web authentication.
mcuESP32-WROOM-32
weather apiOpenWeatherMap · wind + temp
schedulingNTP · user-defined hours
fail-saferelay locks on WiFi loss / stale data
configbuilt-in web dashboard · NVS
ESP32 Arduino OpenWeatherMap Relay
◇ Concept
smartthings · iot
AC Freeze Monitor
Set Point 72°F
Current 79°F
Runtime 47min

$Monitors HVAC units via SmartThings API and personal access tokens. If a unit runs too long without the room temperature meaningfully dropping toward the set point, a fault is raised — the classic signature of a frozen evaporator coil killing airflow while the compressor keeps grinding.

// known constraints

Samsung controls the token lifecycle, and it's gotten stricter: personal access tokens issued after December 2024 now expire in 24 hours, so anything meant to run unattended needs a full OAuth2.0 flow instead of a PAT. Starting October 2026, Samsung is also ending free API access — non-commercial developers get a grace period through Q3, then a $4.99/month "Personal Plan" becomes the price of admission, a change big enough that even Home Assistant is scrambling to figure out how it affects their SmartThings integration. On top of that, there's still no true polling model: sensor data lives behind Samsung's cloud, so you're dependent on their infrastructure and now their billing. A SmartThings outage — or an unpaid invoice — is silently also your monitoring outage. You're always a guest in their ecosystem, and soon a paying one.

apiSmartThings · personal access tokens
detectionruntime vs. temp delta toward setpoint
token lifespan24h (PAT) · OAuth2.0 for production
api costfree through Q3 2026 → $4.99/mo (Oct 2026)
languagePython
Python SmartThings API HVAC IoT
◇ Concept
electronics · power quality
Utility Voltage Monitor
A mains voltage monitor built around the ZMPT101B sensor and an ADS1115 16-bit ADC feeding an ESP32. Samples the 60Hz waveform at 860 SPS, computes true RMS, and raises alerts on sags below 105V or overvoltage above 126V. Events publish to MQTT — timestamps, duration, and min/max voltage — and feed into Home Assistant. Designed to catch the kind of slow sags that don't trip breakers but do kill compressors.
sensorZMPT101B (isolated)
adcADS1115 · 16-bit · I²C
mcuESP32-WROOM-32
sag threshold< 105V RMS
overvoltage threshold> 126V RMS
reportingMQTT → Home Assistant
ESP32 ZMPT101B ADS1115 MQTT true-RMS C++

Contact

Got a project, a question, or something broken that needs a second opinion? Send a packet my way.