Skip to content

Commit

Permalink
Add basic support for json clients
Browse files Browse the repository at this point in the history
  • Loading branch information
SukramJ committed Nov 12, 2024
1 parent 5ba329b commit 73fe35f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 20 deletions.
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

0 comments on commit 73fe35f

Please sign in to comment.