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 denke du verwendest die ältere Version von 99_modbus.pm aus Beitrag 9 die nur einen Parameter annimmt, nämlich den zu schreibenden Wert. Im Anhang von Beitrag 14 befindet sich eine erweiterte Version in der write_modbus 2 Parameter entgegennimmt, nämlich Adresse und Wert. Damit sollte dein notify nach einem 'reload 99_modbus' dann funktionieren.

Grüße,

ChrisD

leibi

Hallo,

war wirklich die alte 99_modbus.pm, vielen dank für den Tipp.
Das lesen von analogen PT100 Eingängen funktioniert problemlos.
Nur kann ich keine Ausgänge setzen(mit Funktion 5 und 6), weiß jemand wieviele Parameter ich bei Funktion 16 übergeben muss?
Ich habe mal in der MB_client geschaut, so wie ich das sehe muss ich doch das Register, Byte, Bit, Wert angeben.
Weiß da jemand weiter?

Das mit dem Modbus über fhem, ist echt top.

Gruß
Markus

ChrisD

Hallo,

Die Funktion 6 (Register schreiben) ist bereits in 99_modbus.pm als write_modbus implementiert. Ein Aufruf von {write_modbus(2,99)} schreibt den Wert 99 ins Register 2.

Die Funktion 5 (Coil schreiben) ist nicht implementiert, sie könnte z.B. so aussehen:
sub
write_modbus_coil($$)
{
  if ($m->write_single_coil($_[0], $_[1])) {
    $m->close();
  } else {
    Log 1, "write error\n $_[0] Wert $_[1]";
    $m = MBclient->new();
    # define server target
    $m->host("192.168.0.250");
    $m->unit_id(1);
  }
}


Der Aufruf {write_modbus_coil(2,1)}setzt das Bit in Coil 2.

Zum Schreiben mehrerer Register (Funktion 16) könnte diese Funktion verwendet werden:
sub
write_modbus_multi($$)
{
  my @data = split(/:/,$_[1]);
 
  if ($m->write_multiple_registers($_[0], \@data)) {
    $m->close();
  } else {
    Log 1, "write error\n $_[0] Wert $_[1]";
    $m = MBclient->new();
    # define server target
    $m->host("192.168.0.250");
    $m->unit_id(1);
  }
}


Der Aufruf von{write_modbus_multi(1,"21:22:23")} schreibt 21 ins Register 1, 22 in 2 und 23 in 3.

Grüße,

ChrisD


leibi

Hallo,

danke für deine Codeschnipsel.
Leider bekomme ich wieder Fehlermeldungen:

act_Garten_Steckdose41 return value: Missing right curly or square bracket at (eval 16) line 2, at end of line
syntax error at (eval 16) line 2, at EOF

Ist bei dem Aufruf: {write_modbus_multi(1,"21:22:23")}, die 1 die Registeradresse?

MFG
Markus

ChrisD

Hallo,

Kannst du die aktuelle Definition von act_Garten_Steckdose41 posten ? Aus der Fehlermeldung geht nicht hervor wodurch der Fehler auftritt.

Beim Beispiel {write_modbus_multi(1,"21:22:23")} ist 1 die Adresse des ersten Registers welches beschrieben wird (mit 21), die restlichen Werte werden automatisch in die folgenden Register (hier also 2 und 3) geschrieben. Die Syntax ist allgemein: write_modbus_multi(Startregister,"Wert1:Wert2:...:Wertn") wobei der Wert von n vom Server abhängt (maximal 125).

Grüße,

ChrisD

leibi

Hallo ChrisD,

vielen dank für deine Hilfe, geht soweit alles.
Nur wenn ich die mehrere Modbus-Funktionen nacheinander benutze, gehen vorherige nicht mehr.
Wie kann ich bei der Funktion 16, im Register einzelne Bits ansprechen?
Kann ich meine eingelesenen Temperaturwerte, auch mit dem PID-Regler verwenden?

Gruß
Markus

oniT

Hallo ChrisD,

ich hätte zu diesem Thema auch noch eine Frage. Wenn ich zum Beispiel mit read_modbus_zaehler einen Wert abfrage, dann ist dieser ja ohne Vorzeichen, also ein unit16bit. Ist es auch möglich einen mit Vorzeichen int16bit abzufragen?

Danke,
Gruß
Tino
BBB - debian weezy - FHEM 5.7
HMLAN - HM-LC-Bl1-FM, HM-ES-PMSw1-PI, HM-LC-Sw1-FM, HM-TC-IT-WM-W-EU, HM-WDS40-TH-I, HM-Sen-Wa-Od, HM-Sec-RHS
Dimplex Wärmepumpe / Dimplex ZL 300 - Modbus TCP
SDM630M - Modbus TCP
SolarLog 200 / SMA SonnyBoy 1.5/2.5 - Modbus TCP

ChrisD

@oniT: Beim Modbus sind Register 16 Bit breit, wie diese 16 Bits zu interpretieren sind ist Sache der Anwendung. Beim Lesen von Daten mittels read_modbus_zaehler wird der negative Wert der SPS im 2-Komplement übertragen, aus -1 wird 65535. Mit dieser Funktion kannst du den Wert zurückrechnen:
sub WORD_TO_INT($)
{
  my ($w)=@_;
  $w -= 65536 if $w>32767;
  return $w;
}

z.B.:
{WORD_TO_INT(read_modbus_zaehler(1))}

@leibi: Ich habe den Satz
ZitatNur wenn ich die mehrere Modbus-Funktionen nacheinander benutze, gehen vorherige nicht mehr.
nicht verstanden, kannst du bitte erklären was genau nicht funktioniert ? Hast du Fehlermeldungen im Log ?

Die Funktion 16 ist zum Schreiben mehrerer Register mit jeweils 16 Bit. Unter Perl gibt es keine direkte Möglichkeit Bits anzusprechen, du musst das mittels Masken mit & und | machen:$w |=1<<3; setzt Bit 3 in der Variable $w (die vorher deklariert sein muss),$w &=~(1<<3);löscht Bit 3. Wenn du einzelne Bits übertragen möchtest kannst du die Modbus-Funktionen 5 und 15 benutzen (wenn sie von deinem Modbus-Server unterstützt werden).

ZitatKann ich meine eingelesenen Temperaturwerte, auch mit dem PID-Regler verwenden?
Ja, dazu musst du ein Dummy definieren, die Daten der SPS regelmäßig mittels at einlesen und dem PID das Dummy als Istwert übergeben, z.B.:
define istW dummy
define stellW dummy
define at_read_istW at +*00:01:00 {fhem "set istW ".read_modbus_zaehler(1)}
define PID PID20 istW:state stellW
attr PID desired 25


Grüße,

ChrisD



leibi

Hallo ChrisD,

danke mal wieder für deine Hilfe.
Mein Problem ist wenn ich mit Funktion 5, ein Coil beschreibe(funktioniert), und danach mit Funktion 16 ein anderes Register, funktioniert danach das erste(mit Funktion 5), nicht mehr.
Aber für meine Anwendung reicht eigentlich auch die Funktion 5, also kein Problem.

Gruß
Markus

leibi

Hallo,

kann sowas funktionieren?

define temp dummy
attr temp room Garten
define at_read_temp at +*00:00:10 {fhem "set temp ".read_modbus_zaehler(0000)/10}
define act_Garten_temp notify temp {if (Value("temp") < "21") {write_modbus_multi(9216,"0:0:0") else {write_modbus_multi(9216,"4:0:0")}}

Bin halt ein blutiger Anfänger

ChrisD

Ja, sollte funktionieren, die Zeile
define act_Garten_temp notify temp {if (Value("temp") < "21") {write_modbus_multi(9216,"0:0:0") else {write_modbus_multi(9216,"4:0:0")}}muss von der Syntax her nur leicht geändert werden:
define act_Garten_temp notify temp {if (Value("temp") < 21) {write_modbus_multi(9216,"0:0:0")} else {write_modbus_multi(9216,"4:0:0")}}

Grüße,

ChrisD

oniT

Hallo ChrisD,

ok Danke, das habe ich so nicht gewusst. Ich dachte man kann diese Werte direkt abfragen.

Jetzt habe ich jedoch noch ein Problem, wie bekomme diesen dann richtig in ein Device?

Ich dache dies geht dann so:


define dummy_test
define test_abfrage at +*00:01:00 {fhem "set dummy_test ".WORD_TO_INT(read_modbus_zaehler(1))/10}


allerdings geht das nicht. Das wäre dann wohl doch zu einfach ;-)

Danke
Gruß
Tino
BBB - debian weezy - FHEM 5.7
HMLAN - HM-LC-Bl1-FM, HM-ES-PMSw1-PI, HM-LC-Sw1-FM, HM-TC-IT-WM-W-EU, HM-WDS40-TH-I, HM-Sen-Wa-Od, HM-Sec-RHS
Dimplex Wärmepumpe / Dimplex ZL 300 - Modbus TCP
SDM630M - Modbus TCP
SolarLog 200 / SMA SonnyBoy 1.5/2.5 - Modbus TCP

ChrisD

Hallo,

In der Zeiledefine dummy_testfehlt der Typ, so sollte es gehen:define dummy_test dummy

Grüße,

ChrisD

oniT

Hallo,

das hatte ich schon mit eingetragen nur nicht mit hier in den Code kopiert. Au weh, mein Fehler. Das war's nicht. Allerdings hatte ich irgendwo eine Klammer zu viel oder zu wenig gesetzt. Jetzt klappt es.


define test_abfrage at +*00:01:00 {fhem "set dummy_test ".WORD_TO_INT(read_modbus_zaehler(1))}


Das ist halt das Problem wenn man dies direkt in fhem einträgt und nicht über einen Editor. Der hätte mir die fehlende Klammer angezeigt ;-)

Danke
Gruß,
Tino
BBB - debian weezy - FHEM 5.7
HMLAN - HM-LC-Bl1-FM, HM-ES-PMSw1-PI, HM-LC-Sw1-FM, HM-TC-IT-WM-W-EU, HM-WDS40-TH-I, HM-Sen-Wa-Od, HM-Sec-RHS
Dimplex Wärmepumpe / Dimplex ZL 300 - Modbus TCP
SDM630M - Modbus TCP
SolarLog 200 / SMA SonnyBoy 1.5/2.5 - Modbus TCP

leibi

Hallo,

was kann das sein, das nach ein paar Schaltspielen mit der Funktion 5, nichts mehr geht(im  log steht write error?
Lesen von Temperaturwerten funktioniert völlig stabil, nur Ausgänge schreiben macht Probleme.

Hätte jemand einen Tipp? Ich habe einen Raspberry.

MFG
Markus