-
Notifications
You must be signed in to change notification settings - Fork 31
Bauanleitung Optolink Adapter auf Basis ESP32 S3, C6 oder C3
Im Rahmen des Energiemanagements in unserem Haus war ich auf der Such nach einer Möglichkeit meine Wärmepumpe vom Typ Viessmann Vitocal 200-G BWP 108 abhängig von der Solar Produktion usw. steuern zu können. In der Community von https://github.com/openv/openv/wiki habe ich einige nützliche Tipps gefunden. Allen Beitragenden sei hiermit gedankt.
In den verschiedenen Bauanleitungen für Optolink Adapter fand ich nicht so genau das, was ich mir vorgestellt hatte. Ich wollte einen möglichst kleinen Adapter mit Wifi Anbindung bauen, der in die kleine Türe passte, welche die Wärmepumpe vor dem Bedienteil aufklappt und direkte ESPHome Unterstützung in Home Assistant mitbringt. Zudem sollte der verwendete Prozessor von der neusten Generation mit aktueller Konnektivität sein, damit die Arbeit, die ich da reinstecke, auch für noch weitere ESPHome Projekt nutzbar sein sollte. Meine Wahl fiel auf die ESP32 Prozessor Plattform und darin den ES32 S3 oder den ESP32 C6, welche beide auf einem kleinen Board (21 x 17.8mm) sehr kompakt daherkommen. Der ESP32 C6 bringt obendrein Wifi 6 und Zigbee mit, was für die Konnektivität viele Möglichkeiten offenlässt. Ein vollständiger Optolink Adapter mit Sender und Empfänger kann damit gerade mal mit den Dimensionen 4.0x2.5x0.5cm (LxBxH) aufgebaut werden. Als Erstes wagte ich mich an den Aufbau eines Optolink Adapters mit dem ESP32 S3 Board von Seeed Studio. Siehe https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/. Allerdings bin ich dabei auf ein paar unerwartete Schwierigkeiten bestossen, die ich mit dem GitHub Issue #699 «Probleme beim Senden resp. Empfangen mit Optolink Adapter auf Basis ESP32 S3» https://github.com/openv/openv/issues/699 protokolliert und zur Diskussion in der Community gestellt habe. Nach Langen Versuchen ist es mir dann doch noch gelungen die Optolink Kommunikation mit der Wärmepumpe aufzubauen. Die wesentlichen Erkenntnisse daraus sind: • Der Standard UART0 kann nicht für die Optolink Kommunikation verwendet werden. Wahrscheinlich wegen der internen Beschaltung auf dem Board in Zusammenhang mit dem USB-C Anschluss. • Die UART Konfiguration für die serielle Kommunikation muss so gesetzt werden, dass der für die Optolink Kommunikation benutzte UART1 nicht der erste in der Liste der UART Konfigurationen ist. UART0 muss der Erste in der Liste sein und explizit aufgeführt werden, auch wenn gar nicht verwendet. • Je nach Viessmann Gerät oder auch nur je nach dem eingesetzten ESP32 Board, muss die Baudrate angepasst werden. Bei meinen ESP32 S3 und C6 Boards auf 5040 Baud. • Eine Verstärkung von Sender und Empfänger mit Transistoren ist bei den ESP32 S3 und ESP32 C6 Boards nicht nötig. Selbst nicht bei Verwendung des Low Power UARTs auf dem ESP32 C6. • Der Abstand von Sender und Empfänger zum Gegenpart an der Wärmepumpe ist gar nicht so heikel. Mit 1.5cm Abstand läuft die Kommunikation immer noch.
ESP32 S3 und ESP32 C6 haben das gleiche Problem mit der Baudrate und den zwei UARTs, die konfiguriert werden müssen. Ich vermute, dass es beim ESP32 C3 dann auch so sein wird.
Diese Bauanleitung vom Optolink Adapter basiert auf den oben erwähnten Erfahrungen, die ich hiermit gerne an die Community weitergeben möchte.
https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
Die Prozessorleistung ist für die Optolink Kommunikation gar nicht so auschlaggebend. Wenn auf dem Board resp. auf dem Adapter nicht noch weitere Sensoren genutzt werden sollen, kann aus meiner heutigen Sicht auch das ESP32 C3 Board eingesetzt werden.
Laut Espressif Datenblatt bringt der ESP32 S3 Prozessor 3 Hardware UARTs mit, der ESP32 C6 2 HW UARTs und einen Low Power UART, der ESP32 C3 hat 2 HW UARTs. Alle drei Boards führen nur den UART0 direkt an die Löt-Pins. ESP32 C6 2 zusätzlich noch den Low Power UART (LP_UART). Über die GPIO Konfiguration kann jedoch auch der UART1 auf die Löt-Pins des Boards gemappt werden. Siehe z.B. Peripheral Pin Assignment vom ESP32 S3 in https://documentation.espressif.com/esp32-s3_datasheet_en.pdf Seite 27.
Die blau markierten GPIOs der Priorität P2 sind frei konfigurierbar. Für UART1 beim ESP32 S3 können dann z.B. GPIO1 und GPIO6 benutzt werden.
In Home Assistant unterstützt der ESPHome Builder die Prozessoren ESP32 S3, C6 und C3 direkt.
ESPHome Builder / New Device / New Device Setup …
In Anlehnung an die Bauanleitungen von https://github.com/JuergenLeber/home-assistant-optolink und https://github.com/openv/openv/wiki/ESPHome-Optolink und den Erfahrungen au meinen Erstversuchen habe ich mir einen Optolink Adapter mit einem seeed studio ESP32 S3 nach folgendem Schaltplan und Pin Belegung aufgebaut.
Pin Liste ESP32 S3
Die Stückliste für die Beschaltung des Optolink Adapters, wie ESP32 Board, Widerstände, Sender IR-LED und Empfänger Photo-Transistor usw. wurde in Anlehnung an https://github.com/JuergenLeber/home-assistant-optolink aufgebaut.
• Streifenrasterplatine, Hartpapier, z.B. 50x100mm (z.B. Reichelt) • https://www.reichelt.com/ch/de/shop/produkt/streifenrasterplatine_hartpapier_50x100mm-8275
• Xiao ESP32S3, Dual-Core, WiFi / BT5.0, ohne Header (z.B. Reichelt) https://www.reichelt.com/ch/de/shop/produkt/xiao_esp32s3_dual-core_wifi_bt5_0_ohne_header-358354 • Oder Xiao ESP32C6, WiFi 6 / BT5.0, Zigbee, Thread (z.B. Reichelt) • https://www.reichelt.com/ch/de/shop/produkt/xiao_esp32c6_wifi_6_bt5_0_zigbee_thread-379732 • Oder Xiao ESP32C3, WiFi / BT, ohne Header (z.B. Reichelt) • https://www.reichelt.com/ch/de/shop/produkt/xiao_esp32c3_wifi_bt_ohne_header-358356
• Banana Pi - 5dB Antenne (UFL Pigtail) (z.B. Reichelt) • https://www.reichelt.com/ch/de/shop/produkt/banana_pi_-_5db_antenne-152351 • Falls der WLAN Verbindung knapp sein sollte
• Fototransistor, NPN, 730...1120nm, 24°, THT-3mm SFH-309 FA (z.B. Reichelt) https://www.reichelt.de/ch/de/shop/produkt/fototransistor_npn_730_1120nm_24_tht-3mm-60553
• Infrarot-Diode, GaAlAs, 880 nm, 50°, 3 mm, T1L-7104SF4BT KB (z.B. Reichelt) https://www.reichelt.de/ch/de/shop/produkt/infrarot-diode_gaalas_880_nm_50_3_mm_t1-216819 • Oder gleich paarweise von Aliexpress: SFH487-2 GaAlAs Infrarot Emitter SFH309FA Silizium NPN Fototransistor SFH487 SFH309 SFH DIP-2 original (880nm) • https://de.aliexpress.com/item/1005003481028413.html?spm=a2g0o.order_list.order_list_main.67.3cf75c5fz2aIL6&gatewayAdapt=glo2deu#nav-specification
• Widerstand, Kohleschicht, 180 Ohm, 0207, 250 mW, 5% (z.B. Reichelt) https://www.reichelt.de/ch/de/shop/produkt/widerstand_kohleschicht_180_ohm_0207_250_mw_5_-1362
• Widerstand, Kohleschicht, 10 kOhm, 0207, 250 mW, 5% (z.B. Reichelt) https://www.reichelt.de/ch/de/shop/produkt/widerstand_kohleschicht_10_kohm_0207_250_mw_5_-1338
• Stifte / Draht zum durchkontaktieren der genutzten ESP32 Pins auf die Streifenrasterplatine • Schaltdraht 1.5mm2 für die Konstruktion der Viessmann-V-Befestigung • Schrumpfschlauch gross zur elektrischen Insolation der Platine • 2 Stück Schrumpfschlauch klein zur optischen Insolation von Sender und Empfänger
Die Bauanleitung geht davon aus, dass der ESP32 ohne Stiftleiste verbaut wird, resp. nur die 4 Pins angelötet werden, die auch benötigt werden. GND, 3V3, RX und TX. Die Streifenrasterplatine ist in der Abbildung mit der Kupfer Seite nach oben zu den Bauteilen dargestellt, zur besseren Sichtbarkeit der Kupferbahnen und damit der Verbindungen der Board Pins. Für den effektiven Bau des Adapters muss die Platine natürlich umgedreht werden. Beim weissen Balken sollte die Kupferbahn unterbrochen werden. Ansonsten werden über die Drahtbrücken vom V drei Kupferbahnen miteinander verbunden und führen damit alle 3V3.
Beim weissen Balken sollte die Kupferbahn unterbrochen werden. Ansonsten werden über die Drahtbrücken vom V drei Kupferbahnen miteinander verbunden und führen damit alle 3V3.
ESP32 S3 und ESP32 C6 wurden mit diesem Aufbau schon getestet. Mit dem gleichen Layout müsste aber auch der ESP32 C3 eingesetzt werden können. Beim ESP32 C6 könnte alternativ auch der LP_UART (auch ohne Verstärker-Transistoren) verwendet werden. Aber für das Layout des Adapters wird auch hier mit den GPIOs gearbeitet. Weil einfacher zu löten und für den Adapter kann so das genau gleiche Layout verwendet werden wie beim ESP32 S3.
Damit der Adapter einfacher bestückt und verlötet werden kann, würde ich empfehlen, dass der Reihe nach die Bauteile mit der geringsten Bauhöhe eingesetzt werden.
- Widerstände
- ESP32 Board (die 4 benutzten Pins GND, 3V3, RX und TX mit Stiften in der Platine durchkontaktieren und auf Ebene Streifenrasterplatine und dann ESP32 Board anlöten)
- IR-LED und Photo-Transistor (für diese beiden Bauteile habe ich für meine Wärmepumpe einen kleinen Distanzhalter unterlegt, damit der USB-C Stecker, der an das Board gesteckt wird, dann noch an der Front vom Bedienteil der Wärmepumpe vorbeikommt. Allenfalls die IR-LED oder dann den Photo-Transistor in erster Phase über ein kurzes Kabel verlöten, damit die Schaltung vor dem Anschluss an die Heizung getestet und ausgemessen werden kann. Siehe auch Kapitel «Testen Adapter»).
- Schaltdraht-Bügel für Nachbildung des Viessmann V (für das Einlöten muss die Bohrung in der Platine ein wenig aufgebohrt werden.
Da ich leider nicht im Besitz eines 3D Druckers bin, verzichte ich auf ein Gehäuse und behelfe mich ganz einfach mit einem Schrumpfschlauch. Eine Anleitungen zum eigenen Gehäuse mit integriertem Viessmann-V findet sich z.B. unter https://github.com/openv/openv/wiki/ESPHome-Optolink
Im Weiteren werden zur optischen Isolation der Sender IR LED und des Empfänger Photo Transistors je ein kleiner Schrumpfschlauch aufgesteckt, damit keine Lichteinflüsse der Umgebung die Signale stören können.
Nach dem Zusammenbau hat es sich bewährt den Adapter mindesten dem folgenden, einfachen Test zu unterziehen. Somit kann sichergestellt werden, dass die Hardware vom gebauten Adapter funktioniert, bevor weitere Funktionen in der ESPHome Software umgesetzt werden.
Zum Prüfen von Sender und Empfänger kann nachfolgendes ESPHome YAML verwendet werden. Über den Sender Switch auf dem Home Assistant Device oder auf der Web Seite des ESP32 Devices (IP Adresse des ESPHome Devices) kann die Sender IR LED ein- oder ausgeschaltet werden.
esphome:
name: vitocal-200
friendly_name: Vitocal 200
esp32:
# board: esp32dev #-- for example ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
board: esp32-s3-devkitc-1 #-- ESP32 S3 https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
framework:
type: esp-idf
#-- Enable logging
logger:
hardware_uart: UART0
baud_rate: 0 #-- deactivate the logging to UART0 with a baudrate value of 0. Even if you deactivate logging on UART0, the log outputs can be seen on the local computer via the esphome command line utility
level: DEBUG #-- level shoult be set. otherwise Level DEBUG (Default) is active also for ESPHome Output
#-- Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
#-- Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Vitocal-200 Fallback Hotspot"
password: ""
captive_portal:
web_server:
port: 80
binary_sensor:
- name: "Optolink Receiver (Photo-Transistor)"
platform: gpio
pin: GPIO01 #-- ESP32 S3 RX UART1
#pin: GPIO44 #-- ESP32 S3 RX UART0
#pin: GPIO16 #-- ESP32 Wemos D1 RX UART1
on_press:
then:
- logger.log: "---- Receiver on_press"
switch:
- name: "Optolink Sender (IR-LED)"
platform: gpio
pin: GPIO06 #-- ESP32 S3 TX UART1
#pin: GPIO43 #-- ESP32 S3 TX UART0
#pin: GPIO17 #-- ESP32 Wemos D1 TX UART1
Mit der Smartphone Kamera kann die Sender IR-LED einfach getestet werden. Die Kamera zeigt auch Anteile vom Infrarotlicht. Es wird ein leicht violettes Licht sichtbar.

Werden Sender und Empfänger optisch kurzgeschlossen wie in folgender Abbildung,
wird der gesendete Zustand optisch auf den Empfänger übertragen. Damit kann die ganze Strecke Sender --> Empfänger getestet werden.
Das gleiche YAML kann für das elektronische Ausmessen der ganzen Beschaltung des Adapters verwendet werden. Siehe auch Kapitel Schalplan.
Für das Testen im Betrieb mit der Wärmepumpe oder anderen Viessmann Gräten mit Optolink Schnittstelle wird der Adapter auf die Optolink Schnittstelle montiert.

Wichtig dabei ist, dass der Adapter so montier wird, dass die Position der IR-RED und des Photo-Transistors vom Adapter mit dem Viessmann Gerät übereinstimmt. Wobei Sender und Empfänger vom Viessmann Gerät natürlich gekreuzt gegenüber liegen. Die folgenden Abbildung zeigt die Sender IR-LED der Wärmepumpe, die sichtbar immer grün leuchtet, mit dem Empfänger Photo-Transistor des Adapters.
Mit dem nachfolgen aufgeführten Mini Tool (YAML für ESPHome Builder) kann die Kommunikation über den Optolink Adapter mit dem Viessmann Gerät überprüft werden. Mit dem Mini Tool ist es auch möglich die initial im YAML konfigurierte Baudrate zur Laufzeit zu verändern.
#=============================================================================
# Title : Mini Tool for Testing Optolink Adapter
# Purpose : Provides functions in ESPHome for testing optolink communication with Viessmann heating devices.
# The web user interface can be reached by opening a browser at IP address where the ESP32 is connected to.
# For the communication with the Viessmann heating devices the KW/VS1-Protokoll is used. https://github.com/openv/openv/wiki/Protokoll-KW
# With great help from the community on https://github.com/openv/openv.
# Requirements: ESP8266 and ESP32 Microcontroller and optolink adapter with optical sender and receiver for example:
# https://github.com/openv/openv/wiki/ESPHome-Optolink or https://github.com/JuergenLeber/home-assistant-optolink
# No custom components like optolink or esphome_vitoconnect are needed for this testing tool. So UART configuration is absolutely independent.
# Author : AutoLotion
#-----------------------------------------------------------------------------
# Version History
# | |
# 10.02.26|1.0|- First version for testing Optolink adapter on base off ESP32, ESP32 S3 or ESP32 C6.
# | |
#-----------------------------------------------------------------------------
# HA Core : 2026.1.3
# HA Supervisor : 2026.02.1
# HA Operating System : 17.0
# HA Frontend : 20260107.2
# ESPHome Device Builder : 2026.1.4
#=============================================================================
#-- ESPHome documentation https://next.esphome.io/components/
esphome:
name: vitocal-200
friendly_name: Vitocal 200
esp32:
# board: esp32dev #-- for example ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
board: esp32-s3-devkitc-1 #-- ESP32 S3 https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
framework:
type: esp-idf
#type: arduino #-- must be arduino for the optolink component, not esp-idf
#-- Enable logging
logger:
hardware_uart: UART0
baud_rate: 0 #-- deactivate the logging to UART0 with a baudrate value of 0. Even if you deactivate logging on UART0, the log outputs can be seen on the local computer via the esphome command line utility
level: DEBUG #-- level shoult be set. otherwise Level DEBUG (Default) is active also for ESPHome Output
#-- Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
#-- Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Vitocal-200 Fallback Hotspot"
password: ""
captive_portal:
#-- add the web server, if you want to access the user interface outside Home Assistant
web_server:
port: 80 #-- To reach the web user interface, open browser on IP address where the esp32 is connected to the network.
globals:
- id: telegram_list_g
type: std::vector<std::array<uint16_t, 4>>
#initial_value: "std::vector<std::array<uint16_t, 3>>{ { {1,2,3} }, { {4,5,6} }, { {7,8,9} } }"
initial_value: "std::vector<std::array<uint16_t, 4>>{}" #-- command, address, number_bytes, new_value (for setting new values)
uart:
#-- for ESP32 S3 UART0 can not be used for optolink adapter. Nevertheless UART0 MUST be configured for example as dummy. It MUST be the first in the list of the configuration of UART Buses
#-- for other ESP32 Boards this UART configuration can be deleted
- id: uart_dummy
rx_pin: GPIO44 #-- ESP32 S3 UART0 RX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
tx_pin: GPIO43 #-- ESP32 S3 UART0 TX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 2
debug:
dummy_receiver: true
direction: BOTH
#-- uart configuration for communicaton with Viessmann heating device througth optolink adapter
#-- for ESP32 S3 the UART for the optolink adapter MUST be UART1, It MUST be configured as second in the list of the configuration of UART Buses
- id: uart_optolink
rx_pin: GPIO01 #-- ESP32 S3 general GPIO as RX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
tx_pin: GPIO06 #-- ESP32 S3 genenal GPIO as TX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
# rx_pin: GPIO16 #-- RX Pin for ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
# tx_pin: GPIO17 #-- TX Pin for ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
#-- Die Optolink Schnittstelle wird immer mit 4800 bps, 8 Bits, Even Parity (gerade Parität) und 2 Stopbits (4800,8,E,2) betrieben.
#-- https://github.com/openv/openv/wiki/Die-Optolink-Schnittstelle
baud_rate: 5040 #-- for some ESP32 S3 boards 4800 baud will not work, some how 5040 baud do work.
data_bits: 8
parity: EVEN
stop_bits: 2
debug:
dummy_receiver: true #-- true means read and log also received data. If an external component like optolink or vitoconnect is used, set it to false
direction: BOTH
sequence:
#----------------------------------------------------------------------------------------
#-- This coummunication code uses the optolink protocoll KW (VS1) for requesting data by telegrams from a Viessmann heating devices
#-- https://github.com/openv/openv/wiki/Protokoll-KW
#-- For getting data from the device a telegram sent to the device must have the following format, example: "Device ID": 01F700F802, or "Aussentemperatur": 01F7080002
#----------------------------------------------------------------------------------------
- lambda: |-
//-- Log all sent and received bytes
//UARTDebug::log_string(direction, bytes);
UARTDebug::log_hex(direction, bytes, ':');
//UARTDebug::log_int(direction, bytes, ',');
//ESP_LOGD("UART Debugging", "Bytes size: %d", bytes.size());
if ((direction == UART_DIRECTION_RX) && (bytes.size() == 1)) //-- check for received singel bytes
{
//-- wait for periodic 0x05 from heating device
if (bytes[0] == 0x05) {
//-- after 0x05 has been received, send telegram immediately
//uint8_t request[] = {0x01, 0xF7, 0x00, 0xF8, 0x02};
//id(uart_optolink).write_array(request, sizeof(request));
//-- get data from global telegram list
if (!id(telegram_list_g).empty()) {
uint8_t command = id(telegram_list_g).front()[0];
uint16_t address = id(telegram_list_g).front()[1];
uint8_t no_bytes = id(telegram_list_g).front()[2];
//ESP_LOGD("uart", "----- !id(telegram_list_g).empty(), command: %02X Address: %04X, no_bytes: %02X", command, address, no_bytes);
if (command == 0xF7) {
uint8_t telegram[5];
telegram[0] = 0x01; //-- initiate optolink communication sequence
telegram[1] = command; //-- set command (0xF7=request value, 0xF4=set values)
telegram[2] = (uint8_t)(address >> 8) & 0xFF; //-- get high byte of address
telegram[3] = (uint8_t)(address & 0xFF); //-- get low byte of address
telegram[4] = no_bytes;
//-- log uart writing separately to log output, because we are inside the debug sequence
ESP_LOGD("uart", "----- >>> %02X:%02X:%02X:%02X:%02X", telegram[0], telegram[1], telegram[2], telegram[3], telegram[4]);
id(uart_optolink).write_array(telegram, sizeof(telegram)); //-- write telegram to uart
}
id(telegram_list_g).erase(id(telegram_list_g).begin()); //-- erase the processed telegram from the global list
} else {
//id(uart_optolink).write_byte(0x04); //-- keep sync alive
//-- log uart writing separately to log output, because we are inside the debug sequence
//ESP_LOGD("uart", "----- >>> 04");
}
}
//std::string str(bytes.begin(), bytes.end()); //-- Pack all received bytes into a string
//id(test_rec).publish_state(str.c_str()); //-- Publish results to an existing text sensor.
}
number:
- platform: template
name: "201: Baudrate uart_optolink"
id: baud_rate_uart_optolink
mode: BOX
optimistic: True
min_value: 4000
max_value: 6000
step: 10
initial_value: 5040
on_value:
then:
- lambda: |-
//uint32_t new_baud_rate = stoi(x);
uint32_t new_baud_rate = (uint32_t) x;
ESP_LOGD("change_baud_rate", "Changing baud rate from %i to %i",id(uart_optolink).get_baud_rate(), new_baud_rate);
id(uart_optolink).flush();
if (id(uart_optolink).get_baud_rate() != new_baud_rate) {
id(uart_optolink).set_baud_rate(new_baud_rate);
id(uart_optolink).load_settings();
}
button:
#----------------------------------------------------------------------------------
#-- several functions with hard-coded addresses
#----------------------------------------------------------------------------------
- platform: template
name: "180: Get Device Info at Address 0x00F8"
icon: "mdi:button-pointer"
on_press:
then:
#- uart.write: [0x01,0xF7, 0x00, 0xF8, 0x08]
- lambda: |-
uint8_t command = 0xF7;
uint16_t address = 0x00F8;
uint8_t no_bytes = 8;
id(telegram_list_g).push_back({{command, address, no_bytes, 0}}); //-- add telegram to global list
- platform: template
name: "181: Get Aussentemperatur at Address 0x0800"
icon: "mdi:button-pointer"
on_press:
then:
#- uart.write: [0x01, 0xF7, 0x08, 0x00, 0x02]
- lambda: |-
uint8_t command = 0xF7;
uint16_t address = 0x0800;
uint8_t no_bytes = 2;
id(telegram_list_g).push_back({{command, address, no_bytes, 0}}); //-- add telegram to global list
- platform: template
name: "190: Send 0x04 to sync Optolink Protocol"
icon: "mdi:button-pointer"
on_press:
then:
- lambda: |-
id(uart_optolink).write_byte(0x04);
interval:
- interval: 30s
startup_delay: 0s
then:
#-- log actual baud rate of the active uarts
- logger.log:
format: "----- Baudrate uart_dummy: %i"
args: [ 'id(uart_dummy).get_baud_rate()' ]
- logger.log:
format: "----- Baudrate uart_optolink: %i"
args: [ 'id(uart_optolink).get_baud_rate()' ]
- interval: 30s #-- interval for periodic request data from heating device
startup_delay: 10s
then:
#- logger.log: "----- Interval: Get Device Info"
- lambda: |-
//id(telegram_list_g).push_back({{0xF7, 0x00F8, 8, 0}}); //-- get "Device Info" (8 bytes)
- delay: 2s
#- logger.log: "----- Interval: Get Aussentemperatur"
- lambda: |-
//id(telegram_list_g).push_back({{0xF7, 0x0800, 2, 0}}); //-- get "Aussentemperatur"
Ist der Adapter richtig an das Viessmann Gerät montiert und das Mini Tool über den Home Assistant ESPHome Builder aktiviert, ist auch automatisch der Empfang aktiviert und wird geloggt. Das Viessmann Gerät sendet periodisch 0x05 (ca. jede Sekunde, KW Protokoll) über die Optolink Schnittstelle. Das ist über den Log Output des Mini Test Tools ersichtlich. Das würde erst mal heissen, der Empfang funktioniert grundsätzlich. Das Mini Tool basiert auf den Kommunikationsprotokoll KW. Siehe auch https://github.com/openv/openv/wiki/Protokoll-KW.
Das Mini Tool stellt Benutzer Funktionen zum Abfragen von der vollständigen Geräte Info (8 Bytes) und der Aussentemperatur zur Verfügung, die in vielen Viessmann Geräten auf der gleichen Adresse liegen. Siehe auch https://github.com/openv/openv/wiki/Adressen.
Nach dem Installieren des Devices in Home Assistant ESPHome Builder, oder auch wenn das Log über den Home Assistant ESPHome Builder aktiviert wird, sollte folgende Log Output erscheinen:
[18:11:45.104][I][app:206]: ESPHome version 2026.1.4 compiled on 2026-02-10 18:10:39 +0100
[18:11:45.107][I][app:213]: ESP32 Chip: ESP32-S3 r0.2, 2 core(s)
[18:11:45.107][C][logger:316]: Logger:
[18:11:45.107][C][logger:316]: Max Level: DEBUG
[18:11:45.107][C][logger:316]: Initial Level: DEBUG
[18:11:45.113][C][logger:322]: Log Baud Rate: 0
[18:11:45.113][C][logger:322]: Hardware UART: UART0
[18:11:45.113][C][logger:332]: Task Log Buffer Size: 768 bytes
[18:11:45.156][C][uart.idf:238]: UART Bus 0:
[18:11:45.159][C][uart.idf:152]: TX Pin: GPIO43
[18:11:45.164][C][uart.idf:152]: RX Pin: GPIO44
[18:11:45.164][C][uart.idf:243]: RX Buffer Size: 256
[18:11:45.164][C][uart.idf:243]: RX Full Threshold: 3
[18:11:45.164][C][uart.idf:243]: RX Timeout: 2
[18:11:45.167][C][uart.idf:249]: Baud Rate: 4800 baud
[18:11:45.167][C][uart.idf:249]: Data Bits: 8
[18:11:45.167][C][uart.idf:249]: Parity: EVEN
[18:11:45.167][C][uart.idf:249]: Stop bits: 2
[18:11:45.172][D][api.connection:2221]: Home Assistant 2026.1.3 (192.168.30.100): connected
[18:11:45.176][C][uart.idf:238]: UART Bus 1:
[18:11:45.180][C][uart.idf:152]: TX Pin: GPIO6
[18:11:45.180][C][uart.idf:152]: RX Pin: GPIO1
[18:11:45.183][C][uart.idf:243]: RX Buffer Size: 256
[18:11:45.183][C][uart.idf:243]: RX Full Threshold: 3
[18:11:45.183][C][uart.idf:243]: RX Timeout: 2
[18:11:45.190][C][uart.idf:249]: Baud Rate: 5040 baud
[18:11:45.190][C][uart.idf:249]: Data Bits: 8
[18:11:45.190][C][uart.idf:249]: Parity: EVEN
[18:11:45.190][C][uart.idf:249]: Stop bits: 2
[18:11:45.194][C][template.number:016]: Template Number '201: Baudrate uart_optolink'
[18:11:45.196][C][template.number:049]: Optimistic: YES
[18:11:45.200][C][template.number:456]: Update Interval: 60.0s
…..
[18:12:04.239][D][uart_debug:113]: <<< 05
[18:12:05.261][D][uart_debug:113]: <<< 05
[18:12:06.280][D][uart_debug:113]: <<< 05
[18:12:07.300][D][uart_debug:113]: <<< 05
[18:12:08.338][D][uart_debug:113]: <<< 05
[18:12:09.358][D][uart_debug:113]: <<< 05
[18:12:10.278][D][main:284]: ----- Baudrate uart_dummy: 4800
[18:12:10.281][D][main:287]: ----- Baudrate uart_optolink: 5040
[18:12:10.383][D][uart_debug:113]: <<< 05
[18:12:11.398][D][uart_debug:113]: <<< 05
[18:12:12.436][D][uart_debug:113]: <<< 05
[18:12:13.456][D][uart_debug:113]: <<< 05
[18:12:14.477][D][uart_debug:113]: <<< 05
[18:12:15.513][D][uart_debug:113]: <<< 05
[18:12:16.534][D][uart_debug:113]: <<< 05
[18:12:27.364][D][button:022]: '180: Get Device Info at Address 0x00F8' Pressed.
[18:12:27.801][D][uart_debug:113]: <<< 05
[18:12:27.814][D][uart:145]: ----- >>> 01:F7:00:F8:08
[18:12:27.979][D][uart_debug:113]: <<< 20:00:45:00:04:00:16:00
[18:12:28.840][D][uart_debug:113]: <<< 05
[18:12:29.855][D][uart_debug:113]: <<< 05
[18:12:30.877][D][uart_debug:113]: <<< 05
[18:12:31.848][D][button:022]: '181: Get Aussentemperatur at Address 0x0800' Pressed.
[18:12:31.911][D][uart_debug:113]: <<< 05
[18:12:31.919][D][uart:145]: ----- >>> 01:F7:08:00:02
[18:12:32.084][D][uart_debug:113]: <<< 4C:00
[18:12:32.927][D][uart_debug:113]: <<< 05
[18:12:37.034][D][uart_debug:113]: <<< 05
[18:12:40.092][D][uart_debug:113]: <<< 05
[18:12:40.278][D][main:284]: ----- Baudrate uart_dummy: 4800
[18:12:40.285][D][main:287]: ----- Baudrate uart_optolink: 5040
Dabei wird initial auch die UART Bus Konfiguration ausbewiesen. UART Bus 1, welcher für die Optolink Kommunikation konfiguriert wurde, sollte der Zweite in der Auflistung sein. Im obigen Log sind auch die manuell ausgelösten Abfragen für Device Info und Aussentemperatur inklusive der zugehörigen Antworten von der Wärmepumpe protokolliert. Funktionieren die zwei grundsätzlichen Abfragen, steht der erweiterten Konfiguration für ein definitives ESPHome resp. Home Assistant Device nichts mehr im Weg.
Um das für die Optolink Kommunikation verwendete Protokoll (siehe auch https://github.com/openv/openv/wiki/Protokoll-KW) einfach umsetzen zu können, werden auf Github zwei ESPHome Komponenten (ESPHome Components) angeboten. • Optolink» Component • esphome_vitoconnect» Component
Unter https://github.com/openv/openv/wiki/ESPHome-Optolink wird eine ESPHome Component vorgestellt, die die Konfiguration von allen möglichen Sensoren ermöglicht. Inkl. setzen / schreiben von Werten. Leider verwaltet die Optolink Component seinen UART für die Optolink Kommunikation komplett selber inkl. Baudrate. Einzig die UART Pins, die für die Optolink Kommunikation verwendet werden sollen, können vorgeben werden. Damit kann die Baudrate nicht über den uart_bus Component in ESPHome gesetzt werden, falls das auch bei anderen Viessmann Geräten oder Prozessor Boards, als meinen, nötig sein sollte. Auch kann die Optolink Component auf dem ESP32 C6 nicht eingesetzt werden, wegen dem benötigten Arduino Framework, das vom ESPHome Builder für den ESP32 C6 nicht unterstützt wird.
Esphome_vitoconnect baut auf dem Framework esp-idf auf und die UART Parameter sind komplett im YAML konfigurierbar. Siehe auch https://github.com/dannerph/esphome_vitoconnect. Esphome_vitoconnect läuft damit auch mit vorgegebenen 5040 Baud. Leider sind in der originalen Plattform vitoconnect keine text und number Components für Optolink möglich. Nur sensor und binary_sensor. Auch ist original kein Setzen / Schreiben von Werten möglich.
Man kann sich jedoch für das Schreiben von Werten mit einer abgeleiteten Version behelfen, die hier vorgestellt wird: https://github.com/dannerph/esphome_vitoconnect/issues/13. Damit können auch number und switch Components für die Plattform vitoconnect konfiguriert werden. Für beide wird schreiben unterstützt.
Eine minimales Beispiel YAML würde dann so aussehen: esphome: name: vitocal-200 friendly_name: Vitocal 200
esp32:
# board: esp32dev #-- for example ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
board: esp32-s3-devkitc-1 #-- ESP32 S3 https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
# board: esp32-c6-devkitc-1 #-- ESP32 C6 https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
framework:
type: esp-idf
#-- Enable logging
logger:
hardware_uart: UART0
baud_rate: 0 #-- deactivate the logging to UART0 with a baudrate value of 0. Even if you deactivate logging on UART0, the log outputs can be seen on the local computer via the esphome command line utility
level: DEBUG #-- level shoult be set. otherwise Level DEBUG (Default) is active also for ESPHome Output
#-- Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
#-- Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Vitocal-200 Fallback Hotspot"
password: ""
captive_portal:
#-- add the web server, if you want to access the user interface outside Home Assistant
web_server:
port: 80 #-- To reach the web user interface, open browser on IP address where the esp32 is connected to the network.
uart:
#-- for ESP32 S3, C6 and C3 UART0 can not be used for optolink adapter. Nevertheless UART0 MUST be configured for example as dummy.
# It MUST be the first in the list of the configuration of UART Buses
#-- for other ESP32 Boards this UART configuration can be deleted
- id: uart_dummy
rx_pin: GPIO44 #-- ESP32 S3 UART0 RX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
tx_pin: GPIO43 #-- ESP32 S3 UART0 TX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
# rx_pin: GPIO17 #-- ESP32 C6 UART0 RX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# tx_pin: GPIO16 #-- ESP32 C6 UART0 TX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# rx_pin: GPIO20 #-- ESP32 C3 UART1 RX Pin https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/
# tx_pin: GPIO21 #-- ESP32 C3 UART1 TX Pin https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 2
debug:
dummy_receiver: true
direction: BOTH
#-- uart configuration for communicaton with Viessmann heating device througth optolink adapter
#-- for ESP32 S3 the UART for the optolink adapter MUST be UART1, It MUST be configured as second in the list of the configuration of UART Buses
- id: uart_optolink
# rx_pin: GPIO16 #-- RX Pin for ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
# tx_pin: GPIO17 #-- TX Pin for ESP32 WEMOS D1 MINI https://www.espboards.dev/esp32/d1-mini32/
rx_pin: GPIO01 #-- ESP32 S3 general GPIO as RX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
tx_pin: GPIO06 #-- ESP32 S3 genenal GPIO as TX Pin https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
# rx_pin: GPIO04 #-- ESP32 C6 LP_UART1 RX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# tx_pin: GPIO05 #-- ESP32 C6 LP_UART1 TX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# rx_pin: GPIO00 #-- ESP32 C6 UART1 RX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# tx_pin: GPIO23 #-- ESP32 C6 UART1 TX Pin https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
# rx_pin: GPIO02 #-- ESP32 C3 UART1 RX Pin https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/
# tx_pin: GPIO07 #-- ESP32 C3 UART1 TX Pin https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/
#-- Die Optolink Schnittstelle wird immer mit 4800 bps, 8 Bits, Even Parity (gerade Parität) und 2 Stopbits (4800,8,E,2) betrieben.
#-- https://github.com/openv/openv/wiki/Die-Optolink-Schnittstelle
baud_rate: 5040 #-- for some ESP32 S3 boards 4800 baud will not work, some how 5040 baud do work.
data_bits: 8
parity: EVEN
stop_bits: 2
# rx_buffer_size: 256 #-- (Optional, int): The size of the buffer used for receiving UART messages. Increase if you use an integration that needs to read big payloads from UART. Defaults to 256.
# rx_full_threshold: 4 #-- (Optional, int): ESP32 only. After receiving this number of bytes, the data becomes available for processing. The default is calculated at compilation time to be approximately ten milliseconds (about 8 bytes at 9600 baud, 114 bytes at 115200 baud).
debug:
external_components:
- source:
type: git
url: https://github.com/dannerph/esphome_vitoconnect
ref: master
refresh: 30s
- source: github://s10l/esphome_vitoconnect@number
components: [ vitoconnect ]
refresh: always
vitoconnect:
uart_id: uart_optolink
protocol: KW
update_interval: 30s
sensor:
- name: "Aussentemperatur"
id: aussen_temperatur
platform: vitoconnect
unit_of_measurement: "°C"
accuracy_decimals: 1
filters:
- multiply: 0.1
- clamp:
#min_value: 0 #-- if not set, there is no lower bound
max_value: 50 #-- if not set, there is no upper bound
ignore_out_of_range: true #-- sensor values outside those bounds will be ignored
state_class: "measurement"
device_class: "temperature"
address: 0x0800
length: 2
binary_sensor:
- name: "Status Wärmepumpe"
platform: vitoconnect
address: 0x088A
- name: "Status Warmwasser"
platform: vitoconnect
address: 0x08B0
number:
- name: "Raum Temperatur"
id: raum_temperatur
platform: vitoconnect
unit_of_measurement: "°C"
min_value: 10
max_value: 30
step: 1
div_ratio: 10
mode: box
device_class: temperature
address: 0x471B
length: 2
Falls für das zu verbindende Viessmann Gerät noch keine vollständige oder genügende Liste von Adressen bekannt ist z.B. unter https://github.com/openv/openv/wiki/Adressen, kann mit diesem ESPHome Tool weitere Adressen / Datenpunkte verifiziert resp. gescannt werden. https://github.com/openv/openv/wiki/Austesten-Optolink-Adressen-mit-ESPHome-Device
- Adapter Eigenbau
- Bauanleitung RS232
- Bauanleitung USB
- LAN/USB Kombiadapter
- Bauanleitung LAN-Ethernet
- Bauanleitung 3.3V TTL
- Weiterentwicklung 3.3V TTL + 3D Teile 🆕
- Bauanleitung LEGO™
- Bauanleitung Raspberry Pi
- Bauanleitung CAN
- Bauanleitung ESP8266
- Bauanleitung OptoPi
- openHab Integration
- Bauanleitung Hovilink
- Bauanleitung ESP32
- Bauanleitung USB-Duo/Sniffer
- Bauanleitung ESP32+Ethernet+PoE+HA 🆕
- Bauanleitung auf-Basis ESP32 S3, C6 oder C3
- Adressen
- Datenpunkt-Adressen
- Weitere Adressen
- Vito-Masterdateien
- Adressen Vitocal/WO1C
- Adressen Vitocal 200-S (Bj. 2018)
- Adressen Vitocal 200-G BWP 108
- Vitodens 200-W (B2HB-19): vito.xml & vcontrold.xml 🔗 🆕
- InsideViessmannVitosoft🔗
- vcontrold
- vcontrol-rs
- vogod
- pyvctrl🔗
- vconnect 🚫
- ViTalk 🚫
- Home Assistant vcontrold 🆕
- Vitodens 200-W (B2HB-19): Home Assistant Konfiguration 🔗 🆕
- OptolinkVS2-Switch: Vitoconnect & MQTT & TCP/IP zusammen 💥 🆕
- Optolink Bridge: Forward Vitoconnect Traffic to MQTT 💥 🆕
- ViLocal: ViCare ohne API/Internet in MQTT & HA einbinden 💥 🆕
- vcontrold-Tester: Python-Script, vcontrold-Commands/Adressen automatisiert zu testen 🆕
- ViessData21
- v-control
- v-commDLL
- IpSymcon Interface
- RS232 Test / VitoTest
- voIdent
- VitoGraph
- Viess-Data, Viess-Data 2.0
- Vies-sion
- Windows "Daemon"
- vogod