-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Advanced OTA from Server with PHP script [Update Failed] #3043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
At least for your questions 2 and 3 it looks right, from my recollection.
I'll have to check my sketches for the calling rules.
I'm using a laravel project which the IDE uploads into and which manages
the various devices and firmwares - behaviour is slightly easier with the
git version (which includes an update to the OTA client that runs on the
ESP which supplies an MD5 of the sketch to determine whether to update or
not) - I don't think that's behind your error, it might be interesting to
see what your webserver is returning (there's usually an access log which
includes the HTTP code returned).
…On Tue, Mar 14, 2017 at 6:24 AM, Jason E. Geistweidt < ***@***.***> wrote:
Basic Infos
I am unclear about the proper use of ESPhttpUpdate in the 'advanced'
scenario (ie, where the ESP calls the server-side script (PHP) and then
replies with the .bin file if all the appropriate conditions are met.) If I
point the ESP directly to the .bin file, there is no issue, and the file is
delivered as expected, the board reboots, and new .bin executes. (Nicely
done!) I believe the issue is related to my use of the .update() method and
PHP script provided with the documentation.
I can confirm the server is running fine and the PHP is executable. When I
hit it with a browser it says "only for ESP8266 updater!" as it should, so
it looks good there. I am not too familiar with PHP, so a few questions:
1. Am I calling the method correctly, I am unsure about the fourth
argument:
If version string argument is given, it will be sent to the server. Server side script can use this to check if update should be performed.
What is the 'version' argument? The version being uploaded, the version
that is already on the server, is there a versioning format that should be
used?
1. Does the PHP require the .bin file to be in a sub-directory called
/bin/, such that the directory structure is such:
/var/www/html/esp/update/
-->arduino.php
/var/www/html/esp/update/bin/
-->IOT4.ino.bin
1. Did I place the MAC address of the ESP and the name of the file to
be downloaded (without the .bin suffix) in the db$ array correctly?
I surmise that the ESP is connecting correctly (it does download the .bin
when pointed at it directly -- the so-called 'Basic' Server method), the
issue is probably with my PHP file and .update call.
Thank you, great project.
Hardware
Hardware: Adafruit Huzzah
Core Version: 2.3.0-rc2
Description
Problem description
Settings in IDE
Module: Adafruit Huzzah
Flash Size: 4MB
CPU Frequency: 80Mhz
Upload Using: OTA / SERIAL
Sketch
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti;
void setup() {
USE_SERIAL.begin(115200);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("Cen---------02", "12-----------G"); //Redacted for privacy
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
t_httpUpdate_return ret = ESPhttpUpdate.update("http://www.mediatedspaces.net", 80, "/esp/update/arduino.php");
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.println("[update] Update failed.");
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("[update] Update no Update.");
break;
case HTTP_UPDATE_OK:
Serial.println("[update] Update ok."); // may not called we reboot the ESP
break;
}
}
}
And here is the PHP
<?PHP
header('Content-type: text/plain; charset=utf8', true);
function check_header($name, $value = false) {
if(!isset($_SERVER[$name])) {
return false;
}
if($value && $_SERVER[$name] != $value) {
return false;
}
return true;
}
function sendFile($path) {
header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
header('Content-Type: application/octet-stream', true);
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Length: '.filesize($path), true);
header('x-MD5: '.md5_file($path), true);
readfile($path);
}
if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater!\n";
exit();
}
if(
!check_header('HTTP_X_ESP8266_STA_MAC') ||
!check_header('HTTP_X_ESP8266_AP_MAC') ||
!check_header('HTTP_X_ESP8266_FREE_SPACE') ||
!check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
!check_header('HTTP_X_ESP8266_SKETCH_MD5') ||
!check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
!check_header('HTTP_X_ESP8266_SDK_VERSION')
) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater! (header)\n";
exit();
}
$db = array(
"18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
"18:FE:AA:AA:AA:BB" => "TEMP-1.0.0",
"5C:CF:7F:88:B6:B9" => "IOT4.ino" # <-- I have added the ESP MAC address and file name
);
if(!isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
header($_SERVER["SERVER_PROTOCOL"].' 500 ESP MAC not configured for updates', true, 500);
}
$localBinary = "./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin";
// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.
if((!check_header('HTTP_X_ESP8266_SDK_VERSION') && $db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] != $_SERVER['HTTP_X_ESP826$
|| $_SERVER["HTTP_X_ESP8266_SKETCH_MD5"] != md5_file($localBinary)) {
sendFile($localBinary);
} else {
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
}
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);
?>
Debug Messages
Here is the serial output . . .
[SETUP] WAIT 4...
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 6
cnt
[SETUP] WAIT 3...
connected with CenturyLink0502, channel 11
dhcp client start...
ip:192.168.0.28,mask:255.255.255.0,gw:192.168.0.1
[SETUP] WAIT 2...
[SETUP] WAIT 1...
pm open,type:2 0
[update] Update failed.
[update] Update failed.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#3043>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAN_A2uBMrnOyjcike-UXAyd7cWE8LOaks5rlXvAgaJpZM4MbkMx>
.
|
Just a few comments ... I use this extensively, but have not yet added any of the MD5 checking ... In my ESP code I'm using:
In this case my script is "index.php" in the path specified, and then I'm passing a "firmwareVersion" string that I have assigned in my sketch code. The string is like: "mySensor-1.55" This is the string that is specified in your array using the MAC as a key. Then in my PHP code, I'm doing:
This works ... but again is not verifying the MD5 on the PHP side ... I wasn't aware the extra header was now being sent. How does the ESP get the proper MD5 of a new fimrware version that it hasn't seen yet? |
The OTA Update client (in git version) calculates the MD5 based on the
values in flash, so it reflects the current flash contents (including
eboot).
…On Wed, Mar 15, 2017 at 7:00 AM, Scott C. Lemon ***@***.***> wrote:
Just a few comments ... I use this extensively, but have not yet added any
of the MD5 checking ...
In my ESP code I'm using:
t_httpUpdate_return ret = ESPhttpUpdate.update("update.myserver.net", 80,
"/v1/ESPUpdate/", firmwareVersion);
In this case my script is "index.php" in the path specified, and then I'm
passing a "firmwareVersion" string that I have assigned in my sketch code.
The string is like: "mySensor-1.55"
This is the string that is specified in your array using the MAC as a key.
Then in my PHP code, I'm doing:
if(isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
if($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] != $_SERVER['HTTP_X_ESP8266_VERSION']) {
error_log("~~ Update required ...\n", 3, "/var/log/ESP8266-ESPUpdate.log");
error_log("Sending file: /var/www/update.myserver.net/html/v1/ESPUpdate/bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin\n", 3, "/var/log/wovyn/ESP8266-ESPUpdate.log");
sendFile("/var/www/update.myserver.net/html/v1/ESPUpdate/bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']].".bin");
error_log("~~ Update file sent.\n\n", 3, "/var/log/ESP8266-ESPUpdate.log");
} else {
error_log("~~ No Update Required.\n\n", 3, "/var/log/ESP8266-ESPUpdate.log");
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
}
exit();
}
error_log("~~ Not Found - Unknown Device.\n\n", 3, "/var/log/ESP8266-ESPUpdate.log");
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);
This works ... but again is not verifying the MD5 on the PHP side ... I
wasn't aware the extra header was now being sent. How does the ESP get the
proper MD5 of a new fimrware version that it hasn't seen yet?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#3043 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAN_A3A27HW-u8Z3lvOMTD5UOZECO81Zks5rltXHgaJpZM4MbkMx>
.
|
I'm using the release and git version in different places but want to use the MD5 in each, so I have: void checkUpdate(void) {
String versionStr = "0.1.2 MD5:" + ESP.getSketchMD5();
Serial.println("[checkUpdate] Enacting update request");
t_httpUpdate_return ret = ESPhttpUpdate.update("http://sl.davison.org.nz/fw/aota/update", versionStr); My PHP webapp will use the md5-header-field if it's there, and if it's not see if there's an 'MD5:' in the version string, using whatever follows it if there is. |
Thanks for all the replies, unfortunately I am still having problems. After trying differing variations of the code offered, I went back to the beginning and started all over (hopefully with better knowledge). Via some error-log()-ing, I had the PHP script log a message whenever the script ran. If I hit the end point (index.php) with a browser, I get a 'script ran!' message in my logs. If I hit it with the ESP, no message. I assume the script is not running. So Firefox fires the script (with the 'ESP only' message) where the ESP returns:
via serial. On the server side the permissions are wide open, and I can always download the update file by hitting the .bin directly via both browser and ESP -- that works perfectly. I am going to check out: https://www.youtube.com/watch?v=UiAc3yYBsNU this afternoon to see if there is anything in there. If anyone knows of a tutorial that goes through the entire process of OTA with PHP script, that would be great. If I ever figure this out, I will do it! Thanks! |
Yeah, no luck. The error.log file for apache2 says:
and the access.log file says:
Which all points to the client. In my code, the update request is formed thus, and fails:
Where this works:
and this fails as well when trying to hook up to iotappstore.org
So, what is the correct way to form my URI? FYI, my files are in /var/www/html/ on the server side, so maybe that is the problem? Any ideas? Thanks to the community! |
Can you just say t_httpUpdate_return ret = ESPhttpUpdate.update("http://93.95.228.77/esp.php", version); ? |
Yeah, that fails, too. It would be interesting to see what ESPhttpUpdate is actually sending . . . a String, I guess? Any suggested debugging strategies/schema would be appreciated. J |
[Solved] I first tried to debug the server/php script by finding the values for the headers that are passed during the update() call:
by Serial.println()-ing out the values:
Which threw an error basically saying ESP has no method called .getSketchMD5() . . . which a bit more search took me to this issue: With the main thrust being that, historically it would seem, MD5 was left out of both Esp.cpp/Esp.h because MD5 was not implemented early on in the HTTPupdate roll out. And yet, the script in the docs is looking for the MD5 key/string and it just ain't there. So, the update fails. I was using the Board Manager to embed Arduino ESP in the IDE using this uri:
as suggested in the README. Unfortunately, this does not have the patches necessary to call ESPhttpUpdate correctly. (It all might have been different if I compiled from source, who knows?) So, you need to go in an manually do the deed: to paraphrase #2228:
So, I wish that the documentation would have been a bit more clear on that, or perhaps I missed it? But, to be clear, 2.3.0-rc2 through Board Manager does not have the MD5 functionality implemented. Thanks! |
2.3.0-rc2 is older than 2.3.0, so that's going back a version I believe.
I can check tomorrow how well the docs match the current release, but I
thought they worked okay when I went through the process last year.
On 20/03/2017 8:17 pm, "Jason E. Geistweidt" <[email protected]> wrote:
[Solved]
Here's how I debugged it. Briefly, there are a few things in the doc files
that are not well documented.
I first tried to debug the server/php script by finding the values for the
headers that are passed during the update() call:
t_httpUpdate_return ret = ESPhttpUpdate.update("93.95.228.77", 80,
"/esp.php", "httpUpdate");
by Serial.println()-ing out the values:
USE_SERIAL.println(WiFi.macAddress());
USE_SERIAL.println(WiFi.softAPmacAddress());
USE_SERIAL.println(ESP.getFreeSketchSpace());
USE_SERIAL.println(ESP.getSketchSize());
USE_SERIAL.println(ESP.getSketchMD5());
USE_SERIAL.println(ESP.getFlashChipRealSize());
USE_SERIAL.println(ESP.getSdkVersion());
Which threw an error basically saying ESP has no method called
.getSketchMD5() . . . which a bit more search took me to this issue:
#2228 <#2228>
With the main thrust being that, historically it would seem, MD5 was left
out of both Esp.cpp/Esp.h because MD5 was not implemented early on in the
HTTPupdate roll out. And yet, the script in the docs is looking for the MD5
key/string and it just ain't there. So, the update fails.
I was using the Board Manager to embed Arduino ESP in the IDE using this
uri:
http://arduino.esp8266.com/staging/package_esp8266com_index.json
as suggested in the README. Unfortunately, this does not have the patches
necessary to call ESPhttpUpdate correctly. (It all might have been
different if I compiled from source, who knows?) So, you need to go in an
manually do the deed: to paraphrase #2228
<#2228>:
1.
Be sure you are using 2.3.0-rc2.
2.
Replace Esp.h with the one found here:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Esp.h
1. Replace Esp.cpp with the one found here:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Esp.cpp
So, I wish that the documentation would have been a bit more clear on that,
or perhaps I missed it? But, to be clear, 2.3.0-rc2 through Board Manager
does not have the MD5 functionality implemented.
Thanks!
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#3043 (comment)>,
or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAN_A6r2VGz3v0O9i6EEvVCmdcbp6eP1ks5rniftgaJpZM4MbkMx>
.
|
Well, that is probably the confusion then, I though the staging version was necessary in order to invoke OTA w/ Server functionality (I read that somewhere). So, for my education, what is the significance of rc2 in the naming convention? To my mind, a 'staging' version would be cutting edge, you know, 'staging' for the next release, FWIW. Thanks again to the community, I am about to unleash 25 students on the library and wanted to work out all the kinks. jg |
RC stands for Release Candidate, so in the logical order, you have alpha (buggy version with new features), beta (version with no known outstanding issues), then one (or more) Release Candidate, which is the version that will ship unless a last minute issue is found. In this case, there have been 2 RC before the actual release, which probably means that 2.3rc2 is very close or identical to the final 2.3. |
I'm using vanilla 2.3.0 with the Arduino IDE. I just checked my Esp.h, and
EspClass does have the method getSketchMD5(). The method is also
implemented in Esp.cpp.
…On Mar 20, 2017 5:09 PM, "Vicne" ***@***.***> wrote:
RC stands for Release Candidate, so in the logical order, you have alpha
(buggy version with new features), beta (version with no known outstanding
issues), then one (or more) Release Candidate, which is the version that
will ship unless a last minute issue is found. In this case, there have
been 2 RC before the actual release, which probably means that 2.3rc2 is
very close or identical to the final 2.3.
Now that's the theory. Practically speaking, there are a few differences
between rc2 and final - see release notes
<https://github.com/esp8266/Arduino/releases> - but you'll see that there
was only 8 days between rc2 and final, so the differences are tiny.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#3043 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AQC6BhMf2DXRY_yEYxW-ve1x0ubXqZyTks5rntz4gaJpZM4MbkMx>
.
|
Yeah, I just grabbed the release candidate instead of the 2.3.0 proper. Well, learned a good deal about servers and updates and what is under the hood along the way. Thanks community . . . I believe I will close this. Solution: grab 2.3.0 vanilla. |
Where did you decide to get 2.3.0-rc2 from? Within the IDE?
You're not the first person to have stumbled on this so I'm wondering if
there's somewhere useful we should be mentioning it, in the docs, say...
J,
…On Tue, Mar 21, 2017 at 12:08 PM, Jason E. Geistweidt < ***@***.***> wrote:
Yeah, I just grabbed the release candidate instead of the 2.3.0 proper.
Well, learned a good deal about servers and updates and what is under the
hood along the way.
Thanks community . . . I believe I will close this.
Solution: grab 2.3.0 vanilla.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#3043 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAN_A605o45OuT7ayixNOu3bQ2jacZ_nks5rnwbogaJpZM4MbkMx>
.
|
Basic Infos
I am unclear about the proper use of ESPhttpUpdate in the 'advanced' scenario (ie, where the ESP calls the server-side script (PHP) and then replies with the .bin file if all the appropriate conditions are met.) If I point the ESP directly to the .bin file, there is no issue, and the file is delivered as expected, the board reboots, and new .bin executes. (Nicely done!) I believe the issue is related to my use of the .update() method and PHP script provided with the documentation.
I can confirm the server is running fine and the PHP is executable. When I hit it with a browser it says "only for ESP8266 updater!" as it should, so it looks good there. I am not too familiar with PHP, so a few questions:
What is the 'version' argument? The version being uploaded, the version that is already on the server, is there a versioning format that should be used?
I surmise that the ESP is connecting correctly (it does download the .bin when pointed at it directly -- the so-called 'Basic' Server method), the issue is probably with my PHP file and .update call.
Thank you, great project.
Hardware
Hardware: Adafruit Huzzah
Core Version: 2.3.0-rc2
Description
Problem description
Settings in IDE
Module: Adafruit Huzzah
Flash Size: 4MB
CPU Frequency: 80Mhz
Upload Using: OTA / SERIAL
Sketch
And here is the PHP
Debug Messages
Here is the serial output . . .
The text was updated successfully, but these errors were encountered: