Allow toggles (switches) state to be None (#64621)

This commit is contained in:
Franck Nijhof 2022-01-23 11:31:01 +01:00 committed by GitHub
parent 01fbc4257b
commit 176f03d4ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 45 additions and 32 deletions

View file

@ -117,7 +117,7 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
) )
@esphome_state_property @esphome_state_property
def is_on(self) -> bool | None: # type: ignore[override] def is_on(self) -> bool | None:
"""Return true if the entity is on.""" """Return true if the entity is on."""
return self._state.state return self._state.state

View file

@ -144,7 +144,7 @@ class EsphomeLight(EsphomeEntity[LightInfo, LightState], LightEntity):
return self._api_version >= APIVersion(1, 6) return self._api_version >= APIVersion(1, 6)
@esphome_state_property @esphome_state_property
def is_on(self) -> bool | None: # type: ignore[override] def is_on(self) -> bool | None:
"""Return true if the light is on.""" """Return true if the light is on."""
return self._state.state return self._state.state

View file

@ -41,7 +41,7 @@ class EsphomeSwitch(EsphomeEntity[SwitchInfo, SwitchState], SwitchEntity):
return self._static_info.assumed_state return self._static_info.assumed_state
@esphome_state_property @esphome_state_property
def is_on(self) -> bool | None: # type: ignore[override] def is_on(self) -> bool | None:
"""Return true if the switch is on.""" """Return true if the switch is on."""
return self._state.state return self._state.state

View file

@ -1,4 +1,6 @@
"""Support for Freedompro fan.""" """Support for Freedompro fan."""
from __future__ import annotations
import json import json
from pyfreedompro import put_state from pyfreedompro import put_state
@ -51,7 +53,7 @@ class FreedomproFan(CoordinatorEntity, FanEntity):
self._attr_percentage = 0 self._attr_percentage = 0
@property @property
def is_on(self) -> bool: def is_on(self) -> bool | None:
"""Return True if entity is on.""" """Return True if entity is on."""
return self._attr_is_on return self._attr_is_on

View file

@ -364,6 +364,8 @@ async def async_setup_entry(
class FritzBoxBaseSwitch(FritzBoxBaseEntity): class FritzBoxBaseSwitch(FritzBoxBaseEntity):
"""Fritz switch base class.""" """Fritz switch base class."""
_attr_is_on: bool | None = False
def __init__( def __init__(
self, self,
avm_wrapper: AvmWrapper, avm_wrapper: AvmWrapper,
@ -386,8 +388,6 @@ class FritzBoxBaseSwitch(FritzBoxBaseEntity):
self._attributes: dict[str, str] = {} self._attributes: dict[str, str] = {}
self._is_available = True self._is_available = True
self._attr_is_on = False
@property @property
def name(self) -> str: def name(self) -> str:
"""Return name.""" """Return name."""

View file

@ -48,7 +48,7 @@ class ModbusFan(BaseSwitch, FanEntity):
await self.async_turn(self.command_on) await self.async_turn(self.command_on)
@property @property
def is_on(self) -> bool: def is_on(self) -> bool | None:
"""Return true if fan is on. """Return true if fan is on.
This is needed due to the ongoing conversion of fan. This is needed due to the ongoing conversion of fan.

View file

@ -161,7 +161,7 @@ class SwitchBotBotEntity(SwitchbotEntity, SwitchEntity, RestoreEntity):
return False return False
@property @property
def is_on(self) -> bool: def is_on(self) -> bool | None:
"""Return true if device is on.""" """Return true if device is on."""
if not self.data["data"]["switchMode"]: if not self.data["data"]["switchMode"]:
return self._attr_is_on return self._attr_is_on

View file

@ -100,7 +100,7 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
await self.info.node.async_set_value(self._target_value, 0) await self.info.node.async_set_value(self._target_value, 0)
@property @property
def is_on(self) -> bool | None: # type: ignore def is_on(self) -> bool | None:
"""Return true if device is on (speed above 0).""" """Return true if device is on (speed above 0)."""
if self.info.primary_value.value is None: if self.info.primary_value.value is None:
# guard missing value # guard missing value

View file

@ -65,7 +65,7 @@ class ZWaveSwitch(ZWaveBaseEntity, SwitchEntity):
self._target_value = self.get_zwave_value(TARGET_VALUE_PROPERTY) self._target_value = self.get_zwave_value(TARGET_VALUE_PROPERTY)
@property @property
def is_on(self) -> bool | None: # type: ignore def is_on(self) -> bool | None:
"""Return a boolean for the state of the switch.""" """Return a boolean for the state of the switch."""
if self.info.primary_value.value is None: if self.info.primary_value.value is None:
# guard missing value # guard missing value
@ -107,7 +107,7 @@ class ZWaveBarrierEventSignalingSwitch(ZWaveBaseEntity, SwitchEntity):
self._update_state() self._update_state()
@property @property
def is_on(self) -> bool | None: # type: ignore def is_on(self) -> bool | None:
"""Return a boolean for the state of the switch.""" """Return a boolean for the state of the switch."""
return self._state return self._state

View file

@ -927,17 +927,19 @@ class ToggleEntity(Entity):
"""An abstract class for entities that can be turned on and off.""" """An abstract class for entities that can be turned on and off."""
entity_description: ToggleEntityDescription entity_description: ToggleEntityDescription
_attr_is_on: bool _attr_is_on: bool | None = None
_attr_state: None = None _attr_state: None = None
@property @property
@final @final
def state(self) -> str | None: def state(self) -> Literal["on", "off"] | None:
"""Return the state.""" """Return the state."""
return STATE_ON if self.is_on else STATE_OFF if (is_on := self.is_on) is None:
return None
return STATE_ON if is_on else STATE_OFF
@property @property
def is_on(self) -> bool: def is_on(self) -> bool | None:
"""Return True if entity is on.""" """Return True if entity is on."""
return self._attr_is_on return self._attr_is_on

View file

@ -12,7 +12,13 @@ from homeassistant.components.light import (
COLOR_MODE_BRIGHTNESS, COLOR_MODE_BRIGHTNESS,
COLOR_MODE_RGBW, COLOR_MODE_RGBW,
) )
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, STATE_ON from homeassistant.const import (
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
)
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
from .conftest import async_setup_entity, mock_feature from .conftest import async_setup_entity, mock_feature
@ -226,7 +232,7 @@ async def test_wlightbox_s_init(wlightbox_s, hass, config):
assert color_modes == [COLOR_MODE_BRIGHTNESS] assert color_modes == [COLOR_MODE_BRIGHTNESS]
assert ATTR_BRIGHTNESS not in state.attributes assert ATTR_BRIGHTNESS not in state.attributes
assert state.state == STATE_OFF assert state.state == STATE_UNKNOWN
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id) device = device_registry.async_get(entry.device_id)
@ -327,7 +333,7 @@ async def test_wlightbox_init(wlightbox, hass, config):
assert ATTR_BRIGHTNESS not in state.attributes assert ATTR_BRIGHTNESS not in state.attributes
assert ATTR_RGBW_COLOR not in state.attributes assert ATTR_RGBW_COLOR not in state.attributes
assert state.state == STATE_OFF assert state.state == STATE_UNKNOWN
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id) device = device_registry.async_get(entry.device_id)

View file

@ -12,6 +12,7 @@ from homeassistant.const import (
SERVICE_TURN_ON, SERVICE_TURN_ON,
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
STATE_UNKNOWN,
) )
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
@ -202,7 +203,7 @@ async def test_switchbox_d_init(switchbox_d, hass, config):
state = hass.states.get(entity_ids[0]) state = hass.states.get(entity_ids[0])
assert state.name == "switchBoxD-0.relay" assert state.name == "switchBoxD-0.relay"
assert state.attributes[ATTR_DEVICE_CLASS] == SwitchDeviceClass.SWITCH assert state.attributes[ATTR_DEVICE_CLASS] == SwitchDeviceClass.SWITCH
assert state.state == STATE_OFF # NOTE: should instead be STATE_UNKNOWN? assert state.state == STATE_UNKNOWN
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id) device = device_registry.async_get(entry.device_id)
@ -219,7 +220,7 @@ async def test_switchbox_d_init(switchbox_d, hass, config):
state = hass.states.get(entity_ids[1]) state = hass.states.get(entity_ids[1])
assert state.name == "switchBoxD-1.relay" assert state.name == "switchBoxD-1.relay"
assert state.attributes[ATTR_DEVICE_CLASS] == SwitchDeviceClass.SWITCH assert state.attributes[ATTR_DEVICE_CLASS] == SwitchDeviceClass.SWITCH
assert state.state == STATE_OFF # NOTE: should instead be STATE_UNKNOWN? assert state.state == STATE_UNKNOWN
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id) device = device_registry.async_get(entry.device_id)

View file

@ -5,6 +5,7 @@ import pytest
from homeassistant.components.light import ATTR_BRIGHTNESS from homeassistant.components.light import ATTR_BRIGHTNESS
from homeassistant.components.rfxtrx import DOMAIN from homeassistant.components.rfxtrx import DOMAIN
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import State from homeassistant.core import State
from tests.common import MockConfigEntry, mock_restore_cache from tests.common import MockConfigEntry, mock_restore_cache
@ -25,7 +26,7 @@ async def test_one_light(hass, rfxtrx):
state = hass.states.get("light.ac_213c7f2_16") state = hass.states.get("light.ac_213c7f2_16")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:16" assert state.attributes.get("friendly_name") == "AC 213c7f2:16"
await hass.services.async_call( await hass.services.async_call(
@ -132,17 +133,17 @@ async def test_several_lights(hass, rfxtrx):
state = hass.states.get("light.ac_213c7f2_48") state = hass.states.get("light.ac_213c7f2_48")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:48" assert state.attributes.get("friendly_name") == "AC 213c7f2:48"
state = hass.states.get("light.ac_118cdea_2") state = hass.states.get("light.ac_118cdea_2")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 118cdea:2" assert state.attributes.get("friendly_name") == "AC 118cdea:2"
state = hass.states.get("light.ac_1118cdea_2") state = hass.states.get("light.ac_1118cdea_2")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 1118cdea:2" assert state.attributes.get("friendly_name") == "AC 1118cdea:2"
await rfxtrx.signal("0b1100cd0213c7f230010f71") await rfxtrx.signal("0b1100cd0213c7f230010f71")

View file

@ -5,6 +5,7 @@ import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.rfxtrx import DOMAIN from homeassistant.components.rfxtrx import DOMAIN
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import State from homeassistant.core import State
from tests.common import MockConfigEntry, mock_restore_cache from tests.common import MockConfigEntry, mock_restore_cache
@ -28,7 +29,7 @@ async def test_one_switch(hass, rfxtrx):
state = hass.states.get("switch.ac_213c7f2_16") state = hass.states.get("switch.ac_213c7f2_16")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:16" assert state.attributes.get("friendly_name") == "AC 213c7f2:16"
await hass.services.async_call( await hass.services.async_call(
@ -90,17 +91,17 @@ async def test_several_switches(hass, rfxtrx):
state = hass.states.get("switch.ac_213c7f2_48") state = hass.states.get("switch.ac_213c7f2_48")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:48" assert state.attributes.get("friendly_name") == "AC 213c7f2:48"
state = hass.states.get("switch.ac_118cdea_2") state = hass.states.get("switch.ac_118cdea_2")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 118cdea:2" assert state.attributes.get("friendly_name") == "AC 118cdea:2"
state = hass.states.get("switch.ac_1118cdea_2") state = hass.states.get("switch.ac_1118cdea_2")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 1118cdea:2" assert state.attributes.get("friendly_name") == "AC 1118cdea:2"
@ -142,22 +143,22 @@ async def test_switch_events(hass, rfxtrx):
state = hass.states.get("switch.ac_213c7f2_16") state = hass.states.get("switch.ac_213c7f2_16")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:16" assert state.attributes.get("friendly_name") == "AC 213c7f2:16"
state = hass.states.get("switch.ac_213c7f2_5") state = hass.states.get("switch.ac_213c7f2_5")
assert state assert state
assert state.state == "off" assert state.state == STATE_UNKNOWN
assert state.attributes.get("friendly_name") == "AC 213c7f2:5" assert state.attributes.get("friendly_name") == "AC 213c7f2:5"
# "16: On" # "16: On"
await rfxtrx.signal("0b1100100213c7f210010f70") await rfxtrx.signal("0b1100100213c7f210010f70")
assert hass.states.get("switch.ac_213c7f2_5").state == "off" assert hass.states.get("switch.ac_213c7f2_5").state == STATE_UNKNOWN
assert hass.states.get("switch.ac_213c7f2_16").state == "on" assert hass.states.get("switch.ac_213c7f2_16").state == "on"
# "16: Off" # "16: Off"
await rfxtrx.signal("0b1100100213c7f210000f70") await rfxtrx.signal("0b1100100213c7f210000f70")
assert hass.states.get("switch.ac_213c7f2_5").state == "off" assert hass.states.get("switch.ac_213c7f2_5").state == STATE_UNKNOWN
assert hass.states.get("switch.ac_213c7f2_16").state == "off" assert hass.states.get("switch.ac_213c7f2_16").state == "off"
# "5: On" # "5: On"