Convert zerproc to use new upstream async api (#44357)

This commit is contained in:
Emily Mills 2020-12-19 09:35:47 -06:00 committed by GitHub
parent 896f51fd82
commit 9de393d116
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 32 additions and 42 deletions

View file

@ -14,7 +14,7 @@ _LOGGER = logging.getLogger(__name__)
async def _async_has_devices(hass) -> bool: async def _async_has_devices(hass) -> bool:
"""Return if there are devices that can be discovered.""" """Return if there are devices that can be discovered."""
try: try:
devices = await hass.async_add_executor_job(pyzerproc.discover) devices = await pyzerproc.discover()
return len(devices) > 0 return len(devices) > 0
except pyzerproc.ZerprocException: except pyzerproc.ZerprocException:
_LOGGER.error("Unable to discover nearby Zerproc devices", exc_info=True) _LOGGER.error("Unable to discover nearby Zerproc devices", exc_info=True)

View file

@ -28,25 +28,10 @@ SUPPORT_ZERPROC = SUPPORT_BRIGHTNESS | SUPPORT_COLOR
DISCOVERY_INTERVAL = timedelta(seconds=60) DISCOVERY_INTERVAL = timedelta(seconds=60)
PARALLEL_UPDATES = 0
async def discover_entities(hass: HomeAssistant) -> List[Entity]:
def connect_lights(lights: List[pyzerproc.Light]) -> List[pyzerproc.Light]:
"""Attempt to connect to lights, and return the connected lights."""
connected = []
for light in lights:
try:
light.connect()
connected.append(light)
except pyzerproc.ZerprocException:
_LOGGER.debug("Unable to connect to '%s'", light.address, exc_info=True)
return connected
def discover_entities(hass: HomeAssistant) -> List[Entity]:
"""Attempt to discover new lights.""" """Attempt to discover new lights."""
lights = pyzerproc.discover() lights = await pyzerproc.discover()
# Filter out already discovered lights # Filter out already discovered lights
new_lights = [ new_lights = [
@ -54,8 +39,13 @@ def discover_entities(hass: HomeAssistant) -> List[Entity]:
] ]
entities = [] entities = []
for light in connect_lights(new_lights): for light in new_lights:
# Double-check the light hasn't been added in another thread try:
await light.connect()
except pyzerproc.ZerprocException:
_LOGGER.debug("Unable to connect to '%s'", light.address, exc_info=True)
continue
# Double-check the light hasn't been added in the meantime
if light.address not in hass.data[DOMAIN]["addresses"]: if light.address not in hass.data[DOMAIN]["addresses"]:
hass.data[DOMAIN]["addresses"].add(light.address) hass.data[DOMAIN]["addresses"].add(light.address)
entities.append(ZerprocLight(light)) entities.append(ZerprocLight(light))
@ -68,7 +58,7 @@ async def async_setup_entry(
config_entry: ConfigEntry, config_entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None], async_add_entities: Callable[[List[Entity], bool], None],
) -> None: ) -> None:
"""Set up Abode light devices.""" """Set up Zerproc light devices."""
if DOMAIN not in hass.data: if DOMAIN not in hass.data:
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {}
if "addresses" not in hass.data[DOMAIN]: if "addresses" not in hass.data[DOMAIN]:
@ -80,7 +70,7 @@ async def async_setup_entry(
"""Wrap discovery to include params.""" """Wrap discovery to include params."""
nonlocal warned nonlocal warned
try: try:
entities = await hass.async_add_executor_job(discover_entities, hass) entities = await discover_entities(hass)
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
warned = False warned = False
except pyzerproc.ZerprocException: except pyzerproc.ZerprocException:
@ -117,11 +107,11 @@ class ZerprocLight(LightEntity):
async def async_will_remove_from_hass(self) -> None: async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass.""" """Run when entity will be removed from hass."""
await self.hass.async_add_executor_job(self._light.disconnect) await self._light.disconnect()
def on_hass_shutdown(self, event): async def on_hass_shutdown(self, event):
"""Execute when Home Assistant is shutting down.""" """Execute when Home Assistant is shutting down."""
self._light.disconnect() await self._light.disconnect()
@property @property
def name(self): def name(self):
@ -172,7 +162,7 @@ class ZerprocLight(LightEntity):
"""Return True if entity is available.""" """Return True if entity is available."""
return self._available return self._available
def turn_on(self, **kwargs): async def async_turn_on(self, **kwargs):
"""Instruct the light to turn on.""" """Instruct the light to turn on."""
if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs: if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs:
default_hs = (0, 0) if self._hs_color is None else self._hs_color default_hs = (0, 0) if self._hs_color is None else self._hs_color
@ -182,20 +172,20 @@ class ZerprocLight(LightEntity):
brightness = kwargs.get(ATTR_BRIGHTNESS, default_brightness) brightness = kwargs.get(ATTR_BRIGHTNESS, default_brightness)
rgb = color_util.color_hsv_to_RGB(*hue_sat, brightness / 255 * 100) rgb = color_util.color_hsv_to_RGB(*hue_sat, brightness / 255 * 100)
self._light.set_color(*rgb) await self._light.set_color(*rgb)
else: else:
self._light.turn_on() await self._light.turn_on()
def turn_off(self, **kwargs): async def async_turn_off(self, **kwargs):
"""Instruct the light to turn off.""" """Instruct the light to turn off."""
self._light.turn_off() await self._light.turn_off()
def update(self): async def async_update(self):
"""Fetch new state data for this light.""" """Fetch new state data for this light."""
try: try:
if not self._light.connected: if not await self._light.is_connected():
self._light.connect() await self._light.connect()
state = self._light.get_state() state = await self._light.get_state()
except pyzerproc.ZerprocException: except pyzerproc.ZerprocException:
if self._available: if self._available:
_LOGGER.warning("Unable to connect to %s", self.entity_id) _LOGGER.warning("Unable to connect to %s", self.entity_id)

View file

@ -4,7 +4,7 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/zerproc", "documentation": "https://www.home-assistant.io/integrations/zerproc",
"requirements": [ "requirements": [
"pyzerproc==0.3.0" "pyzerproc==0.4.3"
], ],
"codeowners": [ "codeowners": [
"@emlove" "@emlove"

View file

@ -1904,7 +1904,7 @@ pyxeoma==1.4.1
pyzbar==0.1.7 pyzbar==0.1.7
# homeassistant.components.zerproc # homeassistant.components.zerproc
pyzerproc==0.3.0 pyzerproc==0.4.3
# homeassistant.components.qnap # homeassistant.components.qnap
qnapstats==0.3.0 qnapstats==0.3.0

View file

@ -939,7 +939,7 @@ pywemo==0.5.3
pywilight==0.0.65 pywilight==0.0.65
# homeassistant.components.zerproc # homeassistant.components.zerproc
pyzerproc==0.3.0 pyzerproc==0.4.3
# homeassistant.components.rachio # homeassistant.components.rachio
rachiopy==1.0.3 rachiopy==1.0.3

View file

@ -44,7 +44,7 @@ async def mock_light(hass, mock_entry):
light = MagicMock(spec=pyzerproc.Light) light = MagicMock(spec=pyzerproc.Light)
light.address = "AA:BB:CC:DD:EE:FF" light.address = "AA:BB:CC:DD:EE:FF"
light.name = "LEDBlue-CCDDEEFF" light.name = "LEDBlue-CCDDEEFF"
light.connected = False light.is_connected.return_value = False
mock_state = pyzerproc.LightState(False, (0, 0, 0)) mock_state = pyzerproc.LightState(False, (0, 0, 0))
@ -57,7 +57,7 @@ async def mock_light(hass, mock_entry):
await hass.config_entries.async_setup(mock_entry.entry_id) await hass.config_entries.async_setup(mock_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
light.connected = True light.is_connected.return_value = True
return light return light
@ -71,12 +71,12 @@ async def test_init(hass, mock_entry):
mock_light_1 = MagicMock(spec=pyzerproc.Light) mock_light_1 = MagicMock(spec=pyzerproc.Light)
mock_light_1.address = "AA:BB:CC:DD:EE:FF" mock_light_1.address = "AA:BB:CC:DD:EE:FF"
mock_light_1.name = "LEDBlue-CCDDEEFF" mock_light_1.name = "LEDBlue-CCDDEEFF"
mock_light_1.connected = True mock_light_1.is_connected.return_value = True
mock_light_2 = MagicMock(spec=pyzerproc.Light) mock_light_2 = MagicMock(spec=pyzerproc.Light)
mock_light_2.address = "11:22:33:44:55:66" mock_light_2.address = "11:22:33:44:55:66"
mock_light_2.name = "LEDBlue-33445566" mock_light_2.name = "LEDBlue-33445566"
mock_light_2.connected = True mock_light_2.is_connected.return_value = True
mock_state_1 = pyzerproc.LightState(False, (0, 0, 0)) mock_state_1 = pyzerproc.LightState(False, (0, 0, 0))
mock_state_2 = pyzerproc.LightState(True, (0, 80, 255)) mock_state_2 = pyzerproc.LightState(True, (0, 80, 255))
@ -144,7 +144,7 @@ async def test_connect_exception(hass, mock_entry):
mock_light = MagicMock(spec=pyzerproc.Light) mock_light = MagicMock(spec=pyzerproc.Light)
mock_light.address = "AA:BB:CC:DD:EE:FF" mock_light.address = "AA:BB:CC:DD:EE:FF"
mock_light.name = "LEDBlue-CCDDEEFF" mock_light.name = "LEDBlue-CCDDEEFF"
mock_light.connected = False mock_light.is_connected.return_value = False
with patch( with patch(
"homeassistant.components.zerproc.light.pyzerproc.discover", "homeassistant.components.zerproc.light.pyzerproc.discover",