Guides¶
Practical guides for integrating, deploying, and operating vito2mqtt.
Home Assistant Integration¶
vito2mqtt publishes telemetry as JSON to MQTT topics that Home Assistant can consume directly via the MQTT integration.
Temperature sensors¶
mqtt:
sensor:
- name: "Outdoor Temperature"
state_topic: "vito2mqtt/vitodens200w/outdoor/state"
value_template: "{{ value_json.outdoor_temperature }}"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
- name: "Hot Water Temperature"
state_topic: "vito2mqtt/vitodens200w/hot_water/state"
value_template: "{{ value_json.hot_water_temperature }}"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
- name: "Boiler Temperature"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.boiler_temperature }}"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
- name: "Exhaust Temperature"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.exhaust_temperature }}"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
Burner statistics¶
mqtt:
sensor:
- name: "Burner Starts"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.burner_starts }}"
state_class: total_increasing
- name: "Burner Hours"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.burner_hours_stage1 }}"
unit_of_measurement: "h"
state_class: total_increasing
- name: "Burner Modulation"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.burner_modulation }}"
unit_of_measurement: "%"
- name: "Plant Power Output"
state_topic: "vito2mqtt/vitodens200w/burner/state"
value_template: "{{ value_json.plant_power_output }}"
unit_of_measurement: "%"
Hot water setpoint control¶
mqtt:
number:
- name: "Hot Water Setpoint"
command_topic: "vito2mqtt/vitodens200w/hot_water/set"
command_template: '{"hot_water_setpoint": {{ value }}}'
min: 30
max: 60
step: 1
unit_of_measurement: "°C"
device_class: temperature
No telemetry feedback for hot_water_setpoint
The hot_water_setpoint signal is not included in the hot_water telemetry
group (which only publishes hot_water_temperature and
hot_water_outlet_temperature). It is available via the command interface, but
its current value is not published in MQTT telemetry, so the HA number entity
will not show the current boiler value based on telemetry alone. To track the
current setpoint, you can either read it explicitly using the command interface
or rely on HA's optimistic mode.
Error status¶
mqtt:
binary_sensor:
- name: "Boiler Error"
state_topic: "vito2mqtt/vitodens200w/diagnosis/state"
value_template: "{{ value_json.error_status }}"
payload_on: 1
payload_off: 0
device_class: problem
Docker Deployment¶
Docker Compose¶
services:
vito2mqtt:
image: ghcr.io/ff-fab/vito2mqtt:latest
restart: unless-stopped
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
env_file:
- .env
environment:
- VITO2MQTT_SERIAL_PORT=/dev/ttyUSB0
- VITO2MQTT_MQTT__HOST=mosquitto
- VITO2MQTT_MQTT__TLS=${VITO2MQTT_MQTT__TLS:-false}
depends_on:
- mosquitto
mosquitto:
image: eclipse-mosquitto:2
restart: unless-stopped
ports:
- "127.0.0.1:1883:1883"
volumes:
- mosquitto-data:/mosquitto/data
- mosquitto-config:/mosquitto/config
volumes:
mosquitto-data:
mosquitto-config:
Device permissions
The container needs access to the serial device. Ensure the container user has
read/write permissions on /dev/ttyUSB0. You may need to add the user to the
dialout group or use privileged: true (not recommended for production).
Dockerfile (from source)¶
FROM python:3.14-slim
RUN pip install uv
WORKDIR /app
COPY . .
RUN uv sync --no-dev
CMD ["uv", "run", "vito2mqtt"]
Common Recipes¶
Adjusting hot water temperature¶
Publish a JSON payload to the hot water command topic:
# Set hot water target to 55°C
mosquitto_pub -h localhost \
-t 'vito2mqtt/vitodens200w/hot_water/set' \
-m '{"hot_water_setpoint": 55}'
The read-before-write optimization checks the current value first. If the boiler
is already set to 55°C, no write occurs. Use "__force": true to write regardless.
Setting heating schedule timers¶
Timer signals use the CycleTime (CT) format — 4 on/off slot pairs per day:
# Set Monday radiator schedule: heat 06:00–08:30 and 17:00–22:00
mosquitto_pub -h localhost \
-t 'vito2mqtt/vitodens200w/heating_radiator/set' \
-m '{
"timer_m1_monday": [
[[6, 0], [8, 30]],
[[17, 0], [22, 0]],
[[null, null], [null, null]],
[[null, null], [null, null]]
]
}'
Unused slots must be [null, null]. Each day has exactly 4 pairs of 2 time slots,
where each slot is [hours, minutes] with int or null elements.
What to expect after a write¶
Commands are never acknowledged on their own topic — the boiler's state is
published by telemetry only. Since a successful write now wakes its own
telemetry group, that refresh happens within seconds instead of at the next
poll (which for the system group is an hour by default).
Two things are worth knowing before you go looking for a value:
- A group's
/setsignals are not the same signals as its/statesignals. Writingheating_curve_gradient_m1does not make that value appear onheating_radiator/state; it changes what the boiler reports forflow_temperature_setpoint_m1. You are watching for the boiler's reaction, not for an echo. - Nothing is published if nothing changed. State is published on change, so a write the boiler has not yet acted on produces no message until it has, or until the next scheduled poll.
Writes that the read-before-write guard suppresses do not trigger a refresh at all — there was no write. Bursts of writes are throttled to one extra read per group per 15 seconds so a full weekly schedule (seven payloads) cannot saturate the serial bus; the last write is still picked up.
Checking error history¶
Subscribe to the diagnosis state topic:
Error history entries (ES type) are returned as objects with error and timestamp
fields, where error is a human-readable description:
{
"error_status": 0,
"error_history_1": { "error": "Flame loss during operation", "timestamp": "2026-01-15T14:30:00" },
"error_history_2": { "error": "Flow sensor fault", "timestamp": "2025-12-03T08:15:00" }
}
A value of 0 for error_status means no active error.
Monitoring burner efficiency¶
Track burner starts and operating hours to assess cycling behavior:
Key metrics:
burner_starts— Total number of burner ignitions. High starts/hour indicates short cycling.burner_hours_stage1— Total stage 1 operating hours.burner_modulation— Current modulation percentage (0–100%). Low sustained modulation suggests oversized output.plant_power_output— Overall power output percentage.
Efficiency tracking
Calculate the average run time per start: burner_hours_stage1 / burner_starts.
Values below 5 minutes suggest the boiler is short-cycling, which reduces
efficiency and increases wear.
Troubleshooting¶
Serial port permission denied¶
Symptom: PermissionError: [Errno 13] Permission denied: '/dev/ttyUSB0'
Fix: Add your user to the dialout group:
Or set permissions directly (temporary):
MQTT connection refused¶
Symptom: ConnectionRefusedError or timeout when connecting to broker.
Checklist:
- Verify the broker is running:
systemctl status mosquitto - Check
VITO2MQTT_MQTT__HOSTis correct (hostname/IP, not URL) - Check
VITO2MQTT_MQTT__PORTmatches the broker's listener port - If using authentication, verify
VITO2MQTT_MQTT__USERNAMEandVITO2MQTT_MQTT__PASSWORD - Check firewall rules allow connections on the MQTT port
P300 protocol timeout¶
Symptom: Timeout errors during Optolink communication.
Possible causes:
- Wrong baud rate — The Vitodens 200-W uses 4800 baud (default). Ensure
VITO2MQTT_SERIAL_BAUD_RATE=4800. - Adapter not connected — Verify the Optolink adapter is seated correctly on the boiler's service port.
- USB adapter issue — Try unplugging and reconnecting the USB adapter. Check
dmesg | tailfor USB device errors. - Multiple readers — Only one application can use the serial port at a time. Ensure no other Optolink software is running.
No data on MQTT topics¶
Symptom: Subscribed to topics but no messages arrive.
Checklist:
- Verify vito2mqtt is running and connected (check log output)
- Confirm topic structure:
vito2mqtt/vitodens200w/+/state - Check
VITO2MQTT_DEVICE_IDmatches what you're subscribing to (default:vitodens200w) - Try dry-run mode to isolate serial vs. MQTT issues:
uv run vito2mqtt --dry-run