Arduino verstuur CSV vanaf SDcard naar PHP Webserver

Kan iemand mij helpen bij het maken van een Arduino script?
Het script zou een CSV bestand opgeslagen op SD Card (welke in Arduino zit) moeten versturen naar een PHP Webserver?

Arduino Ethernet + SD Card Slot.

Op mijn Arduino heb ik een script draaien om de Kwh uur meter uit te lezen.
Ik tel de pulsen en stuur deze direct naar de PHP Webserver.
Daarnaast sla ik deze pulsen op hetzelfde moment op de SD card op.
Ik zou graag mijn pc uit willen kunnen zetten en dan SD card als buffer gebruiken.
De pulsen dan in CSV file laten opnemen, welke ik als de pc weer bereikbaar is als nog verstuur.

Puls -> check pc online -> PHP Webserver + SD card (history.csv)
Puls -> pc offline -> SD card Buffer.csv + SD card (history.csv)
Het history.csv bestand wil ik als naslag behouden.
Het buffer.csv bestand wil ik bij terugkeer pc versturen en mag hierna verwijderd worden (om dubbele verzending van gegevens te voorkomen).

Ik heb van alles geprobeerd met HTTP POST, GET, PUT maar het lukt me niet om de CSV file vanaf SD direct naar PHP Webserver te versturen.

Alle hulp is welkom .

 Serial.print("GET /energy_upload.php");
        client.print("GET /energy_upload.php");
        //client.println("/energy_upload.php");
        Serial.print("?kwhCount=");
        client.print("?kwhCount=");
        Serial.print(kwh_count);
        client.print(kwh_count);

Het direct versturen van de pulse naar de PHP webserver doe ik met bovenstaande code en dit werkt prima. Verwacht dat CSV file versturen op een zelfde manie zal kunnen?

je moet de CSV file per record naar PHP sturen, niet als een file in een keer (dat heb ik nog niet zien werken vanaf een duino) -

HTTP POST is het commando wat je nodig hebt. Aan de PHP kant kun je de records dan weer weg schrijven (optioneel data pre-processen).

gebruik de csv file als buffer (met 2GB sd card kun je waarschijnlijk vrij lang vooruit)

unsigned long in=0, out=0;

loop()
{
  if (millis() - prevTime > 60000UL)  // one sample per 60 seconds 
  {
    schrijf KWHcounter naar csv;
    in++;
    prevTime = millis();

    if (server.reachable() )
    {
      while(out < in  && millis() - prevTime < 30000UL)  // max 30 seconds uploaden (moet kleiner dan sample tijd zijn.)
      {
        read record[out] uit csv file;  // onthoudt fileposition voor snellere access fseek()
        schrijf record weg naar webserver;
        out++;
      }
    }
  }
  
  // other code here
}

in bovenstaande code volgt het uploaden de metingen als de server bereikbaar is.

ben benieuwd wat je ervan maakt!

Rob
Ik ben echt geen expert op de technische detail van netwerking en ik ben het met je eens dat het veel beter is om per record te werken en die direct in een database te steken in het aangehaalde geval. In het geval van bijvoorbeeld foto's moet je toch files uploaden.

Ik heb men eerste stapjes gedaan met webduino maar ben overgeschakeld op TinyWebServer omdat die files kan downloaden naar de browser.
Ik weet dat het niet hetzelfde is als files naar een server sturen; maar het komt toch heel dichtbij.
Ik vraag me dan af waarom het ene wel kan en het andere niet.
Als je het weet, laat het dan weten :slight_smile:

hvannieu
Volgens het protocol zou je dit moeten doen met een POST. Maar eigenlijk maakt POST/GET niks uit als je maar aan de andere kant luistert naar het juiste commando. Natuurlijk gaan tools je beter ondersteunen als je het "juiste" protocol gebruikt.
Je zegt wel dat je van alles hebt geprobeerd (en ik geloof dat ook) en dat het niet werkte. Maar wat heb je precies geprobeerd en wat werkte niet?
In deze setup is er heel veel dat verkeerd kan lopen. Zo stel ik me volgende vragen:
Geraakt je request wel bij je PHP server? Indien niet kijk je naar een netwerk probleem.
Als je request wel bij de server komt; Wat werkt er niet? Dat lijkt me dan eerder een protocol of PHP probleem.

Met vriendelijke groet
Jantje

In het geval van bijvoorbeeld foto's moet je toch files uploaden.

Ja en nee,

je kunt een simpel protocol definieren waarin alles wat groter is dan bv 512 bytes in X chuncks van 512 bytes wordt verstuurd + een restje.
Een jpeg foto van 1600 bytes (om niet te moeilijk te doen) wordt dan als volgt verstuurd:

A -> B: sendfile name=abc.jpg size=1600 optional params
B -> A:
A -> B: 512 bytes
B -> A:
A -> B: 512 bytes
B -> A:
A -> B: 512 bytes
B -> A:
A -> B: 64 bytes
B -> A:
A -> B: DONE
B -> A:

Kijk naar de oude RFC's van bv LPR/LPD hoe makkelijk dit gaat.

Je kunt rondom iedere chunck de socket openen en closen in principe (bij multiclient moet je meer doen).

files uploaden naar een webserver is ook een POST command dus moet een Arduino dat kunnen. Echter omdat de snelheid vd arduino-ethernet relatief laag is (en ethernet verbinding niet gegarandeerd) kan het uploaden van een grote file moeilijker gaan dan verwacht. Maar ik spreek niet uit ervaring (behalve dat mijn ethershield soms uitvalt)

korte uitleg vd PHP kant - PHP Tutorial - File Upload - voor een quick test.

Beste Rob (robtillaart),

Bedankt voor je reactie. Het script ben ik naar aanleiding van je advies opnieuw aan het maken. De basis was al totaal anders, zodoende.
In de logbestanden (buffer) op de SD card zit de tijd nog niet verwerkt. Als ik de buffer op later tijdstip zou versturen naar db, is er niet meer bekend hoe laat de ernergie verbruikt is. Nu worden alle pulsen direct verwerkt, de tijd laat ik door PHP in de DB plaatsen.

Helaas loop ik al vast om de Arduino middels ntp de tijd op te laten halen (bij interne server of ntp op internet).

Zie bijgaand mijn code tot nu toe.

#include <Time.h>
#include <SD.h>
#include <SPI.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <util.h>

//int getNtpTime;

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x60, 0xD6 };
byte ip[] = { 192, 168, 1, 50 };  // Arduino IP-address.
byte gateway[] = { 192, 168, 1, 254 }; 
byte subnet[] = { 255, 255, 0, 0 };
byte server[] = { 192, 168, 1, 2 }; // Database server address.
//byte getNtpTime[] =  { 192, 168, 1, 1 }; // NTP server address.

EthernetClient client;

void setup(){
  Ethernet.begin(mac, ip, subnet, gateway);
  Serial.begin(9600);
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet); // wait until the time is set by the sync provider
  delay(1000);
}

void loop(){
  if (client.connect(server, 80)) {
    Serial.println("Connected");
  }else{
    Serial.println("Connection failed");
  }
  
  if( now() != prevDisplay) //update the display only if the time has changed   
  {
     prevDisplay = now();
     digitalClockDisplay();  
   }   
}

void printDigits(int digits){
     // utility function for digital clock display: prints preceding colon and leading 0
     Serial.print(":");
     if(digits < 10) {
       Serial.print('0');
       Serial.print(digits);
     }
}

void digitalClockDisplay(){
    // digital clock display of the time   
     Serial.print(hour());
     printDigits(minute());
     printDigits(second());
     Serial.print(" ");
     Serial.print(day());
     Serial.print(" ");
     Serial.print(month());
     Serial.print(" ");
     Serial.print(year()); 
     Serial.println(); 
}

Heb jij enig idee wat ik mis doe? De volgende foutmelding blijf ik houden, bij verify code.

sketch_apr29a.cpp: In function 'void setup()':
sketch_apr29a:26: error: 'getNtpTime' was not declared in this scope
sketch_apr29a.cpp: In function 'void loop()':
sketch_apr29a:38: error: 'prevDisplay' was not declared in this scope

Heb getNtptime al als byte (ip) geprobeerd op te geven ook variable voor url? p.s. ben nog een echte beginner. Met veel script voorbeelden (examples) lukt het soms een klein beetje.

Het volgende script heb ik momenteel draaien. Erg simpel als de LED (kwh_meter) knippert stuur ik dit direct naar de PHP webserver.

#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
//#include <Upd.h>
#include <SPI.h>
#include <SD.h>
#include <Time.h>


// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;

int analogPin1 = 1;      // Kwh Sensor
int kwh_sensor1 = 0;     // Kwh counter value 
int kwh_pulsCount = 0;   // variable to store the kwh Counter Pulse

// assign a MAC-, IP-, GW- and Subnetaddress for the ethernet controller.
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x60, 0x06};
byte ip[] = {192,168,1,50};
byte gateway[] = {192,168,1,254}; 
byte subnet[] = {255, 255, 0, 0};

byte server[] = {192,168,1,2 }; // The server (database) address to connect to.
Client client(server, 80); // initialize the library instance:


void setup()
{
  Serial.begin(9600);          //  setup serial
  Ethernet.begin(mac, ip);     // start the ethernet connection
 Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
   pinMode(10, OUTPUT);
   
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  delay(15000);                  // wait 15 seconden for Ethernet connection
}

void loop()
{
  kwh_sensor1 = analogRead(analogPin1);    // read the input pin
  Serial.println(kwh_sensor1);             // debug value
  
  
  // KWH Usage Script...
  if (kwh_sensor1 > 200) {
    kwh_pulsCount+=1;
    Serial.print("kwh_pulsCount = "); 
    Serial.println(kwh_pulsCount); 
    Serial.println("connecting...");
    
      // if you get a connection, report back via serial:
      if (client.connect()) {
        Serial.println("connected");
        Serial.println();
        client.println();
        //Serial.print("PUT /energyusage/YOUR_FEED_HERE.csv HTTP/1.1\n");
        //client.print("PUT /energyusage/YOUR_FEED_HERE.csv HTTP/1.1\n");
        Serial.print("GET /energyusage/energy_upload.php");
        client.print("GET /energyusage/energy_upload.php");
        Serial.print("?kwh_pulsCount=");
        client.print("?kwh_pulsCount=");
        Serial.print(kwh_pulsCount);
        client.print(kwh_pulsCount);
        Serial.println();
        client.println();
            
      } 
      else {
        Serial.println("connection failed"); 
      }
      if (kwh_pulsCount == 1000){kwh_pulsCount = 0;}
      
      String data_sd = "";
      
      time_t t = now(); // store the current time in time variable t 
      hour(t);          // returns the hour for the given time t
      minute(t);        // returns the minute for the given time t
      second(t);        // returns the second for the given time t 
      day(t);           // the day for the given time t 
      weekday(t);       // day of the week for the given time t  
      month(t);         // the month for the given time t 
      year(t);          // the year for the given time t
      
      data_sd += kwh_pulsCount;
      data_sd += ",";
      data_sd += hour(t);
      data_sd += ":";
      data_sd += minute(t);
      data_sd += ":";
      data_sd += second(t);
      //data_sd += "\n";
      
      // open the file. note that only one file can be open at a time,
      // so you have to close this one before opening another.
      File dataFile = SD.open("datalog.csv", FILE_WRITE);
    
      // if the file is available, write to it:
      if (dataFile) {
        Serial.println(data_sd);
        dataFile.println(data_sd);
        dataFile.close();
        // print to the serial port too:
      }  
  }
  // GAS Usage Script...
  //if (gas_sensor1 > ..){
  //  ....
  //}
   // if the server's disconnected, stop the client:
   if (client.connected()) {
     Serial.println();
     Serial.println("disconnecting.");
     client.stop();
   }
}

Ben je zeker dat je subnet goed zit? 255.255.255.0

Je hebt ook helemaal geen code om de tijd op te halen (in de sketch die je ons laat zien)

Gebruik je dhcp en dns? Of zet je alles fix en gebruik je ip-adressen ipv dns? Want dan moet je die libraries ook niet laden. (geheugen).

Ps heb je dit al goed werkend?
Zou je mij een hardware lijstje willen geven..?
En natuurlijk de sketch...
8) 8) 8)