Hallo zusammen,
ich benötige Hilfe zu einer Modbus RS485 Schnittstelle.
Mein gerät: Salzelektrolyse Steuerung mit RS 485 (5-Pin Connector siehe Anhang)
Mein Ziel: Auslesen der Register und Aufbereitung/Schaltung über FHEM
Leider habe ich keinerlei Programmierkenntnisse auf diesem Gebiet. Ist vielleicht jemand so nett und kann mir helfen, auch bezüglich
der benötigten Hardware ,welche ich verwenden sollte?
Modbus Register liegen vor.
Vielen dank vorab
Gruß
DJ-Mix
Zitat von: DJ-Mix am 11 Juli 2016, 12:51:37
Hallo zusammen,
ich benötige Hilfe zu einer Modbus RS485 Schnittstelle.
Mein gerät: Salzelektrolyse Steuerung mit RS 485 (5-Pin Connector siehe Anhang)
Mein Ziel: Auslesen der Register und Aufbereitung/Schaltung über FHEM
Leider habe ich keinerlei Programmierkenntnisse auf diesem Gebiet. Ist vielleicht jemand so nett und kann mir helfen, auch bezüglich
der benötigten Hardware ,welche ich verwenden sollte?
Modbus Register liegen vor.
Ist ein wenig schwierig, da die Infos ein wenig mau sind.
RS485 kann als Halb-Duplex (2-Draht) oder Voll-Duplex (4-Draht) ausgelegt sein. Dann wird oft auch eine Versorgungsspannung mitgeführt (2-Draht), manchmal auch nur eine Gerätemasse (1-Draht), obwohl es da durchaus kontroverse Diskussionen über den Nutzen gibt.
Da Du 5 Kontakte hast, könnte das also eine Voll-Duplex Verbindung mit Gerätemasse sein. Das gäbe 5 Kontakte. Es könnte aber auch Halb-Duplex, mit Versorgungsspannung und doppelter Masse sein usw. usf.
Diese Details müsstest Du rausbekommen. Sonst müsste man das Durchmessen, was ein wenig Gerätschaften erfordert.
Ist das geklärt, dann wird wichtig, welche Baudrate verwendet wird. Obwohl man das relativ einfach testen kann.
Hast Du das alles, dann brauchst Du einen entsprechenden RS485 Adapter für Deinen Computer, der das unterstützt, was Du brauchst.
Der Rest ist dann ziemlich einfach, da FHEM ja schon eine MODBUS Implementierung hat.
vielen Dank erstmal.
Werde die Informationen besorgen.
Laut Register Übersicht:
habe weitere Informationen:
- Baudrate 19200
- halb Duplex
- gnd / -(B) / +(A)
- keine Versorgungsspannung
Adapter würde ich so einen nehmen:
http://www.ebay.de/itm/like/Digitus-DA-70157-Seriell-Adapter-USB-2-0/201583186437?hlpht=true&ops=true&viphx=1&_trksid=p2050601.c100103.m2451&_trkparms=aid%3D111001%26algo%3DREC.SEED%26ao%3D1%26asc%3D20150422114059%26meid%3Dca46de1fd079462d94b21e4efa06170a%26pid%3D100103%26rk%3D1%26rkt%3D4%26sd%3D201583186437%26clkid%3D6767854574877802900&_qi=RTM2266087 (http://www.ebay.de/itm/like/Digitus-DA-70157-Seriell-Adapter-USB-2-0/201583186437?hlpht=true&ops=true&viphx=1&_trksid=p2050601.c100103.m2451&_trkparms=aid%3D111001%26algo%3DREC.SEED%26ao%3D1%26asc%3D20150422114059%26meid%3Dca46de1fd079462d94b21e4efa06170a%26pid%3D100103%26rk%3D1%26rkt%3D4%26sd%3D201583186437%26clkid%3D6767854574877802900&_qi=RTM2266087)
Zitat von: DJ-Mix am 12 Juli 2016, 13:01:02
habe weitere Informationen:
- Baudrate 19200
- halb Duplex
- gnd / -(B) / +(A)
- keine Versorgungsspannung
Adapter würde ich so einen nehmen:
http://www.ebay.de/itm/like/Digitus-DA-70157-Seriell-Adapter-USB-2-0/201583186437?hlpht=true&ops=true&viphx=1&_trksid=p2050601.c100103.m2451&_trkparms=aid%3D111001%26algo%3DREC.SEED%26ao%3D1%26asc%3D20150422114059%26meid%3Dca46de1fd079462d94b21e4efa06170a%26pid%3D100103%26rk%3D1%26rkt%3D4%26sd%3D201583186437%26clkid%3D6767854574877802900&_qi=RTM2266087 (http://www.ebay.de/itm/like/Digitus-DA-70157-Seriell-Adapter-USB-2-0/201583186437?hlpht=true&ops=true&viphx=1&_trksid=p2050601.c100103.m2451&_trkparms=aid%3D111001%26algo%3DREC.SEED%26ao%3D1%26asc%3D20150422114059%26meid%3Dca46de1fd079462d94b21e4efa06170a%26pid%3D100103%26rk%3D1%26rkt%3D4%26sd%3D201583186437%26clkid%3D6767854574877802900&_qi=RTM2266087)
Das ist doch mal was. Jetzt musst Du nur noch rausbekommen, auf welchen der 5 Pins jeweils welches Signal liegt.
Der Adapter, den Du hast, ist aber normal seriell. Für RS485 brauchst Du sowas: http://www.ebay.de/itm/USB-auf-RS485-Adapter-RS-485-USB-Adapter-Konverter-Seriell-Adapter-Arduino-108-/121974380677?hash=item1c663d5885:g:M~8AAOSwbwlXASTQ
(keine Ahnung, ob der auch unter Linux läuft, würd mich aber wundern wenn nicht)
Danach in FHEM in den MODBUS definieren, dann darauf das Device mit den Registern.
Also, so etwa:
define ModBusLine Modbus /dev/ttyAMA0@19200
define MeinDevice ModbusAttr 1 10
attr MeinDevice obj-c1-poll 1
attr MeinDevice obj-c1-reading IO1
attr MeinDevice obj-c1-set 1
Hier wird ein Modbus auf AMA0 (das ist beim RPi der eingebaute serielle, also bei Dir dann sicher was anderes) mit 19200 Bit/s definiert und dann ei Device "MeinDevice" angelegt mit Adresse 1 und 10 Sekunden Pollrate.
Auf diesem Device ei Register vom Typ coil (also quasi Relais) mit Adresse 1 angelegt, welches gelesen (poll) wird und auch geschrieben werden kann (set) und als reading "IO1" erscheint.
Das muß man natürlich entsprechend Deinem Device anpassen.
den USB Adapter hatte ich auch ins Auge gefasst, jedoch benötige ich gnd / + / -
und der von Dir ausgesuchte USB hat nur + / -
Belegung auf der Platine ist von unten nach oben: gnd / + / - / frei / 24V
Sobald alles da ist, werde ich mal testen und einen 2 Raspi (mit FHEM2FHEM) anschließen.
Wie lege ich den das Register an? Habe als Anhang mal die Übersicht beigefügt.
Zitat von: DJ-Mix am 13 Juli 2016, 08:44:46
den USB Adapter hatte ich auch ins Auge gefasst, jedoch benötige ich gnd / + / -
und der von Dir ausgesuchte USB hat nur + / -
Belegung auf der Platine ist von unten nach oben: gnd / + / - / frei / 24V
Sobald alles da ist, werde ich mal testen und einen 2 Raspi (mit FHEM2FHEM) anschließen.
Wie lege ich den das Register an? Habe als Anhang mal die Übersicht beigefügt.
Je nach Kabellänge ist GND wichtig oder auch nicht. Aber GND kannst Du auch vom USB nehmen oder von der Spannungsversorgung. Dazu brauchst Du keinen anderen RS485 Adapter.
In der Anleitung fehlt, welchen Typ die Register haben.
Bei Modbus gibt es verschiedene Typen und innerhalb derer dann die Adressen. Das sind also eigene Adressräume pro Typ. Ich vermute mal, es sind Holding-Register.
Dann kannst Du das erste 0x0100 mit
define MeinDevice ModbusAttr 1 10
attr MeinDevice obj-h256-reading Wert1
attr MeinDevice obj-h256-poll 1
anlegen.
Also das Device mit define anlegen, dabei Modbus-Adresse (1) und Poll-Zyklus (10 Sekunden) angeben.
Mit dem ersten attr wird dann durch das h256 angegeben, Holding, Adresse 256 (also 0x0100) and als Reading "Wert1" festgelegt. Das zweite attr veranlasst dann, daß dieser Wert gelesen wird. Du solltest dann also kurze Zeit später im Device ein Reading "Wert1" sehen, mit dem aktuellen Wert von Register 0x0100.
Wenn da nix kommt, dann müsstest Du selbiges mal i anstelle h für Input probieren.
ok, das mit der Kabellänge wusste ich nicht - so Long - habe den von mir ausgesuchten Adapter bestellt :-)
(falls es nicht klappt - kann ich den von Dir vorgeschlagenen ja nachbestellen)
das mit den Registern verstehe ich leider nicht.
wie kommst du auf die h256? dies finde ich in der Übersicht nicht . . . .
(habe mal den Anfang von Measure Register angehangen)
hier sind die Dinge, die mich als erstes Interessieren . .
aufgebaut nach 0x0100 / 0x0101 / 0x0102 / etc. diese möchte ich gerne in FHEM darstellen
im weiteren Verlauf gibt es dann noch eine Unterteilung der Description nach Bits - wie stelle ich diese dar.
Sorry für so viele Fragen, aber kann mir im Moment leider keinen Reim darauf machen, wie diese Register aufgebaut werden.
Und nochmals Vielen dank für deine Hilfe.
ok, gerade noch was rumgesurft im I-Net und prompt die Lösung für
die 256 gefunden (Hex nach Dez Umrechnung).
Und wieder was schlauer geworden :)
bleibt noch die Unterteilung der Bits . . . .
würde das so funktionieren???
define ModBusLine Modbus /dev/ttyUSB0@19200 # USB Adapter
define Saltlange ModbusAttr 1 10 # Abfragezeit 10sec
attr Saltlange obj-h256-poll 1 # Auto Abfrage
attr Saltlange obj-h256-reading ION # 1 Register "ION"
attr Saltlange obj-h258-poll 1 # Auto Abfrage
attr Saltlange obj-h258-reading pH / 100 # 2 Register "pH" geteilt durch 100
attr Saltlange {sprintf("%.1f", ReadingsVal($name,"pH",0))} # Format Reading pH 0.00
Moin DJ
Die Bits sind genauso einfach! 400 hex gibt das 10. Bit! Nimm den Windofs taschenrechner, stell Ihn auf Programmierer um, und schon hast Du alles!
Gruss Christoph
noch ne Frage zu den Bits . . .
gebe ich diese dann so an?
attr Saltlange obj-h1-reading pH-high #bit 1 hex 0x000F "Alarm Code"
Nein
Das Register ist 0x0107, und es sind mehrere Bits! "F" in hex sind die Bits 0-3, also 4! Das mask in der Tabelle meint, das Du diese Maske brauchst, um die entsprechenden Informationen zu erhalten. Das Register 0x0107 hat insgesamt 16 Bits! Da ich aber mit Modbus nur ganz kuez rumgespielt habe, kann ich Dir die genaue Definition nicht sagen!
Gruss Christoph
Ok,mit den Bits muss ich mich dann noch auseinander setzen . . .
sollte mein Beispiel (leicht geändert) so funktionieren?
define ModBusLine Modbus /dev/ttyUSB0@19200 # USB Adapter
define Saltlange ModbusAttr 1 10 # Abfragezeit 10sec
attr Saltlange obj-h256-poll 1 # Auto Abfrage
attr Saltlange obj-h256-reading ION # 1 Register "ION"
attr Saltlange obj-h258-poll 1 # Auto Abfrage
attr Saltlange obj-h258-expr $val / 100 # Wert dividiert durch 100
attr Saltlange obj-h258-reading pH # 2 Register "pH"
attr Saltlange {sprintf("%.1f", ReadingsVal($name,"pH",0))} # Format Reading pH 0.00
Zitat von: DJ-Mix am 14 Juli 2016, 14:40:25
Ok,mit den Bits muss ich mich dann noch auseinander setzen . . .
sollte mein Beispiel (leicht geändert) so funktionieren?
define ModBusLine Modbus /dev/ttyUSB0@19200 # USB Adapter
define Saltlange ModbusAttr 1 10 # Abfragezeit 10sec
attr Saltlange obj-h256-poll 1 # Auto Abfrage
attr Saltlange obj-h256-reading ION # 1 Register "ION"
attr Saltlange obj-h258-poll 1 # Auto Abfrage
attr Saltlange obj-h258-expr $val / 100 # Wert dividiert durch 100
attr Saltlange obj-h258-reading pH # 2 Register "pH"
attr Saltlange {sprintf("%.1f", ReadingsVal($name,"pH",0))} # Format Reading pH 0.00
Mit der letzten Zeile bin ich nicht glücklich.
Zu den Bits:
ein Reading liest, wie ja schon erklärt, den ganzen 16 Bit-Wert. Solltest Dich ein wenig mit der Bitdarstellung beschäftigen, wenn das folgende Dir nichts sagt.
Wenn Du also das Bit 7 haben möchtest (das ganz rechte wird normalerweise mit 0 bezeichnet, also ist 7 das 8te Bit von rechts, der entsprechende Hex-Wert wäre 0x80 oder in Dezimal 128), dann musst Du 7 mal nach rechts schieben und alle höheren Bits ausmaskieren.
Das würde man so machen:
attr Saltlange obj-h256-expr ($val >> 7) & 0x01
Das >> schiebt das Bitfeld nach rechts und das & ist eine bitweise UND Operation mit dem Wert 0x01, also nur Bit 0 gesetzt.
Wenn Du nur an Bit 0 möchtest, dann kannst Du Dir das schieben sparen und würdest direkt $val & 0x01 machen.
erst mal Vielen dank
letzte Zeile
attr Saltlange obj-h258 stateFormat {sprintf("%.1f", ReadingsVal($name,"pH",0))}
zu den Bits
heißt das ich jeweils um x nach recht schieben muss um an das Bit zu kommen welches ich benötige.
Also wenn ich Bit 16 sehen möchte muss ich attr Saltlange obj-h256-expr ($val >> 16) & 0x01
eingeben!?
Hallo DJ
Ja, das ist eine Methode. Du kannst Dir aber auch die Schieberei sparen, und gleich mit dem entsprechenden Wert ver-unden! (Das ist dann die sogenannte Maske!)
Gruss Christoph
wäre das in etwa dann so . . .
attr Saltlange obj-h256-expr $val & 0x16
oder habe ich das falsch verstanden?
Ja, das hast Du falsch verstanden!
Du hast jetzt drei Bits freigeschaltet! (Bit 1, 2 und 3) Das 16. Bit liegt etwas weiter links! attr Saltlange obj-h263-expr & 0x8000
Zur Erklaerung, 263dez ist 107hex und 0x8000 entspricht 2#10000000_00000000 !
Gruss Christoph
2 Sachen wüsste ich noch gerne
Zitatattr Saltlange obj-h263-expr & 0x8000
benötige ich $val nicht?
bei Mask 0x000F mit 4 Bits (0-3) muss ich das so angeben?
Wenn ich z.B. das 2 Bit anzeigen möchte.
attr Saltlange obj-h263-expr ($val >> 2) & 0x000F
Moin
Doch das $val brauchst du wohl. Deine 2. Frage verstehe ich nicht. Du schiebst jetzt um 2 Bit nach rechts, und maskierst dann auf die letzten 4 Bit. Da haettest du dann Bit 3-6.
Mache es am Besten wie Tunte Ju beschrieben hat, schiebe Dir das entsprechende Bit an die letzte stelle und nimm 0x01 als Maske. Das ist dann das gewollte Bit!
Hast du den Taschenrechner von Windofs mal ausprobiert? Da kann man auch die Bits anklicken, und es wird einem der Hex- oder Dez-Code angezeigt!
Gruss Christoph
ich wollte Register 0x0107 Mask 0x000F und dann eins von den Bits 0-3
als Beispiel hatte ich 2 ausgewählt.
wäre dann also
attr Saltlange obj-h263-expr ($val >> 2) & 0x01
siehe Anhang
Zitat von: DJ-Mix am 15 Juli 2016, 06:32:07
letzte Zeile
attr Saltlange obj-h258 stateFormat {sprintf("%.1f", ReadingsVal($name,"pH",0))}
Das sieht besser aus.
Zitat von: DJ-Mix am 15 Juli 2016, 06:32:07
zu den Bits
heißt das ich jeweils um x nach recht schieben muss um an das Bit zu kommen welches ich benötige.
Also wenn ich Bit 16 sehen möchte muss ich attr Saltlange obj-h256-expr ($val >> 16) & 0x01
eingeben!?
Na ja. Theoretisch hast Du Recht. Aber ein normales Register bei Modbus hat nur 16 Bit. Damit ist das höchste Bit Nummer 15. Es gibt kein Bit 16.
Ausnahme: Wenn das niedrigste Bit nicht als 0 bezeichnet wird, sondern als 1, dann wäre das höchste 16. Aber dann mußt Du um 15 schieben (Bitnummer - 1), da die Nummerierung jeweils eins zu hoch ist.
Wenn wirklich Bit 16, also das richtige, verwendet wird, dann ist das ein Double-Register, dort werden zwei aufeinanderfolgende Register zu einer Zahl kombiniert. Dann wäre Bit 16 das Bit 0 des anderen Registers. Hier müsstest Du aber aufpassen. Manchmal kommen erst die niedrigen Bits 0-15 im ersten Register und 16-31 im zweiten, aber es kann auch umgekehrt sein: Erst 16-31 und dann 0-15.
Gehe aber mal davon aus, daß die mit 16 das oberste Bit meinen und mit 1 angefangen haben zu zählen.
vielen Dank - glaube ich habe es so weit verstanden.
nun habe ich das Problem, dass ich keine Verbindung hinbekomme . . . . :(
Internals:
DEF 1 10
DEST
INTERVAL 10
IODev ModBusLine
MODBUSID 1
NAME Saltlange
NR 25
PROTOCOL RTU
STATE opened
TYPE ModbusAttr
getList MBF_MEASURE_PH
setList
Helper:
lsend 1468698532.02859
Lastread:
Attributes:
IODev ModBusLine
dev-h-defPoll 1
dev-h-defShowGet 1
dev-h-read 3
event-on-change-reading *
obj-h258-reading MBF_MEASURE_PH
userattr IODev dev-h-defPoll dev-h-defShowGet dev-h-read event-on-change-reading obj-h258-reading
my %SaltlangeparseInfo = (
"h258" => { reading => "pH",
name => "MBF_MEASURE_PH",
expr => '$val / 100',
len => 1,
},
);
my %SaltlangedeviceInfo = (
"timing" => {
timeout => 2,
commDelay => 0.7,
sendDelay => 0.7,
},
"h" => {
combine => 5,
defShowGet => 1,
defPoll => 1,
defUnpack => "s>",
},
);
Internals:
BUSY 1
DEF /dev/ttyUSB0@19200
DeviceName /dev/ttyUSB0@19200
FD 4
NAME ModBusLine
NR 16
PARTIAL
RAWBUFFER
REQUESTHEX 0103010200012436
STATE opened
TYPE Modbus
QUEUE:
HASH(0x1052c18)
Readings:
2016-07-16 21:44:38 state opened
Request:
ADR 258
FCODE 3
FRAME $6
LEN 1
READING MBF_MEASURE_PH
TID 0
TYPE h
Device:
DEF 1 10
DEST
INTERVAL 10
IODev ModBusLine
MODBUSID 1
NAME Saltlange
NR 25
PROTOCOL RTU
STATE opened
TYPE ModbusAttr
getList MBF_MEASURE_PH
setList
Helper:
lsend 1468698592.04595
Lastread:
Defptr:
1:
DEF 1 10
DEST
INTERVAL 10
IODev ModBusLine
MODBUSID 1
NAME Saltlange
NR 25
PROTOCOL RTU
STATE opened
TYPE ModbusAttr
getList MBF_MEASURE_PH
setList
Helper:
lsend 1468698592.04595
Lastread:
5:
DEF 1 10
DEST
INTERVAL 10
IODev ModBusLine
MODBUSID 1
NAME Saltlange
NR 25
PROTOCOL RTU
STATE opened
TYPE ModbusAttr
getList MBF_MEASURE_PH
setList
Helper:
lsend 1468698592.04595
Lastread:
6:
DEF 1 10
DEST
INTERVAL 10
IODev ModBusLine
MODBUSID 1
NAME Saltlange
NR 25
PROTOCOL RTU
STATE opened
TYPE ModbusAttr
getList MBF_MEASURE_PH
setList
Helper:
lsend 1468698592.04595
Lastread:
Helper:
buffer
lsend 1468698592.04595
Attributes:
wo habe ich den hier einen Fehler?
danke vorab
RS485 USB Adapter ist dieser https://www.amazon.de/Digitus-DA-70157-Seriell-Adapter-USB/dp/B007VZY4CW/ref=sr_1_1?ie=UTF8&qid=1468698781&sr=8-1&keywords=rs485+usb (https://www.amazon.de/Digitus-DA-70157-Seriell-Adapter-USB/dp/B007VZY4CW/ref=sr_1_1?ie=UTF8&qid=1468698781&sr=8-1&keywords=rs485+usb)
hat sich erledigt, funktioniert. Hatte vergessen mal Neu zu starten - da hing irgendwas.