NodeMCU + KeyValueProtocol + FHEM-Modul

Begonnen von habeIchVergessen, 11 Dezember 2015, 22:37:17

Vorheriges Thema - Nächstes Thema

Mad-at

#45
Danke! Ich nutze das zuletzt von Dir gepostete:
Zitat von: habeIchVergessen am 18 Juli 2017, 23:56:00

Code (Zeilen196 bis 206) Auswählen

  }
  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!

habeIchVergessen


PeMue

#47
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)
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

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;
  }

PeMue

#49
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<<<
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

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()?

RaspiLED

#51
Hi,

ist denn ein privilegierter/System Port unter 1024 zu empfehlen?

Gruß Arnd


Gesendet von iPhone mit Tapatalk
Raspberry Pi mit FHEM, CUL, Signalduino, MySensors, HomeBridge, Presence, WifiLight2, Bravia, ...

PeMue

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
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

poste bitte mal den Quellcode und deine Netzwerk-Konfiguration (Subnetz reicht).

PeMue

#54
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
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

#55
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

PeMue

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
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

#57
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.

PeMue

#58
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.
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

habeIchVergessen

#59
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-multicast6-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.