diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp
index 6ef4f93ae7..fc1320f5e8 100644
--- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp
+++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp
@@ -15,13 +15,20 @@ R"(<html><body><form method='POST' action='' enctype='multipart/form-data'>
 const char* ESP8266HTTPUpdateServer::_failedResponse = R"(Update Failed!)";
 const char* ESP8266HTTPUpdateServer::_successResponse = "<META http-equiv=\"refresh\" content=\"15;URL=\">Update Success! Rebooting...";
 
+template<class ...Ts>
+void ESP8266HTTPUpdateServer::debug(const char *fmt, Ts... args) {
+    if (_serial_output) {
+        Serial.printf(fmt, args...);
+    }
+}
+
 ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug)
 {
-  _serial_output = serial_debug;
-  _server = NULL;
-  _username = NULL;
-  _password = NULL;
-  _authenticated = false;
+    _serial_output = serial_debug;
+    _server = NULL;
+    _username = NULL;
+    _password = NULL;
+    _authenticated = false;
 }
 
 void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, const char * username, const char * password)
@@ -31,57 +38,123 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path,
     _password = (char *)password;
 
     // handler for the /update form page
-    _server->on(path, HTTP_GET, [&](){
-      if(_username != NULL && _password != NULL && !_server->authenticate(_username, _password))
-        return _server->requestAuthentication();
-      _server->send(200, "text/html", _serverIndex);
+    _server->on(path, HTTP_GET, [&]() {
+        if (_username != NULL && _password != NULL && !_server->authenticate(_username, _password)) {
+            return _server->requestAuthentication();
+        }
+        _server->send(200, "text/html", _serverIndex);
     });
 
     // handler for the /update form POST (once file upload finishes)
-    _server->on(path, HTTP_POST, [&](){
-      if(!_authenticated)
-        return _server->requestAuthentication();
-      _server->send(200, "text/html", Update.hasError() ? _failedResponse : _successResponse);
-      ESP.restart();
-    },[&](){
-      // handler for the file upload, get's the sketch bytes, and writes
-      // them through the Update object
-      HTTPUpload& upload = _server->upload();
-      if(upload.status == UPLOAD_FILE_START){
-        if (_serial_output)
-          Serial.setDebugOutput(true);
-
-        _authenticated = (_username == NULL || _password == NULL || _server->authenticate(_username, _password));
-        if(!_authenticated){
-          if (_serial_output)
-            Serial.printf("Unauthenticated Update\n");
-          return;
+    _server->on(path, HTTP_POST, [&]() {
+        if (!_authenticated) {
+            return _server->requestAuthentication();
         }
+        _server->send(200, "text/html", Update.hasError() ? _failedResponse : _successResponse);
+        ESP.restart();
+    }, [&]() {
+        // handler for the file upload, get's the sketch bytes, and writes
+        // them through the Update object
+        HTTPUpload& upload = _server->upload();
+        if (upload.status == UPLOAD_FILE_START) {
+            if (_serial_output) {
+                Serial.setDebugOutput(true);
+            }
+            handle_start();
 
-        WiFiUDP::stopAll();
-        if (_serial_output)
-          Serial.printf("Update: %s\n", upload.filename.c_str());
-        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
-        if(!Update.begin(maxSketchSpace)){//start with max available size
-          if (_serial_output) Update.printError(Serial);
-        }
-      } else if(_authenticated && upload.status == UPLOAD_FILE_WRITE){
-        if (_serial_output) Serial.printf(".");
-        if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
-          if (_serial_output) Update.printError(Serial);
+            _authenticated = (_username == NULL || _password == NULL || _server->authenticate(_username, _password));
+            if (!_authenticated) {
+                debug("Unauthenticated Update\n");
+                handle_error(1);
+                return;
+            }
 
+            WiFiUDP::stopAll();
+            debug("Update: %s\n", upload.filename.c_str());
+            uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
+            if (!Update.begin(maxSketchSpace)) {//start with max available size
+                if (_serial_output) {
+                    Update.printError(Serial);
+                    handle_error(2);
+                }
+            }
+            handle_progress(0, upload.totalSize);
+        } else if (_authenticated && upload.status == UPLOAD_FILE_WRITE) {
+            debug(".");
+            if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
+                if (_serial_output) {
+                    Update.printError(Serial);
+                    handle_error(3);
+                }
+            }
+            handle_progress(upload.currentSize, upload.totalSize);
+        } else if (_authenticated && upload.status == UPLOAD_FILE_END) {
+            if (Update.end(true)) { //true to set the size to the current progress
+                debug("Update Success: %u\nRebooting...\n", upload.totalSize);
+                handle_progress(upload.totalSize, upload.totalSize);
+                handle_end();
+            } else {
+                if (_serial_output) {
+                    Update.printError(Serial);
+                    handle_error(4);
+                }
+            }
+            if (_serial_output) {
+                Serial.setDebugOutput(false);
+            }
+        } else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED) {
+            Update.end();
+            debug("Update was aborted");
+            handle_error(5);
         }
-      } else if(_authenticated && upload.status == UPLOAD_FILE_END){
-        if(Update.end(true)){ //true to set the size to the current progress
-          if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
-        } else {
-          if (_serial_output) Update.printError(Serial);
-        }
-        if (_serial_output) Serial.setDebugOutput(false);
-      } else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){
-        Update.end();
-        if (_serial_output) Serial.println("Update was aborted");
-      }
-      delay(0);
+        delay(0);
     });
 }
+
+void ESP8266HTTPUpdateServer::onStart(THandlerFunction fn)
+{
+    _cb_start = fn;
+}
+
+void ESP8266HTTPUpdateServer::onEnd(THandlerFunction fn)
+{
+    _cb_end = fn;
+}
+
+void ESP8266HTTPUpdateServer::onError(THandlerFunction_Error fn)
+{
+    _cb_error = fn;
+}
+
+void ESP8266HTTPUpdateServer::onProgress(THandlerFunction_Progress fn)
+{
+    _cb_progress = fn;
+}
+
+void ESP8266HTTPUpdateServer::handle_start()
+{
+    if (_cb_start) {
+        _cb_start();
+    }
+}
+
+void ESP8266HTTPUpdateServer::handle_end()
+{
+    if (_cb_end) {
+        _cb_end();
+    }
+}
+
+void ESP8266HTTPUpdateServer::handle_error(int err)
+{
+    if (_cb_error) {
+        _cb_error(err);
+    }
+}
+
+void ESP8266HTTPUpdateServer::handle_progress(unsigned int i, unsigned int j)
+{
+    if (_cb_progress) {
+        _cb_progress(i, j);
+    }
+}
diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h
index fbe1d211d1..41c9f8bec7 100644
--- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h
+++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h
@@ -1,38 +1,70 @@
 #ifndef __HTTP_UPDATE_SERVER_H
 #define __HTTP_UPDATE_SERVER_H
 
+#include <functional>
+
 class ESP8266WebServer;
 
 class ESP8266HTTPUpdateServer
 {
-  private:
-    bool _serial_output;
-    ESP8266WebServer *_server;
-    static const char *_serverIndex;
-    static const char *_failedResponse;
-    static const char *_successResponse;
-    char * _username;
-    char * _password;
-    bool _authenticated;
-  public:
-    ESP8266HTTPUpdateServer(bool serial_debug=false);
+public:
+    typedef std::function<void(void)> THandlerFunction;
+    typedef std::function<void(int)> THandlerFunction_Error; // fixme enum?
+    typedef std::function<void(unsigned int chunk, unsigned int total)> THandlerFunction_Progress;
 
+    ESP8266HTTPUpdateServer(bool serial_debug = false);
     void setup(ESP8266WebServer *server)
     {
-      setup(server, NULL, NULL);
+        setup(server, NULL, NULL);
     }
 
     void setup(ESP8266WebServer *server, const char * path)
     {
-      setup(server, path, NULL, NULL);
+        setup(server, path, NULL, NULL);
     }
 
     void setup(ESP8266WebServer *server, const char * username, const char * password)
     {
-      setup(server, "/update", username, password);
+        setup(server, "/update", username, password);
     }
 
     void setup(ESP8266WebServer *server, const char * path, const char * username, const char * password);
+
+    //This callback will be called when an update starts
+    void onStart(THandlerFunction fn);
+
+    //This callback will be called when an update has finished
+    void onEnd(THandlerFunction fn);
+
+    //This callback will be called when an update encounters any error
+    void onError(THandlerFunction_Error fn);
+
+    //This callback will be called when an update is under way
+    void onProgress(THandlerFunction_Progress fn);
+
+
+private:
+    bool _serial_output;
+    ESP8266WebServer *_server;
+    static const char *_serverIndex;
+    static const char *_failedResponse;
+    static const char *_successResponse;
+    char * _username;
+    char * _password;
+    bool _authenticated;
+
+    THandlerFunction _cb_start;
+    THandlerFunction _cb_end;
+    THandlerFunction_Error _cb_error;
+    THandlerFunction_Progress _cb_progress;
+protected:
+    template<class ...Ts>
+    void debug(const char *fmt, Ts... args);
+    void handle_start();
+    void handle_end();
+    void handle_error(int);
+    void handle_progress(unsigned int, unsigned int);
+
 };