| name | coffee-bridge-barista |
|---|---|
| description | Operate the NIVONA coffee bridge over its HTTP API, including durable brew queues, API v2 BLE jobs, cache-backed resources, settings, histories, backups, and maintenance. |
Use this skill to inspect, control, or automate a local NIVONA coffee bridge. Prefer saved-machine endpoints over low-level BLE, GATT, or protocol diagnostics.
- Check
GET /api/statusandGET /api/machinesbefore machine-specific work. - Treat brewing, confirmation, setting/recipe writes, deletion, restore, OTA, and reboot as mutations. Perform only the mutation requested.
- Never resubmit a mutation after a timeout, disconnect, restart, or ambiguous response. Recover its existing job or brew by ID.
- Distinguish
commandAcceptedfrom physical completion. Report a drink as completed only when its brew state iscompleted. - Surface
attention_requiredwith the machine's message, such as refill water, fill beans, empty trays, move cup/open valve, or flush. - Never send
HYautomatically. Use the confirmation endpoint only when the user asks or explicitly agrees to the machine prompt. reconnectingis not failure. The bridge keeps observing indefinitely.unknown,failed, andinterruptedpause the queue. Never continue past an unverified outcome without explicit user acknowledgement.- For one drink, do not mention cup sensing or ask the user to confirm a cup. Treat the brew request itself as readiness to dispense.
- For a batch that needs separate cups, make cup changes an actionable workflow:
set
holdAfter: trueon every drink except the last, and ask the user to replace the cup only when each completed hold is reached. Do not recite the bridge's hardware limitations as a generic warning. - Back up and validate durable data before restore, bulk deletion, or firmware work.
Start with GET /api/status. The current local API reports:
{
"apiVersion": 2,
"capabilities": {
"asyncBleJobs": true,
"websocketEvents": true,
"eventProtocolVersion": 2,
"durableBrewQueue": true,
"eventsUrl": "/api/events"
}
}Unversioned paths are used. Generic BLE operations return boot-scoped API v2 jobs. Brews are different: they return durable brew records and survive reboot/OTA.
When a non-brew operation returns 202 with job.id:
- Retain the job ID and do not resubmit the request.
- Poll
GET /api/jobs/{id}afterpollAfterMs, or watch it over WebSocket. - On
succeeded, follow the exact same-originjob.resultUrl. - On
failedorcancelled, surfacejob.error; do not retry a mutation. - Bound the whole operation to about 60 seconds unless the user asks otherwise.
Jobs are boot-scoped and expire after five minutes. Valid states are queued,
running, succeeded, failed, and cancelled.
For WebSockets, connect to /api/events, require event protocol 2, use
watch_job/unwatch_job for generic jobs, and accept broadcast brew events.
After reconnect or resync, reload GET /api/brew-queue and recover generic
job watches. REST is authoritative.
The bridge owns BLE/HU sessions. A first saved-machine access establishes the session implicitly; clients do not call a separate online endpoint. A failed session is marked offline, and later access reconnects.
summary: 60-second cachestatsandsettings: 15-minute cachefeatures: 24-hour cache
Fresh/stale responses return 200; cold or ?refresh=1 reads can return a
generic job. Stale data remains usable while refresh runs. Recipe and MyCoffee
details use persistent LittleFS caches.
- Read status and machines; select a saved machine by serial.
- Read
/api/machines/{serial}/summaryfor context. Offline status does not prohibit enqueueing: the bridge will connect when the brew reaches the head. - Read
/recipes, then/recipes/{selector}for a customized drink. - Use only
writableFieldsand listed option codes; never guess model limits. - Enqueue the brew with a fresh persistent
correlationId. - Retain
brew.idand follow/api/brews/{id}until a terminal outcome or user intervention is required.
POST /api/machines/{serial}/brew requires a caller-generated printable
1-64-character correlationId. Reuse the same ID only for an exact retry of the
same canonical request. The bridge deduplicates it; different content returns
409 correlation_conflict.
{
"selector": 2,
"strengthBeans": 3,
"aroma": 2,
"temperature": 2,
"coffeeAmountMl": 120,
"source": "ai",
"actor": "Barista Agent",
"label": "Bright Morning Lungo",
"note": "Softer morning cup.",
"correlationId": "barista-20260912-001",
"holdAfter": false
}The response is 202 with brew.id, brew.state, and
Location: /api/brews/{id}. Do not pass this response to the generic job
resolver.
Valid states:
queued,waiting_for_machine,dispatchingaccepted— the machine acknowledged the command; the drink is not donepreparingattention_required— reportmachineStatus.messageLabeland waitreconnecting— observation is temporarily unavailable; keep waitingcompleted— dispensing was observed and the machine stably returned readyfailed,interrupted,unknown,cancelled
The queue is global FIFO with 16 slots. By default it advances after verified
completion. For a multi-cup batch, set holdAfter: true on every drink except
the last. When a held drink reaches completed, ask the user to replace the
cup; after they confirm, continue it with POST /api/brews/{brewId}/resolve
and {"action":"continue"}. If the user explicitly says one container can
hold the whole batch, it is fine to leave holdAfter false. The queue accepts
an offline machine and waits indefinitely. Before sending the command, it
requires a fresh ready observation, so it also waits behind a
manual/front-panel drink, cleaning, startup, or an operator prompt.
If GET /api/brew-queue reports recoveryBlocked: true, do not enqueue or try
to bypass the queue. Automatic dispatch is fail-closed until its stored state
is repaired.
Management routes:
GET /api/brew-queueGET /api/brews/{brewId}DELETE /api/brews/{brewId}for a definitely unsent itemDELETE /api/brew-queueto cancel every definitely unsent itemPOST /api/brews/{brewId}/resolve
Resolution bodies are {"action":"abandon"} to stop monitoring and mark an
active outcome unknown, {"action":"cancel_remaining"} to preserve the head
and cancel the unsent tail, or
{"action":"continue","acknowledgeRisk":true} to advance after an ambiguous
terminal outcome. Ask the user before the risk acknowledgement.
Known messages take precedence over the process code. Refill-water, beans,
trays, brewing-unit, powder-shaft, move-cup, and flush states are not brew
completion. The bridge keeps the brew in attention_required and resumes
observation after the condition clears.
Use POST /api/machines/{serial}/confirm only when the current status reports
hostConfirmSuggested: true and the user wants to proceed. It is a generic
asynchronous mutation, not a brew resolution action.
Brew history contains one finalized record per brew with brewId, correlation,
command-acceptance flags, physical outcome, raw final status, completion
evidence, applied recipe, and timestamps. Counter history is separate.
The live queue is intentionally excluded from backup; it persists independently across reboot/OTA. The bridge rejects saved-machine deletion/reset, backup restore, and destructive brew-history cleanup while affected brews are unresolved.
Before OTA, download and validate /api/backup/export, archive a crash dump if
present, then upload firmware. Never trigger a real brew merely to validate a
deployment unless the user separately authorizes it.