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

Add basic support for json clients #1837

Merged
merged 1 commit into from
Nov 12, 2024
Merged
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
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Version 2024.11.1 (2024-11-09)

- Add getDeviceDescription, getParamsetDescription, listDevices, getValue, setValue, getParamset, putParamset to json_rpc
- Add basic support for json clients
- Add data_point_path event
- Add getDeviceDescription, getParamsetDescription, listDevices, getValue, setValue, getParamset, putParamset to json_rpc
- Rename event to data_point_event

# Version 2024.11.0 (2024-11-04)
Expand Down
79 changes: 63 additions & 16 deletions hahomematic/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
DEFAULT_CUSTOM_ID,
DEFAULT_MAX_WORKERS,
DP_KEY,
HOMEGEAR_SERIAL,
DUMMY_SERIAL,
INIT_DATETIME,
INTERFACES_SUPPORTING_FIRMWARE_UPDATES,
VIRTUAL_REMOTE_MODELS,
Expand Down Expand Up @@ -1168,6 +1168,31 @@ async def _get_system_information(self) -> SystemInformation:
class ClientJsonCCU(ClientCCU):
"""Client implementation for CCU backend."""

async def init_client(self) -> None:
"""Init the client."""
self._system_information = await self._get_system_information()

@service(re_raise=False, no_raise_return=False)
async def check_connection_availability(self, handle_ping_pong: bool) -> bool:
"""Check if proxy is still initialized."""
return await self._json_rpc_client.is_present(interface=self.interface)

async def proxy_init(self) -> ProxyInitState:
"""Init the proxy has to tell the CCU / Homegear where to send the events."""
device_descriptions = await self.list_devices()
await self.central.add_new_devices(
interface_id=self.interface_id, device_descriptions=device_descriptions
)
return ProxyInitState.INIT_SUCCESS

async def proxy_de_init(self) -> ProxyInitState:
"""De-init to stop CCU from sending events for this remote."""
return ProxyInitState.DE_INIT_SUCCESS

async def stop(self) -> None:
"""Stop depending services."""
return

@property
def supports_ping_pong(self) -> bool:
"""Return the supports_ping_pong info of the backend."""
Expand Down Expand Up @@ -1355,6 +1380,16 @@ async def _exec_set_value(
value=value,
)

async def _get_system_information(self) -> SystemInformation:
"""Get system information of the backend."""
return SystemInformation(
available_interfaces=(
Interface.CUXD,
Interface.CCU_JACK,
),
serial=f"{self.interface}_{DUMMY_SERIAL}",
)


class ClientHomegear(Client):
"""Client implementation for Homegear backend."""
Expand Down Expand Up @@ -1390,8 +1425,8 @@ async def fetch_device_details(self) -> None:
):
try:
self.central.device_details.add_name(
address,
await self._proxy_read.getMetadata(address, _NAME),
address=address,
name=await self._proxy_read.getMetadata(address, _NAME),
)
except BaseHomematicException as ex:
_LOGGER.warning(
Expand Down Expand Up @@ -1489,7 +1524,7 @@ async def get_all_functions(self) -> dict[str, set[str]]:
async def _get_system_information(self) -> SystemInformation:
"""Get system information of the backend."""
return SystemInformation(
available_interfaces=(Interface.BIDCOS_RF,), serial=HOMEGEAR_SERIAL
available_interfaces=(Interface.BIDCOS_RF,), serial=f"{self.interface}_{DUMMY_SERIAL}"
)


Expand Down Expand Up @@ -1525,20 +1560,19 @@ def __init__(

async def get_client(self) -> Client:
"""Identify the used client."""
client: Client | None = None
check_proxy = await self._get_simple_xml_rpc_proxy()
try:
if methods := check_proxy.supported_methods:
# BidCos-Wired does not support getVersion()
self.version = (
cast(str, await check_proxy.getVersion()) if "getVersion" in methods else "0"
)

if client := (
ClientHomegear(client_config=self)
if "Homegear" in self.version or "pydevccu" in self.version
else ClientCCU(client_config=self)
self.version = await self._get_version()
client: Client | None
if self.interface == Interface.BIDCOS_RF and (
"Homegear" in self.version or "pydevccu" in self.version
):
client = ClientHomegear(client_config=self)
elif self.interface in (Interface.CCU_JACK, Interface.CUXD):
client = ClientJsonCCU(client_config=self)
else:
client = ClientCCU(client_config=self)

if client:
await client.init_client()
if await client.check_connection_availability(handle_ping_pong=False):
return client
Expand All @@ -1548,6 +1582,19 @@ async def get_client(self) -> Client:
except Exception as ex:
raise NoConnectionException(f"Unable to connect {reduce_args(args=ex.args)}.") from ex

async def _get_version(self) -> str:
"""Return the version of the backend."""
if self.interface in (Interface.CCU_JACK, Interface.CUXD):
return str(self.interface)
check_proxy = await self._get_simple_xml_rpc_proxy()
try:
if (methods := check_proxy.supported_methods) and "getVersion" in methods:
# BidCos-Wired does not support getVersion()
return cast(str, await check_proxy.getVersion())
except Exception as ex:
raise NoConnectionException(f"Unable to connect {reduce_args(args=ex.args)}.") from ex
return "0"

async def get_xml_rpc_proxy(
self, auth_enabled: bool | None = None, max_workers: int = DEFAULT_MAX_WORKERS
) -> XmlRpcProxy:
Expand Down
16 changes: 16 additions & 0 deletions hahomematic/client/json_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class _JsonRpcMethod(StrEnum):
INTERFACE_GET_PARAMSET = "Interface.getParamset"
INTERFACE_GET_PARAMSET_DESCRIPTION = "Interface.getParamsetDescription"
INTERFACE_GET_VALUE = "Interface.getValue"
INTERFACE_IS_PRESENT = "Interface.isPresent"
INTERFACE_LIST_DEVICES = "Interface.listDevices"
INTERFACE_LIST_INTERFACES = "Interface.listInterfaces"
INTERFACE_PUT_PARAMSET = "Interface.putParamset"
Expand Down Expand Up @@ -919,6 +920,21 @@ async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, .

return tuple(all_programs)

async def is_present(self, interface: Interface) -> bool:
"""Get value from CCU."""
value: bool = False
params = {_JsonKey.INTERFACE: interface}

response = await self._post(
method=_JsonRpcMethod.INTERFACE_IS_PRESENT, extra_params=params
)

_LOGGER.debug("IS_PRESENT: Getting the value")
if json_result := response[_JsonKey.RESULT]:
value = bool(json_result)

return value

async def has_program_ids(self, channel_hmid: str) -> bool:
"""Return if a channel has program ids."""
params = {_JsonKey.ID: channel_hmid}
Expand Down
2 changes: 1 addition & 1 deletion hahomematic/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
REPORT_VALUE_USAGE_VALUE_ID: Final = "PRESS_SHORT"
REPORT_VALUE_USAGE_DATA: Final = "reportValueUsageData"

HOMEGEAR_SERIAL = "Homegear_SN0815"
DUMMY_SERIAL = "SN0815"

PROGRAM_ADDRESS: Final = "program"
SYSVAR_ADDRESS: Final = "sysvar"
Expand Down
4 changes: 2 additions & 2 deletions hahomematic/model/hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def fetch_sysvar_data(self, scheduled: bool) -> None:
"""Fetch sysvar data for the hub."""
if self._config.sysvar_scan_enabled:
_LOGGER.debug(
"FETCH_SYSVAR_DATA: % fetching of system variables for %s",
"FETCH_SYSVAR_DATA: %s fetching of system variables for %s",
"Scheduled" if scheduled else "Manual",
self._central.name,
)
Expand All @@ -76,7 +76,7 @@ async def fetch_program_data(self, scheduled: bool) -> None:
"""Fetch program data for the hub."""
if self._config.program_scan_enabled:
_LOGGER.debug(
"FETCH_PROGRAM_DATA: % fetching of programs for %s",
"FETCH_PROGRAM_DATA: %s fetching of programs for %s",
"Scheduled" if scheduled else "Manual",
self._central.name,
)
Expand Down