Problem: Arduino mit Ethernet Shield über ReST api an deConz

Hallo Zusammen,

folgender Hintergrund, ich versuche Ikea Tradfri Lampen mit einem Arduino über einen
Raspberry Pi mit DeConz über die ReST API zu steuern.

nach langem hin und her und Probieren und googlen habe ich auch die richtige Zusammensetzung
des HTML PUT Befehls gefunden und es funktioniert.

Im Ersten Ansatz, hatte ich das Zusammenstellen und Senden in einer extra Funktion, habe dies aber
aufgrund der Probleme wieder in den Loop gezogen.

Auch das zum Testen angesetzte Timing von 4 Schaltzuständen ob mit oder ohne delay habe
ich durch senden eines Serial Kommandos ersetzt um die Fehlerquelle auch auszuschließen.

Nun zum Problem:

Am Anfang ist alles ok, ich sende das Serial Kommando "LIGHT 1 20" es wird per HMTL gesendet,
es erfolgt die Rückmeldung dass der Status gesetzt wurde, die Lampe geht auf Wert 20.
Dann sende ich "LIGHT 1 40" auch das geht usw. usw.

Rückmeldung Serial:

10 (Kontrolle für die Länge)
0 (Kontrolle für false)
0 (Kontrolle für false)
PUT /api/720FC36C33/lights/1/state HTTP/1.1
Host: 192.168.5.60
Connection: close
Content-Type: application/json
Content-Length: 10
{"bri":40}
Abfrage
Success
1
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length:40
Connection: close
ETag:"d5b1c44e68e46da9ba27727e80b128fb"
[{"success":{"/lights/1/state/bri":40}}]

Bis dann nach ca 10x (mal mehr mal weniger)
Nur noch ausgegeben wird

10
*0 *
*0 *
PUT /api/720FC36C33/lights/1/state HTTP/1.1
Host: 192.168.5.60
Connection: close
Content-Type: application/json
Content-Length: 10
{"bri":20}
closing connection

und irgendwann nur noch:

10
0
0
closing connection

Am Anfang mit dem Senden in der Funktion, lief der Loop nicht mehr!
Jetzt wo das ganze im Loop ist, läuft das Blinken LED 13 weiter, nur
es wird nichts mehr abgesetzt....

Dazu gesagt sei noch, dass über den Webbrowser mit REST Plugin es so fot geht
wie man möchte... nur mit dem Arudino nicht..

Hat jemand ne Lösung, Verbesserung, Vorschlag???

Hier der Code:

Danke
Gruß Jens

#include <SPI.h>
#include <Ethernet.h>
#include <string.h>

byte mac[]     = { 0x90, 0xA2, 0xDA, 0x0D, 0x83, 0x9D };
byte ip[]      = { 192, 168,   5,  74 };
byte gateway[] = { 192, 168,   5,  1 };
byte subnet[]  = { 255, 255, 255,   0 };
String befehl;
String befehl2;
String ContentLength;
boolean gesendet = false;

byte ledPin = 13;
boolean value = LOW;
unsigned long previousMillis = 0;
unsigned long intervalBlink = 1000;


void setup()
{
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  delay(1000);
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  EthernetClient client;
  IPAddress server(192, 168, 5, 60);

  if (Serial.available() > 0)
  {
    if (Serial.findUntil("LIGHT", "\n"))
    {
      int RCval = Serial.parseInt();
      int RCval1 = Serial.parseInt();

      //Befehl zusammensetzten
      befehl = "PUT /api/";
      befehl += "720FC36C33";
      befehl += "/lights/";
      befehl += RCval;
      befehl += "/state HTTP/1.1";

      //Befehl2 zusammensetzten
      befehl2 = "{\"";
      befehl2 += "bri";
      befehl2 += "\":";
      befehl2 += RCval1;
      befehl2 += "}";

      int Laenge = befehl2.length();
      Serial.println(Laenge);

      ContentLength = "Content-Length: ";
      ContentLength += Laenge;
      ContentLength += "\r\n";
      
      gesendet = false;
      Serial.println(gesendet);

      // Senden mit wiederholung bis "Success" Rückgemeldet wird
      if (gesendet == false)
      {
        Serial.println(gesendet);
        EthernetClient client;
        IPAddress server(192, 168, 5, 60);
        if (client.connect(server, 80))
        {
          client.println(befehl);
          Serial.println(befehl);
          client.println("Host: 192.168.5.60");
          Serial.println("Host: 192.168.5.60");
          client.println("Connection: close");
          Serial.println("Connection: close");
          //client.println("Content-Type: application/x-www-form-urlencoded");
          //Serial.println("Content-Type: application/x-www-form-urlencoded");
          client.println("Content-Type: application/json");
          Serial.println("Content-Type: application/json");
          client.println(ContentLength);
          Serial.println(ContentLength);
          client.println(befehl2);
          Serial.println(befehl2);
        }
        delay(20);

        // Rückmeldung auslesen, Success finden und Serielle ausgabe
        if (client.available()) {
          Serial.println("Abfrage");
          String str = client.readString();
          gesendet = true;
          if (strstr(str.c_str(), "success") != NULL)
          {
            Serial.println("Success");
            gesendet = true;
            Serial.println(gesendet);
          }
          Serial.print(str);
        }
        delay(500);
      }
      Serial.println();
      Serial.println("closing connection");
      //gesendet = true;

    }
  }

  if (millis() - previousMillis > intervalBlink) {
    previousMillis = millis();
    value = !value;
    digitalWrite(ledPin, value);
  }
}

Du verwendest im Loop die String-Klasse. Das ist auf einem Arduino keine gute Idee, da dadurch der Speicher fragmentiert wird und damit wie aufgebraucht wird. Danach ist unbestimmtes Verhalten angesagt.

Du wirst das umschreiben müssen auf C-Strings, also CharArrays, die mit '\0' abgeschlossen sind. Als Hilfestellung kann ich Dir Infos zu Zeichenketten in C anbieten.

Gruß Tommy

Hi Tommy,

Danke für die schnelle Antwort.

Die Umstellung von String in CharArrays, beziehst Du Dich hierbei
auf die Serial Seite oder im HTML Bereich unten bezüglich der Rückmeldung

Also Umstellen auf:

if (client.available())
{
  char c = client.read();
  Serial.print(c);
}

oder der des Sendens? Oder alle?

Danke
Gruß Jens

Alle natürlich :wink:

Gruß Tommy

Hallo,

Momentan habe ich Probleme, wie ich denn den ausgelesenen int in den char bekomme,

mit
sprintf(val,"%ld", RCval);

macht er aus einer 1 im int dann 38928385 im char

den int direkt reinhängen mit strcat macht er nicht, da er dann an der Stelle ein Quadrat einsetzt

#include <SPI.h>
#include <Ethernet.h>

byte mac[]     = { 0x90, 0xA2, 0xDA, 0x0D, 0x83, 0x9D };
byte ip[]      = { 192, 168,   5,  74 };
byte gateway[] = { 192, 168,   5,  1 };
byte subnet[]  = { 255, 255, 255,   0 };

//char befehl[50];
char val[5];


void setup()
{
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  delay(1000);
}

void loop()
{
  if (Serial.available() > 0)
  {
    if (Serial.findUntil("LIGHT", "\n"))
    {
      int RCval = Serial.parseInt();
      int RCval1 = Serial.parseInt();
      sprintf(val,"%ld", RCval);

      char befehl[50] = "PUT /api/";
      strcat(befehl, "720FC36C33");
      strcat(befehl, "/lights/");
      strcat(befehl, val);
      strcat(befehl, "/state HTTP/1.1");
      Serial.println(befehl);

    }
  }
}

Kann doch eigentlich nicht so schwer sein oder?

Hat jemand einen Tipp?

Danke

Gruß Jens

Erweitere mal den "val" von 5 Zeichen auf 8, also char val[8]

Hat leider nichts gebracht, schade.

Du fängst von der falschen Seite an. Da Du ohne String auch kein ParseInt hast, stellt sich Dir diese Frage dann nicht mehr.

Du musst erst mal Zeilenweise in ein CharArray einlesen und wenn Du ein '\n' findest, die Zeichenkette mit '\0' abschließen.
Dann kannst Du schauen, ob da LICHT drin steht.

Gruß Tommy

Puh, da hast mir aber einen Auftrag gegeben.... :o

nungut, bin auf dem Weg.

Habe aber moment aber das Problem, dass die Rückmeldung vom Gateway nicht komplett ausgegeben wird.
allerdings würde ich sagen, brauche ich ja auch nicht alles sondern nur den Body mit der Rückmeldung und nicht den Header.

Evtl. n Tipp?

Danke

Gruß Jens

Hallo Zusammen,

hat evtl. noch jemand einen Tipp, das Rückmeldung auslesen Problem ist eher zweitrangig.

Hauptproblem, das Gateway nimmt nicht jedes Mal den Befehl entgegen, mal geht es auch mehrere Male
hintereinander, mal nicht.

Also habe ich mit Wireshark geschaut was ankommt.

Seitens Firefox REST Plugin:

PUT /api/720FC36C33/lights/1/state HTTP/1.1
Host: 192.168.5.60
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64;rv:54.0) Gecko/20100101 Firefox/54.0
Accept: */*
Accept-Language: null
Accept-Encoding: gzip, deflate
Content-Length: 11
Content-Type: text/plain; charset=utf-8
Connection: keep-alive\r\n
{“on”:true}

seitens Arduino, auch jedes Mal gleich, ob es angenommen wird oder nicht:

PUT /api/720FC36C33/lights/1/state HTTP/1.1
Host: 192.168.5.60
Content-Length: 11
Content-Type: text/plain; charset=utf-8
Connection: keep-alive\r\n
{“on”:true}

1:1 das selbe zu senden wie Firefox REST Plugin funktioniert überhaupt nicht.

Hat jemand eine Idee, was evtl. noch entscheidend ist, dass das Gateway den Request verarbeitet?

Danke

Gruß Jens

Sorry, my German is not that good, but I came across this topic on my way of looking for a solution to turn on/off my DeConz controlled ZigBee lights via Arduino. After a lot of trial and error, this is the simplest solution I have found:

#include <ArduinoHttpClient.h>
char httpserverAddress[] = "192.168.0.2"; // server address
HttpClient httpclient = HttpClient(ethClient, httpserverAddress, port);

boolean ok=false;
unsigned long timestart=millis(); // save for 15 seconds timeout
while ( ok != true && (millis()-timestart) < 15000)
{
delay(1000);
Serial.println("Sending");
httpclient.put("/api/BD0AB797F7/lights/32/state", "Content-Type: application/json", "{"on": true}");
delay(20);
Serial.println(F("CHECK Response"));
String str = httpclient.readString();
Serial.print(str);
if (strstr(str.c_str(), "success") != NULL)
{
Serial.println("Success");
ok=true;
}
else
{
delay(5000);
}
}