Firmata - ArduinoCommander Unterstützung

Begonnen von CaptBlaubaer, 20 November 2013, 04:50:32

Vorheriges Thema - Nächstes Thema

CaptBlaubaer

Hallo liebe FHEM Experten,

ich wünsche mir diese Unterstützung da diese, im Gegensatz zur Ethernet Firmata Lösung, das Firmata Gerät nicht als Client sondern als Server implementiert.

Der Vorteil der ArduinoCommander Lösung ist, dass die IP Adresse des FHEM Systems nicht ins Firmata Gerät programmiert werden muss. D. h., nach der "Fertigung" muss das Firmata Gerät nicht mehr von einem Programmierer angepackt werden.

Die ArduinoCommander Lösung ermöglicht es auch die Geräte automatisch durch einen IP Scan zu erkennen.

Ich hab mir zwar mal die FRM Implementierung angeschaut aber noch fehlen mir zu viele Infos um es selber zu programmieren.

(CBR)
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

wenn Du die Arduino-seite stabil bekommst, dann passe ich das FRM-modul gerne an.

Mit Stabil meine ich: man muss beliebig oft versuchen dürfen eine Verbindung zum Arduino aufzubauen, ohne diese im Anschluss sauber zu schließen und der Arduino muss trotzdem weiterhin ohne Reset für neue Requests erreichbar bleiben. Ich wüßte nicht, wie man das ohne Erweiterung der Ethernet-library hinbekommen könnte und würde mich über eine Lösung für diese Stabilitätsanforderung ganz ehrlich freuen.
Wenn das nicht gewährleisten ist, wirst Du nicht viel Freude mit dem Setup haben.

Gruß,

Norbert
while (!asleep()) {sheep++};

CaptBlaubaer

Hi Norbert,

vermute ich richtig, dass Du von den max. 4 Sockets sprichst, die im Ethernet Server unterstützt werden?
Wenn diese nicht korrekt geschlossen werden, dann werden die Verbindungen bis zu einem Timeout vom Firmata Gerät abgelehnt.
Hast Du ne Idee für einen abstrakten Sketch an dem das Verhalten möglichst einfach zu reproduzieren ist.
Ich denke man sollte die Mängel der  Ethernet lib abstellen anstatt Workarounds zu programmieren.
Zumindest sollte man es versuchen.
Bitte nicht als Kritik verstehen aber die Ethernet Lösung von Arduino ist noch eher der Spielzeugwelt zuzuordnen.
(Keine Reset Möglichkeit, keine Erkennung ob überhaupt ein Ethernet Shield vorhanden, deshalb auch keine Erkennung ob der LAN Controller hängt, ........)
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

Zitat von: CaptBlaubaer am 20 November 2013, 17:18:12
vermute ich richtig, dass Du von den max. 4 Sockets sprichst, die im Ethernet Server unterstützt werden?
Ja, richtig. Nur dass es nicht einfach nur die EthernetServer-klasse ist, sondern der W5100-chip selbst gar nicht mehr kann (wobei es schon sehr helfen würde, wenn die EthernetClient-klasse mehr über den Status der verwalteten Verbindung verraten und EthernetServer die aktuell verbundenen Clients direkt zugänglich machen würde). Mit meiner UIPEthernet-library für ENC28J60 ist man zwar nicht grundsätzlich auf 4 TCP-verbindungen beschränkt (kann man in uipethernet-conf.h einstellen), aber bei den beschränkten Resourcen eines ATmega328 kann man realistischerweise sowieso nicht signifikant mehr verwalten.

Eine möglichst dauerhaft verbundene Socket-verbindung im Server-mode müsste so verwaltet werden:

1. kein Client verbunden, Socket im Listen-mode
2. Socket-Accept -> Annahme der neuen Verbindung (Client-objekt in einer globalen Variable speichern, damit es beim nächtsten Durchlauf durch loop noch da ist)
3. Falls die Verbindung von der Gegenseite geschlossen wurde (Client.connected() == false), stop aufrufen und Client verwerfen. -> Goto 1
4. Kommunikation mit dem Client.
5. wieder testen ob Socket-Accept, wenn nein -> goto 3.
6. falls neue Verbindung, bisherigen Client stoppen, neuen benutzen, goto 3.

Gruß,

Norbert
while (!asleep()) {sheep++};

CaptBlaubaer

Hi Norbert,

hast Du mir ein Testszenario, das die Probleme reproduzierbar beschreibt?

Anscheinend gibt es ja auch relativ stabile Applikationen, wie der Web Server von
SurferTim:
Zitathttp://forum.arduino.cc/index.php?topic=197103.0
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

#5
Bei einem Webserver darf (bzw. wird) die Verbindung nach jedem Request oder beim Auftreten eines Fehlers einfach geschlossen, dazu noch einen applikationsseitigen Timeout falls kein gültiges Request-ende im Datenstrom erkennbar ist (oder gar nix reinkommt). Das http-protokoll ist vom Design her schon robust im Hinblick auf clientseitig nicht geschlossene Verbindungen ausgelegt.
Das kannst Du nicht mit der Anforderung eine tcp-Verbindung dauerhaft offen zu lassen vergleichen.
Wobei der Webserver von Surfertim auch nicht in der Lage ist Anfragen anzunehmen, wenn schon 4 verbundene Http-Request anstehen.

Als Testszenario kannst Du einfach versuchen mit mehreren Telnetfenstern parallel zu verbinden. Mit jedem neuen Verbindungsaufbau müssen die vorher geöffneten Verbindungen automatisch vom Arduino beendet werden, dann taugt es für Firmata.

- Norbert

while (!asleep()) {sheep++};

CaptBlaubaer

Hi Norbert,

Zitat von: ntruchsess am 21 November 2013, 15:19:10
Das http-protokoll ist vom Design her schon robust im Hinblick auf clientseitig nicht geschlossene Verbindungen ausgelegt.
Warum sollte dies dann nicht auch bei Firmata funktionieren?

Zitat von: ntruchsess am 21 November 2013, 15:19:10
Wobei der Webserver von Surfertim auch nicht in der Lage ist Anfragen anzunehmen, wenn schon 4 verbundene Http-Request anstehen.
Das ist weder bei dem Web-Server noch bei Firmata nötig. Selbst mit den 4 Sockets können genügend redundante FHEM Systeme gleichzeitig auf das Firmata Gerät zugreifen. Mehr als zwei parallele Sockets sind, IMHO, für Firmata Applikationen also nicht nötig.

Zitat von: ntruchsess am 21 November 2013, 15:19:10
Mit jedem neuen Verbindungsaufbau müssen die vorher geöffneten Verbindungen automatisch vom Arduino beendet werden, dann taugt es für Firmata.
Diese Aussage kann ich so nicht nachvollziehen, denn das automatische Beenden von funktionsfähigen Verbindungen führt eher zu Problemen und Missverständnissen.

Ich werd mir mal einen Sketch überlegen mit dem ich das Verhalten von Firmata-Server simulieren kann.
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

CaptBlaubaer

"Firmata"-Server Simulator zur Demo der Verbindungen (leicht veränderter Chat Server)

Mit Telnet können 4 Verbindungen gleichzeitig zum Arduino aufgebaut werden. Weitere Telnet Verbindungen laufen in einen Timeout.
Der Server sendet alle 1000 ms einen Wert an alle offenen Telnet Verbindungen.
Eingaben über Telnet werden zu der Telnet Instanz zurückgespiegelt von der der Server sie empfangen hat (als einfache Form der Verarbeitung)
/*
DHCP Chat  Server

A simple server that distributes any incoming messages to all
connected clients.  To use telnet to  your device's IP address and type.
You can see the client's input in the serial monitor as well.
Using an Arduino Wiznet Ethernet shield.

THis version attempts to get an IP address using DHCP

Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13

created 21 May 2011
modified 9 Apr 2012
by Tom Igoe
Based on ChatServer example by David A. Mellis

*/

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
// gateway and subnet are optional:
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
IPAddress ip(192,168,1, 177);
IPAddress gateway(192,168,1, 1);
IPAddress subnet(255, 255, 0, 0);

// telnet defaults to port 23
EthernetServer server(23);
//boolean gotAMessage = false; // whether or not you got a message from the client yet

/* timer variables */
unsigned long currentMillis;        // store the current value from millis()
unsigned long previousMillis;       // for comparison with currentMillis
int samplingInterval =1000;          // how often to run the main loop (in ms)

unsigned int i = 0;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  // this check is only needed on the Leonardo:
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // start the Ethernet connection:
  Serial.println("Trying to get an IP address using DHCP");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    Serial.println("Use default values");
    // initialize the ethernet device not using DHCP:
    Ethernet.begin(mac, ip, gateway, subnet);
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  ip = Ethernet.localIP();
  Serial.println(ip);

  Serial.println();
  // start listening for clients
  server.begin();

}

void loop() {
  // wait for a new client:
  EthernetClient client = server.available();

  currentMillis = millis();
  if (currentMillis - previousMillis > samplingInterval) {
    previousMillis += samplingInterval;
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
    server.println(i); // server writes to all clients
    i++;
  }

  if (client) {
    // read the bytes incoming from the client:
    char thisChar = client.read();
    // echo the bytes back to the client:
    client.write(thisChar);
    // echo the bytes to the server as well:
    Serial.print(thisChar);
  }
}

Vielleicht kann man an dem abstrakten Beispiel aufzeigen wo noch Bedarf für Verbesserungen an der Ethernet Implementierung besteht.

Funktioniert bei mir meistens, manchmal gibt es Aussetzer, d.h. die regelmässigen Werte werden nicht vollständig empfangen.
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

Firmata ist designed mit genau einem Stream zu arbeiten. Wie bildest Du mehr als eine offene Verbindungen darauf ab?

- Norbert
while (!asleep()) {sheep++};

CaptBlaubaer

Ach deshalb willst Du eine bestehende und funktionierende Verbindung kappen wenn eine neue Anfrage kommt.

Für die meisten Anwendungen genügt es, wenn die Daten nur von einem System (z.B. FHEM) verarbeitet werden.
Wenn eine höhere Verfügbarkeit gefordert ist, sollten die Werte von einem, redundanten System zusätzlich verarbeitet werden. Dies kann man ja ganz bewusst für die Firmata Lösung ausschliessen. Zumindest bis die Anforderungen genau definiert sind.

Bei der Arduino Serverlösung ist es für mich schwer nachvollziehbar an welchen Socket die Werte geliefert werden. Ich bekomme zwar ein Handle auf einen Client wenn dieser Daten gesendet hat aber keine Zuordnung zu einem Socket(IP,Port).
Wenn man für Firmata sowieso nur einen Socket definiert, warum beschränken wir dann die Anzahl nicht einfach auf 1?
Damit sollte doch die Client - Socket Zuordnung klar definiert sein, oder habe ich noch etwas übersehen?
Eigentlich sollte man dann die EthernetStream Klasse aus  dem ArdCommander verwenden können
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

Zitat von: CaptBlaubaer am 22 November 2013, 16:14:47warum beschränken wir dann die Anzahl nicht einfach auf 1?
Endlich reden wir nicht mehr aneinander vorbei ;-)
Der Listen-socket im W5100 nimmt ja weitere Verbindungen an. Auch wenn man die nicht unmittelbar (als Client-objekt) nutzt, sind die doch schon verbunden.
while (!asleep()) {sheep++};

CaptBlaubaer

#11
Wenn ich gemein wäre hätte ich jetzt gesagt :"Zwei Dumme, ein Gedanke!"
Bin ich aber natürlich nicht und würde es auch nie sagen.

Hab' dazu ne Weile gebraucht, weil so TCP/IP nun mal nicht funktioniert, zumindest nicht in "richtigen" Geräten.

Werde meine Weltsensation an ChatServer mal auf einen Socket umstellen und schauen was passiert.

Also:
In der Ethernet.cpp folgendes geändert

// XXX: don't make assumptions about the value of MAX_SOCK_NUM.
uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { 0 };
//  0, 0, 0, 0 };
uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {  0 };
//  0, 0, 0, 0 };


In der Ethernet.h geändert
#define MAX_SOCK_NUM 1


Jetzt akzeptiert der ChatServer nur noch eine Verbindung.



Noch nicht verstehe ich, warum ich den unflexiblen Teil der Ethernet.cpp nicht auskommentieren kann und durch einen Constructor in der .h ersetzen kann.
/*  EthernetClass() {
    for ( int i = 0; i < MAX_SOCK_NUM; i++) {
      // XXX: don't make assumptions about the value of MAX_SOCK_NUM.
      _state[i] = 0;
      _server_port[i] = 0;  
} // for
  } //EthernetClass()
*/
  static uint8_t _state[MAX_SOCK_NUM];
  static uint16_t _server_port[MAX_SOCK_NUM];


Fehlermeldung mit constructor:
src\EthernetClient.cpp.o: In function `EthernetClient::stop()':
C:\Users\Arduino\Downloads\arduino-1.5.4\libraries\Ethernet\src/EthernetClient.cpp:143: undefined reference to `EthernetClass::_server_port'


Vielleicht gibt's ja einen C++ Experten der das versteht.
Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

Zitat von: CaptBlaubaer am 22 November 2013, 23:20:43
In der Ethernet.h geändert
#define MAX_SOCK_NUM 1

Jetzt akzeptiert der ChatServer nur noch eine Verbindung.

Das ist nicht zielführend, die library selbst verwaltet so zwar nur noch 1 Verbindung, die Hardware (der W5100-chip) selbst weiß nur nix davon.

- Norbert
while (!asleep()) {sheep++};

CaptBlaubaer

Hi Norbert,

also bei dem DHCPServer mit einem Socket wird genau eine Verbindung geöffnet.
Das ist IMHO eigentlich schon das was für eine Firmata gefordet ist. Die Hardware öffnet die Sockets ja nicht aus Jux und Dollerei, sondern weil die Library die Öffnung (listen()) anfordert. Was braucht die Firmata mehr?
Zitat von: ntruchsess am 23 November 2013, 11:01:29
Das ist nicht zielführend, die library selbst verwaltet so zwar nur noch 1 Verbindung, die Hardware (der W5100-chip) selbst weiß nur nix davon.

- Norbert

Best regards und viele Gruesse,
CaptBlaubaer (CBR)
_________________________________
FHEM 5.5 Raspberry Pi (B), IOMEGA iConnect, Firmata Arduinos USB/LAN, Gembird USB/LAN, ToDo: FHEM auf FritzBox 7390, 7270

ntruchsess

Probier mal folgendes aus: Verbinde zu Deinem 1-Channel chat-server, dann zieh das Netzwerkkabel am Arduino ab, beende das telnet und stecke anschließend das Kabel wieder dran. Jetzt öffnest Du ein neues Telnet und verbindest Dich wieder.
Wenn das wiederholbar jedes mal beim ersten Versuch klappt, dann taugt es.
while (!asleep()) {sheep++};