Repository navigation
24V thermostats: mode, fan mode, humidity and cooling setpoint are received but never surfaced #998
Description
Summary
For 24 V thermostats (LowVoltageThermostat, e.g. a Honeywell T10 enrolled in Hilo), the climate entity is permanently stuck on hvac_modes: ['heat'] with the heating setpoint, even while the system is actively cooling. Mode, fan mode, ambient humidity and the cooling setpoint are all received from the Hilo API and stored as readings — they are simply never surfaced.
I own this hardware and can test and support the feature, which I understand has been the blocker on similar requests (#824, #473).
Environment
- Home Assistant Core 2026.7.4 (HAOS 18.2)
hilo2026.8.1 (HACS)python-hilo2026.3.5- Device: Honeywell T10, reported by Hilo as a low voltage thermostat (heat pump with auxiliary heat)
What happens
The Hilo app itself offers Auto / Heat / Emergency Heat / Cool / Off, three fan modes and ambient humidity. Home Assistant shows:
climate.thermostat_central
state : heat # hardcoded
hvac_modes : ['heat']
temperature : 21 # heating setpoint, while cooling to 24
current_temperature: 24
supported_features : 1
Root cause
The data does arrive. Dumping device.readings for this thermostat gives:
['CoolTemperatureSet', 'CurrentState', 'CurrentTemperature', 'Disconnected', 'FanMode',
'FanSpeed', 'GdState', 'Heating', 'Humidity', 'MaxCoolSetpoint', 'MaxTempSetpoint',
'MinCoolSetpoint', 'MinTempSetpoint', 'Power', 'TargetTemperature',
'Thermostat24VAllowedFanMode', 'Thermostat24VAllowedMode', 'Thermostat24VMode',
'ThermostatAllowedModes', 'ThermostatMode', 'Unpaired', 'Version', 'ZigbeeVersion']
Two independent problems:
1. climate.py hardcodes heating. _attr_hvac_modes = [HVACMode.HEAT], hvac_mode returns HVACMode.HEAT, and set_hvac_mode() is an empty return.
2. Those attributes cannot be read back through get_value(). The 24 V attribute names are built by graphql_value_mapper but are absent from the static registry in pyhilo/const.py (only Humidity is present there). HiloDevice.get_value() resolves names through API.dev_atts(), which — for an unregistered name and with no value_type — returns the plain string instead of a DeviceAttribute. _get_attribute() then compares that string against reading.device_attribute objects, never matches, and returns None. The value is lost silently, with no warning.
Readings themselves are fine, because build_attribute() passes valueType, which makes dev_atts() take its fallback branch and construct a proper DeviceAttribute.
Fix and result
Reading the values directly off device.readings (matching on reading.device_attribute.hilo_attribute) and deriving the modes from Thermostat24VAllowedMode gives, on the same device, with no library change:
state : cool
hvac_modes : ['heat', 'off', 'cool', 'heat_cool']
fan_mode : ON
fan_modes : ['ON', 'AUTO', 'CIRCULATE']
current_humidity : 53
temperature : 24 # cooling setpoint while in cool mode
supported_features : 393
Everything is gated on the 24 V readings being present, so baseboard thermostats keep the exact previous behaviour (['heat'], TARGET_TEMPERATURE only).
I would be happy to open a PR with this if you are open to it.
Related: writes are refused on these devices
While testing the setters I found that Hilo advertises:
settable_attributes = ['Disconnected']
so HiloDevice._set_attribute() drops every command — mode, fan and temperature. I believe this is the actual cause of #937 (temperature changes working in the Hilo app but not from Home Assistant on a Sinopé 24 V), and it cannot be fixed from climate.py. I have posted the details there.
In the meantime my setters raise an explicit HomeAssistantError rather than failing silently, so the UI does not offer a control that quietly does nothing.
Activity
ic-dev21 commentedon Aug 2, 2026
Duplicate of #937, I do not own any devices to test code out on this so fixing it will require outside help else I'm going in totally blind.
24V thermostats expect a batch attribute set, no a single attribute. They need to receive setpoints for both heating and cooling, even if one or the other hasn't changed. This is the root of your issue.
ic-dev21 commentedon Aug 2, 2026
@ColtHub
Your "PUT" command must be sent to this endpoint:
Automation/v1/api/Locations/{location_id}/Devices/BatchAttributesPayload should be a string dict mapping to the device's attributes list, i.e:
{"456": {"Hue": 120.0, "Saturation": 80.0}}min_temp setpoint and max_temp_setpoint must be sent together.
It's not much, but it's all I know.
ColtHub commentedon Aug 2, 2026
(je passe au français, j'avais ouvert en anglais par réflexe — dis-moi si tu préfères qu'on garde l'anglais pour le tracker)
Merci pour l'indication sur l'envoi groupé : elle était juste et c'est elle qui m'a débloqué. J'ai testé sur mon T10, et il y a un deuxième obstacle que je n'avais pas isolé.
Ce que j'ai mesuré
PUT Locations/{loc}/Devices/{id}/Attributesavec le lot complet :{"Thermostat24VMode": "HEAT", "TargetTemperature": 20.0, "CoolTemperatureSet": 22}Réponse :
[{"operationId": "6078ab26-...", "status": 1, "statusReason": 0, "message": null}]L'API accepte et applique. Vérifié de bout en bout, trois fois :
HEAT→COOLON→AUTOLa relecture est une vraie confirmation et non un affichage optimiste : mon code
court-circuite
set_attribute(), doncpyhilone met à jour aucun état local — la valeurrevient bien de Hilo par le flux de lecture.
Le blocage principal est côté client
C'est le point que je n'avais pas vu et qui change le diagnostic de #937 :
Hilo ne déclare rien de modifiable sur ces thermostats, alors que l'API accepte
parfaitement l'écriture. Or
HiloDevice._set_attribute()ne fait rien quand l'attribut estabsent de
settable_attributes— donc la requête n'est jamais émise, quel que soit sonformat. C'est ce qui produit le
Invalid attribute DeviceAttribute(hilo_attribute='TargetTemperature', ...) for devicerapporté dans #937.Autrement dit, les deux obstacles s'empilent : l'envoi groupé est nécessaire, comme tu le
dis, mais tant que le garde-fou refuse, aucun envoi — groupé ou non — ne part.
Au passage, le vocabulaire réel des modes est
['EMERGENCY_HEAT', 'HEAT', 'OFF', 'COOL', 'AUTO'].Ce que je peux proposer
J'ai chez moi un
climate.pycomplet qui fait lecture et écriture sur le T10, avecnon-régression vérifiée sur mes 6 thermostats de plinthe (ils restent en
['heat'],supported_features: 1, sans ventilateur). Il tourne en production.Deux réserves avant d'ouvrir une PR, et j'aimerais ton avis :
_batch_put()appelleapi.async_request()etapi._get_url(), donc des méthodesprivées de python-hilo. Ça convient à un correctif local, pas à une contribution propre.
Préfères-tu que le lot soit exposé par la bibliothèque — par exemple un
HiloDevice.set_attributes(dict)— et que l'intégration s'y branche ?settable_attributespour ces appareils, ou plutôt corriger la façondont la liste est peuplée ? Je n'ai pas assez de recul sur les autres types d'appareils
pour trancher sans risquer une régression ailleurs.
Dis-moi la forme qui te convient et je la prépare. Je peux tester chaque itération sur du
vrai matériel, donc tu n'as pas à avancer à l'aveugle sur cette partie-là.
ic-dev21 commentedon Aug 2, 2026
Salut, aucune préférence de mon côté pour la langue, vas-y comme tu le sens.
J'ai des contacts dans la communauté ainsi que chez HQ qui peuvent aussi beta tester au besoin, je vais devoir m'en remettre à eux pour ce bout-là.
Pour ce qui est de tes questions. Je pense qu'une version "propre" est préférable sur le long terme, tu n'est certainement pas le seul utilisateur qui a ces thermostats comme en témoigne l'autre issue. Je peux merger et build le release mais je vais avoir besoin de support externe pour les tests.
Si jamais tu veux sync up ou jaser de vive voix la communauté est pas mal active sur discord quand même. Full disclaimer, je ne suis pas programmeur donc des fois je comprends vite quand on m'explique longtemps.
Toujours plaisant de voir la communauté open source s'entraider comme ça, merci d'avance!
aboredman commentedon Aug 6, 2026
J'ai un problème identique avec un Honeywell T6 et peut aider pour les tests au besoin
ColtHub commentedon Aug 13, 2026
Les deux PR sont ouvertes :
Testsy exécute vraiment la suite : 97 tests).J'ai suivi ta préférence pour la version propre : plus aucune méthode privée de
python-hilon'est appelée depuis l'intégration. L'envoi groupé est exposé par la bibliothèque sousHiloDevice.set_attributes(dict), etclimate.pyne fait plus que traduire entre les propriétés deClimateet le modèle Home Assistant — aucun nom d'attribut Hilo ne descend dans l'intégration.Sur ta suggestion pour
settable_attributes— j'ai divergé, dis-moi si j'ai eu tortTu proposais de conditionner
settable_attributesselon ledevicetype. J'ai pris un autre chemin et je préfère te le dire franchement.set_attributes()est une méthode distincte qui ne consulte passettable_attributesdu tout._set_attribute()et son garde-fou ne sont pas touchés d'une ligne. Mon raisonnement : tu as dit devoir avancer à l'aveugle sur le matériel que tu ne possèdes pas, et toucher au garde-fou aurait mis en jeu tous les types d'appareils — lampes, interrupteurs, chauffe-eau. Là, le pire cas d'une erreur de ma part reste confiné aux thermostats 24 V.L'inconvénient, c'est que la cause racine reste : Hilo continue d'annoncer
settable_attributes = ['Disconnected']à tort. On contourne au lieu de corriger. Si tu préfères ta version, je la prépare — mais il faudrait alors quelqu'un pour valider qu'aucun autre type d'appareil ne régresse.Note aussi que j'ai utilisé
PUT Locations/{loc}/Devices/{id}/Attributes, l'endpoint que j'avais mesuré comme fonctionnel, et non leBatchAttributesque tu mentionnais. Si le second est la voie officielle, je bascule volontiers.Validé sur matériel réel
Honeywell T10, à côté de six thermostats de plinthe sur la même installation.
ON→AUTO→ONcool→heat→coolLes relectures sont de vraies confirmations :
set_attributes()ne met à jour aucun état local, donc les valeurs reviennent bien de Hilo.Un détail qui valait la peine d'être trouvé : ton appareil annonce ses modes dans l'ordre
['EMERGENCY_HEAT', 'HEAT', 'OFF', 'COOL', 'AUTO'], etEMERGENCY_HEATcommeHEATcorrespondent tous deux àHVACMode.HEAT. Prendre le premier de la liste qui correspond écrivait doncEMERGENCY_HEATpour une simple demande de chauffage — sur une thermopompe, c'est la résistance d'appoint qui s'enclenche, à plusieurs fois le coût, sans rien d'anormal à l'écran. La sélection privilégie maintenant la correspondance exacte. Il y a un test de régression dessus.Un défaut de l'API que je te signale au passage
Thermostat24VAllowedModeannonceAUTO, et ton application l'offre dans son interface. Mon T10 ne le tient pas : le mode retombe surCoolen quelques secondes, y compris quand je le sélectionne depuis l'application Hilo — donc sans mon code dans la boucle. Home Assistant n'a jamais eu le temps de le lire.Le vocabulaire annoncé n'est donc pas une liste de capacités fiable. Je n'ai rien câblé en dur : un seul appareil est une base trop mince. La question est dans la PR — faut-il filtrer
AUTO? Tu sauras si c'est propre au T10, à la passerelle, ou commun à tous les 24 V.Pour les tests
@aboredman a un Honeywell T6 avec le même problème et propose d'aider — ça tombe bien, c'est un second modèle et tu disais avoir besoin de support externe. Le T6 devrait exposer les mêmes attributs ; s'il annonce un vocabulaire de modes différent du mien, c'est exactement ce qu'il faut savoir avant de fusionner.
De mon côté je fais tourner ces branches en production sur ma box et je peux valider chaque itération sur du vrai matériel.
Limites déclarées
hvac_actionafficheidlependant que l'appareil climatise. Il est dérivé de la seule lectureheating. L'attributcurrent_stateporterait la vraie réponse, mais je ne l'ai jamais observé qu'àOFF— je ne voulais pas inventer une correspondance sur un seul échantillon.heat_cooln'est pas testable pour la raison ci-dessus.Prends le temps qu'il te faut, et dis-moi si tu veux que je change quoi que ce soit dans la forme.
ic-dev21 commentedon Aug 13, 2026
Je vais m'en remettre à l'expertise de @nlz242 qui a une meilleure connaissance du backend Hilo et qui aura les vraies réponses à tes questions.
ColtHub commentedon Sep 9, 2026
Est-ce que le dossier a bougé depuis?
ic-dev21 commentedon Sep 9, 2026
J’attends des news, mais dès que c’est testé avec les divers trucs 24v (pas juste les tiens) ça sera merge et release
etiennnr commentedon Oct 24, 2026
PVI, même problème avec mon Sinopé TH6250WF. Je suis prêt à aider avec les tests au besoin 😄