Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] set_action service #183

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions custom_components/connectlife/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform, CONF_USERNAME, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from connectlife.api import ConnectLifeApi, LifeConnectAuthError

from .const import CONF_DEVELOPMENT_MODE, CONF_TEST_SERVER_URL, DOMAIN
from .coordinator import ConnectLifeCoordinator
from .services import async_setup_services

PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Expand All @@ -22,6 +24,16 @@
Platform.WATER_HEATER,
]

CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up ConnectLife."""

await async_setup_services(hass)

return True


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up ConnectLife from a config entry."""
Expand Down
81 changes: 81 additions & 0 deletions custom_components/connectlife/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Services for the Fully Kiosk Browser integration."""

from __future__ import annotations

import logging
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import ATTR_DEVICE_ID
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
import homeassistant.helpers.device_registry as dr

from .coordinator import ConnectLifeCoordinator
from .const import DOMAIN

ATTR_ACTION = "action"
SERVICE_SET_ACTION = "set_action"

_LOGGER = logging.getLogger(__name__)


async def async_setup_services(hass: HomeAssistant) -> None:
"""Set up the services for the Fully Kiosk Browser integration."""

async def collect_coordinators(
device_ids: list[str],
) -> dict[str, ConnectLifeCoordinator]:
config_entries = dict[str, ConfigEntry]()
registry = dr.async_get(hass)
for target in device_ids:
device = registry.async_get(target)
if device:
device_entries = dict[str, ConfigEntry]()
for entry_id in device.config_entries:
entry = hass.config_entries.async_get_entry(entry_id)
if entry and entry.domain == DOMAIN:
for (domain, device_id) in device.identifiers:
if domain == DOMAIN:
_LOGGER.debug(f"device_id: {device_id}")
device_entries[device_id] = entry
break
if not device_entries:
raise HomeAssistantError(
f"Device '{target}' is not a {DOMAIN} device"
)
config_entries.update(device_entries)
else:
raise HomeAssistantError(
f"Device '{target}' not found in device registry"
)
coordinators = dict[str, ConnectLifeCoordinator]()
for device_id, config_entry in config_entries.items():
if config_entry.state != ConfigEntryState.LOADED:
raise HomeAssistantError(f"{config_entry.title} is not loaded")
coordinators[device_id] = hass.data[DOMAIN][config_entry.entry_id]
return coordinators

async def async_set_action(call: ServiceCall) -> None:
"""Set action on device."""
coordinators = await collect_coordinators(call.data[ATTR_DEVICE_ID])
for device_id, coordinator in coordinators.items():
_LOGGER.debug("Setting Actions to %d on %s", call.data[ATTR_ACTION], device_id)
# TODO: Consider trigging a data update to avoid waiting for next poll to update state.
# Make sure to only do this once per coordinater.
await coordinator.async_update_device(device_id, {"Actions": call.data[ATTR_ACTION]}, {})

hass.services.async_register(
DOMAIN,
SERVICE_SET_ACTION,
async_set_action,
schema=vol.Schema(
vol.All(
{
vol.Required(ATTR_DEVICE_ID): cv.ensure_list,
vol.Required(ATTR_ACTION): cv.positive_int,
}
)
),
)
18 changes: 18 additions & 0 deletions custom_components/connectlife/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,22 @@ set_value:
required: true
selector:
number:
set_action:
target:
device:
integration: connectlife
fields:
action:
required: true
selector:
select:
options:
- label: stop
value: "1"
- label: start
value: "2"
- label: pause
value: "3"
- label: open_door
value: "4"

10 changes: 10 additions & 0 deletions custom_components/connectlife/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@
"description": "Value to set."
}
}
},
"set_action": {
"name": "Set action",
"description": "Sets action for device. Use with care.",
"fields": {
"action": {
"name": "Action",
"description": "Action to set."
}
}
}
},
"entity": {
Expand Down
10 changes: 10 additions & 0 deletions custom_components/connectlife/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@
"description": "Value to set."
}
}
},
"set_action": {
"name": "Set action",
"description": "Sets action for device. Use with care.",
"fields": {
"action": {
"name": "Action",
"description": "Action to set."
}
}
}
},
"entity": {
Expand Down
Loading