Skip to content
Open
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
15 changes: 14 additions & 1 deletion homeassistant/components/peblar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_create_clientsession
import homeassistant.helpers.config_validation as cv

from .const import DOMAIN
from .coordinator import (
PeblarConfigEntry,
PeblarDataUpdateCoordinator,
PeblarRuntimeData,
PeblarUserConfigurationDataUpdateCoordinator,
PeblarVersionDataUpdateCoordinator,
)
from .services import async_setup_services, async_unload_services

CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)

PLATFORMS = [
Platform.BINARY_SENSOR,
Expand All @@ -39,6 +44,8 @@

async def async_setup_entry(hass: HomeAssistant, entry: PeblarConfigEntry) -> bool:
"""Set up Peblar from a config entry."""
if not hass.services.has_service(DOMAIN, "list_rfid_tokens"):
async_setup_services(hass)

# Set up connection to the Peblar charger
peblar = Peblar(
Expand Down Expand Up @@ -86,4 +93,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: PeblarConfigEntry) -> bo

async def async_unload_entry(hass: HomeAssistant, entry: PeblarConfigEntry) -> bool:
"""Unload Peblar config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok and not any(
e.entry_id != entry.entry_id
for e in hass.config_entries.async_loaded_entries(DOMAIN)
):
async_unload_services(hass)
return unload_ok
2 changes: 2 additions & 0 deletions homeassistant/components/peblar/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

DOMAIN: Final = "peblar"

CONF_UID: Final = "uid"

LOGGER = logging.getLogger(__package__)

PEBLAR_CHARGE_LIMITER_TO_HOME_ASSISTANT = {
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/peblar/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,16 @@
"default": "mdi:palette"
}
}
},
"services": {
"add_rfid_token": {
"service": "mdi:card-plus"
},
"delete_rfid_token": {
"service": "mdi:card-remove"
},
"list_rfid_tokens": {
"service": "mdi:card-account-details"
}
}
}
130 changes: 130 additions & 0 deletions homeassistant/components/peblar/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""Services for the Peblar integration."""

from __future__ import annotations

from typing import cast

from peblar import Peblar
import voluptuous as vol

from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_CONFIG_ENTRY_ID, CONF_DESCRIPTION
from homeassistant.core import (
HomeAssistant,
ServiceCall,
ServiceResponse,
SupportsResponse,
callback,
)
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.util.json import JsonValueType

from .const import CONF_UID, DOMAIN
from .coordinator import PeblarConfigEntry

LIST_RESPONSE_SCHEMA = vol.Schema(
{
"tokens": [
vol.Schema(
{
"uid": str,
"description": str,
}
)
]
}
)


def _get_peblar(hass: HomeAssistant, entry_id: str) -> Peblar:
entry = hass.config_entries.async_get_entry(entry_id)
if (
entry is None
or entry.domain != DOMAIN
or entry.state is not ConfigEntryState.LOADED
):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_config_entry",
translation_placeholders={ATTR_CONFIG_ENTRY_ID: entry_id},
)
return cast(
PeblarConfigEntry, entry
).runtime_data.user_configuration_coordinator.peblar


@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Register RFID management services."""

async def _handle_list_rfid_tokens(call: ServiceCall) -> ServiceResponse:
peblar = _get_peblar(hass, call.data[ATTR_CONFIG_ENTRY_ID])
tokens = await peblar.rfid_tokens()
return cast(
dict[str, JsonValueType],
LIST_RESPONSE_SCHEMA(
{
"tokens": [
{
"uid": t.rfid_token_uid,
CONF_DESCRIPTION: t.rfid_token_description,
}
for t in tokens
]
}
),
)

async def _handle_add_rfid_token(call: ServiceCall) -> None:
peblar = _get_peblar(hass, call.data[ATTR_CONFIG_ENTRY_ID])
await peblar.add_rfid_token(
rfid_token_uid=call.data[CONF_UID],
rfid_token_description=call.data[CONF_DESCRIPTION],
)

async def _handle_delete_rfid_token(call: ServiceCall) -> None:
peblar = _get_peblar(hass, call.data[ATTR_CONFIG_ENTRY_ID])
await peblar.delete_rfid_token(uid=call.data[CONF_UID])

async_register_admin_service(
hass,
DOMAIN,
"list_rfid_tokens",
_handle_list_rfid_tokens,
schema=vol.Schema({vol.Required(ATTR_CONFIG_ENTRY_ID): str}),
supports_response=SupportsResponse.ONLY,
)
Comment thread
syphernl marked this conversation as resolved.
async_register_admin_service(
hass,
DOMAIN,
"add_rfid_token",
_handle_add_rfid_token,
schema=vol.Schema(
{
vol.Required(ATTR_CONFIG_ENTRY_ID): str,
vol.Required(CONF_UID): str,
vol.Required(CONF_DESCRIPTION): str,
}
),
)
async_register_admin_service(
hass,
DOMAIN,
"delete_rfid_token",
_handle_delete_rfid_token,
schema=vol.Schema(
{
vol.Required(ATTR_CONFIG_ENTRY_ID): str,
vol.Required(CONF_UID): str,
}
),
)


@callback
def async_unload_services(hass: HomeAssistant) -> None:
"""Unregister RFID management services."""
hass.services.async_remove(DOMAIN, "list_rfid_tokens")
hass.services.async_remove(DOMAIN, "add_rfid_token")
hass.services.async_remove(DOMAIN, "delete_rfid_token")
35 changes: 35 additions & 0 deletions homeassistant/components/peblar/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
list_rfid_tokens:
fields:
config_entry_id:
required: true
selector:
config_entry:
integration: peblar

add_rfid_token:
fields:
config_entry_id:
required: true
selector:
config_entry:
integration: peblar
uid:
required: true
selector:
text:
description:
required: true
selector:
text:

delete_rfid_token:
fields:
config_entry_id:
required: true
selector:
config_entry:
integration: peblar
uid:
required: true
selector:
text:
Comment thread
syphernl marked this conversation as resolved.
47 changes: 47 additions & 0 deletions homeassistant/components/peblar/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,55 @@
"communication_error": {
"message": "An error occurred while communicating with the Peblar EV charger: {error}"
},
"invalid_config_entry": {
"message": "Config entry {config_entry_id} is not a valid Peblar config entry or is not loaded."
},
"unknown_error": {
"message": "An unknown error occurred while communicating with the Peblar EV charger: {error}"
}
},
"services": {
"add_rfid_token": {
"description": "Adds an RFID token to the charger's standalone authorization list.",
"fields": {
"config_entry_id": {
"description": "The Peblar EV charger to add the RFID token to.",
"name": "Config entry"
},
"description": {
"description": "A human-readable label for this RFID token.",
"name": "Description"
},
"uid": {
"description": "The unique identifier of the RFID token.",
"name": "UID"
}
},
"name": "Add RFID token"
},
"delete_rfid_token": {
"description": "Deletes an RFID token from the charger's standalone authorization list.",
"fields": {
"config_entry_id": {
"description": "The Peblar EV charger to delete the RFID token from.",
"name": "Config entry"
},
"uid": {
"description": "The unique identifier of the RFID token to delete.",
"name": "UID"
}
},
"name": "Delete RFID token"
},
"list_rfid_tokens": {
"description": "Returns the RFID tokens configured in the charger's standalone authorization list.",
"fields": {
"config_entry_id": {
"description": "The Peblar EV charger to list RFID tokens for.",
"name": "Config entry"
}
},
"name": "List RFID tokens"
}
}
}
Loading