- Python 42.1%
- JavaScript 29.7%
- HTML 14.8%
- CSS 12.3%
- Shell 1.1%
|
|
||
|---|---|---|
| app | ||
| config | ||
| scripts | ||
| skills/homescreen-implementation | ||
| specs | ||
| static | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
Homescreen
Touchscreen homescreen for a Raspberry Pi with five main pages:
- Kalender
- Telefon
- Radio
- PV-Anlage
- Ämtliplan
Start
Install dependencies and start the local server:
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
uvicorn app.main:app --reload
Then open http://127.0.0.1:8000.
Run API smoke tests with:
pytest -q
Current status
- Python backend with live calendar, contacts, radio, energy, and chores endpoints
- Calls run in production over
baresip(audio and video), with alinphonecshfallback - Static fullscreen-oriented frontend
- Config files for calendars, contacts, radio stations, chores, and ioBroker
Python version
The project now targets Python 3.10+.
Recommended local setup:
- Python 3.13
- virtual environment in
.venv
Environments
- Development: macOS on Intel
- Production target: Raspberry Pi 5 on Raspberry Pi OS, with a Verbatim PMT-17 portable touchscreen as the display. Touch input on this screen has been tested and confirmed working.
The backend is structured so integrations stay behind Python services. Frontend code remains platform-neutral, while Raspberry-Pi-specific concerns such as Linphone control and kiosk startup can be added later without changing the UI contract.
For telephony, video calls are a product requirement, not an optional enhancement. The production SIP path must support video reliably, with H.264 preferred for Linphone interoperability and VP8 kept as a fallback where possible.
Deployment
Production is deployed from Git only.
Recommended flow:
git add ...
git commit -m "Your change"
git push origin main
ssh pi@<raspberry-pi>
sudo git -C /opt/homescreen pull --ff-only
sudo systemctl restart homescreen.service
Do not update /opt/homescreen via scp, rsync, or tar-over-SSH. The Pi should stay on a normal Git checkout so deployed code matches repository history.
Access from the LAN
The backend listens on 0.0.0.0:8000, so the homescreen is reachable from other devices at http://neeri-kino.local:8000/ or http://192.168.1.19:8000/.
The frontend treats the page as the kiosk only when it is loaded via loopback (127.0.0.1, as scripts/launch-kiosk.sh does). Other devices get a normal mouse cursor and do not run the brightness timer, and POST /api/system/brightness rejects non-loopback clients with 403. Everything else, including calls and the PV switches, works from any device in the LAN without authentication.
Do not change the uvicorn host to ::: uvicorn then listens on IPv6 only and the kiosk's 127.0.0.1 stops working.
Kiosk Browser
The Raspberry Pi kiosk browser is Chromium started from ~pi/.config/autostart/frontend.desktop.
Use --password-store=basic in the Chromium command line so the kiosk session does not prompt for GNOME Keyring or Secret Service access during unattended startup.
To avoid Chromium restoring stale kiosk sessions after updates or reboots, start it through scripts/launch-kiosk.sh from the Git checkout. The script uses a fresh dedicated temporary Chromium profile on each start.
Secrets
Copy config/secrets.example.json to config/secrets.json and fill in the real credentials.
Current secret blocks:
nextcloudfor CalDAV accessiobrokerfor the REST API onoctopus.schnurri.ch(web.0 extension,/rest-api/)linphonefor Raspberry-Pi-side dialing commandsbaresipas a pragmatic SIP CLI fallback when the Debianlinphonecshpath is unreliable
For the productive Raspberry Pi setup, the current baresip path expects PulseAudio/PipeWire style audio devices.
Recommended defaults:
baresip.audioPlayer = "pulse,default"baresip.audioSource = "pulse,default"baresip.audioAlert = "pulse,default"
The current production path also offers PCMU, PCMA, G722, and Opus for audio plus H.264 for video.
For Raspberry-Pi phone dialing, linphone.sip can hold the SIP registration data used by linphonecsh register.
If your PBX has broken or incomplete IPv6 reachability, set linphone.disableIpv6 to true and use the IPv4 host directly.
Contact photos
Store MVP contact photos in:
static/assets/contacts/
Filename rule:
- file name must match the contact
id - preferred format is
.jpg - examples:
static/assets/contacts/mama.jpgstatic/assets/contacts/arzt.jpgstatic/assets/contacts/yorick.jpg
If a contact has no image yet, keep the photoUrl empty or point it to a later file and the UI can fall back to initials.
Radio
Configured in config/radio.json:
stations: fixed online stations (Icecast/HTTP streams)nfsMountPath: NFS share that can be browsed and played from the Radio tabconfigFile/serviceName: the localradioplaysystemd service is driven through this config file and restarted on playback changes
If another NFS track is tapped while something is already playing, it is added to a queue instead of interrupting playback. A stop action clears both playback and the queue.
Ämtliplan (Chores)
Configured in config/chores.json (chore catalog with point value and icon). Per-member scores live in config/chores_state.json (untracked in Git, see .gitignore) and reset automatically every Sunday at 20:00.
Once a member collects 20 points without spinning in between, a spin of the "Glücksrad" (wheel of fortune) unlocks. Spinning (POST /api/chores/spin) randomly awards 5 bonus points, another spin, or nothing.
A long-press on a person's score opens a correction dialog for parents (POST /api/chores/adjust).