Wago /SPS über Modbus(TCP/IP) in FHEM steuern

Begonnen von lechez, 05 Mai 2013, 10:50:13

Vorheriges Thema - Nächstes Thema

ChrisD

Hallo,

Ich habe das Modul 99_modbus nicht geschrieben sondern lechez. Ihm ist es zu verdanken dass die Kommunikation mit den SPSen möglich ist. Ich habe lediglich einige Änderungen und Ergänzungen vorgenommen.

@Markus: Was meintest du mit
ZitatKönnte man zum Anfang mit dem Frontend verstärkt beginnen?
?

@Tino: Solange es ohne Probleme funktioniert würde ich es nicht ändern. Wenn du die 20 Werte in einer Funktion ausliest und ein Aufruf z.B. 100ms dauert, ist FHEM 2s 'blockiert'. Dies reicht nicht für den Disconnect des HMLAN. Wenn du das Dummy verwendest wird in den Internals des Dummys eine Zeile mit 'packets' angezeigt in der Zeiten stehen.  Wenn alle Werte auf 0 stehen musst du ein 'reload 99_modbus' machen, den Grund dafür habe ich noch nicht gefunden.

Es ist bei ModbusTCP möglich (und laut Spezifikation sogar erwünscht) die Verbindung zu öffnen und bis zum Ende des Clients (FHEM) offen zu lassen. Weiterhin ist es auch erlaubt mehrere Anfragen parallel abzuschicken, ob dies allerdings von den unterschiedlichen SPSen korrekt unterstützt ist weiß ich nicht. Das aktuelle Modul müsste dazu umgebaut werden.

Ich habe das Ganze zu Testzwecken mal als Modul umgebaut das über define deklariert wird. Dies hat verschiedene Vorteile (nur ein Verbindungsaufbau, automatisches Pollen, FHEM wird nicht blockiert bei Timeouts, ...) muss allerdings nach ausgiebig getestet werden.

@Hermann-Josef: Ob und wie du Coils und Register lesen kannst hängt von der Implementierung des Servers ab, wobei hier jeder SPS-Hersteller seine eigene Variante verwendet. Beim BC9000 sollte das Lesen über die Coil-Funktionen aber funktionieren, mit read_coil(16384) würde %M0.0 gelesen.

Um die Modbus-Funktionen in 99_myUtils zu verwenden brauchst du nichts zu tun. FHEM lädt 99_modbus automatisch und damit stehen die Funktioen auch in 99_myUtils zur Verfügung, 'use' ist nicht nötig.

ZitatAus irgendwelchen Gründen wird ein minimales (= entsprechend des Template) 99_myUtils.pm bei FHEM zum Editieren angezeigt, 99_modbus.pm taucht da bei mir nicht auf.
Unter 'Edit Files', 'Own modules and helper files' werden nur Dateien angezeigt die das Wort 'Util' im Namen haben, dies ist bei 99_modbus nicht der Fall.

ZitatZu guter Letzt, ist es normal, dass sich fhem.pl aufhängt, wenn man einen Perl-Fehler gemacht hat? Es lässt sich dann auch nicht mehr via /etc/init.d/fhem stop stoppen?
FHEM hängt sich dabei nicht auf sondern wird vom Perl-Interpreter beendet, dadurch kannst du es auch nicht mehr stoppen. Wenn du 'ps ax' aufrufst sollte der Perl-Prozess nicht mehr laufen. Mittels '/etc/init.d/fhem start' sollte FHEM aber wieder laufen (nachdem der Fehler behoben wurde).

Wenn du einen Taster in FHEM mit einem Dummy simulieren möchtest wäre on-for-timer optimal, nur leider funktioniert dies nicht mit Dummies (vielleicht ein weiterer Grund für ein Modul). Manuell könnte es so gehen:
define T1 dummy
attr T1 webCmd on
define n_T1 notify T1:on {write_modbus_coil(16384,1);;fhem("define a_T1_off at +00:00:01 {write_modbus_coil(16384,0);;;;fhem(\"set T1 off\")}")}

Das Stromstoßrelais würde ich im SPS-Code realisieren (mit z.B. R_TRIG und XOR).

Grüße,

ChrisD

Wiliam

Hallo,

Versuche schon seit längerem einen Temperaturwert aus der Wago SPS über Modbus in Fhem anzuzeigen.

Die Kommunikation zwischen Wago und Fhem funktioniert mittlerweile und ich bekomme Werte unter Fhem. Jedoch habe ich einige Probleme mit der der Darstellung, bei REAL Werten zeigt mir Fhem nur in der darauffolgenden Modbusadresse einen Wert an (sollte wahrscheinlich am Doppelwort liegen). Wie muß ich diesen Wert abfragen um ihn richtig Darstellen zu können?

Habe mir in der Not eine zweite Lösung überlegt in der ich aus dem REAL ein Integer in der SPS Wandel. Dieser wird nun unter Fhem richtig angezeigt, nur die negativen Werte fangen dann bei 32.767 an und laufen rückwärts.

Um dies zu umgehen, habe ich in der SPS einfach den gemessenen Wert um 100 addiert, so bleibe ich bei der Modebusübergabe im positiven Bereich, nur wie kann man die 100 unter Fhem wieder abziehen?? (habe zusätzlich die Temperatur in der SPS noch mit 100 multipliziert und unter Fhem wieder dividiert (damit ich zwei Nachkommerstellen bekomme), das dividieren Funktioniert wunderbar)

Bin wahrscheinlich mal wieder mit der Kirche um ganze Landkreise gezogen und man hätte das Ganze auch etwas einfacher realisieren können doch die Programmierung unter Fhem ist für eine ungeübten echt schwer.

Hier ist mein Eintrag in der Config:

define Temperatur_aussen dummy
attr Temperatur_aussen room Wetter
define at_read_Temperatur_aussen at +*00:00:05 {fhem("set Temperatur_aussen ".read_modbus_zaehler(12388)/100)}
define FileLog_Temperatur_aussen FileLog ./log/Tes/Temperatur_aussen-%Y.log FileLog_Temperatur_aussen:.*
attr FileLog_Temperatur_aussen logtype temp4:Plot,Temperatur_aussen
attr FileLog_Temperatur_aussen room Temperatur_aussen
define wlTemperatur_aussen SVG FileLog_Temperatur_aussen:temp4:CURRENT
attr wlTemperatur_aussen room Temperatur_aussen


Ich hoffe das meine Beschreibung einigermaßen verständlich ist.


Eventuell kann mir ja jemand weiterhelfen und mir sagen, wo ich die "-100" einsetzen muss damit mein Temperaturwert nicht mehr 100° bei 0° anzeigt.

Gruß

ChrisD

#107
Hallo,

Es gibt 2 Möglichkeiten die REAL-Werte zu übertragen:

- du liest 2 aufeinanderfolgende Modbus-Register und verwandelst diese wieder in REAL, z.B. in der SPS (Wago):
fTest AT %MD0 : REAL;und in FHEM:
define at_read_Temperatur_aussen at +*00:00:05 {fhem("set Temperatur_aussen ".(unpack "f", pack "L", ((read_modbus_zaehler(12289)<<16)+read_modbus_zaehler(12288)))}


- du benutzt Fixpunktzahlen, wie in deinem Beitrag beschrieben. Das Problem mit negativen Zahlen kommt daher dass über Modbus Worte ohne Vorzeichen übertragen werden, umwandeln geht mit:
define at_read_Temperatur_aussen at +*00:00:05 {fhem("set Temperatur_aussen ".(unpack "s", pack "S", read_modbus_zaehler(12388))/100)}wobei die Addition von 100 im SPS-Programm entfernt werden muss.

Wenn du nur die 100 wieder abziehen möchtest geht das mit:
define at_read_Temperatur_aussen at +*00:00:05 {fhem("set Temperatur_aussen ".(read_modbus_zaehler(12388)/100)-100)}

Grüße,

ChrisD

Wiliam

Juchuuu!!

vielen Dank, für die Mühe, es funktioniert!

Danke Danke Danke,      tolle Sache :) :) :)

bytebold

Hallo zusammen,

ich bekomme es igendwie nicht hin, abhängig von Bits eines eingelesenen Merkerwortes fhem- Dummies zu setzen.

Ich hole mir einen Wert aus der Wago ab:

fhem("set Wago12293 ".read_modbus_zaehler_indoor(12293))}

Jetzt möchte ich abhängig von bit 3 und bit 4, also Wert 8 und 16 zwei Dummys Kontakt_Gartentor und Kontakt_Garagentor setzen.
Habe jetzt auch schon Stunden damit verbracht, aber mir gelingt es nicht........ mir fehlt leider immer noch ein wenig das Verständnis
fhem- und Perl- Befehle zu mischen.

Sowas geht nicht:
fhem("set Kontakt_Gartentor ".(read_modbus_zaehler_outdoor(12293) && 8))

Sowas habe ich auch mal probiert:

define act_Wago12293 notify Wago12293 {
my $r1 == $value{"Wago12293"};;
my $r2 == 8;;
if ($r1 && $r2 == 8) {
   fhem "set Zustand_Garagentor closed"
} else {
   fhem "set Zustand_Garagentor open"
}
}

 

Hat jemand eine Idee ?

Gruß, bytebold
fhem auf Synology DS112+
HM-Lan Konfigurationsadapter
2x Wago 750-881 Feldbuscontroller
Fernbedienung RC-19

ChrisD

Hallo,

So könnte es gehen:
fhem("set Kontakt_Gartentor ".((read_modbus_zaehler_outdoor(12293) & 8)?"on":"off"))

Statt 'on' und 'off' kannst du natürlich beliebige andere Texte einsetzen.

Grüße,

ChrisD

bytebold

Hallo,

danke für den Vorschlag, werde ich noch ausprobieren. Ich habe gerade auch noch eine Lösung gefunden. Ist zwar komplizierter, klappt aber.

define Wago12293 dummy

define act_Wago12293 notify Wago12293 {\
my $zahl = Value("Wago12293");;\
my $bitmaske = 0b00001000;;\
if ($zahl & $bitmaske) { fhem ("set Zustand_Garagentor closed") }\
else {fhem ("set Zustand_Garagentor open")}}


Gruß, bytebold
fhem auf Synology DS112+
HM-Lan Konfigurationsadapter
2x Wago 750-881 Feldbuscontroller
Fernbedienung RC-19

bytebold

Hallo Chris,

habe Deine Lösung genommen, klappt wunderbar, danke.

Ich würde gerne verstehen, was das "?" macht, habe aber in der Doku nichts gefunden.
Entweder war ich blind oder es ist wirklich nicht dokumentiert.

Gruß, bytebold

fhem auf Synology DS112+
HM-Lan Konfigurationsadapter
2x Wago 750-881 Feldbuscontroller
Fernbedienung RC-19

ChrisD

Hallo,

? ist ein Standard-Perl Befehl und wird ternärer Operator genannt. Informationen dazu gibt es u.a. unter http://perldoc.perl.org/perlop.html#Conditional-Operator.

Grüße,

ChrisD

qwikser

Hi,

erstmal möchte ich danke sagen für dieses Modul und die Funktionen!
Da ich totaler Anfänger im Bereich fhem und 0 Kenntnisse in Perl besitze hänge ich nun ein wenig.
Was ich im Grunde möchte, ist lediglich fhem als Schnittstelle zwischen meiner Wago SPS und Systemen wie zB. MAX!, XBMC, ... nutzen.
SPS seitig habe ich keinerlei Probleme. FHEM rennt auf meinem Syno NAS, MAXLAN funktioniert auch schon.
Das Modbus Modul habe ich auch schon erfolgreich eingebunden. Und Funktionen wie z.B.

define myModbus modbus

define Temperatur_Soll_mw0 dummy
attr Temperatur_Soll_mw0 room Wago
attr Temperatur_Soll_mw0 stateFormat state °C
define at_read_Temperatur_Soll_mw0 at +*00:00:05 {fhem("set Temperatur_Soll_mw0 ".read_modbus_zaehler(12288)/10)}

define Dummy4_0 dummy
attr Dummy4_0 room Wago
attr Dummy4_0 setList On Off
attr Dummy4_0 webCmd On:Off
define act_Dummy4_0 notify Dummy4_0 { my $test  = read_modbus_zaehler(12292);; if (Value("Dummy4_0") eq "Off") {write_modbus(12292,$test & 65534)} else {write_modbus(12292,$test | 1)}}


laufen schon. Kann also einzelne bit`s in die SPS schreiben und word`s aus der SPS lesen.

Wo ich nun hänge ist, was muss ich noch bei dem Dummy4_0 einfügen damit er auch stätig das einzelne Bit`s ausließt?
Wenn ich die Variable in der SPC "umschalte" aktualisiert sich fhem nämlich nicht.

Auch brauche ich noch ein Beispiel wie man ein WORD von fhem in die SPS schreibt.

Vielen Dank im voraus.
MfG.
Daniel

ChrisD

Hallo,

Das Auslesen des Bits ist nicht so einfach. Du kannst zwar mit einem at den Zustand regelmässig lesen:
define at_read_Dummy4_0 at +*00:00:05 {fhem("set Dummy4_0 ".((read_modbus_zaehler(12292) & 1)?"on":"off"))}dies führt aber dazu dass dein notify anschließend ausgeführt wird und der eben gelesene Wert sofort wieder geschrieben wird. Ein Möglichkeit dies zu umgehen ist jedes Mal das notify abzuschalten, den Wert zu lesen und das notify wieder einzuschalten:
define at_read_Dummy4_0 at +*00:00:05 {fhem("attr act_Dummy4_0 disable 1;set Dummy4_0 ".((read_modbus_zaehler(12292) & 1)?"on":"off").";attr act_Dummy4_0 disable 0")}

Die Alternative wäre ein eigenständiges Modul welches das Lesen und Schreiben implementiert.

In fhem gibt es den Datentyp WORD nicht, du kannst aber wie beim Schreiben des Bits auch Zahlen mit write_modbus schreiben.

Grüße,

ChrisD




qwikser

Hallo Chris,

danke schon mal für diesen Gedanken anstoß!
Habe nun 2 Dummys angelegt pro BIT. Das genügt mir so um nur Daten hin und her zu schaufeln. :)

define Dummy4_3 dummy
attr Dummy4_3 room Wago
attr Dummy4_3 setList On Off
attr Dummy4_3 webCmd On:Off
define act_Dummy4_3 notify Dummy4_3 { my $test  = read_modbus_zaehler(12292);; if (Value("Dummy4_3") eq "Off") {write_modbus(12292,$test & 65527)} else {write_modbus(12292,$test | 8)}}
define Dummy4_3_x dummy
attr Dummy4_3_x room Wago
define at_read_Dummy4_3_x at +*00:00:02 {fhem("set Dummy4_3_x ".((read_modbus_zaehler(12292) & 8)?"on":"off"))}


Was ich mit dem WORD meinte war folgendes.
So sehen die Sollwerte aus in der Wago:

Temperatur_Soll_mw0 AT %MW0 : WORD;
Temperatur_Soll_mw1 AT %MW1 : WORD;

Und so in der fhem cfg:

define Temperatur_Soll_mw0 dummy
attr Temperatur_Soll_mw0 room Wago
attr Temperatur_Soll_mw0 stateFormat state °C
define at_read_Temperatur_Soll_mw0 at +*00:00:05 {fhem("set Temperatur_Soll_mw0 ".read_modbus_zaehler(12288)/10)}

define Temperatur_Soll_mw1 dummy
attr Temperatur_Soll_mw1 room Wago
attr Temperatur_Soll_mw1 stateFormat state °C
define at_read_Temperatur_Soll_mw1 at +*00:00:05 {fhem("set Temperatur_Soll_mw1 ".read_modbus_zaehler(12289)/10)}


Das funktioniert soweit schon super. Was ich nun noch brauch, ist der Weg zurück. Quasi die IST Temp. von meinem MAX! System in die SPS.

MFG.
Daniel

qwikser

#117
Hallo,

habe direkt noch eine frage. Habe ich hier vll. einen Fehler drin? ..oder könnte das so funktionieren?

define haustuer_zu_wago dummy
attr haustuer_zu_wago room Wago
define act_haustuer_zu_wago notify MAX_0850c2 { if (Value("STATE") eq "opened") { my $test  = read_modbus_zaehler(12292);; if (Value("haustuer_zu_wago") eq "Off") {write_modbus(12292,$test & 65519)} else {write_modbus(12292,$test | 16)}}}


Landen wollte ich auf diesem BIT in meiner SPS:

Dummy4_4 AT %MX4.4 : BOOL;


Das ist der Magnetkontakt meines MAX! Systems:

define MAX_0850c2 MAX ShutterContact 0850c2
attr MAX_0850c2 alias Flur Haustür
attr MAX_0850c2 icon fts_door_right_open
attr MAX_0850c2 room MAX


Als State gibt dieser die Meldung "closed" oder "opened"

MfG.
Daniel

ChrisD

#118
Hallo,

Die Ist-Temperatur könntest du entweder regelmässig mit
define at_write_Temperatur_Ist_mw10 at +*00:01:00 {write_modbus(12298,ReadingsVal("MAX_Thermostat_1","temperature",0)*10)}
oder über notify übertragen
define n_write_Temperatur_Ist_mw10 notify MAX_Thermostat_1:temperature.* {write_modbus(12298,$EVTPART1*10)}
Die Temperatur wird mit 10 multipliziert an die SPS übertragen so dass das Format deinen SPS-Sollwerten entspricht.

Das notify für den Türkontakt habe ich nicht verstanden. MAX_0850c2 ist der Magnetkontakt und liefert "opened" oder "closed". Die Funktion des Dummys "haustuer_zu_wago" ist mir aber nicht klar.

Wenn du nur den Magnetkontakt übertragen willst reicht
define act_haustuer_zu_wago notify MAX_0850c2:onoff.* {my $test  = read_modbus_zaehler(12292);; if ($EVTPART1 eq "0") {write_modbus(12292,$test & 65519)} else {write_modbus(12292,$test | 16)}}
oder wenn du dir Funktion "write_modbus_coil" verwendest
define act_haustuer_zu_wago notify MAX_0850c2:onoff.* {write_modbus_coil(12356,$EVTPART1)}
12356 ist die Coil-Adresse von MX4.4 (12288+4*16+4).

Du kannst generell das Schreiben (und Lesen) der Bits mit write_modbus_coil (und read_modbus_coil) machen, dadurch entfällt beim Schreiben der Lesevorgang und Maskieren des ganzen Wortes. Die Coil-Adressen bei Wago ergeben sich aus 12288+Wortadresse*16+Bit. Die höchste so ansprechbare Adresse ist %MX1279.15 (=Coil 32767).

Da ich keine MAX-Geräte habe musst du den Code eventuell anpassen.

Grüße,

ChrisD


Edit 01.03.2014 Funktionsaufruf 'write_modbus_zaehler' in 'write_modbus' geändert

qwikser

Hi,

das mit dem Magnetkontakt funktioniert schon wie eine 1. Danke! ..habe nun auch alles in der fhem.cfg mit Coils gemacht, das finde ich persönlich etwas übersichtlicher.  :)
Anbei nochmal der Code für die, die nach mir das nochmal benötigen:

define Dummy4_3 dummy
attr Dummy4_3 room Wago
define act_Dummy4_3 notify MAX_0850c2:onoff.* {write_modbus_coil(12355,$EVTPART1)}
define Dummy4_3_x dummy
attr Dummy4_3_x room Wago
define at_read_Dummy4_3_x at +*00:00:05 {fhem("set Dummy4_3_x ".((read_modbus_zaehler(12292) & 8)?"on":"off"))}


Das setzten der Ist-Temp funktioniert leider noch nicht. Habe nun schon 2 Stunden rum experimentiert, nur leider ohne Erfolg. :(
Aktuell sieht mein versuch so aus:

define Temperatur_Ist_mw3 dummy
attr Temperatur_Ist_mw3 room Wago
define at_write_Temperatur_Ist_mw3 at +*00:00:05 {write_modbus_zaehler(12291,ReadingsVal("MAX_07e1ea","temperature")*10)}


Auch habe ich versucht, einen Dummy anzulegen um einfach nur so einen Wert zu senden, ging aber auch nicht.

define act_write_Temperatur_Ist_mw3 {write_modbus_zaehler(12291)*10}


Anbei auch mal ein Screenshot (thermo.png) von dem Thermostat in fhem, vll. hilft das ja.

Anbei auch ein Screenshot vom Magnetkontakt (magnet.png). Wollte hierzu fragen, ob es auch möglich ist, den Battery Zustand übertragen wie die Auf/zu Meldung?

Vielen Dank nochmal für die bisherigen Antworten
An alle Karnevals Jecken noch, ALLAF!!  ;D ;D
Daniel