Boba Rhythm
An IoT-connected device that tracks a domestic cat's door-crossing behavior over time. Built in a tangible design class centered on physical computing, the project pairs custom Arduino-style hardware with cloud data logging to ask a simple question: does a house cat have a schedule, or do patterns emerge from his behavior over time?
Role
Hardware & Firmware / Concept
Discipline
Tangible Design / Physical Computing
Stack
ESP32 Feather, HC-SR04, Adafruit IO
Concept
Design an internet-connected object that observes behavior in an environment over time.
The concept landed on tracking a cat named Boba as he uses a sliding glass back door. The guiding question became: does Boba have a defined schedule, or do patterns emerge from his behavior over time?
The framing draws on real animal behavior research showing that even simple animals follow surprisingly consistent rhythms, and asks whether the same might be true of a house cat's daily routine.
Hardware
The device uses an Adafruit HUZZAH32 ESP32 Feather microcontroller with two Elegoo HC-SR04 ultrasonic distance sensors mounted at different heights on the back door frame.
- The low sensorsits 4–6 inches off the ground to detect cat-height crossings.
- The high sensor sits around 14 inches to filter out the dog (an Australian Shepherd) and humans.
- Power comes from a USB wall adapter for continuous 24/7 operation.
- Data transmits to Adafruit IO over WiFi.


High sensor & ESP32 Feather

Low sensor
Sensor Calibration
Getting reliable detection required several rounds of calibration.
Problem 1 — False triggers in an empty doorway
The device fired every 15–30 seconds with nothing in the doorway. The initial trigger threshold was set to 75% of an assumed 80cm door width, which turned out to be wider than the actual opening. The real doorway measured about 61cm, and the empty doorway consistently read around 75cm. Setting a fixed trigger threshold of 50cm eliminated the false triggers entirely.
Problem 2 — Missing humans on the high sensor
The high sensor only caught humans about 50% of the time. The initial approach sampled both sensors simultaneously once before classifying—not enough, because a person moving through the doorway might not hit the high beam at the exact moment the code sampled it.
The first fix sampled both sensors twice, 300ms apart. This improved accuracy but was still inconsistent on faster crossings.
The final fix was a 1 second polling window. When the low sensor triggers, the code polls the high sensor every 100ms for a full second before classifying. That gives the high sensor 10 chances to detect a human or dog during the crossing. If it fires at any point, the event is ignored; if it never fires, the crossing is logged as a cat. This worked reliably across all test subjects.
Problem 3 — Spurious low-sensor spikes
Occasional false triggers appeared on the low sensor despite the empty doorway reading well above the threshold. This was solved by requiring two consecutive low-sensor readings below the threshold, 80ms apart, before registering a crossing. A single spurious spike is ignored, while a real crossing holds the reading across both checks.
Classification Logic
Low sensor only
If only the low sensor fires, it is logged as a cat crossing.
High sensor fires
If the high sensor fires at any point during the 1 second window following a low trigger, the event is ignored as a dog or human crossing.
The high sensor never publishes to Adafruit IO—it only acts as a local filter on the chip.
Pin Assignments
During wiring it was discovered that GPIO 13 on the HUZZAH32 is the onboard LED and should not be used for sensor TRIG. Final assignments are GPIO 32 for TRIG and GPIO 33 for ECHO on both sensors.
The A0 label on the board corresponds to GPIO 26, which caused some confusion when the code referenced GPIO numbers that did not visibly appear on the board.
Adafruit IO Setup
Three feeds were created inside a group called cat-door: cat-crossings, cat-count, and high-trigger. The high-trigger feed was used during the two-board phase and removed once the single-board setup made it redundant.
The two active feeds are cat-crossings, which logs a timestamped 1 for every confirmed crossing, and cat-count, a running daily total that resets every 24 hours.
Data
Four days of data have been collected. June 1st is partial due to setup issues, with data starting at 3pm. June 2nd is the most complete day with 19 logged events. June 3rd has 13 crossings with a board restart around noon, and June 8th adds a fourth full day of activity.
Early pattern analysis shows heavy afternoon activity clustering across every day, a consistent midday cluster around 12:30–1pm, a quieter stretch in the early afternoon, and activity trailing off toward the end of the allowed window. Morning crossings stay sparse throughout.

Crossings over four days
Each dot is a confirmed cat crossing plotted by time of day. Hover any dot to see the exact timestamp. The data was difficult to record consistently—not being able to be home 24/7, combined with errors occurring throughout the week, rendered some days a total loss of data.
* June 1 data starts at 3pm due to setup issues. June 3 board restarted around noon.
Reflection
Boba is not random. There is a shape to his day, and it shows up whether the door opens at 9am or later.
Across four days of data a consistent pattern emerged. Crossings cluster heavily around midday, typically between 12:30pm and 1pm, with a secondary wave of activity in the mid to late afternoon. Morning crossings are sparse and evening crossings taper off toward the end of the allowed window. The shape is remarkably similar day to day — suggesting Boba does have a rhythm, and it is his own.
The most telling day was June 3rd. Boba was let out at 10am with no one home until around 3:30pm. Activity was noticeably lighter through the morning and early afternoon compared to other days, picking up once someone returned. It is a single observation and not enough to draw firm conclusions, but it raises a question worth exploring in a longer deployment — whether Boba's crossings are driven purely by his own internal clock, or whether human presence plays a role too.
What stands out most is how closely the days rhyme with one another. Plotted against time of day, each day's line traces a strikingly similar shape—a quiet morning, a sharp climb into the midday cluster, a brief dip, and a second afternoon swell before tapering off. The peaks and valleys land in nearly the same places regardless of the exact day, which is the clearest signal that Boba is following an internal routine rather than reacting to one-off events.
The data does not answer the guiding question definitively. But it suggests there is a structure to his day. That alone is worth something.
Future Improvements
Thermal camera
A summer version could upgrade to an MLX90640 thermal camera ($20–$30), giving a 32×24 thermal image of each crossing—enough to see a cat-shaped heat blob versus a human or dog. This would replace the height-threshold classification entirely with shape-based detection.
Real-time clock
A real-time clock module would improve the daily reset accuracy so it happens at actual midnight rather than after 24 hours of uptime.