mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Add battery sensor for gogogate2 wireless door sensor (#47145)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
853d9ac4a9
commit
7e71050669
@ -1,5 +1,8 @@
|
|||||||
"""The gogogate2 component."""
|
"""The gogogate2 component."""
|
||||||
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
|
import asyncio
|
||||||
|
|
||||||
|
from homeassistant.components.cover import DOMAIN as COVER
|
||||||
|
from homeassistant.components.sensor import DOMAIN as SENSOR
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_DEVICE
|
from homeassistant.const import CONF_DEVICE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -8,6 +11,8 @@ from homeassistant.exceptions import ConfigEntryNotReady
|
|||||||
from .common import get_data_update_coordinator
|
from .common import get_data_update_coordinator
|
||||||
from .const import DEVICE_TYPE_GOGOGATE2
|
from .const import DEVICE_TYPE_GOGOGATE2
|
||||||
|
|
||||||
|
PLATFORMS = [COVER, SENSOR]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, base_config: dict) -> bool:
|
async def async_setup(hass: HomeAssistant, base_config: dict) -> bool:
|
||||||
"""Set up for Gogogate2 controllers."""
|
"""Set up for Gogogate2 controllers."""
|
||||||
@ -34,8 +39,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
if not data_update_coordinator.last_update_success:
|
if not data_update_coordinator.last_update_success:
|
||||||
raise ConfigEntryNotReady()
|
raise ConfigEntryNotReady()
|
||||||
|
|
||||||
|
for platform in PLATFORMS:
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
hass.config_entries.async_forward_entry_setup(config_entry, COVER_DOMAIN)
|
hass.config_entries.async_forward_entry_setup(config_entry, platform)
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@ -43,8 +49,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
"""Unload Gogogate2 config entry."""
|
"""Unload Gogogate2 config entry."""
|
||||||
hass.async_create_task(
|
unload_ok = all(
|
||||||
hass.config_entries.async_forward_entry_unload(config_entry, COVER_DOMAIN)
|
await asyncio.gather(
|
||||||
|
*[
|
||||||
|
hass.config_entries.async_forward_entry_unload(config_entry, platform)
|
||||||
|
for platform in PLATFORMS
|
||||||
|
]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return unload_ok
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
from typing import Awaitable, Callable, NamedTuple, Optional
|
from typing import Awaitable, Callable, NamedTuple, Optional
|
||||||
|
|
||||||
from gogogate2_api import AbstractGateApi, GogoGate2Api, ISmartGateApi
|
from gogogate2_api import AbstractGateApi, GogoGate2Api, ISmartGateApi
|
||||||
from gogogate2_api.common import AbstractDoor
|
from gogogate2_api.common import AbstractDoor, get_door_by_id
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -15,9 +15,13 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.debounce import Debouncer
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
UpdateFailed,
|
||||||
|
)
|
||||||
|
|
||||||
from .const import DATA_UPDATE_COORDINATOR, DEVICE_TYPE_ISMARTGATE, DOMAIN
|
from .const import DATA_UPDATE_COORDINATOR, DEVICE_TYPE_ISMARTGATE, DOMAIN, MANUFACTURER
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -57,6 +61,44 @@ class DeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
|
|
||||||
|
class GoGoGate2Entity(CoordinatorEntity):
|
||||||
|
"""Base class for gogogate2 entities."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
data_update_coordinator: DeviceDataUpdateCoordinator,
|
||||||
|
door: AbstractDoor,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize gogogate2 base entity."""
|
||||||
|
super().__init__(data_update_coordinator)
|
||||||
|
self._config_entry = config_entry
|
||||||
|
self._door = door
|
||||||
|
self._unique_id = cover_unique_id(config_entry, door)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self) -> Optional[str]:
|
||||||
|
"""Return a unique ID."""
|
||||||
|
return self._unique_id
|
||||||
|
|
||||||
|
def _get_door(self) -> AbstractDoor:
|
||||||
|
door = get_door_by_id(self._door.door_id, self.coordinator.data)
|
||||||
|
self._door = door or self._door
|
||||||
|
return self._door
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Device info for the controller."""
|
||||||
|
data = self.coordinator.data
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._config_entry.unique_id)},
|
||||||
|
"name": self._config_entry.title,
|
||||||
|
"manufacturer": MANUFACTURER,
|
||||||
|
"model": data.model,
|
||||||
|
"sw_version": data.firmwareversion,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_data_update_coordinator(
|
def get_data_update_coordinator(
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
hass: HomeAssistant, config_entry: ConfigEntry
|
||||||
) -> DeviceDataUpdateCoordinator:
|
) -> DeviceDataUpdateCoordinator:
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
"""Support for Gogogate2 garage Doors."""
|
"""Support for Gogogate2 garage Doors."""
|
||||||
from typing import Callable, List, Optional
|
from typing import Callable, List, Optional
|
||||||
|
|
||||||
from gogogate2_api.common import (
|
from gogogate2_api.common import AbstractDoor, DoorStatus, get_configured_doors
|
||||||
AbstractDoor,
|
|
||||||
DoorStatus,
|
|
||||||
get_configured_doors,
|
|
||||||
get_door_by_id,
|
|
||||||
)
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.cover import (
|
from homeassistant.components.cover import (
|
||||||
@ -26,14 +21,13 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
DeviceDataUpdateCoordinator,
|
DeviceDataUpdateCoordinator,
|
||||||
cover_unique_id,
|
GoGoGate2Entity,
|
||||||
get_data_update_coordinator,
|
get_data_update_coordinator,
|
||||||
)
|
)
|
||||||
from .const import DEVICE_TYPE_GOGOGATE2, DEVICE_TYPE_ISMARTGATE, DOMAIN, MANUFACTURER
|
from .const import DEVICE_TYPE_GOGOGATE2, DEVICE_TYPE_ISMARTGATE, DOMAIN
|
||||||
|
|
||||||
COVER_SCHEMA = vol.Schema(
|
COVER_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
@ -74,7 +68,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeviceCover(CoordinatorEntity, CoverEntity):
|
class DeviceCover(GoGoGate2Entity, CoverEntity):
|
||||||
"""Cover entity for goggate2."""
|
"""Cover entity for goggate2."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -84,18 +78,10 @@ class DeviceCover(CoordinatorEntity, CoverEntity):
|
|||||||
door: AbstractDoor,
|
door: AbstractDoor,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the object."""
|
"""Initialize the object."""
|
||||||
super().__init__(data_update_coordinator)
|
super().__init__(config_entry, data_update_coordinator, door)
|
||||||
self._config_entry = config_entry
|
|
||||||
self._door = door
|
|
||||||
self._api = data_update_coordinator.api
|
self._api = data_update_coordinator.api
|
||||||
self._unique_id = cover_unique_id(config_entry, door)
|
|
||||||
self._is_available = True
|
self._is_available = True
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> Optional[str]:
|
|
||||||
"""Return a unique ID."""
|
|
||||||
return self._unique_id
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the door."""
|
"""Return the name of the door."""
|
||||||
@ -141,20 +127,3 @@ class DeviceCover(CoordinatorEntity, CoverEntity):
|
|||||||
attrs = super().state_attributes
|
attrs = super().state_attributes
|
||||||
attrs["door_id"] = self._get_door().door_id
|
attrs["door_id"] = self._get_door().door_id
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def _get_door(self) -> AbstractDoor:
|
|
||||||
door = get_door_by_id(self._door.door_id, self.coordinator.data)
|
|
||||||
self._door = door or self._door
|
|
||||||
return self._door
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_info(self):
|
|
||||||
"""Device info for the controller."""
|
|
||||||
data = self.coordinator.data
|
|
||||||
return {
|
|
||||||
"identifiers": {(DOMAIN, self._config_entry.unique_id)},
|
|
||||||
"name": self._config_entry.title,
|
|
||||||
"manufacturer": MANUFACTURER,
|
|
||||||
"model": data.model,
|
|
||||||
"sw_version": data.firmwareversion,
|
|
||||||
}
|
|
||||||
|
59
homeassistant/components/gogogate2/sensor.py
Normal file
59
homeassistant/components/gogogate2/sensor.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""Support for Gogogate2 garage Doors."""
|
||||||
|
from typing import Callable, List, Optional
|
||||||
|
|
||||||
|
from gogogate2_api.common import get_configured_doors
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import DEVICE_CLASS_BATTERY
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .common import GoGoGate2Entity, get_data_update_coordinator
|
||||||
|
|
||||||
|
SENSOR_ID_WIRED = "WIRE"
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], Optional[bool]], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the config entry."""
|
||||||
|
data_update_coordinator = get_data_update_coordinator(hass, config_entry)
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
DoorSensor(config_entry, data_update_coordinator, door)
|
||||||
|
for door in get_configured_doors(data_update_coordinator.data)
|
||||||
|
if door.sensorid and door.sensorid != SENSOR_ID_WIRED
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DoorSensor(GoGoGate2Entity):
|
||||||
|
"""Sensor entity for goggate2."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the door."""
|
||||||
|
return f"{self._get_door().name} battery"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||||
|
return DEVICE_CLASS_BATTERY
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the entity."""
|
||||||
|
door = self._get_door()
|
||||||
|
return door.voltage # This is a percentage, not an absolute voltage
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state_attributes(self):
|
||||||
|
"""Return the state attributes."""
|
||||||
|
attrs = super().state_attributes or {}
|
||||||
|
door = self._get_door()
|
||||||
|
if door.sensorid is not None:
|
||||||
|
attrs["sensorid"] = door.door_id
|
||||||
|
return attrs
|
261
tests/components/gogogate2/test_sensor.py
Normal file
261
tests/components/gogogate2/test_sensor.py
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
"""Tests for the GogoGate2 component."""
|
||||||
|
from datetime import timedelta
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from gogogate2_api import GogoGate2Api, ISmartGateApi
|
||||||
|
from gogogate2_api.common import (
|
||||||
|
DoorMode,
|
||||||
|
DoorStatus,
|
||||||
|
GogoGate2ActivateResponse,
|
||||||
|
GogoGate2Door,
|
||||||
|
GogoGate2InfoResponse,
|
||||||
|
ISmartGateDoor,
|
||||||
|
ISmartGateInfoResponse,
|
||||||
|
Network,
|
||||||
|
Outputs,
|
||||||
|
Wifi,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.gogogate2.const import DEVICE_TYPE_ISMARTGATE, DOMAIN
|
||||||
|
from homeassistant.config_entries import SOURCE_USER
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_DEVICE_CLASS,
|
||||||
|
CONF_DEVICE,
|
||||||
|
CONF_IP_ADDRESS,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_USERNAME,
|
||||||
|
DEVICE_CLASS_BATTERY,
|
||||||
|
STATE_UNAVAILABLE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
|
def _mocked_gogogate_sensor_response(battery_level: int):
|
||||||
|
return GogoGate2InfoResponse(
|
||||||
|
user="user1",
|
||||||
|
gogogatename="gogogatename0",
|
||||||
|
model="",
|
||||||
|
apiversion="",
|
||||||
|
remoteaccessenabled=False,
|
||||||
|
remoteaccess="abc123.blah.blah",
|
||||||
|
firmwareversion="",
|
||||||
|
apicode="",
|
||||||
|
door1=GogoGate2Door(
|
||||||
|
door_id=1,
|
||||||
|
permission=True,
|
||||||
|
name="Door1",
|
||||||
|
gate=False,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.OPENED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid="ABCD",
|
||||||
|
camera=False,
|
||||||
|
events=2,
|
||||||
|
temperature=None,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
door2=GogoGate2Door(
|
||||||
|
door_id=2,
|
||||||
|
permission=True,
|
||||||
|
name="Door2",
|
||||||
|
gate=True,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.UNDEFINED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid="WIRE",
|
||||||
|
camera=False,
|
||||||
|
events=0,
|
||||||
|
temperature=None,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
door3=GogoGate2Door(
|
||||||
|
door_id=3,
|
||||||
|
permission=True,
|
||||||
|
name="Door3",
|
||||||
|
gate=False,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.UNDEFINED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid=None,
|
||||||
|
camera=False,
|
||||||
|
events=0,
|
||||||
|
temperature=None,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
outputs=Outputs(output1=True, output2=False, output3=True),
|
||||||
|
network=Network(ip=""),
|
||||||
|
wifi=Wifi(SSID="", linkquality="", signal=""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _mocked_ismartgate_sensor_response(battery_level: int):
|
||||||
|
return ISmartGateInfoResponse(
|
||||||
|
user="user1",
|
||||||
|
ismartgatename="ismartgatename0",
|
||||||
|
model="ismartgatePRO",
|
||||||
|
apiversion="",
|
||||||
|
remoteaccessenabled=False,
|
||||||
|
remoteaccess="abc321.blah.blah",
|
||||||
|
firmwareversion="555",
|
||||||
|
pin=123,
|
||||||
|
lang="en",
|
||||||
|
newfirmware=False,
|
||||||
|
door1=ISmartGateDoor(
|
||||||
|
door_id=1,
|
||||||
|
permission=True,
|
||||||
|
name="Door1",
|
||||||
|
gate=False,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.CLOSED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid="ABCD",
|
||||||
|
camera=False,
|
||||||
|
events=2,
|
||||||
|
temperature=None,
|
||||||
|
enabled=True,
|
||||||
|
apicode="apicode0",
|
||||||
|
customimage=False,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
door2=ISmartGateDoor(
|
||||||
|
door_id=2,
|
||||||
|
permission=True,
|
||||||
|
name="Door2",
|
||||||
|
gate=True,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.CLOSED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid="WIRE",
|
||||||
|
camera=False,
|
||||||
|
events=2,
|
||||||
|
temperature=None,
|
||||||
|
enabled=True,
|
||||||
|
apicode="apicode0",
|
||||||
|
customimage=False,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
door3=ISmartGateDoor(
|
||||||
|
door_id=3,
|
||||||
|
permission=True,
|
||||||
|
name="Door3",
|
||||||
|
gate=False,
|
||||||
|
mode=DoorMode.GARAGE,
|
||||||
|
status=DoorStatus.UNDEFINED,
|
||||||
|
sensor=True,
|
||||||
|
sensorid=None,
|
||||||
|
camera=False,
|
||||||
|
events=0,
|
||||||
|
temperature=None,
|
||||||
|
enabled=True,
|
||||||
|
apicode="apicode0",
|
||||||
|
customimage=False,
|
||||||
|
voltage=battery_level,
|
||||||
|
),
|
||||||
|
network=Network(ip=""),
|
||||||
|
wifi=Wifi(SSID="", linkquality="", signal=""),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@patch("homeassistant.components.gogogate2.common.GogoGate2Api")
|
||||||
|
async def test_sensor_update(gogogate2api_mock, hass: HomeAssistant) -> None:
|
||||||
|
"""Test data update."""
|
||||||
|
|
||||||
|
api = MagicMock(GogoGate2Api)
|
||||||
|
api.async_activate.return_value = GogoGate2ActivateResponse(result=True)
|
||||||
|
api.async_info.return_value = _mocked_gogogate_sensor_response(25)
|
||||||
|
gogogate2api_mock.return_value = api
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
source=SOURCE_USER,
|
||||||
|
data={
|
||||||
|
CONF_IP_ADDRESS: "127.0.0.1",
|
||||||
|
CONF_USERNAME: "admin",
|
||||||
|
CONF_PASSWORD: "password",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert hass.states.get("cover.door1") is None
|
||||||
|
assert hass.states.get("cover.door2") is None
|
||||||
|
assert hass.states.get("cover.door2") is None
|
||||||
|
assert hass.states.get("sensor.door1_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("cover.door1")
|
||||||
|
assert hass.states.get("cover.door2")
|
||||||
|
assert hass.states.get("cover.door2")
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == "25"
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
|
||||||
|
api.async_info.return_value = _mocked_gogogate_sensor_response(40)
|
||||||
|
async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == "40"
|
||||||
|
|
||||||
|
api.async_info.return_value = _mocked_gogogate_sensor_response(None)
|
||||||
|
async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
assert not hass.states.async_entity_ids(DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
|
@patch("homeassistant.components.gogogate2.common.ISmartGateApi")
|
||||||
|
async def test_availability(ismartgateapi_mock, hass: HomeAssistant) -> None:
|
||||||
|
"""Test availability."""
|
||||||
|
sensor_response = _mocked_ismartgate_sensor_response(35)
|
||||||
|
api = MagicMock(ISmartGateApi)
|
||||||
|
api.async_info.return_value = sensor_response
|
||||||
|
ismartgateapi_mock.return_value = api
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
source=SOURCE_USER,
|
||||||
|
data={
|
||||||
|
CONF_DEVICE: DEVICE_TYPE_ISMARTGATE,
|
||||||
|
CONF_IP_ADDRESS: "127.0.0.1",
|
||||||
|
CONF_USERNAME: "admin",
|
||||||
|
CONF_PASSWORD: "password",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert hass.states.get("cover.door1") is None
|
||||||
|
assert hass.states.get("cover.door2") is None
|
||||||
|
assert hass.states.get("cover.door2") is None
|
||||||
|
assert hass.states.get("sensor.door1_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("cover.door1")
|
||||||
|
assert hass.states.get("cover.door2")
|
||||||
|
assert hass.states.get("cover.door2")
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == "35"
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert hass.states.get("sensor.door2_battery") is None
|
||||||
|
assert (
|
||||||
|
hass.states.get("sensor.door1_battery").attributes[ATTR_DEVICE_CLASS]
|
||||||
|
== DEVICE_CLASS_BATTERY
|
||||||
|
)
|
||||||
|
|
||||||
|
api.async_info.side_effect = Exception("Error")
|
||||||
|
|
||||||
|
async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
api.async_info.side_effect = None
|
||||||
|
api.async_info.return_value = sensor_response
|
||||||
|
async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("sensor.door1_battery").state == "35"
|
Loading…
x
Reference in New Issue
Block a user