mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Surepetcare, service to set pet location (#56198)
* Surepetcare, add handle_set_pet_location Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net> * Surepetcare, add handle_set_pet_location Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net> * Surepetcare, add handle_set_pet_location Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
This commit is contained in:
parent
811feb69ba
commit
f97cce6f57
@ -5,7 +5,7 @@ from datetime import timedelta
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from surepy import Surepy, SurepyEntity
|
from surepy import Surepy, SurepyEntity
|
||||||
from surepy.enums import LockState
|
from surepy.enums import EntityType, Location, LockState
|
||||||
from surepy.exceptions import SurePetcareAuthenticationError, SurePetcareError
|
from surepy.exceptions import SurePetcareAuthenticationError, SurePetcareError
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -20,17 +20,21 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.service import ServiceCall
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_FLAP_ID,
|
ATTR_FLAP_ID,
|
||||||
|
ATTR_LOCATION,
|
||||||
ATTR_LOCK_STATE,
|
ATTR_LOCK_STATE,
|
||||||
|
ATTR_PET_NAME,
|
||||||
CONF_FEEDERS,
|
CONF_FEEDERS,
|
||||||
CONF_FLAPS,
|
CONF_FLAPS,
|
||||||
CONF_PETS,
|
CONF_PETS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_LOCK_STATE,
|
SERVICE_SET_LOCK_STATE,
|
||||||
|
SERVICE_SET_PET_LOCATION,
|
||||||
SURE_API_TIMEOUT,
|
SURE_API_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -91,12 +95,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
surepy = Surepy(
|
hass.data[DOMAIN][entry.entry_id] = coordinator = SurePetcareDataCoordinator(
|
||||||
entry.data[CONF_USERNAME],
|
entry,
|
||||||
entry.data[CONF_PASSWORD],
|
hass,
|
||||||
auth_token=entry.data[CONF_TOKEN],
|
|
||||||
api_timeout=SURE_API_TIMEOUT,
|
|
||||||
session=async_get_clientsession(hass),
|
|
||||||
)
|
)
|
||||||
except SurePetcareAuthenticationError:
|
except SurePetcareAuthenticationError:
|
||||||
_LOGGER.error("Unable to connect to surepetcare.io: Wrong credentials!")
|
_LOGGER.error("Unable to connect to surepetcare.io: Wrong credentials!")
|
||||||
@ -105,40 +106,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
_LOGGER.error("Unable to connect to surepetcare.io: Wrong %s!", error)
|
_LOGGER.error("Unable to connect to surepetcare.io: Wrong %s!", error)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def _update_method() -> dict[int, SurepyEntity]:
|
|
||||||
"""Get the latest data from Sure Petcare."""
|
|
||||||
try:
|
|
||||||
return await surepy.get_entities(refresh=True)
|
|
||||||
except SurePetcareError as err:
|
|
||||||
raise UpdateFailed(f"Unable to fetch data: {err}") from err
|
|
||||||
|
|
||||||
coordinator = DataUpdateCoordinator(
|
|
||||||
hass,
|
|
||||||
_LOGGER,
|
|
||||||
name=DOMAIN,
|
|
||||||
update_method=_update_method,
|
|
||||||
update_interval=SCAN_INTERVAL,
|
|
||||||
)
|
|
||||||
|
|
||||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
|
||||||
await coordinator.async_config_entry_first_refresh()
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
lock_states = {
|
|
||||||
LockState.UNLOCKED.name.lower(): surepy.sac.unlock,
|
|
||||||
LockState.LOCKED_IN.name.lower(): surepy.sac.lock_in,
|
|
||||||
LockState.LOCKED_OUT.name.lower(): surepy.sac.lock_out,
|
|
||||||
LockState.LOCKED_ALL.name.lower(): surepy.sac.lock,
|
|
||||||
}
|
|
||||||
|
|
||||||
async def handle_set_lock_state(call):
|
|
||||||
"""Call when setting the lock state."""
|
|
||||||
flap_id = call.data[ATTR_FLAP_ID]
|
|
||||||
state = call.data[ATTR_LOCK_STATE]
|
|
||||||
await lock_states[state](flap_id)
|
|
||||||
await coordinator.async_request_refresh()
|
|
||||||
|
|
||||||
lock_state_service_schema = vol.Schema(
|
lock_state_service_schema = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(ATTR_FLAP_ID): vol.All(
|
vol.Required(ATTR_FLAP_ID): vol.All(
|
||||||
@ -147,18 +118,35 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
vol.Required(ATTR_LOCK_STATE): vol.All(
|
vol.Required(ATTR_LOCK_STATE): vol.All(
|
||||||
cv.string,
|
cv.string,
|
||||||
vol.Lower,
|
vol.Lower,
|
||||||
vol.In(lock_states.keys()),
|
vol.In(coordinator.lock_states.keys()),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_LOCK_STATE,
|
SERVICE_SET_LOCK_STATE,
|
||||||
handle_set_lock_state,
|
coordinator.handle_set_lock_state,
|
||||||
schema=lock_state_service_schema,
|
schema=lock_state_service_schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_pet_location_schema = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(ATTR_PET_NAME): vol.In(coordinator.get_pets().values()),
|
||||||
|
vol.Required(ATTR_LOCATION): vol.In(
|
||||||
|
[
|
||||||
|
Location.INSIDE.name.title(),
|
||||||
|
Location.OUTSIDE.name.title(),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_PET_LOCATION,
|
||||||
|
coordinator.handle_set_pet_location,
|
||||||
|
schema=set_pet_location_schema,
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -169,3 +157,64 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
|
class SurePetcareDataCoordinator(DataUpdateCoordinator):
|
||||||
|
"""Handle Surepetcare data."""
|
||||||
|
|
||||||
|
def __init__(self, entry: ConfigEntry, hass: HomeAssistant) -> None:
|
||||||
|
"""Initialize the data handler."""
|
||||||
|
self.surepy = Surepy(
|
||||||
|
entry.data[CONF_USERNAME],
|
||||||
|
entry.data[CONF_PASSWORD],
|
||||||
|
auth_token=entry.data[CONF_TOKEN],
|
||||||
|
api_timeout=SURE_API_TIMEOUT,
|
||||||
|
session=async_get_clientsession(hass),
|
||||||
|
)
|
||||||
|
self.lock_states = {
|
||||||
|
LockState.UNLOCKED.name.lower(): self.surepy.sac.unlock,
|
||||||
|
LockState.LOCKED_IN.name.lower(): self.surepy.sac.lock_in,
|
||||||
|
LockState.LOCKED_OUT.name.lower(): self.surepy.sac.lock_out,
|
||||||
|
LockState.LOCKED_ALL.name.lower(): self.surepy.sac.lock,
|
||||||
|
}
|
||||||
|
super().__init__(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name=DOMAIN,
|
||||||
|
update_interval=SCAN_INTERVAL,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> dict[int, SurepyEntity]:
|
||||||
|
"""Get the latest data from Sure Petcare."""
|
||||||
|
try:
|
||||||
|
return await self.surepy.get_entities(refresh=True)
|
||||||
|
except SurePetcareError as err:
|
||||||
|
raise UpdateFailed(f"Unable to fetch data: {err}") from err
|
||||||
|
|
||||||
|
async def handle_set_lock_state(self, call: ServiceCall) -> None:
|
||||||
|
"""Call when setting the lock state."""
|
||||||
|
flap_id = call.data[ATTR_FLAP_ID]
|
||||||
|
state = call.data[ATTR_LOCK_STATE]
|
||||||
|
await self.lock_states[state](flap_id)
|
||||||
|
await self.async_request_refresh()
|
||||||
|
|
||||||
|
def get_pets(self) -> dict[int, str]:
|
||||||
|
"""Get pets."""
|
||||||
|
names = {}
|
||||||
|
for surepy_entity in self.data.values():
|
||||||
|
if surepy_entity.type == EntityType.PET and surepy_entity.name:
|
||||||
|
names[surepy_entity.id] = surepy_entity.name
|
||||||
|
return names
|
||||||
|
|
||||||
|
async def handle_set_pet_location(self, call: ServiceCall) -> None:
|
||||||
|
"""Call when setting the pet location."""
|
||||||
|
pet_name = call.data[ATTR_PET_NAME]
|
||||||
|
location = call.data[ATTR_LOCATION]
|
||||||
|
for device_id, device_name in self.get_pets().items():
|
||||||
|
if pet_name == device_name:
|
||||||
|
await self.surepy.sac.set_pet_location(
|
||||||
|
device_id, Location[location.upper()]
|
||||||
|
)
|
||||||
|
await self.async_request_refresh()
|
||||||
|
return
|
||||||
|
_LOGGER.error("Unknown pet %s", pet_name)
|
||||||
|
@ -13,7 +13,10 @@ SURE_BATT_VOLTAGE_FULL = 1.6 # voltage
|
|||||||
SURE_BATT_VOLTAGE_LOW = 1.25 # voltage
|
SURE_BATT_VOLTAGE_LOW = 1.25 # voltage
|
||||||
SURE_BATT_VOLTAGE_DIFF = SURE_BATT_VOLTAGE_FULL - SURE_BATT_VOLTAGE_LOW
|
SURE_BATT_VOLTAGE_DIFF = SURE_BATT_VOLTAGE_FULL - SURE_BATT_VOLTAGE_LOW
|
||||||
|
|
||||||
# lock state service
|
# state service
|
||||||
SERVICE_SET_LOCK_STATE = "set_lock_state"
|
SERVICE_SET_LOCK_STATE = "set_lock_state"
|
||||||
|
SERVICE_SET_PET_LOCATION = "set_pet_location"
|
||||||
ATTR_FLAP_ID = "flap_id"
|
ATTR_FLAP_ID = "flap_id"
|
||||||
|
ATTR_LOCATION = "location"
|
||||||
ATTR_LOCK_STATE = "lock_state"
|
ATTR_LOCK_STATE = "lock_state"
|
||||||
|
ATTR_PET_NAME = "pet_name"
|
||||||
|
@ -20,3 +20,23 @@ set_lock_state:
|
|||||||
- 'locked_in'
|
- 'locked_in'
|
||||||
- 'locked_out'
|
- 'locked_out'
|
||||||
- 'unlocked'
|
- 'unlocked'
|
||||||
|
|
||||||
|
set_pet_location:
|
||||||
|
name: Set pet location
|
||||||
|
description: Set pet location
|
||||||
|
fields:
|
||||||
|
pet_name:
|
||||||
|
description: Name of pet
|
||||||
|
example: My_cat
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
location:
|
||||||
|
description: Pet location (Inside or Outside)
|
||||||
|
example: inside
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- 'Inside'
|
||||||
|
- 'Outside'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user