Hello, I spent already more than a week to get this working, but I still can not achieve the result I want. I have heat pump from Acond which support communication over ModBus. The problem is that when I set it up it jups between the auto mode and the ModBus mode. In the documentation there is mentioned that it will switch to auto mode when in time = MaxCommDataRefresh there was no value written or read over ModBus. I suspect that this MaxCommDataRefresh is 1s or lower, but Home Assistant only allows me to read in 1s intervals. That is the first problem.
Second problem is that when I setup “climates” it can write only one register, but based on the documentation I need to write multiple registers because some needs to be set to some values. Is there some solution how to write multiple registers when the target temperature is set?
Hi Jakub! I also have an Acond heat pump and I am just getting my bearings around its Modbus interface. Can you tell me where you obtained the documentation you mentioned?
Also, did you make any headway with the issue you described here? I am currently looking to use the heat pump as a sensor source only, and I want to be able to track its reported outside and inside air temperature, and the heating and hot water temperature. In other words, I am currently only interested in the read registers. Since your question was about writes, I suppose you already succeeded at reads before those?
Hello,
here is my configuration.yaml which I use and it works.
You have to change the IP address.
And technicians from Acond must allow Modbus communication on the unit.
With Best Regards Thomas
though I haven’t made much headway yet, I just wanted to say thanks for the pointers thus far.
I have put in this request with the contractor that installed my heat pump, and am still waiting to hear back from them.
I have found this video though; it contains some information about Modbus from about the 14-minute mark:
Unfortunately I don’t speak Czech, and Youtube’s auto-caption/auto-translate feature doesn’t appear to work for this video. So I can’t make out a whole lot. One question that I do have is this, though: do the Modbus registers expose the system’s current power consumption? Is that the ACOND_capacity_actual_W sensor you define, @tnovicky?
Ahoj Jakube,
I see your modbus with ACOND is working. I have ACOND as well, I have paper protocol from ACOND, and I think I made it all exactly according this protocol, but answer is ILLEGAL DATA ADDRESS. Can you send me a couple of packets from communication recorded by wireshark or can you check where should be problem on my side please? I have info from ACOND that it should works, but not in my case. Thank you Vasek.
Hello,
below is my configuration.yaml. I think I copied it correctly from you, but I can’t get the correct result.
After restarting HA it gives me an error:
Logger: homeassistant.setup
Source: setup.py:190
First occurred: 11:41:39 (2 occurrences)
Last logged: 11:41:40
Setup failed for sensors: Integration not found.
Setup failed for climates: Integration not found.
Could you please help me with what I am doing wrong.
I’m sorry, but I’m a beginner with HA, so please be patient and forgiving.
thank you very much
Hello, did You solve the problem? If not I will try to help, but prefer email conversation. So send Your question to [email protected].
With Best Regards Thomas
Returning to this thread with additional information, just in case someone finds it useful.
I’ve finally added my Acond PRO-R to my Home Assistant configuration via Modbus, using the documentation available from loxone-library as a reference (this appears to be a translation of https://acond.cz/wp-content/uploads/Acond_ModbusTCP-v2.34.pdf though the version IDs don’t match up, and also I’m not sure if the translation comes directly from Acond or from a third party).
Here’s what I’ve added to my modbus configuration thus far:
- name: Acond PRO-R
type: tcp
host: acond.lan # This is a DNS entry in my local network; using an IP address is fine too
port: 502
delay: 1
timeout: 1
message_wait_milliseconds: 1
retries: 1
climates:
- name: ACOND_T_set_indoor1 # Indoor temperature, sensor #1 (I only have one at this time)
slave: 1
address: 1
target_temp_register: 0
input_type: input
data_type: int16
scan_interval: 60
scale: 0.1
precision: 1
max_temp: 28
min_temp: 10
temp_step: 0.1
- name: ACOND_T_set_TUV # Domestic hot water temperature
slave: 1
address: 5
target_temp_register: 4
input_type: input
data_type: int16
scan_interval: 60
scale: 0.1
precision: 1
max_temp: 55
min_temp: 10
temp_step: 0.1
sensors:
- name: ACOND_T_act_indoor1 # Current indoor temperature at sensor #1
slave: 1
address: 1
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: "°C"
- name: ACOND_T_act_TUV # Current domestic hot water temperature
slave: 1
address: 5
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: "°C"
- name: ACOND_T_act_water_back # Current return water temperature in heating circuit
slave: 1
address: 8
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: "°C"
- name: ACOND_T_act_air # Current outside air temperature
slave: 1
address: 9
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: "°C"
- name: ACOND_err_number # General error number, should always be 0 in normal operation
slave: 1
address: 20
data_type: int16
input_type: input
- name: ACOND_err_number_SECMono # SECMono error number, should always be 0 in normal operation
slave: 1
address: 21
data_type: int16
input_type: input
- name: ACOND_err_number_driver # Driver error number, should always be 0 in normal operation
slave: 1
address: 22
data_type: int16
input_type: input
- name: ACOND_capacity_actual_W # Current heat production
slave: 1
address: 23
data_type: int16
input_type: input
device_class: power
unit_of_measurement: "W"
For the ACOND Grandis R/P the configuration is different.
For instance the power settings
I have made some automations to let the heat pump work with TADO.
The house I own is build in 1895. And has over 240 square meters flooring, of which most is ground level.
To make sure the rooms will get the correct temperature, I let TADO decide what the room temperature should be.
config.yaml
# Modbus configuration for Acond Grandis R
modbus: !include modbus.yaml
# Logger for modbud
logger: !include logger.yaml
# Template for the modbus implementation
template: !include template.yaml
# Include scripts configuration
scripts: !include scripts.yaml
# Include the automations
automation: !include automations.yaml
modbus.yaml
- name: acond_grandis_r
type: tcp
host: _host_ip_address_# Change to the IP address of the control unit
port: 502
delay: 1
timeout: 1
message_wait_milliseconds: 1
climates:
- name: ACOND_T_set_indoor1 # Indoor temperature, sensor #1 (I only have one at this time)
slave: 1
address: 0
target_temp_register: 0
input_type: input
data_type: int16
scan_interval: 60
scale: 0.1
precision: 1
max_temp: 28
min_temp: 10
temp_step: 0.1
unique_id: acond_grandis_r_0001
- name: ACOND_T_set_TUV # Domestic hot water temperature
slave: 1
address: 4
target_temp_register: 4
input_type: input
data_type: int16
scan_interval: 60
scale: 0.1
precision: 1
max_temp: 65
min_temp: 10
temp_step: 0.1
unique_id: acond_grandis_r_0002
sensors:
- name: ACOND_T_act_indoor1 # Current indoor temperature at sensor #1
slave: 1
address: 1
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: 'ÂşC'
unique_id: acond_grandis_r_0003
- name: ACOND_T_act_TUV # Current domestic hot water temperature
slave: 1
address: 5
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: 'ÂşC'
unique_id: acond_grandis_r_0004
- name: ACOND_T_act_water_back # Current return water temperature in heating circuit
slave: 1
address: 8
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: 'ÂşC'
unique_id: acond_grandis_r_0005
- name: ACOND_T_act_air # Current outside air temperature
slave: 1
address: 9
data_type: int16
scale: 0.1
precision: 1
input_type: input
device_class: temperature
unit_of_measurement: 'ÂşC'
unique_id: acond_grandis_r_0006
- name: ACOND_err_number # General error number, should always be 0 in normal operation
slave: 1
address: 20
data_type: int16
input_type: input
unique_id: acond_grandis_r_0007
- name: ACOND_err_number_SECMono # SECMono error number, should always be 0 in normal operation
slave: 1
address: 21
data_type: int16
input_type: input
unique_id: acond_grandis_r_0008
- name: ACOND_err_number_driver # Driver error number, should always be 0 in normal operation
slave: 1
address: 22
data_type: int16
input_type: input
unique_id: acond_grandis_r_0009
- name: ACOND_comp_rpm_actual # Current compressor speed
slave: 1
address: 23
data_type: int16
input_type: input
unit_of_measurement: "rpm"
unique_id: acond_grandis_r_0010
- name: ACOND_comp_rpm_max # Maximum compressor speed
slave: 1
address: 19
data_type: int16
input_type: input
unit_of_measurement: "rpm"
unique_id: acond_grandis_r_0011
- name: ACOND_type_reg_pan # Current type regulation
slave: 1
address: 14
data_type: int16
input_type: input
scan_interval: 60
unique_id: acond_grandis_r_0012
- name: ACOND_type_rezim_pan # Heatpump mode
slave: 1
address: 13
data_type: int16
input_type: input
scan_interval: 60
unique_id: acond_grandis_r_0013
- name: ACOND_TC_status # Current status of the heatpump
slave: 1
address: 6
scan_interval: 60
data_type: int16
input_type: input
unique_id: acond_grandis_r_0014
- name: ACOND_TC_set # Set the state of the heatpump using the holding register
slave: 1
address: 5
input_type: holding
data_type: int16
unique_id: acond_grandis_r_0015
- name: ACOND_T_set_indoor1_holding # Set the indoor temperature of the heatpump using the holding register
slave: 1
address: 0
input_type: holding
data_type: int16
unique_id: acond_grandis_r_0016
Template.yaml
- sensor:
# Debugging the bitwise word value of sensor acond_tc_status
- name: "Get_ACOND_TC_status"
state: "{{ states('sensor.acond_tc_status') }}"
attributes:
hp_on: "{% if states('sensor.acond_tc_status') | int | bitwise_and(1) %}on{% else %}off{% endif %}"
hp_operation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(2) %}on{% else %}off{% endif %}"
hp_failure: "{% if states('sensor.acond_tc_status') | int | bitwise_and(4) %}on{% else %}off{% endif %}"
dhw_heating_progress: "{% if states('sensor.acond_tc_status') | int | bitwise_and(8) %}on{% else %}off{% endif %}"
circulation_heating_circuit_1: "{% if states('sensor.acond_tc_status') | int | bitwise_and(16) %}on{% else %}off{% endif %}"
circulation_heating_circuit_2: "{% if states('sensor.acond_tc_status') | int | bitwise_and(32) %}on{% else %}off{% endif %}"
solar_circulation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(64) %}on{% else %}off{% endif %}"
pool_circulation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(128) %}on{% else %}off{% endif %}"
defrosting: "{% if states('sensor.acond_tc_status') | int | bitwise_and(256) %}on{% else %}off{% endif %}"
auxiliary_heating: "{% if states('sensor.acond_tc_status') | int | bitwise_and(512) %}on{% else %}off{% endif %}"
summer_operation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(1024) %}on{% else %}off{% endif %}"
brine_circulation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(2048) %}on{% else %}off{% endif %}"
cooling_operation: "{% if states('sensor.acond_tc_status') | int | bitwise_and(4096) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_0
# Debugging the sensor acond_type_reg_pan
- name: "GET_ACOND_type_reg_pan"
state: "{{ states('sensor.acond_type_reg_pan') }}"
attributes:
acondtherm: "{% if int(states('sensor.acond_type_reg_pan')) == 0 %}on{% else %}off{% endif %}"
equiterm: "{% if int(states('sensor.acond_type_reg_pan')) == 1 %}on{% else %}off{% endif %}"
manually: "{% if int(states('sensor.acond_type_reg_pan')) == 3 %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0012_0
# Debugging the sensor acond_type_rezim_pan
- name: "GET_ACOND_type_rezim_pan"
state: "{{ states('sensor.acond_type_rezim_pan') }}"
attributes:
automatically: "{% if int(states('sensor.acond_type_rezim_pan')) == 0 %}on{% else %}off{% endif %}"
only_heatpump: "{% if int(states('sensor.acond_type_rezim_pan')) == 1 %}on{% else %}off{% endif %}"
only_auxiliary: "{% if int(states('sensor.acond_type_rezim_pan')) == 3 %}on{% else %}off{% endif %}"
off: "{% if int(states('sensor.acond_type_rezim_pan')) == 4 %}on{% else %}off{% endif %}"
manually: "{% if int(states('sensor.acond_type_rezim_pan')) == 5 %}on{% else %}off{% endif %}"
cooling: "{% if int(states('sensor.acond_type_rezim_pan')) == 6 %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0013_0
# Defining all the binary sensors
- binary_sensor:
- name: Heatpump On
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(1) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_1
- binary_sensor:
- name: Heatpump Operation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(2) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_2
- binary_sensor:
- name: Heatpump Failure
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(4) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_3
- binary_sensor:
- name: Domestic Hot Water heating in progress
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(8) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_13
- binary_sensor:
- name: Circulation Heating Circuit 1
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(16) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_4
- binary_sensor:
- name: Circulation Heating Circuit 2
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(32) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_5
- binary_sensor:
- name: Solar Circulation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(64) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_6
- binary_sensor:
- name: Pool Circulation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(128) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_7
- binary_sensor:
- name: Defrosting
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(256) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_8
- binary_sensor:
- name: Auxiliary Heating
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(512) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_9
- binary_sensor:
- name: Summer Operation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(1024) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_10
- binary_sensor:
- name: Brine Circulation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(2048) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_11
- binary_sensor:
- name: Cooling Operation
state: "{% if states('sensor.acond_tc_status') | int | bitwise_and(4096) %}on{% else %}off{% endif %}"
unique_id: acond_grandis_r_0014_12
- sensor:
- name: "Heatpump mode"
icon: mdi:state-machine
unique_id: acond_grandis_r_0013_1
state: >-
{% if int(states('sensor.acond_type_rezim_pan')) == 0 %}
"Automatic"
{% elif int(states('sensor.acond_type_rezim_pan')) == 1 %}
"Only Heatpump"
{% elif int(states('sensor.acond_type_rezim_pan')) == 3 %}
"Only Auxiliary" }}
{% elif int(states('sensor.acond_type_rezim_pan')) == 4 %}
"Off"
{% elif int(states('sensor.acond_type_rezim_pan')) == 5 %}
"Manually"
{% elif int(states('sensor.acond_type_rezim_pan')) == 6 %}
"Cooling"
{% else %}
"Unknown"
{% endif %}
- sensor:
- name: "Heatpump temperature regulation"
icon: mdi:state-machine
unique_id: acond_grandis_r_0012_1
state: >-
{% if int(states('sensor.acond_type_reg_pan')) == 0 %}
"Acondtherm"
{% elif int(states('sensor.acond_type_reg_pan')) == 1 %}
"Equitherm"
{% elif int(states('sensor.acond_type_reg_pan')) == 3 %}
"Manually"
{% else %}
"Unknown"
{% endif %}
scripts.yaml
# Generic code to turn on a bit in a bitwise holding register
write_register_turn_on_bit:
sequence:
- service: modbus.write_register
data:
hub: "{{ hub }}"
slave: "{{ slave_id }}"
address: "{{ address }}"
value: "{{ states(sensor_value) | int(default=0) | bitwise_or(2 ** (bit | int - 1)) }}"
- service: homeassistant.update_entity
data:
entity_id: "{{ sensor_value }}"
# Generic code to turn off a bit in a bitwise holding register
write_register_turn_off_bit:
sequence:
- service: modbus.write_register
data:
hub: "{{ hub }}"
slave: "{{ slave_id }}"
address: "{{ address }}"
value: "{{ states(sensor_value) | int(default=0) | bitwise_and(65535 - (2 ** (bit | int - 1))) }}"
- service: homeassistant.update_entity
data:
entity_id: "{{ sensor_value }}"
# Increase the indoor temperature by an int value of the Acond Grandis R
increase_acond_temperature_value:
sequence:
- service: modbus.write_register
data:
hub: "{{ hub }}"
slave: "{{ slave_id }}"
address: "{{ address }}"
value: "{{ int(states(sensor_value)) + (int(temperature_value) * 10) }}"
- service: homeassistant.update_entity
data:
entity_id:
- "{{ sensor_value }}"
- "{{ update_sensor }}"
# Decrease the indoor temperature by an int value of the Acond Grandis R
decrease_acond_temperature_value:
sequence:
- service: modbus.write_register
data:
hub: "{{ hub }}"
slave: "{{ slave_id }}"
address: "{{ address }}"
value: "{{ int(states(sensor_value)) - (int(temperature_value) * 10) }}"
- service: homeassistant.update_entity
data:
entity_id:
- "{{ sensor_value }}"
- "{{ update_sensor }}"
# Set the indoor temperature by an int value of the Acond Grandis R
set_acond_temperature_value:
sequence:
- service: modbus.write_register
data:
hub: "{{ hub }}"
slave: "{{ slave_id }}"
address: "{{ address }}"
value: "(int(temperature_value) * 10)"
- service: homeassistant.update_entity
data:
entity_id:
- "{{ sensor_value }}"
- "{{ update_sensor }}"
Thanks everyone for keeping track of what you have done!
I am currently looking into this myself. However, as enabling Modbus is directly connected with a loss of warranty, I was wondering if anyone checked out how the local web server behaves? I was just briefly looking at it and it seems the client is just sending HTTP requests, such as a POST request for logging in:
POST /SYSWWW/LOGIN.XML HTTP/1.1
Host: 192.168.0.10
Content-Type: application/x-www-form-urlencoded
Priority: u=0, i
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:130.0) Gecko/20100101 Firefox/130.0
Referer: http://192.168.0.10/SYSWWW/LOGIN.XML
Content-Length: 56
USER=acond&PASS=03a9ca25acba8c63ef7d9ec14d4ffb2edc3a66ef
EDIT: Oh, and can someone explain to me, in more detail, what the purpose of the different modes (AcondTherm, EquiTherm, and Manual) is? I have no Acond control unit / sensor installed and am relying on the room thermostats.
Hi Bob, heel erg bedankt voor het delen van jou code bestanden. Ik ben helemaal nieuw met HA en totaal onervaren met code/programmeren maar kom langzaam wegwijs in de werking van de codering en heb jou code (met wat kleine aanpassingen) werkend gekregen op mijn acond PRO. Ik heb nu de modbus.yaml en template.yaml helemaal werkend en ben toegekomen aan het automatiserings gedeelte.
Hier had ik een vraag over, als ik het goed begrijp dan stuur jij de acond opdracht wanneer 1 van de verschillende kamers onder de gewenste temperatuur komt, om de acond thermostaat 2 of 5 graden te verhogen. Dit blijft verhoogd tot
dat alle kamers in idle staan en dan gaat de acond thermostaat weer terug naar 19 graden. Wanneer kies je ervoor om 2 of 5 graden te verhogen, wat houdt die meting <50 in?
Thank you Florian Haas to share this piece of code. I have my ACOND PRO-N working with this code you shared.
I know the Acond PRO-N records it’s Electrical Energy per day and Electrical Energy as a sum. I have been trying to add the sensor for the Electrical Energy per day with the following additional code for the sensors:
- name: ACOND_EED # Electrical energy per day
slave: 1
address: 40
data_type: int16
input_type: input
device_class: power
unit_of_measurement: "kW"
However I have not succeeded in receiving a correct value. After reboot of HA it is still showing “unavailable”. Do you maybe have any suggestions?
In the meantime I have been able to add the sensors for HeartBeat (address 30017) and Actual PWM (address 30025). It seems to me that the addresses in red in the referred documentation are not implemented in my ACOND PRO-N. The document is dated 17.10.2024 and my PRO-N is installed 06-12-2022. I am not sure how ACOND is dealing with Software Updates on older systems, but I get the impression they do not update them.
Maybe anyone has some more insight or information regarding this.
My experience with Acond is that they only update the software if they know of a bug or a major improvement. So twice the first year and then not at all.
You need to write to the service in the summer and ask for an update, ideally with the description you provide here.
They are very helpful in the summer. In the winter they wrote to me that they updated the software, but only because of a new circulation pump that did not work well with PWM control. When I found out that the update also included a MODbus extension (in the previous version I only had up to address 30026), I also wanted a PDF for it. They sent me that (but stil only address up to 30026), but with the understanding that they are asking me to leave such requests for the summer because now they have to deal with repairs at the beginning of the heating season.
I have contact with the Dutch company importing the ACOND heatpump into the Netherlands and distributing it over the installers. On my question regarding firmware version on my heatpump and the update they reacted very quickly, and within half a day I had an update.
I have up to address 30049 visible in the webpage at the moment right now. But my documentation only describes up to address 30044. So I requested the MODBUS documentation describing up to 30049, but still waiting for an answer (send the request only two days ago).
When you are interested in the documentation up to 30044, I can send it you via a private message. Since it is not freely available from ACOND, I do not want to share it here publicly.
I am still relatively new to this forum, so I do not know yet how private messages work.
Dear all, who own a heat pump from acond:
I recently installed a Grandis R on my own, since technical background and some job background on that area.
Now the inicial operation should take place, but the reseller is not willing to provide the password to start coupling inner and outer unit. Instead the inicial operation should cost additional almost 2k€. This was not mentioned when selling the heat pump…
If someone can help, I would appreciate it. My Family also, to get warm water and house… thx.