Skip to content

Instantly share code, notes, and snippets.

@lewurm
Last active July 2, 2025 18:08
Show Gist options
  • Save lewurm/6ab5a914209e8a16f4532ccfcd25b865 to your computer and use it in GitHub Desktop.
Save lewurm/6ab5a914209e8a16f4532ccfcd25b865 to your computer and use it in GitHub Desktop.
HomeAssistant Modbus configuration for Pichler LG350 Ventilation Units (possible for LG450 too)
modbus:
- name: pichlerlg350
type: tcp
host: 192.168.44.232
port: 502
delay: 2
message_wait_milliseconds: 30
binary_sensors:
- name: "lg350_bypassklappe" # 0.0
unique_id: "lg350_bypassklappe"
slave: 20
address: 20
input_type: input
device_class: opening
switches:
- name: "lg350_betriebsmodus_sommer"
slave: 20
address: 1
write_type: holding
command_on: 1 # Sommer
command_off: 2 # Winter
verify:
delay: 1
- name: "lg350_bypassklappe_force_open"
slave: 20
address: 49
write_type: holding
# data_type: uint16
command_on: 2 # Ein/Offen
command_off: 0 # Normal. "1" waere Aus/Geschlossen
verify:
delay: 1
sensors:
- name: "lg350_temp_aussenluft" # 0.0
unique_id: "lg350_temp_aussenluft"
unit_of_measurement: "°C"
slave: 20
address: 30
input_type: input
data_type: int16
offset: -100
precision: 1
scale: 0.1
- name: "lg350_temp_fortluft" # 3.0
unique_id: "lg350_temp_fortluft"
unit_of_measurement: "°C"
slave: 20
address: 31 # 30
input_type: input
data_type: int16
offset: -100
precision: 1
scale: 0.1
- name: "lg350_temp_abluft" # 0.2
unique_id: "lg350_temp_abluft"
unit_of_measurement: "°C"
slave: 20
address: 32 # 31
input_type: input
data_type: int16
offset: -100
precision: 1
scale: 0.1
- name: "lg350_temp_zuluft" # xxx
unique_id: "lg350_temp_zuluft"
unit_of_measurement: "°C"
slave: 20
address: 33 # 32
input_type: input
data_type: int16
offset: -100
precision: 1
scale: 0.1
- name: "lg350_temp_aussenluft_vhr"
unique_id: "lg350_temp_aussenluft_vhr"
unit_of_measurement: "°C"
slave: 20
address: 34
input_type: input
data_type: int16
offset: -100
precision: 1
scale: 0.1
- name: "lg350_zuluftdrehzahl"
unique_id: "lg350_zuluftdrehzahl"
unit_of_measurement: "rpm"
slave: 20
address: 39
input_type: input
data_type: int16
- name: "lg350_abluftdrehzahl"
unique_id: "lg350_abluftdrehzahl"
unit_of_measurement: "rpm"
slave: 20
address: 40
input_type: input
data_type: int16
- name: "lg350_zuluftstrom"
unique_id: "lg350_zuluftstrom"
unit_of_measurement: "m3/h"
slave: 20
address: 46
input_type: input
data_type: int16
- name: "lg350_abluftstrom"
unique_id: "lg350_abluftstrom"
unit_of_measurement: "m3/h"
slave: 20
address: 47
input_type: input
data_type: int16
- name: "lg350_reststandzeit_filter"
unique_id: "lg350_reststandzeit_filter"
unit_of_measurement: "h"
slave: 20
address: 50
input_type: input
data_type: uint16
- name: "lg350_betriebsmodus_sw"
unique_id: "lg350_betriebsmodus_sw"
slave: 20
address: 1
input_type: holding
data_type: uint16
- name: "lg350_lufstrom_stufe1"
unique_id: "lg350_luftstrom_stufe1"
unit_of_measurement: "m3/h"
slave: 20
address: 9
input_type: holding
data_type: int16
- name: "lg350_lufstrom_stufe2"
unique_id: "lg350_luftstrom_stufe2"
unit_of_measurement: "m3/h"
slave: 20
address: 10
input_type: holding
data_type: int16
- name: "lg350_lufstrom_stufe3"
unique_id: "lg350_luftstrom_stufe3"
unit_of_measurement: "m3/h"
slave: 20
address: 11
input_type: holding
data_type: int16
- name: "lg350_luftstufe"
unique_id: "lg350_luftstufe"
slave: 20
address: 2
input_type: holding
data_type: int16
- name: "lg350_bypassklappe_set"
unique_id: "lg350_bypassklappe_set"
slave: 20
address: 49
input_type: holding
data_type: int16
- name: "lg350_abluftdifferenz_stufe1"
unique_id: "lg350_abluftdifferenz_stufe1"
unit_of_measurement: "m3/h"
slave: 20
address: 83
input_type: holding
data_type: int16
offset: -500
- name: "lg350_abluftdifferenz_stufe2"
unique_id: "lg350_abluftdifferenz_stufe2"
unit_of_measurement: "m3/h"
slave: 20
address: 84
input_type: holding
data_type: int16
offset: -500
- name: "lg350_abluftdifferenz_stufe3"
unique_id: "lg350_abluftdifferenz_stufe3"
unit_of_measurement: "m3/h"
slave: 20
address: 85
input_type: holding
data_type: int16
offset: -500
sensor:
- platform: template
sensors:
lg350_luftstufe_render:
friendly_name: "Luftstufe"
value_template: >-
{% set lg350_luftstufe_mapper = {
0: 'Standby',
1: 'Stufe 1',
2: 'Stufe 2',
3: 'Stufe 3',
4: 'Grundlüftung'} %}
{% set state = states('sensor.lg350_luftstufe')|int %}
{{ lg350_luftstufe_mapper[state] if state in lg350_luftstufe_mapper else 'Unknown' }}
lg350_bypassklappe_set_render:
friendly_name: "Bypass Klappe Stellung"
value_template: >-
{% set lg350_bypassklappe_set_mapper = {
0: 'Normal',
1: 'Aus/Geschlossen',
2: 'Ein/Offen'} %}
{% set state = states('sensor.lg350_bypassklappe_set')|int %}
{{ lg350_bypassklappe_set_mapper[state] if state in lg350_bypassklappe_set_mapper else 'Unknown' }}
lg350_betriebsmodus_sw_render:
friendly_name: "Betriebsmodus"
value_template: >-
{% set lg350_betriebsmodus_sw_mapper = {
1: 'Sommer',
2: 'Winter'} %}
{% set state = states('sensor.lg350_betriebsmodus_sw')|int %}
{{ lg350_betriebsmodus_sw_mapper[state] if state in lg350_betriebsmodus_sw_mapper else 'Unknown' }}
template:
- sensor:
- name: "LG350 Heizleistung"
unique_id: "lg350_heizleistung"
state_class: "measurement"
unit_of_measurement: "W"
device_class: power
state: >
{% set vorlauf = states('sensor.lg350_temp_zuluft') | float (0) %}
{% set ruecklauf = states('sensor.lg350_temp_abluft') | float %}
{% set durchfluss = states('sensor.lg350_zuluftstrom') | float %}
{{ ((vorlauf - ruecklauf) * durchfluss * 0.33 ) | round(1, default=0) }}
@lewurm
Copy link
Author

lewurm commented Jun 17, 2025

I answered (mostly) in the energiesparhaus thread.

set the ventilation volume for one specific level or

I configured an input_number for that in Home Assistant (Settings -> Devices & services -> Helpers), so that I have a nice UI slider.

Screenshot 2025-06-17 at 22 14 31

and then there is an automation associated with it:

alias: "lg350: base change "
description: ""
mode: single
triggers:
  - entity_id:
      - input_number.lg350_base_luftmenge
    from: null
    to: null
    trigger: state
conditions: []
actions:
  - data_template:
      hub: pichlerlg350
      address: 9
      slave: 20
      value: "{{ states('input_number.lg350_base_luftmenge') | int }}"
    action: modbus.write_register

You could do something similar for the ventilation level. Personally I just stick to one ventilation level and adapt the volume of that. For example, I've a CO2 sensor in my bedroom and control the ventilation level based on the CO2 concentration; that automation just changes input_number.lg350_base_luftmenge which will trigger the automation above to propagate the value to the correct modbus register.

@sventiffe
Copy link

sventiffe commented Jun 22, 2025

Thank you! As mentioned in the forum, I've received some (incomplete) documentation from Pichler for the LG 150 and updated my config here: https://gist.github.com/sventiffe/788b25ff50a8b3cc2c3a33cac5576616

I've defined an input number and action like suggested:

alias: 'lg150: luftmenge stufe 1 änderung'
description: ''
triggers:
  - entity_id:
      - input_number.lg150_base_luftmenge
    from: null
    to: null
    trigger: state
conditions: []
actions:
  - data_template:
      hub: pichler_lg150
      address: 9
      slave: 20
      value: '{{ states(''input_number.lg150_base_luftmenge'') | int / 10 }}'
    action: modbus.write_register
mode: single

In contrast, apparently, to the bigger devices, the LG150 operates with 1/10th of the actual settings. I've also defined helper methods to render the air volume nicely, multiplying the modbus data by 10

@silenthunter99
Copy link

Hello guys,
excuse me if it is a dumb question, First time doing something with Modbus RTU-> TCP and not too long in HA

Has anyone an idea why i can´t set any settings at the ventilation unit?
I have the same device Elfin EE11A as [mihu-ov].

Can´t seem to find the right setting for this

Elfin1 Elfin2

Elfin3`

Elfin seems to communicate with the HA instance

HA:
HA1

HA2 Sensor readings work

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment