feat: verstuur dashcam-notificatie via Matrix (sherpa) i.p.v. WhatsApp

wwebjs-api is vervangen door wuzapi; notificatiekanaal is nu Matrix:
- send_matrix_notification() POST -> sherpa compat-token uit
  ~/whatsed-new/secrets/sherpa-token naar eddy-report-room
- zelfde patronen als watchdog-report/WAN IP Guard
- tests: SendWhatsappTest -> SendMatrixTest (+2 asserts)
This commit is contained in:
Eddy de Vink 2026-10-13 23:49:18 +02:00
commit 55c282906e
3 changed files with 88 additions and 40 deletions

View file

@ -23,7 +23,7 @@ SD-kaart insteken
4. Check vrije ruimte — verwijder oudste datum-mappen indien nodig
5. Copy + verify + delete per bestand, met retry
6. Early-abort bij aanhoudende I/O-fouten (SD-kaart defect)
7. Stuur WhatsApp notificatie via wwebjs-api
7. Stuur Matrix notificatie via sherpa-bot
SD-kaart uittrekken
→ udev REMOVE trigger (zelfde vendor:product)
@ -39,22 +39,22 @@ mount/umount-rechten op Fedora met SELinux in enforcing mode.
## Robuustheid
Het script is ontworpen tegen een geziene productie-fout (defecte/flakke
Het script is ontworpen tegen een bekende productie-fout (defecte/flakke
SD-kaartlezer die midden in de transfer offline klapt, `I/O error`, `device offline`):
- **Echte fout zichtbaar** — kopieerfouten worden als `OSError` met reden gelogd
(i.p.v. alleen "exit status 1"); de eerdere `cp`-stderr ging verloren.
- **Pre-flight leesbaarheidscheck** — voordat oude datum-mappen op de SSD worden
verwijderd, wordt eerst een bestand van de kaart gelezen. Een onleesbare kaart
resulteert in een duidelijke WhatsApp-"GESTOPT" en **niets** wordt gewist.
resulteert in een duidelijke Matrix-"GESTOPT" en **niets** wordt gewist.
- **Retry per bestand** — 3 pogingen met 2s pauze; vangt transiënte USB-glitches.
- **Early-abort** — bij 5 opeenvolgende fouten stopt het script en stuurt het een
WhatsApp met de laatste fout. Bronbestanden worden nooit verwijderd zonder
Matrix-bericht met de laatste fout. Bronbestanden worden nooit verwijderd zonder
geverifieerde kopie.
- **Geen crash mid-loop** — alle bestandssysteem-calls zijn afgeschermd.
- **fsck.exfat** — na mount draait het mount-script een read-only health check;
een dirty/defecte kaart wordt daarmee zichtbaar in syslog.
- **Geen dubbele runs** — het mount-script skip als de transfer al actief is.
- **Geen dubbele runs** — het mount-script skipt als de transfer al actief is.
- **Stale-mount opruiming** — als de kaartlezer wordt uitgetrokken (of de kaart
offline klapt) ruimt een udev REMOVE-trigger de mount op: de service wordt
gestopt en `/mnt/sdcard` netjes ontkoppeld (lazy als dat mislukt). Zo blijft er
@ -82,7 +82,7 @@ kernel-device (b.v. `sde1`) als argument — zo werkt het ongeacht het filesyste
└── ...
```
Bestandsnaam: `YYYYMMDDHHMMSS_<sequentie><kamera>.MP4`
Bestandsnaam: `YYYYMMDDHHMMSS_<sequentie><camera>.MP4`
- `F` = front, `B` = back
- ~381 MB per clip (~5 minuten)
@ -99,7 +99,7 @@ Bestandsnaam: `YYYYMMDDHHMMSS_<sequentie><kamera>.MP4`
## Operations-handleiding
### WhatsApp berichten
### Matrix-berichten
Na elke transfer stuurt het script een notificatie naar de beheerder. Er zijn drie
basissituaties:
@ -140,7 +140,7 @@ journalctl -t dashcam-transfer --since today
grep dashcam-transfer /var/log/messages
# I/O- en USB-fouten van de lezer
dmesg | grep -Ei "usb|sd[a-z]|dided|device offline|I/O error"
dmesg | grep -Ei "usb|sd[a-z]|device offline|I/O error"
```
### Troubleshooting
@ -152,7 +152,7 @@ dmesg | grep -Ei "usb|sd[a-z]|dided|device offline|I/O error"
| `Geen MP4 bestanden gevonden` in log | Kaart leeg (transfer geslaagd) of verkeerde mapstructuur | Niks mis; controleer op de SSD of bestanden er zijn |
| Transfer start niet na insteken | Service draait al (is-active gate) of device verscheen niet binnen 60s | Logs checken; als het device nooit komt, lezer opnieuw insteken |
| Stale mount in `mount`-output | REMOVE-trigger miste (lezer trok in één keer beide devices weg) | Cleanup-script handmatig draaien (zie herstel) |
| `WhatsApp notificatie mislukt` in log | wwebjs-api container down | `docker compose` in `/home/aiaiaiaiagent/wwebjs-api/` controleren |
| `Matrix notificatie mislukt` in log | sherpa-token/room-file ontbreken of Matrix-homeserver onbereikbaar | `~/whatsed-new/secrets/sherpa-token` + `eddy-report-room` controleren (mode 600), `https://whatsed.eddydevink.nl` checken |
| Abort: onvoldoende vrije ruimte | SSD vol, opschonen hielp niet | Oude datum-mappen handmatig opschonen of SSD uitbreiden |
### Herstelprocedures
@ -193,8 +193,9 @@ systemctl start dashcam-transfer
| `MAX_RETRIES` | `3` | Kopieerpogingen per bestand |
| `RETRY_DELAY` | `2` | Pauze tussen pogingen (seconden) |
| `MAX_CONSECUTIVE_ERRORS` | `5` | Aantal opeenvolgende fouten vóór abort |
| `WHATSAPP_API` | `http://localhost:3001/client/sendMessage/EdGpt` | wwebjs-api endpoint (localhost = nextcloud zelf) |
| `WHATSAPP_CHAT` | `31620248011@c.us` | Ontvanger van notificaties |
| `MATRIX_API` | `https://whatsed.eddydevink.nl/_matrix/client/v3` | Matrix homeserver client API |
| `MATRIX_TOKEN_FILE` | `/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token` | Compat-token van `@sherpa:whatsed.eddydevink.nl` |
| `MATRIX_ROOM_FILE` | `/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room` | DM sherpa → Eddy (Systeemrapportage) |
### `dashcam-transfer-mount.sh`
@ -214,25 +215,30 @@ systemctl start dashcam-transfer
| SD-kaart UUID | `00D3-7715` |
| SSD UUID | `3027-8ECA` |
## WhatsApp notificatie
## Matrix notificatie
De API (`wwebjs-api`) draait als Docker container op nextcloud zelf:
De notificatie wordt verstuurd als `@sherpa:whatsed.eddydevink.nl` naar de bestaande
DM "Systeemrapportage" met `@eddy:whatsed.eddydevink.nl` (zelfde kanaal als
watchdog-rapportage, Home Assistant en Uptime Kuma):
| Config | Waarde |
|---|---|
| API endpoint | `http://localhost:3001/client/sendMessage/EdGpt` |
| Sessie | `EdGpt` |
| Ontvanger | `31620248011@c.us` (privé chat Eddy) |
| API | `https://whatsed.eddydevink.nl/_matrix/client/v3` |
| Bot-account | `@sherpa:whatsed.eddydevink.nl` (compat-token `mct_…`) |
| Tokenbestand | `/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token` (mode 600) |
| Roombestand | `/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room` (mode 600) |
| Bericht | `PUT /rooms/<id>/send/m.room.message/…` met `m.text`-event |
De container: `docker-compose.yml` in `/home/aiaiaiaiagent/wwebjs-api/`.
De notificatie zelf is een JSON-payload naar het endpoint; een mislukte notificatie
wordt alleen gelogd en breekt de transfer niet af.
Token en room-ID blijven buiten Git; de bestanden worden bij elke notificatie gelezen.
Een mislukte notificatie wordt alleen gelogd en breekt de transfer niet af. Verloopt
het token → nieuw compat-token uitgeven met `mas-cli manage issue-compatibility-token
sherpa` en het bestand bijwerken (zie [[Homelab/Software Infrastructuur/Matrix Bots]]).
## Repo-structuur
```
dashcam-transfer/
├── dashcam-transfer.py Hoofdscript: transfer + WhatsApp-notificatie
├── dashcam-transfer.py Hoofdscript: transfer + Matrix-notificatie
├── dashcam-transfer-mount.sh Udev add-trigger: wachten, mount, fsck, service start
├── dashcam-transfer-cleanup.sh Udev remove-trigger: stale mount opruimen
├── udev/
@ -295,7 +301,7 @@ trigger-scripts loggen naar syslog met tag `dashcam-transfer`.
| Suite | Commando | Aantal | Dekking |
|---|---|---|---|
| Python unit | `python3 -m unittest discover -s tests` | 20 | Naam-parsing, directory-scans, kopie/retry, bestandsvergelijking, ruimte-opschoning, WhatsApp-berichten |
| Python unit | `python3 -m unittest discover -s tests` | 22 | Naam-parsing, directory-scans, kopie/retry, bestandsvergelijking, ruimte-opschoning, Matrix-berichten |
| Mount-script | `./tests/test_mount_script.sh` | 7 | Skip bij actieve service, mount + service start, fsck-uitvoering, logging |
| Cleanup-script | `./tests/test_cleanup_script.sh` | 12 | Stale-detectie (device weg / naam-match), service stop, umount + lazy-fallback, no-op bij gezonde mount |