helix-2.com

I write software for a dispatch desk, a family and a homelab.

I'm John. I work on a dispatch communications desk and I've been programming since a copy of Borland Turbo C for DOS. C# is the language I keep coming back to. At home I run a homelab on Proxmox and build embedded projects.

How it started

EducationBachelor of Science in Information Systems, summa cum laude. The City University of New York.

  1. 1 CommsHub The operations platform a dispatch desk runs on
  2. 2 LM Dashboard Start page and uptime monitor for a home network
  3. 3 FamilyMatters Calendar, chores and rewards for one family
  4. 4 CaddyMonWeb Live view of the traffic hitting every site on my server
  5. 5 CaddyMon The same view, in a terminal
  6. 6 Page String Watcher Edge extension that watches open tabs for words you pick

CommsHub

The operations platform a busy transport dispatch desk runs on. It replaced spreadsheets, email threads and paper forms, and when one person saves a change, everyone else on the desk sees it straight away.

Type
Operations platform
Status
In daily use since Feb 2025
Built with
C# and Blazor Server
Fleet page filtered to the vehicles overdue or coming due for inspection, with counts of out-of-service vehicles and radios.
Fleet. Example data only.
  1. Counts of vehicles out of service, overdue and coming due.
  2. A note says what the list is filtered to, with a link to show all vehicles.
  3. Each vehicle's next inspection, PM and registration, in orange when due and red when late.
  4. Each vehicle's status. Taking one out of service needs a reason.
  • Transport referrals sorted by time left, each with a follow-up thread and a quick-reply generator. Admins edit its vendors and templates in the app itself.
  • Builds the daily crew rundown from the scheduling system's CSV export. A rundown is a safety document, so it only places a crew member on a unit when the match is exact.
  • Tracks vehicles, radios and inspections, with a full history. Taking anything out of service needs a reason, and a weekly email lists what's overdue.
  • Announcements with a roster of who has read them. Urgent ones also post to the Dispatch chat and flag the browser tab.
  • A shared Notes board for pass-down, redeployments and reminders. Only the person who posted a note can change it. A note with a time counts down for everyone, turning amber 15 minutes before and red once it's due.
  • QA/QI requests that only the person who filed them and supervisors can see. The server checks that on every read and write, badge counts included.
  • Several hundred unit tests and a browser test suite run on every change.
CommsHub on a phone: the home screen with an announcement banner and the attention list.
The home screen on a phone.

NoteScreenshots show example data only: made-up names, units, hospitals and messages.

LM Dashboard

A start page and uptime monitor for the services on a home network, styled after old line-mode terminals. Each link is checked on its own schedule, and the page updates as the results come in.

Type
Uptime monitor
Runs
Self-hosted
LM Dashboard in its dark theme, listing home-lab services with their status, response time and a bar graph of recent checks. Two services show failed checks in red.
Dark theme
  1. Failing links sort to the top, with how long each has been down.
  2. A graph of the last 20 checks.
  3. The status code and response time. A 301 or 302 shows as a redirect.
  4. Failing only cuts the list to what needs attention.
  • Each link has its own check interval, down to one second. A row shows the status code, the response time and a graph of the last 20 checks. Failing links sort to the top with how long they've been down, and Failing only cuts the list to what needs attention.
  • Redirects aren't followed, so a 301 or 302 shows as a redirect, not as the status of the page behind it. Internal links accept self-signed certificates; external links get full validation, so an expired certificate counts as a failure.
  • Checks can land several times a second. The page batches them into one refresh every 250 ms, and each row carries a version number so Blazor re-renders only the rows that changed.
  • It only answers requests addressed to host names and networks on an allowlist, which stops other websites from reaching it through DNS rebinding.
  • Dark and light themes, plus a green-phosphor Classic theme with optional scanlines, a vignette and a brightness slider.
LM Dashboard on a phone, with the search prompt and Add link on one line and the filters below. Each link takes two lines, with its status code and response time under the name and its actions behind a menu button.
On a phone, each link takes two lines, with its actions behind a menu button.

FamilyMatters

A shared home base for one family: calendar, to-dos, shopping lists, notes and announcements, plus chores that earn points the kids spend in a rewards store.

Type
Household app
Runs
Self-hosted
For
One family
FamilyMatters home for a parent: the day's name as a heading, the family's weekly goal, chores and a reward request waiting for approval, today's schedule and the announcements board.
Parent home
  1. Chores waiting for a parent's approval before any points are paid.
  2. Approve each finished chore, or send it back with a reason.
  3. Today's schedule, with who each event is for.
  4. The family announcements board, pinned notes first.
  • Chores go to a parent for approval before any points are paid. Repeating chores can rotate between the kids, or be left up for grabs for whoever does them first.
  • Kids can save toward a reward and suggest new ones. The family shares one weekly goal, and nobody is ranked against anyone else.
  • A daily digest email, plus a weekly recap sent on Sunday evening. Outside calendars, such as school and sports teams, come in by subscription.
  • Parents and admins sign in with an authenticator app. The app is on the public internet, so it enforces its own rate limits, security headers and session checks.
  • Light and dark themes, and a bottom tab bar on a phone.
FamilyMatters on a phone: a child's home screen with their points, saving goal, the family's weekly goal and today's chores.
A child's home screen on a phone.

NoteScreenshots show example data only: a made-up family and its events.

CaddyMonWeb

A live view of the traffic hitting every site on my server, in the browser. It's the web version of CaddyMon, so I can check on things from my phone.

Type
Server monitoring
Runs
Self-hosted, private
See also
CaddyMon
CaddyMonWeb dashboard for the last 24 hours: request totals, seven flagged scanners, a stacked chart of requests by status class, the client IP table and the newest requests.
Dashboard
  1. Requests per half hour over the last day, by status class.
  2. Flagged scanners: addresses that got client errors and never a successful response.
  3. Requests grouped by client IP, with who owns each address.
  4. The newest requests, as they're written to the log.
  • It follows each site's Caddy access log as it's written, groups requests by client IP, shows who owns each address and flags the bots probing for /.env and wp-login.php.
  • No database: the logs are the record. At startup it reads back a week of each log, including Caddy's rotated and gzipped copies, then picks up the live file exactly where that left off, so nothing is counted twice or missed.
  • Switching between 15 minutes, an hour, a day and a week is instant. Each window keeps running totals that add a request when it arrives and subtract it when it ages out, and memory use has a fixed cap.
  • An IP gets a scanner badge when it collects client errors and no successful responses, or probes several sites. Known addresses, like my own networks, are shown by name and never flagged.
  • Owners come from the regional internet registries. Lookups only run for the rows on screen and stay within each registry's published rate limits. Only the address ranges are cached, never visitors' IPs.
  • It's private: only reachable from approved networks, behind its own sign-in with an optional authenticator code, and a strict content security policy with no inline scripts or styles.
  • Settings are edited as a draft, checked as you type, and the page says which changes mean reading the logs again. Light and dark themes, and it works on a phone.
CaddyMonWeb on a phone: the time-window and status filters, request totals, flagged scanners and a 24-hour chart above the client IP list.
On a phone, for checking in from anywhere.

NoteScreenshots show generated traffic: documentation IP ranges and made-up requests.

Smaller projects

CaddyMon

A live, htop-style view of a Caddy web server's access log, in the terminal.

Type
Command-line tool
CaddyMon terminal view listing client IPs with request counts by status class and owner names, above a list of recent requests from one IP.
Split view

It groups requests by client IP, shows who owns each address and flags likely scanners, so one bot probing for /.env doesn't bury everything else. CaddyMonWeb is the web version of it.

NoteExample data only: documentation IP ranges and made-up owners.

Page String Watcher

A free Edge extension that watches the tabs you already have open for words you pick, like "Available" on a sold-out ticket page.

Type
Browser extension
A made-up ticket listing where Page String Watcher has found "Available". Its banner runs across the top of the page, and the word is highlighted in the Saturday row.
Match found

It checks again every time the page changes, so it also catches web apps that update without reloading. When a word turns up, you get a desktop notification, a banner on the page, a flashing tab title and a highlight on the match. It makes no network requests of its own.

NoteExample data only: a made-up venue on example.com.

The homelab

I write the apps above at home, on a Windows 11 virtual machine on my Proxmox server, and a Linux Mint one covers development on the Linux side. The same machine runs Pi-hole for the home network and a Docker host.

The Proxmox server

Hypervisor
Proxmox VE 9
CPU
Intel Core i7-11700, 8 cores
Memory
64 GB
Storage
1.5 TB of NVMe
Backups
Manual, to the NAS
What runs on it
GuestKindSizeWhat it's for
DNS Container 2 cores, 2 GB Pi-hole, answering DNS for the home network.
Docker Ubuntu VM 4 cores, 8 GB BookStack, Gotify, Plex and LM Dashboard, managed with Portainer.
Windows 11 VM 8 cores, 16 GB Where I write code, in Visual Studio.
Linux desktop Linux Mint VM 4 cores, 16 GB Development on Linux, with Visual Studio Code and GCC.

The NAS

It holds the Proxmox backups and the media Plex serves, and it syncs with OneDrive, so I keep a local copy of everything I store there.

Model
Synology DS920+
CPU
Intel Celeron J4125, 4 cores
Memory
4 GB
Drives
Four 1 TB, RAID 5
Runs
DSM 7

Embedded projects

Low-power environmental sensor board

A battery-powered indoor monitor with an e-paper display, built to replace a desk unit that stopped working. It reads temperature, humidity, air quality and barometric pressure, and runs on two AA cells. The boards worked first time, and asleep it drew about 57 µA before the firmware was finished.

MCU
STM32L431
Sensors
SHT45, SGP41, BMP390
Power
Two AA cells, TPS613221A boost
Write-up
Hackaday.io

3.3 V boost converter with a button latch

A power circuit for a larger project. It boosts one or two AA cells to 3.3 V, and a push button turns it on and off through a D flip-flop, so the microcontroller it powers can also switch itself off. With the output off, it draws about 0.64 µA.

Converter
TPS610994
Latch
D flip-flop
Off current
0.64 µA
Write-up
Hackaday.io

How it started

I've worked on a dispatch communications desk for a number of years. When I started, a lot of the work ran on information copied by hand from one place to another, things passed along by word of mouth, and long email chains that held the latest version of a procedure. There was plenty to automate.

The first thing I took on was a report we sent to a third party every day. Someone typed it up by hand, which took 45 minutes to an hour depending on how often the phones interrupted. Now a program downloads the CSV, parses it and produces the PDFs in two or three minutes.

Transport referrals came next. Six or seven of us kept them in one shared Excel sheet and edited it all day, and mistakes crept in. I replaced it with a small WPF app backed by a SQL database, and later folded both tools into one Blazor Server app. A lot has gone into it since: full fleet management, QA/QI requests for the whole department or for one person, a department-wide chat, and more. That's CommsHub, and the desk has used it every day since February 2025.

I've been programming since I bought a copy of Borland Turbo C for DOS. I've written Python, Perl, shell scripts and assembly since, on Windows, FreeBSD and Linux, but C# is the language I kept coming back to. I loved building desktop apps with it in WPF, and when the work moved to the browser I didn't want to give it up. Blazor Server meant I didn't have to.

Say hello.

I'm not taking on new work at the moment, but the form still works. Send a question about one of the tools on this page, or something to talk about later, and I'll reply.

Or email me directly:

hello@helix-2.com

Up to 4,000 characters.

I'll reply from hello@helix-2.com.

I only use these details to reply to you. Your message is emailed to me and saved on this site's server, along with your IP address to help block spam. I don't pass it on or add you to a mailing list. To have it deleted, email hello@helix-2.com.