Skip to content

Commit

Permalink
Add description to sysvar and program (#1888)
Browse files Browse the repository at this point in the history
* Add description to sysvar and program

* Update json_rpc.py

* Update const.py

* Fix tests
  • Loading branch information
SukramJ authored Dec 1, 2024
1 parent 8ae6e73 commit cfa2ac7
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 33 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Version 2024.12.0 (2024-12-01)

- Add description to sysvar and program

# Version 2024.11.11 (2024-11-25)

- Enable central link management for HmIP-wired
Expand Down
52 changes: 35 additions & 17 deletions hahomematic/client/json_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,17 @@
from hahomematic import central as hmcu, config
from hahomematic.async_support import Looper
from hahomematic.const import (
EXTENDED_SYSVAR_MARKER,
HTMLTAG_PATTERN,
PATH_JSON_RPC,
REGA_SCRIPT_FETCH_ALL_DEVICE_DATA,
REGA_SCRIPT_GET_SERIAL,
REGA_SCRIPT_PATH,
REGA_SCRIPT_SET_SYSTEM_VARIABLE,
REGA_SCRIPT_SYSTEM_VARIABLES_EXT_MARKER,
UTF8,
DeviceDescription,
Interface,
ParameterData,
ParamsetKey,
ProgramData,
RegaScript,
SystemInformation,
SystemVariableData,
SysvarType,
Expand All @@ -59,8 +57,8 @@ class _JsonKey(StrEnum):

ADDRESS = "address"
CHANNEL_IDS = "channelIds"
DESCRIPTION = "description"
ERROR = "error"
HAS_EXT_MARKER = "hasExtMarker"
ID = "id"
INTERFACE = "interface"
IS_ACTIVE = "isActive"
Expand Down Expand Up @@ -475,7 +473,7 @@ async def set_system_variable(self, name: str, value: Any) -> bool:
)
return False
response = await self._post_script(
script_name=REGA_SCRIPT_SET_SYSTEM_VARIABLE, extra_params=params
script_name=RegaScript.SET_SYSTEM_VARIABLE, extra_params=params
)
else:
response = await self._post(
Expand Down Expand Up @@ -538,11 +536,12 @@ async def get_all_system_variables(

_LOGGER.debug("GET_ALL_SYSTEM_VARIABLES: Getting all system variables")
if json_result := response[_JsonKey.RESULT]:
ext_markers = await self._get_system_variables_ext_markers()
descriptions = await self._get_system_variable_descriptions()
for var in json_result:
is_internal = var[_JsonKey.IS_INTERNAL]
if include_internal is False and is_internal is True:
continue
extended_sysvar = False
var_id = var[_JsonKey.ID]
name = var[_JsonKey.NAME]
org_data_type = var[_JsonKey.TYPE]
Expand All @@ -551,7 +550,10 @@ async def get_all_system_variables(
data_type = SysvarType.FLOAT if "." in raw_value else SysvarType.INTEGER
else:
data_type = org_data_type
extended_sysvar = ext_markers.get(var_id, False)
if (description := descriptions.get(var_id)) and (
extended_sysvar := EXTENDED_SYSVAR_MARKER in description
):
description = description.replace(EXTENDED_SYSVAR_MARKER, "").strip()
unit = var[_JsonKey.UNIT]
values: tuple[str, ...] | None = None
if val_list := var.get(_JsonKey.VALUE_LIST):
Expand All @@ -569,6 +571,7 @@ async def get_all_system_variables(
vid=var_id,
name=name,
data_type=data_type,
description=description,
unit=unit,
value=value,
values=values,
Expand All @@ -587,17 +590,29 @@ async def get_all_system_variables(

return tuple(variables)

async def _get_system_variables_ext_markers(self) -> dict[str, Any]:
"""Get all system variables from CCU / Homegear."""
ext_markers: dict[str, Any] = {}
async def _get_program_descriptions(self) -> dict[str, str]:
"""Get all program descriptions from CCU via script."""
descriptions: dict[str, str] = {}

response = await self._post_script(script_name=RegaScript.GET_PROGRAM_DESCRIPTIONS)

_LOGGER.debug("GET_PROGRAM_DESCRIPTIONS: Getting program descriptions")
if json_result := response[_JsonKey.RESULT]:
for data in json_result:
descriptions[data[_JsonKey.ID]] = data[_JsonKey.DESCRIPTION]
return descriptions

async def _get_system_variable_descriptions(self) -> dict[str, str]:
"""Get all system variable descriptions from CCU via script."""
descriptions: dict[str, str] = {}

response = await self._post_script(script_name=REGA_SCRIPT_SYSTEM_VARIABLES_EXT_MARKER)
response = await self._post_script(script_name=RegaScript.GET_SYSTEM_VARIABLE_DESCRIPTIONS)

_LOGGER.debug("GET_SYSTEM_VARIABLES_EXT_MARKERS: Getting system variables ext markers")
_LOGGER.debug("GET_SYSTEM_VARIABLE_DESCRIPTIONS: Getting system variable descriptions")
if json_result := response[_JsonKey.RESULT]:
for data in json_result:
ext_markers[data[_JsonKey.ID]] = data[_JsonKey.HAS_EXT_MARKER]
return ext_markers
descriptions[data[_JsonKey.ID]] = data[_JsonKey.DESCRIPTION]
return descriptions

async def get_all_channel_ids_room(self) -> dict[str, set[str]]:
"""Get all channel_ids per room from CCU / Homegear."""
Expand Down Expand Up @@ -874,7 +889,7 @@ async def get_all_device_data(self, interface: Interface) -> dict[str, Any]:
}
try:
response = await self._post_script(
script_name=REGA_SCRIPT_FETCH_ALL_DEVICE_DATA, extra_params=params
script_name=RegaScript.FETCH_ALL_DEVICE_DATA, extra_params=params
)

_LOGGER.debug(
Expand All @@ -900,11 +915,13 @@ async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, .

_LOGGER.debug("GET_ALL_PROGRAMS: Getting all programs")
if json_result := response[_JsonKey.RESULT]:
descriptions = await self._get_program_descriptions()
for prog in json_result:
is_internal = prog[_JsonKey.IS_INTERNAL]
if include_internal is False and is_internal is True:
continue
pid = prog[_JsonKey.ID]
description = descriptions.get(pid)
name = prog[_JsonKey.NAME]
is_active = prog[_JsonKey.IS_ACTIVE]
last_execute_time = prog[_JsonKey.LAST_EXECUTE_TIME]
Expand All @@ -913,6 +930,7 @@ async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, .
ProgramData(
pid=pid,
name=name,
description=description,
is_active=is_active,
is_internal=is_internal,
last_execute_time=last_execute_time,
Expand Down Expand Up @@ -1060,7 +1078,7 @@ async def _get_serial(self) -> str | None:
"""Get the serial of the backend."""
_LOGGER.debug("GET_SERIAL: Getting the backend serial")
try:
response = await self._post_script(script_name=REGA_SCRIPT_GET_SERIAL)
response = await self._post_script(script_name=RegaScript.GET_SERIAL)

if json_result := response[_JsonKey.RESULT]:
serial: str = json_result[_JsonKey.SERIAL]
Expand Down
19 changes: 14 additions & 5 deletions hahomematic/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import re
from typing import Any, Final, Required, TypedDict

VERSION: Final = "2024.11.11"
VERSION: Final = "2024.12.0"

DEFAULT_CONNECTION_CHECKER_INTERVAL: Final = 15 # check if connection is available via rpc ping
DEFAULT_CUSTOM_ID: Final = "custom_id"
Expand Down Expand Up @@ -37,11 +37,7 @@
MAX_WAIT_FOR_CALLBACK: Final = 60
MAX_CACHE_AGE: Final = 10

REGA_SCRIPT_FETCH_ALL_DEVICE_DATA: Final = "fetch_all_device_data.fn"
REGA_SCRIPT_GET_SERIAL: Final = "get_serial.fn"
REGA_SCRIPT_PATH: Final = "../rega_scripts"
REGA_SCRIPT_SET_SYSTEM_VARIABLE: Final = "set_system_variable.fn"
REGA_SCRIPT_SYSTEM_VARIABLES_EXT_MARKER: Final = "get_system_variables_ext_marker.fn"

DEFAULT_DEVICE_DESCRIPTIONS_DIR: Final = "export_device_descriptions"
DEFAULT_PARAMSET_DESCRIPTIONS_DIR: Final = "export_paramset_descriptions"
Expand Down Expand Up @@ -88,6 +84,7 @@
FILE_DEVICES: Final = "homematic_devices.json"
FILE_PARAMSETS: Final = "homematic_paramsets.json"

EXTENDED_SYSVAR_MARKER: Final = "hahm"
PROGRAM_SET_PATH_ROOT: Final = "program/set"
PROGRAM_STATE_PATH_ROOT: Final = "program/status"
SET_PATH_ROOT: Final = "device/set"
Expand Down Expand Up @@ -394,6 +391,16 @@ class ProductGroup(StrEnum):
VIRTUAL = "VirtualDevices"


class RegaScript(StrEnum):
"""Enum with homematic rega scripts."""

FETCH_ALL_DEVICE_DATA: Final = "fetch_all_device_data.fn"
GET_PROGRAM_DESCRIPTIONS: Final = "get_program_descriptions.fn"
GET_SERIAL: Final = "get_serial.fn"
GET_SYSTEM_VARIABLE_DESCRIPTIONS: Final = "get_system_variable_descriptions.fn"
SET_SYSTEM_VARIABLE: Final = "set_system_variable.fn"


class Interface(StrEnum):
"""Enum with homematic interfaces."""

Expand Down Expand Up @@ -598,6 +605,7 @@ class ProgramData(HubData):
"""Dataclass for programs."""

pid: str
description: str | None
is_active: bool
is_internal: bool
last_execute_time: str
Expand All @@ -610,6 +618,7 @@ class SystemVariableData(HubData):
vid: str
value: SYSVAR_TYPE
data_type: SysvarType | None = None
description: str | None = None
extended_sysvar: bool = False
max_value: float | int | None = None
min_value: float | int | None = None
Expand Down
14 changes: 10 additions & 4 deletions hahomematic/model/hub/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from hahomematic import central as hmcu
from hahomematic.const import PROGRAM_ADDRESS, DataPointCategory, HubData, ProgramData
from hahomematic.decorators import get_service_calls, service
from hahomematic.model.decorators import state_property
from hahomematic.model.decorators import config_property, state_property
from hahomematic.model.hub.data_point import GenericHubDataPoint
from hahomematic.model.support import PathData, ProgramPathData

Expand All @@ -30,6 +30,7 @@ def __init__(
data=data,
)
self._ccu_program_name: Final = data.name
self._description = data.description
self._is_active: bool = data.is_active
self._is_internal: bool = data.is_internal
self._last_execute_time: str = data.last_execute_time
Expand All @@ -40,17 +41,22 @@ def available(self) -> bool:
"""Return the availability of the device."""
return self._is_active

@state_property
@config_property
def ccu_program_name(self) -> str:
"""Return the ccu program name."""
return self._ccu_program_name

@config_property
def description(self) -> str | None:
"""Return sysvar description."""
return self._description

@state_property
def is_active(self) -> bool:
"""Return the program is active."""
return self._is_active

@state_property
@config_property
def is_internal(self) -> bool:
"""Return the program is internal."""
return self._is_internal
Expand All @@ -60,7 +66,7 @@ def last_execute_time(self) -> str:
"""Return the last execute time."""
return self._last_execute_time

@state_property
@config_property
def pid(self) -> str:
"""Return the program id."""
return self._pid
Expand Down
6 changes: 6 additions & 0 deletions hahomematic/model/hub/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __init__(
self._vid: Final = data.vid
self.ccu_var_name: Final = data.name
super().__init__(central=central, address=SYSVAR_ADDRESS, data=data)
self._description = data.description
self._data_type = data.data_type
self._values: Final[tuple[str, ...] | None] = tuple(data.values) if data.values else None
self._max: Final = data.max_value
Expand Down Expand Up @@ -93,6 +94,11 @@ def data_type(self, data_type: SysvarType) -> None:
"""Write data_type."""
self._data_type = data_type

@config_property
def description(self) -> str | None:
"""Return sysvar description."""
return self._description

@config_property
def vid(self) -> str:
"""Return sysvar id."""
Expand Down
37 changes: 37 additions & 0 deletions hahomematic/rega_scripts/get_program_descriptions.fn
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
!# get_program_descriptions.fn
!# Erstellt in Ergänzung zu https://github.com/eq-3/occu/blob/45b38865f6b60f16f825b75f0bdc8a9738831ee0/WebUI/www/api/methods/sysvar/getall.tcl
!# Erweitert das Script um "description"
!#

var prgList = dom.GetObject(ID_PROGRAMS);
string id;

boolean dpFirst = true;
Write("[");
foreach(id, prgList.EnumIDs())
{
var prg = dom.GetObject(id);
string description;

if (prg)
{
var desc = prg.PrgInfo();
if (desc) {
description = desc;
} else {
description = "";
}

if (dpFirst) {
dpFirst = false;
} else {
WriteLine(',');
}

Write("{");
Write("\"id\": \"" # prg.ID() # "\",");
Write("\"description\": \"" # description # "\"");
Write("}");
}
}
Write("]");
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
!# get_system_variables_ext_marker.fn
!# get_system_variable_descriptions.fn
!# Erstellt in Ergänzung zu https://github.com/eq-3/occu/blob/45b38865f6b60f16f825b75f0bdc8a9738831ee0/WebUI/www/api/methods/sysvar/getall.tcl
!# Erweitert das Script um "description"
!#

var svList = dom.GetObject(ID_SYSTEM_VARIABLES);
string id;

boolean dpFirst = true;
string SYSVAR_EXT_MARKER = "hahm";
Write("[");
foreach(id, svList.EnumIDs())
{
var sv = dom.GetObject(id);
string description;
if (sv)
{
var desc = sv.DPInfo();
if (desc) {
description = desc;
} else {
description = "";
}

if (dpFirst) {
dpFirst = false;
} else {
WriteLine(',');
}
Write("{");

Write("{");
Write("\"id\": \"" # sv.ID() # "\",");
Write("\"hasExtMarker\": " # sv.DPInfo().ToLower().Contains(SYSVAR_EXT_MARKER) # "");
Write("\"description\": \"" # description # "\"");
Write("}");
}
}
Write("]");
Write("]");
Loading

0 comments on commit cfa2ac7

Please sign in to comment.