systemd management scripts
This commit is contained in:
57
README.md
57
README.md
@@ -5,20 +5,23 @@ WebSocket servers that feed system stats, alarm audio, and status images to the
|
||||
## File Structure
|
||||
|
||||
```
|
||||
pi/
|
||||
run_all.py # Launches both servers as child processes
|
||||
stats_server.py # Real system stats over WebSocket (port 8765)
|
||||
contents_server.py # Alarm audio + status images over WebSocket (port 8766)
|
||||
mock_server.py # Drop-in replacement for stats_server with random data
|
||||
audio_handler.py # WAV loading, PCM chunking, alarm streaming
|
||||
image_handler.py # PNG to 1-bit monochrome conversion, alpha compositing
|
||||
alarm_scheduler.py # Loads and validates alarm config, checks firing schedule
|
||||
requirements.txt
|
||||
config/
|
||||
alarms.json # Alarm schedule configuration
|
||||
assets/
|
||||
alarm/ # WAV files for alarm audio
|
||||
img/ # Status images (idle.png, on_alarm.png)
|
||||
run_all.py # Launches both servers as child processes
|
||||
stats_server.py # Real system stats over WebSocket (port 8765)
|
||||
contents_server.py # Alarm audio + status images over WebSocket (port 8766)
|
||||
mock_server.py # Drop-in replacement for stats_server with random data
|
||||
audio_handler.py # WAV loading, PCM chunking, alarm streaming
|
||||
image_handler.py # PNG to 1-bit monochrome conversion, alpha compositing
|
||||
alarm_scheduler.py # Loads and validates alarm config, checks firing schedule
|
||||
requirements.txt
|
||||
config/
|
||||
alarms.json # Alarm schedule configuration
|
||||
assets/
|
||||
alarm/ # WAV files for alarm audio
|
||||
img/ # Status images (idle.png, on_alarm.png, sleep.png)
|
||||
scripts/
|
||||
setup.sh # Install deps + create and enable systemd service
|
||||
edit.sh # Edit alarm config and restart service
|
||||
remove.sh # Stop, disable, and remove systemd service
|
||||
```
|
||||
|
||||
## Requirements
|
||||
@@ -48,6 +51,16 @@ python contents_server.py --config path/to.json # port 8766, custom config
|
||||
python mock_server.py # port 8765, random data (no psutil needed)
|
||||
```
|
||||
|
||||
### Running as a systemd service
|
||||
|
||||
Use the helper scripts in `scripts/` to manage a `pi-dashboard` systemd service:
|
||||
|
||||
```bash
|
||||
bash scripts/setup.sh # install deps, create + enable service
|
||||
bash scripts/edit.sh # edit alarm config, restart service
|
||||
bash scripts/remove.sh # stop + remove service
|
||||
```
|
||||
|
||||
## Servers
|
||||
|
||||
### stats_server.py -- port 8765
|
||||
@@ -56,8 +69,8 @@ Pushes a JSON object every 2 seconds with real system metrics from `psutil`:
|
||||
|
||||
- `cpu_pct`, `mem_pct`, `mem_used_mb`, `disk_pct`
|
||||
- `cpu_temp` (reads `/sys/class/thermal/` as fallback)
|
||||
- `uptime_hrs`, `net_rx_kbps`, `net_tx_kbps`
|
||||
- `services` (mocked until systemd integration)
|
||||
- `uptime_hrs`, `net_rx_kbps`, `net_tx_kbps` (values are in kB/s despite the field names)
|
||||
- `services` — live Docker container statuses via `docker ps -a`, with a ternary status model (`running`, `warning`, `stopped`). Monitored containers: gitea, samba, pihole, qbittorrent, frpc (ny), pinepods, frpc (ssh), jellyfin.
|
||||
- `local_time` fields for RTC sync (`y`, `mo`, `d`, `h`, `m`, `s`)
|
||||
|
||||
### contents_server.py -- port 8766
|
||||
@@ -65,8 +78,8 @@ Pushes a JSON object every 2 seconds with real system metrics from `psutil`:
|
||||
Serves alarm audio and status images. Protocol:
|
||||
|
||||
**Status image:**
|
||||
1. Text frame: `{"type":"status_image","width":120,"height":120}`
|
||||
2. Binary frame: 1-bit monochrome bitmap (1800 bytes)
|
||||
1. Text frame: `{"type":"status_image","width":200,"height":200}`
|
||||
2. Binary frame: 1-bit monochrome bitmap (5000 bytes)
|
||||
|
||||
**Alarm audio:**
|
||||
1. Text frame: `{"type":"alarm_start","sample_rate":N,"channels":N,"bits":N}`
|
||||
@@ -108,8 +121,8 @@ Example with two alarms:
|
||||
| `alarm_time` | `string` | Yes | 4-digit HHMM, 24-hour. Fires on the matched minute. |
|
||||
| `alarm_days` | `string[]` | No | 3-letter abbreviations: `Mon`–`Sun`. If omitted, fires every day. |
|
||||
| `alarm_dates` | `string[]` | No | `MM/DD` strings. Ignored if `alarm_days` is also set. |
|
||||
| `alarm_audio` | `string` | No | WAV path, relative to `pi/`. Default: `assets/alarm/alarm_test.wav`. |
|
||||
| `alarm_image` | `string` | No | Status PNG path, relative to `pi/`. Default: `assets/img/on_alarm.png`. |
|
||||
| `alarm_audio` | `string` | No | WAV path, relative to project root. Default: `assets/alarm/alarm_test.wav`. |
|
||||
| `alarm_image` | `string` | No | Status PNG path, relative to project root. Default: `assets/img/on_alarm.png`. |
|
||||
|
||||
If both `alarm_days` and `alarm_dates` are present, `alarm_days` takes priority.
|
||||
|
||||
@@ -118,12 +131,12 @@ If both `alarm_days` and `alarm_dates` are present, `alarm_days` takes priority.
|
||||
### audio_handler.py
|
||||
|
||||
- `find_wav(path=None)` -- uses the given path if it exists, otherwise falls back to glob in `assets/alarm/`
|
||||
- `read_wav(path)` -- reads WAV, returns `(pcm_bytes, sample_rate, channels, bits)`
|
||||
- `read_wav(path)` -- reads WAV, normalizes audio to 0 dBFS, returns `(pcm_bytes, sample_rate, channels, bits)`
|
||||
- `stream_alarm(ws, pcm, sr, ch, bits)` -- streams one alarm cycle over WebSocket
|
||||
|
||||
### image_handler.py
|
||||
|
||||
- `load_status_image(path)` -- loads PNG, composites transparency onto white, converts to 1-bit 120x120 monochrome bitmap (black=1, MSB-first)
|
||||
- `load_status_image(path)` -- loads PNG, composites transparency onto white, converts to 1-bit 200x200 monochrome bitmap (black=1, MSB-first)
|
||||
- `send_status_image(ws, img_bytes)` -- sends status image header + binary over WebSocket
|
||||
|
||||
### alarm_scheduler.py
|
||||
|
||||
Reference in New Issue
Block a user