Dateiname vom Http server Auslesen auswerten

Hallo Leute, zwecks Update habe ich auf meinem Server Die Firmwarexxxx.bin

Zwecks Version Überprüfung, müsste ich diese auslesen und weiß grade nicht wie.
da die Datei Version sich ja ständig Ändert...

Wie kann ich also Abfragen wie die Datei heißt die im Ordner Http://Meinserver.xx/Update/ sich Befindet die Z.b die Endung .bin Besitzt?

Die Version aus dem laufendem Sketch habe ich bereits.
Nun müsste ich wissen ob die Datei(Name) auf den Server Größer ist wie die Eigene ist.

P.s Alternative Könnte ich eine Php Datei anlegen auf dem Server, der danach sucht, und mir per echo Den Namen Übergibt o.ä?!

lg. und vielen dank :grinning:

erstelle auf PHP eine Seite/Resource die als Eingangsparameter eine Version von deinem Microcontroller übernimmt und als Ergebnis den Link oder "keine neuere Version Verfügbar" retourniert.

Jap Genau so hatte ich es mir Vorgestellt..

*Update.php

<?php if(!empty($_GET['status']))
    {
    	$file = $_GET['status'];

			if ($handle = opendir('otaupdate/')) {

				while (false !== ($entry = readdir($handle))) {
					if ($entry != "." && $entry != "..") {
						echo "$entry\n";
					}
				}
				closedir($handle);
			}		
	}
?>

*.ino



String OTA_ENDPOINT = "http://server.xx/otaupdate/";
String Otalink = "http:///server.xx/Update.php";
  String substring1 = ".ino";
  String substring2 = ".bin";

    String ThisVersion = __FILE__;
    ThisVersion = (ThisVersion.substring((ThisVersion.indexOf(""))));

    ThisVersion.replace(substring1, substring2);
    
 HTTPClient http;
  getData = "?status=" +  ThisVersion; 
  Link = Otalink + getData;
  
  http.begin(Link);
  
  int httpCode = http.GET();           
 String payload2 = http.getString();   

  http.end();

  if(payload2 != ThisVersion){
 ESPhttpUpdate......... mit case Überprüfung etc...
}

Mal so auf die schnelle, muss ich noch Verbessern, es tut aber schonmal was es soll :grinning: :ok_hand:

Kan ich beim String eigentlich auch Überprüfen ob A > ist wie B? beil bei != würde auch dann updaten wenn die Version auf den Server < währe, solange nicht = ist :thinking:

Hey,

Ich hab das selbe "Problem" auch mit einer php und einer .bin Datei gelöst, die php Datei gibt die Versionsnummer zurück, hier wandel ich den String in ein int um und wenn die Versionsnummer höher als die hardcoded-Versionsnummer ist, wird die *.bin Datei downgeloaden und ein Update durchgeführt.

  int FirmwareVer = 10; // aktuelle Version
  http.begin(client, "http://server.com/version.php?token=123");     // Versionsinfo aufrufen
  int httpCode = http.GET();
  if (httpCode == HTTP_CODE_OK)         // Wenn Antwort OK: (int: 200)
  {
    String payload = http.getString();  // Webseite einlesen
    FirmwareNeu = payload.toInt();      // Zahl aus Sting bilden
   } 
  http.end();
  
  if (FirmwareNeu > FirmwareVer)        // Firmwareversion mit aktueller vergleichen
  {
     Serial.println("Neue Firmware verfuegbar");
    // Firmeware Update durchführen
  }

Grüße!

1 Like

Ich wollte das etwas mehr automatisieren.
Den so muss man dann leider jedes mal selbst die werte Ändern etc..
Also habe ich mir eine Bat Datei aufgebaut der mir mein Projekt Ordner umbenennt ProjectV+1 Also die Version Nummer automatisch immer um 1 Größer.
Ebenso die ProjectV+1.ino. Danach startet der Sketch automatisch.

Sobald ich dann die ProjectV+1.ino.nodemcu.bin herstelle. Erkennt es die Bat Datei Bennent sie um in ProjectV+1.bin Startet den Ftp Zugang und lädt sie rauf...

Soweit So gut....

Nun hängt es aber am code selbst..
Nach dem Updaten Macht es Kein Reset, oder etwas anderes stimmt nicht damit, Manuales Reset lässt das Esp8266 auch nicht neu Booten...

1 Like

Ja klar, ich hätte vielleicht noch mehr über den "Server" Teil reden sollen.

Ich habe ein kleines Interface gebastelt, hier kann ich jederzeit eine neue Firmeware Uploaden, die Versionsnummer wird automatisch um 1 erhöht, kann ich aber auch manuell ändern.
Beim Upload werden diese Infos in einer MySQL DB gespeichert und die "version.php" besteht im Grunde nur aus einer Datenbankabfrage.

Cool wäre es das ganze noch mit git zu "verwursteln" aber vielleicht auch Übertrieben, nur so ein Gedanke. :wink:

Kannst Du den Code bitte posten. Also im ersten Code-Teil hast Du ja geschrieben:

Was bis auf die if-Anweisung auch richtig ist. Ich habe "ESP.reset();" für den "HTTP_UPDATE_OK" Fall drinnen.

Manueller Reset funktioniert nicht?
Was verstehst Du unter "manueller Reset", die Reset Taste oder "ESP.reset();"?

Grüße!

edit: Sorry da habe ich etwas übersehen!

Grüße!

"ESP.reset();" für den "HTTP_UPDATE_OK"

Ich habe es inzwischen Gelöst Der Update Code stand nicht Im void Loop.
Er hat also den Update gestartet und blieb dann am ende stehen, weil er nicht mehr Überprüfen konnte Ob Fertig ist. Somit hat das ESP8266HttpUpdate Lib Nicht den ESP.reset oder HTTP_UPDATE_OK ausführen Können.

if(payload2 != ThisVersion) {
Du meinst != ist ein int Vergleich? Den Playload2 und ThisVersion sind Beides String....

Danke für Deine Rückmeldung, freut mich das es funktioniert!
Ich habe allerdings diesen gesamten Code Abschnitt im Setup().

Ich kann den Rest ja noch dazu posten:

if (FirmwareNeu > FirmwareVer)        // Firmwareversion mit aktueller vergleichen
  {
   Serial.println("Neue Firmware verfuegbar");
   ESPhttpUpdate.rebootOnUpdate(false); // reboot abschalten, will erst eine Meldung ausgeben!
   t_httpUpdate_return ret = ESPhttpUpdate.update(client, urlFirmware); //- Update ausführen

    switch (ret) { // Nach dem Update
      case HTTP_UPDATE_FAILED:
        Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
        break;

      case HTTP_UPDATE_NO_UPDATES:
        Serial.println("HTTP_UPDATE_NO_UPDATES");
        break;

      case HTTP_UPDATE_OK:
        Serial.println("HTTP_UPDATE_OK");
        Serial.println("Update erfolgreich");
        delay(100);
        ESP.reset();
        delay(10);
        break;
    }

Sorry, das hab ich falsch gesehen! Natürlich kann man 2 Strings mit "==" überprüfen ob sie die selben sind oder eben mit != ob sie es nicht sind.

Grüße!

Mal eine andre frage... Bei mir scheint beim starten des Update das der Http Server gekillt wird?
Ich habe in den ESP8266HttpUpdate alle http.end(); ausgeklammert..
Aber nix, Seite ist während des Update nicht mehr erreichbar?

Ich hab nun den Abschnitt...

void update_progress(int cur, int total) {
  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
  String Progressstatus1 = "Updating at %d ";
  String Progressstatus2 = "of %d  bytes...";
  webserver.send(200, "text/html", (String)HTMLANFANG + cout  + HomeButton + Progerrbar + Progressstatus1 + cur + Progressstatus2 + total + Progerrbar2 + HTMLENDE);
  delay(2000);
}

Und würde dies gerne Verfolgen können, per serial Monitor ok, per http aber nix :thinking:

lg

Gute Frage! Ich denke das der gesamte Wifi Kram (also die SDK) während des Update "abgeschaltet" wird, ich habe eine Ausgabe über den Seriellen Monitor und über ein Display, das ist kein Problem da es vom Sektch "bedient" wird.

Ich würde hier ein JS Script schreiben welches zeigt "Update in Arbeit" und im Abschluss dann "Update OK" oder "Update fehlgeschlagen" zurückgibt.
Für den Fall, dass die neue Firmeware defekt oder aus irgendwelchen Gründen nicht wie gewünscht läuft auch noch eine weitere Funktion einbauen wie "ESP nicht erreichbar". Wie hoch man hier den Timeout setzt, musst Du selber durch testen herausfinden, ist auch nur eine Idee.

Grüße!

Habs...
In der ESP8266httpUpdate.h
Ganz unten von true auf false.
bool _closeConnectionsOnUpdate = false;

Allerdings funktioniert es nur mit Wificlient.

In der ESP8266httpUpdate.ccp zeile 348

       if (_closeConnectionsOnUpdate) {
                    WiFiUDP::stopAll();
                    WiFiClient::stopAllExcept(tcp);
                }

Ich Verwende Den ESP8266WebServer webserver(80); , dort wird man ganz kurz zur nexte Seite Geladen, und dann die Verbindung trotzdem Gekillt.

Der abschnitt Mit dem WiFiServer server(80); hingegen Funktioniert super.

1 Like

Interessant!
Der "ESP8266WebServer" ist im Gegensatz zum "WiFiServer" ein richtiger Webserver der auch eine eigene .h Datei im Core hat.
Der "WiFiServer" läuft in irgendeiner Weiße über den WiFiClient, vor allem muss man sich um einen Teil des Protokoll Stack kümmern, zb: Datei Header

Viel mehr kann ich dazu allerdings auch nicht sagen, ich verwende eigentlich den "ESP8266WebServer" und der gesamte Update Prozess schaut bei mir so aus:
.) beim starten (Setup) des ESP wird die Firmware Version überprüft.
.) Über das Webinterface kann die Version händisch überprüft werden, update durch einen Reboot. (der ESP startet täglich neu)
.) Ist eine neue Version verfügbar -> Schreibe "update" in Datei "run" -> Logout & Update -> Log -> Reboot

Beim Login in das Webinterface wird eine random Zahl als Cookie gespeichert damit der ESP mich wiedererkennt. Spätestens nach dem Reboot ändert sich diese und ich wäre nicht mehr eingeloggt.
Klar das kann man alles umschiffen, zb: den "login" als Datei speichern aber das ist derzeit nicht so wichtig für mein Projekt.

Verwendest Du eigentlich die Arduino IDE? Mit MS Code (mit PlatformIO) oder auch Sublime Text kannst Du sehr leicht nachverfolgen in welcher Datei sich eine Klasse/Funktion befindet und eben schnell zu diesem Code wechseln. Ist sehr angenehm! :wink:

Grüße!

Also ich Speicher So gut wie alles Im Eeprom. Außer wen die Werte sich viel zu Oft Ändern, Um die Schreibzyklen nicht Unnötig runter zu hauen.

Der "ESP8266WebServer"

Naja zumindest kommt jetzt schonmal eine Seite, wo man den User informieren kann, das das Updaten gestartet ist.
Ein Progress bar Wäre Schöner aber was solls...

Verwendest Du eigentlich die Arduino IDE?

Ja für die Arduino Sachen nutze ich nur die Arduino Ide.
MS Code habe ich auch, das nervt aber mit den Libraries Imports, hab ich mich noch nicht so mit beschäftigt.
Die Arduino IDE ist eigentlich schon ganz gut, bis auf paar Optionen die sie einbinden Könnten.
Wie Z.b .bin Export mit andrem Namen.
und Ftp Upload :rofl:
Aber gut, man kann ja nicht alles haben :joy:

Es gibt übrigens auch die Möglichkeit den ESP via Webserver und einen FileUpload up-zu-daten.
Vielleicht sagt Dir das mehr zu, da brauchst Du keine Dateien auf einem Dritt Server zu haben und sparst Dir auch die FTP Uploads. (Soweit ich das verstanden habe)

Dir ist schon klar, dass der ESP eigentlich nur einen EEPROM im Flash Speicher simuliert (ESP EEPROM). Der hat auch nur 4kb und klar, den Flash Speicher kann man auch nicht endlos neu beschreiben.
Der ESP stellt allerdings ein "gutes" Dateisystem zur Verfügung, das sich IMHO hier oft besser eignet und bis zu 3MB groß sein kann. (Es gibt auch 16MB Varianten des ESP8266).

Wie auch immer, für manche Anwendungen eignet sich der "EEPROM" wahrscheinlich auch besser.
Noch ein Vorteil von LittleFS (nicht SPIFFS), dass man den Code auch für SD Karten verwenden kann, also auch eine ganze Klasse (zb sowas wie: FileManager) sowohl für LittleFS als auch für SD Karten in 2 Instanzen verwendet werden kann.

Das kannst Du nur "simulieren", wenn man etwas im ESP Core herumfummels't (wovon ich eigentlich abrate aber ich denke Du weißt was Du tust) kann man vielleicht eine Meldung "download abgeschlossen" rausbringen.
Das wäre dann aber nur "0%->50%->90%" und nach erfolgreichen reset dann 100% (oder so).

Du müsstest ein Java Script schreiben welches den Fortschritt Balken langsam nach vorne bewegt, auf Basis der Dateigröße und Resetdauer usw.

Wie handelst Du eigentlich den Login in das Webinterface? (Falls Du überhaupt einen hast)

Klar, ich verwende die Arduino IDE schon auch noch (ab und zu) aber mir fehlt die Auto Vervollständigung! :wink: Für große Projekte ist die Arduino IDE einfach zu "klein", alleine das Dateimanagment ist so, naja. (Die Frage war eher aus Eigeninteresse)

Grüße!

Natürlich :wink:

Genau an sowas hatte ich gedacht. Zwecks Meldung etc Per JS etc..

Nein Bei Diesem Projekt Wird Noch Keins Verwendet.
Ein kleines Login Sollte aber dennoch später rein, zur Sicherheit.
Den kann der Benutzer bei der Einrichtung, des gerät aktivieren wenn er mag.
Direkt auf das gerät, also ohne Registrierung etc.
Und nur 1 Benutzer Zugang, einfach nur damit keiner von außen drauf kommt.

Was ich noch brauche ist so eine Art Cookie, damit sich der Nutzer nicht jedes mal neu einloggen muss.

Und eine Config Export/Import.
Falls mal falsche Password eingegeben wurde etc.
Dann kann er sich die Config rein Laden, die speichert dann das Pw nicht.
Und nach dem Neustart kann er sich neues pw setzen :sunglasses:

Ich denke das ist auch der einzige vernüftige Weg. Wenn überhaupt ist nur der Download "verfolgbar", für das Update selbst wird es wohl eher keine Möglichkeit geben!

Ich hab bereits einen login, ich sehe hier eigentlich nur 2 Möglichkeiten:
Cookie setzten oder einen Security "token" bei jedem Link weitergeben, zweiteres ist nicht besonders.

Cookie setzten ist nicht so schwierig, einfach den Header erweitern. Zum Auslesen (auch von anderen Header Daten wie etwas "user-agent") brauchst musst Du dem Webserver mitteilen, dass Du an den Header Daten interessiert bist:

  server.onNotFound(handleNotFound);

  server.collectHeaders("User-Agent", "Cookie");  // Damit Cookies ausgelesen werden können
  server.begin(); // Starte den Webserver

So ist auch der User-Agent abrufbar

Auch eine gute Idee!
Ich muss beim Reset einen Pin auf Ground legen dann wird das Default Passwort wiederhergestellt (das ist hardcoded).

Gut zu Wissen, so werd ich meine Erstanmeldung wohl eher geheim halten. :sunglasses:

Grüße!

1 Like

Oder doch wird aber langes code hier... :rofl:

String Otalink = "http://server.xx/Checkfw.php";
String OTA_ENDPOINT = "http:///server.xx/otaupdate/";
///////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////UPDATE OVER HTTP//////////////////////////////////////////////
void processOta(){

  String substring1 = ".ino";
  String substring2 = ".bin";

    
    String ThisVersion = __FILE__;
    ThisVersion = (ThisVersion.substring((ThisVersion.indexOf(""))));

    ThisVersion.replace(substring1, substring2);
    
  HTTPClient http;
  getData = "?status=" +  ThisVersion; 
  Link = Otalink + getData;
  
  http.begin(Link);
  int httpCode = http.GET();        
  payload2 = http.getString();
  //http.end();

   if(payload2 !="" ){ //Wird später erweitert wegen Version check etc...
      // Add optional callback notifiers
    ESPhttpUpdate.onStart(update_started);
    ESPhttpUpdate.onEnd(update_finished);
    ESPhttpUpdate.onProgress(update_progress);
    ESPhttpUpdate.onError(update_error);
      
      OTA_ENDPOINT += payload2;

    ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
    t_httpUpdate_return ret = ESPhttpUpdate.update(OTA_ENDPOINT);

   switch (ret) {
        case HTTP_UPDATE_FAILED:
       
            Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
            webserver.send(200, "text/html", (String)HTMLANFANG + cout  + HomeButton + UpdateErrorTitle);
            break;

        case HTTP_UPDATE_NO_UPDATES:
            Serial.println("HTTP_UPDATE_NO_UPDATES");
            webserver.send(200, "text/html", (String)HTMLANFANG + cout  + HomeButton + UpdateNotConfimedTitle);
            break;

        case HTTP_UPDATE_OK:
            Serial.println("HTTP_UPDATE_OK");          
            break;
    } 
  }
 
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////Funktion Update Läuft /////////////////////////////////////////////////////////////
void update_progress(int cur, int total) {
   //Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);  
  if(cur >0 and total >0 ){

  
  IpToString();
  int Vorschritt = total / cur;
      
  webserver.send(200, "text/html", (String)HTMLANFANG + cout + Progerrbar1 + UpdateStatuscount + Vorschritt + UpdateStatuscount2 + bufferip + RefreschtoHome1 );
  } 
}
** char bufferip[100];
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////Funktion Ip In String ////////////////////////////////////////////////////////////
void IpToString(){
  sprintf(bufferip, "%s", WiFi.localIP().toString().c_str());
}

Dafür habe ich eine Buttons.h und lade von dort meine Buttons und Progress bar Ink Script...
PLATZHALTER ist eine Anmerkung das im Haupt Datei dort ein wert Geladen wird.


/////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////Update Progressabr////////////////////////////////////////////
const char Progerrbar1[] = "<h1>Updating Pls Wait..</h1></p><div id=\"myProgress\"><div id=\"myBar\"></div></div>";
String UpdateStatuscount = "<script>var i = 0; if (i == 0) { i = 1; var elem = document.getElementById(\"myBar\");var width = 1; var id = setInterval(frame,";

//int Vorschritt = total / cur;******* PLATZHALTER

String UpdateStatuscount2 = "); function frame() {if (width >= 100) {clearInterval(id); i = 0; } else {width++; elem.style.width = width + \"%\";if(width >= 99){setTimeout(function(){ window.location.href = 'http://";

//char bufferip[100]; ******* PLATZHALTER
//sprintf(bufferip, "%s", WiFi.localIP().toString().c_str()); ******* PLATZHALTER

String RefreschtoHome1 =  "/';}, 5000);}}}} </script>";

Danke für den cookie :grinning:
Natürlich ist das meiste bei mir erst einmal nur Test.
Progress bar wird jedoch zeit gleich zum Upload Beendet, und beim Reladen ist die Server Wieder Online, passt soweit alles.

Lg

1 Like

Nice!!! :wink:

Woher bekommt eigentlich die "update_progress" Funktion den Current Wert?
edit: Wahrscheinlich direkt über den ESP Core... :thinking:

Gerne! Freut mich das es funktioniert! :wink:

Lädt ja die Funktion.

ESPhttpUpdate.onProgress(update_progress);

In der ESP8266httpUpdate.h.. Gibt es Mehrere Funktionen etc.. Z.b

if (_cbProgress) {
Update.onProgress(_cbProgress);
}

if (_cbProgress) {
_cbProgress(0, size); Größe Fängt mit 0 an Und size Übergibt die Gesammt Größe
}

t_httpUpdate_return ret = ESPhttpUpdate.update(OTA_ENDPOINT);
Ruft die funktion auf für den ret etc ...

t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false);
bool runUpdate(Stream& in, uint32_t size, const String& md5, int command = U_FLASH);

Hoffe das waren jetzt die richtigen aber ja so in etwa :rofl: