[ModBusAttr] Werte schreiben als Text ?

Begonnen von cotecmania, 24 März 2020, 10:26:29

Vorheriges Thema - Nächstes Thema

cotecmania

Hallo,

Ich betreibe meinen Solarladeregler LS2024B seit Jahren und er läuft zuverlässig, Werte werden gelesen.
Ich schaffe es aber nicht, die RealTimeClock (RTC) auf dem Gerät zu setzen.
Der Wert z.B. RTC2 ist so definiert und wird korrekt gelesen :


obj-h36884-expr   sprintf("%02d %02d", ($val & 0xff), ($val >> 8) )
obj-h36884-format   %s
obj-h36884-polldelay   x12
obj-h36884-reading   RTC2
obj-h36884-set 1


RTC2 wird z.B. so richtig als reading angezeigt : 16 22

Wenn ich den Wert nun setzen will bekomme ich Fehlermeldungen.
set LS2024B RTC2 17 25  -> Set Value 17 25 is not numeric and textArg not specified
set LS2024B RTC2 1         -> Error code 04 / slave device failure

Das steht in der Doku zum Gerät :
D2 Real time clock 9014
03(read)10(write) D7-0 Hour, D15-8 Day

Das im Log, wenn ich es mit dem Wert 1 teste :
2020.03.24 10:23:20 5: LS2024B: UpdateSetList: setList=interval reread:noArg reconnect:noArg stop:noArg start:noArg close:noArg saveAsModule scanModbusId scanStop:noArg scanModbusObjects Batterie_Typ:User,AGM,Gel,Saeure RTC2 Last_Modus:manuell,nachts,nachts+timer,timer
2020.03.24 10:23:20 5: LS2024B: UpdateSetList: getList=
2020.03.24 10:23:27 5: LS2024B: set called with RTC2 (h36884) setVal = 1
2020.03.24 10:23:27 5: LS2024B: GetSetChecks with force
2020.03.24 10:23:27 5: LS2024B: GetSetChecks returns success
2020.03.24 10:23:27 5: LS2024B: set packed hex 31 with n to hex 0001
2020.03.24 10:23:27 4: LS2024B: DoRequest called from Set created request: id 1, fCode 16, type h, adr 36884, len 1, value 0001 for device LS2024B reading RTC2 (set RTC2), read buffer empty
2020.03.24 10:23:42 5: LS2024B: attr change set updateGetSetList to 1


Wie kann ich den Wert korrekt setzen ?

PS: Einfache Integerwerte wie 0/1 für einen anderen Wert funktionieren

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Hallo Joe,

mit dem Attribut obj-h36884-expr definierst Du wie man von dem 16-Bit Wert im Holding-Register 36884 zu einem Text kommt.
Wenn Du nun einen eingegebenen Text im richtigen Format in das Register schreiben möchtest, dann musst Du den umgekehrten Weg auch definieren.
In der Doku findest Du dazu:

obj-[cdih][1-9][0-9]*-setexpr
    defines a perl expression that converts the user specified value in a set to a raw value that can be sent to the device. This is typically the inversion of -expr above.

Zudem musst Du dem Modul noch beibringen, dass es nach dem Set-Befehl einen String (zwei Zahlen mit Space dazwischen) akzeptieren soll. Die Lösung dafür steht aber schon in der Fehlermeldung drin: textArg.

obj-h36884-textArg 1

Dann kann die setExpr den String zerlegen und daraus eine passende 16-Bit-Zahl machen.

Dann musst Du ggf. noch dafür sorgen, dass mit function code 16 (Hex 10 in Deiner Doku) geschrieben wird und nicht mit 6.

dev-([cdih]-)*write
specifies the function code to use for writing this type of object. The default is 6 for holding registers and 5 for coils. Discrete inputs and input registers can not be written by definition.


Ich hoffe das hilft Dir weiter.

Gruss
   Stefan

cotecmania

Hallo Stefan,

Danke für die Ausführungen. Das mit der Textformatierung habe ich verstanden, allerdings finde ich in der Commandref keine Beschreibung zu "textArg"

Um den Problemen mit dem Stringhandling erstmal aus dem Wege zu gehen, wollte ich einfach mal einen Integer-Wert schreiben z.B. 1 was ja auch nicht funktioniert.
Fehler : Error code 04 / slave device failure
Siehe auch noch mal meinen LOG-Auszug von oben

dev-h-write passt schon mit 16. In der Doku war das wohl ein Hex-Wert 0x10

Diesen Wert hier kann ich problemlos schreiben mit 0 oder 1:

obj-h36970-reading Last_EinAus
obj-h36970-set 1


Warum RTC2 nicht ?

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

cotecmania

Hallo nochmals,

Das Problem war, dass die RealTimeClock nur auf einmal beschrieben werden darf, d.h. alle 3 Register müssen mit einem Write beschrieben werden.

Die 3 Bytes auf einmal zu lesen und zu formatieren habe ich geschafft, aber wie sieht das "setexpr" aus, um die Uhrzeit setzen zu können ?

Also die "inversion" zu folgendem ?
obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d",(($val[1]>>8), $val[2] & 0xff), ($val[2] >> 8), ($val[1] & 0xff) , ($val[0] >> 8),($val[0] & 0xff) )
ergibt
25.03.2020 11:12:08


Gruss und Danke
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Bitte poste doch erst mal Deine Konfiguration (unpack, len etc.), da das ja zusammen passen muss.

Ich könnte mir vorstellen, dass es am einfachsten ist, in den Expressions von / zu Hex-Strings zu arbeiten und den unpack- / pack-code als H* zu setzen.
Vermutlich ist das aber Geschmackssache ;-)

Gruss
   Stefan

cotecmania


   obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d",(($val[1]>>8), $val[2] & 0xff), ($val[2] >> 8), ($val[1] & 0xff) , ($val[0] >> 8),($val[0] & 0xff) )
   obj-h36883-len 3
   obj-h36883-reading RTC
   obj-h36883-set 1
   obj-h36883-textArg 1
   obj-h36883-unpack s>s>s>
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Die Herausforderung ist jetzt dass s>s>s> zwar praktisch für das Lesen ist, aber beim Schreiben so nicht funktioniert, da Du beim Set eben nur einen Wert übergeben kannst bzw. die Expression auch nur einen Wert zurückgibt.
Wenn Du aber als unpack-Code so etwas wie "HHHHHHHHHHHH" verwendest, dann bekommst Du in der Expr beim Lesen einen Hex-String, den Du auch gut byteweise auseinandernehmen kannst und beim Schreiben kann Deine setExpr ebenfalls einen Hex-String zusammenbauen.

Gruss
   Stefan

cotecmania

Hallo Stefan,

"HHHHHHHHHHHH" funktioniert nicht.
Ich habe leider nix mit perl am Hut aber nach etwas googeln  fand ich raus, dass unpack mit "H*" folgendes Ergebnis liefert : 042c19151403
Das sind die 6 Bytes, die die Zeitinformation beinhaltet.
Diese Bytefolge kann ich auch direkt wieder mit neuen Werten auf den Laderegler schreiben.
So weit so gut.
Nur will ich das Ganze ja menschlich lesbar :

Das ist somit meine expr:
sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
und erzeugt, wie gewünscht so etwas : 25.03.2020 22:59:55

Morgen muss ich schauen, wie ich das wieder in eine Bytefolge (mit setexpr) bringe und dann muesste das Schreiben ja funktionieren.
Ob es der effektivste Weg ist, bezweifle ich ...

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

laserrichi

Hi Jo,
bist du da schon weitergekommen ? wie sieht jetzt dein reading aus ?
Ich habe gerade gesehen das mein Laderegler ja die gleichen register hat und ich auch bisher gescheitert bin die Zeit zu setzen.
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

springber

Hallo,

ich habe auch meinen Solarladeregler LS2024B mit ModbusAttr eingebunden. Ich habe keine Möglichkeit gefunden über setexpr das Datum vom Format "TT.MM.YYYY HH:MM:SS" in HEX umzuwandeln. Beim Versuch eine perlfunktion (99_myUtils.pm) einzugeben gab es immer Fehlermeldungen und das hat nicht funktioniert. Die Perfunktion funktioniert und der daraus berechnete HHHHHHHHHHHH Wert kann auch in set <DEVICE> RTC HHHHHHHHHHHH eingegeben werden und die Uhr im LS2024B wird gesetzt. Aber ich kann nicht das Datum in Klartext "TT.MM.YYYY HH:MM:SS" eingeben.

Ich habe mir damit beholfen ein at Device anzulegen in dem eine Perl Funktion steht. In der Perl Funktion wird die aktuelle Systemzeit vom fhem System ermittelt und in das Format HHHHHHHHHHHH umgewandelt. Der HHHHHHHHHHHH Wert wird dann als fhem set <DEVICE> RTC HHHHHHHHHHHH ausgeführt. Ergebnis - die Uhr am Solarladeregler stimmt mit der fehm Systemzeit überein.

Die raw DEF von dem at device ist:

defmod EPSOLAR_1_set_date_time at *01:01:01 {\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);;\
  #$sec = 00;;\
  #$min = 00;;\
  #$hour = 10;;\
  #$mday = 02;;\
  #$mon = 03;;\
  #$year=21;;\
  $year = $year-2000+1900;;\
  #print "Aktuelles Datum ist : $mday.$mon.$year $hour:$min:$sec\n\r\n\r";;\
  my $setvalue = sprintf("%02X", $min).sprintf("%02X", $sec);;\
  my $dezvalue = hex($setvalue);;\
  #print "Min\tSec\t$min\t$sec\t$setvalue\t$dezvalue\n\r";;\
  my $alles = $setvalue;;\
  $setvalue = sprintf("%02X", $mday).sprintf("%02X", $hour);;\
  $dezvalue = hex($setvalue);;\
  #print "Day\tHour\t$mday\t$hour\t$setvalue\t$dezvalue\n\r";;\
  $alles = $alles.$setvalue;;\
  $setvalue = sprintf("%02X", $year).sprintf("%02X", $mon);;\
  $dezvalue = hex($setvalue);;\
  #print "Year\tMonth\t$year\t$mon\t$setvalue\t$dezvalue\n\r";;  \
  $alles = $alles.$setvalue;;\
  #print "Alles in HEX:\t$alles\n\r";;\
  Log 1, "set EPSOLAR_1 RTC $mday.$mon.$year $hour:$min:$sec in HEX: $alles";;\
  fhem("set EPSOLAR_1 RTC $alles");;\
}


Die Definition RTC im Device für den Solarladeregler LS2024B ist:

attr EPSOLAR_1 obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
attr EPSOLAR_1 obj-h36883-len 3
attr EPSOLAR_1 obj-h36883-poll 1
attr EPSOLAR_1 obj-h36883-polldelay X1
attr EPSOLAR_1 obj-h36883-reading RTC
attr EPSOLAR_1 obj-h36883-set 1
attr EPSOLAR_1 obj-h36883-setexpr $val
attr EPSOLAR_1 obj-h36883-showGet 1
attr EPSOLAR_1 obj-h36883-textArg 1
attr EPSOLAR_1 obj-h36883-unpack H*

laserrichi

ui es bewegt sich etwas :-)

habe das mal probiert aber bekomme fehler: Global symbol "$setvalue" requires explicit package name

wobei ich das jetzt noch kein setexpr mal eingebaut hatte, ich hab bei mir ja das modul gebastelt für meinen Solarlader.

Kann man das nicht in das eigene Modul dann evtl. einbauen ?

RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

springber

Und es geht doch   :) :)

wenn man bei setexpr einen einzeiler macht ist der zwar ziemlich lang aber es geht. Also habe ich das geändert und kann Datum und Zeit vom Solarlader über set ändern. Das Eingabeformat für das set ist wie das reading TT.MM.YYYY hh.mm.ss also z.B. 02.02.2021 12:04:36. Zu beachten ist, die Zahlen müssen immer 2 (oder 4) Stellig sein - also 3.2.21 12:4:56 geht nicht - aber 03.02.2021 12:04:56 schon.  :)

Das at Device musste ich natürlich auch wieder anpassen, so dass der set DEVICE RTC Befehl wieder mit TT.MM.YYYY hh.mm.ss ausgeführt wird.

attr EPSOLAR_1 obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
attr EPSOLAR_1 obj-h36883-len 3
attr EPSOLAR_1 obj-h36883-poll 1
attr EPSOLAR_1 obj-h36883-polldelay X1
attr EPSOLAR_1 obj-h36883-reading RTC
attr EPSOLAR_1 obj-h36883-set 1
attr EPSOLAR_1 obj-h36883-setexpr sprintf("%02X", substr($val,14,2)).sprintf("%02X", substr($val,17,2)).sprintf("%02X", substr($val,0,2)).sprintf("%02X", substr($val,11,2)).sprintf("%02X", substr($val,8,2)).sprintf("%02X", substr($val,3,2))
attr EPSOLAR_1 obj-h36883-showGet 1
attr EPSOLAR_1 obj-h36883-textArg 1
attr EPSOLAR_1 obj-h36883-unpack H*


Das at Device um die aktuelle Systemzeit an den Solarlader zu schicken:

defmod EPSOLAR_1_set_date_time at *01:01:01 {\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);;\
  #$sec = 00;;\
  #$min = 00;;\
  #$hour = 10;;\
  #$mday = 02;;\
  #$mon = 03;;\
  #$year=21;;\
  $year = $year+1900;;\
  #print "Aktuelles Datum ist : $mday.$mon.$year $hour:$min:$sec\n\r\n\r";;\
  my $alles = sprintf("%02d", $mday)."\.".sprintf("%02d", $mon)."\.".sprintf("%04d", $year)." ".sprintf("%02d", $hour).":".sprintf("%02d", $min).":".sprintf("%02d", $sec);;\
  Log 1, "set EPSOLAR_1 RTC $alles";;\
  fhem("set EPSOLAR_1 RTC $alles");;\
}

laserrichi

sehr cool ...  genau das ist DIE Lösung die ich lange gesucht hatte.
Ich habe es in mein Modul schon mal eingebaut und es funktioniert :-)
Werde dann noch ein paar andere Dinge weiter ausbauen und mein Modul 98_ModbusEPEVER.pm hier wieder aktualisieren.
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

StefanStrobel

Hallo,

wie genau sah denn Euer Versuch aus, es ohne "at" und direkt mit einer setExpr zu machen und was genau war die Fehlermeldung?
Eigentlich sollte das auch funktionieren.

Gruss
   Stefan

springber

Hallo,

meine ersten versuche waren in der setexr etwas zu definieren ähnlich wie in einem userReading - also {perlcode}. Da ist es so, dass der letzte Wert dann im Reading steht. In dem {Perlcode} kann ich dann auch ins Log schreiben, andere Werte setzen, eine Message zu schicken etc.

Das hat bei setexpr nicht funktioniert. Auch die Eingabe im Attribut so weit zu vereinfachen, indem ich nur eine Funktion und $val schreibe (Funktion($val)) und diese Funktion in99_myUtils.pm definieren hat nicht funktioniert (die Funktion hat mit return $neuerWert geendet) . Wenn ich in der Funktion Übergabewerte definiert habe (sub Funktion ($) {my ($Wert) = @_;) habe ich immer die Fehlermedlung im Log bekommen falsche Anzahl an Übergabeparameter. Ich habe verschiedenes probiert- ohne Erfolg.

Erst das Ganze als onliner direkt in setexpr hat dann geklappt.

(ich gebe zu, ich bin kein Freund von onlinern, Performance ist nicht mein Ziel ich habe es lieber runtergebrochen in kleine Schritte....)