Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
A free, self-hosted temperature and humidity dashboard for reptile keepers. Clear room status, no account or subscription.
LifestylePython · JavaScriptGitHub @jlyfshhhOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
At-a-glance enclosure temperature and humidity monitoring for reptile keepers. Self-hosted with Docker on 64-bit Raspberry Pi OS.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
At-a-glance temperature & humidity monitoring for your animal room.
Reads your Bluetooth thermo-hygrometers, groups them by enclosure, and tells you from across the room whether your husbandry is good.
Bask is a small, self-hosted dashboard for reptile/amphibian keepers (or anyone with Govee H5075 sensors). It listens to your sensors over Bluetooth, checks each enclosure against per-species day/night ranges, and shows a big green "all good" — or a red alert that names exactly what's wrong.Read the full README ↗Bask is a small, self-hosted dashboard for reptile/amphibian keepers (or anyone with Govee H5075 sensors). It listens to your sensors over Bluetooth, checks each enclosure against per-species day/night ranges, and shows a big green "all good" — or a red alert that names exactly what's wrong.
It runs as a Docker container on an inexpensive Raspberry Pi — a Pi 4, Pi 3B+, Pi 5, or Zero 2 W all work great. The Pi only scans and serves; any phone, tablet, or browser displays it. Core sensor monitoring needs no cloud, account, or ongoing internet connection.
The idea: walk into your animal room and know instantly — green or not green — whether everything's okay. Details are a tap away; status is readable from the doorway.
🆕 New to Raspberry Pi? The beginner's setup guide takes you from a working Raspberry Pi OS card to a dashboard in about 20 minutes—and includes fresh-card instructions if you need them. Nothing assumed.
Govee H5075 sensors Host (e.g. Raspberry Pi) Any display
(in your enclosures) ┌──────────────────────────────┐ (tablet / browser /
│ scanner ──writes──┐ │ smart display)
temp / humidity / batt │ (owns Bluetooth) ▼ │
│ BLE adverts │ readings.db │ HTTP ┌────────────┐
└────────────────▶ │ web server ──reads─┘ │ ◀───────│ browser │
│ (FastAPI + serves the UI) │ :8080 └────────────┘
└──────────────────────────────┘
Two processes share one SQLite file so they never contend for the Bluetooth radio:
scanner/ — the only component that touches Bluetooth. Passively listens for Govee advertisements, decodes temperature/humidity/battery, and writes them to readings.db.server/ — does no Bluetooth. Reads the database, evaluates each enclosure against its species' (day or night) ranges, and serves the dashboard + JSON API.frontend/ — a plain HTML/CSS/JS dashboard served by the web server.Bask is hardware-agnostic — adapt it to whatever you have:
If your Pi already boots into Raspberry Pi OS, connect it to your network, open Terminal on the Pi (or connect with SSH), and paste:
curl -fsSL https://animalroom.app/bask/install.sh | bash
This installs Docker when needed, enables Bluetooth passive scanning and local
hostname discovery, and runs Bask as restart-safe containers with its settings and history in
~/bask/data. When it finishes it prints your dashboard URL —
http://<hostname>.local:8080. Run the same command again any time to update.
Updates are staged and validated first, create and verify a private config plus
SQLite backup, and restore the prior images, configuration, database, and
per-service running state if startup or health verification fails.
New to Raspberry Pi or unsure what “open Terminal” means? The beginner's setup guide walks through the supplied-card and fresh-card paths, enabling SSH, installation, and first sensor setup.
Already running the former systemd/virtualenv version? The installer stops the old services, takes a timestamped backup (including a consistent SQLite snapshot), migrates the settings and history, and starts the container.
The one-line installer above is the supported path — it sets ownership, loads the scanner's AppArmor profile, and validates each release before switching to it. Set it up by hand only if you want to; the two steps that matter are getting the shared data directory's ownership right and, on Ubuntu-family hosts, loading the AppArmor profile. Miss the first and the root scanner wins the first-start race and writes root-owned files the non-root web service cannot read.
With Docker Engine and the Compose plugin installed:
mkdir -p ~/bask && cd ~/bask
curl -fsSLO https://raw.githubusercontent.com/jlyfshhh/bask/main/compose.yaml
curl -fsSL https://raw.githubusercontent.com/jlyfshhh/bask/main/.env.example -o .env
# Run the web service as you, so it — not the root scanner — creates the shared
# files in a directory you own. The scanner stays root (BlueZ requires it) and
# writes into those files through CAP_DAC_OVERRIDE.
sed -i "s/^BASK_UID=.*/BASK_UID=$(id -u)/; s/^BASK_GID=.*/BASK_GID=$(id -g)/" .env
mkdir -p data backups
docker compose up -d
Bask is published as a prebuilt multi-architecture image, so this downloads a container rather than building one. To build from a checkout instead, clone the repository and use the dev overlay:
docker compose -f compose.yaml -f compose.dev.yaml up -d --build
On Linux, enable BlueZ's reliable passive scanning mode once:
sudo sed -i 's/^#*Experimental = .*/Experimental = true/' /etc/bluetooth/main.conf
sudo systemctl restart bluetooth
sudo apt install -y avahi-daemon bluez rfkill
On an Ubuntu-family host, AppArmor mediates D-Bus, and the docker-default
profile does not mention it, so the scanner's first call to BlueZ is denied and
no readings arrive. Load the shipped profile once and point the scanner at it —
Debian and Raspberry Pi OS do not need this:
curl -fsSL https://raw.githubusercontent.com/jlyfshhh/bask/main/deploy/apparmor/bask-scanner \
| sudo tee /etc/apparmor.d/bask-scanner >/dev/null
sudo apparmor_parser -r /etc/apparmor.d/bask-scanner
echo 'BASK_SCANNER_APPARMOR=bask-scanner' >> .env
docker compose up -d
Then open http://<hostname>.local:8080 (or http://<host-ip>:8080) in any browser, and tap ⚙ Manage → Sensors → Pair by proximity to add your sensors.
Re-run the one-line installer. It validates the new release in a temporary Git
worktree before touching the running service, then pulls the new image while
leaving ~/bask/data in place:
curl -fsSL https://animalroom.app/bask/install.sh | bash
Settings has a 💾 Download backup button. It writes an explicit list of portable settings — sensors, enclosures, species, thermostats, and preferences — and by construction contains no Head Keeper record, session secret, ntfy topic, or integration credential. Restoring one never changes authentication: the key and the private topic on the machine you restore onto are kept as they are.
Before every update, the installer uses scripts/backup.sh to create and verify
a private, machine-local archive containing deployment settings, application
configuration, SQLite history, and configured integration credentials. The
same script can be run manually. Keep
those archives to yourself. Storage defaults beneath ~/bask; external mounts
require an explicit opt-in and are never recursively re-owned by the installer.
Everything lives in the persistent data/ directory (config.json plus
readings.db). You don't need to hand-edit it — the Manage screen in the UI does it all:
config.example.json ships with day/night ranges for eight common species as a starting point — see the disclaimer below.
If you run Herpstat SpyderWeb thermostats, Bask can show each unit's outputs — live probe temperature, setpoint, output %, and any alarms — in a compact strip above the enclosure grid. It reads each unit's built-in status page over your LAN; there's no cloud and nothing to install on the thermostat. When adding one, choose the temperature unit configured on that Herpstat. This is separate from Bask's display preference and keeps the long-term climate log accurate. If you don't add any, the strip never appears.
1. Enable the status page on each thermostat. Bask reads http://<unit-ip>/RAWSTATUS, which is off by default. In the unit's network/web settings (via its touchscreen or the Spyder app), turn on the web status page (sometimes labelled "web enabled" / "status"). To confirm it's on, open http://<unit-ip>/RAWSTATUS in a browser — you should see a page of JSON. A static IP or DHCP reservation for each unit is recommended so its address doesn't change.
2. Add it in Bask. Go to ⚙ Manage → Thermostats → + Add, enter the unit's IP, and tap ⚡ Test connection to verify before saving. Bask polls each unit every few seconds and caches the result, so an offline or slow unit never stalls the dashboard. Output names come straight from the thermostat, so naming an output after its enclosure (e.g. "Ball Python") lines the strip up with your cards.
Bask can also show a compact, read-only room-climate card from a Cielo Breez Max. Go to ⚙ Manage → Thermostats → Animal room climate → Connect and paste a Cielo Connect API key. If the account has multiple controllers, choose which one represents the animal room.
Cielo permits an API key to be used only once and currently limits generation to three keys per month. Bask therefore saves the resulting access token and reuses it across restarts. Generate a fresh key, submit it once, and do not revoke it while Bask is using it. The integration polls Cielo's cloud about every two minutes, so it requires internet access; an outage only marks the card stale and never affects enclosure sensor monitoring.
The integration is deliberately status-only: Bask cannot turn the mini-split on/off or change its mode or setpoint. The API key and token are stored in cielo-secrets.json inside Bask's private data directory with owner-only file permissions. They are excluded from Git, Docker build context, and portable Manage-page exports. The private scripts/backup.sh filesystem archive includes them with owner-only permissions so a full server restore can preserve the integration; protect that archive like any other credential backup.
See Cielo's Breez Max integration instructions for where to generate a Cielo Connect key.
Go to ⚙ Manage → Thermostats → Animal room humidifier → Connect and sign in with a regular VeSync email/password account that can access the humidifier. If the account contains more than one supported humidifier, choose the animal-room device after connecting.
If the owner account uses Sign in with Apple or Google: third-party VeSync libraries cannot use that social-login flow, and you must never enter your Apple/Google password into Bask. Create a separate VeSync account using an email address and a unique VeSync password, then share the humidifier to it using VeSync's family/friend device-sharing feature. Enter only that dedicated account in Bask.
Bask shows current humidity, power, mode, target humidity, mist level, connectivity, stale data, and a low-water warning. The integration is deliberately status-only: it cannot turn the humidifier on/off or change its settings. VeSync does not provide a supported local connection for this model, so status updates use the VeSync cloud about every two minutes and require internet access.
The account login and reusable token are stored in vesync-secrets.json and vesync-token.json inside Bask's private data directory with owner-only permissions. Both are excluded from Git, Docker build context, and portable Manage-page exports. The private scripts/backup.sh archive includes them so a full server restore can preserve the connection; protect that archive like any other credential backup.
Bask can ping your phone when an enclosure goes out of range, loses signal, or recovers. It uses ntfy, a free open-source notification service: Bask generates a private, random topic for your install, and the Pi posts outbound only — nothing on your network is exposed, and Bask still needs no account.
Setup takes about two minutes: ⚙ Manage → Settings → Set up phone alerts, install the free ntfy app (App Store / Google Play), and scan the QR code Bask shows you. Tap Send test to confirm. Alerts fire on status transitions (in-range → out-of-range and back), so you get one ping per event, not a flood.
Your topic name is effectively a password — anyone who knows it can see your alerts (enclosure names and readings only). Bask generates a long random one; keep it private. Self-hosting an ntfy server also works — set
ntfy.serverinconfig.json.
kiosk.sh launches a fullscreen browser (it prefers the lightweight cog WPE browser, with Chromium as a fallback). Rendering a browser on a very low-power host (e.g. Pi Zero W) is slow, so a separate display device is usually smoother. kiosk.sh loads room.html?kiosk=1, which opts the wall display into a 20:00–08:00 night blackout (append &night=START-END in 24-hour hours to change the window). Ordinary phone/browser visits to room.html (no ?kiosk=1) stay live around the clock.frontend/keep.js includes a small same-origin keep-alive so Silk-class browsers don't time out — it activates only on that user-agent and is a no-op everywhere else.)Bask is built for a trusted local network. Reading the dashboard is open to anyone on that network on purpose — it is a wall display, and everyone in the house should be able to glance at it. Changing the setup is not.
A fresh install generates a Head Keeper key, prints it, and keeps a copy in
~/bask/.env (grep BASK_KEEPER_KEY ~/bask/.env). It is needed
to change sensors, enclosures, species ranges, thermostats, cloud integrations,
phone alerts, backups, and updates. The running application stores only a PBKDF2
hash of it and has no endpoint that returns it; the plaintext copy lives beside
the install's other settings in .env, mode 0600, which is what makes a lost key
recoverable instead of terminal.
The key limits changes, not viewing. It is not a substitute for keeping the port off the internet:
:8080 or put it on a public network.0.0.0.0 so your wall display can reach it. Restrict it with a host firewall, an IoT VLAN, or by binding to a specific interface if you want tighter scoping.What Bask does on its side:
config.json (sensor IDs + enclosure names) is git-ignored.GET /api/manage-snapshot and send its revision as X-Bask-Revision on
setup-changing requests (GET /api/config/revision is also available).
Successful writes return their exact new revision; missing and stale
revisions return HTTP 428 and 409, respectively.CAP_DAC_OVERRIDE and a direct host system-D-Bus socket for passive advertisement monitoring. Its only other host bind is the private /data directory. This is a materially smaller attack surface than giving the web service Bluetooth access, but it is not the isolation of a VM: only run images you trust and keep the Pi and Docker host updated.The species ranges in config.example.json are starting points compiled from public care resources, not veterinary advice. Temperature and humidity needs vary by animal, age, and setup, and sensor placement matters (a probe at the basking spot reads hotter than the ambient air, which is usually what you want to alert on). Verify everything against trusted sources and your own animals, and tune the ranges to your room. Bask is a monitoring aid, not a substitute for proper research and care.
scanner/ BLE scanner — owns Bluetooth, writes readings.db
scanner.py main loop: passive scan + batched DB writes
govee.py H5075 advertisement decoding
db.py shared SQLite layer
server/
app.py FastAPI: JSON API, range evaluation, serves the frontend
frontend/ vanilla HTML/CSS/JS dashboard (+ favicon, keep-alive)
config.example.json copy to config.json
Dockerfile portable multi-architecture Bask container
compose.yaml service, Bluetooth D-Bus access, port, and persistent volume
get-bask.sh one-line installer and safe legacy migration
deploy/install.sh installs Docker/BlueZ/mDNS and starts the container
scripts/backup.sh consistent settings + SQLite backup
start.sh run scanner + web server together (local/dev)
kiosk.sh optional fullscreen browser launcher for a host-attached screen
docs/SETUP.md complete beginner's guide (Pi OS → one-line install → first sensor)
Bask can run by itself, or alongside Shed:
| Project | What it watches | |
|---|---|---|
| ☀️ | Bask (this repo) | The environment — live temperature & humidity on a wall display |
| 🐍 | Shed | The care — feeding, weights, enclosure work, and history for terrestrial animals |
| 🌿 | Haven | The combined room view — enclosure status and today's care in one glance |
Haven is not a third database. It is the secure, read-only room dashboard that appears when Bask and Shed are installed together. The apps remain separate, so either can still work independently and each keeps its own portable data.
Choose Bask, Shed, or the combined Haven setup from the Haven installer.
Bask is free, open source, local-first, and has no telemetry. If it has helped your animals—or you simply want to keep the project growing—a tip helps cover test sensors, Raspberry Pi hardware, the domain, and compatibility work. Nothing is locked behind payment.
MIT — see LICENSE.
Built by jlyfshhh. I keep a room full of reptiles and amphibians — follow along on Instagram @thebioactivekeeper for the animals and bioactive builds behind this project. 🦎
Built with the help of Claude, Anthropic's AI assistant — from the Bluetooth decoding and the dashboard to this README. Reviewed, tested, and deployed by a human (me).