[Risolto] - Ricezione UDP da scheda di rete Netman Plus

BuonGiorno,
ho comprato la Ethernet Shield con l'intenzione di comunicare direttamente con la scheda di rete Netman Plus 102 montata sull'inverter dell'impianto fotovoltaico.
La scheda di rete supporta sia SNMP che UDP. Inizialmente sono partito con l'SNMP ma poi ho visto che esiste la libreria EthernetUDP quindi sto provando con quella.
Purtroppo però non riesco a ricevere nulla :0(

Pacchetti in rete dovrebbero essercene perché sul PC mi gira un programma che mostra i dati relativi alla produzione e se dalla Scheda di Rete disabilito la trasmissione UDP oppure cambio la porta, il programma sul PC non riceve più niente.

Ho provato ad utilizzare lo sketch di Esempio UDPSendReceive mettendo:

IPAddress ip(192, 168, 0, 10); // IP assegnato ad Arduino dal Router
unsigned int localPort = 33000; // Porta utilizzata dalla Netman Plus per l'UDP.

il resto dell'esempio è rimasto uguale. Ho solo commentato la parte di codice che Invia la risposta:
// send a reply, to the IP address and port that sent us the packet we received
// Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
// Udp.write(ReplyBuffer);
// Udp.endPacket();

Ma non riesco a ricevere niente.
Cosa sbaglio? Cosa posso provare?

Alessio.

Prova prima a vedere su PC il tipo di dati che trasmette la centralina. Usa uno sniffer tipo wireshark.

Ciao Paolo,
grazie per la risposta.

Ho seguito il tuo consiglio e utilizzando WireShark su PC vedo i Pacchetti UDP che transitano dall'IP dell'Inverter all'IP del mio PC sulla porta.
Porta utilizzata dall'inverter 33000 (come da configurazione).
Porta utilizzzata dal PC mcs-fastmail (ovvero 3302).

Ho provato allora a cambiare la porta configurata nello sketch mettendo 3302 ma niente. Poi ho provato a configurare l'inverter sulla porta 8888 (quella di default dello sketch di esempio per l'EthernetUDP) ma niente lo stesso, c'è comunque comunicazione tra Inverter e PC ma Arduino resta sordo come una campana!

Nel pacchetto UDP ci sono informazioni che potrebbero essere utili per venirne fuori?

Controlla che non sia il PC che inizializza la trasmissione e l'inverter risponda solamente.
Vedi se oltre all'UDP il PC esce con una trasmissione TCP. Su wireshark, senza filtri, dovresti visualizzare tutto il traffico in entrata e in uscita.

Eccomi qui.
Dunque, dopo aver visto con WireShark che prima partiva un pacchetto dal PC e l'Inverter rispondeva ho provato a fare lo stesso con Arduino.
Se prima invio un pacchetto con un messaggio qualsiasi poi ricevo una risposta.
E qui nascono nuove problematiche.
Nella console di arduino quando vado a "stampare" il pacchetto ricevuto non lo visualizzo. Mi dice che ho ricevuto un pacchetto lungo 690 ma non vedo niente.
Ho fatto altre prove creando sul pc un ServerUDP. Qui lo scambio di messaggi tra PC e Arduino funziona a dovere.
Ma la domanda principale a questo punto è:
ammesso che io riesca a visualizzare i Dati del pacchetto inviato dall'Inverter, temo che dovrei avere anche l'informazione di come mappare poi quella lunga stringa di numeri e lettere. Altrimenti chi me lo dice dove si trova la tensione, la corrente, la potenza... Insomma, nel CD della Scheda di Rete che ho montato sull'inverter non ho trovato nulla. UDP non funziona come l'SNMP che ha i file .mib come descrittori dei dati? Altrimenti non mi resta che contattare la casa produttrice della scheda di rete.

Aggiungo che ho provato ad utilizzare la libreria Agentuino per utilizzare il protocollo SNMP ma.. questa non riesco nemmeno a compilarla :0((((
Suggerimenti?

Ciao,

come ti è stato consigliato devi capire quale sia il flusso delle informazioni, ci sono due possibilità: 1) il PC richiede i dati all'inverter; 2) l'inverter fa broadcast dei dati.

Nel primo caso troverai pacchetti con indirizzi IP sorgente e destinazione pari a quelli del PC e dell'inverter, nel secondo ci sarà solo quello dell'inverter.

L'aspetto più importante è un'altro, UDP è un protocollo di trasporto, ovvero non definisce alcuna struttura dati il che significa che pur riuscendo a ricevere non avrai qualcosa di automaticamente intellegibile.
Nel tuo caso, con buona probabilità, l'inverter utilizza un protocollo Modbus (anche se normalmente non viaggia su UDP), se inserisci la parte "Data" dei pacchetti visti in WireShark posso dirti se il protocollo sia o meno quello.

Saluti,
Dario.

Sembrerebbe che il Client richiede i dati all'inverter perché da WireShark ci sono pacchetti con ip sorgente e destinatario precisi.
Cronologicamente prima un pacchetto da PC a Inverter e poi l'Inverter risponde.

Dovrei aver allegato 2 file.
Data da Inverter è l'export del solo campo data del pacchetto in arrivo dall'inverter.
ComunicazioneUDP è il salvataggio del FollowUDPStream.

Se riesci a visualizzarlo, per maggior chiarezza sappi che 192.168.0.5 è il PC mentre 192.168.0.60 è l'Inverter.

Data da Inverter (690 Bytes)

ComunicazioneUDP (11.8 KB)

Senza estensione non riesco ad aprirli, puoi dirmi qual'è l'estensione di salvataggio? Al volo, viene riportato Modbus (o un altro tipo di protocollo) nel datatype?

Saluti,
Dario.

Hai ragione, sorry.
Io stesso non so come riaprili ;0PP

Carico un altro file:

PacchettoDaInverter

questo lo puoi aprire direttamente con Wireshark e contiene lo scambio tra PC (192.168.0.5) e Inverter (192.168.0.60).

Ho dato un'occhiata ma di protocolli particolari non ho vistro traccia... almeno non mi pare :0(

Alessio ;0)

Ps: Hai per caso esperienza anche con Agentuino?

PacchettoDaInverter.pcapng (4.61 KB)

In effetti non è uno di quei protocolli riconosciuti, quindi con buona probabilitàè un protocollo proprietario. Questo però non significa che l'inverter non supporti anche protocolli standardizzati, come primo passo direi di verificare sulla scheda tecnica dell'inverter se esistono altri protocolli supportati.

Se così non fosse, dovresti provare a fare un reverse, non dovrebbe essere poi troppo complesso perché sembra che ci sia sempre la stessa richiesta. Posso provare a darti una mano, però è un lavoro che non necessariamente giunge a buon fine.

Saluti,
Dario.

Non ho mai utilizzato la librerie Agentuino, ho dato un occhio al volo e non è chiaro se quella libreria implementa un manager o meno. Mi aspetto che l'inverter sia un nodo managed che quindi fornisca le informazioni al manager, tu avresti bisogno di un manager per raccogliere i dati lato arduino.

In generale se non sei riuscito a compilare è perché la libreria è ferma alla IDE0019, contro l'attuale IDE100 (o 1), se cerchi nel forum dovresti riuscire a trovare una guida per migrare la libreria alla IDE attuale o in alternativa utilizzare la IDE0019 (sconsigliato).

Se andiamo avanti per passi vediamo se questa strada sia percorribile.

Saluti,
Dario.

Qui un topic sull'Agentuino --> http://arduino.cc/forum/index.php/topic,50848.0.html

Grazie ragazzi,
grazie a tutti per la gentilezza e la disponibilità ;0)

Mi studio un po la discussione su Agentuino che ha linkato Paolo (non vado proprio spedito spedito con l'Inglese).
Sono riuscito a compilare l'esempio di Agentuino. Poi ho messo su una sorta di client in java sul pc per fare chiamate SNMP verso Arduino ma non ha funzionato, o il PC non ha chiamato o Arduino non ha ricevuto.
Purtroppo le prove con l'Inverter le posso fare solo di giorno (per ovvi motivi) e domani lavorerò quindi per le prove pratiche se ne riparlerà dopodomani.

Non voglio però abbandonare la via parallela dell'UDP.

Per quel che mi pare di capire l'UDP va bene per fare cose personalizzate. Se sono io che chiamo e rispondo l'UDP va bene, altrimenti forse è più opportuno l'SNMP.
Alla fine quello migliore sarà quello che funzionerà prima ;0))))

Alessio ;0)

Ehi, forse sto proprio fuori io ma da quel che capisco Agentuino è una libreria che ti permette di ricevere delle richieste e fornire delle risposte.
Ma proprio non riesco a capire se si può usare per fare delle richieste e ricevere delle risposte!!

In attesa di un vostro parere mi ributto un po sulla EthernetUDP.

Allora facciamo chiarezza. UDP è il protocollo di trasporto dati, ma non fornisce nessuna indicazione sul tipo di dati trasportati e quindi sulla loro codifica.
L'SNMP è un protocollo che usa l'UDP (ma volendo può usare anche il TCP) come protocollo per il trasporto dati, e ma dice anche come vanno codificati i comandi e come vanno fatte le richieste. Essendo uno standard che si pone come sistema di comunicazione semplificato per qualsiasi tipo di macchina, non sono definiti i comandi disponibili, ma solo come vanno "richiesti". Diciamo che ci sono due famiglie di comani, quelli per fare le impostazioni e quelli per leggere le impostazioni/dati.

Quindi quei dati grezzi che hai letto via UDP non sono altro che i comandi SNMP

I comandi disponibili per la determinata macchina li hai attraverso i MIB file che fornisce il venditore.

altre info: Simple Network Management Protocol - Wikipedia

quindi devi capire come inviare le richieste che ti interessano usando la libreria che hai trovato, per il resto fregatene di UDP che fa tutto la libreria

Eh, la libreria che ho trovato (e che mi sembra essere l'unica per l'SNMP con Arduino) è appunto Agentuino le cui mie considerazioni sono poco sopra.

Io non capisco come fare una Richiesta DA Arduino VERSO l'Inverter.
Ho i MIB e conosco i "codici" per richiedere i dati che mi servono, li ho utilizzati nel programma Java che ho sviluppato per provare l'SNMP.
Ma se con Java faccio snmp.get(pdu, comtarget), quale è il relativo metodo get nella libreria Agentuino?

c'è un esempio nella libreria: Google Code Archive - Long-term storage for Google Code Project Hosting..
però serve per fare l'agent, ovvero "il server", mentre a te serve "il client" che non mi sembra essere implementato.

mi sa che devi litigare con le RFC, comunque la veriosne 1 e 2 non sono criptate ma non sono nemmeno compatibili. vedi http://www.rane.com/note161.html

aiutati con wireshark a decodificare le risposte, per le richieste invece puoi copiare direttamente il contenuto delle richieste fatte da java

Dunque, ho risolto i miei problemi con la libreria EthernetUDP.

Incollo di seguito lo Sketch risultante e che per quel che mi riguarda chiude la prima fase del mio progetto:

 /*
 	Sketch che mi permette di interrogare l'Inverter di un impianto Fotovoltaico per farmi restituire in tempo reale i Watt generati.
 	Invio una richiesta all'Inverter, leggo la Risposta, la converto in una Stringa Esadecimale e ne estraggo le sole parti che mi interessano.
 	L'impianto Fotovoltaico è Trifase quindi dalla Stringa Esadecimale dovrò estrarre la potenza generata su ogni fase e sommarle.
  
     Alessio Zelati.
 */

#include <SPI.h>         // needed for Arduino versions later than 0018
#include <stdlib.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008

// MacAddress dell'Ethernet Shield
byte mac[] = { 0x00, 0x1D, 0x60, 0xAF, 0x03, 0x31 };
// IpAddress assegnato allo Shield
IPAddress localIp(192, 168, 0, 10);

//IPAddress del Managed, ovvero l'oggetto a cui vogliamo rivolgere richieste
IPAddress remoteIp(192, 168, 0, 60);

// Il pacchetto inviato come richiesta al Managed.
// Io l'ho copiato da uno inviato da un programma su PC ed intercettato con WireShark.
// Mi sembra però di capire che si ottiene una risposta anche se si invia un pacchetto vuoto.
const int PACKET_SIZE = 1;
byte packetRequest[] = { 0x00 };

// buffers per la ricezione dei dati.
// Lo faccio lungo 700 perché i pacchetti in arrivo so che sono lunghi 690.
byte packetBuffer[700];
String pacHex;  // Stringa in cui verrà "scompattato" il pachetBuffer traducendolo in una Stringa Esadecimale.

EthernetUDP Udp; // No Comment.

void setup() {
  Ethernet.begin(mac, localIp);
  Udp.begin(8888);
  Serial.begin(9600);
}

void loop() {
// Invio un pacchetto qualsiasi
    Udp.beginPacket(remoteIp, 33000);  // 33000 è la porta del Managed su cui è attiva la comunicazione UDP.
    Udp.write(packetRequest, PACKET_SIZE);
    Udp.endPacket();
    
    Serial.println("Inviato Pacchetto");
    delay(100);

    int packetSize = Udp.parsePacket(); 
    if(packetSize) {
      Serial.print("Ricevuto pacchetto. Size: ");
      Serial.println(packetSize);
  
      Udp.read(packetBuffer, packetSize);

// Trasforma il packetBuffer in una Stringa di caratteri Esadecimali
      for (int x = 0; x < packetSize; x++) {
        String a = String(packetBuffer[x], HEX);
        pacHex += (a.length() < 2) ? "0"+a : a;
      }
      
      char pwr1Hex[5]; // 4 caratteri esadecimali contenenti la Potenza generata dalla Fase 1
      unsigned int intPwr1; // valore Decimale della Potenza generata dalla Fase 1
      char pwr2Hex[5]; // 4 caratteri esadecimali contenenti la Potenza generata dalla Fase 2
      unsigned int intPwr2; // valore Decimale della Potenza generata dalla Fase 1
      char pwr3Hex[5]; // 4 caratteri esadecimali contenenti la Potenza generata dalla Fase 3
      unsigned int intPwr3; // valore Decimale della Potenza generata dalla Fase 1
      
 // Estraggo dalla Stringa Esadecimale i 3 gruppi di 4 caratteri che costituiscono le Potenze generate dall'Inverter Fotovoltaico
      pacHex.substring(280, 284).toCharArray(pwr1Hex, 5);
      pacHex.substring(284, 288).toCharArray(pwr2Hex, 5);
      pacHex.substring(288, 292).toCharArray(pwr3Hex, 5);
      
// Converto gli Esadecimali in Decimali.      
      sscanf( (const char*)pwr1Hex, "%4x", &intPwr1 );
      sscanf( (const char*)pwr2Hex, "%4x", &intPwr2 );
      sscanf( (const char*)pwr3Hex, "%4x", &intPwr3 );

// Stampo i valori ottenuti.      
	    Serial.print(intPwr1);
	    Serial.print("  ");   
	    Serial.print(intPwr2);
	    Serial.print("  ");   
	    Serial.print(intPwr3);
	    Serial.print("    Totale: "); 
	    int tot = intPwr1 + intPwr2 + intPwr3;
	    Serial.println(tot);

    }
// Pulisco il buffer.    
    Udp.flush();
    pacHex = "";
    Serial.println("");
    delay(5000);
}


// Ho lasciato questo metodo perché è grazie a lui che nella lavorazione sono riuscito a "vedere" 
//    cosa c'era nel buffer. 
// Il metodo scorre tutto il "text" (che contiene la stringa esadecimale) 2 caratteri per volta, li converte in decimale
//    Se il valore ottenuto è un carattere Ascii (da 32 a 127) allora lo converte nel carattere corrispondente
//    altrimenti prende in esame non 2 ma 4 caratteri e li converte in decimale e quello sarà un dato significativo 
//    (nel mio caso erano proprio i valori che cercavo di Volt, Ampere, Watt...  etc etc etc)
//void to_ascii( unsigned char* dest, char *text ) {
//    unsigned int ch ;
//    for( ; sscanf( (const char*)text, "%2x", &ch ) == 1 ; text += 2 ) {
//      if (31<ch && ch<128) {
//        Serial.print((char)ch);
//      } else {
//        sscanf( (const char*)text, "%4x", &ch );
//        Serial.print(ch);
//        text += 2;
//      }
//      Serial.print(" ");
////      *dest++ = ch ;
//    }
////    *dest = 0 ;
//}

Chissà se queste poche righe in futuro potranno essere utili a qualcuno.

;0))

Grazie per la condivisione. :wink:

Figurati,
anzi, ho dimenticato di ringraziare te e gli altri per il supporto ;0))

Grazie a tutti ;0)

Alessio.