gtdiehl / iotawatt_ha

IoTaWatt for Home Assistant
Apache License 2.0
16 stars 16 forks source link

Removing sensor from IoTaWatt device causes errors #1

Closed gtdiehl closed 3 years ago

gtdiehl commented 3 years ago

When removing a sensor from the IoTaWatt webpage, Home Assistant tries to update the state of the removed sensor and results in the errors in the log to appear for every poll

Traceback (most recent call last):
  File "/Users/greg/Documents/GitHub/core/homeassistant/helpers/update_coordinator.py", line 119, in _handle_refresh_interval
    await self.async_refresh()
  File "/Users/greg/Documents/GitHub/core/homeassistant/helpers/update_coordinator.py", line 193, in async_refresh
    update_callback()
  File "/Users/greg/Documents/GitHub/core/homeassistant/helpers/update_coordinator.py", line 245, in _handle_coordinator_update
    self.async_write_ha_state()
  File "/Users/greg/Documents/GitHub/core/homeassistant/helpers/entity.py", line 296, in async_write_ha_state
    self._async_write_ha_state()
  File "/Users/greg/Documents/GitHub/core/homeassistant/helpers/entity.py", line 320, in _async_write_ha_state
    sstate = self.state
  File "/Users/greg/Documents/GitHub/core/homeassistant/components/iotawatt/sensor.py", line 89, in state
    return self.coordinator.data["sensors"][self._ent].getValue()
KeyError: 'output_mhghjk'
mmiller7 commented 3 years ago

Same issue - can't figure out how to remove an old sensor without deleting the entire addon and reinstalling.

jherby2k commented 3 years ago

Renaming an output causes havok as well

gtdiehl commented 3 years ago

Any ideas on how to if this? 🤷

Ideally, I would want to resolve this one before submitting it to the HA repo for inclusion.

EDIT: It appears to be the logic on the API side.

gtdiehl commented 3 years ago

I fixed the issue on the API side and released a new version to PyPi 0.0.7. The issue is now in the IoTaWatt sensor code.

Below is a trackback from the sensor code in my branch


Traceback (most recent call last):
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 134, in _handle_refresh_interval
    await self._async_refresh(log_failures=True, scheduled=True)
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 265, in _async_refresh
    update_callback()
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 325, in _handle_coordinator_update
    self.async_write_ha_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 464, in async_write_ha_state
    self._async_write_ha_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 498, in _async_write_ha_state
    state = self._stringify_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 470, in _stringify_state
    state = self.state
  File "/workspaces/core/homeassistant/components/iotawatt/sensor.py", line 103, in state
    return self.coordinator.data["sensors"][self._ent].getValue()
KeyError: 'output_vvv'
balloob commented 3 years ago

Step 1 is to add a new available property so it won't fetch the state anymore:

@property
def available(self) -> bool:
    """Return if entity is available."""
    return super().available and self._ent in self.coordinator.data["sensors"]
balloob commented 3 years ago

That way it will be marked as unavailable and won't cause a key error.

A more proper fix is to remove the sensor completely. You can do that by overriding _handle_coordinator_update in sensor entity. If the key doesn't exist anymore in the output, delete the entity:

from homeassistant.helpers import entity_registry

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        if self._ent not in self.coordinator.data["sensors"]:
            entity_registry.async_get(self.hass).async_remove(self.entity_id)
            return

        super()._handle_coordinator_update()
gtdiehl commented 3 years ago

@balloob Thank you for your insights! I will take a look. 😃

gtdiehl commented 3 years ago

@balloob I tried adding an available method a while ago, and it did not seem to work. Even when I did a quick hack and set all entities to unavailable Home Assistant would still try and get some info. I'll try it again or see if the callback works.

I wanted to set an entity to unavailable rather than removing it so that historical data is still accessible. In either case I'll see what I can make work.

gtdiehl commented 3 years ago

@balloob Sorry to flood you with messages! But the @callback works.

I can live with the removal of older data from Home Assistant when removing/renaming a sensor from the IoTaWatt web interface.