Selaa lähdekoodia

add github downloader code, start debugging

Chris Mullins 8 vuotta sitten
vanhempi
commit
59b2baad44

+ 91 - 0
lib/GithubDownloader/GithubDownloader.cpp

@@ -0,0 +1,91 @@
+#include <GithubDownloader.h>
+#include <FS.h>
+  
+Stream& GithubDownloader::streamFile(const String& path) {
+  if (!client.connect(GITHUB_RAW_DOMAIN, 443)) {
+    Serial.println("Failed to connect to github over HTTPS.");
+  }
+  
+  if (!client.verify(GITHUB_SSL_FINGERPRINT, GITHUB_RAW_DOMAIN)) {
+    Serial.println("Failed to verify github certificate");
+  }
+  
+  client.print(String("GET ") + path + " HTTP/1.1\r\n" +
+               "Host: " + GITHUB_RAW_DOMAIN + "\r\n" +
+               "Connection: close\r\n\r\n");
+               
+  return client;
+}
+  
+Stream& GithubDownloader::streamFile(const String& username, const String& repo, const String& path) {
+  return streamFile(buildPath(username, repo, path));
+}
+  
+bool GithubDownloader::downloadFile(const String& path, Stream& dest) {
+  Stream& client = streamFile(path);
+  
+  if (client.available()) {
+    if (!client.find("\r\n\r\n")) {
+      Serial.println("Error seeking to body");
+      return false;
+    }
+  } else {
+    Serial.println("Failed to open stream to Github");
+    return false;
+  }
+               
+  while (client.available()) {
+    size_t l = client.readBytes(buffer, GITHUB_DOWNLOADER_BUFFER_SIZE);
+    size_t w = dest.write(buffer, l);
+    
+    dest.flush();
+    
+    if (w != l) {
+      printf("Error writing to stream. Expected to write %d bytes, but only wrote %d\n", l, w);
+      return false;
+    }
+    
+    printf("Read %d bytes\n", w);
+    
+    yield();
+  }
+  
+  return true;
+}
+
+bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, Stream& dest) {
+  return downloadFile(buildPath(username, repo, repoPath), dest);
+}
+
+bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, const String& fsPath) {
+  String tmpFile = fsPath + ".download_tmp";
+  File f = SPIFFS.open(tmpFile.c_str(), "w");
+  
+  if (!f) {
+    Serial.print("ERROR - could not open file for downloading: ");
+    Serial.println(fsPath);
+    return false;
+  }
+  
+  if (!downloadFile(buildPath(username, repo, repoPath), f)) {
+    f.close();
+    return false;
+  }
+  
+  f.flush();
+  f.close();
+  
+  SPIFFS.remove(fsPath);
+  SPIFFS.rename(tmpFile, fsPath);
+  
+  Serial.print("Finished downloading file: ");
+  Serial.println(fsPath);
+  Serial.println(f.size());
+  
+  return true;
+}
+  
+String GithubDownloader::buildPath(const String& username, const String& repo, const String& repoPath) {
+  String path = String("/") + username + "/" + repo + "/master/" + repoPath;
+  return path;
+}

+ 29 - 0
lib/GithubDownloader/GithubDownloader.h

@@ -0,0 +1,29 @@
+#include <Arduino.h>
+#include <WiFiClientSecure.h>
+
+#ifndef _GITHUB_DOWNLOADER
+#define _GITHUB_DOWNLOADER 
+
+#define GITHUB_DOWNLOADER_BUFFER_SIZE 100
+
+#define GITHUB_SSL_FINGERPRINT "21 99 13 84 63 72 17 13 B9 ED 0E 8F 00 A5 9B 73 0D D0 56 58"
+#define GITHUB_RAW_DOMAIN "raw.githubusercontent.com"
+
+class GithubDownloader {
+public:
+  Stream& streamFile(const String& path);
+  Stream& streamFile(const String& username, const String& repo, const String& path);
+  
+  bool downloadFile(const String& path, Stream& dest);
+  bool downloadFile(const String& username, const String& repo, const String& path, Stream& dest);
+  bool downloadFile(const String& username, const String& repo, const String& path, const String& fsPath);
+  
+  uint8_t buffer[GITHUB_DOWNLOADER_BUFFER_SIZE];
+  
+private:
+  WiFiClientSecure client;
+  
+  String buildPath(const String& username, const String& repo, const String& path);
+};
+
+#endif

+ 4 - 0
lib/Settings/Settings.h

@@ -18,6 +18,10 @@
 
 #define WEB_INDEX_FILENAME "/web/index.html"
 
+#define MILIGHT_GITHUB_USER "sidoh"
+#define MILIGHT_GITHUB_REPO "esp8266_milight_hub"
+#define MILIGHT_REPO_WEB_PATH "/data/web/index.html"
+
 class GatewayConfig {
 public:
   GatewayConfig(uint16_t deviceId, uint16_t port, uint8_t protocolVersion) 

+ 81 - 0
lib/WebServer/MiLightHttpServer.cpp

@@ -4,6 +4,7 @@
 #include <Settings.h>
 #include <MiLightHttpServer.h>
 #include <MiLightRadioConfig.h>
+#include <GithubDownloader.h>
 
 void MiLightHttpServer::begin() {
   applySettings(settings);
@@ -17,6 +18,7 @@ void MiLightHttpServer::begin() {
   server.onPattern("/gateways/:device_id/:type/:group_id", HTTP_PUT, [this](const UrlTokenBindings* b) { handleUpdateGroup(b); });
   server.onPattern("/gateways/:device_id/:type", HTTP_PUT, [this](const UrlTokenBindings* b) { handleUpdateGateway(b); });
   server.onPattern("/send_raw/:type", HTTP_PUT, [this](const UrlTokenBindings* b) { handleSendRaw(b); });
+  server.onPattern("/download_update/:component", HTTP_GET, [this](const UrlTokenBindings* b) { handleDownloadUpdate(b); });
   server.on("/web", HTTP_POST, [this]() { server.send(200, "text/plain", "success"); }, handleUpdateFile(WEB_INDEX_FILENAME));
   server.on("/about", HTTP_GET, [this]() { handleAbout(); });
   server.on("/firmware", HTTP_POST, 
@@ -55,6 +57,85 @@ void MiLightHttpServer::handleClient() {
   server.handleClient();
 }
 
+void MiLightHttpServer::handleDownloadUpdate(const UrlTokenBindings* bindings) {
+  GithubDownloader* downloader = new GithubDownloader();
+  const String& component = bindings->get("component");
+  
+  if (component.equalsIgnoreCase("web")) {
+    Serial.println("Attempting to update web UI...");
+    
+    const bool result = downloader->downloadFile(
+      MILIGHT_GITHUB_USER,
+      MILIGHT_GITHUB_REPO,
+      MILIGHT_REPO_WEB_PATH,
+      WEB_INDEX_FILENAME
+    );
+    
+    Serial.println("Download complete!");
+    
+    if (result) {
+      server.sendHeader("Location", "/");
+      server.send(302);
+    } else {
+      server.send(500, "text/plain", "Failed to download update from Github. Check serial logs for more information.");
+    }
+  } else if (component.equalsIgnoreCase("firmware")) {
+    String firmwareFile = String("dist/firmware-") + FIRMWARE_VARIANT + ".bin";
+    Stream& stream = downloader->streamFile(
+      MILIGHT_GITHUB_USER,
+      MILIGHT_GITHUB_REPO,
+      firmwareFile
+    );
+    
+    if (stream.available()) {
+      WiFiUDP::stopAll();
+      uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
+      
+      if(!Update.begin(maxSketchSpace)){//start with max available size
+        Update.printError(Serial);
+        return;
+      }
+      
+      size_t read = 0;
+      
+      while (stream.available()) {
+        size_t l = stream.readBytes(downloader->buffer, GITHUB_DOWNLOADER_BUFFER_SIZE);
+        read += l;
+    
+        Serial.print("Read ");
+        Serial.print(l);
+        Serial.print(" bytes from Github (");
+        Serial.print(read);
+        Serial.println(" total)");
+        
+        if (Update.write(downloader->buffer, l) != l) {
+          Update.printError(Serial);
+          return;
+        }
+        
+        Serial.println("Write to flash");
+        
+        yield();
+      }
+      
+      Serial.println("Update complete");
+      
+      if (! Update.end(true)) {
+        server.send(200, "text/plain", String(FIRMWARE_VARIANT));
+      } else {
+        Serial.println("Error completing update");
+      }
+    } else {
+      server.send(500, "text/plain", "Couldn't open strem to firmware file on Github. Check serial logs.");
+    }
+  } else {
+    String body = String("Unknown component: ") + component;
+    server.send(400, "text/plain", body);
+  }
+  
+  delete downloader;
+}
+
 void MiLightHttpServer::applySettings(Settings& settings) {
   if (server.authenticationRequired() && !settings.hasAuthSettings()) {
     server.disableAuthentication();

+ 1 - 0
lib/WebServer/MiLightHttpServer.h

@@ -38,6 +38,7 @@ protected:
   void handleSendRaw(const UrlTokenBindings* urlBindings);
   void handleUpdateGroup(const UrlTokenBindings* urlBindings);
   void handleUpdateGateway(const UrlTokenBindings* urlBindings);
+  void handleDownloadUpdate(const UrlTokenBindings* urlBindings);
   
   File updateFile;
   

+ 1 - 0
src/main.cpp

@@ -3,6 +3,7 @@
 #include <ArduinoJson.h>
 #include <stdlib.h>
 #include <FS.h>
+#include <GithubDownloader.h>
 #include <IntParsing.h>
 #include <MiLightClient.h>
 #include <MiLightRadioConfig.h>