Skip to content

Commit

Permalink
refactor: Chained DATA_SCHEMA for services
Browse files Browse the repository at this point in the history
  • Loading branch information
davidrapan committed Dec 9, 2024
1 parent c0717b2 commit dc12385
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 66 deletions.
4 changes: 2 additions & 2 deletions custom_components/solarman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .coordinator import Inverter, InverterCoordinator
from .config_flow import ConfigFlowHandler
from .entity import migrate_unique_ids
from .services import register_services
from .services import async_register

_LOGGER = logging.getLogger(__name__)

Expand All @@ -25,7 +25,7 @@
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
_LOGGER.debug(f"async_setup")

register_services(hass)
async_register(hass)

return True

Expand Down
6 changes: 4 additions & 2 deletions custom_components/solarman/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .const import *
from .common import *
from .provider import *
from .include.pysolarmanv5 import PySolarmanV5Async, V5FrameError
from .include.pysolarmanv5 import PySolarmanV5Async

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -198,6 +198,7 @@ async def try_read_write(self, code, start, arg, message, incremental_wait):
_LOGGER.debug(f"[{self.config.serial}] {message} ...")

response = None

attempts_left = ACTION_ATTEMPTS
while attempts_left > 0 and not response:
attempts_left -= 1
Expand All @@ -206,7 +207,6 @@ async def try_read_write(self, code, start, arg, message, incremental_wait):
raise Exception(f"[{self.config.serial}] Unexpected response: Invalid length! (Length: {length}, Expected: {expected})")

_LOGGER.debug(f"[{self.config.serial}] {message} succeeded, response: {response}")
return response
except Exception as e:
_LOGGER.debug(f"[{self.config.serial}] {message} failed, attempts left: {attempts_left}{'' if attempts_left > 0 else ', aborting.'} [{format_exception(e)}]")

Expand All @@ -215,6 +215,8 @@ async def try_read_write(self, code, start, arg, message, incremental_wait):
if not attempts_left > 0:
raise
await asyncio.sleep(((ACTION_ATTEMPTS - attempts_left) * TIMINGS_WAIT_SLEEP) if incremental_wait else TIMINGS_WAIT_SLEEP)

return response

async def get_failed(self):
_LOGGER.debug(f"[{self.config.serial}] Fetching failed. [Previous State: {self.get_connection_state} ({self.state})]")
Expand Down
96 changes: 36 additions & 60 deletions custom_components/solarman/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,40 @@

import voluptuous as vol

from homeassistant.core import HomeAssistant, ServiceCall, ServiceResponse, SupportsResponse
from homeassistant.helpers import config_validation as cv, device_registry as dr, entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.exceptions import ServiceValidationError

from .const import *
from .api import Inverter
from .coordinator import InverterCoordinator
from .coordinator import Inverter, InverterCoordinator

_LOGGER = logging.getLogger(__name__)

# Register the services one can invoke on the inverter.
# Apart from this, it also need to be defined in the file
# services.yaml for the Home Assistant UI in "Developer Tools"

SERVICE_READ_REGISTERS_SCHEMA = vol.Schema(
{
vol.Required(SERVICES_PARAM_DEVICE): vol.All(vol.Coerce(str)),
vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)),
vol.Required(SERVICES_PARAM_QUANTITY): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)),
vol.Required(SERVICES_PARAM_WAIT_FOR_ATTEMPTS): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 30))
}
)

SERVICE_WRITE_HOLDING_REGISTER_SCHEMA = vol.Schema(
{
vol.Required(SERVICES_PARAM_DEVICE): vol.All(vol.Coerce(str)),
vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)),
vol.Required(SERVICES_PARAM_VALUE): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)),
vol.Required(SERVICES_PARAM_WAIT_FOR_ATTEMPTS): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 30))
}
)

SERVICE_WRITE_MULTIPLE_HOLDING_REGISTERS_SCHEMA = vol.Schema(
{
vol.Required(SERVICES_PARAM_DEVICE): vol.All(vol.Coerce(str)),
vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)),
vol.Required(SERVICES_PARAM_VALUES): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))]),
vol.Required(SERVICES_PARAM_WAIT_FOR_ATTEMPTS): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 30))
}
)

def register_services(hass: HomeAssistant) -> None:
_LOGGER.debug(f"register_services")

def getDevice(device_id) -> Inverter:
HEADER_SCHEMA = {
vol.Required(SERVICES_PARAM_DEVICE): vol.All(vol.Coerce(str)),
vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))
}

QUANTITY_SCHEMA = {
vol.Required(SERVICES_PARAM_QUANTITY): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 125))
}

VALUE_SCHEMA = {
vol.Required(SERVICES_PARAM_VALUE): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))
}

VALUES_SCHEMA = {
vol.Required(SERVICES_PARAM_VALUES): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))])
}

WAIT_SCHEMA = {
vol.Required(SERVICES_PARAM_WAIT_FOR_ATTEMPTS): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 30))
}

def async_register(hass: HomeAssistant) -> None:
_LOGGER.debug(f"register")

def get_device(device_id) -> Inverter:
device_registry = dr.async_get(hass)
device = device_registry.async_get(device_id)

Expand All @@ -62,7 +50,7 @@ def getDevice(device_id) -> Inverter:
async def read_holding_registers(call: ServiceCall) -> int:
_LOGGER.debug(f"read_holding_registers: {call}")

if (inverter := getDevice(call.data.get(SERVICES_PARAM_DEVICE))) is None:
if (inverter := get_device(call.data.get(SERVICES_PARAM_DEVICE))) is None:
raise ServiceValidationError(
"No communication interface for device found",
translation_domain = DOMAIN,
Expand Down Expand Up @@ -94,7 +82,7 @@ async def read_holding_registers(call: ServiceCall) -> int:
async def read_input_registers(call: ServiceCall) -> int:
_LOGGER.debug(f"read_input_registers: {call}")

if (inverter := getDevice(call.data.get(SERVICES_PARAM_DEVICE))) is None:
if (inverter := get_device(call.data.get(SERVICES_PARAM_DEVICE))) is None:
raise ServiceValidationError(
"No communication interface for device found",
translation_domain = DOMAIN,
Expand Down Expand Up @@ -126,7 +114,7 @@ async def read_input_registers(call: ServiceCall) -> int:
async def write_holding_register(call: ServiceCall) -> None:
_LOGGER.debug(f"write_holding_register: {call}")

if (inverter := getDevice(call.data.get(SERVICES_PARAM_DEVICE))) is None:
if (inverter := get_device(call.data.get(SERVICES_PARAM_DEVICE))) is None:
raise ServiceValidationError(
"No communication interface for device found",
translation_domain = DOMAIN,
Expand All @@ -151,7 +139,7 @@ async def write_holding_register(call: ServiceCall) -> None:
async def write_multiple_holding_registers(call: ServiceCall) -> None:
_LOGGER.debug(f"write_multiple_holding_registers: {call}")

if (inverter := getDevice(call.data.get(SERVICES_PARAM_DEVICE))) is None:
if (inverter := get_device(call.data.get(SERVICES_PARAM_DEVICE))) is None:
raise ServiceValidationError(
"No communication interface for device found",
translation_domain = DOMAIN,
Expand All @@ -174,29 +162,17 @@ async def write_multiple_holding_registers(call: ServiceCall) -> None:
return

hass.services.async_register(
DOMAIN, SERVICE_READ_HOLDING_REGISTERS, read_holding_registers, schema = SERVICE_READ_REGISTERS_SCHEMA, supports_response = SupportsResponse.OPTIONAL
DOMAIN, SERVICE_READ_HOLDING_REGISTERS, read_holding_registers, schema = vol.Schema(HEADER_SCHEMA | QUANTITY_SCHEMA | WAIT_SCHEMA), supports_response = SupportsResponse.OPTIONAL
)

hass.services.async_register(
DOMAIN, SERVICE_READ_INPUT_REGISTERS, read_input_registers, schema = SERVICE_READ_REGISTERS_SCHEMA, supports_response = SupportsResponse.OPTIONAL
DOMAIN, SERVICE_READ_INPUT_REGISTERS, read_input_registers, schema = vol.Schema(HEADER_SCHEMA | QUANTITY_SCHEMA | WAIT_SCHEMA), supports_response = SupportsResponse.OPTIONAL
)

hass.services.async_register(
DOMAIN, SERVICE_WRITE_HOLDING_REGISTER, write_holding_register, schema = SERVICE_WRITE_HOLDING_REGISTER_SCHEMA
DOMAIN, SERVICE_WRITE_HOLDING_REGISTER, write_holding_register, schema = vol.Schema(HEADER_SCHEMA | VALUE_SCHEMA | WAIT_SCHEMA)
)

hass.services.async_register(
DOMAIN, SERVICE_WRITE_MULTIPLE_HOLDING_REGISTERS, write_multiple_holding_registers, schema = SERVICE_WRITE_MULTIPLE_HOLDING_REGISTERS_SCHEMA
DOMAIN, SERVICE_WRITE_MULTIPLE_HOLDING_REGISTERS, write_multiple_holding_registers, schema = vol.Schema(HEADER_SCHEMA | VALUES_SCHEMA | WAIT_SCHEMA)
)

return

def remove_services(hass: HomeAssistant) -> None:
_LOGGER.debug(f"remove_services")

hass.services.async_remove(DOMAIN, SERVICE_READ_HOLDING_REGISTERS)
hass.services.async_remove(DOMAIN, SERVICE_READ_INPUT_REGISTERS)
hass.services.async_remove(DOMAIN, SERVICE_WRITE_HOLDING_REGISTER)
hass.services.async_remove(DOMAIN, SERVICE_WRITE_MULTIPLE_HOLDING_REGISTERS)

return
4 changes: 2 additions & 2 deletions custom_components/solarman/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ read_holding_registers:
selector:
number:
min: 1
max: 65535
max: 125
mode: box
wait_for_attempts:
name: Wait for attempts
Expand Down Expand Up @@ -73,7 +73,7 @@ read_input_registers:
selector:
number:
min: 1
max: 65535
max: 125
mode: box
wait_for_attempts:
name: Wait for attempts
Expand Down

0 comments on commit dc12385

Please sign in to comment.