danielperna84 / hahomematic

Python 3 Interface for Home Assistant to interact with HomeMatic devices
MIT License
136 stars 21 forks source link

Support for write access to Homematic string variables #396

Closed eikowagenknecht closed 2 years ago

eikowagenknecht commented 2 years ago

Is your feature request related to a problem? Please describe. I have a string variable in Homematic. I want to be able to set it from Home Assistant.

service: homematicip_local.set_variable_value
data:
  entity_id: homematicip_local.ccu3
  name: NachrichtAdmin
  value: 0

This works but sets the string variable to "0.0". false also works and sets the string to "0.0", true sets it to "1.0".

Describe the solution you'd like I'd like for this to work as well:

service: homematicip_local.set_variable_value
data:
  entity_id: homematicip_local.ccu3
  name: NachrichtAdmin
  value: "Hello world!"

Currently it results in an error:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 379, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 582, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1634, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1671, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 800, in check_permissions
    return await service_handler(call)
  File "/config/custom_components/homematicip_local/services.py", line 143, in async_call_hmip_local_service
    await _async_service_set_variable_value(hass=hass, service=service)
  File "/config/custom_components/homematicip_local/services.py", line 259, in _async_service_set_variable_value
    await hub.async_set_variable(name=name, value=value)
  File "/config/custom_components/homematicip_local/control_unit.py", line 659, in async_set_variable
    value = cv.boolean(value) if isinstance(old_value, bool) else float(value)
ValueError: could not convert string to float: 'Hello world'

Describe alternatives you've considered

Additional context Files this as a feature request and not a bug because I can't find documentation that says that this should work.

SukramJ commented 2 years ago

This is not supported by the JsonRPC API. See http:/{CCU_IP}/api/homematic.cgi.

Only SysVar.setBool, SysVar.setEnum and SysVar.setFloat are supported by the API. We only support SysVar.setBool and SysVar.setFloat, which also supports enums by their index. [Edit] SysVar.setEnumis also not relevant, because the value list is set and not a value of the list.

eikowagenknecht commented 2 years ago

Is there another API that can be used instead? E.g. pocketControl can set the variable values for text, so it is possible somehow.

SukramJ commented 2 years ago

There is no API, that we use, that supports writing strings to variables. The only option i see is writing a rega script that accepts a value and a variable name. Currently we only use rega scripts without parameters for reading. I cannot provides such a script, but maybe someone else can do this.

Baxxy13 commented 2 years ago

Wenn du Name der SV (sv_name) und zu schreibenden Wert (sv_value) als String an das Script übergeben kannst dann sollte das bspw. so gehen.

string sv_name;
string sv_value;
object target_sv = dom.GetObject (ID_SYSTEM_VARIABLES).Get (sv_name);
if (target_sv) { target_sv.State(sv_value); }

Eine Prüfung ob es tatsächlich eine Text-SysVar ist ließe sich noch problemlos einbauen. Edit: (sv_value) muss kein string sein, das ließe sich im Script noch wandeln.

SukramJ commented 2 years ago

Eine Prüfung ob es tatsächlich eine Text-SysVar ist ließe sich noch problemlos einbauen.

Das wäre gut.

Ich hab es jetzt so eingebaut:

string sv_name = "##name##";
string sv_value = "##value##";
object target_sv = dom.GetObject(sv_name);
if (target_sv) {
    WriteLine(target_sv.State(sv_value));
}

Das Script wird nur bei String Werten ausgeführt.

SukramJ commented 2 years ago

Eine Prüfung ob es tatsächlich eine Text-SysVar ist ließe sich noch problemlos einbauen.

Vielleicht brauchen wir das doch nicht.

Wenn ich das richtig sehe wird das hier auch nicht geprüft.

Baxxy13 commented 2 years ago

Die Text-SysVars sind da recht unproblematisch, da kann alles rein. Daher braucht man auch nicht wirklich prüfen ob das Ziel eine Teyt-SysVar ist. Nur mit html-Code sollte man vorsichtig sein, wenn sowas in der SysVar landet liegt schnell mal die WebUI auf dem Bauch.

WriteLine(target_sv.State(sv_value)); Interessant. Habe ich so auch noch nicht gesehen. Das gibt immer ein "true" als WriteLine aus, wozu brauchst du das? Ich würde bei meine Code bleiben, der ist konsequent und nachvollziehbar. WriteLines nutze man eher zum Debuggen für einzelne Scriptabschnitte. Im verlinkten Beispiel heißt es ja... Write(sv.State(value));

SukramJ commented 2 years ago

Aus hm_script teil 2:

Der Rückgabewert gibt Aufschluss darüber, ob das Setzen erfolgreich war (true) oder nicht (false).

WriteLine würde ich noch mal gegen Write austauschen.

Nur mit html-Code sollte man vorsichtig sein, wenn sowas in der SysVar landet liegt schnell mal die WebUI auf dem Bauch.

Kann man das im Script prüfen?

SukramJ commented 2 years ago

Ich werde eine html Prüfung per regex siehe einbauen.

Ist nur html-Code problematisch?

Baxxy13 commented 2 years ago

Ok, hab das nochmal nachgelesen. Sollte passen mit dem Write... Aber bitte nimm statt... object target_sv = dom.GetObject(sv_name); mein... object target_sv = dom.GetObject (ID_SYSTEM_VARIABLES).Get (sv_name);

Nur damit ist sichergestellt das das Ziel eine Systemvariable ist. Andernfalls wird vielleicht ein Gerät was genauso heißt versucht zu beschreiben. Das einfache dom.GetObject() iteriert durch alle Objekte, der erste Treffer wird genommen. Ich habe nun doch noch die Prüfung auf string eingebaut, kann nicht schaden.

string sv_name = "##name##";
string sv_value = "##value##";
object target_sv = dom.GetObject (ID_SYSTEM_VARIABLES).Get (sv_name);
if (target_sv) {
    if (target_sv.ValueTypeStr() == "String") {
       Write(target_sv.State(sv_value));
}}

Kann man das im Script prüfen.

Nicht wirklich. Dafür ist die HM-Scriptsprache nicht gemacht. Viele "gefährliche" Sachen werden aber auch in der WebUI "umcodiert". Ein kleines Restrisiko besteht aber. Das nehmen wir (zumindest mit RaspberryMatic) in Kauf. Man kann nicht alles abdecken. Da müsstest du dich mal mit @jens-maus kurzschließen ob es sinnvoll wäre was auszufiltern.

SukramJ commented 2 years ago

Ok, ich hatte das mit ID_SYSTEM_VARIABLES nicht verstanden. Letzter Stand:

string sv_name = "##name##";
string sv_value = "##value##";
object target_sv = dom.GetObject(ID_SYSTEM_VARIABLES).Get(sv_name);
if (target_sv) {
    Write(target_sv.State(sv_value));
}
Baxxy13 commented 2 years ago

Deine Entscheidung. Wenn an das Script von HA aus immer ein String übergeben wird, wovon ich ausgehe... dann kann man damit diesen String auch (versuchen) in alle anderen SysVar-Arten (Zahl / Logik / Alarm / WerteListe) zu schreiben. Das könnte problematisch sein.

Ich würde die Prüfung auf die Text-SysVar drin lassen wenn du keine anderen Vorkehrungen triffst um obiges zu vermeiden.

SukramJ commented 2 years ago

Ich würde die Prüfung auf die Text-SysVar drin lassen wenn du keine anderen Vorkehrungen triffst um obiges zu vermeiden.

Den Teil hab ich übersehen. Bei dem Farbschema sieht alles gleich aus.

string sv_name = "##name##";
string sv_value = "##value##";
object target_sv = dom.GetObject(ID_SYSTEM_VARIABLES).Get(sv_name);
if (target_sv) {
    if (target_sv.ValueTypeStr() == "String") {
       Write(target_sv.State(sv_value));
    }
}
Baxxy13 commented 2 years ago

Ich seh hier nur schwarz / weiss. ;-)

Bin gespannt ob das funktioniert. Mit remote Script kenne ich mich nicht wirklich aus. So wie es jetzt zu sehen ist würd es lokal nicht funktionieren da die strings noch die Rauten enthalten. Mal schauen.

SukramJ commented 2 years ago

Dann schaut es euch bitte in Version 1.1.2 an.

Baxxy13 commented 2 years ago

Sieht gut aus!

service: homematicip_local.set_variable_value
data:
  entity_id: homematicip_local.rm_test_pi3bplus_27
  name: A_Test_SV_Text
  value: funktioniert

Text_SysVar_von_HA_beschreiben

SukramJ commented 2 years ago

Ich denke das ticket kann erst mal geschlossen werden. Vielen Dank für dein Unterstützung @Baxxy13

eikowagenknecht commented 2 years ago

Vielen Dank für die schnelle Umsetzung 👍

SukramJ commented 1 year ago

Mit Version 1.23.0, die zusammen mit HA 2022.12 erscheinen wird, gibt es Text(r/w) Entitäten. Wenn Sysvars in der CCU mit hahm deklariert werden, dann erscheinen die Sysvars in HA auch als Text Entität. Die Einschränkung auf 255 Zeichen bleibt aber bestehen.

eikowagenknecht commented 1 year ago

Nice use case for those! Thanks!