- JavaScript 50.3%
- PHP 32.7%
- CSS 16.2%
- Dockerfile 0.8%
|
All checks were successful
Auto Build & Push Multi-Arch Docker Image / build-and-push (push) Successful in 1m55s
|
||
|---|---|---|
| .forgejo/workflows | ||
| api | ||
| lang | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| app.js | ||
| docker-compose.override.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| i18n.js | ||
| icon-192.png | ||
| icon-512.png | ||
| index.php | ||
| LICENSE | ||
| manifest.php | ||
| nosleep.mp4 | ||
| README.md | ||
| style.css | ||
Internal Dashboard
A fullscreen wallboard for displaying Home Assistant sensor data, camera feeds, and weather forecasts. Designed to run on a wall-mounted tablet or monitor.
Features
- Live clock and date
- Outdoor and indoor temperature and humidity (top left), each with a smooth temperature history sparkline (configurable time range)
- Click the indoor climate card to open a modal with the temperature and humidity of other rooms (also with sparklines)
- Click any temperature tile (outdoor, indoor, or a room) to open a large history chart with labelled X (time) and Y (value) axes; the indoor tile stays clickable for its own chart when no rooms are configured
- Configurable quick-access entities in the top-right bar
- Camera feed with a subtle blue-tint overlay and optional location dot
- Daily and hourly weather forecasts with precipitation charts (equal-height, side by side)
- Toggle support for switches, lights, automations, and scripts
- Real-time updates via Home Assistant WebSocket API (60 s polling fallback)
- Multi-language support (Dutch, English, German) — auto-detected from browser
- PWA support — installable on iPad/Android home screen
- Screen wake lock to keep the display active (Wake Lock API + silent video fallback for iOS 15.8)
- Subtle refresh button in the bottom-right corner
Compatibility
Tested with Home Assistant version 2026.6
Getting started
1. Configure environment
Copy .env.example to .env and fill in your values:
cp .env.example .env
2. Run with Docker
docker compose up -d
The dashboard is available at http://localhost:8080.
For development, docker-compose.override.yml mounts the project directory as a volume so changes are reflected immediately without rebuilding.
Environment variables
Two variables are required; all others are optional.
General
| Variable | Required | Description |
|---|---|---|
APP_NAME |
— | Display name shown in the browser tab, home screen, and PWA manifest. Defaults to Dashboard. |
Home Assistant connection
| Variable | Required | Description |
|---|---|---|
HASS_URL |
✓ | Base URL of your Home Assistant instance, without trailing slash. Example: http://homeassistant.local:8123 |
HASS_TOKEN |
✓ | Long-lived access token. Create one via Profile → Security → Long-lived access tokens. |
Security note: The token is injected into the page source by the PHP backend. Only expose this dashboard on a trusted local network — never on the public internet.
Entities
| Variable | Required | Description |
|---|---|---|
HASS_ENTITIES |
— | Comma-separated list of entity IDs to display as cards on the dashboard. If omitted, no general entity cards are shown. |
HASS_ENTITY_NAMES |
— | Custom display names for HASS_ENTITIES, in the same order. |
HASS_OUTDOOR_TEMP |
— | Entity ID for outdoor temperature, shown prominently in the top left. |
HASS_OUTDOOR_HUMIDITY |
— | Entity ID for outdoor humidity, shown next to the outdoor temperature. |
HASS_INDOOR_TEMP |
— | Entity ID for indoor temperature, shown next to the outdoor climate card in the top left. |
HASS_INDOOR_HUMIDITY |
— | Entity ID for indoor humidity, shown next to the indoor temperature. |
HASS_ROOM_NAMES |
— | Comma-separated room labels for the rooms modal (opened by clicking the indoor climate card). |
HASS_ROOM_TEMPS |
— | Comma-separated temperature entity IDs for the rooms modal, in the same order as HASS_ROOM_NAMES. |
HASS_ROOM_HUMIDITY |
— | Comma-separated humidity entity IDs for the rooms modal, in the same order as HASS_ROOM_NAMES. |
HASS_HISTORY_HOURS |
24 |
Number of hours of history shown in the temperature sparklines (1–168). |
HASS_TOP_ENTITIES |
— | Comma-separated entity IDs shown in the fixed top-right bar. Supports sensors, switches, lights, scripts, and automations. Text is truncated with an ellipsis if too long. |
HASS_TOP_ENTITY_NAMES |
— | Custom display names for HASS_TOP_ENTITIES, in the same order. |
Camera
| Variable | Required | Description |
|---|---|---|
HASS_CAMERA |
— | Entity ID of a camera to display (e.g. camera.buienradar). The image is rendered square with a grayscale + blue-tint overlay. |
HASS_CAMERA_DOT |
— | Position of a small location dot on the camera image, as x,y in percentage (0–100). Example: 52,48 places the dot slightly left of centre. Useful for marking your location on a rain radar. |
Weather
| Variable | Required | Description |
|---|---|---|
HASS_WEATHER |
— | Entity ID of a weather integration for the daily forecast card (up to 8 days). |
HASS_WEATHER_HOURLY |
— | Entity ID of a weather integration for the hourly forecast card (up to 24 hours). |
The precipitation chart prefers the precipitation amount (mm) from the forecast. If the integration does not provide it (e.g. KNMI's daily forecast only exposes precipitation_probability), the chart falls back to showing the probability (%) instead. If neither field is present, no bars are drawn. Note that some integrations (e.g. Buienradar) do not support an hourly forecast at all — keep HASS_WEATHER_HOURLY on an entity that does.
Language
The dashboard language is automatically detected from the browser. Supported languages:
| Code | Language |
|---|---|
nl |
Dutch |
en |
English (default fallback) |
de |
German |
Translation files are located in lang/. To add a language, create lang/<code>.json following the structure of an existing file.
Real-time updates
The dashboard connects to the Home Assistant WebSocket API on load and subscribes to state_changed events. Entity cards are updated in place without rebuilding the DOM, which avoids camera image flicker. A 60-second polling interval runs in parallel as a safety net. The WebSocket reconnects automatically after 5 seconds if the connection is lost.
Troubleshooting
Inspecting the weather forecast
If a forecast card is empty or the precipitation chart shows no bars, you can inspect exactly what Home Assistant returns by adding ?debug to the forecast endpoint in your browser:
| URL | Forecast |
|---|---|
http://<host>:8080/api/forecast.php?debug |
Daily (HASS_WEATHER) |
http://<host>:8080/api/forecast.php?hourly&debug |
Hourly (HASS_WEATHER_HOURLY) |
The response highlights the most useful diagnostics at the top:
available_keys— the fields each forecast entry exposes (look forprecipitationand/orprecipitation_probability).has_precipitation— whether theprecipitation(mm) field is present.first_entry— the full first forecast entry.raw_service_response— the completeweather.get_forecastsresponse.
This is handy when switching between weather integrations, since each exposes a different set of fields.
PWA / tablet installation
The dashboard can be installed as a Progressive Web App on iPad or Android:
- Open the dashboard in Safari (iPad) or Chrome (Android).
- Tap the share icon → Add to Home Screen.
- The app opens fullscreen without browser chrome.
The fullscreen button is automatically hidden when running in standalone (PWA) mode or when the Fullscreen API is unavailable.
Keeping the screen awake
| Platform | Method |
|---|---|
| Modern browsers | Screen Wake Lock API |
| iOS 15.8 and older | Silent looping H.264 video (nosleep.mp4) activated on first touch |
On iPadOS 15 and older, also set Settings → Display & Brightness → Auto-Lock → Never for fully reliable always-on behaviour.
Docker
The image is built from the official php:apache base image. Apache mod_rewrite and mod_headers are enabled.
services:
internal-dashboard:
build: .
container_name: internal-dashboard
env_file:
- .env
ports:
- "8080:80"
The docker-compose.override.yml file adds a bind-mount of the project directory for live development without rebuilding the image.