New integration for REMKO Heatpump

The “skipped MQTT messages” only affects the update interval of the sensors. Some sensors get updates each second which I found a bit too much.

Apart from that there’s a watchdog which sends a keep alive message every 5 minutes. If you want to give it a try, you can edit line 363 from heatpump.py where it says:

if time.time() - self._last_time >= 300: 

300 seconds = 5 minutes.
(Don’t forget to restart home assistant after changing the code)

According to the log I can see, that the message had no values.
While you’re having this issue, did you try reaching the webpage of the heat pump?

Die Sensoren werden nur dann aktualisiert, wenn auch neue Werte kommen. Vergleiche mal die anderen Sensoren. Wenn dort einer aktuellere Werte hat ist grds. erst einmal alles in Ordnung.


The sensors are only updated when new values appear. Compare the other sensors. If one has more current values, everything is fine.

Die Wärmepumpe hat über MQTT keine Adressen, um Stromwerte zu empfangen, die für PV Überschuss genutzt werden können. Hierzu ist es vielmehr nötig über einen Impulseingang (Kabelanschluss) zu arbeiten. Hierfür benötigt man entsprechende Komponenten, die das Impulssignal erzeugen.


The heat pump has no addresses via MQTT to receive current values which can be used for PV surplus. For this purpose, it is rather necessary to work via a pulse input (cable connection). For this purpose, appropriate components are required to generate the pulse signal.

I have set the keep alive to 1 minute now to see whether it does anything, will keep you updated on that.

While the issue is occurring i can still access the webpage of the heatpump. Everything on that side seems to be operational while the integration seems not to be working.

Can you check with a MQTT explorer whether you can see messages (HOST2CLIENT)?

Right now i can see then, the integration has been working ok for some days now. If it stops working i will check this again.

Weisst du zufällig welche Komponenten ich hierfür benötige und wie diese anzuschließen wären?

Does it work for you know? I made the interesting experience that if I am in Expert mode the integration doesn’t show any values. As soon I go back to Basic mode values are available.
Once I used the modified/outdated integration of MHeul(?). It run almost perfect besides warm water temperature.

I guess it’s about the amount of values you request. Expert mode might deliver more data. But I am just guessing. Further investigation is required.

Hi, gibt es aktuell wieder irgendwelche Probleme mit der Integration? Ich bekomme wieder keine Entitäten angezeigt???

My guess is that is the integration by HMeuleman :slight_smile: Can you explain what is outdated according to you? I recently checked the changes that were made to the original integration but didn’t find anything of interest, but I might have missed some useful things. I only have a Remko heatpump no DHW.

Anyway, I can explain what is wrong with the original version (and when I checked recently it still has this “error”). What happens is the following:
The HA Remko integration registers on MQTT events delivered by the Remko Heatpump. At the same time it every now and then fires a request to forcefully get an event (REMKO will keep sending updates even you don’t request new ones). The problem is in the way the original integration is handling the events. In order to limit the updates it is only processing one every every x seconds, but this is a wrong concept because it is unknown which event is arriving. So if the event it processes is not holding any values (because you have a browser open towards the Remko WEB Gui requesting a certain page, which is also using MQTT under water (dutch expression)) then none of the entities will get populated.
What I changed is how heatpump.py in the function async def message_received(self, message):
a message is processed and decoded. Instead of processing only every now and then an event, I process all events. But the updating of the actual entity is only done when something changes (and I’ve added a couple of hysteresis handling routines for certain types like temp). The hysteresis handling is to limit the number of updates and I’m personally fine with how it is currently working for me.
Anyway in the original handler (by Altrec) there is this code:

async def message_received(self, message):
    """Handle new MQTT messages."""
    _LOGGER.debug(
        "%s: message.payload:[%s] [%s]", self._id, message.topic, message.payload
    )
    try:
        # In case the heatpump is controlled from another client don't send query_list
        if "CLIENT2HOST" in message.topic:
            if "CLIENT_ID" in message.payload:
                self._last_time = time.time()
                _LOGGER.debug("Message from other client")
        elif self._mqtt_counter == self._freq:

This last line is causing the problem. This filters out large amount of responses and if that happens to be the response (event) that you were looking for then you are out of luck. If you wann try you can simply change that line into

        elif self._mqtt_counter >= 0:

and you will get your updates, however that is not something you want to do without removing (or commenting out) the line:

       await self.mqtt_keep_alive()

In the same function, because it will trigger a new request. You want to limit the requests, and that is what I did in mqtt_keep_alive by using a sleep of 30 there, but for testing you could try above change, since Altrec version has a watchdog triggering the MQTT updates every 5 minutes which is probably more then enough.

regards,
Hante

Hi Hante,

thank you for this great support and detailed explanation why Altrec’s implementation doesn’t work (in my case). I made the proposed changes and set the watchdog to 1 min. The 5 min watchdog was too long. And to make control with Home Assistant more reliable queries from other clients are ignored. This is some trade of which client you want to use. I prefer Home Assistant.

In combination with dynamic energy prices (Tibber) and our personal life style I could optimize the usage of the heatpump.

Best regards,
Acema

Hi all,

one great hint for reengineering the Remko Ids:

  1. Open the dialog in the web view of the heatpump
  2. subscribe to the Remko MQTT topic
  3. Grep the query list
  4. try to identify the queried Ids
mosquitto_sub -h <MQTT server> -u <MQTT user> -P <MQTT password> -v -t 'V04P28/#' | grep query

I would be happy to see more reengineered Ids :wink:

Just to add some clarification/correction:

Not finding anything of interest is not an indication wether there have been made some modifications/updates and wether a fork is outdated compared to an original repository.

The thing is: The heat pump will send values according to the last request it got. Furthermore not all values are available on all pages of the menu. Therefore handling every message the heat pump is sending won’t necessarily lead to updating all entities. Opening the web page and going to certain sub menus will lead to missing updates for the integration. But sending keep alive messages alongside requesting values will interfere with browsing the web side plus it might not even give you the values you’re requesting.

You don’t have to change any code since this “wait counter” is configurable. (Standard setting is 100)

Hi Altrec,

first of all, thank you for your great work. I’ve been using the integration with great satisfaction and am glad I could because Remko Heatpump does not integrate well with other hw (like evohome), but with this integration I was able to control 'the heatpump properly.

As said I heavily rely on a working version so perhaps there have been some updates which are useful but I don’t want to change/merge too much with risk that it is not working for some while.

Now for the changes I made; Your comment hits the nail on the head: “Furthermore not all values are available on all pages of the menu”. The problem I see is that the response that gets parsed is not always the response on the request send by the integration (and that is due to this count), and then only a few (or none) of the desired Ids get parsed. Parsing any string is not an issue, just try to avoid setting variables if they don’t change that will limit the database updates and that is all that is needed. Parsing a few extra strings every interval is not problematic/costly. Database updates are costly and those can be avoided by updating only when the value changed (preferably with some hysteresis on things like temperature).
To be clear: The wait counter causes to process only one in every x strings. And this string does not have to contain any useful information.There is no guarantee that it will be requested data.

Anyway you don’t have to change anything, I just wanted to explain why in some situations nothing gets parsed (for some time) or in some situations updates seem to take a long time. I spent quite a bit of time getting this to work for me and I think it may differ per device/environment, but as said, for me it is very important it works reliable.

regards,
Hante

Hallo allerseits und frohes Neues Jahr.

Ich muss hier leider in Deutsch schreiben, da mein Englisch etwas eingerostet ist.

Die Integration habe ich am Laufen, funktioniert auch soweit.
Allerdings habe ich seitdem Probleme mit dem Abtaubetrieb.
Der Soll-Volumenstrom wird beim Abtauen auf 60l/min gesetzt, das schafft die Pumpe nicht. Was dann folgt ist eine Störung, weil Mindest-Volumenstrom nicht erreicht und eine Verriegelung der Wärmepumpe, die ich immer zurücksetzen muss. Abtauen funktioniert dann natürlich nicht.
Bei der momentanen Wetterlage nicht wirklich zuträglich.

Gibt es eine Möglichkeit, den maximalen Soll-Volumenstrom zu begrenzen bzw. zu reduzieren?
Der zugehörige Datenpunkt ist 5073, soviel habe ich herausgefunden.
Ich weiß allerdings nicht, wie ich der Pumpe erzähle, dass der Volumenstrom auf z.B. max 20l/min begrenzt werden soll.

Ich habe Zugriff auf 2 weitere identische Geräte, hier liegt der maximale Volumenstrom bei Abtaubetrieb bei 18l/min. Daher vermute ich ein Einstellungsproblem.

Vielen Dank

Ebenfalls ein frohes Neues!

dumme Frage, aber was hast Du vor? An solche Einstellungen würde ich mich als Laie nicht wagen. Dieses Register fasse ich nicht an.

(Das ist für Deine Frage nicht hilfreich - das ist eher persönliche Neugierde, weil ich meine Wärmepumpe weiter optimieren möchte.)

Hi Hantec,
Hi Altec,

for sure there is still some logic that is not understood. Depending on the page you visit with the web browser or app you get the correct values. Even the user mode (Expert/Normal User) seems to have an impact on the response.

In general I like the check_capabilities() approach because it pevents wrong values of the entities (-1, …). But if the integration starts with the wrong preselected page from the web browser/app the queried sensors I quite limited. And changing the page afterwards doesn’t solve the issue because check_capabilities() in only called at the integration setup.

The JSON sent by the web browser/app has some more values like SMT_USER, DEVID, … Do you think these values are necessary in our case?

Best regards,
Acema

@Altrec: I use your code with Hante’s suggestions. The improvements make sense for me!

Hi,

ich habe garnichts vor. Ich will lediglich den maximalen Soll Volumenstrom soweit begrenzen, dass die eingebaute Pumpe das auch schafft und nicht ständig wegen zu geringem Volumenstrom den Abrauvorgang abbricht. Es reicht mir eigentlich einen Wert von unter 50l/min einzustellen, das schafft die Pumpe gerade noch so eben. Dann taut die Kiste auch mal wieder ab.

Hallo,

vielleicht hilft ein Blick auf Deine remko_regs.py. Könntest Du die posten?

Hi,

# Remko generated register definitions
FIELD_REGNUM = 0
FIELD_REGTYPE = 1
FIELD_UNIT = 2
FIELD_MINVALUE = 3
FIELD_MAXVALUE = 4

# Query list
#query_list = []
#query_list = [127, 132, 327, 1014, 1088, 1893, 1894, 1946, 1951, 2015, 5001, 5032, 5036, 5123, 5039, 5190, 5320, 5693, 5822, 5824]
query_list = [1014, 1063, 1088, 1666, 1781, 1782, 1893, 1894, 1946, 2015, 5001, 5032, 5036, 5039, 5073, 5123, 5190, 5320, 5360, 5361, 5579, 5693, 5822, 5824]

#min_work_temp, WP will not work when 'outside temp' below this temp. Goes into frost protection state
# Register as sensors
reg_id = {
    #  reg_id: ['reg#', 'type', 'unit', 'min', 'max'],
    "language": ["1014", "string", "", "", ""],
    #"version": ["327", "number", "", "" , "" ],
    #"user_level": ["5029", "string", "", "", ""],
    "dhw_opmode": ["1079", "select_input", "", 0, 16],
    #"water_temp_req": ["1082", "temperature_input", "ºC", 20.0, 60.0],
    "min_work_temp": ["1666", "temperature_input", "ºC", -20.0, 20.0],
    "bivalenz_ww": ["1781", "temperature_input", "ºC", -20.0, 20.0],
    "bivalenz_hz": ["1782", "temperature_input", "ºC", -20.0, 20.0],
    "temp_req": ["1946", "temperature_input", "ºC", -10.0, 10.0],
    "absence_mode": ["1893", "switch", "", "", ""],
    "party_mode": ["1894", "switch", "", "", ""],
    "main_mode": ["1088", "select_input", "", "", ""],
    "opmode": ["5001", "sensor_mode", "", "", ""],
    "out_temp": ["5032", "temperature", "ºC", 0, 40],
    "out_temp_corr": ["2015", "temperature_input", "ºC", -10.0, 10.0],
    "floor_temp": ["5036", "temperature", "ºC", 0, 70],
    "return_floor_temp": ["5123", "temperature", "ºC", 0, 70],
    "verw_water_temp": ["5190", "temperature", "ºC", 0, 70],
    "el_consumption": ["5320", "sensor_el", "W", 0, 6000],
    "energy_heating": ["5374", "sensor_en", "kWh", "", ""],
    "el_inside_unit": ["5579", "sensor_elc", "W", "", ""],
    "dhw_heating": ["5693", "action", "", "", ""],
    "comp_starts": ["5822", "number", "", "" , "" ],
    "comp_hours": ["5824", "number", "", "" , "" ],
    "communication_status": ["communication_status", "generated_sensor", "", 0, 0],
    "dhw_temp": ["5039", "temperature",  "ºC", 0, 70],
}

# Translation dictionary
#  'de', 'en', 'fr', 'it', 'nl']
id_names = {
    "language": ["Sprache", "Language", "Langue", "Lingua", "Taal"],
    "version": ["Version number", "Versionsnummer", "Versionsnummer", "Versionsnummer", "Versionsnummer"],
    "user_level": ["user level", "user level", "user level", "user level", "user level"],
    #"water_temp_req": ["Water temp. req.", "Warmwasser soll", "Warmwasser soll", "Warmwasser soll", "Warmwasser soll"],
    "min_work_temp": ["min. Außentemperatur", "Min. outside temperature", "Min. outside temperature", "Temperatura esterna min.", "Min. buiten temperatuur"],
    "temp_req": ["Kälter / Wärmer", "Colder / hotter", "Plus froid / Plus chaud", "Più freddo / più caldo", "Kouder / Warmer"],
    "out_temp": ["Außentemperatur", "Outside temperature", "Température extérieure", "Temp. esterna", "Buitentemperatuur"],
    "out_temp_corr": ["Außentemperatur korrigiert", "Outside temperature S10", "Température extérieure S10", "Temp. Esterna S10", "Buitentemperatuur S10"],
    "floor_temp": ["Ist-Temperatur", "Actual temperature", "Température réelle", "Temp. Circ.", "Vloerverwarming temp."],
    "return_floor_temp": ["Rücklauftemp", "Return temp.", "Temp. retour", "Temp. ritorno", "Vloerverwarming retour temp."],
    "verw_water_temp": ["Heizwasser Ist-Temp.", "Heating water temp. (actual)", "Temp. eau chaude (Val.r réelle)", "Temp. Produzione", "Verw. watertemp (act. waarde)"],
    "el_consumption": ["Leistung elektrisch", "electr. power heatpump", "Puissance électr. thermopompe", "Ass. elettrico PDC", "Elektr. Vermogen warmtepomp"],
    "energy_heating": ["Energie Heizen", "Energy heating", "Énergie Chauffer", "Energia riscaldamento", "Energie verwarmen"],
    "bivalenz_ww": ["Bivalenzpunkt WW", "Energy heating", "Énergie Chauffer", "Energia riscaldamento", "Energie verwarmen"],
    "bivalenz_hz": ["Bivalenzpunkt Heizung", "Energy heating", "Énergie Chauffer", "Energia riscaldamento", "Energie verwarmen"],
    "el_inside_unit": ["Leistungsaufnahme", "Power input", "Puissance absorbée", "Potenza assorbita", "Opgenomen vermogen"],
    "main_mode": ["Raumklima Modus", "Room climate mode", "Mode de climat ambiant", "Modalità Clima ambiente", "Ruimteklimaat-Modus"],
    "opmode": ["Aktuelle Betriebsart", "Current operating mode", "Mode de fonctionnement actuel", "Modo operativo attuale", "Actuele bedrijfstoestand"],
    #"dhw_opmode": ["Modus", "Mode", "Mode", "Modo funzionamento", "Modus"],
    "absence_mode": ["Abwesenheitsmodus", "Absence mode", "Mode d'absence", "Modalità Assenza", "Afwezig mode"],
    "party_mode": ["Partymodus", "Party mode", "Mode de fête", "Modalità Party", "Partymodus"],
    "dhw_heating": ["1x WW aufheizen", "1x DHW heating", "1x WW Chauffage", "Riscaldare 1 x AC", "1x WW Opwarmen"],
    "comp_starts": ["Kompressorstarts", "Compressor starts", "Démarrages de compresseurs", "Avviamenti compressore", "Compressor opstarts"],
    "comp_hours": ["Laufzeit (Stunden)", "Runtime (hours)", "Durée (heures)", "Ore funzionamento", "Looptijd (uren)"],
    "mode1": ["Auto", "Auto", "Auto", "Auto", "Auto"],
    "mode2": ["Heizen", "Heating", "Chauffage", "Riscald.", "Verwarmen"],
    "mode3": ["Standby", "Standby", "Standby", "Standby", "Standby"],
    "mode4": ["Kühlen", "Cooling", "Refroidissement", "Raffredd.", "Koelen"],
    "dhwopmode0": ["Automatik Komfort", "Automatic comfort", "Automatic comfort", "Automatic comfort", "Automatisch comfort"],
    "dhwopmode1": ["Automatik Eco", "Automatic eco", "Automatic eco", "Automatic eco", "Automatisch eco"],
    "dhwopmode2": ["Nur Solar/PV", "Solar/PV only", "Solar/PV only", "Solar/PV only", "Zonnepanelen enkel", ],
    "dhwopmode3": ["Aus", "Off", "Off", "Off", "Uit"],
    "opmode1": ["Störung", "Forced off", "Forced off", "Forced off", "Forced off"],
    "opmode2": ["Abtauen", "Defrosting", "Defrosting", "Defrosting", "Defrosting"],
    "opmode3": ["Abtaupuffer", "Load defr. puffer", "Load defr. puffer", "Load defr. puffer", "Load defr. puffer"],
    "opmode4": ["WW Puffer", "DHW loading", "DHW loading", "DHW loading", "DHW loading"],
    "opmode5": ["Speicherenergie", "Storage energy", "Storage energy", "Storage energy", "Storage energy"],
    "opmode6": ["Heizen", "Heating", "Chauffage", "Riscald.", "Verwarmen"],
    "opmode7": ["Kühlen", "Cooling", "Refroidissement", "Raffredd.", "Koelen"],
    "opmode8": ["Pool", "Pool", "Pool", "Pool", "Pool"],
    "opmode9": ["Umwälzung", "Idle", "Idle" , "Idle" , "Idle"],
    "opmode10": ["Standby", "Standby", "Standby", "Standby", "Standby"],
    "opmode11": ["Estrichtrockung", "Screed drying", "Screed drying", "Screed drying", "Screed drying"],
    "opmode12": ["Frostschutz", "Frost protection", "Protection anti-gel", "Antigelo", "Vorstbeveiliging"],
    "opmode13": ["Prüfbetrieb", "Test mode", "Test mode", "Test mode", "Test mode"],
    "opmode14": ["Sperrsignal", "Blocking signal", "Blocking signal", "Blocking signal", "Blocking signal"],
    "opmode15": ["Hygienefunktion", "Hygiene function", "Hygiene function", "Hygiene function", "Hygiene function"],
    "opmode16": ["Silent Modus", "Silent mode", "Silent mode", "Silent mode", "Silent mode"],
    "dhw_temp": ["WW Speicher Ist-Temp."],
    }

Eigentlich steht nicht soviel drin, der Standard bis auf die Bivalenzpunkte.