Vaillant Smart Server: A Flask API for OpenHAB Integration (Gas & Heat Pump Support)

Hello everyone,

I’ve developed a Flask-based API server for integrating Vaillant heating systems with OpenHAB. The project is available on GitHub:
:backhand_index_pointing_right: Vaillant Smart Server

Why did I build this?

I own a Vaillant hybrid system with both a heat pump and a condensing gas boiler. However, in recent updates, the official Vaillant mobile app removed the ability to see data from the secondary generator, meaning I can no longer track gas consumption—only the heat pump’s electricity usage is displayed.

The only official way to access this data is through EEBUS, which is complex to set up and requires additional compatible hardware.

How does this work?

This server uses myPyllant (a Python library for interacting with Vaillant APIs) to expose key system data via a simple Flask API.

It can run with Gunicorn for production deployment and can be used to:
:check_mark: Retrieve gas consumption
:check_mark: Get and update heating zone information
:check_mark: Monitor water pressure
:check_mark: Adjust zone temperatures and modes
:check_mark: Fetch system-wide data

The API can be easily integrated into OpenHAB using the HTTP binding. Below is an example configuration for my 3-zone setup:
Example OpenHAB Configuration
:pushpin: Thing file (vaillant.things)

Thing http:url:vaillant "Vaillant API" [
    baseURL="http://192.168.0.224:5000",
    refresh=10
] {
    Channels:
        Type number : gasConsumption "Consumo gas mese" [
            stateExtension="/boiler-consumption-current-month",
			stateTransformation="JSONPATH:$.consumption_m3"
        ]

        Type number : waterPressure "Pressione acqua" [
            stateExtension="/get-water-pressure",
			stateTransformation="JSONPATH:$.pressure"
        ]

        Type string : zone0Mode "Piano zero" [
            stateExtension="/zone-info/0",
            stateTransformation="JSONPATH:$.heating_state",
            commandExtension="/zone-update/0/%2$s",
            commandTransformation="JS:zone_mode.js"
        ]

        Type string : zone1Mode "Piano Terra" [
            stateExtension="/zone-info/1",
            stateTransformation="JSONPATH:$.heating_state",
            commandExtension="/zone-update/1/%2$s",
            commandTransformation="JS:zone_mode.js"
        ]

        Type string : zone2Mode "Mansarda" [
            stateExtension="/zone-info/2",
            stateTransformation="JSONPATH:$.heating_state",
            commandExtension="/zone-update/2/%2$s",
            commandTransformation="JS:zone_mode.js"
        ]

        Type number : zone0Temp "Seminterrato Temp" [
            stateExtension="/zone-info/0",
            stateTransformation="JSONPATH:$.current_temperature"
        ]

        Type number : zone1Temp "Piano Terra Temp" [
            stateExtension="/zone-info/1",
            stateTransformation="JSONPATH:$.current_temperature"
        ]

        Type number : zone2Temp "Mansarda Temp" [
            stateExtension="/zone-info/2",
            stateTransformation="JSONPATH:$.current_temperature"
        ]

        Type number : zone0TempSet "Seminterrato Temp desiderata" [
            stateExtension="/zone-info/0",
            stateTransformation="JSONPATH:$.desired_temperature",
            commandExtension="/zone-set-temp/0/%.1f",
            mode="READWRITE"
        ]

        Type number : zone1TempSet "Piano Terra Temp desiderata" [
            stateExtension="/zone-info/1",
            stateTransformation="JSONPATH:$.desired_temperature",
            commandExtension="/zone-set-temp/1/%2$s",
            mode="READWRITE"
        ]		
		
        Type number : zone2TempSet "Mansarda Temp desiderata" [
            stateExtension="/zone-info/2",
            stateTransformation="JSONPATH:$.desired_temperature",
            commandExtension="/zone-set-temp/2/%.1f",
            mode="READWRITE"
        ]			
}

:pushpin: Items file (vaillant.items)

Number Vaillant_GasConsumption "Consumo gas [%.2f m³]" <fire> { channel="http:url:vaillant:gasConsumption" }
Number Vaillant_WaterPressure "Pressione acqua [%.2f bar]" <water> { channel="http:url:vaillant:waterPressure" }

String Vaillant_Zone0Mode "Piano zero [%s]" <heating> { channel="http:url:vaillant:zone0Mode", autoupdate="false" }
String Vaillant_Zone1Mode "Piano Terra [%s]" <heating> { channel="http:url:vaillant:zone1Mode", autoupdate="false" }
String Vaillant_Zone2Mode "Mansarda [%s]" <heating> { channel="http:url:vaillant:zone2Mode", autoupdate="false" }

Number:Temperature Vaillant_Zone0Temp "Attuale [%.1f °C]" <temperature> { channel="http:url:vaillant:zone0Temp" }
Number:Temperature Vaillant_Zone1Temp "Attuale [%.1f °C]" <temperature> { channel="http:url:vaillant:zone1Temp" }
Number:Temperature Vaillant_Zone2Temp "Attuale [%.1f °C]" <temperature> { channel="http:url:vaillant:zone2Temp" }

Number Vaillant_Zone0TempSet "Impostata [%.1f °C]"	<temperature>	{ channel="http:url:vaillant:zone0TempSet", autoupdate="false" }
Number Vaillant_Zone1TempSet "Impostata [%.1f °C]"	<temperature>	{ channel="http:url:vaillant:zone1TempSet", autoupdate="false" }
Number Vaillant_Zone2TempSet "Impostata [%.1f °C]"	<temperature>	{ channel="http:url:vaillant:zone2TempSet", autoupdate="false" }

:pushpin: Sitemap file (vaillant.sitemap)

		Text label="Riscaldamento" icon="heating" {
			Text label="Info sistema" icon="settings" {
				Text item=Vaillant_GasConsumption
				Text item=Vaillant_WaterPressure
			}		
					
			Text label="Piano 0" icon="cellar"
			Text item=Vaillant_Zone0Temp
			Switch item=Vaillant_Zone0Mode mappings=["OFF"="Off", "MANUAL"="Manuale", "TIME_CONTROLLED"="Temporizzato"]
			Setpoint item=Vaillant_Zone0TempSet minValue=5 maxValue=30 step=0.5 visibility=[Vaillant_Zone0Mode=="MANUAL"]	
			Text item=Vaillant_Zone0TempSet	visibility=[Vaillant_Zone0Mode=="TIME_CONTROLLED"]		
			
			Text label="Piano terra" icon="groundfloor"
			Text item=Vaillant_Zone1Temp
			Switch item=Vaillant_Zone1Mode mappings=["OFF"="Off", "MANUAL"="Manuale", "TIME_CONTROLLED"="Temporizzato"]
			Setpoint item=Vaillant_Zone1TempSet minValue=5 maxValue=30 step=0.5 visibility=[Vaillant_Zone1Mode=="MANUAL"]	
			Text item=Vaillant_Zone1TempSet	visibility=[Vaillant_Zone1Mode=="TIME_CONTROLLED"]	

			Text label="Mansarda" icon="attic"
			Text item=Vaillant_Zone2Temp
			Switch item=Vaillant_Zone2Mode mappings=["OFF"="Off", "MANUAL"="Manuale", "TIME_CONTROLLED"="Temporizzato"]
			Setpoint item=Vaillant_Zone2TempSet minValue=5 maxValue=30 step=0.5 visibility=[Vaillant_Zone2Mode=="MANUAL"]	
			Text item=Vaillant_Zone2TempSet	visibility=[Vaillant_Zone2Mode=="TIME_CONTROLLED"]	
		}

Current Status & Future Improvements

:white_check_mark: The server is currently in testing but working well so far.
:rocket: Future plans include expanding functionality, improving performance, and possibly adding MQTT support for easier integration.

:light_bulb: Feedback and contributions are welcome! If you have a Vaillant system and want to test this, feel free to try it and share your thoughts!

3 Likes