HMCCUCHAN generischer Ansatz

Begonnen von martinp876, 21 Dezember 2019, 16:34:33

Vorheriges Thema - Nächstes Thema

martinp876

Schon länger trage ich mich mit dem Anliegen, die devices (auch)  über die ccu zu kontrollieren. Ich habe vor etlicher zeit begonnen und dann wieder abgebrochen. Grund ist, dass es für mein verständniss nicht hinreichend generisch implementiert ist.
Was hier kommt ist natürlich meine private Ansicht, welche ich definitiv auf die eine oder andere Art verfolgen werde. Was ich sagen will: es sind vorschläge und konstruktive (keine negative) Kritik. Sollte es auf Ablehnung stossen, kein Problem. Dann mache ich privat weiter.
Also:
Ich werde immer den channel Ansatz für entities nutzen. Diesen brauche ich zwingend generisch. Wenn ich kanal 3 eines aktors ansehe darf keines der readings mit 3.LEVEL beginnen. Es ist schlicht level... usw.
Im kanal haben die device infos nichts verloren. Hierzu habe ich device 0.
Die capital letter sind störend. Nicht so prickelnd, nicht fhem üblich. Sollte man einfach umstezen.
Ich habe einmal einen dimmer probiert. Man kann ihn über pct dimmen. Allerdings fehlt das reading, was den slider dann nicht bedient. Geht natürlich nur über das entfernen der kanalnummer in den readings namen.

Beim dimmer fehlen einige Kommandos wie on\off. Das übliche eben.

Ich bin erst am Anfang....  Gibt es einen einfachen Weg, die konfig so zu implementieren, wie ich es dargestellt habe? Ich habe nicht vor, jedes reading manuell umzubenennen.

In jeden Fall, vielen dank für das Modul.

zap

Ich nehme an, du meinst HMCCUCHN.

Alle Deine Wünsche lassen sich mit Attributen umsetzen, außer die Kanalnummer im Readingname. Das müsste ich noch konfigurierbar machen.

Die  Readings in Kleinbuchstaben gibts mit ccureadingformat = datapointlc, lc am Ende für lowercase.

Ein pct Reading bekommst du mit

ccureadingname LEVEL:+pct, ohne das + wird LEVEL durch pct ersetzt.

Den Kanal 0 kannst du mit ccuflags = nochn0 abschalten. Finde ich aber ganz praktisch, da hier die Lowbat und Unreach States drin stecken
2xCCU3 mit ca. 100 Aktoren, Sensoren
Entwicklung: FHEM auf Proxmox Debian VM
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: HMCCU, (Fully, AndroidDB)

martinp876

ok, danke. Ich komme schon einmal weiter.
Ich haben also
ccureadingformat = datapointlc
gesetzt. lc ist klar, danke.
Du hast alles einstellbar gemacht. Gibt jede menge optionen - und viel Arbeit sich durchzuwurschteln.
zu ccureadingformat  sehe ich ccudef-readingfilter. Das hört sich dann schon viel besser an. Ich könnte wenn notwendig, aber will nur "unter Zwang" solche Attribute bei jeder Entity setzen.
Dein Vorschlag für mich ist also präzise
set  ccu ccudef-readingformat datapointlc
Wobei ich in der Beschreibung "commandref" den Hinweis vermissem dass dieses Attribut nicht am Device sondern der CCU anzubringen ist.
Unsauber: Das Attribut funktioniert nur für "neue" Readings. Beim Umschalten sollten m.E. alle bestehenden Readings umgearbeitet werden. Das macht Arbeit, klar. Aber wenn du es nicht machst muss es der User jedes mal machen.
Gleiches gilt für ccuflags = nochn0.
Hierzu ist mir das Verhalten noch unklar - ich kann es im Code sucher oder experimintieren. Ist aber langwierig - Beschreibung wäre cool:
a) setze ich ccuflags = nochn0 in der ccu - wirkt dies auf alle Entities der ccu?
b) wenn ich das Attribut überall setze - was passiert mit Kanal 0? Sind dann alle Readings weg? Hoffentlich nicht.

Ich finde es unpraktisch eine Liste von Readings des Device im kanal zu haben. Eine Zusammenfassung ist sicher ok. Z.B. Message State: Commands pending/done/fault sowie DeviceHealth:ok/batlow/reachabel/overheat. 2 Readings -ok. RSSI zu Peers - no!

Aber neben der (konstruktiven!) Kritik - ich sehe das Modul grundsätzlich natürlich positiv. Vielen Dank hierfür.

Jetzt muss ich erst einmal suchen, was get config macht und warum bei mir "Cannot detect or create external RPC device" erscheint. Und ob das irgendwo beschrieben ist.


martinp876

Ich habe nun etwas ccureadingname gespielt. Ziel ist es, den level des dimmers darzustellen. Für fhem brauche ich
level und pct als reading. Weiter level_real natürlich für hm dimmer.
Etwas inkonsistent ist:
- nutze ich +pct wird ein zusätzliches reading ohne nummer (1.)  eingefügt. Jetzt: level oder level_real?
- nutze ich pct werden die beiden readings 1.xxx ersetzt. Die alten muss ich (natürlich und leider) manuell löschen
Ok, wenn ich es korrekt sehe wird eine regular expression genutzt wobei die Kanal nummer (leider) teil des readings ist.
Im kommandref beschrieben ist, dass bei mehrfachtreffern nur ein reading erzeugt wird. Der inhalt ist mir nicht wirklich klar.

De-facto brauche ich als anwender nun eine übersetzungstabelle. Und zwar devicetyp\channel(typ)\ccureading nach fhem reading.
Ich will das schliesslich nicht für jede entity eintragen. Alle entities gleichen typs müssen identische readings nutzen.
Daraus müssen dann die attribute generiert und gesetzt werden.

martinp876

meine Probleme:
Scheinbar brauche ich irgendwie einen externen RPC server. Hierzu kommen immer fehlermeldungen, aber ich finde keinen Info in Wiki wie  best-current practice o.ä.
Mache ich das Grundsätzlich falsch?

get <chan> config <device>
a) was soll ich als "device" angeben?
   Es muss ein HMCCU I/O Device existieren. Was ist ein HMCCU I/O Device? Ich habe eine HMccu definiert. Das reicht nicht.
b) warum muss ich das Device überhaupt angeben? Kann man das nicht automatisch einsetzen?

get <chan> configdesc  <device>
a) das Kommando hat keinen Parameter. Doku und Implementierung sind nicht konsistent
b) Es funktioniert bei mir nicht, mangels external RPC device.  Brauche ich das  udn wie bekomme ich es?
get <chan> configdesc  <device>

Scheinbar habe ich ein grundsätzliches Problem mit einem external RPC device

get <chan> datapoint <datapoint>
liefert kein Ergebnis - keine Reaktion. Wird das Reading upgedated? Sollet ein Fenster aufgehen?

attr <chan> statedatapoint <datapoint>
a) <datapoint> ist der CCU-datapoint, nicht der Umgesetzt. Ist m.E. schade - sollte aber zumindest beschrieben werden. Allerdings ist mir nicht klar, warum ich das brauche. FHEM bietet für State bereits default attribut. Warum nutzt man nicht diese? Was macht statedatapoint anders?

Zitatget <chan> devstate
was macht dies? Es ist ein Update readings für genau einen Parameter. macht 'update' nicht das gleich? Ist das Kommando überflüssig?

Zitatget <chan> update ...
Die Beschreibung verstehe ich nicht
a) er werden ALLE Datapoints upgedated (sehr gut). Das sollte idR automatisch gehen. Ist also einfach ein manueller Trigger in Sonderfällen. korrekt?
b) With option 'State' the device is queried. Was sagt mir das? Wo soll das Device hin? Ist es ein Device oder der Channel, also schlicht die Entity? Und was wird dann upgedatet - immer noch alle Datapoints?
c)This request method is more accurate but slower then 'Value'.Das ist nun beängstigend. Was bedeutet, dass "Value" nicht akkurat ist? Es kommen manchmal falsche Werte? Ich verstehe den Unterschied schlicht nicht.

In den Beschreibungen wäre es m.E. korrekt zwischen Kanälen und Devices zu unterscheiden. Die Begriffe werden vermischt. Ich nutze (hoffentlich immer :) ) Kanäle, Devices dediziert und entites wenn beides möglich ist.

In der Doku zu HMccu device.list fehlen m.E. ein paar umbrüche für die Lesbarkeit. Mein Vorschlag:

      <li><b>get &lt;name&gt; devicelist create &lt;devexp&gt; [t={chn|<u>dev</u>|all}]
      [p=&lt;prefix&gt;] [s=&lt;suffix&gt;] [f=&lt;format&gt;] [defattr] [duplicates]
      [save] [&lt;attr&gt;=&lt;value&gt; [...]]</b><br/>
         create: HMCCU will automatically create client entities for all CCU entities
         matching specified regular expression in devexp. <br>
         t=chn/dev/all: Creation of entities is limited to CCU channels or devices. dev = default. <br>
         prefix/suffix/format: defines a template for entity names in FHEM. All can contain format identifiers which are substituted by corresponding values of the CCU device or
         channel: <br>
         <li>
         %n = CCU object name (channel or device)<br>
         %d = CCU device name<br>
         %a = CCU address<br>
         </li>
         Additionally a list of default attributes for the created entities can be specified.<br>
         defattr: HMCCU sets default attributes for entities if available. <br>
         duplicates: HMCCU will not only create non-existing entites but also overwrite existing entities for existing addresses. <br>
         save: auto-save FHEM config after finishing

zap

#5
    Hey richtig inspirierend Deine Anmerkungen. vielen Dank! Endlich mal jemand, der die richtigen Fragen stellt ;)

    Bei vielen Dingen hast Du recht, die sind teilweise inkonsistent, da historisch gewachsen. Ich versuche, heute oder morgen auf die wichtigsten Punkte zu antworten.

RPC Devices / Server

Das RPC Device (HMCCURPCPROC) wird für alle Funktionen benötigt, die die RPC Schnittstellen der CCU benötigen:


  • alle get oder set config, configlist, configdesc Befehle. Bei CUL_HM sind das glaube ich die Register. Also alles, was sich in der CCU unter Einstellungen / Geräteeinstellungen findet
  • der relativ neue Befehl set rpcparameter (lowlevel Variante anderer Befehle wie z.B. set config)
  • das automatische Aktualisieren der Readings, wenn sich irgendwelche Zustände in den Geräten ändern (das ist eigentlich die Hauptfunktion eines RPC Device)

Das ist im Wiki-Hauptartikel zu HMcCU beschrieben (Stichwort RPC Server konfigurieren).

Die anderen Befehle wie get/set datapoint oder auch get update benutzen die ReGA Schnittstelle der CCU, kommen also ohne RPC Device aus.
Es genügt, im IO Device das Attribut ccuinterfaces auf die verwendeten Schnittstellen zu setzten, dann werden die RPC Devices beim ersten Starten der RPC Server automatisch angelegt.

Die Architektur entspricht im Prinzip der Umsetzung der CCU Schnittstellen in ioBroker, OpenHab, ...

1 IO Device je CCU
1 RPC Device je CCU Schnittstelle (hmip, bidcos, wired, ...)
>= 1 Device je Gerät oder Kanal

Readingformate

Die Readings umzubauen, sobald sich an einem der Attribute etwas ändert (z.B. Format des Readingnames) ist ein ziemlicher Aufwand. Aktuell könnte ein Nutzer vor oder nach der Änderung der Attribute einmal die alten Readings mit set clear löschen und dann per get update einmal alle neu von der CCU holen. Oder er wartet, bis sie über den RPC Server automatisch nach und nach aktualisiert werden. Kurzfristig könnte ich die beiden Schritte automatisieren, d.h. eine Änderung der Attribute hat ein set clear / get update zur Folge.

Das Attribut ccuscaleval sorgt für die Skalierung von Werten wie z.B. LEVEL, mach also aus 0..1 0..100. Leider ist es derzeit noch nicht möglich, beides zu haben. Also z.B. in LEVEL die Werte 0..1 und in pct die Werte 0..100.

get / set config

Die Syntax ist abhängig davon, ob man ein HMCCUCHN oder HMCCUDEV Device verwendet. Bei HMCCUCHN bewirkt get <name> config das Auslesen der Parameter von dem Kanal, auf den sich das HMCCUCHN Device bezieht. Wenn dieser Kanal keine konfigurierbaren Parameter besitzt, schlägt der Befehl fehlt.
'device' ist kein Platzhalter sondern tatsächlich der String "device". Wenn Du diese Option bei einem HMCCUCHN Device anhängst, werden die Konfigurationsparameter vom Gerät (nicht die vom Kanal) ausgelesen. Meistens sind Parameter wie AES gerätebezogen. Ich weiß, das ist wieder ein Stück weit inkonsequent, da von einem Kanaldevice auf Geräteparameter zugegriffen werden kann. Macht aber das Leben manchmal einfacher und erspart ein separates HMCCUDEV Device.

Zitat
get <chan> datapoint <datapoint>
liefert kein Ergebnis - keine Reaktion. Wird das Reading upgedated? Sollet ein Fenster aufgehen?
Das entsprechende Reading sollte aktualisiert werden. Zu beachten: Der Datenpunkt muss im regulären Ausdruck vom Attribut ccureadingfilter enthalten sein.

Zitat
attr <chan> statedatapoint <datapoint>
a) <datapoint> ist der CCU-datapoint, nicht der Umgesetzt. Ist m.E. schade - sollte aber zumindest beschrieben werden. Allerdings ist mir nicht klar, warum ich das brauche. FHEM bietet für State bereits default attribut. Warum nutzt man nicht diese? Was macht statedatapoint anders?
Legt den Datenpunkt fest, dessen Wert in state/STATE geschrieben wird. Dieser Datenpunkt wird auch angesprochen, wenn Du zusätzlich mit statevals Werte für den statedatapoint festgelegt hast. Beispiel:
[/list]
attr <name> statevals on:1,off:0
attr <name> statedatapoint 2.STATE
set <name> on

Außerdem fließt statedatapoint noch in andere Funktionen ein, ist also relativ wichtig.

Zitat
get <chan> devstate
was macht dies? Es ist ein Update readings für genau einen Parameter. macht 'update' nicht das gleich? Ist das Kommando überflüssig?
Ja, ist eigentlich veraltet. Bezieht sich immer auf den Datenpunkt, der als statedatapoint festgelegt wurde.

Zitat
get <chan> update ...
Die Beschreibung verstehe ich nicht
a) er werden ALLE Datapoints upgedated (sehr gut). Das sollte idR automatisch gehen. Ist also einfach ein manueller Trigger in Sonderfällen. korrekt?
RPC Devices sind Dein Freund. Jedes RPC Device startet einen RPC-Server, der Reading-Aktualisierungen von der CCU empfängt und alle entsprechenden Devices (HMCCUCHN, HMCCUDEV) aktualisiert. Ohne RPC Device funktioniert nur ein Bruchteil. Daher siehe auch HMCCU Wiki Konfiguration des RPC Servers.

Zitat
b) With option 'State' the device is queried. Was sagt mir das? Wo soll das Device hin? Ist es ein Device oder der Channel, also schlicht die Entity? Und was wird dann upgedatet - immer noch alle Datapoints?
c)This request method is more accurate but slower then 'Value'.Das ist nun beängstigend. Was bedeutet, dass "Value" nicht akkurat ist? Es kommen manchmal falsche Werte? Ich verstehe den Unterschied schlicht nicht.

Die ReGa Schnittstelle der CCU bietet zwei Methoden, auf den Wert eines Datenpunktes zuzugreifen. Mit VALUE() bekommt man den Wert, den ein Datenpunkt aktuell in der CCU hat. Dieser ist ggf. einige Sekunden oder Minuten alt.
Mit STATE() hingegen fragt die CCU explizit immer beim Gerät nach dem tatsächlichen Wert eines Datenpunktes. Dieser zusätzliche Kommunikationsschritt kostet Zeit und wirkt sich auf den Duty Cycle aus.

HMCCUCHN -- VALUE() --> CCU
HMCCUCHN -- STATE() --> CCU --> Gerät

Sofern man die RPC Devices nutzt, gibt es nur wenig Gründe, per get datapoint oder get update Werte direkt von der CCU zu holen.
2xCCU3 mit ca. 100 Aktoren, Sensoren
Entwicklung: FHEM auf Proxmox Debian VM
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: HMCCU, (Fully, AndroidDB)

martinp876

Hi, ich komme langsam voran. Ich befasse mich erst einmal aussschliesslich mit get kommandos und Darstellung da ich an meinem livesystem arbeite :)

klar kenne ich das Problem mit historschen Gegebenheiten... ;)

Das mit "Device" habe ich nun endlich auch gemerkt - danke.

Zum Kommando conficdesc: Mein Vorschlag ist in Zeile 7175 folgender Code
elsif ($method eq 'getParamsetDescription') {
my @operFlags = ('', 'R', 'W', 'RW', 'E', 'RE', 'WE', 'RWE');
foreach my $key (sort keys %$reqResult) {
$result .= $key.": "
                      ."\t["      .$operFlags[$reqResult->{$key}->{OPERATIONS}]."]"
                      ."\ttyp: "  .$reqResult->{$key}->{TYPE}
                      ."\trange: ".$reqResult->{$key}->{MIN}
                      ." - "      .$reqResult->{$key}->{MAX}
                      .(defined $reqResult->{$key}{VALUE_LIST}
                                ?"\n                 ".join("\n                 ",@{$reqResult->{$key}{VALUE_LIST}})
                                :"\tunit: " .$reqResult->{$key}->{UNIT})
                      ."\n"
                      ;
}
}


Das ist hier der erste Teil, da die Link kommandos noch fehlen.
Die Enums muss man permanent speichern um sie in allen Darstellungen einsetzen zu können.
Eigentlich ist das beim Booten durchzuziehen. Oder nach Bedarf bei der Anzeige...

martinp876

und 88_HMCCUCHN.pm zeile 573:
elsif ($opt eq 'configdesc') {
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par) && $par eq 'device') {
($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
}

my ($rc1, $result1) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef);
return HMCCU_SetError ($hash, $rc1, $result1) if ($rc1 < 0);
my ($rc2, $result2) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "LINK", undef);
return HMCCU_SetError ($hash, $rc2, $result2) if ($rc2 < 0);
return "MASTER:\n".$result1."LINK:\n".$result2;
}


Dann haben wir erst einmal (für Channel ;) ) die formale Beschreibung der Register abfragbar. Incl Grenzwerte und enums.

martinp876

so, und noch "ENUMs" die Dritte - habe einmal darüber geschlafen ;). Hier meine Herleitung:

- Sollen enums implementiert werden? => es gibt keine Alternative- ein Muss
- Welche enums? => alle. Es gibt welche für config und datapoints, values, links, master
- wie wird es implementiert?
  a) dynamisch abfragen, also bei Jeder nutzung die CCU befragen => lehne ich ab
  b) statisch speichern. Praktikabel ist, einen hash anzulegen welcher sukzesive befüllt wird. Nach jedem neustart. Für Maintenance können man ein kommando zum "neulesen" einführen. Das dauert aber noch
- Wo ist es zu speichern
  Es wird bei der Visualisierung benötigt, also in HMCCUCHN (DEV auch, ignoriere ich aber ;) ). Gefüllt wird es bei Instanziieren der Entity. Hier sollten alle fehlenden Enums gelesen werden.
  => ein Hash welcher global angelegt wird ist wohl notwendig. Angelegt sollte er von HMCCU werden. Genutzt von HMCCUCHN/DEV und gefüllt von RPC
- Nur enums? Wohl nicht. Das ist zu kurz gesprungen und wird uns irgendwann auf die Füsse fallen. Also gleich die "Description" speichern.
- Struktur des Hash
  * Im Prinzip wird es aussehen wie die Register in HMConfig. Ist ja auch das gleiche. Am Ende des Tages kannst du das gesamte Konzekt der Entity "Beschreibung" so aufsetzen. Deutlicher Vorteil zu HMConfig: Du kannst die Daten automatisch aus der CCU befüllen lassen
- Lebensdauer: Die Beschreibungsdaten ändern sich nur nach einem Update der CCU. Erweitert werden sie ggf. wenn ein neuer Typ von Device instanziiert wird. Dann sind dessen Daten aus der CCU abzufragen. => erst einmal reicht es, nach Neustart bei NULL anzufangen und bei jeden Define prüfen, ob das Device schon geladen ist.

Ich mache mir noch ein paar Gedanken


zap

Ich habe mittlerweile einige Deiner Anforderungen umgesetzt und im Test.

Das mit den enums verstehe ich nicht. Ja, es gibt sehr viele davon in der CCU, sowohl auf RPC- als auch auf Logikschicht-Ebene. Wozu werden die in FHEM benötigt? Hast Du ein Beispiel?

Der Befehl RPC Request "getParamsetDescription" und damit der Befehl get configdesc funktioniert nicht für jeden Gerätetyp. Von daher kann man sich nicht darauf verlassen. Manchmal liefert er auch falsche oder unvollständige Informationen. Daher habe ich diesen Befehl nur als Info implementiert, die helfen kann, die Bedeutung der Config-Parameter zu entschlüsseln, da diese bei EQ-3 leider nicht dokumentiert sind.
2xCCU3 mit ca. 100 Aktoren, Sensoren
Entwicklung: FHEM auf Proxmox Debian VM
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: HMCCU, (Fully, AndroidDB)

martinp876

Ich habe einmal etwas experimentiert - verstehe langsam besser, was schon implemenitert ist und was ich zumindest noch nicht gefunden haben.
Ideen und Vorstellungen habe ich viele. Sicher nicht alle sinnvoll :( . Aber wichtig hierbei ist,  das Konzept  und die gewünschte Architektur zu verstehen. Wäre einfach, wenn man sich ein Wochenende für das Diskussionen zeit nehmen würde.

Enums:
Mir nicht klar, was dir nicht klar ist ;).
1) enums sind m.E. wichtig, da es der für mich einzige Weg der Programmierung ist. So will ich die Werte (enums) für Register (und eigentich alles) aus der CCU sehen. So haben bspw die folgenden Register die angegebenen Namen als Werte. Genau diese will ich nutzen - zum Lesen und zun Schreiben
SHORT_ON_TIME_MODE:VALUE_LIST=ARRAY    ABSOLUTE,MINIMAL
SHORT_JT_REFON:VALUE_LISTNO_JUMP_IGNORE_COMMAND,ONDELAY,REFON,RAMPON,ON,OFFDELAY,REFOFF,RAMPOFF,OFF
2)Die Enums müssen zur Nutzung geholt oder gespeichert werden. Natürlich müssen sie immer erst einmal geholt (aus der CCU) werden. Das sollte man nur einmal machen. Dann in FHEM speichern und nutzen. Alles andere ist eine Performance-Kathastrophe aus meiner Sicht.
3) Nutzung der Enums für Register ist a) im Kommando, die Register-beschreibung auszugeben und b) die Registerwerte. In CUL_HM vergleichbar den Kommandos get regList und get regTable
4) neben den enums sind natürlich auch die anderen Beschreibungen der Register in regList auszugeben. Also min/max wert, und Einheit. Genauso wie Lese und Schreibbarkeit.

5) enums sind natürlich nicht auf Register beschränkt. Diese sind für alle Kommandos notwendig. Hier sind die "VALUES" tabellen interessant.

Du hast sicher meine Codebeispiele gesehen. Allerdings würde ich den Code wegen der von mir präferierten architekturänderungen so auf dauer nicht implementieren. Aktuell könntest du es einfach einbauen.

ZitatDer Befehl RPC Request "getParamsetDescription" und damit der Befehl get configdesc funktioniert nicht für jeden Gerätetyp.
Kann ich mir nicht vorstellen. Möglich, dass es keine Werte gibt. Kannst du mir 2-3 Beispiele nennen? Also die Modelle. Dann werde ich es prüfen. Die CCU arbeitet mit diesen Werten - bei Fehlern wüde ich für Fehlinterpretationen unserer Seits vermuten.
Die Bedeutung der Parameter ist in CUL_HM weitgehend dekodiert. Wo sind deine Probleme? Bisher kann ich es recht gut lesen.

==> Ich muss die Datenarchitektur deiner Module verstehen.

Übrigens: Die Aufteilung HMCCU und HMCCUCHN hätte ich mir bei CUL_HM auch gewünscht. Das ist super, hatte mich nie getraut, es umzustellen. Ich habe hmInfo als kleinen Ersatz. Einige der zentralen Funktionen hätte ich auch gerne in HMCCU

martinp876

Vielleicht habe ich dich aber nicht korrekt verstanden bezüglich der enum Frage. Noch ein paar Gedanken
Für die Beschreibung der Devices und Funktionalitäten würde ich ein ( oder mehrere) hashes anlegen, welche von HMCCU befüllt werden und von HMCCUCHN genutzt werden. HMCCUDEV wenn du es willst -interessiert mich nicht.

Wenn HMCCUCHN definiert wird muss geprüft werden
? ist die Seriennummer schon instanziiert (hier ist es ja nur ein kanal). 
    => nein : führe "getDeviceDescription" aus.


Hier bekomme ich die Info, welche  wie folgt abzulegen ist
  - DevDef{HM-LC-Dim1TPBU-FM}{AVAILABLE_FIRMWARE}=2.9
     DevDef{HM-LC-Dim1TPBU-FM}{UPDATABLE}=1
     DevDef{HM-LC-Dim1TPBU-FM}{RX_MODE}=1
     DevDef{HM-LC-Dim1TPBU-FM}{FLAGS}=1
     DevDef{HM-LC-Dim1TPBU-FM}{PARAMSETS}=("MASTER")
     
     DevDef{HM-LC-Dim1TPBU-FM}{CHILDREN}{CNT}=4                            # count of children incl MAINTENANCE channel
     DevDef{HM-LC-Dim1TPBU-FM}{CHILDREN}{DEF}{0}{TYPE}="MAINTENANCE"       # definition of channel 0 MEINTENANCE
     DevDef{HM-LC-Dim1TPBU-FM}{CHILDREN}{DEF}{1}{TYPE}="DIMMER"       # definition of channel 1   
     DevDef{HM-LC-Dim1TPBU-FM}{CHILDREN}{DEF}{2}{TYPE}="VIRTUAL_DIMMER"       # definition of channel 2
     DevDef{HM-LC-Dim1TPBU-FM}{CHILDREN}{DEF}{3}{TYPE}="VIRTUAL_DIMMER"       # definition of channel 2

     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{MAINTENANCE}{PARAMSETS}=("MASTER","VALUES")   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{MAINTENANCE}{DIRECTION}=0   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{MAINTENANCE}{FLAGS}=3     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{MAINTENANCE}{LINK_SOURCE_ROLES}=""     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{MAINTENANCE}{LINK_TARGET_ROLES}=""     

     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{DIMMER}{PARAMSETS}=("MASTER","VALUES","LINK")   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{DIMMER}{DIRECTION}=2   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{DIMMER}{FLAGS}=1     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{DIMMER}{LINK_SOURCE_ROLES}=""     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{DIMMER}{LINK_TARGET_ROLES}="SWITCH WCS_TIPTRONIC_SENSOR WEATHER_CS"     
     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{VIRTUAL_DIMMER}{PARAMSETS}=("MASTER","VALUES","LINK")   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{VIRTUAL_DIMMER}{DIRECTION}=2   
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{VIRTUAL_DIMMER}{FLAGS}=1     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{VIRTUAL_DIMMER}{LINK_SOURCE_ROLES}=""     
     DevDef{HM-LC-Dim1TPBU-FM}{ChDef}{VIRTUAL_DIMMER}{LINK_TARGET_ROLES}="SWITCH WCS_TIPTRONIC_SENSOR WEATHER_CS"     


Das Dynamische Hash ist dann jeder Entity entsprechend zuzuordnen und tyisch in "helper" anzulegen
    $def{entityname}{helper}{defInfo}{AES_ACTIVE}=[0/1]
   
    Und im Kanal 0 kommt die Device Information zum Tragen:
    $def{entityname}{helper}{defInfo}{dev}{ADDRESS}="IEQ0545891"
    $def{entityname}{helper}{defInfo}{dev}{FIRMWARE}="2.1"
    $def{entityname}{helper}{defInfo}{dev}{INTERFACE}="KEQ1038237"
    $def{entityname}{helper}{defInfo}{dev}{RF_ADDRESS}="1617137"
   

Wenn du also die erste Entity des Models HM-LC-Dim1TPBU-FM instanziierst wird der Hash gefüllt. Beim 2. Mal ist das erledigt, die Daten sind unveränderlich.
Leider sehe ich keine Zusammenfassung, so dass mehrere Models den selben Hash nutzen könnten. Wäre möglich, gibt eq3 nicht her.
Danach sind die ParameterSetDescriptions zu holen und zu cachen. Auch diese sind unveränderlich.

Danach werden die getParamsetDescription ausgewertet. Beim Erstellen des obigen Hash (also wenn er noch nicht existiert) werden die Parameter Beschreibungen gelesen. MASTER und LINK beschreiben Register, werden also im selben Hash gespeichert
bspw

{reg}{SHORT_ON_TIME_MODE}{DEFAULT}=0
  {reg}{SHORT_ON_TIME_MODE}{FLAGS}=1
  {reg}{SHORT_ON_TIME_MODE}{MAX}=1
  {reg}{SHORT_ON_TIME_MODE}{MIN}=0
  {reg}{SHORT_ON_TIME_MODE}{OPERATIONS}=3
  {reg}{SHORT_ON_TIME_MODE}{TAB_ORDER}=15
  {reg}{SHORT_ON_TIME_MODE}{TYPE}=ENUM
  {reg}{SHORT_ON_TIME_MODE}{UNIT}=""
  {reg}{SHORT_ON_TIME_MODE}{VALUE_LIST}=("ABSOLUTE","MINIMAL")



bei VALUES ... kann man eigentlich identisch verfahren und es im gleichen Hash ablegen.

zap

#12
Ok, hab's verstanden. HMCCU legt bereits jetzt eine ganze Menge Infos unter

$hash->{hmccu}

ab. Auch Gerätetyp spezifische Infos. Diese Struktur wäre dann um die enums und weitere Infos zu ergänzen. Das Konzept, wie diese Daten ermittelt werden, folgt aber einem komplett anderen Ansatz. Ein Großteil der Infos wird von einem (einzigen) Homematic Script abgefragt. Gegenüber der von Dir vorgeschlagenen RPC Methode hat das den großen Vorteil, dass alle Infos mit einem einzigen Http Request abgefragt werden können. Bei der RPC Methode brauche ich je Device mindestens 4 Request (getParamsetDesc für MASTER, VALUE und LINK + getDeviceDesc). Da wird zumindest die CCU2 ziemlich schnell ziemlich dicke Backen machen. Je Device, weil sich die paramsets je nach Firmwarestand eines Geräts unterscheiden können.

Einige Infos gibt es gar nicht auf RPC Ebene. Die müsste ich noch zusätzlich per HM Script holen. Ich kann das mal testen mit meiner CCU3. Wenn es da schon zu Timeouts kommt, funktioniert es auf der CCU2 sowieso nicht.

Einige CCU Erweiterungen wie HUE, HVL etc. bieten nicht mal RPC Schnittstellen an. Oder sie implementieren Methoden wie getParamsetDesc nicht (CuXD sowei ich weiß). Wie es bei Wired oder HmIP Wired aussieht, weiß ich auch nicht, da ich es nicht verwende.

Zur Zeit arbeite ich an der Version 4.4. Das ist erst mal als "Aufräumrelease" gedacht, bei dem ich einiges rauswerfe, was veraltet, historisch gewachsen oder einfach überflüssig ist. Allerdings werden schon einige Verbesserungen hinsichtlich Abfrage von CCU Infos enthalten sein.

Kommt die Tage ...
2xCCU3 mit ca. 100 Aktoren, Sensoren
Entwicklung: FHEM auf Proxmox Debian VM
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: HMCCU, (Fully, AndroidDB)

martinp876

Bin schon gespannt. Ich habe mit meiner CCU2 einmal gespielt.
Ziel ist es, die Register und Enums "einzulagern" welche für das jeweilige Device interessant, also definiert sind.
Mit der Routine unten klappt das und ist so geordnet, wie ich es mir vorstelle. Man kann es verkürzen, wenn die enthaltenen entity spezifischen Daten separat abgefragt werden (macht m.E. sinn).
Es kostet 0 Zeit, wenn bspw der Wert ccutype auf vorhanden sein in $HMCCU_DevDef überprüft wird. Die Implementierung hängt von den Ablauf der Definition der Entity ab.

Aber wenn du alles auf einen Rutsch bekommst ist es effizienter.

Weiter habe ich bei den ersten Kommandos welche ich probiert habe festgestellt, dass man die Nummern der Devices eingeben muss um ein Resultat zu erhalten.
Also
Zitatget HMccu deviceinfo <serialnumber>
Das sollte nie der Fall sein. Wir haben Namen für die Devices. Allerdings würde ich das Kommando "get deviceinfo" in der HMCCU schlicht löschen. Das kanna man in der channel-entity ausführen.
Und wo wir bei deviceinfo sind:

Ich bekommen
ZitatCHN 0001D7098D99DC:0 HCCpsm1:0
  DPT {f} HmIP-RF.0001D7098D99DC:0.ACTUAL_TEMPERATURE = 0.000000 [RE]
  DPT {b} HmIP-RF.0001D7098D99DC:0.CONFIG_PENDING = false [RE]
  DPT {b} HmIP-RF.0001D7098D99DC:0.DUTY_CYCLE = false [RE]
  DPT {n} HmIP-RF.0001D7098D99DC:0.ERROR_CODE = 0 [RE]
.....
CHN 0001D7098D99DC:1 HCCpsm1Btn
  DPT {b} HmIP-RF.0001D7098D99DC:1.PRESS_LONG =  [E]
  DPT {b} HmIP-RF.0001D7098D99DC:1.PRESS_SHORT =  [E]

Ich will es komprimierter - und nur die Daten dieses Kanals
Zitat
CHN 0001D7098D99DC:0 HCCpsm1:0
  [RE] ACTUAL_TEMPERATURE = 0.000000
  [RE] CONFIG_PENDING = false
  [RE] DUTY_CYCLE = false
  [RE] ERROR_CODE = 0
.....
Wobei eine Methode die aktellen Werte und eine die Möglichkeiten ( min/max/unit/enums) darstellen sollte. 

Ich warte auf deinen neuen code - zum Ausprobieren.  :)

Routine nur für BidCos....
sub HMCCU_getDeviceDefs ($)
{
my ($name)  = @_;  # address of the entity - i.e. the serial number
my $hash    = $defs{$name}; 
my $DefAddr = $hash->{DEF};  # address of the entity - i.e. the serial number
    my ($Serial) = split(":",$DefAddr); #separate the serial number
my $hmccu_hash = HMCCU_GetHash ($hash);#
    my $rpchash = $defs{$hmccu_hash->{hmccu}{interfaces}{"BidCos-RF"}{device}};
    my $res="";
   
    my $res =HMCCURPCPROC_SendRequest ($rpchash,"getDeviceDescription", $Serial , "MASTER");
    my $model = $res->{TYPE};
    my $justEntitiesData = defined $HMCCU_DevDef{$model}?1:0; # we also need dynamic data. To be implemented
    foreach my $k (keys %$res) {
      if ($k =~ m/(ADDRESS|INTERFACE|FIRMWARE)/){## todo: add this to dynamic data
        next;
        }
      elsif ($k =~ m/(TYPE|VERSION|PARENT)/ ||
             $justEntitiesData){
        next;
        }
      elsif($k eq "CHILDREN"){
        $HMCCU_DevDef{$model}{$k} = scalar @{$res->{$k}};
        }
      elsif($k eq "PARAMSETS"){
        @{$HMCCU_DevDef{$model}{$k}} = @{$res->{$k}};     
        }
      else{
        $HMCCU_DevDef{$model}{$k} = $res->{$k};
        }
      }
    for (my $ch = 0;$ch < $HMCCU_DevDef{$model}{CHILDREN};$ch++){
      $res = HMCCURPCPROC_SendRequest ($rpchash,"getDeviceDescription", $Serial.":".$ch , "MASTER");
      my $Type = $res->{TYPE}; # this is the type of channel for this device
      my $justChanDedData = defined $HMCCU_DevDef{$model}{ChDef} && defined $HMCCU_DevDef{$model}{ChDef}{$Type} ? 1 : 0;
      foreach my $k (keys %$res) {
        #AES_ACTIVE=0
        if ($k =~ m/(AES)/){## todo: add this to dynamic data
          next;
          }
        elsif ($justChanDedData ||
               $k =~ m/(TYPE|VERSION|ADDRESS|PARENT|INDEX)/){## todo: add this to dynamic data
          next;
          }
        elsif($k eq "PARAMSETS"){
          @{$HMCCU_DevDef{$model}{ChDef}{$Type}{$k}} = @{$res->{$k}};     
          }
        else{
          $HMCCU_DevDef{$model}{ChDef}{$Type}{$k} = $res->{$k};
          }
        }
      next if ($justChanDedData); # no parameter description - we alrady have it
      foreach my $k (@{$HMCCU_DevDef{$model}{ChDef}{$Type}{PARAMSETS}}) { # foreach paramset
        my $res2 = HMCCURPCPROC_SendRequest ($rpchash,"getParamsetDescription", $Serial.":".$ch,$k  );
        foreach my $var (keys %$res2){
          foreach my $varAttr (keys %{$res2->{$var}}){
            if ($varAttr =~ m/(ID)/){
              next;
              }
            elsif($var eq "SPECIAL"){
              #todo: have to implement this.       
              }
            elsif($var eq "VALUE_LIST"){
              @{$HMCCU_ParamDesc{$var}{$k}} = @{$res->{$k}};     
              }
            else{
              $HMCCU_ParamDesc{$var}{$k} = $res->{$k};
              }
            }
          }
        }
      }
}

martinp876

Und ein weiteres Thema (sorry, dich zu überfluten, meine ungedult ;) )

Es geht um die Synchronisation der Entites. Die CCU hat einiges mehr, hier erst einmal die physikalischen Geräte:
Meine Philosophie
- Nutze ich FHEM will ich alle (ALLE) Geräte der CCU in FHEM sehen. Ich denke (nein, ich weiss) man kann auch das Pairen in FHEM bewerkstellgen - lasse ich aussen vor. Reicht wenn ich vorerst in der CCU paire. Dann aber muss alles nach FHEM gespiegelt werden. Semi-Automatisch. Das Kommando muss einfach sein - was in FHEM heisst: nur ein (EIN!) parameter. keine Filter! (ich hatte in hmInfo auch Filter - mittlerweile gibt es die Kommandos "simplified")
-> Ich stelle mir also ein Kommando vor
Zitat- get/set HMccu deviceList [verify|createDev|createChn|update]
      * das Verify prüft, ob CCU-entites in FHEM existieren. Da du sicher nicht von HMCCUDEV ablassen willst musst du es "smart"  implementieren:
          a) die Liste aller CCU entites wird gelesen. Bspw ein listDevices mit grep auf die Adressen.
          b) prüfen welche Adressen in FHEM instanziiert sind. Sollte HMCCUDEV existieren sind alle Kanäle abgedeckt. Existieren HMCCUCHN entites sind alle Kanäle einzeln zu verifizieren
          c) Ausnahme: Die 50 (virtuellen) Kanäle der Zentrale würde ich ausklammern
          d) Ausgegeben wird die Unterschiedsliste. Entites welche in FHEM, nicht aber in der CCU und umgekehrt existieren
       * createDev: alle fehlenden Devices werden als HMCCUDEV creiert. Keine weiteren optionen. Alles was noch notwendig ist kommt nachher, incl der (smarten) Namensvergabe
       * createChn: alle fehlenden channeld werden als HMCCUCHN creiert. Keine weiteren optionen. Alles was noch notwendig ist kommt nachher.
         - Ein Kommando deviceRename wie in CUL_HM wäre praktisch. Hier werden alle Kanäle eines Device umbeannnt - also Devicename.channelextention
          - Der kanal 0 (maintenance) beinhaltet auch die allgemeinen Device-Informationen und Readings. Macht sinn, da es diese immer gibt und er sowieso "zentral" ist.
       * update: alle "existierenden!" DEV/CHN erfahren einen Update. Will sagen die Konfigurations-attribute (readings) werden mit der CCU abgeglichen. Verify sollte hier auch unterschiede/abweichungen anzeigen
+ Das Kommando lösche keine FHEM instanzen,macht der User nach "verify" manuell
+ Das erstellen der Entites erfolgt nach best-guess. Also alles was du meinst, dass Sinn macht - aber keine User Optionen.
+ Das Kommando sollte sich explizit und ausschliesslich auf Description-daten beziehen(siehe unten). Operationelle/Config Daten müssen mit anderen Kommandos abgedekt werden
bezogen auf das obige Kommando müssen wir wieder einmal definitionen vereinbaren

  • Kanal: eine CHN entity. Kanal 0 beinhaltet auch das Device und dessen Information. Kanal 0 wäre in CUL_HM das Device
  • Device: eine DEV entity. Allerdings
  • Description: Beschreibung einer entity welche unveränderlich ist. Bspw der Typ, die Adresse, die RF Adresse, die Anzahl der Kanäle,... Bisher habe ich dies so nicht genutzt, sollte man aber
  • Configuration: die permanenten/remanenten Daten  welche im Geräte geflasht werden. Das sind erst einmal register und peerings.
  • OperDate: alle dynamischen Daten wie on/off/level oder temperatur gemessen/gesetzt/helligkeit,....

Wäre cool wenn du eine Liste der Definitionen pflegen könntest. Aus meiner Sicht ist das immer die Basis einer Diskussion - aber auch meines Denkens. Hilft mir selbst und anderen.

P.S. in CUL_HM musste ich nicht zwischen Description und Config unterschieden. Der Unterschied bei CCU ist die CCU. Du hast eine weitere Zwischen- Instanz welche Änderungen vornehmen kann. Somit würde ich hier unbedingt eine Unterscheidung vornehmen.
P.S. natürlich werde ich am Ende ein Kommando erwarten, welche alles mit einem Click prüft (hmInfo checkConfig). Aber erst einmal braucht man es getrennt
P.S. wäre schön, wenn man sich in Teilen an CUL_HM anlehnen könnte. Erst einmal halte ich das Kozept für ... zumindest ok. Weiter kann man den Umstieg vereinfachen, wenn sich die User wiederfinden.
Mir ist seit den Erscheinen der ersten HM-IP devices klar, dass CUL_HM ein Auslaufmodell ist.