Komplett überarbeitetes ECMD und ECMDDevice vom 16.3.2014

Begonnen von kpwg, 20 März 2014, 20:40:17

Vorheriges Thema - Nächstes Thema

kpwg

Hallo Boris, Hallo Forum,

Zuerst Vielen Dank für die lange gewünschte Überarbeitung des Moduls für alle Ethersex-Plattformen. Die Ankündigung und die Dateien dazu sind hier zu finden.

Seit zwei Abenden beschäftige ich mich damit, werde aber noch nicht so ganz schlau aus der neuen Syntax. Die Übernahme der ungeänderten alten classdef geht schief und FHEM hängt komplett. Tests sind also nur- wie schon beschrieben- nicht auf dem Produktivsystem durchzuführen.

Die Beispiele der classdef und zugehörige Abschnitte der fhem.cfg sollten wir hier sammeln, damit Andere es leichter haben, ihre Konfiguration anzupassen und das Modul auch nutzen zu können. Für die "im Stoff" stehenden Programmierer ist das sicher kein Ding und in 5 Minuten angepasst. Bin gerade noch dabei, meine classdef's anzupassen und die Beispiele nachzuvollziehen und zu testen.

Beispiel: Aus bisher
get value cmd {"adc get %channel\n"}
get value params channel
get value postproc { s/^(\d+)\n$/$1/;; $_ }


wird jetzt
get value cmd {"adc get %channel\n"}
get value params channel
get value expect "\d+\n"
get value postproc { s/^(\d+)\n$/$1/;; $_ }

In der dritten Zeile wird mit dem neuen expect mitgeteilt, das in diesem Fall eine ein- oder mehrstellige Zahl sowie ein newline erwartet wird.

Wie sehen eure classdefs aus?

Viele Grüße, Ricardo

Dr. Boris Neubert

#1
Eines von drei Knöpfchen drücken an einer Fernsteuerung (Ethersex auf AVR-NET-IO):



# these are the numbers of the buttons as hex chars from 0 to f;
params btnup btnstop btndown

# setter definitions for opening, stopping and closing the shutters
set up cmd {"io set ddr 2 ff\n\000io set port 2 1%btnup\n\000wait 1000\n\000io set port 2 00\n"}
set up expect ".+"
set up postproc { s/^OK\n\000?OK\n\000?OK\n\000?OK\n\000?$/up/; "$_" eq "up" ? undef : "error"; }
set stop cmd {"io set ddr 2 ff\n\000io set port 2 1%btnstop\n\000wait 1000\n\000io set port 2 00\n"}
set stop expect ".+"
set stop postproc { s/^OK\n\000?OK\n\000?OK\n\000?OK\n\000?$/stop/; "$_" eq "stop" ? undef : "error"; }
set down cmd {"io set ddr 2 ff\n\000io set port 2 1%btndown\n\000wait 1000\n\000io set port 2 00\n"}
set down expect ".+"
set down postproc { s/^OK\n\000?OK\n\000?OK\n\000?OK\n\000?$/down/; "$_" eq "down" ? undef : "error"; }


Ausgang ein- und ausschalten (NetServer/Pollin auf AVR-NET-IO):


# these are the numbers of the output pin from 1 to 8
params out
set on cmd { "setport %out.1\r\n" }
set on expect "^(ACK|NAK).*$"
set off cmd { "setport %out.0\r\n" }
set on expect "^(ACK|NAK).*$"
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

kpwg

#2
Heute habe ich die 1wire Sensoren getestet. Der Beitrag im Wiki erscheint mir zu "umständlich", da dort die Messung erst mit 1w convert angestoßen werden muss, was doch E6 bereits mit Polling selbst erledigen kann. Ich habe 30sec. gewählt. Der Code wird dadurch etwas einfacher.

1wire.classdef
# Uebergabeparameter Onewire Geräte ID
params devID
# Umsetzung in ECMD Befehle 1w get = Tempwert lesen
get temperature cmd {"1w get %devID\n"}
get temperature expect ".*"


In FHEM selbst zuerst wieder mit define dem Sensor einen Namen und die entsprechende 1wire-ID zuweisen.
Dann mit get <Sensorname> temperature die Messung aktualisieren. Der Wert ist im ungünstigsten Fall (bei mir) 30sec. "alt".
Ich habe "temperature" gewählt, damit das Reading einen identischen Namen wie alle Temperatur-Readings der anderen Sensoren besitzt.

Für eine zyklische Messung: Mit define Sensor_1_Messung at +*00:03 get Sensor_1 temperature
bekommt ihr dann alle 3 Minuten das reading aktualisiert.

Viel Spaß beim Testen, Ricardo


kpwg

Es geht schon wieder um 1wire-Temperatur-Sensoren. Die Überlegung ist, die 1w-Sensoren den states und readings anderer Sensoren weiter anzupassen. Dazu habe ich nun ein paar kleine Änderungen in der 1wire.classdef vorgenommen:
# Uebergabeparameter Onewire Geräte ID
params devID
# Umsetzung in ECMD Befehle 1w get = Tempwert lesen
get T: cmd {"1w get %devID\n"}
get T: expect ".*"

Damit kann ich nun mit T: identisch zu anderen Sensoren loggen, habe ein state mit T: <Temperatur> und ein reading T:. Nun fehlt noch das reading temperature, was ich zwar mit einem Notify als Userreading erstellen könnte, eleganter jedoch in der classdef mit
get T: postproc {\
my $hash  = $defs{%NAME};\
my $temperature = $1;\
\
readingsSingleUpdate($hash, "temperature", $temperature, 1);\
\
}
einmalig für alle DS1820 erstellen könnte.

Mir diesem postproc erhalte ich gar keine Messwerte, kein reading temperature, CHANGED bei den Internals wird gesetzt und das Log sieht so aus:
2014.03.22 10:15:31 3: NETIO_WZ: write "1w get 10008b7702080057\n", expect ".*"
2014.03.22 10:15:31 3: NETIO_WZ: read "20.4\n"
2014.03.22 10:15:31 3: NETIO_WZ: write "1w get 2890a5200500000b\n", expect ".*"
2014.03.22 10:15:31 3: NETIO_WZ: read "20.5\n"
2014.03.22 10:15:31 3: NETIO_WZ: write "1w get 284c8820050000a6\n", expect ".*"
2014.03.22 10:15:31 3: NETIO_WZ: read "20.4\n"
2014.03.22 10:15:31 3: NETIO_WZ: write "1w get 28521520050000b5\n", expect ".*"
2014.03.22 10:15:31 3: NETIO_WZ: read "20.5\n"
2014.03.22 10:15:31 3: Sensoren_Messung: T:
T:
T:
T:


Ohne den postproc-Teil erhalte ich wieder brauchbare Werte:
2014.03.22 10:18:16 3: NETIO_WZ: write "1w get 10008b7702080057\n", expect ".*"
2014.03.22 10:18:16 3: NETIO_WZ: read "20.4\n"
2014.03.22 10:18:16 3: NETIO_WZ: write "1w get 2890a5200500000b\n", expect ".*"
2014.03.22 10:18:16 3: NETIO_WZ: read "20.4\n"
2014.03.22 10:18:16 3: NETIO_WZ: write "1w get 284c8820050000a6\n", expect ".*"
2014.03.22 10:18:16 3: NETIO_WZ: read "20.4\n"
2014.03.22 10:18:16 3: NETIO_WZ: write "1w get 28521520050000b5\n", expect ".*"
2014.03.22 10:18:16 3: NETIO_WZ: read "20.5\n"
2014.03.22 10:18:16 3: Sensor_1_Messung: T: 20.4

T: 20.4

T: 20.4

T: 20.5

Die überzähligen Zeilenumbrüche sollten kein Problem darstellen...  8)

Hat jemand eine Idee?

Viele Grüße, Ricardo


Dr. Boris Neubert

Zitat von: kpwg am 22 März 2014, 10:27:21
get T: postproc {\
my $hash  = $defs{%NAME};\
my $temperature = $1;\
\
readingsSingleUpdate($hash, "temperature", $temperature, 1);\
\
}


Der Postprocessor operiert auf $_. Probier mal $_ statt $1. Ein eingestreuseltes Log3 $hash,1,$_ hilft vielleicht bei der Fehlersuche.

Grüße
Boris

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

kpwg

Da hast Du natürlich Recht. Es funktioniert! Habe die readings nun passend gemacht:
# Uebergabeparameter Onewire Geräte ID
params devID
# Umsetzung in ECMD Befehle 1w get = Tempwert lesen
get T: cmd {"1w get %devID\n"}
get T: expect ".*"
get T: postproc {\
my $hash  = $defs{%NAME};\
my $temperature = $_;\
\
readingsSingleUpdate($hash, "temperature", $temperature, 1);\
readingsSingleUpdate($hash, "T:", $temperature, 1);\
readingsSingleUpdate($hash, "state", $temperature, 1);\
\
}


Damit sieht das jetzt so aus:
(http://abload.de/img/1wire_messungzsfvy.jpg)

Viele Grüße, Ricardo

tpm88

Hallo Ricardo,

deine Lösung für 1wire Temperaturen ist sehr sauber - gefällt mir gut.

Zitat von: kpwg am 21 März 2014, 20:16:35
Der Beitrag im Wiki erscheint mir zu "umständlich", da dort die Messung erst mit 1w convert angestoßen werden muss, was doch E6 bereits mit Polling selbst erledigen kann. Ich habe 30sec. gewählt. Der Code wird dadurch etwas einfacher.

Kannst Du das ein wenig näher erklären? Muss man das Polling mit E6 bereits beim Kompilieren von Ethersex einstellen? Wo wird das Polling-Intervall gewählt?

Gruss
Tobias
Test FHEM Server on RPi, CUL_HM
Prod FHEM Server on Odroid HC1, HM-USB, JeeLink
Devices: diverse HM, IT1500, 1wire, LaCrosse, MQTT

Tom_S

#7
hallo,

so.. habe jetzt die 2. Version noch mal getestet. Alles was mit der alten Version ging funktioniert auch wieder. Allerdings musste ich die classdef's anpassen. Hauptsächlich wegen "\n" und "\000". Soweit oK.

Was ich noch nicht Verstanden habe ist die Funktion
  reading <reading> match "<regex>"

Ich habe bis jetzt mit der geänderten Version von Ulli mit der recv Funktion gearbeitet. Wenn ich es richtig verstanden habe soll das ähnlich funktionieren? Wenn das so ist, wäre ich für ein Beispiel dankbar.

Bis jetzt funktioniert es so:
bei Änderung des Zustands eines Ein oder Ausgang sendet der Controller von sich aus zB. "Port 2 3 1".  Port ist zum erkennen, 2 wäre dann Port C, 3 das 4. Pin und 1 für high.
Das Device ist so definiert
define PORT91C3 ECMDDevice ECMD91A 2 3
Die classdef sieht dafür so aus
params port pin
recv on cmd {"port %port %pin 1"}
recv off cmd {"port %port %pin 0"}

vielen Dank und LG


RaspberryPI2 + pilight, 3x AVR-NetIO, LW12, LW12HX, LW12FC; MAX-Lan, ESP8266, Arduino, H801, Neopixel, Solaredge, Modbus

Dr. Boris Neubert

Zitat von: Tom_S am 22 März 2014, 18:17:59
Wenn das so ist, wäre ich für ein Beispiel dankbar.

Was ist am Beispiel aus der commandref.html in meinem Post im Developer-Board nicht verständlich?

Zitat
Bis jetzt funktioniert es so:
bei Änderung des Zustands eines Ein oder Ausgang sendet der Controller von sich aus zB. "Port 2 3 1".  Port ist zum erkennen, 2 wäre dann Port C, 3 das 4. Pin und 1 für high.

Deine Definition könnte so aussehen:


reading on match "^port 2 3 1\n$"
reading off match "^port 2 3 0\n$"


Ob da Newlines dahinter sind, mußt Du selbst herausfinden anhand des Logs. attr PORT91C3 logTraffic 3 ist Dein Freund.

In der aktuellen Version werden die %-Parameter im Match nicht ersetzt. Das könnte eine sinnvolle Erweiterung werden.

Viele Grüße
Boris

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

kpwg

#9
Zitat von: tpm88 am 22 März 2014, 18:08:55
Hallo Ricardo,

deine Lösung für 1wire Temperaturen ist sehr sauber - gefällt mir gut.

Kannst Du das ein wenig näher erklären? Muss man das Polling mit E6 bereits beim Kompilieren von Ethersex einstellen? Wo wird das Polling-Intervall gewählt?

Gruss
Tobias

Hallo Tobias,

Danke für die Blumen! Das Polling habe ich bereits beim kompilieren ausgewählt. Die 600sec bzw 30sec sind voreingestellt.
(http://abload.de/img/1wire_menuconfigdqd4y.jpg)
Der convert Befehl und die Pause werden somit überflüssig. Allerdings wird 1w convert weiterhin mit OK bestätigt, so das vorhandener Code ohne Fehler funktioniert. Meines Wissens erfolgt bei Polling intern keine Auswertung von convert.

Viele Grüße, Ricardo

Dr. Boris Neubert

Zitat von: Tom_S am 22 März 2014, 18:17:59
so.. habe jetzt die 2. Version noch mal getestet. Alles was mit der alten Version ging funktioniert auch wieder. Allerdings musste ich die classdef's anpassen. Hauptsächlich wegen "\n" und "\000". Soweit oK.

Ich grübele derzeit darüber, ob die zwischen den Antworten eingefügten \000 wirklich sinnvoll/hilfreich sind. Zumindest in meiner Ethersex-Installation kommt es vor, daß die Antworten zu zwei Befehlen in einem Rutsch zurückgeliefert werden, also als OK\nOK\n. GGf. baue ich das wieder aus.

Ich bin hier auf Eure Meinungen angewiesen.

Viele Grüße
Boris

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

kpwg

Boris, ich habe mir nochmals die ADC-Sache angeschaut. das Beispiel aus der neuen commandref sieht so aus:
get value cmd {"adc get %channel\n"}
get value params channel
get value expect "\d+\n"
get value postproc { s/^(\d+)\n$/$1/;; $_ }


Damit kommt zwar dank Substitutionsoperator im postproc der derzimale Wert, jedoch meint das Log dazu:
2014.03.23 11:34:21 0: NETIO_WZ: write "adc get 3\n", expect "\\d+\\n"
2014.03.23 11:34:21 0: NETIO_WZ: read "178 \n"
2014.03.23 11:34:21 1: NETIO_WZ: unexpected answer "178 \n" received (wrote "adc get 3\n", expected "\\d+\\n")
2014.03.23 11:34:21 3: ADC_Messung: value 178


Prinzipell kann man expect ja immer mit ".*" ausstatten, nur ist das nicht das Ziel, oder? Mogeln sich hier zwei Backslashs ein?

Viele Grüße, Ricardo

Dr. Boris Neubert

Hallo,

was erwartetet wird ("expect"), wird maskiert. Aus den \ werden daher \\. Das ist aber überflüssig, weil das Regex ja schon per se maskiert ist. Das werde ich noch ändern.

Das Problem ist das Leerzeichen im empfangenen Wert zwischen der 178 und dem Newline. Du erwartest, um genau zu sein,

^\d \n$

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Tom_S

#13
hallo Boris,
danke für die Erläuterung
ZitatIn der aktuellen Version werden die %-Parameter im Match nicht ersetzt.
war der entscheidende Hinweis. Mit einem Pin funktioniert es jetzt. Allerdings wird das Symbol dann erst mit der Webseite aktuallisiert (kein Longpoll).
Aber so richtig klar ist mir das jetzt nicht. Da stehe ich wohl gerade auf der Leitung. Woher weis er welches logische ECMDDevice gemeint ist. Muß ich für ein weiteres Pin (also 2. logisches Device) einfach
reading on match "^port 2 4 1\n$"
reading off match "^port 2 4 0\n$".
das geht aber nicht.


ZitatIch grübele derzeit darüber, ob die zwischen den Antworten eingefügten \000 wirklich sinnvoll/hilfreich sind.
das weis ich leider auch nicht. Im Moment stellt es für mich keinen Mehrwert dar.

LG Tom_S
RaspberryPI2 + pilight, 3x AVR-NetIO, LW12, LW12HX, LW12FC; MAX-Lan, ESP8266, Arduino, H801, Neopixel, Solaredge, Modbus

kpwg

Zitat von: Dr. Boris Neubert am 23 März 2014, 11:48:31
Das Problem ist das Leerzeichen im empfangenen Wert zwischen der 178 und dem Newline. Du erwartest, um genau zu sein,

^\d \n$

Hallo Boris, das sehe ich anhand des Log genauso. Aber leider klappt es nicht:
2014.03.28 10:12:37 0: NETIO_WZ: write "adc get 3\n", expect "^\\d \\n$"
2014.03.28 10:12:37 0: NETIO_WZ: read "177 \n"
2014.03.28 10:12:37 1: NETIO_WZ: unexpected answer "177 \n" received (wrote "adc get 3\n", expected "^\\d \\n$")
2014.03.28 10:12:37 3: ADC_Messung: value 177


read und expect passen aus meiner Sicht genau zueinander. Vielleicht kannst du bitte bei Gelegenheit nochmal schauen; ich mache mich derweil an die Erstellung gut verwertbarer Readings bereits in der classdef.

Viele Grüße,

Ricardo