letzte veröffentlichte Version von
36_KVPUDP.pm (08-11-2017) (https://forum.fhem.de/index.php/topic,45545.msg889384.html#msg889384)#############################################################
ich möchte mehr über die Erstellung eines Modules für FHEM lernen.
Dazu habe ich mir folgendes Beispiel ausgesucht:
- Sketch auf NodeMCU liest alle 60s ein BMP180 aus
- Daten werden per UDP-Multicast gesendet
- 00_KVPUDP.pm empfängt die Daten und stellt sie in FHEM zur Verfügung
Leider sind mir noch eingige Sachen unklar bzgl. des FHEM-Modules
- warum wird als IODev ein JeeLink eingetragen?
- warum werden keine Daten mehr verarbeitet, wenn Clients gesetzt wird (KeyValueProtocol)?
Vieleicht findet sich ja der ein oder andere Wissende, um mich in die richtige Richtung zu schubsen.
anbei die Sourcen und der Sketch
kurzes Perl-Skript zum Testen ohne Harware
use IO::Socket::Multicast;
# create a new UDP socket ready to read datagrams on port 1100
my $s = IO::Socket::Multicast->new(LocalPort=>1100);
# Set time to live on outgoing multicast packets
$s->mcast_ttl(1);
# Multicast a message to group 225.0.0.1
$s->mcast_send('OK VALUES TEST 0 1=Test,','239.0.0.57:12345');
$s->mcast_send('OK VALUES TEST 0 1=Test,','239.0.0.57:12345');
Empfang ohne FHEM
use IO::Socket::Multicast;
use constant mCastAddr => '239.0.0.57';
use constant mCastPort => '12345';
# create a new UDP socket ready to read datagrams on port 1100
my $s = IO::Socket::Multicast->new
(
Domain => AF_INET,
Proto => 'udp',
LocalPort => mCastPort,
ReuseAddr => 1, # true
);
die "couldn\'t create socket!" if (!defined($s));
# Add a multicast group
$s->mcast_add(mCastAddr) || die "set multicast group failed!";
print "\nrecv from multicast address " . mCastAddr . ":" . mCastPort . "\n";
# recv a message
while (1) {
my $data;
next unless $s->recv($data, 1024);
print $s->peerhost() . ": " . $data . "\n";
}
als IODev wird automatisch das zuletzt definierte passende eingetragen. das kannst du aber per IODev attribut überschreiben. das ganze ist aber nicht für die sende richtung relevant. wenn dein modul nur empfängt ist es egal.
bau ein paar debug meldungen ein um zu sehen wo genau die nachrichten verloren gehen. vor dem empfang? in dispatch? in KeyValueProtocol?
was steht bei verbose 5 im log?
gruss
andre
im phys. Modul muss die FingerprintFn definiert werden, sonst werden alle Nachrichten verworfen, da im Dispatch 2x CheckDuplicate und rejectDuplicate aufgerufen wird (fhem.pl). Ob das ein Bug oder Feature ist, kann ich nicht sagen.
Jedenfalls funktioniert jetzt der Empfang so wie erwartet.
@justme1968: danke
Nachtrag: Log-Auszug inkl. diverser Debug-Ausgaben aus fhem.pl
2015.12.17 20:10:22 3: myKVPUDP: Received 34 bytes from '192.168.10.52''
2015.12.17 20:10:22 3: Dispatch: dispatch 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:10:22 3: CheckDuplicate: msg 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:10:22 3: CheckDuplicate: #1
2015.12.17 20:10:22 3: CheckDuplicate: lim=1450379422.21072, TIM=1450379363.50959
2015.12.17 20:10:22 3: computeClientArray
2015.12.17 20:10:22 3: computeClientArray: m=KeyValueProtocol, re=KeyValueProtocol
2015.12.17 20:10:22 3: Dispatch: matched KeyValueProtocol
2015.12.17 20:10:22 3: CheckDuplicate: msg 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:10:22 3: KeyValueProtocol_Fingerprint: myKVPUDP, OK VALUES BMP180 0 1=19.80,2=1018,
2015.12.17 20:10:22 3: CheckDuplicate: #1
2015.12.17 20:10:22 3: CheckDuplicate: lim=1450379422.27607, TIM=1450379422.71072
2015.12.17 20:10:22 3: Dispatch: reject duplicate
2015.12.17 20:11:22 3: myKVPUDP: Received 34 bytes from '192.168.10.52''
2015.12.17 20:11:22 3: Dispatch: dispatch 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:11:22 3: CheckDuplicate: msg 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:11:22 3: CheckDuplicate: #1
2015.12.17 20:11:22 3: CheckDuplicate: lim=1450379482.24323, TIM=1450379422.71072
2015.12.17 20:11:22 3: Dispatch: matched KeyValueProtocol
2015.12.17 20:11:22 3: CheckDuplicate: msg 'OK VALUES BMP180 0 1=19.80,2=1018,'
2015.12.17 20:11:22 3: KeyValueProtocol_Fingerprint: myKVPUDP, OK VALUES BMP180 0 1=19.80,2=1018,
2015.12.17 20:11:22 3: CheckDuplicate: #1
2015.12.17 20:11:22 3: CheckDuplicate: lim=1450379482.24795, TIM=1450379482.74323
2015.12.17 20:11:22 3: Dispatch: reject duplicate
Sketch v0.3
- OTA via FHEM-Modul eingefügt
- SoftAP startet automatisch, wenn nicht mit WLAN verbunden
- WiFi Setup via HTML
36_KVPUDP.pm
- set raw <peer ip> <cmd list>
- set flash <peer ip> [filename]
v0.3a
Sketch
- ESP8266WiFi.waitForConnectResult ausgebaut (Endlosschleife)
- SoftAP startet auch, wenn Wifi nicht connected ist (hat in v0.3 nicht richtig funktioniert)
FHEM-modul
- Filter für ChipID eingebaut
Discovery-Mode für Davis Vantage funktionsfähig.
Leider noch keine komplette Unterstützung, da noch keine Lösung für die 2 Interrupt-Implementierungen von Arduino umgesetzt.
Moin,
ich spiele aktuell mit deiner "36_KVPUDP.pm".
Kannst Du mir mal erläutern was Du da genau mit deiner Config-Abfrage machst?
PS: Danke fürs sharen!
Gruß
Shojo
meinst du den HTTP-Request?
my $req = HTTP::Request->new(GET => "http://" . $remote . "/config?Version=&ChipID=&MAC=&Dictionary=");
Da werden SW-Version, ChipID und Dictionary abgefragt.
$remote ist die IP-Adresse aus dem UDP-Multicast-Paket.
Ja genau das meinte ich :)
verstehe ich das richtig das Du so optional deine Readings anlegst ?
@Shojo: wofür verwendest du den http rückweg? der sketch kann die daten doch auch von sich aus senden?
und schau mal hier: https://forum.fhem.de/index.php?topic=73623.msg655717#msg655717
vielleicht wäre es gut wenn wir uns alle einigen. auch HCS.
Nutzen tue ich es nicht, wollte nur wissen was seine Idee dahinter ist / war ;)
Beim Empfang eines UDP-Mulitcast-Paket in FHEM wird die Konfiguration des Absenders aktiv ausgelesen, wenn der Absender
- nicht bekannt ist
- ein entsprechendes Paket gesendet hat (passiert bei jedem Booten vom NodeMCU)
perl 5.24 Anpassungen
Moin,
magst Du in deinen Modul die Paketgröße von 128 auf 512 Byte anheben?
(Zeile 204)
Da ich in einen anderen Projekt mit den 128 Byte nicht mehr klar komme :)
angepasst
Landen die Änderungen die hier gemacht werden auch im SVN von FHEM und werden über das Update bereitgestellt?
aktuell gibt es die Änderungen nur hier!
Ich hab mal dem Modul Maintainer eine PN geschrieben, damit die Änderungen hier nicht unter gehen.
Es gibt keinen Maintainer, da nicht unter Versionskontrolle. Sollte ich beim Kopieren einer anderen pm-Datei aus FHEM dies nicht bereinigt haben, so bitte ich um Entschuldigung.
@gloob: Bitte kläre das mit dem Empfänger deiner PM
Hast du einen Tipp was ich in FHEM für Devices anlegen muss um Daten zu empfangen?
Mein Gerät sendet am Anfang folgendes:
OK VALUES IR_Blaster 14590508 ChipID=14590508,FlashChipId=1458400,MAC=18:FE:34:DE:A2:2C,Version=v2.2
Über eine UDP Verbindung:
// multicast
WiFiUDP WiFiUdp;
IPAddress ipMulti(239, 0, 0, 57);
unsigned int portMulti = 12345; // local port to listen on
String deviceID = "";
das oben verlinkte KVPUDP.
define myKVPUDP KVPUDP
attr myKVPUDP verbose 4
innerhalb von 2 Minuten müssen 2 Nachrichten eintreffen, damit auto-create funktioniert.
Im ersten Post ist ein kleines Perl-Skript, das Nachrichten generiert.
und das lässt sich über das autocreateThreshold antribut ändern.
Vielen Dank jetzt funktioniert es. Ich musste nur noch ein Lib installieren:
sudo apt-get install libio-socket-multicast-perl
Gibt es eine Möglichkeit für ein "Clear" um die Readings vorerst wieder los zu werden. Bin noch am testen mit den Namen.
einfach das jeweilige Device löschen.
delete KeyValueProtocol_Test_0
oder wenn du attribute behalten willst: deletereading <name> .*
Hi,
zum senden FHEM => UPD Device ist aber noch nichts im Sicht oder?
Gruß
Dennis
schau dir mal set raw vom KVPUDP-Device an.
Damit kann ein HTTP-GETPOST ausgelöst werden (http://<ip>/config). Die Variablen (abc=123; s.u.) werden im Content vom POST verpackt.
set myKVPUDP raw 192.168.10.10 abc 123
Ja Ok das ist schon nice, allerdings würde es auch gehen das man es so umbaut das man nicht mit der IP sonder per Device den raw Befehl aufruft ?
Da ich ja so die Flexibilität verliere, das ich mich nicht um die IP des Devices kümmern muss.
Das war einer der Gründe für mich UDP Multicast einzusetzten.
set myKVPUDP raw IR-Blaster_0815 abc 123
wie oben schon angekündigt habe ich etwas dazu in arbeit. dauert aber noch etwas.
bis dahin kannst du dir vermutlich mit cmdalias etwas zusammenbauen.
Zitat von: Shojo am 18 Juli 2017, 22:11:44
Da ich ja so die Flexibilität verliere, das ich mich nicht um die IP des Devices kümmern muss.
alternativ zur IP kann auch die ChipID benutzt werden glaube ich.
Das Device zu benutzen finde ich nicht gut, da ja folgendes intuitiver wäre
set <device> raw ...
Zitat von: habeIchVergessen am 18 Juli 2017, 22:57:56
Das Device zu benutzen finde ich nicht gut, da ja folgendes intuitiver wäre
set <device> raw ...
Ok da stimme ich dir absolut zu.
Zitat von: habeIchVergessen am 18 Juli 2017, 22:57:56
alternativ zur IP kann auch die ChipID benutzt werden glaube ich.
Das probiere ich mal :)
natürlich alles anders als erwartet.
- set raw Chip-ID habe ich eingebaut
- die Kommandos, die gesendet werden dürfen müssen diese regexp erfüllen
m/^(-{0,1}\d*,{0,1}\d*)([a-zA-Z]{1})$/;
In Anlehnung an LaCrosseGateway kann man dann z.B.
1l
-5,14r
d
senden. Soll heißen 1 oder 2 Zahlen mit Komma getrennt und ein Buchstabe. Ist aber nicht in Stein gemeiselt.
Zitat von: habeIchVergessen am 18 Juli 2017, 23:56:00
Soll heißen 1 oder 2 Zahlen mit Komma getrennt und ein Buchstabe. Ist aber nicht in Stein gemeiselt.
Das ist ja schon mal was :)
Ich hatte aber vor eine Ganze Menge mehr zu sende :D
Einmal zum 360 Grad IR WLAN Gateway (https://forum.fhem.de/index.php?topic=72950)
Und noch ein anderes Projekt (eine LED Dotmatrix für FHEM)
Da kommen dann schon gerne 500 Zeichen beisammen ;D
würde gerne den Aufwand zum Parsen in FHEM belassen.
Skizziert doch mal kurz die Anforderungen auf der FHEM-Seite, die Übertragung und das Auslesen im Sketch.
Ja ich hätte es nun gedacht:
set myKVPUDP raw <ChipID> <Funktion> <Wert>
set myKVPUDP raw 2354154 json.plain [{'data':'0', 'type':'RC6', 'length':1}]
set myKVPUDP raw 2354154 json.plain [{'data':[550,650, 1200,650, 1200,650, 1200,650, 550,650, 1200,650, 550,650, 550,650, 550,650, 550,25300, 2350,650, 550,650, 1200,650, 550,650, 1200,650, 1200,650, 1200,650, 550,650, 1200,650, 550,650, 550,650, 550,650, 550], 'type':'raw', 'khz':38}]
set myKVPUDP raw 2354154 msg.code 0:RC6:1
set <Device> <Funktion> <Wert>
Natürlich wäre natürlich das ein Traum :)
263 Zeichen
set myKVPUDP raw 2354154 json.plain [{'data':[550,650, 1200,650, 1200,650, 1200,650, 550,650, 1200,650, 550,650, 550,650, 550,650, 550,25300, 2350,650, 550,650, 1200,650, 550,650, 1200,650, 1200,650, 1200,650, 550,650, 1200,650, 550,650, 550,650, 550,650, 550], 'type':'raw', 'khz':38}]
die bei SIGNALduino wahrscheinlich so aussehen würden und "nur" 124 Zeichen benötigen
set myKVPUDP raw 2354154 P1=550;P2=650;P3=1200;P4=2350;P5=25300;D=123232321232121212154212321232323212321212121;F=38;T=raw;
die sind ja sehr ähnlich
set myKVPUDP raw 2354154 json.plain [{'data':'0', 'type':'RC6', 'length':1}]
set myKVPUDP raw 2354154 msg.code 0:RC6:1
wo ist die Betrachtung der Logik zum Parsen auf dem Zielgerät (z.B. NodeMCU/Wemos D1)?
Die sollte aus meiner Sicht sehr "einfach" sein, da dort die wenigsten Resourcen zur Verarbeitung vorhanden sind.
Wie steht es mit dem Zeitverhalten? kleine Latenz gewünscht?
Zitat von: habeIchVergessen am 20 Juli 2017, 22:49:50
wo ist die Betrachtung der Logik zum Parsen auf dem Zielgerät (z.B. NodeMCU/Wemos D1)?
Die sollte aus meiner Sicht sehr "einfach" sein, da dort die wenigsten Resourcen zur Verarbeitung vorhanden sind.
Wie steht es mit dem Zeitverhalten? kleine Latenz gewünscht?
Ja da dafür gibt es noch nichts, da ich ja nichts habe worauf ich aufbauen kann.
Sonst ist die Firmware von IR-Blaster ist hier zu finden.
Wenn es um die aktuellen Beispiele geht.
Für die Dotmatrix habe ich noch nichts geschrieben,da dieses Projekt noch nicht geratet ist.
Nabend,
eine Frage, ich nutze das Modul um IR Codes im IRBlaster zu empfangen. FHEM läuft bei mir auch einem Linux Rechner, ich sehe die Multicast Pakete mit tcpdump aber das Modul legt mir per autocreate kein neues Gerät an. Hat noch jemand eine Idee? Ich habe via iptables eigentlich alles was Multicast ist erlaubt, aber irgendwie bin ich etwas Ratlos warum es nicht funktioniert. In den Logs sehe ich auch nichts.
Hat noch jemand ein Tip?
Internals:
Clients :KeyValueProtocol
FD 41
NAME myKVPUDP
NR 2003
STATE Opened
TYPE KVPUDP
MatchList:
1:KeyValueProtocol ^OK\sVALUES\s
helper:
bm:
KVPUDP_Set:
cnt 11
dmx -1000
dtot 0
dtotcnt 0
mTS 11.01. 20:59:16
max 8.98838043212891e-05
tot 0.000323295593261719
mAr:
HASH(0x849bb48)
myKVPUDP
?
Attributes:
verbose 5
/Daniel
schon das perl-Skript aus dem ersten Post probiert?
sollte ein neues Geräte KeyValueProtocol_Test_0 anlegen.
Ja das hat funktioniert und das entsprechende Geräte angelegt.
/Daniel
im FHEM ist dann nur noch das Limit vom autocreate (default 2 Nachrichten in 2 min.).
vor dem dispatch wird ins log geschrieben, das x Bytes von IP empfangen wurden.
Sind solche Einträge im Log?
Wieviele Ethernet-Devices sind aktiv?
Beim Empfang der ersten Nachricht, wird ein http-Request gegen die sendende IP ausgeführt. Ist der mit tcpdump zu sehen (inkl. Response)?
>Sind solche Einträge im Log?
Nein
>Wie viele Ethernet-Devices sind aktiv?
3, Loopback, br0 und eth0
>Beim Empfang der ersten Nachricht, wird ein http-Request gegen die sendende IP ausgeführt. Ist der mit tcpdump zu sehen (inkl. Response)?
Nein, man sieht nur die UDP Multicast Pakete vom IRBlaster (tcpdump auf eth0)
Dann habe ich tcpdump mal auf dem br0 Interface gestartet und schon funktioniert es, sofort hat FHEM das Device angelegt und man sieht auch die Logs und Nachrichten die du beschrieben hast.
Jetzt frage ich mich aber warum. Das sieht ja so aus, als wenn der premiscous mode in den tcpdump ja die Interface setzt dafür sorgt, dass es funktioniert. Ich glaube ich muss mir die bridge config nochmal anschauen. (Die habe ich nur angelegt wegen KVM, da braucht man das wenn man mit virtuellen Maschinen arbeitet)
/Daniel
UPDATE: Ich hab die Bridge rausgehauen. Jetzt geht es.
Hm, sorry, hänge gerade ein bißchen, FHEM will das Modul nicht laden weil "Bareword "KeyValueProtocol" not allowed while "strict subs" in use at ./FHEM/36_KVUDP.pm line 201."
Irgend eine Idee?
ich vermute einen Typo im Modul.
Welche Version benutzt du (Link)?
Kannst du bitte Zeile 196 bis 206 aus deinem Modul posten?
Danke! Ich nutze das zuletzt von Dir gepostete: Zitat von: habeIchVergessen am 18 Juli 2017, 23:56:00
}
Log3 $hash, 3, "$name: Received " . length($data) . " bytes from '" .
$remote . "''";
Dispatch($hash, $data, \%addvals) if (!$serviceMsg &&
!defined($hash->{PEERS}{$remote}{Ignored})); # dispatch result to
KeyValueProtocol
}
sub KVPUDP_WriteCmd ($@) {
my ($peer, @params) = @_;
my $cmds = "";
while (my $param = shift @params) {
[/s]
Edith sagt: Ich bin ein Trottel: da hat sich beim Kopieren ein CR eingeschlichen, sodass der Kommentar zerrissen wurde.... Das hab ich jetzt korrigiert und es gibt zumindest schonmal einen anderen Fehler... - gelöst!
Danke für die Hilfe!
letzter Stand vom 08.11.2017
Hallo zusammen,
noch mal, damit das auch für mich klar wird: wenn ich folgenden String
OK VALUES heizung 1 timer=0,109E85B700080021=85.12,10C175B5020800C5=85.12,duration=29
OK VALUES heizung 1 timer=5,109E85B700080021=22.75,10C175B5020800C5=22.87,duration=28
OK VALUES heizung 1 timer=10,109E85B700080021=22.69,10C175B5020800C5=22.81,duration=28
über eine ESP8266 UDP Verbindung sende, kann ich das obige Modul verwenden, um die Daten in FHEM weiterzuverarbeiten, korrekt?
Hier wäre dann <Device> heizung und die <ID> 01. Geht auch als Reading Name eine 1-wire ID?
Muss ich dann die UDP Verbindung die ganze Zeit offen lassen?
Danke + Gruß
Peter
Edit: klar, die ID muss 1 sein 8)
Zitat von: PeMue am 10 März 2019, 18:38:07
OK VALUES heizung 1 timer=0,109E85B700080021=85.12,10C175B5020800C5=85.12,duration=29
Hier wäre dann <Device> heizung und die <ID> 1.
Zitat von: PeMue am 10 März 2019, 18:38:07
Geht auch als Reading Name eine 1-wire ID?
Punkte im Namen sind zulässig
list KeyValueProtocol_TEST_0
READINGS:
...
2019-03-10 18:56:35 10.a20000000505.6a Test
...
UDP hat keine Verbindung auf der Client-Seite. Lediglich der Server (KVPUDP) macht permanent ein Listen.
Client
if (WiFiUdp.beginPacketMulticast(ipMulti, portMulti, WiFi.localIP()) == 1) {
WiFiUdp.write(msg.c_str());
WiFiUdp.endPacket();
yield(); // force ESP8266 background tasks (wifi); multicast requires approx. 600 µs vs. delay 1ms
result = true;
}
Ups, da scheint was noch nicht so ganz zu funktionieren, vor oder während dem Senden gibt es einen Reboot >:( >:( >:(:
Vitotronic 1-wire demo
Connecting to PMWLAN02 .... connected ...
UDP port at IP 192.168.188.28, UDP port 82 opened
Locating devices ...
Found 3 device(s).
Parasite power is: OFF
Device 0 Address: 109E85B700080021
Device 1 Address: 10C175B5020800C5
Device 2 Address: 288B22A8000000C2
Exception (9):
epc1=0x40202b78 epc2=0x00000000 epc3=0x00000000 excvaddr=0x45554c45 depc=0x00000000
>>>stack>>>
ctx: cont
sp: 3ffffdc0 end: 3fffffc0 offset: 01a0
3fffff60: 4020b690 00000000 00000000 3ffefe04
3fffff70: 0000006f 0000006c 00000000 00000000
3fffff80: 3ffee57c 00000000 feefeffe feefeffe
3fffff90: feefeffe feefeffe feefeffe 3ffee860
3fffffa0: 3fffdad0 00000000 3ffee830 4020acf8
3fffffb0: feefeffe feefeffe 3ffe8518 40100a71
Was ist denn der dritte Parameter bei
WiFiUdp.beginPacketMulticast(ipMulti, portMulti, WiFi.localIP()) == 1)?
Gibt es Einschränkungen für die Wahl des Ports (ich habe 82 genommen)?
Ich schau mal selber, ob ich den Fehler finde, andernfalls poste ich den Sketch.
Danke + Gruß
Peter
Edit: Da passt was mit der Konvertierung bzw. der Hauptroutine noch nicht.
Vitotronic 1-wire demo
Connecting to PMWLAN02 . connected ...
OTA initialized ...
UDP port at IP 192.168.188.28, UDP port 82 opened
Locating devices ...
Found 3 device(s).
Parasite power is: OFF
Device 0 Address: 109E85B700080021
Device 1 Address: 10C175B5020800C5
Device 2 Address: 288B22A8000000C2
String converted to array ...
O
Exception (9):
epc1=0x4020afab epc2=0x00000000 epc3=0x00000000 excvaddr=0x303d7299 depc=0x00000000
>>>stack>>>
ctx: cont
sp: 3ffffdb0 end: 3fffffc0 offset: 01a0
3fffff50: 00000003 3ffee9f8 3ffe84e4 40202c96
3fffff60: 00000000 00000000 00000000 3fff00ec
3fffff70: 0000006f 0000006d 00000000 00000000
3fffff80: 3ffee82c 00000000 feefeffe feefeffe
3fffff90: feefeffe feefeffe feefeffe 3ffeeb18
3fffffa0: 3fffdad0 00000000 3ffeeae8 4020c55c
3fffffb0: feefeffe feefeffe 3ffe8518 40100ad9
<<<stack<<<
ich würde eine Multicast-IP aus dem 239.0.0.0/24 nehmen. Der Port ist nur mit 65535 nach oben limitiert.
WiFi.localIP() ist die IP von ESP.
Kommt er denn noch zum endPacket()?
Hi,
ist denn ein privilegierter/System Port unter 1024 zu empfehlen?
Gruß Arnd
Gesendet von iPhone mit Tapatalk
Zitat von: habeIchVergessen am 12 März 2019, 23:14:24
Kommt er denn noch zum endPacket()?
er steigt schon bei
Udp.beginPacket ...
aus :o.
Gruß Peter
poste bitte mal den Quellcode und deine Netzwerk-Konfiguration (Subnetz reicht).
Hallo,
anbei der Quellcode:
//- -----------------------------------------------------------------------------------------------------------------------
// ESP8266 test sketch for the Viessmann Optolink WLAN interface 1-wire functionality
// 1-wire from https://arduino.stackexchange.com/questions/18919/how-to-read-temperature-from-multiple-ds18b20-faster
// time from https://draeger-it.blog/arduino-ein-sketch-ohne-delayms-schreiben/
// UDP and Key Value Protocol see also here: https://forum.fhem.de/index.php/topic,45545.msg917375.html#msg917375
// UDP sketch https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/udp-examples.html
//- -----------------------------------------------------------------------------------------------------------------------
// import required libraries, ESP8266 libraries >2.1.0 are required
#include <ESP8266WiFi.h> // ESP8266 core WiFi Arduino library
#include <WiFiUdp.h> // UDP communication
// for OTA update, only with valid WLAN connection
#include <ArduinoOTA.h>
// for 1-wire
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_PIN 0
#define T_PRECISION 12
#define REQUIRESALARMS false // no 1-wire alarms for this firmware necessary, redefinition from library
#define TIMEOUT 30000 // timeout for WiFi connection
// for UDP cnonnection
WiFiUDP Udp;
#define UDP_PORT 82 // UDP port to send to (alternative was 4210)
char sendPacket[] = ""; // buffer to send to UDP port
// constant for time between measurements in ms
const int UPDATE_TIME = 5000;
// variable to calculate the time between measurements
long cycle_count = -1;
// variable to store the time of the last action
long lastActionTime = -1;
// variable to check if connected to WiFi
bool connected=false;
#define BAUD_RATE 9600
// declare global variables -----------------------------------------------------------------------------------------------
// wireless network credentials
const char* ssid = "your_ssid";
const char* password = "your_password";
// hostname for this system
const char* host = "PM1wire01";
// setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_PIN);
// pass our oneWire reference to Dallas Temperature
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress devices[10];
int devicesFound = 0;
//- -----------------------------------------------------------------------------------------------------------------------
// setup
//- -----------------------------------------------------------------------------------------------------------------------
void setup(void)
{
// for timeout calculation
long start_time = 0;
long act_time = 0;
// start serial port
Serial.begin(BAUD_RATE);
// delay in order to get terminal ready after reset
delay(5000);
Serial.println("Vitotronic 1-wire demo");
Serial.println();
// connect to the wireless network, from vitotronic
// include timeout, in case WLAN for WiFi parameters is not found
start_time = millis();
act_time = millis();
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while ((WiFi.status() != WL_CONNECTED) && ((act_time-start_time)<TIMEOUT))
{
delay(500);
act_time = millis();
Serial.print(".");
}
if (WL_CONNECTED)
{
Serial.println(" connected ...");
connected = true;
}
else
{
Serial.println();
Serial.println("WiFi not found ...");
connected = false; // not necessary, because already initialized to false
}
if (connected)
{
// initialize OTA
ArduinoOTA.setPort(8266);
ArduinoOTA.begin();
Serial.println("OTA initialized ...");
Udp.begin(UDP_PORT);
Serial.printf("UDP port at IP %s, UDP port %d opened\n", WiFi.localIP().toString().c_str(), UDP_PORT);
}
// start up 1-wire bus
sensors.begin();
sensors.setResolution(12);
// locate devices on the bus
Serial.println("Locating devices ...");
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" device(s).");
devicesFound = sensors.getDeviceCount();
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
for (int i = 0; i < devicesFound; i++)
if (!sensors.getAddress(devices[i], i))
Serial.println("Unable to find address for Device " + i);
// show the addresses we found on the bus
for (int i = 0; i < devicesFound; i++)
{
Serial.print("Device " + (String)i + " Address: ");
printAddress(devices[i]);
Serial.println();
}
// set precision for all found sensors
for (int i = 0; i < devicesFound; i++)
sensors.setResolution(devices[i], T_PRECISION);
}
//- -----------------------------------------------------------------------------------------------------------------------
//- -----------------------------------------------------------------------------------------------------------------------
// function to print a device address
//- -----------------------------------------------------------------------------------------------------------------------
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
//- -----------------------------------------------------------------------------------------------------------------------
//- -----------------------------------------------------------------------------------------------------------------------
// function to print a device address
//- -----------------------------------------------------------------------------------------------------------------------
String printAddressStr(DeviceAddress deviceAddress)
{
String outstr = "";
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
if (deviceAddress[i] < 16) outstr += "0";
outstr += String(deviceAddress[i], HEX);
}
outstr.toUpperCase();
return outstr;
}
//- -----------------------------------------------------------------------------------------------------------------------
//- -----------------------------------------------------------------------------------------------------------------------
// function to print the temperature for a device
//- -----------------------------------------------------------------------------------------------------------------------
String printTemperatureStr(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC < 10)
return "0" + (String)tempC;
else
return (String)tempC;
}
//- -----------------------------------------------------------------------------------------------------------------------
//- -----------------------------------------------------------------------------------------------------------------------
// main loop
//- -----------------------------------------------------------------------------------------------------------------------
void loop(void)
{
// variable for time needed for 1-wire conversion
long time_between_measurements;
// save the time (in ms) since start of processor
long currentMillis = millis();
if (connected)
{
// handle OTA flash
ArduinoOTA.handle();
}
// here comes the code outside the 1-wire conversion
if(lastActionTime<(currentMillis-UPDATE_TIME))
{
// overwrite time stamp with actual time
lastActionTime = currentMillis;
// increment cycle_count
cycle_count++;
// start 1-wire conversion
if (devicesFound == 0)
{
Serial.println("No devices found.");
return;
}
// speed optimized code
// if still too much time is consumed, it can be done in several steps
sensors.setWaitForConversion(false); // makes it async
sensors.requestTemperatures();
sensors.setWaitForConversion(true);
String sendstr = "OK VALUES heizung 1 timer=";
sendstr += String(cycle_count*UPDATE_TIME/1000, DEC);
sendstr += ",";
// print the device information, change in case it is too slow
for (int i = 0; i < devicesFound; i++)
{
sendstr += printAddressStr(devices[i]);
sendstr += "=";
sendstr += printTemperatureStr(devices[i]);
if (i != devicesFound - 1)
sendstr += ",";
}
// get the time for conversion
time_between_measurements = millis() - lastActionTime;
sendstr += ",time_conv=";
sendstr += String(time_between_measurements, DEC);
//sendstr += " ms";
if (connected)
{
// convert string to array
sendstr.toCharArray(sendPacket, sendstr.length());
Serial.println("String converted to array ...");
//for (int i = 0; i < sizeof(sendPacket); i++)
//{
//Serial.print(sendPacket[i], ASC);
//Serial.println();
//}
Serial.print(sendPacket);
// send string to UPD port, use sendstr instead of replyPacket
Serial.println("before Udp.beginPacket ...");
//Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
//Serial.println("IPaddress %s, port %d", Udp.remoteIP().toString().c_str(), Udp.remotePort());
Udp.beginPacket(WiFi.localIP(), UDP_PORT);
Serial.println("after Udp.beginPacket ...");
Udp.write(sendPacket, sizeof(sendPacket));
Serial.println("after Udp.write ...");
Udp.endPacket();
Serial.println("after Udp.endPacket ...");
}
// get the time for sending
time_between_measurements = millis() - lastActionTime;
sendstr += ",time_all=";
sendstr += String(time_between_measurements, DEC);
Serial.println(sendstr);
}
}
//- -----------------------------------------------------------------------------------------------------------------------
Ich will eigentlich nur eine IP-Adresse per DHCP zugewiesen bekommen und da regelmäßig auf einen UDP Port Daten schreiben, die mit Deinem FHEM Modul abgeholt werden können. M.E. funktioniert das Beispielprogramm, das ich im Kopf angezogen habe auch nicht so richtig, ich habe es aber noch nie getestet.
Zitat von: habeIchVergessen am 14 März 2019, 13:53:04
... und deine Netzwerk-Konfiguration (Subnetz reicht).
Was meinst Du damit? Subnetz ist 192.168.188.x, x per DHCP und SubnetMask ist 255.255.255.0.
Danke + Gruß
Peter
habe nur den Sende-Teil in der Funktion loop() rausgezogen und geändert
if (connected)
{
Serial.print(sendPacket);
// send string to UPD port, use sendstr instead of replyPacket
Serial.println("before Udp.beginPacketMulticast ...");
// Multicast declarations
IPAddress ipMulti(239, 0, 0, 57);
unsigned int portMulti = 12345; // local port to listen on
if (Udp.beginPacketMulticast(ipMulti, portMulti, WiFi.localIP()) == 1) {
Serial.println("after Udp.beginPacketMulticast ...");
Udp.write(sendstr.c_str());
Serial.println("after Udp.write ...");
Udp.endPacket();
yield();
Serial.println("after Udp.endPacket ...");
}
}
Nachtrag: WiFiUdp angepasst (Udp)
dein Udp-Objekt ist ein UDP-Server, der lokal läuft und auf Port 82 lauscht. sofern keine Daten empfangen werden sollen, ist Udp.begin() überflüssig.
239.0.0.57:12345 ist die Multi-Cast Adresse/Port von KVPUDP
Vielen Dank, nach kleinen Anpassungen (WiFiUdp -> Udp) sendet jetzt der ESP, ich muss noch den Empfang in FHEM testen.
So richtig verstanden, warum das Programm bei mir abgestürzt ist, habe ich aber nicht.
Gruß Peter
im 1. Post ist ein kleines Perl-Skript, dass einen KVPUDP simuliert.
Bzgl. Anpassung WiFiUdp -> Udp: muss Udp heißen (meine Fehler; o. korrigiert; Objekt hat bei mir einen anderen Namen).
zum Udp-Objekt: du hast versucht, eine Nachricht an die IP des ESP zu schicken und dazu den Udp-Server verwendet, der die Nachricht empfangen muss. Wenn du die IP von deinem Router nimmst, dann sollte kein Fehler auftreten.
Hm, ich verstehe nur nicht, dass ich im Prinzip dasselbe gemacht habe, wie hier:
https://github.com/esp8266/Arduino/blob/master/doc/esp8266wifi/udp-examples.rst
nur, dass ich nichts empfange sondern gleich sende. Auf jeden Fall compiliert das Skript, verbindet sich mit dem WiFi und lauscht, ohne abzustürzen.
Oder gibt es doch noch Unterschiede?
Sorry für die ggf. unqualifizierten Fragen eines Hardware Menschen.
Danke + Gruß
Peter
Edit: selbst nach erfolgreicher Installation von
apt-get install libio-socket-multicast6-perl libdigest-crc-perl
kommt bei
reload 36_KVPUDP.pm
folgende Fehlermeldung :o:
Can't locate IO/Socket/Multicast.pm in @INC (you may need to install the IO::Socket::Multicast module) (@INC contains: . /etc/perl /usr/local/lib/arm-linux-gnueabihf/perl/5.20.2 /usr/local/share/perl/5.20.2 /usr/lib/arm-linux-gnueabihf/perl5/5.20 /usr/share/perl5 /usr/lib/arm-linux-gnueabihf/perl/5.20 /usr/share/perl/5.20 /usr/local/lib/site_perl ./FHEM ./FHEM/lib) at ./FHEM/36_KVPUDP.pm line 31.
BEGIN failed--compilation aborted at ./FHEM/36_KVPUDP.pm line 31.
Zitat von: PeMue am 15 März 2019, 19:24:15
Edit: selbst nach erfolgreicher Installation von
apt-get install libio-socket-multicast6-perl libdigest-crc-perl
kommt bei
versuch es bitte mit libio-socket-multicast
6-perl
Zitat von: PeMue am 15 März 2019, 19:24:15
Hm, ich verstehe nur nicht, dass ich im Prinzip dasselbe gemacht habe, wie hier:
im o.g. Beispiel wird erst nach erfolgreichem Aufruf von Udp.parsePacket() != 0 auf Udp.remotIP() zugegriffen. Da zu diesem Zeitpunkt ein "echter" Client-Aufruf vorliegt (der wird im ESP gecacht), kann auch eine sinnvolle IP geliefert werden.
das Senden an WiFi.localIP() funktioniert ggf. von einem anderen WiFiUDP-Objekt.
Zitat von: habeIchVergessen am 15 März 2019, 20:28:18
versuch es bitte mit libio-socket-multicast6-perl
Ja, das wars, vielen Dank.
Internals:
CFGFN
Clients :KeyValueProtocol
FD 26
MSGCNT 8
NAME vitotronic1wire
NR 848
RAWMSG OK VALUES heizung 1 timer=115,109E85B700080021=20.44,10C175B5020800C5=20.25,288B22A8000000C2=20.88,time_conv=41
STATE Opened
TIME 2019-03-15 20:31:50
TYPE KVPUDP
MatchList:
1:KeyValueProtocol ^OK\sVALUES\s
PEERS:
192.168.188.28:
IP 192.168.188.28
MSGCNT 8
RAWMSG OK VALUES heizung 1 timer=115,109E85B700080021=20.44,10C175B5020800C5=20.25,288B22A8000000C2=20.88,time_conv=41
TIME 2019-03-15 20:31:50
Attributes: