Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
212f901
docs: design for expanded HomeKit features (doorbell, camera, probes,…
keithah Jul 8, 2026
0d661c1
docs: plain doorbell now + camera later, snapshot vs video clarified
keithah Jul 8, 2026
61ed24d
docs: implementation plan for expanded HomeKit features
keithah Jul 8, 2026
297f3fa
feat: config types and normalization for doorbell, modes, probe sensors
keithah Jul 8, 2026
356fa9f
feat: parse food-probe telemetry and add startMode helper
keithah Jul 8, 2026
f4573af
feat: add doorbell, cook-mode switch, and probe sensor accessories
keithah Jul 8, 2026
09b8b79
feat: config UI for doorbell, probe sensors, and cook-mode switches
keithah Jul 8, 2026
b1c5dc2
docs: document new opt-in features and intentional omissions
keithah Jul 8, 2026
c7405c6
feat: parse 10011 camera frames into latest snapshot URL
keithah Jul 8, 2026
8f08023
feat: interior camera + Video Doorbell (snapshot + ffmpeg live stream)
keithah Jul 8, 2026
45572bb
docs: mark camera feature as built in spec
keithah Jul 8, 2026
16d8606
fix: parse real probe telemetry format (sensor_data.probe array)
keithah Jul 8, 2026
57f6138
chore: 0.1.1-beta.0
keithah Jul 8, 2026
8057515
feat(ui): expose doorbell, camera, probe, and mode-switch settings in…
keithah Jul 8, 2026
3100969
fix(camera): don't advertise audio — video-only feed, fixes stream crash
keithah Jul 9, 2026
25f5aed
feat(camera): live view advances — pipe evolving stills into ffmpeg
keithah Jul 9, 2026
d0add8f
fix(probe): single food probe, not left/right
keithah Jul 9, 2026
706ca52
fix(probe): remove legacy left/right probe services on upgrade
keithah Jul 9, 2026
d7865c9
chore: release 0.2.0-beta
keithah Jul 9, 2026
4012cc3
chore: release 0.2.0-beta.1
keithah Jul 9, 2026
d39f8e3
fix: remove unsupported door-open trigger
keithah Jul 9, 2026
2cbe2f5
docs: align PR2 validation notes
keithah Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ A [Homebridge](https://homebridge.io) plugin that brings [June](https://juneoven
- **Thermostat accessory** (`June` by default) — set a target temperature, read the current cavity temperature, turn off to cancel a cook.
- **Optional preheat switch** (`June Preheat`) — turning it on preheats to your configured default mode/temperature; turning it off cancels.
- **Optional `June Ready` / `June Done` occupancy sensors** — see [Ready and Done sensors](#ready-and-done-sensors) below for what they do and how to hook up notifications.
- **Optional cook doorbell** — a HomeKit Doorbell that rings on the events you choose (cook done and/or preheat-ready), giving you a doorbell-style notification on your phone and Apple TV. Off by default; enable and pick triggers in the Config UI.
- **Optional food-probe temperature sensor** — exposes the oven's food-probe temperature as a HomeKit Temperature Sensor so you can automate on "probe reached 145°F." Off by default.
- **Optional cook-mode switches** — add a switch for any cook mode you like (bake, roast, broil, air fry, toast, or any other mode id the oven accepts), each with its own temperature. Turning one on starts that cook; they're mutually exclusive. None are added unless you configure them.
- **Optional interior camera** — shows the oven's interior camera (a still refreshed ~1×/sec while cooking, which is the oven's native feed). Snapshots work out of the box; tap-to-view live streaming uses system `ffmpeg` if present. Enable the camera *and* the doorbell together to get a **Video Doorbell**, so the "cook done" notification arrives with a photo of your food. Off by default.
- **In-plugin pairing** — pair from the Config UI with an 8-digit code, the same flow the June app uses. No account credentials are ever entered into or stored by the plugin.
- **Editable per-oven settings in the Config UI** — rename accessories, toggle sensors, set default cook mode/temperature (in whichever unit you prefer), and check an oven's live connection status, all without hand-editing `config.json`.
- **Automatic token refresh** and a persistent, signed WebSocket connection to June's messaging service for live status and commands.
- **Multi-oven support.**

## Not exposed (and why)

- **Cook timer** — the oven accepts a set-timer command, but HomeKit has no timer/countdown surface for a thermostat-style accessory, so there's nowhere sensible to put it. Use a Home automation on the Done doorbell/sensor instead.
- **Cook progress %** — HomeKit has no native "percent complete" characteristic, so progress is used internally only (to drive the Ready/Done triggers) rather than shown as its own tile.
- **Continuous/HD video & HKSV recording** — the oven's interior camera is a ~1 fps still feed (that's the hardware's native output, used to build its timelapse); there is no continuous HD video or HomeKit Secure Video recording. The camera feature above turns that still feed into a live view.

## Requirements

- Homebridge `>=1.8.0`
Expand Down
59 changes: 58 additions & 1 deletion config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,53 @@
{ "title": "Celsius", "enum": ["C"] }
]
},
"doorbell": {
"title": "Cook Doorbell",
"type": "object",
"properties": {
"enabled": { "title": "Enable Doorbell", "type": "boolean", "default": false },
"name": { "title": "Doorbell Name", "type": "string", "default": "June Doorbell" },
"triggers": {
"type": "object",
"properties": {
"done": { "title": "Ring when cook is done", "type": "boolean", "default": false },
"ready": { "title": "Ring when preheat/ready", "type": "boolean", "default": false }
}
}
}
},
"camera": {
"title": "Interior Camera",
"type": "object",
"properties": {
"enabled": { "title": "Enable Camera", "type": "boolean", "default": false, "description": "Shows the oven's interior camera (a still refreshed ~1x/sec while cooking). If Doorbell is also enabled, they combine into a Video Doorbell so the notification shows a photo of your food." },
"name": { "title": "Camera Name", "type": "string", "default": "June Camera" },
"ffmpegPath": { "title": "ffmpeg Path", "type": "string", "default": "ffmpeg", "description": "Path to ffmpeg, used only for tap-to-view live streaming. Snapshots work without it. Leave as 'ffmpeg' to use the system install." }
}
},
"probeSensors": {
"title": "Food Probe Temperature Sensor",
"type": "object",
"properties": {
"enabled": { "title": "Enable Probe Sensor", "type": "boolean", "default": false },
"name": { "title": "Probe Name", "type": "string", "default": "Food Probe" }
}
},
"modes": {
"title": "Cook Mode Switches",
"type": "array",
"default": [],
"description": "Add a switch for each cook mode you want. primitiveType is the June mode id (e.g. bake, roast, broil, air_fry, toast) — you can enter any value the oven supports.",
"items": {
"type": "object",
"properties": {
"label": { "title": "Switch Name", "type": "string" },
"primitiveType": { "title": "June Mode (primitive_type)", "type": "string" },
"tempF": { "title": "Temperature (F)", "type": "integer", "default": 350, "minimum": 100, "maximum": 550 }
},
"required": ["primitiveType"]
}
},
"ovenId": { "type": "string", "hidden": true },
"deviceId": { "type": "string", "hidden": true },
"deviceName": { "type": "string", "hidden": true },
Expand All @@ -92,7 +139,17 @@
"ovens[].doneSensor",
"ovens[].defaultMode",
"ovens[].defaultTempF",
"ovens[].tempUnit"
"ovens[].tempUnit",
"ovens[].doorbell.enabled",
"ovens[].doorbell.name",
"ovens[].doorbell.triggers.done",
"ovens[].doorbell.triggers.ready",
"ovens[].camera.enabled",
"ovens[].camera.name",
"ovens[].camera.ffmpegPath",
"ovens[].probeSensors.enabled",
"ovens[].probeSensors.name",
{ "key": "ovens[].modes", "type": "array", "items": ["ovens[].modes[].label", "ovens[].modes[].primitiveType", "ovens[].modes[].tempF"] }
]
}
]
Expand Down
95 changes: 95 additions & 0 deletions docs/superpowers/plans/2026-07-08-doorbell-probe-polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Doorbell and Probe Polish Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Remove the unsupported door-open doorbell trigger and make the food-probe accessory singular while cleaning up legacy plural accessories.

**Architecture:** Keep the changes in existing boundaries: `protocol.ts` owns normalized config shape, `platform.ts` owns accessory UUID/name lifecycle, schema/UI/README expose user-facing config. Add protocol and platform tests so behavior is covered without depending on a real Homebridge runtime.

**Tech Stack:** TypeScript, Homebridge plugin API types, Vitest.

---

### Task 1: Remove Unsupported Door-Open Trigger

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep the Markdown heading hierarchy sequential.

### Task 1 skips directly from the H1 title to H3. Change task headings to ## (or add an H2 section) to satisfy MD001 and preserve document navigation.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 13-13: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-07-08-doorbell-probe-polish.md` at line 13,
Change the “Task 1: Remove Unsupported Door-Open Trigger” heading from level 3
to level 2 so it follows the document’s H1 title sequentially and satisfies
MD001.

Source: Linters/SAST tools


**Files:**
- Modify: `src/protocol.ts`
- Modify: `src/protocol.test.ts`
- Modify: `config.schema.json`
- Modify: `homebridge-ui/public/index.html`
- Modify: `README.md`
- Modify: `docs/superpowers/specs/2026-07-08-june-expanded-homekit-features-design.md`

- [ ] **Step 1: Write failing protocol tests**

In `src/protocol.test.ts`, change expected doorbell trigger objects so they only contain `done` and `ready`, and add an assertion that an input `doorOpen` value is ignored.

- [ ] **Step 2: Run protocol tests to verify failure**

Run: `npm test -- src/protocol.test.ts`
Expected: FAIL because `normalizeOvenConfig` still returns `doorOpen`.

- [ ] **Step 3: Remove `doorOpen` from normalized config**

In `src/protocol.ts`, change `JuneDoorbellConfig.triggers` to `{ done: boolean; ready: boolean }` and remove the `doorOpen` default/pass-through line.

- [ ] **Step 4: Remove user-facing config entries**

Remove `doorOpen` from `config.schema.json` properties and form list. Remove stale docs language that describes door-open as pending or tentative.

- [ ] **Step 5: Run protocol tests**

Run: `npm test -- src/protocol.test.ts`
Expected: PASS.

### Task 2: Singular Probe Accessory and Legacy Cleanup

**Files:**
- Modify: `src/platform.ts`
- Create: `src/platform.test.ts`

- [ ] **Step 1: Write failing platform tests**

Create `src/platform.test.ts` with fake Homebridge API classes. Test that enabling `probeSensors` registers an accessory named `Kitchen Probe` for an oven named `Kitchen`, and that a cached legacy UUID generated from `ovenId:probes` is unregistered.

- [ ] **Step 2: Run platform tests to verify failure**

Run: `npm test -- src/platform.test.ts`
Expected: FAIL because current code registers `Kitchen Probes` and treats `ovenId:probes` as the current wanted UUID.

- [ ] **Step 3: Rename platform kind and display name**

In `src/platform.ts`, change the accessory kind from `probes` to `probe`, bind the accessory with `${oven.name || 'June'} Probe`, and instantiate `JuneProbeSensorAccessory` for `kind === 'probe'`.

- [ ] **Step 4: Add legacy cleanup**

In `src/platform.ts`, ensure the previous UUID generated from `${client.config.ovenId}:probes` is not marked wanted and is unregistered by the existing stale cleanup path.

- [ ] **Step 5: Run platform tests**

Run: `npm test -- src/platform.test.ts`
Expected: PASS.

### Task 3: Full Verification

**Files:**
- No new files beyond Tasks 1-2.

- [ ] **Step 1: Run full test suite**

Run: `npm test`
Expected: all test files pass.

- [ ] **Step 2: Run lint/typecheck**

Run: `npm run lint`
Expected: TypeScript exits 0.

- [ ] **Step 3: Run build**

Run: `npm run build`
Expected: TypeScript emits `dist` successfully.

- [ ] **Step 4: Commit and push**

Commit focused changes and push to `feature/expanded-homekit-features`.
Loading
Loading