New Project: Clockd

Available today; Clockd. It’s an HTTP API that estimates vehicle speeds from video and the source is up now on GitHub.

The motivation is a street near my home with a speeding problem. The city can act on data. Anecdotes… not so much. The data cities usually buy comes from radar studies that are expensive and run rarely, but there were already cameras with a view of the street and the speeds are sitting right there in the video.

Clockd pulls them out. Give it a clip, or let it watch your NVR and process vehicle events on its own. Event sources are modular; UniFi Protect support ships today, and adding another NVR or camera system means implementing one small polling class. It detects vehicles in each frame, tracks them across the clip, projects pixel positions onto real-world road coordinates using a per-camera calibration, and computes speed from displacement over time. Results come back as JSON, and per-vehicle metrics can go straight to InfluxDB so Grafana can draw the charts a traffic engineer will actually read.

Key features:

  • Modular NVR event sources (UniFi Protect included)
  • Per-camera perspective calibration
  • Sync and async processing
  • Multiple detection backends
  • Automatic local CPU fallback
  • InfluxDB and Prometheus metrics
  • Speed range and track quality filtering
  • Config via file or environment variables
  • Kubernetes-ready deployment

Detection runs where you want it. Local CPU inference works out of the box, and it can also call a Roboflow Inference server on a GPU, CodeProject.AI, LocalAI, or a Google Coral TPU through coralapi, which I also published this week. If a remote backend goes down, Clockd falls back to local CPU inference instead of dropping data, and every result records which backend produced it.

One lesson from running it: calibration matters more than model choice. A nano model with accurate source points beats a large model with sloppy ones; the README covers this in detail.

Clockd produces estimates and a calibrated camera is no radar gun. It doesn’t need to be. A few hundred vehicles a day with an 85th percentile of 12 over the limit is a strong argument at a council meeting.

On privacy: Clockd tracks bounding boxes. It does not read plates and it does not identify anyone. Clips are deleted after processing and what remains is anonymous speed statistics.

Under the hood it’s Python, FastAPI, Ultralytics YOLO, and ByteTrack, deployable as a container, and the repo includes a hardened Kubernetes manifest. My instance processes a few hundred clips a day from one camera and the dashboard already tells a clear story.

If you have a camera pointed at a road, give it a try; the README will get you from clip to speed report in an afternoon. If your NVR isn’t supported yet, the event source interface is small and PRs are welcome. Constructive feedback too.

-Nathan

New Project: CoralAPI

Available now; CoralAPI. Point it at a Google Coral Edge TPU, POST an image, get JSON back.

Coral’s little accelerators are great hardware. Real object detection on a few watts, on a Raspberry Pi or a mini PC, no GPU and no cloud bill. The software stack around them has aged badly, though. The official Python library, pycoral, is stuck on Python 3.9. The projects that put a Coral behind an API, mostly CodeProject.AI’s Coral path, are heavy and half-maintained… when they run at all.

I built CoralAPI because nothing out there was current. Getting a newer model running, a recent YOLO export for example, meant fighting the toolchain or forking someone’s stale wrapper, and in a few cases standing up the existing options was more work than writing a clean one. So I wrote the clean one.

CoralAPI is a small FastAPI service. It runs on current Python and ships a matched libedgetpu and tflite runtime, built on feranick’s community packages, that actually work together; getting that pairing right is harder than it has any right to be. There are build profiles for modern CPUs, older no-AVX2 boxes, and the Raspberry Pi. Models download on demand. What it does:

  • Classification
  • Object detection (SSD and YOLO)
  • Semantic segmentation
  • Pose estimation
  • Image embeddings
  • Raw tensor output for anything it doesn’t recognize

No CPU fallback; if there’s no Coral attached it exits at startup and tells you why. That’s on purpose. A running instance always means real acceleration.

Put a Coral behind a URL and get on with your day. MIT licensed. PRs and feedback welcome.

-Nathan

New Project: CoI

I’ve posted the code for a project that I’ve been thinking about for a while; CoI.

This project is, at this point, a draft or an early work in progress but I wanted to get it actually started and work on some code; something I haven’t done enough of lately.

The goal with CoI is to have a single place to record and track incident post-mortems. I’ve worked quite a few places and most had terrible post-mortem practices that left things unresolved, untracked, and unfixed and it’s driven me crazy.

If you know that something can cause a production outage because it has and you’ve identified the fix should you really accept that being thrown into a team’s backlog and just.. left there? It’s not a new and exciting feature. It’s not something that is going to move the needle for customer adoption. It’s probably just not all that interesting. That fix can go ignored by the engineering team and project managers for months and while it waits to be addressed your site is still vulnerable.

The intent with CoI is to surface those action items and clear ownership over the original incident and who needs to do the work identified to prevent it from happening again. While there are solutions that people have come up with to do this using other issue tracking systems I’ve seen those attempts fail.

In any case; the draft is up and I plan on working on it occasionally to build it into something more ready to use.

-Nathan

Project release: AWS Okta Keyman

Available today; AWS Okta Keyman. This package is a fork of previous work by Nextdoor, Inc. that adds Duo Auth support and has other features already on the roadmap.

This package allows the user, who uses Okta with AWS today, to authenticate with Okta, use that to authenticate to AWS, and then pulls down temporary credentials (access key and secret key) for interacting with the AWS APIs. This allows for users to have access to AWS APIs without long-lived API keys stored on their dev systems. This helps protect the AWS resources as the keys are only valid for at most an hour so an unintended disclosure or leak has a very short window of risk before the keys become invalid. It also helps by enforcing the idea of continually rotating keys; not so different from what the on-box EC2 experience is like when using IAM Roles for EC2.

If you are using Okta to log in to AWS give it a try today; pip install aws-okta-keyman

The source is available under the Apache 2.0 license.

For more information: https://github.com/nathan-v/aws_okta_keyman

Project release: resque-state gem

I’m posting this late as the code has been available for a bit now but I’ve published my first Ruby Gem (fork) on Github; resque-state. It adds more features to the original gem (resque-status) including more interactive-like controls to allow you to run semi-interactive jobs via Resque. The biggest addition was adding pause and revert functionality.

This project came from something I built (and hope to eventually publish) that runs automated rolling deployments to AWS. What the pause functionality gave me was the ability to let a user do a one-box or canary ahead of a full roll as well as the ability to pause a job that might be having troubles. This lets an engineer launch a deployment to an Auto Scaling Group (ASG) and initially add just a single machine. Once that instance is healthy the job then pauses and waits for the engineer to give the deployment the green light to continue. The pause/unpause functionality became one of the critical features to enable safer production releases.

Just added was a revert feature. You could accomplish something similar with on_failure but I thought that might be overloading that functionality a bit. I believe these are two different cases. If a job fails you may not want to undo it because the failure may have been fatal for the job process but not something that actually needs reverted. Maybe there was a network blip the automation didn’t handle well or perhaps you’re able to course-correct without actually pulling back what was done. Revert gives you a separate path for cases where you specifically want to pull back what was done. This can be done from the paused state (for example; a deployment one-box that is no good) as well as just while the job is running.

PRs and constructive feedback are welcome. 🙂

Consistency matters; even when you disagree

No matter where you fit into any of the great developer debates (vim vs Emacs, tabs vs spaces, 80 vs 120 vs no column limit) the most critical point is consistency. Switching between tabs and spaces inside your own project would certainly prove annoying for others should you share the code even it won’t affect function. When you’re working on a team, though, or as part of a large organization; consistency has to exist not just in your project but across many.

Maybe you’re a tab person. Cool. Go nuts; at home. If your company prefers spaces the reality is that your preference doesn’t matter. Conforming to a shared norm is more important. When you have to share code with others the bottom line is that the consistency is bigger than your preference. This can even escape your own company should you end up open-sourcing your work for others to benefit from.

This is why I prefer to lean on community-driven style guides. I may not agree that Ruby should be written with an 80 character line limit but the community-driven Ruby Style Guide says otherwise and Rubocop defaults to that as well. Given that; it then makes sense that in any project that I plan on making public I should follow these norms as much as possible.

When it comes to Python we have PEP. The old Sun Java guide works but there’s a newer offering from Google that could be used. Older languages aren’t left out; even Perl has guidelines.

It’s hard to get consensus when opinions are strong and nobody’s preference is really wrong (unless they prefer tabs- then they’re wrong). Rather than infighting and company-specific styles that lead to Python that looks like Java and Perl that looks like, well, chaos we should be able to agree to disagree and stick to accepted solutions. I’m going to link a few below. Mostly these are the top or near-top hits on Google if you look for style guides for these languages. Google is the source of some but as the massive engineering powerhouse they are that makes sense.

Decide what to use, commit to move forward with it, and stop wasting time arguing over the right column to end the line at.


Ruby: https://github.com/bbatsov/ruby-style-guide
Python: https://www.python.org/dev/peps/
Java: https://google.github.io/styleguide/javaguide.html
Scala: http://docs.scala-lang.org/style/
Golang: https://github.com/golang/go/wiki/CodeReviewComments
Perl: http://perldoc.perl.org/perlstyle.html
Shell: https://google.github.io/styleguide/shell.xml
R: https://google.github.io/styleguide/Rguide.xml
Haskell: https://wiki.haskell.org/Programming_guidelines
Javascript: https://github.com/airbnb/javascript
C#: https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx