Files
Kao/openapi.yaml
Spencer aaae20281d Bump to v2.3.0: replace polling with SSE stream, fix detector imports
- Add GET /stream SSE endpoint to aggregator.py; state is pushed
  instantly on every change instead of fetched every 2s
- Replace setInterval polling in index.html with EventSource;
  onerror shows the ( ?.?) face and auto-reconnect is handled by
  the browser natively
- Fix ModuleNotFoundError in detectors: inject project root into
  PYTHONPATH when launching subprocesses from kao.py
- Update openapi.yaml, CLAUDE.md, README.md with /stream endpoint
- Remove completed SSE item from TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:25:15 -06:00

469 lines
13 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.0.3
info:
title: Kao API
description: |
Kao is a minimalist system status monitor that uses ASCII emotes to represent system health.
## Priority System
Events use a priority system where lower numbers indicate higher priority:
- **1 (Critical)**: System failure - red, shaking
- **2 (Warning)**: Degraded state - yellow, breathing
- **3 (Notify)**: Informational alert - blue, popping
- **4 (Optimal)**: All systems healthy - green, varies
## TTL/Heartbeat Pattern
Events can have a TTL (time-to-live) that auto-expires them. Detectors typically send
heartbeat events that expire if not refreshed, indicating loss of communication.
version: 2.3.0
license:
name: MIT
servers:
- url: http://192.168.2.114:5100
description: Local development server
paths:
/event:
post:
summary: Register an event
description: |
Register or update a system event. Events are identified by their ID and will
overwrite any existing event with the same ID. Use TTL for heartbeat-style
monitoring where absence of updates indicates a problem.
operationId: postEvent
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EventRequest"
examples:
critical:
summary: Critical event
value:
id: "disk_root"
priority: 1
message: "Root disk 98% full"
heartbeat:
summary: Heartbeat with TTL
value:
id: "cpu_monitor"
priority: 4
message: "CPU nominal"
ttl: 60
responses:
"200":
description: Event registered successfully
content:
application/json:
schema:
$ref: "#/components/schemas/EventResponse"
"400":
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/clear-all:
post:
summary: Clear all events
description: |
Clear all active events at once. Used by the frontend when the display
is tapped to dismiss warnings and critical alerts.
operationId: clearAllEvents
responses:
"200":
description: All events cleared
content:
application/json:
schema:
$ref: "#/components/schemas/ClearAllResponse"
/clear:
post:
summary: Clear an event
description: Remove an event by its ID. Use this when a condition has resolved.
operationId: clearEvent
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
description: Event identifier to clear
example: "disk_root"
responses:
"200":
description: Event cleared successfully
content:
application/json:
schema:
$ref: "#/components/schemas/ClearResponse"
"400":
description: Missing required field
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"404":
description: Event not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/notify:
post:
summary: Send a notification
description: |
Send a temporary notification with optional custom display properties.
Designed for Home Assistant integration. Notifications auto-expire after
the specified duration.
operationId: notify
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/NotifyRequest"
examples:
simple:
summary: Simple notification
value:
message: "Doorbell rang"
duration: 10
custom:
summary: Custom notification
value:
message: "Welcome home!"
duration: 10
emote: "(-´)ゞ"
color: "#00FF88"
animation: "celebrating"
sound: "chime"
responses:
"200":
description: Notification sent
content:
application/json:
schema:
$ref: "#/components/schemas/NotifyResponse"
/sleep:
post:
summary: Enter sleep mode
description: |
Put Kao into sleep mode. The display will show a sleeping emote with
dimmed colors. All events are preserved but not displayed until wake.
operationId: sleep
responses:
"200":
description: Entered sleep mode
content:
application/json:
schema:
$ref: "#/components/schemas/SleepResponse"
/wake:
post:
summary: Exit sleep mode
description: Wake Kao from sleep mode and resume normal status display.
operationId: wake
responses:
"200":
description: Exited sleep mode
content:
application/json:
schema:
$ref: "#/components/schemas/WakeResponse"
/stream:
get:
summary: SSE stream of state updates
description: |
Server-Sent Events stream that pushes the current state as JSON whenever
it changes. The frontend connects here instead of polling `/status`.
Each event is a `data:` line containing a JSON-encoded Status object,
followed by a blank line. A `: keepalive` comment is sent every 30
seconds to prevent proxy timeouts. The current state is pushed
immediately on connection.
The browser's `EventSource` API handles automatic reconnection if the
connection drops.
operationId: getStream
responses:
"200":
description: Event stream
content:
text/event-stream:
schema:
type: string
description: |
Newline-delimited SSE events. `data:` lines contain a
JSON-encoded Status object. Lines beginning with `:` are
keepalive comments and can be ignored.
example: "data: {\"current_state\": \"optimal\", ...}\n\n"
/status:
get:
summary: Get current status
description: |
Returns the current display state including the active emote, color,
animation, and list of active events. Prefer `/stream` for live
displays; use this endpoint for one-shot queries.
operationId: getStatus
responses:
"200":
description: Current status
content:
application/json:
schema:
$ref: "#/components/schemas/Status"
/events:
get:
summary: List all active events
description: Returns all currently active events with their full details.
operationId: listEvents
responses:
"200":
description: List of active events
content:
application/json:
schema:
$ref: "#/components/schemas/EventList"
components:
schemas:
EventRequest:
type: object
required:
- id
- priority
properties:
id:
type: string
description: Unique identifier for this event
example: "cpu_high"
priority:
type: integer
minimum: 1
maximum: 4
description: |
Event priority (1=Critical, 2=Warning, 3=Notify, 4=Optimal)
example: 2
message:
type: string
description: Optional message to display
example: "CPU at 90%"
ttl:
type: integer
description: Time-to-live in seconds. Event auto-expires after this duration.
example: 60
EventResponse:
type: object
properties:
status:
type: string
example: "ok"
current_state:
$ref: "#/components/schemas/Status"
ClearAllResponse:
type: object
properties:
status:
type: string
example: "cleared"
count:
type: integer
description: Number of events that were cleared
example: 2
current_state:
$ref: "#/components/schemas/Status"
ClearResponse:
type: object
properties:
status:
type: string
example: "cleared"
current_state:
$ref: "#/components/schemas/Status"
NotifyRequest:
type: object
properties:
message:
type: string
description: Text to display below the emote
example: "Someone at the door"
duration:
type: integer
description: Seconds before auto-expire
default: 5
example: 10
emote:
type: string
description: Custom emote to display (overrides default)
example: "( °o°)"
color:
type: string
description: Custom color in hex format
pattern: "^#[0-9A-Fa-f]{6}$"
example: "#FF9900"
animation:
type: string
description: Animation style
enum:
- breathing
- shaking
- popping
- celebrating
- floating
- bouncing
- swaying
example: "popping"
sound:
type: string
description: Sound effect to play
enum:
- chime
- alert
- warning
- critical
- success
- notify
- doorbell
- knock
- ding
- blip
- siren
- tada
- ping
- bubble
- fanfare
- alarm
- klaxon
- none
example: "chime"
NotifyResponse:
type: object
properties:
status:
type: string
example: "ok"
id:
type: string
description: Generated event ID
example: "ha_notify_1704067200000"
current_state:
$ref: "#/components/schemas/Status"
SleepResponse:
type: object
properties:
status:
type: string
example: "sleeping"
current_state:
$ref: "#/components/schemas/Status"
WakeResponse:
type: object
properties:
status:
type: string
example: "awake"
current_state:
$ref: "#/components/schemas/Status"
Status:
type: object
properties:
current_state:
type: string
description: Current state name
enum:
- critical
- warning
- notify
- optimal
- sleeping
example: "optimal"
active_emote:
type: string
description: ASCII emote to display
example: "( ^_^)"
color:
type: string
description: Display color in hex
example: "#00FF00"
animation:
type: string
description: Current animation
example: "breathing"
message:
type: string
description: Status message
example: "Optimal"
sound:
type: string
description: Sound to play (only present when triggered)
example: "chime"
active_events:
type: array
items:
$ref: "#/components/schemas/ActiveEvent"
last_updated:
type: string
format: date-time
description: ISO 8601 timestamp
example: "2024-01-01T12:00:00"
ActiveEvent:
type: object
properties:
id:
type: string
example: "cpu_monitor"
priority:
type: integer
example: 4
message:
type: string
example: "CPU nominal"
EventList:
type: object
properties:
events:
type: object
additionalProperties:
type: object
properties:
priority:
type: integer
message:
type: string
timestamp:
type: number
ttl:
type: number
Error:
type: object
properties:
error:
type: string
example: "Missing required fields: id, priority"