mirror of
https://github.com/Andre0512/hon.git
synced 2026-06-15 03:36:27 +00:00
fix(thread-safety): use schedule_update_ha_state in async entity methods
Replace self.async_write_ha_state() with self.schedule_update_ha_state() in async command handlers across climate, fan, light, lock and switch entities. HA Core 2026.5.x enforces that async_write_ha_state() is only called from the event loop, but pyhon-revived delivers MQTT push updates from another thread, causing 'Detected blocking call'/thread-safety errors on 2026.5.4. See https://developers.home-assistant.io/docs/asyncio_thread_safety/#async_write_ha_state Fixes mmalolepszy/hon-revived#44 Cherry-picked from hon-revived PR #43 (head VadymMelnychuk:async-write-ha-state-fix). (cherry picked from commit e99a734c2dd07ca216f452a006b1605a1529a710) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
0fb3e2dc00
commit
047800ccbf
|
|
@ -196,7 +196,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
|
|||
|
||||
self._device.settings["settings.tempSel"].value = str(int(temperature))
|
||||
await self._device.commands["settings"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
|
|
@ -235,7 +235,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
|
|||
await self.async_set_preset_mode(HON_HVAC_PROGRAM[hvac_mode])
|
||||
return
|
||||
await self._device.commands["settings"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
await self._device.commands["startProgram"].send()
|
||||
|
|
@ -260,7 +260,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
|
|||
self.coordinator.async_set_updated_data({})
|
||||
self._attr_preset_mode = preset_mode
|
||||
await self._device.commands["startProgram"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def fan_modes(self) -> list[str]:
|
||||
|
|
@ -291,7 +291,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
|
|||
self._device.settings["settings.windSpeed"].value = str(fan_modes[fan_mode])
|
||||
self._attr_fan_mode = fan_mode
|
||||
await self._device.commands["settings"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def swing_mode(self) -> str | None:
|
||||
|
|
@ -328,7 +328,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
|
|||
horizontal.value = "0"
|
||||
self._attr_swing_mode = swing_mode
|
||||
await self._device.commands["settings"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self, update: bool = True) -> None:
|
||||
|
|
@ -397,7 +397,7 @@ class HonClimateEntity(HonEntity, ClimateEntity):
|
|||
return
|
||||
self._device.settings[self.entity_description.key].value = str(int(temperature))
|
||||
await self._device.commands["settings"].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
|
|
@ -414,7 +414,7 @@ class HonClimateEntity(HonEntity, ClimateEntity):
|
|||
else:
|
||||
await self._device.commands["startProgram"].send()
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Set the HVAC State to on."""
|
||||
|
|
@ -453,7 +453,7 @@ class HonClimateEntity(HonEntity, ClimateEntity):
|
|||
self._attr_preset_mode = preset_mode
|
||||
self.coordinator.async_set_updated_data({})
|
||||
await self._device.commands[command].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def _set_temperature_bound(self) -> None:
|
||||
temperature = self._device.settings[self.entity_description.key]
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class HonFanEntity(HonEntity, FanEntity):
|
|||
mode = math.ceil(percentage_to_ranged_value(self._speed_range, percentage))
|
||||
self._device.settings[self.entity_description.key].value = mode
|
||||
await self._device.commands[self._command].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
|
|
@ -112,7 +112,7 @@ class HonFanEntity(HonEntity, FanEntity):
|
|||
"""Turn the entity off."""
|
||||
self._device.settings[self.entity_description.key].value = 0
|
||||
await self._device.commands[self._command].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self, update: bool = True) -> None:
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class HonLightEntity(HonEntity, LightEntity):
|
|||
else:
|
||||
light.value = light.max
|
||||
await self._device.commands[self._command].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn off."""
|
||||
|
|
@ -119,7 +119,7 @@ class HonLightEntity(HonEntity, LightEntity):
|
|||
raise ValueError()
|
||||
light.value = light.min
|
||||
await self._device.commands[self._command].send()
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def brightness(self) -> int | None:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class HonLockEntity(HonEntity, LockEntity):
|
|||
if type(setting) == HonParameter or setting is None:
|
||||
return
|
||||
setting.value = setting.max if isinstance(setting, HonParameterRange) else 1
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
await self._device.commands["settings"].send()
|
||||
self.coordinator.async_set_updated_data({})
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ class HonLockEntity(HonEntity, LockEntity):
|
|||
if type(setting) == HonParameter:
|
||||
return
|
||||
setting.value = setting.min if isinstance(setting, HonParameterRange) else 0
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
await self._device.commands["settings"].send()
|
||||
self.coordinator.async_set_updated_data({})
|
||||
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ class HonSwitchEntity(HonEntity, SwitchEntity):
|
|||
if type(setting) == HonParameter:
|
||||
return
|
||||
setting.value = setting.max if isinstance(setting, HonParameterRange) else 1
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
await self._device.commands["settings"].send()
|
||||
self.coordinator.async_set_updated_data({})
|
||||
|
||||
|
|
@ -454,7 +454,7 @@ class HonSwitchEntity(HonEntity, SwitchEntity):
|
|||
if type(setting) == HonParameter:
|
||||
return
|
||||
setting.value = setting.min if isinstance(setting, HonParameterRange) else 0
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
await self._device.commands["settings"].send()
|
||||
self.coordinator.async_set_updated_data({})
|
||||
|
||||
|
|
@ -492,14 +492,14 @@ class HonControlSwitchEntity(HonEntity, SwitchEntity):
|
|||
self.coordinator.async_set_updated_data({})
|
||||
await self._device.commands[self.entity_description.turn_on_key].send()
|
||||
self._device.attributes[self.entity_description.key] = True
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
self._device.sync_command(self.entity_description.turn_off_key, "settings")
|
||||
self.coordinator.async_set_updated_data({})
|
||||
await self._device.commands[self.entity_description.turn_off_key].send()
|
||||
self._device.attributes[self.entity_description.key] = False
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
|
|
@ -542,7 +542,7 @@ class HonConfigSwitchEntity(HonEntity, SwitchEntity):
|
|||
return
|
||||
setting.value = setting.max if isinstance(setting, HonParameterRange) else "1"
|
||||
self.coordinator.async_set_updated_data({})
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
setting = self._device.settings[self.entity_description.key]
|
||||
|
|
@ -550,7 +550,7 @@ class HonConfigSwitchEntity(HonEntity, SwitchEntity):
|
|||
return
|
||||
setting.value = setting.min if isinstance(setting, HonParameterRange) else "0"
|
||||
self.coordinator.async_set_updated_data({})
|
||||
self.async_write_ha_state()
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self, update: bool = True) -> None:
|
||||
|
|
|
|||
Loading…
Reference in a new issue