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>
This commit is contained in:
46
CLAUDE.md
46
CLAUDE.md
@@ -61,6 +61,7 @@ Edit `config.json` to configure detectors:
|
|||||||
| Memory | `detectors/memory.py` | — |
|
| Memory | `detectors/memory.py` | — |
|
||||||
| Service | `detectors/service.py` | `SERVICES` (comma-separated process names) |
|
| Service | `detectors/service.py` | `SERVICES` (comma-separated process names) |
|
||||||
| Network | `detectors/network.py` | `HOSTS` (comma-separated hostnames/IPs) |
|
| Network | `detectors/network.py` | `HOSTS` (comma-separated hostnames/IPs) |
|
||||||
|
| Docker | `detectors/docker.py` | `CONTAINERS` (optional, monitors all if empty) |
|
||||||
|
|
||||||
All detectors support: `AGGREGATOR_URL`, `CHECK_INTERVAL`, `THRESHOLD_WARNING`, `THRESHOLD_CRITICAL`
|
All detectors support: `AGGREGATOR_URL`, `CHECK_INTERVAL`, `THRESHOLD_WARNING`, `THRESHOLD_CRITICAL`
|
||||||
|
|
||||||
@@ -70,7 +71,8 @@ All detectors support: `AGGREGATOR_URL`, `CHECK_INTERVAL`, `THRESHOLD_WARNING`,
|
|||||||
|----------|--------|-------------|
|
|----------|--------|-------------|
|
||||||
| `/event` | POST | Register event: `{"id": "name", "priority": 1-4, "message": "optional", "ttl": seconds}` |
|
| `/event` | POST | Register event: `{"id": "name", "priority": 1-4, "message": "optional", "ttl": seconds}` |
|
||||||
| `/clear` | POST | Clear event: `{"id": "name"}` |
|
| `/clear` | POST | Clear event: `{"id": "name"}` |
|
||||||
| `/sleep` | POST | Enter sleep mode (for Home Assistant) |
|
| `/notify` | POST | Simple notification: `{"message": "text", "duration": 5}` |
|
||||||
|
| `/sleep` | POST | Enter sleep mode |
|
||||||
| `/wake` | POST | Exit sleep mode |
|
| `/wake` | POST | Exit sleep mode |
|
||||||
| `/status` | GET | Current state JSON |
|
| `/status` | GET | Current state JSON |
|
||||||
| `/events` | GET | List active events |
|
| `/events` | GET | List active events |
|
||||||
@@ -93,7 +95,7 @@ The optimal state cycles through emotes with paired animations every 5 minutes:
|
|||||||
| Emote | Animation | Vibe |
|
| Emote | Animation | Vibe |
|
||||||
|-------|-----------|------|
|
|-------|-----------|------|
|
||||||
| `( ^_^)` | breathing | calm |
|
| `( ^_^)` | breathing | calm |
|
||||||
| `( ᵔᴥᵔ)` | floating | dreamy |
|
| `( ˙▿˙)` | floating | content |
|
||||||
| `(◕‿◕)` | bouncing | cheerful |
|
| `(◕‿◕)` | bouncing | cheerful |
|
||||||
| `( ・ω・)` | swaying | curious |
|
| `( ・ω・)` | swaying | curious |
|
||||||
| `( ˘▽˘)` | breathing | cozy |
|
| `( ˘▽˘)` | breathing | cozy |
|
||||||
@@ -104,6 +106,43 @@ Additional states:
|
|||||||
- **Connection lost**: `( ?.?)` gray, searching animation
|
- **Connection lost**: `( ?.?)` gray, searching animation
|
||||||
- **Sleep mode**: `( -_-)zzZ` dim, very slow breathing
|
- **Sleep mode**: `( -_-)zzZ` dim, very slow breathing
|
||||||
|
|
||||||
|
## Home Assistant Integration
|
||||||
|
|
||||||
|
Add REST commands to `configuration.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
rest_command:
|
||||||
|
kao_notify:
|
||||||
|
url: "http://kao-host:5100/notify"
|
||||||
|
method: POST
|
||||||
|
content_type: "application/json"
|
||||||
|
payload: '{"message": "{{ message }}", "duration": {{ duration | default(5) }}}'
|
||||||
|
|
||||||
|
kao_sleep:
|
||||||
|
url: "http://kao-host:5100/sleep"
|
||||||
|
method: POST
|
||||||
|
|
||||||
|
kao_wake:
|
||||||
|
url: "http://kao-host:5100/wake"
|
||||||
|
method: POST
|
||||||
|
```
|
||||||
|
|
||||||
|
Use in automations:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Doorbell notification
|
||||||
|
- service: rest_command.kao_notify
|
||||||
|
data:
|
||||||
|
message: "Someone at the door"
|
||||||
|
duration: 10
|
||||||
|
|
||||||
|
# Bedtime routine
|
||||||
|
- service: rest_command.kao_sleep
|
||||||
|
|
||||||
|
# Morning routine
|
||||||
|
- service: rest_command.kao_wake
|
||||||
|
```
|
||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -116,7 +155,8 @@ Additional states:
|
|||||||
│ ├── cpu.py
|
│ ├── cpu.py
|
||||||
│ ├── memory.py
|
│ ├── memory.py
|
||||||
│ ├── service.py
|
│ ├── service.py
|
||||||
│ └── network.py
|
│ ├── network.py
|
||||||
|
│ └── docker.py
|
||||||
├── requirements.txt
|
├── requirements.txt
|
||||||
└── SPEC.md # Original project specification
|
└── SPEC.md # Original project specification
|
||||||
```
|
```
|
||||||
|
|||||||
85
README.md
85
README.md
@@ -8,18 +8,14 @@ A minimalist system status monitor that uses ASCII emotes to display server heal
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- Figure out way to update installation in /opt/kao when git updates. Maybe run a git pull on service startup?
|
|
||||||
- Think about ways of implementing noises.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **OLED-optimized** — Pure black background, saves battery
|
- **OLED-optimized** — Pure black background, saves battery
|
||||||
- **Glanceable** — Know your server's status from across the room
|
- **Glanceable** — Know your server's status from across the room
|
||||||
- **Extensible** — Add custom detectors for any metric
|
- **Extensible** — Add custom detectors for any metric
|
||||||
- **Personality** — Rotating expressions, celebration animations, sleep mode
|
- **Personality** — Rotating expressions, celebration animations, sleep mode
|
||||||
- **Home Assistant ready** — Webhook endpoints for automation
|
- **Sound effects** — Optional audio cues for state changes (tap to enable)
|
||||||
|
- **Home Assistant ready** — Webhook endpoints for notifications and automation
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -50,13 +46,14 @@ Open http://localhost:5100 on your phone (use Fully Kiosk Browser for best resul
|
|||||||
|
|
||||||
## Built-in Detectors
|
## Built-in Detectors
|
||||||
|
|
||||||
| Detector | Monitors |
|
| Detector | Monitors |
|
||||||
| -------------- | ----------------------------- |
|
| -------------- | ------------------------------------- |
|
||||||
| **disk_space** | Disk usage on all drives |
|
| **disk_space** | Disk usage on all drives |
|
||||||
| **cpu** | CPU utilization |
|
| **cpu** | CPU utilization |
|
||||||
| **memory** | RAM usage |
|
| **memory** | RAM usage |
|
||||||
| **service** | Whether processes are running |
|
| **service** | Whether processes are running |
|
||||||
| **network** | Host reachability (ping) |
|
| **network** | Host reachability (ping) |
|
||||||
|
| **docker** | Container health and restart loops |
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -104,57 +101,83 @@ curl -X POST http://localhost:5100/clear \
|
|||||||
|
|
||||||
## Home Assistant Integration
|
## Home Assistant Integration
|
||||||
|
|
||||||
Add webhook commands to your Home Assistant config:
|
Add REST commands to your `configuration.yaml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
rest_command:
|
rest_command:
|
||||||
sentry_sleep:
|
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"
|
url: "http://YOUR_SERVER:5100/sleep"
|
||||||
method: POST
|
method: POST
|
||||||
sentry_wake:
|
|
||||||
|
kao_wake:
|
||||||
url: "http://YOUR_SERVER:5100/wake"
|
url: "http://YOUR_SERVER:5100/wake"
|
||||||
method: POST
|
method: POST
|
||||||
```
|
```
|
||||||
|
|
||||||
Trigger from automations:
|
Use in automations:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
automation:
|
automation:
|
||||||
- alias: "Sentry Sleep at Bedtime"
|
- 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:
|
trigger:
|
||||||
platform: time
|
platform: time
|
||||||
at: "23:00:00"
|
at: "23:00:00"
|
||||||
action:
|
action:
|
||||||
service: rest_command.sentry_sleep
|
service: rest_command.kao_sleep
|
||||||
|
|
||||||
- alias: "Sentry Wake in Morning"
|
- alias: "Kao Wake in Morning"
|
||||||
trigger:
|
trigger:
|
||||||
platform: time
|
platform: time
|
||||||
at: "07:00:00"
|
at: "07:00:00"
|
||||||
action:
|
action:
|
||||||
service: rest_command.sentry_wake
|
service: rest_command.kao_wake
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
| Endpoint | Method | Description |
|
| Endpoint | Method | Description |
|
||||||
| --------- | ------ | ---------------------- |
|
| --------- | ------ | ------------------------------------------------ |
|
||||||
| `/` | GET | Web UI |
|
| `/` | GET | Web UI |
|
||||||
| `/status` | GET | Current state as JSON |
|
| `/status` | GET | Current state as JSON |
|
||||||
| `/events` | GET | List all active events |
|
| `/events` | GET | List all active events |
|
||||||
| `/event` | POST | Register an event |
|
| `/event` | POST | Register an event |
|
||||||
| `/clear` | POST | Clear an event by ID |
|
| `/clear` | POST | Clear an event by ID |
|
||||||
| `/sleep` | POST | Enter sleep mode |
|
| `/notify` | POST | Simple notification `{"message": "", "duration": 5}` |
|
||||||
| `/wake` | POST | Exit sleep mode |
|
| `/sleep` | POST | Enter sleep mode |
|
||||||
|
| `/wake` | POST | Exit sleep mode |
|
||||||
|
|
||||||
## Personality
|
## Personality
|
||||||
|
|
||||||
The emote has personality! In optimal state it:
|
The emote has personality! In optimal state it:
|
||||||
|
|
||||||
- Rotates through happy faces every 5 minutes
|
- Rotates through happy faces every 5 minutes
|
||||||
- Occasionally winks `( -_^)` or blinks `( ᵕ.ᵕ)`
|
- Occasionally winks `( -_^)` or blinks `( ᵕ.ᵕ)` for a second or two
|
||||||
- Celebrates `\(^o^)/` when recovering from warnings
|
- Celebrates `\(^o^)/` when recovering from warnings
|
||||||
- Each face has its own animation (floating, bouncing, swaying)
|
- 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
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -223,6 +223,34 @@ def clear_event():
|
|||||||
return jsonify({"error": "Event not found"}), 404
|
return jsonify({"error": "Event not found"}), 404
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/notify", methods=["POST"])
|
||||||
|
def notify():
|
||||||
|
"""
|
||||||
|
Simple notification endpoint for Home Assistant.
|
||||||
|
JSON: {"message": "text", "duration": 5}
|
||||||
|
Shows the Notify emote with message, auto-expires after duration.
|
||||||
|
"""
|
||||||
|
data = request.get_json(force=True) if request.data else {}
|
||||||
|
message = data.get("message", "")
|
||||||
|
duration = int(data.get("duration", 5))
|
||||||
|
|
||||||
|
# Generate unique ID to avoid conflicts
|
||||||
|
event_id = f"ha_notify_{int(time.time() * 1000)}"
|
||||||
|
|
||||||
|
event = {
|
||||||
|
"priority": 3, # Notify priority
|
||||||
|
"message": message,
|
||||||
|
"timestamp": time.time(),
|
||||||
|
"ttl": time.time() + duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
with events_lock:
|
||||||
|
active_events[event_id] = event
|
||||||
|
|
||||||
|
state = write_status()
|
||||||
|
return jsonify({"status": "ok", "id": event_id, "current_state": state}), 200
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sleep", methods=["POST"])
|
@app.route("/sleep", methods=["POST"])
|
||||||
def sleep_mode():
|
def sleep_mode():
|
||||||
"""Enter sleep mode. For Home Assistant webhook."""
|
"""Enter sleep mode. For Home Assistant webhook."""
|
||||||
|
|||||||
Reference in New Issue
Block a user