Spencer Grimes d149580387 Add /notify endpoint for Home Assistant integration
- New /notify endpoint: simple {"message": "", "duration": 5} API
- Uses Priority 3 (Notify) with auto-expiring TTL
- Updated CLAUDE.md with HA integration examples
- Updated README.md with new features and endpoints
- Added Docker detector to documentation
- Removed completed TODO items

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:15:32 -06:00

Kao

A minimalist system status monitor that uses ASCII emotes to display server health on an old phone.

Status: Optimal

Why?

Turn an old phone (with its OLED screen) into a glanceable ambient display for your home server. Instead of graphs and numbers, see a happy face ( ^_^) when things are good, and a worried face ( o_o) when they're not.

Features

  • OLED-optimized — Pure black background, saves battery
  • Glanceable — Know your server's status from across the room
  • Extensible — Add custom detectors for any metric
  • Personality — Rotating expressions, celebration animations, sleep mode
  • Sound effects — Optional audio cues for state changes (tap to enable)
  • Home Assistant ready — Webhook endpoints for notifications and automation

Quick Start

# Clone and setup
git clone https://github.com/yourusername/kao.git
cd kao
python -m venv venv
source venv/bin/activate  # Windows: .\venv\Scripts\activate
pip install -r requirements.txt

# Run everything
python kao.py

Open http://localhost:5100 on your phone (use Fully Kiosk Browser for best results).

Status Faces

State Emote Meaning
Optimal ( ^_^) All systems healthy
Warning ( o_o) Something needs attention
Critical ( x_x) Immediate action required
Notify ( 'o') Transient notification
Sleeping ( -_-)zzZ Sleep mode active
Disconnected ( ?.?) Can't reach server

Built-in Detectors

Detector Monitors
disk_space Disk usage on all drives
cpu CPU utilization
memory RAM usage
service Whether processes are running
network Host reachability (ping)
docker Container health and restart loops

Configuration

Edit config.json to enable/disable detectors and set thresholds:

{
	"aggregator_url": "http://localhost:5100",
	"detectors": [
		{
			"name": "disk_space",
			"enabled": true,
			"script": "detectors/disk_space.py",
			"env": {
				"CHECK_INTERVAL": "300",
				"THRESHOLD_WARNING": "85",
				"THRESHOLD_CRITICAL": "95"
			}
		}
	]
}

Custom Detectors

Create your own detector by POSTing events to the aggregator:

curl -X POST http://localhost:5100/event \
  -H "Content-Type: application/json" \
  -d '{"id": "my_check", "priority": 2, "message": "Something is wrong", "ttl": 120}'
  • id — Unique identifier for this event
  • priority — 1 (critical), 2 (warning), 3 (notify), 4 (optimal)
  • message — What to display
  • ttl — Auto-expire after N seconds (for heartbeat pattern)

Clear an event:

curl -X POST http://localhost:5100/clear \
  -d '{"id": "my_check"}'

Home Assistant Integration

Add REST commands to your configuration.yaml:

rest_command:
  kao_notify:
    url: "http://YOUR_SERVER:5100/notify"
    method: POST
    content_type: "application/json"
    payload: '{"message": "{{ message }}", "duration": {{ duration | default(5) }}}'

  kao_sleep:
    url: "http://YOUR_SERVER:5100/sleep"
    method: POST

  kao_wake:
    url: "http://YOUR_SERVER:5100/wake"
    method: POST

Use in automations:

automation:
  - alias: "Doorbell Notification"
    trigger:
      platform: state
      entity_id: binary_sensor.doorbell
      to: "on"
    action:
      service: rest_command.kao_notify
      data:
        message: "Someone at the door"
        duration: 10

  - alias: "Kao Sleep at Bedtime"
    trigger:
      platform: time
      at: "23:00:00"
    action:
      service: rest_command.kao_sleep

  - alias: "Kao Wake in Morning"
    trigger:
      platform: time
      at: "07:00:00"
    action:
      service: rest_command.kao_wake

API Reference

Endpoint Method Description
/ GET Web UI
/status GET Current state as JSON
/events GET List all active events
/event POST Register an event
/clear POST Clear an event by ID
/notify POST Simple notification {"message": "", "duration": 5}
/sleep POST Enter sleep mode
/wake POST Exit sleep mode

Personality

The emote has personality! In optimal state it:

  • Rotates through happy faces every 5 minutes
  • Occasionally winks ( -_^) or blinks ( ᵕ.ᵕ) for a second or two
  • Celebrates \(^o^)/ when recovering from warnings
  • Each face has its own animation (floating, bouncing, swaying)
  • Reacts when tapped ( °o°) and shows version info

Sound effects (tap screen to enable, or use ?sound=on):

  • Warning: soft double-beep
  • Critical: urgent descending tone
  • Notify: gentle ping
  • Recovery: happy ascending chirp

License

MIT

Description
No description provided
Readme 333 KiB
Languages
Python 73.6%
HTML 19.4%
Shell 7%