diff --git a/src/FSUpdater.cpp b/src/FSUpdater.cpp new file mode 100644 index 0000000..86e83db --- /dev/null +++ b/src/FSUpdater.cpp @@ -0,0 +1,74 @@ +#include "FSUpdater.h" +#include +#include + + +void FSUpdater::freeMemory() { + /* + if (bom != NULL) free(bom); + bom = NULL; + */ + if (bomBuffer != NULL) free(bomBuffer); + bomBuffer = NULL; + bomCounter = 0; + errorMessage = String(); +} + +void FSUpdater::manageFsOtaBom(String payload) { + freeMemory(); + //bom = malloc(sizeof(BomEntry) * MAX_FILES); + bomBuffer = (char *) malloc(payload.length()+1); + payload.toCharArray(bomBuffer, payload.length()+1); + memset(bom, sizeof(BomEntry) * MAX_FILES_IN_BOM, 0); + + char *parsePtr = bomBuffer; // to start + while (*parsePtr != 0) { + bom[bomCounter].executionMark = *parsePtr; + if (*parsePtr != ':') { errorMessage = String("Wrong seperation character ") + String(*parsePtr) + " at line " + String(bomCounter+1); return; } + ++parsePtr; + + bom[bomCounter].localFilename = parsePtr; + while (*parsePtr != ':' && *parsePtr != 0) ++parsePtr; + *parsePtr++ = 0; // End of string for localFilename + + char *size_string = parsePtr; + while (*parsePtr != ':' && *parsePtr != 0) ++parsePtr; + *parsePtr++ = 0; // End of string for localFilename + bom[bomCounter].filesize = atol(size_string); + + bom[bomCounter].md5 = parsePtr; + while (*parsePtr != ':' && *parsePtr != 0) ++parsePtr; + *parsePtr++ = 0; // End of string for localFilename + + bom[bomCounter].remoteFilename = parsePtr; + while (*parsePtr != ':' && *parsePtr != 0 && *parsePtr != '\n' && *parsePtr != '\r') ++parsePtr; + *parsePtr++ = 0; // End of string for localFilename + + // skip trailing characters if these are seperators or end of line + while (*parsePtr == ':' || *parsePtr == '\n' || *parsePtr == '\r' || *parsePtr == ' ') ++parsePtr; + ++bomCounter; + if (bomCounter != MAX_FILES_IN_BOM) { errorMessage = "Too many files in BOM, max=" + String(MAX_FILES_IN_BOM); return; } + } +} + +void FSUpdater::checkForUpdates() { + HTTPClient http; + + //http.begin("https://192.168.1.12/test.html", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS + http.begin(baseUrl + "/" + swVersion + "/bom"); //HTTP + Serial.printf("[HTTP] GET %s/%s/bom", baseUrl.c_str(), swVersion.c_str()); + // start connection and send HTTP header + int httpCode = http.GET(); + + // httpCode will be negative on error + if (httpCode > 0) { + if (httpCode == HTTP_CODE_OK) { + String payload = http.getString(); + manageFsOtaBom(payload); + } + } else { + Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); +} diff --git a/src/FSUpdater.h b/src/FSUpdater.h new file mode 100644 index 0000000..7ce7f59 --- /dev/null +++ b/src/FSUpdater.h @@ -0,0 +1,38 @@ +#ifndef FSUpdater_h_included +#define FSUpdater_h_included + +#include + +#define MAX_FILES_IN_BOM 20 + +typedef struct { + char *localFilename, *remoteFilename, *md5; + unsigned long filesize; + char executionMark; +} BomEntry; + +class FSUpdater { +public: + FSUpdater(String _baseUrl, String currentVersion, String user, String password): + baseUrl(_baseUrl), + swVersion(currentVersion), + authUser(user), + authPassword(password) {}; + void checkForUpdates(); + void manageFsOtaBom(String payload); + void freeMemory(); + boolean errorWhileParsingBom() { return (errorMessage.length() > 0); }; + String getBomParsingError() { return errorMessage; }; + unsigned int numberOfBomEntries() { return bomCounter; }; + BomEntry *getBomEntry(unsigned int num) { return &bom[num]; }; +protected: + String baseUrl; + String swVersion; + String authUser, authPassword; + BomEntry bom[MAX_FILES_IN_BOM]; // array of bom's, dynamically allocated + char *bomBuffer = NULL; + unsigned int bomCounter = 0; + String errorMessage; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 1ebe5e1..8086888 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,13 @@ /* Wemos8266RelaysLedDisplay/main.cpp + * (C) Dirk Jahnke */ #define COMPDATE __DATE__ __TIME__ -#define APP_VERSION "0.2.18" +// Following defines are set by build environment using -D parameter +// #define APP_VERSION "0.2.18" +// #define FS_UPDATE_BASE_URL "http://ota.iotjunkie.org/fc_client" +// #define FS_UPDATE_AUTH_USER "fcclient" +// #define FS_UPDATE_AUTH_PASSWORD "63Gs59PWveT6uQSh" #include #include @@ -15,11 +20,12 @@ #include "Relays.h" #include "Clock.h" #include "Display.h" +#include "FSUpdater.h" // Button pin on the esp for selecting modes. 0 for Generic devices! #define MODEBUTTON D3 -#define RELAY1_PIN D1 -#define RELAY2_PIN D2 +//#define RELAY1_PIN D1 +//#define RELAY2_PIN D2 #define DEBUG_RELAYS false #define DEBUG_DISPLAY false #define STARTUP1_ANIMATION_DURATION_ms 2000 @@ -38,21 +44,36 @@ Display D(&realTime, &modelTime); WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); +FSUpdater fsUpdater(FS_UPDATE_BASE_URL, APP_VERSION, FS_UPDATE_AUTH_USER, FS_UPDATE_AUTH_PASSWORD); #define mkstring(x) #x // Field default values -char *clockName = "FREMO"; -char *clockSpeed_modelMsPerRealSec_String = "250"; -char *relay1Pin_String = mkstring(RELAY1_PIN); -char *relay2Pin_String = mkstring(RELAY2_PIN); -int relay1Pin = RELAY1_PIN, relay2Pin = RELAY2_PIN; -char *relayHoldTime_ms_String = "200"; -char *relayMinOffTime_ms_String = "100"; - +#define CLOCK_NAME_LEN 8 +#define CLOCK_SPEED_LEN 4 +#define RELAY_PIN_LEN 2 +#define RELAY_TIMING_LEN 3 +#define CLOCK_NAME_DISPLAY_TIMING_LEN 5 +static char def_clockName[CLOCK_NAME_LEN+1] = "FREMO"; +static char def_clockSpeed_modelMsPerRealSec_String[CLOCK_SPEED_LEN+1] = "250"; +static char def_relay1Pin_String[RELAY_PIN_LEN+1] = mkstring(D1); +static char def_relay2Pin_String[RELAY_PIN_LEN+1] = mkstring(D2); +static int relay1Pin = D1, relay2Pin = D2; +static char def_relayHoldTime_ms_String[RELAY_TIMING_LEN+1] = "200"; +static char def_relayMinOffTime_ms_String[RELAY_TIMING_LEN+1] = "100"; // Clock Display Config Parameter -static char * displayClockNameEvery_ms_String = "16000"; -static char * displayClockNameDuration_ms_String = "1200"; +static char def_displayClockNameEvery_ms_String[CLOCK_NAME_DISPLAY_TIMING_LEN+1] = "16000"; +static char def_displayClockNameDuration_ms_String[CLOCK_NAME_DISPLAY_TIMING_LEN+1] = "1200"; + +static char *clockName = def_clockName; +static char *clockSpeed_modelMsPerRealSec_String = def_clockSpeed_modelMsPerRealSec_String; +static char *relay1Pin_String = def_relay1Pin_String; +static char *relay2Pin_String = def_relay2Pin_String; +static char *relayHoldTime_ms_String = def_relayHoldTime_ms_String; +static char *relayMinOffTime_ms_String = def_relayMinOffTime_ms_String; +static char *displayClockNameEvery_ms_String = def_displayClockNameEvery_ms_String; +static char *displayClockNameDuration_ms_String = def_displayClockNameDuration_ms_String; + void setupIAS(void) { #if defined ESP8266 @@ -69,14 +90,14 @@ void setupIAS(void) { IAS.preSetAutoUpdate(true); // define fields - IAS.addField(clockName, "Clock Name", 8, 'T'); - IAS.addField(clockSpeed_modelMsPerRealSec_String, "Model MilliSec per Real Sec", 8, 'N'); - IAS.addField(displayClockNameEvery_ms_String, "Display clock name every (ms)", 5, 'N'); - IAS.addField(displayClockNameDuration_ms_String, "Display clock name duration (ms)", 5, 'N'); - IAS.addField(relay1Pin_String, "Pin Relay 1", 2, 'P'); - IAS.addField(relay2Pin_String, "Pin Relay 2", 2, 'P'); - IAS.addField(relayHoldTime_ms_String, "Relay hold time (ms)", 3, 'N'); - IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", 3, 'N'); + IAS.addField(clockName, "Clock Name", CLOCK_NAME_LEN, 'T'); + IAS.addField(clockSpeed_modelMsPerRealSec_String, "Model MilliSec per Real Sec", CLOCK_SPEED_LEN, 'N'); + IAS.addField(displayClockNameEvery_ms_String, "Display clock name every (ms)", CLOCK_NAME_DISPLAY_TIMING_LEN, 'N'); + IAS.addField(displayClockNameDuration_ms_String, "Display clock name duration (ms)", CLOCK_NAME_DISPLAY_TIMING_LEN, 'N'); + IAS.addField(relay1Pin_String, "Pin Relay 1", RELAY_PIN_LEN, 'P'); + IAS.addField(relay2Pin_String, "Pin Relay 2", RELAY_PIN_LEN, 'P'); + IAS.addField(relayHoldTime_ms_String, "Relay hold time (ms)", RELAY_TIMING_LEN, 'N'); + IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", RELAY_TIMING_LEN, 'N'); IAS.onModeButtonShortPress([]() { Serial.println(F(" If mode button is released, I will enter firmware update mode.")); @@ -176,7 +197,7 @@ static unsigned long lastTimeOutput_ms = 0; void loop(void) { - static int lastMinutes = 0; + static unsigned int lastMinutes = 0; static unsigned long firstLoop_ts = 0; if (firstLoop_ts == 0) firstLoop_ts = millis(); @@ -213,7 +234,7 @@ void loop(void) D.loop(); - // toggle relays + // toggle relays on minute change if (lastMinutes != realTime.getMinutes()) { R.toggle(); lastMinutes = realTime.getMinutes(); diff --git a/src/web/0.2.18/bom-files b/src/web/0.2.18/bom-files new file mode 100644 index 0000000..8108ec0 --- /dev/null +++ b/src/web/0.2.18/bom-files @@ -0,0 +1,11 @@ +manifest.json.gz +main.css.gz +fremoei.gif.gz +img_fremo_sw.gif.gz +index.htm.gz +led-on.png.gz +led-off.png.gz +img_sh.gif.gz +btn-do.png.gz +btn.png.gz +favicon.ico.gz