1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Add MD5 to core, Fix OTA examples and Digest Authentication to OTA and espota.py

This commit is contained in:
Me No Dev 2015-11-09 00:42:30 +02:00
parent e613e42249
commit a8976a01fd
13 changed files with 518 additions and 247 deletions

View File

@ -0,0 +1,43 @@
#include "Arduino.h"
#include "md5.h"
#include "MD5Builder.h"
#define hex_char_to_byte(c) (((c)>='a'&&(c)<='f')?((c)-87):((c)>='A'&&(c)<='F')?((c)-55):((c)>='0'&&(c)<='9')?((c)-48):0)
void MD5Builder::begin(void){
memset(_buf, 0x00, 16);
MD5Init(&_ctx);
}
void MD5Builder::add(uint8_t * data, uint16_t len){
MD5Update(&_ctx, data, len);
}
void MD5Builder::addHexString(const char * data){
uint16_t i, len = strlen(data);
uint8_t * tmp = (uint8_t*)malloc(len/2);
if(tmp == NULL)
return;
for(i=0; i<len; i+=2) tmp[i/2] = (hex_char_to_byte(data[i]) & 0x0F) << 4 | (hex_char_to_byte(data[i+1]) & 0x0F);
add(tmp, len/2);
free(tmp);
}
void MD5Builder::calculate(void){
MD5Final(_buf, &_ctx);
}
void MD5Builder::getBytes(uint8_t * output){
memcpy(output, _buf, 16);
}
void MD5Builder::getChars(char * output){
for(uint8_t i = 0; i < 16; i++)
sprintf(output + (i * 2), "%02x", _buf[i]);
}
String MD5Builder::toString(void){
char out[32];
getChars(out);
return String(out);
}

View File

@ -0,0 +1,47 @@
/*
md5.h - exposed md5 ROM functions for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ESP8266_MD5_BUILDER__
#define __ESP8266_MD5_BUILDER__
#include "Arduino.h"
#include "md5.h"
class MD5Builder {
private:
md5_context_t _ctx;
uint8_t _buf[16];
public:
void begin(void);
void add(uint8_t * data, uint16_t len);
void add(const char * data){ add((uint8_t*)data, strlen(data)); }
void add(char * data){ add((const char*)data); }
void add(String data){ add(data.c_str()); }
void addHexString(const char * data);
void addHexString(char * data){ addHexString((const char*)data); }
void addHexString(String data){ addHexString(data.c_str()); }
void calculate(void);
void getBytes(uint8_t * output);
void getChars(char * output);
String toString(void);
};
#endif

View File

@ -32,6 +32,7 @@ void UpdaterClass::_reset() {
_currentAddress = 0; _currentAddress = 0;
_size = 0; _size = 0;
_command = U_FLASH; _command = U_FLASH;
_target_md5 = 0;
} }
bool UpdaterClass::begin(size_t size, int command) { bool UpdaterClass::begin(size_t size, int command) {
@ -97,9 +98,16 @@ bool UpdaterClass::begin(size_t size, int command) {
_buffer = new uint8_t[FLASH_SECTOR_SIZE]; _buffer = new uint8_t[FLASH_SECTOR_SIZE];
_command = command; _command = command;
_target_md5 = new char[64];
_md5.begin();
return true; return true;
} }
void UpdaterClass::setMD5(const char * expected_md5){
if(strlen(expected_md5) != 32) return;
strcpy(_target_md5, expected_md5);
}
bool UpdaterClass::end(bool evenIfRemaining){ bool UpdaterClass::end(bool evenIfRemaining){
if(_size == 0){ if(_size == 0){
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
@ -124,6 +132,20 @@ bool UpdaterClass::end(bool evenIfRemaining){
_size = progress(); _size = progress();
} }
_md5.calculate();
if(_target_md5 && strlen(_target_md5) == 32){
if(strcmp(_target_md5, _md5.toString().c_str()) != 0){
_error = UPDATE_ERROR_MD5;
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("MD5 Failed: expected:%s, calculated:%s\n", _target_md5, _md5.toString().c_str());
#endif
return false;
}
#ifdef DEBUG_UPDATER
else DEBUG_UPDATER.printf("MD5 Success: %s\n", _md5.toString().c_str());
#endif
}
if (_command == U_FLASH) { if (_command == U_FLASH) {
eboot_command ebcmd; eboot_command ebcmd;
ebcmd.action = ACTION_COPY_RAW; ebcmd.action = ACTION_COPY_RAW;
@ -157,6 +179,7 @@ bool UpdaterClass::_writeBuffer(){
#endif #endif
return false; return false;
} }
_md5.add(_buffer, _bufferLen);
_currentAddress += _bufferLen; _currentAddress += _bufferLen;
_bufferLen = 0; _bufferLen = 0;
return true; return true;
@ -232,6 +255,8 @@ void UpdaterClass::printError(Stream &out){
out.println("Bad Size Given"); out.println("Bad Size Given");
} else if(_error == UPDATE_ERROR_STREAM){ } else if(_error == UPDATE_ERROR_STREAM){
out.println("Stream Read Timeout"); out.println("Stream Read Timeout");
} else if(_error == UPDATE_ERROR_MD5){
out.println("MD5 Check Failed");
} else { } else {
out.println("UNKNOWN"); out.println("UNKNOWN");
} }

View File

@ -3,6 +3,7 @@
#include "Arduino.h" #include "Arduino.h"
#include "flash_utils.h" #include "flash_utils.h"
#include "MD5Builder.h"
#define UPDATE_ERROR_OK 0 #define UPDATE_ERROR_OK 0
#define UPDATE_ERROR_WRITE 1 #define UPDATE_ERROR_WRITE 1
@ -10,11 +11,12 @@
#define UPDATE_ERROR_SPACE 3 #define UPDATE_ERROR_SPACE 3
#define UPDATE_ERROR_SIZE 4 #define UPDATE_ERROR_SIZE 4
#define UPDATE_ERROR_STREAM 5 #define UPDATE_ERROR_STREAM 5
#define UPDATE_ERROR_MD5 6
#define U_FLASH 0 #define U_FLASH 0
#define U_SPIFFS 100 #define U_SPIFFS 100
//#define DEBUG_UPDATER Serial1 //#define DEBUG_UPDATER Serial
class UpdaterClass { class UpdaterClass {
public: public:
@ -57,6 +59,21 @@ class UpdaterClass {
*/ */
void printError(Stream &out); void printError(Stream &out);
/*
sets the expected MD5 for the firmware (hexString)
*/
void setMD5(const char * expected_md5);
/*
returns the MD5 String of the sucessfully ended firmware
*/
String md5String(void){ return _md5.toString(); }
/*
populated the result with the md5 bytes of the sucessfully ended firmware
*/
void md5(uint8_t * result){ return _md5.getBytes(result); }
//Helpers //Helpers
uint8_t getError(){ return _error; } uint8_t getError(){ return _error; }
void clearError(){ _error = UPDATE_ERROR_OK; } void clearError(){ _error = UPDATE_ERROR_OK; }
@ -120,6 +137,9 @@ class UpdaterClass {
uint32_t _startAddress; uint32_t _startAddress;
uint32_t _currentAddress; uint32_t _currentAddress;
uint32_t _command; uint32_t _command;
char *_target_md5;
MD5Builder _md5;
}; };
extern UpdaterClass Update; extern UpdaterClass Update;

44
cores/esp8266/md5.h Normal file
View File

@ -0,0 +1,44 @@
/*
md5.h - exposed md5 ROM functions for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
original C source from https://github.com/morrissinger/ESP8266-Websocket/raw/master/MD5.h
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ESP8266_MD5__
#define __ESP8266_MD5__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t state[4];
uint32_t count[2];
uint8_t buffer[64];
} md5_context_t;
extern void MD5Init (md5_context_t *);
extern void MD5Update (md5_context_t *, uint8_t *, uint16_t);
extern void MD5Final (uint8_t [16], md5_context_t *);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -2,14 +2,24 @@
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include "ArduinoOTA.h" #include "ArduinoOTA.h"
#include "MD5Builder.h"
ArduinoOTA::ArduinoOTA(const char *mdns_host_prefix, int port, bool serial_debug) //#define OTA_DEBUG 1
ArduinoOTAClass::ArduinoOTAClass()
{ {
_port = port;
_mdns_host = new String(mdns_host_prefix);
*_mdns_host += String(ESP.getChipId(), HEX);
_udp_ota = new WiFiUDP(); _udp_ota = new WiFiUDP();
_serial_debug = serial_debug; _password = 0;
_hostname = 0;
_port = 0;
_nonce = 0;
_state = OTA_IDLE;
_size = 0;
_cmd = 0;
_ota_port = 0;
_ota_ip = (uint32_t)0;
_md5 = new char[33];
_start_callback = NULL; _start_callback = NULL;
_end_callback = NULL; _end_callback = NULL;
@ -17,104 +27,210 @@ ArduinoOTA::ArduinoOTA(const char *mdns_host_prefix, int port, bool serial_debug
_error_callback = NULL; _error_callback = NULL;
} }
void ArduinoOTA::onStart(OTA_CALLBACK(fn)){ void ArduinoOTAClass::onStart(OTA_CALLBACK(fn)){
_start_callback = fn; _start_callback = fn;
} }
void ArduinoOTA::onEnd(OTA_CALLBACK(fn)){ void ArduinoOTAClass::onEnd(OTA_CALLBACK(fn)){
_end_callback = fn; _end_callback = fn;
} }
void ArduinoOTA::onProgress(OTA_CALLBACK_PROGRESS(fn)){ void ArduinoOTAClass::onProgress(OTA_CALLBACK_PROGRESS(fn)){
_progress_callback = fn; _progress_callback = fn;
} }
void ArduinoOTA::onError(OTA_CALLBACK(fn)){ void ArduinoOTAClass::onError(OTA_CALLBACK_ERROR(fn)){
_error_callback = fn; _error_callback = fn;
} }
ArduinoOTA::~ArduinoOTA(){ ArduinoOTAClass::~ArduinoOTAClass(){
delete _udp_ota; delete _udp_ota;
delete _mdns_host;
} }
void ArduinoOTA::setup() { void ArduinoOTAClass::setPort(uint16_t port){
_udp_ota->begin(_port); if(!_initialized && !_port && port){
if (_mdns_host) { _port = port;
if (_serial_debug)
Serial.printf("OTA server at: %s:%u\n",
_mdns_host->c_str(),
_port);
MDNS.begin(_mdns_host->c_str());
MDNS.addService("arduino", "tcp", _port);
} }
} }
void ArduinoOTA::handle() { void ArduinoOTAClass::setHostname(const char * hostname){
if(!_initialized && !_hostname && hostname){
_hostname = new char[strlen(hostname)];
sprintf(_hostname, "%s", hostname);
}
}
void ArduinoOTAClass::setPassword(const char * password){
if(!_initialized && !_password && password){
_password = new char[strlen(password)];
sprintf(_password, "%s", password);
}
}
void ArduinoOTAClass::begin() {
if(_initialized)
return;
_initialized = true;
if(!_hostname){
_hostname = new char[15];
sprintf(_hostname, "esp8266-%02x", ESP.getChipId());
}
if(!_port)
_port = 8266;
_udp_ota->begin(_port);
MDNS.begin(_hostname);
if(_password){
_nonce = new char[33];
MDNS.enableArduino(_port, true);
} else
MDNS.enableArduino(_port);
_state = OTA_IDLE;
#if OTA_DEBUG
Serial.printf("OTA server at: %s.local:%u\n", _hostname, _port);
#endif
}
void ArduinoOTAClass::_runUpdate(){
if(!Update.begin(_size, _cmd)){
#if OTA_DEBUG
Serial.println("Update Begin Error");
#endif
if (_error_callback) _error_callback(OTA_BEGIN_ERROR);
_udp_ota->begin(_port);
_state = OTA_IDLE;
return;
}
Update.setMD5(_md5);
WiFiUDP::stopAll();
WiFiClient::stopAll();
if (_start_callback) _start_callback();
if (_progress_callback) _progress_callback(0, _size);
WiFiClient client;
if (!client.connect(_ota_ip, _ota_port)) {
#if OTA_DEBUG
Serial.printf("Connect Failed\n");
#endif
_udp_ota->begin(_port);
if (_error_callback) _error_callback(OTA_CONNECT_ERROR);
_state = OTA_IDLE;
}
uint32_t written, total = 0;
while(!Update.isFinished() && client.connected()){
int waited = 1000;
while(!client.available() && waited--)
delay(1);
if(!waited){
#if OTA_DEBUG
Serial.printf("Recieve Failed\n");
#endif
_udp_ota->begin(_port);
if (_error_callback) _error_callback(OTA_RECIEVE_ERROR);
_state = OTA_IDLE;
}
written = Update.write(client);
if(written > 0){
client.print(written, DEC);
total += written;
if(_progress_callback) _progress_callback(total, _size);
}
}
if(Update.end()){
client.print("OK");
#if OTA_DEBUG
Serial.printf("Update Success\nRebooting...\n");
#endif
if(_end_callback) _end_callback();
ESP.restart();
} else {
_udp_ota->begin(_port);
if (_error_callback) _error_callback(OTA_END_ERROR);
Update.printError(client);
#if OTA_DEBUG
Update.printError(Serial);
#endif
_state = OTA_IDLE;
}
}
void ArduinoOTAClass::handle() {
if (!*_udp_ota) { if (!*_udp_ota) {
_udp_ota->begin(_port); _udp_ota->begin(_port);
if (_serial_debug) { #if OTA_DEBUG
Serial.println("OTA restarted"); Serial.println("OTA restarted");
} #endif
} }
if (!_udp_ota->parsePacket()) return; if (!_udp_ota->parsePacket()) return;
IPAddress remote = _udp_ota->remoteIP(); if(_state == OTA_IDLE){
int cmd = _udp_ota->parseInt(); _ota_ip = _udp_ota->remoteIP();
int port = _udp_ota->parseInt(); _cmd = _udp_ota->parseInt();
int size = _udp_ota->parseInt(); _ota_port = _udp_ota->parseInt();
_size = _udp_ota->parseInt();
_udp_ota->read();
sprintf(_md5, "%s", _udp_ota->readStringUntil('\n').c_str());
if (_serial_debug){ #if OTA_DEBUG
Serial.print("Update Start: ip:"); Serial.print("Update Start: ip:");
Serial.print(remote); Serial.print(_ota_ip);
Serial.printf(", port:%d, size:%d\n", port, size); Serial.printf(", port:%d, size:%d, md5:%s\n", _ota_port, _size, _md5);
#endif
_udp_ota->beginPacket(_ota_ip, _udp_ota->remotePort());
if(_password){
MD5Builder nonce_md5;
nonce_md5.begin();
nonce_md5.add(String(micros()));
nonce_md5.calculate();
nonce_md5.getChars(_nonce);
_udp_ota->printf("AUTH %s", _nonce);
_udp_ota->endPacket();
_state = OTA_WAITAUTH;
return;
} else {
_udp_ota->print("OK");
_udp_ota->endPacket();
_state = OTA_RUNUPDATE;
}
} else if(_state == OTA_WAITAUTH){
String cnonce = _udp_ota->readStringUntil(' ');
String response = _udp_ota->readStringUntil('\n');
MD5Builder _passmd5;
_passmd5.begin();
_passmd5.add(_password);
_passmd5.calculate();
String passmd5 = _passmd5.toString();
String challenge = passmd5 + ":" + String(_nonce) + ":" + cnonce;
MD5Builder _challengemd5;
_challengemd5.begin();
_challengemd5.add(challenge);
_challengemd5.calculate();
String result = _challengemd5.toString();
if(result.equals(response)){
_udp_ota->beginPacket(_ota_ip, _udp_ota->remotePort());
_udp_ota->print("OK");
_udp_ota->endPacket();
_state = OTA_RUNUPDATE;
} else {
_udp_ota->beginPacket(_ota_ip, _udp_ota->remotePort());
_udp_ota->print("Authentication Failed");
_udp_ota->endPacket();
if (_error_callback) _error_callback(OTA_AUTH_ERROR);
_state = OTA_IDLE;
}
} }
WiFiUDP::stopAll(); if(_state == OTA_RUNUPDATE)
_runUpdate();
if(!Update.begin(size, cmd)){
if (_serial_debug)
Serial.println("Update Begin Error");
if (_error_callback) _error_callback();
_udp_ota->begin(_port);
return;
}
if (_start_callback) _start_callback();
if (_progress_callback) _progress_callback(0, size);
WiFiClient client;
if (!client.connect(remote, port)) {
if (_serial_debug)
Serial.printf("Connect Failed\n");
_udp_ota->begin(_port);
if (_error_callback) _error_callback();
}
uint32_t written;
while(!Update.isFinished() && client.connected()){
// TODO(mangelajo): enhance the Update.write(client) to
// accept a progress callback
written = Update.write(client);
if(written > 0) client.print(written, DEC);
if(_progress_callback) _progress_callback(written, size);
}
Serial.setDebugOutput(false);
if(Update.end()){
client.println("OK");
if (_serial_debug)
Serial.printf("Update Success\nRebooting...\n");
if(_end_callback) _end_callback();
ESP.restart();
} else {
// Update failed: listen UDP again, callback and print
_udp_ota->begin(_port);
if (_error_callback) _error_callback();
Update.printError(client);
if (_serial_debug)
Update.printError(Serial);
}
} }
ArduinoOTAClass ArduinoOTA;

View File

@ -5,31 +5,58 @@ class WiFiUDP;
#define OTA_CALLBACK(callback) void (*callback)() #define OTA_CALLBACK(callback) void (*callback)()
#define OTA_CALLBACK_PROGRESS(callback) void (*callback)(unsigned int, unsigned int) #define OTA_CALLBACK_PROGRESS(callback) void (*callback)(unsigned int, unsigned int)
#define OTA_CALLBACK_ERROR(callback) void (*callback)(ota_error_t)
class ArduinoOTA typedef enum {
OTA_IDLE,
OTA_WAITAUTH,
OTA_RUNUPDATE
} ota_state_t;
typedef enum {
OTA_AUTH_ERROR,
OTA_BEGIN_ERROR,
OTA_CONNECT_ERROR,
OTA_RECIEVE_ERROR,
OTA_END_ERROR
} ota_error_t;
class ArduinoOTAClass
{ {
private:
int _port; int _port;
String* _mdns_host; char *_password;
char * _hostname;
char * _nonce;
WiFiUDP* _udp_ota; WiFiUDP* _udp_ota;
bool _serial_debug; bool _initialized;
ota_state_t _state;
int _size, _cmd, _ota_port;
IPAddress _ota_ip;
char * _md5;
OTA_CALLBACK(_start_callback); OTA_CALLBACK(_start_callback);
OTA_CALLBACK(_end_callback); OTA_CALLBACK(_end_callback);
OTA_CALLBACK(_error_callback); OTA_CALLBACK_ERROR(_error_callback);
OTA_CALLBACK_PROGRESS(_progress_callback); OTA_CALLBACK_PROGRESS(_progress_callback);
public: void _runUpdate(void);
ArduinoOTA(const char *mdns_host="ESP8266-OTA-",
int port=8266, public:
bool serial_debug=true); ArduinoOTAClass();
~ArduinoOTA(); ~ArduinoOTAClass();
void setup(); void setPort(uint16_t port);
void handle(); void setHostname(const char *hostname);
void onStart(OTA_CALLBACK(fn)); void setPassword(const char *password);
void onEnd(OTA_CALLBACK(fn)); void onStart(OTA_CALLBACK(fn));
void onProgress(OTA_CALLBACK_PROGRESS(fn)); void onEnd(OTA_CALLBACK(fn));
void onError(OTA_CALLBACK (fn)); void onProgress(OTA_CALLBACK_PROGRESS(fn));
void onError(OTA_CALLBACK_ERROR (fn));
void begin();
void handle();
}; };
extern ArduinoOTAClass ArduinoOTA;
#endif /* __ARDUINO_OTA_H */ #endif /* __ARDUINO_OTA_H */

View File

@ -6,26 +6,36 @@
const char* ssid = "..."; const char* ssid = "...";
const char* password = "..."; const char* password = "...";
ArduinoOTA ota_server;
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println("Booting");
Serial.println("Booting"); WiFi.mode(WIFI_STA);
WiFi.mode(WIFI_STA); WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED){
/* try the flash stored password first */ Serial.println("Connection Failed! Rebooting...");
WiFi.begin(); delay(5000);
ESP.reset();
while (WiFi.waitForConnectResult() != WL_CONNECTED){
WiFi.begin(ssid, password);
Serial.println("Retrying connection...");
} }
ota_server.setup(); //ArduinoOTA.setPort(8266);//Defaults to 8266
//ArduinoOTA.setHostname((const char *)"myesp8266");//Defaults to esp8266-[ChipID]
//ArduinoOTA.setPassword((const char *)"123");//defaults to no authentication
ArduinoOTA.onStart([]() { Serial.println("Start"); });
ArduinoOTA.onEnd([]() { Serial.println("End"); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\n", (progress/(total/100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if(error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if(error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if(error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if(error == OTA_RECIEVE_ERROR) Serial.println("Recieve Failed");
else if(error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready"); Serial.println("Ready");
} }
void loop() { void loop() {
ota_server.handle(); ArduinoOTA.handle();
yield();
} }

View File

@ -5,9 +5,7 @@
const char* ssid = "..."; const char* ssid = "...";
const char* password = "..."; const char* password = "...";
const char* host_prefix = "OTA-LEDS-"; const char* host = "OTA-LEDS";
ArduinoOTA ota_server(host_prefix, 8266, /* debug_serial= */ true);
int led_pin = 13; int led_pin = 13;
#define N_DIMMERS 3 #define N_DIMMERS 3
@ -23,8 +21,7 @@ void setup() {
Serial.println("Booting"); Serial.println("Booting");
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
/* try the flash stored password first */ WiFi.begin(ssid, password);
WiFi.begin();
while (WiFi.waitForConnectResult() != WL_CONNECTED){ while (WiFi.waitForConnectResult() != WL_CONNECTED){
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
@ -33,10 +30,6 @@ void setup() {
/* switch off led */ /* switch off led */
digitalWrite(led_pin, HIGH); digitalWrite(led_pin, HIGH);
/* setup the OTA server */
ota_server.setup();
Serial.println("Ready");
/* configure dimmers, and OTA server events */ /* configure dimmers, and OTA server events */
analogWriteRange(1000); analogWriteRange(1000);
analogWrite(led_pin,990); analogWrite(led_pin,990);
@ -47,13 +40,14 @@ void setup() {
analogWrite(dimmer_pin[i],50); analogWrite(dimmer_pin[i],50);
} }
ota_server.onStart([]() { // switch off all the PWMs during upgrade ArduinoOTA.setHostname(host);
ArduinoOTA.onStart([]() { // switch off all the PWMs during upgrade
for(int i=0; i<N_DIMMERS;i++) for(int i=0; i<N_DIMMERS;i++)
analogWrite(dimmer_pin[i], 0); analogWrite(dimmer_pin[i], 0);
analogWrite(led_pin,0); analogWrite(led_pin,0);
}); });
ota_server.onEnd([]() { // do a fancy thing with our board led at end ArduinoOTA.onEnd([]() { // do a fancy thing with our board led at end
for (int i=0;i<30;i++) for (int i=0;i<30;i++)
{ {
analogWrite(led_pin,(i*100) % 1001); analogWrite(led_pin,(i*100) % 1001);
@ -61,11 +55,14 @@ void setup() {
} }
}); });
ota_server.onError([]() { ESP.restart(); }); ArduinoOTA.onError([](ota_error_t error) { ESP.restart(); });
/* setup the OTA server */
ArduinoOTA.begin();
Serial.println("Ready");
} }
void loop() { void loop() {
ota_server.handle(); ArduinoOTA.handle();
yield();
} }

View File

@ -1,107 +0,0 @@
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
const char* host = "esp8266-ota";
const char* ssid = "**********";
const char* pass = "**********";
const uint16_t ota_port = 8266;
const char* ota_pass = "1234";
WiFiUDP OTA;
WiFiServer MonitorServer(ota_port);
WiFiClient Monitor;
void setup() {
Serial.begin(115200);
Serial.println("");
Serial.println("Bare Minimum Arduino OTA");
Serial.printf("Sketch size: %u\n", ESP.getSketchSize());
Serial.printf("Free size: %u\n", ESP.getFreeSketchSpace());
WiFi.begin(ssid, pass);
if(WiFi.waitForConnectResult() == WL_CONNECTED){
MDNS.begin(host);
MDNS.enableArduino(ota_port, true);
OTA.begin(ota_port);
MonitorServer.begin();
MonitorServer.setNoDelay(true);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi Connect Failed");
delay(10000);
ESP.reset();
}
}
void loop() {
if (OTA.parsePacket()) {
IPAddress remote = OTA.remoteIP();
String pass = OTA.readStringUntil(' ');
int cmd = OTA.parseInt();
int port = OTA.parseInt();
int size = OTA.parseInt();
if(!pass.equals(String(ota_pass))){
Serial.println("ERROR: Wrong Password");
return;
}
Serial.print("Update Start: ip:");
Serial.print(remote);
Serial.printf(", port:%d, size:%d\n", port, size);
uint32_t startTime = millis();
if(!Update.begin(size)){
Update.printError(Serial);
return;
}
WiFiUDP::stopAll();
WiFiClient::stopAll();
WiFiClient client;
if (client.connect(remote, port)) {
uint32_t written;
while(!Update.isFinished()){
written = Update.write(client);
if(written > 0) client.print(written, DEC);
}
if(Update.end()){
client.println("OK");
Serial.printf("Update Success: %u\nRebooting...\n", millis() - startTime);
ESP.restart();
} else {
Update.printError(client);
Update.printError(Serial);
}
} else {
Serial.printf("Connect Failed: %u\n", millis() - startTime);
}
}
//IDE Monitor (connected to Serial)
if (MonitorServer.hasClient()){
if (!Monitor || !Monitor.connected()){
if(Monitor) Monitor.stop();
Monitor = MonitorServer.available();
} else {
MonitorServer.available().stop();
}
}
if (Monitor && Monitor.connected() && Monitor.available()){
while(Monitor.available())
Serial.write(Monitor.read());
}
if(Serial.available()){
size_t len = Serial.available();
uint8_t * sbuf = (uint8_t *)malloc(len);
Serial.readBytes(sbuf, len);
if (Monitor && Monitor.connected()){
Monitor.write((uint8_t *)sbuf, len);
delay(0);
}
free(sbuf);
}
delay(0);
}

View File

@ -38,10 +38,6 @@ const char* ap_default_psk = "esp8266esp8266"; ///< Default PSK.
/// Uncomment the next line for verbose output over UART. /// Uncomment the next line for verbose output over UART.
//#define SERIAL_VERBOSE //#define SERIAL_VERBOSE
/// OTA server handle.
ArduinoOTA ota_server;
/** /**
* @brief Read WiFi connection information from file system. * @brief Read WiFi connection information from file system.
* @param ssid String pointer for storing SSID. * @param ssid String pointer for storing SSID.
@ -244,7 +240,8 @@ void setup()
} }
// Start OTA server. // Start OTA server.
ota_server.setup(); ArduinoOTA.setHostname((const char *)hostname.c_str());
ArduinoOTA.begin();
} }
@ -254,7 +251,7 @@ void setup()
void loop() void loop()
{ {
// Handle OTA server. // Handle OTA server.
ota_server.handle(); ArduinoOTA.handle();
yield(); yield();
} }

View File

@ -64,7 +64,7 @@ recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
## Create archives ## Create archives
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}"
## Combine gc-sections, archives, and objects ## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/{archive_file}" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}" recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/{archive_file}" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}"

View File

@ -4,11 +4,12 @@
# https://gist.github.com/igrr/d35ab8446922179dc58c # https://gist.github.com/igrr/d35ab8446922179dc58c
# #
# Modified since 2015-09-18 from Pascal Gollor (https://github.com/pgollor) # Modified since 2015-09-18 from Pascal Gollor (https://github.com/pgollor)
# Modified since 2015-11-09 from Hristo Gochkov (https://github.com/me-no-dev)
# #
# This script will push an OTA update to the ESP # This script will push an OTA update to the ESP
# use it like: python espota.py -i <ESP_IP_address> -p <ESP_port> -f <sketch.bin> # use it like: python espota.py -i <ESP_IP_address> -p <ESP_port> [-a password] -f <sketch.bin>
# Or to upload SPIFFS image: # Or to upload SPIFFS image:
# python espota.py -i <ESP_IP_address> -p <ESP_port> -s -f <spiffs.bin> # python espota.py -i <ESP_IP_address> -p <ESP_port> [-a password] -s -f <spiffs.bin>
# #
# Changes # Changes
# 2015-09-18: # 2015-09-18:
@ -16,6 +17,11 @@
# - Add logging. # - Add logging.
# - Send command to controller to differ between flashing and transmitting SPIFFS image. # - Send command to controller to differ between flashing and transmitting SPIFFS image.
# #
# Changes
# 2015-11-09:
# - Added digest authentication
# - Enchanced error tracking and reporting
#
from __future__ import print_function from __future__ import print_function
import socket import socket
@ -23,6 +29,7 @@ import sys
import os import os
import optparse import optparse
import logging import logging
import hashlib
# Commands # Commands
FLASH = 0 FLASH = 0
@ -43,14 +50,55 @@ def serve(remoteAddr, remotePort, password, filename, command = FLASH):
return 1 return 1
content_size = os.path.getsize(filename) content_size = os.path.getsize(filename)
f = open(filename,'rb')
file_md5 = hashlib.md5(f.read()).hexdigest()
f.close()
logging.info('Upload size: %d', content_size) logging.info('Upload size: %d', content_size)
message = '%s %d %d %d\n' % (password, command, serverPort, content_size) message = '%d %d %d %s\n' % (command, serverPort, content_size, file_md5)
# Wait for a connection # Wait for a connection
logging.info('Sending invitation to: %s', remoteAddr) logging.info('Sending invitation to: %s', remoteAddr)
sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
remote_address = (remoteAddr, int(remotePort)) remote_address = (remoteAddr, int(remotePort))
sent = sock2.sendto(message, remote_address) sent = sock2.sendto(message, remote_address)
sock2.settimeout(10)
try:
data = sock2.recv(37)
except:
logging.error('No Answer')
sock2.close()
return 1
if (data != "OK"):
if(data.startswith('AUTH')):
nonce = data.split()[1]
cnonce_text = '%s%u%s%s' % (filename, content_size, file_md5, remoteAddr)
cnonce = hashlib.md5(cnonce_text).hexdigest()
passmd5 = hashlib.md5(password).hexdigest()
result_text = '%s:%s:%s' % (passmd5 ,nonce, cnonce)
result = hashlib.md5(result_text).hexdigest()
sys.stderr.write('Authenticating...')
sys.stderr.flush()
message = '%s %s\n' % (cnonce, result)
sock2.sendto(message, remote_address)
sock2.settimeout(10)
try:
data = sock2.recv(32)
except:
sys.stderr.write('FAIL\n')
logging.error('No Answer to our Authentication')
sock2.close()
return 1
if (data != "OK"):
sys.stderr.write('FAIL\n')
logging.error('%s', data)
sock2.close()
sys.exit(1);
return 1
sys.stderr.write('OK\n')
else:
logging.error('Bad Answer: %s', data)
sock2.close()
return 1
sock2.close() sock2.close()
logging.info('Waiting for device...') logging.info('Waiting for device...')
@ -94,9 +142,13 @@ def serve(remoteAddr, remotePort, password, filename, command = FLASH):
connection.close() connection.close()
f.close() f.close()
sock.close() sock.close()
if (data != "OK"):
sys.stderr.write('\n')
logging.error('%s', data)
return 1;
return 0 return 0
except: except:
logging.error('Result: No Answer!') logging.error('No Result!')
connection.close() connection.close()
f.close() f.close()
sock.close() sock.close()