A robust bridge that subscribes to your Tibber Pulse real-time energy feed and publishes measurements as MQTT sensors to Home Assistant, with automatic device discovery.
- Node.js 22 or later
- Yarn
- A Tibber Pulse device connected to your meter
- An MQTT broker reachable from this machine (e.g. Mosquitto)
- Home Assistant with the MQTT integration enabled
- Open a browser and go to developer.tibber.com/settings/access-token
- Log in with your Tibber account
- Click "Create new token" and give it a name (e.g.
tibber-ha-mqtt) - Copy the token -- you will paste it into
.envasTIBBER_TOKEN
Your token grants full read access to your Tibber account. Keep it secret and never commit it to git.
# 1. Clone the repo
git clone https://github.com/your-user/tibber-ha-mqtt.git
cd tibber-ha-mqtt
# 2. Install dependencies
yarn inst
# 3. Create your config file
cp .env.example .env
# 4. Fill in your token and MQTT broker URL
# Open .env in your editor and set TIBBER_TOKEN and MQTT_URLAll configuration lives in .env. Copy .env.example for a fully annotated template.
| Variable | Required | Default | Description |
|---|---|---|---|
TIBBER_TOKEN |
Yes | -- | Your Tibber personal access token |
TIBBER_HOME_ID |
Yes | -- | Your Tibber home ID (find it at developer.tibber.com/explorer) |
MQTT_URL |
Yes | -- | MQTT broker URL (mqtt://host:port) |
MQTT_USERNAME |
No | -- | MQTT username if your broker requires auth |
MQTT_PASSWORD |
No | -- | MQTT password if your broker requires auth |
NTFY_URL |
No | -- | ntfy topic URL for failure alerts |
STALE_DATA_TIMEOUT_MS |
No | 300000 |
Reconnect if no data received for this long (ms) |
ALERT_COOLDOWN_MS |
No | 1800000 |
Minimum gap between same-type alerts (ms) |
RECONNECT_MAX_DELAY_MS |
No | 300000 |
Maximum backoff delay between reconnect attempts (ms) |
LOG_LEVEL |
No | info |
Log verbosity: trace, debug, info, warn, error, fatal |
Each SENSOR_* line in .env controls one Home Assistant sensor. Comment a line out to disable it:
SENSOR_POWER=true # enabled
SENSOR_CURRENT_L1=false # disabled
# SENSOR_VOLTAGE_L1=true # also disabled (commented out)Every time the bridge starts it actively manages all known sensor topics on the broker:
- Enabled sensors get their discovery payload published (retained), so HA creates or updates those entities.
- Disabled sensors get an empty retained message published, which removes the old retained payload from the broker and tells HA to delete those entities.
This means disabling a sensor in .env and restarting the bridge is enough -- HA will drop that entity automatically within a few seconds.
Full reset -- if you want to remove every Tibber entity from HA and start completely fresh, run:
yarn resetThis publishes an empty retained message to every discovery topic (enabled and disabled alike). After it completes, restart the bridge normally and only the sensors enabled in .env will be re-created.
yarn startThe image is published to the GitHub Container Registry and runs on both amd64 and arm64 (e.g. Raspberry Pi).
The container reads all configuration from an env file. Start from the template:
cp .env.example .env
# Then open .env and fill in at minimum:
# TIBBER_TOKEN=...
# TIBBER_HOME_ID=...
# MQTT_URL=mqtt://192.168.1.x:1883See the Configuration section for all available variables.
Place your .env file in the same directory as docker-compose.yml, then run:
docker compose up -dDocker Compose automatically picks up the .env from that directory (via the env_file: .env line in the compose file) and passes all variables into the container. The container restarts automatically if it crashes.
To follow logs:
docker compose logs -fIf you prefer to run the container directly without Compose:
docker run -d \
--name tibber-ha-mqtt \
--env-file /path/to/your/.env \
--restart unless-stopped \
ghcr.io/orangecoding/tibber-ha-mqtt:latestReplace /path/to/your/.env with the absolute path to your env file. The --env-file flag must point to the file on the host machine -- it is not copied into the image.
All sensors are published under the Tibber Energy Source device in Home Assistant.
Sensors marked with * are meter-dependent -- they may have no value if your electricity meter does not report that measurement.
Instantaneous power
.env key |
Sensor name | Unit | Description |
|---|---|---|---|
SENSOR_POWER |
Power | W | Grid consumption right now |
SENSOR_POWER_PRODUCTION |
Power Production | W | Grid export right now (e.g. solar) * |
SENSOR_POWER_REACTIVE |
Power Reactive | kvar | Reactive power drawn from grid right now * |
SENSOR_POWER_PRODUCTION_REACTIVE |
Power Production Reactive | kvar | Reactive power exported to grid right now * |
SENSOR_POWER_FACTOR |
Power Factor | -- | Ratio of real to apparent power, 0.0-1.0 * |
Daily min / average / max (reset at midnight)
.env key |
Sensor name | Unit | Description |
|---|---|---|---|
SENSOR_AVERAGE_POWER |
Average Power | W | Average grid consumption since midnight |
SENSOR_MIN_POWER |
Min Power | W | Lowest instantaneous consumption since midnight |
SENSOR_MAX_POWER |
Max Power | W | Highest instantaneous consumption since midnight |
SENSOR_MIN_POWER_PRODUCTION |
Min Power Production | W | Lowest instantaneous export since midnight * |
SENSOR_MAX_POWER_PRODUCTION |
Max Power Production | W | Highest instantaneous export since midnight * |
Accumulated energy (reset at midnight / top of each hour)
.env key |
Sensor name | Unit | Description |
|---|---|---|---|
SENSOR_ACCUMULATED_CONSUMPTION |
Accumulated Consumption | kWh | Total drawn from grid since midnight |
SENSOR_ACCUMULATED_PRODUCTION |
Accumulated Production | kWh | Total exported to grid since midnight |
SENSOR_ACCUMULATED_CONSUMPTION_LAST_HOUR |
Accumulated Consumption Last Hour | kWh | Drawn from grid since the last full hour |
SENSOR_ACCUMULATED_PRODUCTION_LAST_HOUR |
Accumulated Production Last Hour | kWh | Exported to grid since the last full hour |
Cost (requires an active Tibber power deal; otherwise no value)
.env key |
Sensor name | Description |
|---|---|---|
SENSOR_ACCUMULATED_COST |
Accumulated Cost | Electricity cost since midnight, VAT included (account currency) |
SENSOR_ACCUMULATED_REWARD |
Accumulated Reward | Production reward earned since midnight (account currency) |
Per-phase measurements *
.env key |
Sensor name | Unit | Description |
|---|---|---|---|
SENSOR_CURRENT_L1 |
Current L1 | A | Current on phase 1 |
SENSOR_CURRENT_L2 |
Current L2 | A | Current on phase 2 |
SENSOR_CURRENT_L3 |
Current L3 | A | Current on phase 3 |
SENSOR_VOLTAGE_L1 |
Voltage L1 | V | Voltage on phase 1 |
SENSOR_VOLTAGE_L2 |
Voltage L2 | V | Voltage on phase 2 |
SENSOR_VOLTAGE_L3 |
Voltage L3 | V | Voltage on phase 3 |
Device and meter state
.env key |
Sensor name | Unit | Description |
|---|---|---|---|
SENSOR_SIGNAL_STRENGTH |
Signal Strength | dBm | Tibber Pulse signal strength * |
SENSOR_LAST_METER_CONSUMPTION |
Last Meter Consumption | kWh | Electricity meter all-time import total (never resets) * |
SENSOR_LAST_METER_PRODUCTION |
Last Meter Production | kWh | Electricity meter all-time export total (never resets) * |
Set NTFY_URL in .env to receive push notifications when the bridge loses connectivity:
NTFY_URL=https://ntfy.sh/my-private-topic-12345Three alert categories are tracked independently with a 30-minute cooldown each:
- tibber-disconnect -- Tibber WebSocket connection lost after multiple retries
- mqtt-disconnect -- MQTT broker unreachable
- stale-data -- No measurements received within the timeout window
To receive alerts on your phone, install the ntfy app and subscribe to the same topic.
Create /etc/systemd/system/tibber-ha-mqtt.service:
[Unit]
Description=Tibber MQTT Bridge
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=YOUR_USERNAME
WorkingDirectory=/path/to/tibber-ha-mqtt
ExecStart=/usr/bin/node src/index.js
Restart=always
RestartSec=10
EnvironmentFile=/path/to/tibber-ha-mqtt/.env
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetThen enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable tibber-ha-mqtt
sudo systemctl start tibber-ha-mqtt
# Check logs
sudo journalctl -u tibber-ha-mqtt -fdocker run -d \
--name tibber-ha-mqtt \
--restart unless-stopped \
--env-file .env \
node:22-alpine \
sh -c "yarn inst && yarn start"# Run tests
yarn test
# Lint
yarn lint
# Format
yarn format