From f5676f43081ce5ba05c152774320f65caa15ef54 Mon Sep 17 00:00:00 2001 From: SukramJ Date: Mon, 2 Sep 2024 21:23:02 +0200 Subject: [PATCH] Bump hahomematic to 2024.9.3 (#718) --- README.md | 9 ++ changelog.md | 2 +- custom_components/homematicip_local/const.py | 6 +- .../homematicip_local/manifest.json | 2 +- .../homematicip_local/services.py | 119 +++++++++++++++--- .../homematicip_local/services.yaml | 39 ++++++ .../homematicip_local/strings.json | 40 ++++++ .../homematicip_local/translations/de.json | 50 +++++++- .../homematicip_local/translations/en.json | 40 ++++++ requirements_test.txt | 2 +- 10 files changed, 286 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 2920699b..e262d2f2 100644 --- a/README.md +++ b/README.md @@ -368,10 +368,19 @@ Returns a dict of link partners Call to `getParamset` on the XML-RPC interface. Returns a paramset +### `homematicip_local.get_link_paramset` + +Call to `getParamset` for links on the XML-RPC interface. +Returns a paramset + ### `homematicip_local.put_paramset` Call to `putParamset` on the XML-RPC interface. +### `homematicip_local.put_link_paramset` + +Call to `putParamset` for links on the XML-RPC interface. + ### `homematicip_local.set_cover_combined_position` Move a blind to a specific position and tilt position. diff --git a/changelog.md b/changelog.md index d4bc4855..9d7095af 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # Version 1.66.0 (2024-09-01) -- Bump hahomematic to 2024.9.1 +- Bump hahomematic to 2024.9.3 - Add check for link paramsets - Add getLinkPeers XmlRPC method - Add paramset_key to entity_key diff --git a/custom_components/homematicip_local/const.py b/custom_components/homematicip_local/const.py index 531e181f..60bf7260 100644 --- a/custom_components/homematicip_local/const.py +++ b/custom_components/homematicip_local/const.py @@ -60,9 +60,11 @@ SERVICE_FETCH_SYSTEM_VARIABLES: Final = "fetch_system_variables" SERVICE_FORCE_DEVICE_AVAILABILITY: Final = "force_device_availability" SERVICE_GET_DEVICE_VALUE: Final = "get_device_value" +SERVICE_GET_LINK_PARAMSET: Final = "get_link_paramset" SERVICE_GET_LINK_PEERS: Final = "get_link_peers" SERVICE_GET_PARAMSET: Final = "get_paramset" SERVICE_LIGHT_SET_ON_TIME: Final = "light_set_on_time" +SERVICE_PUT_LINK_PARAMSET: Final = "put_link_paramset" SERVICE_PUT_PARAMSET: Final = "put_paramset" SERVICE_SET_COVER_COMBINED_POSITION: Final = "set_cover_combined_position" SERVICE_SET_DEVICE_VALUE: Final = "set_device_value" @@ -81,9 +83,11 @@ SERVICE_FETCH_SYSTEM_VARIABLES, SERVICE_FORCE_DEVICE_AVAILABILITY, SERVICE_GET_DEVICE_VALUE, + SERVICE_GET_LINK_PARAMSET, + SERVICE_GET_LINK_PEERS, SERVICE_GET_PARAMSET, SERVICE_LIGHT_SET_ON_TIME, - SERVICE_GET_LINK_PEERS, + SERVICE_PUT_LINK_PARAMSET, SERVICE_PUT_PARAMSET, SERVICE_SET_COVER_COMBINED_POSITION, SERVICE_SET_DEVICE_VALUE, diff --git a/custom_components/homematicip_local/manifest.json b/custom_components/homematicip_local/manifest.json index b606fad4..73f88ac6 100644 --- a/custom_components/homematicip_local/manifest.json +++ b/custom_components/homematicip_local/manifest.json @@ -10,7 +10,7 @@ "iot_class": "local_push", "issue_tracker": "https://github.com/danielperna84/hahomematic/issues", "loggers": ["hahomematic"], - "requirements": ["hahomematic==2024.9.1"], + "requirements": ["hahomematic==2024.9.3"], "ssdp": [ { "manufacturer": "EQ3", diff --git a/custom_components/homematicip_local/services.py b/custom_components/homematicip_local/services.py index 580f384e..5e92a1ca 100644 --- a/custom_components/homematicip_local/services.py +++ b/custom_components/homematicip_local/services.py @@ -9,7 +9,8 @@ from hahomematic.const import ForcedDeviceAvailability, ParamsetKey from hahomematic.exceptions import ClientException from hahomematic.platforms.device import HmDevice -from hahomematic.support import to_bool +from hahomematic.support import get_device_address, to_bool +import hahomematic.validator as hmval import voluptuous as vol from homeassistant.config_entries import ConfigEntryState @@ -35,8 +36,10 @@ SERVICE_FETCH_SYSTEM_VARIABLES, SERVICE_FORCE_DEVICE_AVAILABILITY, SERVICE_GET_DEVICE_VALUE, + SERVICE_GET_LINK_PARAMSET, SERVICE_GET_LINK_PEERS, SERVICE_GET_PARAMSET, + SERVICE_PUT_LINK_PARAMSET, SERVICE_PUT_PARAMSET, SERVICE_SET_DEVICE_VALUE, SERVICE_SET_INSTALL_MODE, @@ -53,7 +56,7 @@ CONF_ADDRESS: Final = "address" CONF_CHANNEL: Final = "channel" -CONF_TIME: Final = "time" +CONF_CHANNEL_ADDRESS: Final = "channel_address" CONF_DEVICE_ADDRESS: Final = "device_address" CONF_ENTRY_ID: Final = "entry_id" CONF_INTERFACE_ID: Final = "interface_id" @@ -62,6 +65,8 @@ CONF_PARAMSET: Final = "paramset" CONF_PARAMSET_KEY: Final = "paramset_key" CONF_RX_MODE: Final = "rx_mode" +CONF_SENDER_CHANNEL_ADDRESS: Final = "sender_channel_address" +CONF_TIME: Final = "time" CONF_VALUE: Final = "value" CONF_VALUE_TYPE: Final = "value_type" CONF_WAIT_FOR_CALLBACK: Final = "wait_for_callback" @@ -71,7 +76,7 @@ BASE_SCHEMA_DEVICE = vol.Schema( { vol.Optional(CONF_DEVICE_ID): cv.string, - vol.Optional(CONF_DEVICE_ADDRESS): cv.string, + vol.Optional(CONF_DEVICE_ADDRESS): hmval.device_address, } ) @@ -105,7 +110,7 @@ cv.has_at_most_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), BASE_SCHEMA_DEVICE.extend( { - vol.Required(CONF_CHANNEL, default=DEFAULT_CHANNEL): vol.Coerce(int), + vol.Required(CONF_CHANNEL, default=DEFAULT_CHANNEL): hmval.channel_no, vol.Required(CONF_PARAMETER): vol.All(cv.string, vol.Upper), } ), @@ -116,18 +121,25 @@ cv.has_at_most_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), BASE_SCHEMA_DEVICE.extend( { - vol.Optional(CONF_CHANNEL): vol.Coerce(int), + vol.Optional(CONF_CHANNEL): hmval.channel_no, } ), ) +SCHEMA_SERVICE_GET_LINK_PARAMSET = vol.All( + { + vol.Optional(CONF_CHANNEL_ADDRESS): hmval.channel_address, + vol.Optional(CONF_SENDER_CHANNEL_ADDRESS): hmval.channel_address, + } +) + SCHEMA_SERVICE_GET_PARAMSET = vol.All( cv.has_at_least_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), cv.has_at_most_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), BASE_SCHEMA_DEVICE.extend( { - vol.Optional(CONF_CHANNEL): vol.Coerce(int), - vol.Required(CONF_PARAMSET_KEY): vol.All(cv.string, vol.Upper), + vol.Optional(CONF_CHANNEL): hmval.channel_no, + vol.Required(CONF_PARAMSET_KEY): vol.In(["MASTER", "VALUES"]), } ), ) @@ -145,7 +157,7 @@ vol.Required(CONF_INTERFACE_ID): cv.string, vol.Optional(CONF_TIME, default=60): cv.positive_int, vol.Optional(CONF_MODE, default=1): vol.All(vol.Coerce(int), vol.In([1, 2])), - vol.Optional(CONF_ADDRESS): vol.All(cv.string, vol.Upper), + vol.Optional(CONF_ADDRESS): hmval.device_address, } ) @@ -154,10 +166,10 @@ cv.has_at_most_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), BASE_SCHEMA_DEVICE.extend( { - vol.Required(CONF_CHANNEL, default=DEFAULT_CHANNEL): vol.Coerce(int), + vol.Required(CONF_CHANNEL, default=DEFAULT_CHANNEL): hmval.channel_no, vol.Required(CONF_PARAMETER): vol.All(cv.string, vol.Upper), vol.Required(CONF_VALUE): cv.match_all, - vol.Optional(CONF_WAIT_FOR_CALLBACK): cv.positive_int, + vol.Optional(CONF_WAIT_FOR_CALLBACK): hmval.wait_for, vol.Optional(CONF_VALUE_TYPE): vol.In( ["boolean", "dateTime.iso8601", "double", "int", "string"] ), @@ -166,15 +178,24 @@ ), ) +SCHEMA_SERVICE_PUT_LINK_PARAMSET = vol.All( + { + vol.Optional(CONF_CHANNEL_ADDRESS): hmval.channel_address, + vol.Optional(CONF_SENDER_CHANNEL_ADDRESS): hmval.channel_address, + vol.Required(CONF_PARAMSET): dict, + vol.Optional(CONF_RX_MODE): vol.All(cv.string, vol.Upper), + } +) + SCHEMA_SERVICE_PUT_PARAMSET = vol.All( cv.has_at_least_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), cv.has_at_most_one_key(CONF_DEVICE_ID, CONF_DEVICE_ADDRESS), BASE_SCHEMA_DEVICE.extend( { - vol.Optional(CONF_CHANNEL): vol.Coerce(int), - vol.Required(CONF_PARAMSET_KEY): vol.All(cv.string, vol.Upper), + vol.Optional(CONF_CHANNEL): hmval.channel_no, + vol.Required(CONF_PARAMSET_KEY): vol.In(["MASTER", "VALUES"]), vol.Required(CONF_PARAMSET): dict, - vol.Optional(CONF_WAIT_FOR_CALLBACK): cv.positive_int, + vol.Optional(CONF_WAIT_FOR_CALLBACK): hmval.wait_for, vol.Optional(CONF_RX_MODE): vol.All(cv.string, vol.Upper), } ), @@ -207,8 +228,12 @@ async def async_call_hmip_local_service(service: ServiceCall) -> ServiceResponse return await _async_service_get_device_value(hass=hass, service=service) elif service_name == SERVICE_GET_LINK_PEERS: return await _async_service_get_link_peers(hass=hass, service=service) + elif service_name == SERVICE_GET_LINK_PARAMSET: + return await _async_service_get_link_paramset(hass=hass, service=service) elif service_name == SERVICE_GET_PARAMSET: return await _async_service_get_paramset(hass=hass, service=service) + elif service_name == SERVICE_PUT_LINK_PARAMSET: + await _async_service_put_link_paramset(hass=hass, service=service) elif service_name == SERVICE_PUT_PARAMSET: await _async_service_put_paramset(hass=hass, service=service) elif service_name == SERVICE_SET_INSTALL_MODE: @@ -269,6 +294,14 @@ async def async_call_hmip_local_service(service: ServiceCall) -> ServiceResponse supports_response=SupportsResponse.OPTIONAL, ) + hass.services.async_register( + domain=DOMAIN, + service=SERVICE_GET_LINK_PARAMSET, + service_func=async_call_hmip_local_service, + schema=SCHEMA_SERVICE_GET_LINK_PARAMSET, + supports_response=SupportsResponse.OPTIONAL, + ) + hass.services.async_register( domain=DOMAIN, service=SERVICE_GET_PARAMSET, @@ -299,6 +332,13 @@ async def async_call_hmip_local_service(service: ServiceCall) -> ServiceResponse schema=SCHEMA_SERVICE_SET_INSTALL_MODE, ) + hass.services.async_register( + domain=DOMAIN, + service=SERVICE_PUT_LINK_PARAMSET, + service_func=async_call_hmip_local_service, + schema=SCHEMA_SERVICE_PUT_LINK_PARAMSET, + ) + hass.services.async_register( domain=DOMAIN, service=SERVICE_PUT_PARAMSET, @@ -395,12 +435,33 @@ async def _async_service_get_link_peers( return None +async def _async_service_get_link_paramset( + hass: HomeAssistant, service: ServiceCall +) -> ServiceResponse: + """Service to call the getParamset method for links on a Homematic(IP) Local connection.""" + channel_address = service.data[CONF_CHANNEL_ADDRESS] + sender_channel_address = service.data[CONF_SENDER_CHANNEL_ADDRESS] + + if hm_device := _async_get_hm_device_by_service_data(hass=hass, service=service): + try: + return dict( + await hm_device.client.get_paramset( + address=channel_address, + paramset_key=sender_channel_address, + ) + ) + except ClientException as cex: + raise HomeAssistantError(cex) from cex + + return None + + async def _async_service_get_paramset( hass: HomeAssistant, service: ServiceCall ) -> ServiceResponse: """Service to call the getParamset method on a Homematic(IP) Local connection.""" channel_no = service.data.get(CONF_CHANNEL) - paramset_key = ParamsetKey(service.data[CONF_PARAMSET_KEY]) + paramset_key = service.data[CONF_PARAMSET_KEY] if hm_device := _async_get_hm_device_by_service_data(hass=hass, service=service): address = ( @@ -493,6 +554,25 @@ async def _async_service_fetch_system_variables(hass: HomeAssistant, service: Se await control.fetch_all_system_variables() +async def _async_service_put_link_paramset(hass: HomeAssistant, service: ServiceCall) -> None: + """Service to call the putParamset method for link manipulation on a Homematic(IP) Local connection.""" + channel_address = service.data[CONF_CHANNEL_ADDRESS] + sender_channel_address = service.data[CONF_SENDER_CHANNEL_ADDRESS] + # When passing in the paramset from a YAML file we get an OrderedDict + # here instead of a dict, so add this explicit cast. + # The service schema makes sure that this cast works. + values = dict(service.data[CONF_PARAMSET]) + rx_mode = service.data.get(CONF_RX_MODE) + + if hm_device := _async_get_hm_device_by_service_data(hass=hass, service=service): + await hm_device.client.put_paramset( + channel_address=channel_address, + paramset_key=sender_channel_address, + values=values, + rx_mode=rx_mode, + ) + + async def _async_service_put_paramset(hass: HomeAssistant, service: ServiceCall) -> None: """Service to call the putParamset method on a Homematic(IP) Local connection.""" channel_no = service.data.get(CONF_CHANNEL) @@ -564,6 +644,17 @@ def _async_get_hm_device_by_service_data( service.domain, service.service, ) + elif channel_address := service.data.get(CONF_CHANNEL_ADDRESS): + hm_device = _async_get_hm_device_by_address( + hass=hass, device_address=get_device_address(address=channel_address) + ) + if not hm_device: + _LOGGER.warning( + "No device found by channel_address %s for service %s.%s", + device_address, + service.domain, + service.service, + ) return hm_device diff --git a/custom_components/homematicip_local/services.yaml b/custom_components/homematicip_local/services.yaml index 67ef2e1a..6fe46b7b 100644 --- a/custom_components/homematicip_local/services.yaml +++ b/custom_components/homematicip_local/services.yaml @@ -80,6 +80,19 @@ get_link_peers: min: 0 max: 99 +get_link_paramset: + fields: + channel_address: + example: "0008789453:3" + required: true + selector: + text: + sender_channel_address: + example: "0008789453:3" + required: true + selector: + text: + get_paramset: fields: device_id: @@ -106,6 +119,7 @@ get_paramset: options: - "MASTER" - "VALUES" + set_variable_value: fields: entry_id: @@ -200,6 +214,31 @@ set_install_mode: selector: text: +put_link_paramset: + fields: + channel_address: + example: "0008789453:3" + required: true + selector: + text: + sender_channel_address: + example: "0008789453:3" + required: true + selector: + text: + paramset: + required: true + example: '{"WEEK_PROGRAM_POINTER": 1}' + selector: + object: + rx_mode: + example: BURST + selector: + select: + options: + - "BURST" + - "WAKEUP" + put_paramset: fields: device_id: diff --git a/custom_components/homematicip_local/strings.json b/custom_components/homematicip_local/strings.json index 04bf2636..a7e0d116 100644 --- a/custom_components/homematicip_local/strings.json +++ b/custom_components/homematicip_local/strings.json @@ -740,6 +740,20 @@ }, "name": "Get link peers" }, + "get_link_paramset": { + "description": "Call to getParamset for links in the RPC XML interface.", + "fields": { + "channel_address": { + "description": "Channel address for calling a paramset.", + "name": "Channel Address" + }, + "sender_channel_address": { + "description": "Channel address of the associated sender.", + "name": "Sender Channel Address" + } + }, + "name": "Get link paramset" + }, "get_paramset": { "description": "Call to getParamset in the RPC XML interface.", "fields": { @@ -772,6 +786,32 @@ }, "name": "Set light on time" }, + "put_link_paramset": { + "description": "Call to putParamset on the RPC XML interface.", + "fields": { + "channel_address": { + "description": "Channel address for calling a paramset.", + "name": "Channel Address" + }, + "sender_channel_address": { + "description": "Channel address of the associated sender.", + "name": "Sender Channel Address" + }, + "paramset": { + "description": "A paramset dictionary.", + "name": "Paramset" + }, + "paramset_key": { + "description": "The paramset_key argument.", + "name": "Paramset key" + }, + "rx_mode": { + "description": "The receive mode used.", + "name": "RX mode" + } + }, + "name": "Put paramset" + }, "put_paramset": { "description": "Call to putParamset on the RPC XML interface.", "fields": { diff --git a/custom_components/homematicip_local/translations/de.json b/custom_components/homematicip_local/translations/de.json index b1e16b29..123798e8 100644 --- a/custom_components/homematicip_local/translations/de.json +++ b/custom_components/homematicip_local/translations/de.json @@ -693,7 +693,7 @@ "description": "Erzwingt die Verfügbarkeit eines Geräts. Dadurch wird der tatsächliche Status überschrieben.", "fields": { "device_address": { - "description": "Geben die Geräteadresse ein.", + "description": "Gib die Geräteadresse ein.", "name": "Geräteadresse" }, "device_id": { @@ -733,7 +733,7 @@ "name": "Kanal" }, "device_address": { - "description": "Geben die Geräteadresse ein.", + "description": "Gib die Geräteadresse ein.", "name": "Geräteadresse" }, "device_id": { @@ -743,6 +743,20 @@ }, "name": "Verbindungsgegenstellen lesen" }, + "get_link_paramset": { + "description": "Abruf von getParamset für eine Verknüpfung in der RPC-XML-Schnittstelle.", + "fields": { + "channel_address": { + "description": "Kanaladresse des Parametersatzes.", + "name": "Kanaladresse" + }, + "sender_channel_address": { + "description": "Kanaladresse des verknüpften Senders.", + "name": "Sender Kanaladresse" + } + }, + "name": "Parametersatz lesen" + }, "get_paramset": { "description": "Abruf von getParamset in der RPC-XML-Schnittstelle.", "fields": { @@ -751,7 +765,7 @@ "name": "Kanal" }, "device_address": { - "description": "Geben die Geräteadresse ein.", + "description": "Gib die Geräteadresse ein.", "name": "Geräteadresse" }, "device_id": { @@ -775,6 +789,32 @@ }, "name": "Stellt die Einschaltdauer eines Lichts ein" }, + "put_link_paramset": { + "description": "Aufruf von putParamset einer Verknüpfung auf der RPC-XML-Schnittstelle.", + "fields": { + "channel_address": { + "description": "Kanaladresse des Parametersatzes.", + "name": "Kanaladresse" + }, + "sender_channel_address": { + "description": "Kanaladresse des verknüpften Senders.", + "name": "Sender Kanaladresse" + }, + "paramset": { + "description": "Ein Paramset-Wörterbuch.", + "name": "\"Parametersatz" + }, + "paramset_key": { + "description": "Das paramset_key-Argument für putParamset.", + "name": "Parametersatzschlüssel" + }, + "rx_mode": { + "description": "Der verwendete Empfangsmodus.", + "name": "RX Modus" + } + }, + "name": "Parametersatz einer Verknüpfung schreiben" + }, "put_paramset": { "description": "Aufruf von putParamset auf der RPC-XML-Schnittstelle.", "fields": { @@ -783,7 +823,7 @@ "name": "Kanal" }, "device_address": { - "description": "Geben die Geräteadresse ein.", + "description": "Gib die Geräteadresse ein.", "name": "Geräteadresse" }, "device_id": { @@ -835,7 +875,7 @@ "name": "Kanal" }, "device_address": { - "description": "Geben die Geräteadresse ein.", + "description": "Gib die Geräteadresse ein.", "name": "Geräteadresse" }, "device_id": { diff --git a/custom_components/homematicip_local/translations/en.json b/custom_components/homematicip_local/translations/en.json index 04bf2636..a7e0d116 100644 --- a/custom_components/homematicip_local/translations/en.json +++ b/custom_components/homematicip_local/translations/en.json @@ -740,6 +740,20 @@ }, "name": "Get link peers" }, + "get_link_paramset": { + "description": "Call to getParamset for links in the RPC XML interface.", + "fields": { + "channel_address": { + "description": "Channel address for calling a paramset.", + "name": "Channel Address" + }, + "sender_channel_address": { + "description": "Channel address of the associated sender.", + "name": "Sender Channel Address" + } + }, + "name": "Get link paramset" + }, "get_paramset": { "description": "Call to getParamset in the RPC XML interface.", "fields": { @@ -772,6 +786,32 @@ }, "name": "Set light on time" }, + "put_link_paramset": { + "description": "Call to putParamset on the RPC XML interface.", + "fields": { + "channel_address": { + "description": "Channel address for calling a paramset.", + "name": "Channel Address" + }, + "sender_channel_address": { + "description": "Channel address of the associated sender.", + "name": "Sender Channel Address" + }, + "paramset": { + "description": "A paramset dictionary.", + "name": "Paramset" + }, + "paramset_key": { + "description": "The paramset_key argument.", + "name": "Paramset key" + }, + "rx_mode": { + "description": "The receive mode used.", + "name": "RX mode" + } + }, + "name": "Put paramset" + }, "put_paramset": { "description": "Call to putParamset on the RPC XML interface.", "fields": { diff --git a/requirements_test.txt b/requirements_test.txt index 5341108f..825b1948 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ -r requirements_test_pre_commit.txt async-upnp-client==0.40.0 -hahomematic==2024.9.1 +hahomematic==2024.9.3 homeassistant==2024.9.0b2 mypy==1.11.2 mypy-dev==1.11.0a9