Compare commits
	
		
			16 Commits
		
	
	
		
			263d47d8d0
			...
			e3e01da80b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e3e01da80b | ||
|  | 2eb604d24d | ||
|  | 04a5eb9643 | ||
|  | 9988b03306 | ||
|  | beefe8e355 | ||
|  | 967e5ccdbe | ||
|  | 09aee48f27 | ||
|  | 0dcb532007 | ||
|  | 63b6cf626f | ||
|  | d0d5df2b98 | ||
|  | 86452fb1b8 | ||
|  | f547c8fc07 | ||
|  | ab493ef6d8 | ||
|  | 636acb1be1 | ||
|  | ff16dbcfce | ||
|  | 636c3093de | 
							
								
								
									
										8
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @ -6,9 +6,9 @@ | ||||
|         { | ||||
|             "label": "Build", | ||||
|             "type": "shell", | ||||
|             "command": "arduino-cli compile -v --warnings all -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 -e \"`pwd`/src/app\"", | ||||
|             "command": "arduino-cli compile -v --warnings all -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2n,dbg=Disabled,lvl=None____,wipe=none,baud=921600 -e \"`pwd`/src/app\"", | ||||
|             "windows":{ | ||||
|                 "command": "arduino-cli compile -v --warnings all -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 -e ((pwd).path + '/src/app')" | ||||
|                 "command": "arduino-cli compile -v --warnings all -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2n,dbg=Disabled,lvl=None____,wipe=none,baud=921600 -e ((pwd).path + '/src/app')" | ||||
|             }, | ||||
|             "group": "build", | ||||
|             "presentation": { | ||||
| @ -23,9 +23,9 @@ | ||||
|         { | ||||
|             "label": "Flash", | ||||
|             "type": "shell", | ||||
|             "command": "arduino-cli upload -v -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 \"`pwd`/src/app\" -p ${input:com_port}", | ||||
|             "command": "arduino-cli upload -v -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2n,dbg=Disabled,lvl=None____,wipe=none,baud=921600 \"`pwd`/src/app\" -p ${input:com_port}", | ||||
|             "windows":{ | ||||
|                 "command": "arduino-cli upload -v -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=921600 ((pwd).path + '/src/app') -p ${input:com_port}" | ||||
|                 "command": "arduino-cli upload -v -b esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,stacksmash=enabled,ssl=basic,mmu=3232,non32xfer=fast,eesz=4M,led=2,ip=lm2n,dbg=Disabled,lvl=None____,wipe=none,baud=921600 ((pwd).path + '/src/app') -p ${input:com_port}" | ||||
|             }, | ||||
|             "group": "build", | ||||
|             "presentation": { | ||||
|  | ||||
							
								
								
									
										11
									
								
								sdCard_content/CONFIG/OTA.CFG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								sdCard_content/CONFIG/OTA.CFG
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| #This config file stores the configuration needed for OTA updates | ||||
| #If this file is not present or if there is an error at parsing time | ||||
| #the OTA update feature will be disabled. | ||||
| #If the OTA service does not require any auth key then set this field empty ie '' | ||||
| #The blank new line at then end of the file is mendatory. Without it, the last parameter won't be read. | ||||
| 
 | ||||
| ENABLED : 'true' | ||||
| OTA_SERVER_ADDRESS : 'OTA server IP address' | ||||
| OTA_SERVER_PORT : 80 | ||||
| OTA_SERVICE_PATH : 'OTA service url path on the server' | ||||
| OTA_SERVICE_AUTH_KEY : 'OTA service auth key' | ||||
| @ -8,9 +8,11 @@ | ||||
| WEB_ENABLED : 'true' | ||||
| WEB_PORT : 80 | ||||
| WEB_MAX_CLIENT : 0 | ||||
| WEB_WWW_DIR : '/WWW' | ||||
| FTP_ENABLED : 'true' | ||||
| FTP_LOGIN : 'ESP8266' | ||||
| FTP_PASSWORD : '12345678' | ||||
| FTP_ROOT_DIR : '/FTP' | ||||
| FTP_PORT : 21 | ||||
| FTP_DATA_PORT : 1024 | ||||
| FTP_MAX_CLIENT : 0 | ||||
|  | ||||
| @ -6,6 +6,7 @@ const uint16_t screenHeight, | ||||
| const uint16_t I2C_IOExpanderAddress, | ||||
| const uint16_t _I2C_RTCFlashAddress, | ||||
| const Pin SPI_SDCard_cs, | ||||
| const Pin onBoard_LED, | ||||
| const Pin I2C_sda,  | ||||
| const Pin I2C_scl,  | ||||
| const Pin SPI_mosi, | ||||
| @ -19,6 +20,7 @@ _SPI_mosi(SPI_mosi == DEFAULT_PIN ? GPIO_13_MOSI : SPI_mosi), | ||||
| _SPI_miso(SPI_miso == DEFAULT_PIN ? GPIO_12_MISO : SPI_miso), | ||||
| _SPI_clk(SPI_clk == DEFAULT_PIN ? GPIO_14_CLK : SPI_clk), | ||||
| _SPI_SDCard_cs(SPI_SDCard_cs == DEFAULT_PIN ? GPIO_2 : SPI_SDCard_cs), | ||||
| _onBoard_LED(onBoard_LED == DEFAULT_PIN ? GPIO_2 : onBoard_LED), | ||||
| _I2C_screenAddress(I2C_screenAddress), | ||||
| _I2C_IOExpanderAddress(I2C_IOExpanderAddress), | ||||
| _I2C_RTCFlashAddress(_I2C_RTCFlashAddress), | ||||
| @ -59,6 +61,11 @@ Pin BoardConfig::getSPI_SDCard_cs() const | ||||
| 	return _SPI_SDCard_cs; | ||||
| } | ||||
| 
 | ||||
| Pin BoardConfig::getOnBoard_LED() const | ||||
| { | ||||
| 	return _onBoard_LED; | ||||
| } | ||||
| 
 | ||||
| uint16_t BoardConfig::getI2C_screenAddress() const | ||||
| { | ||||
| 	return _I2C_screenAddress; | ||||
| @ -69,12 +76,11 @@ uint16_t BoardConfig::getI2C_IOExpanderAddress() const | ||||
| 	return _I2C_IOExpanderAddress; | ||||
| } | ||||
| 
 | ||||
| uint16_t BoardConfig::getRTCFlashAddress() const | ||||
| uint16_t BoardConfig::getI2C_RTCFlashAddress() const | ||||
| { | ||||
| 	return _I2C_RTCFlashAddress; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| uint32_t BoardConfig::getSPISpeed() const | ||||
| { | ||||
| 	return _SPISpeed; | ||||
|  | ||||
| @ -17,6 +17,7 @@ class BoardConfig | ||||
| 		const uint16_t I2C_IOExpanderAddress = 0x27, | ||||
| 		const uint16_t _I2C_RTCFlashAddress = 0x0, | ||||
| 		const Pin SPI_SDCard_cs = GPIO_2, | ||||
| 		const Pin onBoard_LED = GPIO_2, | ||||
| 		const Pin I2C_sda = GPIO_4_SDA,  | ||||
| 		const Pin I2C_scl = GPIO_5_SCL,  | ||||
| 		const Pin SPI_mosi = GPIO_13_MOSI, | ||||
| @ -32,10 +33,11 @@ class BoardConfig | ||||
| 		Pin getSPI_miso() const; | ||||
| 		Pin getSPI_clk() const; | ||||
| 		Pin getSPI_SDCard_cs() const; | ||||
| 		Pin getOnBoard_LED() const; | ||||
| 		 | ||||
| 		uint16_t getI2C_screenAddress() const; | ||||
| 		uint16_t getI2C_IOExpanderAddress() const; | ||||
| 		uint16_t getRTCFlashAddress() const; | ||||
| 		uint16_t getI2C_RTCFlashAddress() const; | ||||
| 		 | ||||
| 		uint32_t getSPISpeed() const; | ||||
| 		 | ||||
| @ -51,6 +53,7 @@ class BoardConfig | ||||
| 	const Pin _SPI_miso; | ||||
| 	const Pin _SPI_clk; | ||||
| 	const Pin _SPI_SDCard_cs; | ||||
| 	const Pin _onBoard_LED; | ||||
| 	 | ||||
| 	//2) I2C Addresses
 | ||||
| 	const uint16_t _I2C_screenAddress; | ||||
|  | ||||
| @ -72,7 +72,7 @@ void *CFGFileParser::parseFile() | ||||
|                 } | ||||
|             } | ||||
|             else if(readChar == ' ') _state = PARAM_SECTION; | ||||
|             else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || readChar == '_' || readChar == '-' || (readChar >= 48 && readChar <= 57)) | ||||
|             else if((readChar >= 65 && readChar <= 90) /*A to Z*/ || (readChar >= 97 && readChar <= 122) /*a to z*/ || (readChar >= 48 && readChar <= 57) /*0 to 9*/ || readChar == '_' || readChar == '-') | ||||
|             { | ||||
|                 if(_type == PARAMETER) | ||||
|                 { | ||||
| @ -100,7 +100,9 @@ void *CFGFileParser::parseFile() | ||||
|                 else | ||||
|                     _quotedValue = true; | ||||
|             } | ||||
|             else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || readChar == ' ' || readChar == '_' || readChar == '-' || (readChar >= 48 && readChar <= 57)) | ||||
|             else if((readChar >= 65 && readChar <= 90) /*A to Z*/ || (readChar >= 97 && readChar <= 122) /*a to z*/ || (readChar >= 48 && readChar <= 57) /*0 to 9*/ ||  | ||||
|                         readChar == ' ' || readChar == '_' || readChar == '-' || readChar == '.' || readChar == '/' | ||||
|                     ) | ||||
|             { | ||||
|                 //printf("%c",readChar);
 | ||||
|                 if(_type == PARAMETER) | ||||
| @ -123,7 +125,7 @@ void *CFGFileParser::parseFile() | ||||
|             _type = VALUE; | ||||
|             if(readChar == '\'')_state = OPENING_QUOTE; | ||||
|             else if(readChar == ' ') _state = PARAM_SECTION; | ||||
|             else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || (readChar >= 48 && readChar <= 57) || readChar == '-' || readChar == '_') | ||||
|             else if((readChar >= 65 && readChar <= 90) /*A to Z*/ || (readChar >= 97 && readChar <= 122) /*a to z*/ || (readChar >= 48 && readChar <= 57) /*0 to 9*/ || readChar == '_' || readChar == '-') | ||||
|             { | ||||
|                 _state = PARAM_SECTION; | ||||
| 
 | ||||
|  | ||||
| @ -24,7 +24,7 @@ public: | ||||
|     { | ||||
|         if(_value == NULL) | ||||
|             return false; | ||||
|         return strcmp(_value,"true") == 0 || strcmp(_value,"TRUE") == 0 ? true : false; | ||||
|         return strcasecmp(_value,"true") == 0 ? true : false; | ||||
|     } | ||||
|     const char *getParameter() const{return _parameter == NULL ? "" : _parameter;} | ||||
|     bool isQuotedParameter()const{return _quotedParameter;} | ||||
|  | ||||
| @ -10,7 +10,6 @@ | ||||
| HttpClient::HttpClient(const char *address, uint16_t port, uint32_t timeout) : WiFiClient(), _pAddress(address), _port(port) | ||||
| { | ||||
|   setTimeout(timeout); | ||||
|   connectByHostOrIp(); | ||||
| } | ||||
| 
 | ||||
| HttpClient::HttpClient(const char *address, const char *resource, uint16_t port, uint32_t timeout) : HttpClient(address, port, timeout) | ||||
| @ -44,7 +43,10 @@ HttpClient::HttpClient(const HttpClient &object) : WiFiClient() | ||||
| 
 | ||||
| HttpClient::~HttpClient() | ||||
| { | ||||
|   if(_resource != NULL)free(_resource); | ||||
|   if(connected()) | ||||
|     stop(); | ||||
|   if(_resource != NULL) | ||||
|     free(_resource); | ||||
| } | ||||
| 
 | ||||
| boolean HttpClient::connectByHostOrIp() | ||||
| @ -53,6 +55,17 @@ boolean HttpClient::connectByHostOrIp() | ||||
|   #ifdef DEBUG_HTTP_CLIENT | ||||
|   Serial.printf("About to connect\n"); | ||||
|   #endif | ||||
| 
 | ||||
|   //If we constructed the HttpClient with a NULL server address, we don't go further.
 | ||||
|   if(!_pAddress) | ||||
|   { | ||||
|     #ifdef DEBUG_HTTP_CLIENT | ||||
|     Serial.printf("IP Address is NULL !\n"); | ||||
|     #endif | ||||
|     _connectionStatus = FAILED; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   if(ipAddress.fromString(_pAddress)) | ||||
|   { | ||||
|     _isIp = true; | ||||
| @ -93,12 +106,15 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | ||||
|   //We reset this two flags
 | ||||
|   _httpCode = HTTP_CODE::UNDEFINED_CODE; | ||||
|   _httpCodeParsed = false; | ||||
|    | ||||
| 
 | ||||
|   #ifdef DEBUG_HTTP_CLIENT | ||||
|   if(_keepAlive) | ||||
|     Serial.printf("Link status : %d\n", status()); | ||||
|   #endif | ||||
| 
 | ||||
|   //If we did not want to keep the connection alive and it is still open, then we first close it.
 | ||||
|   if(!_keepAlive && connected())stop(); | ||||
| 
 | ||||
|   if(!connected() || _connectionStatus == FAILED) | ||||
|   { | ||||
|     if(_retries == _maxRetries) return -__LINE__; | ||||
| @ -111,9 +127,9 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | ||||
|      | ||||
|     #ifdef DEBUG_HTTP_CLIENT | ||||
|     if(_keepAlive) | ||||
|       Serial.printf("Link broken, we try to reconnect : addr : %s port %u\nretries : %u\n", _pAddress, _port, _retries); | ||||
|       Serial.printf("Link broken, we try to reconnect : addr : %s port %u\nretries : %u\n", _pAddress ? _pAddress : "NULL", _port, _retries); | ||||
|     else | ||||
|       Serial.printf("We start a new connection : %s port %u\nretries : %u\n", _pAddress, _port, _retries); | ||||
|       Serial.printf("We start a new connection : %s port %u\nretries : %u\n", _pAddress ? _pAddress : "NULL", _port, _retries); | ||||
|     #endif | ||||
|      | ||||
|     if(!connectByHostOrIp()) | ||||
| @ -131,7 +147,7 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | ||||
|   if(connected()) | ||||
|   { | ||||
|     #ifdef DEBUG_HTTP_CLIENT | ||||
|     Serial.printf("Server is listening\n", status()); | ||||
|     Serial.printf("Server is listening\n"); | ||||
|     #endif | ||||
|      | ||||
|     switch(method) | ||||
| @ -142,6 +158,7 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | ||||
|         //Here we send the parameters
 | ||||
|         sendUriWithGetParams(getData); | ||||
|         sendHeader(HttpMIMEType::UNKNOWN_MIME, 0, headerData); | ||||
|         flush(); //We force the send of the request to prevent any timeout on reception !
 | ||||
|         break; | ||||
|       case HttpRequestMethod::POST: | ||||
|         //It is necessary to compute the content length
 | ||||
| @ -150,17 +167,18 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | ||||
|         sendUriWithGetParams(getData); | ||||
|         sendHeader(HttpMIMEType::APPLICATION_X_WWW_FORM_URLENCODED, computeBodyLength(postData), headerData); | ||||
|         sendPostData(postData); | ||||
|         flush(); //We force the send of the request to prevent any timeout on reception !
 | ||||
|         break; | ||||
|       default: | ||||
|         #ifdef DEBUG_HTTP_CLIENT | ||||
|         Serial.printf("Http verb unspecified\n", status()); | ||||
|         Serial.printf("Http verb unspecified\n"); | ||||
|         #endif | ||||
|         if(!_keepAlive)stop(); | ||||
|         return -__LINE__; | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| @ -274,7 +292,7 @@ HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout) | ||||
|           #ifdef DEBUG_HTTP_CLIENT | ||||
|           safeSize = available() > 99 ? 99 : available(); | ||||
|           buffer[peekBytes((uint8_t*)buffer,safeSize)] = '\0'; | ||||
|           Serial.printf("Body chunk is : %s\n",buffer); | ||||
|           Serial.printf("Body chunk is : %s\n", buffer); | ||||
|           #endif | ||||
|           break; | ||||
|         } | ||||
| @ -285,7 +303,7 @@ HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout) | ||||
|   } | ||||
| 
 | ||||
|   #ifdef DEBUG_HTTP_CLIENT | ||||
|   Serial.println("\nAfter timeout or all data is received"); | ||||
|   Serial.printf("\nAfter timeout or all data is received, HTTP_CODE is : %d\n", _httpCode); | ||||
|   #endif | ||||
|    | ||||
|   return _httpCode; | ||||
| @ -408,5 +426,20 @@ uint64_t HttpClient::computeBodyLength(Dictionary<DictionaryHelper::StringEntity | ||||
| 
 | ||||
| void HttpClient::setMaxRetries(int16_t retries) | ||||
| { | ||||
|   _maxRetries = retries; | ||||
|   _maxRetries = retries < 0 ? -1 : retries; | ||||
| } | ||||
| 
 | ||||
| int16_t HttpClient::getMaxRetries(void) const | ||||
| { | ||||
|   return _maxRetries; | ||||
| } | ||||
| 
 | ||||
| uint16_t HttpClient::retriesCount(void) const | ||||
| { | ||||
|   return _retries; | ||||
| } | ||||
| 
 | ||||
| void HttpClient::resetRetriesCount(void) | ||||
| { | ||||
|   _retries = 0; | ||||
| } | ||||
|  | ||||
| @ -37,7 +37,10 @@ class HttpClient : public WiFiClient, public HttpConstants | ||||
|     Dictionary<DictionaryHelper::StringEntity> *headerData = NULL); | ||||
|     void keepAlive(boolean enabled); | ||||
|     void setMaxRetries(int16_t retries); | ||||
|     //100 ms is the default timeout
 | ||||
|     int16_t getMaxRetries(void) const; | ||||
|     uint16_t retriesCount(void) const; | ||||
|     void resetRetriesCount(void); | ||||
|     //10s is the default timeout
 | ||||
|     HTTP_CODE isReplyAvailable(uint16_t timeout = 10000); | ||||
|      | ||||
|     uint16_t readHttpBody(uint8_t *buffer, uint32_t size); | ||||
|  | ||||
							
								
								
									
										114
									
								
								src/app/OTAManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/app/OTAManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| #include "OTAManager.h" | ||||
| #include "definition.h" | ||||
| 
 | ||||
| #define DEBUG_OTA_MANAGER(...) do {} while(0) | ||||
| 
 | ||||
| //#define DEBUG_OTA_MANAGER(...) do { Serial.printf(__VA_ARGS__); Serial.println();} while(0)
 | ||||
| 
 | ||||
| OTAManager::OTAManager(SDCardManager &sdCardManager, const BoardConfig &boardConfig) : _sdCardManager(&sdCardManager), _boardConfig(&boardConfig) | ||||
| { } | ||||
| 
 | ||||
| OTAManager::~OTAManager() | ||||
| { } | ||||
| 
 | ||||
| boolean OTAManager::init(void) | ||||
| { | ||||
|     //If the SDCardManager is not available, then we disable the OTA service
 | ||||
|     if(!_sdCardManager) | ||||
|     { | ||||
|         DEBUG_OTA_MANAGER("SDCardMng is NULL !"); | ||||
|         return true; | ||||
|     } | ||||
|             | ||||
|     //If the SDCardManager is available, then we try to read the config file
 | ||||
|     CFGDictionary<CFGParameterValue> *otaCfg = _sdCardManager->getCFGFile(OTA_CFG_FILE); | ||||
|     boolean toReturn(true); | ||||
|     //If we did not find the file
 | ||||
|     if(!otaCfg) | ||||
|     { | ||||
|         DEBUG_OTA_MANAGER("otaCfg is NULL !"); | ||||
|         return false; | ||||
|     }    | ||||
| 
 | ||||
|     if((*otaCfg)("ENABLED") != nullptr) | ||||
|     { | ||||
|         if((*otaCfg)("ENABLED")->booleanValue()) | ||||
|         { | ||||
|             DEBUG_OTA_MANAGER("ENABLED : %s", (*otaCfg)("ENABLED")->stringValue()); | ||||
|             if((*otaCfg)("OTA_SERVER_ADDRESS") != nullptr) //This is the only required parameter
 | ||||
|             { | ||||
|                 _isServiceEnabled = true; | ||||
|                 _otaUpdater.setLedPin(_boardConfig->getOnBoard_LED(), LOW); | ||||
|                 _otaUpdater.onStart(std::bind(&OTAManager::updateStartedCb, this)); | ||||
|                 _otaUpdater.onError(std::bind(&OTAManager::updateErrorCb, this, std::placeholders::_1)); | ||||
|                 _otaUpdater.onProgress(std::bind(&OTAManager::updateProgressdCb, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|                 _otaUpdater.onEnd(std::bind(&OTAManager::updateFinishedCb, this)); | ||||
| 
 | ||||
| 
 | ||||
|                 _otaUpdater.setServerAddress((*otaCfg)("OTA_SERVER_ADDRESS")->stringValue()); | ||||
|                  | ||||
|                 if((*otaCfg)("OTA_SERVER_PORT") != nullptr) | ||||
|                 { | ||||
|                     DEBUG_OTA_MANAGER("OTA_SERVER_PORT : %s", (*otaCfg)("OTA_SERVER_PORT")->stringValue()); | ||||
|                     _otaUpdater.setPort((*otaCfg)("OTA_SERVER_PORT")->uintValue()); | ||||
|                 } | ||||
|                      | ||||
|                 if((*otaCfg)("OTA_SERVICE_PATH") != nullptr) | ||||
|                 { | ||||
|                     DEBUG_OTA_MANAGER("OTA_SERVICE_PATH : %s", (*otaCfg)("OTA_SERVICE_PATH")->stringValue()); | ||||
|                     _otaUpdater.setPath((*otaCfg)("OTA_SERVICE_PATH")->stringValue()); | ||||
|                 } | ||||
|                  | ||||
|                 if((*otaCfg)("OTA_SERVICE_AUTH_KEY") != nullptr) | ||||
|                 { | ||||
|                     DEBUG_OTA_MANAGER("OTA_SERVICE_AUTH_KEY : %s", (*otaCfg)("OTA_SERVICE_AUTH_KEY")->stringValue()); | ||||
|                     _otaUpdater.setOtaAuthKey((*otaCfg)("OTA_SERVICE_AUTH_KEY")->stringValue()); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 DEBUG_OTA_MANAGER("OTA_SERVER_ADDRESS is NULL !"); | ||||
|                 toReturn = false; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         DEBUG_OTA_MANAGER("ENABLED is NULL !"); | ||||
|         toReturn = false; | ||||
|     } | ||||
|          | ||||
|     delete otaCfg; | ||||
| 
 | ||||
|     return toReturn; | ||||
| } | ||||
| 
 | ||||
| boolean OTAManager::isEnabled(void) const | ||||
| { | ||||
|     return _isServiceEnabled; | ||||
| } | ||||
| 
 | ||||
| OTAUpdater& OTAManager::getOTAUpdater(void) | ||||
| { | ||||
|     return _otaUpdater; | ||||
| } | ||||
| 
 | ||||
| void OTAManager::updateStartedCb(void) | ||||
| { | ||||
|     Serial.println("CALLBACK:  HTTP update process started"); | ||||
| } | ||||
| 
 | ||||
| void OTAManager::updateFinishedCb(void) | ||||
| { | ||||
|     Serial.println("CALLBACK:  HTTP update process finished"); | ||||
| } | ||||
| 
 | ||||
| void OTAManager::updateProgressdCb(int cur, int total) | ||||
| { | ||||
|     Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total); | ||||
| } | ||||
| 
 | ||||
| void OTAManager::updateErrorCb(int err) | ||||
| { | ||||
|     Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err); | ||||
| } | ||||
							
								
								
									
										32
									
								
								src/app/OTAManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/app/OTAManager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| #ifndef OTAMANAGER_H | ||||
| #define OTAMANAGER_H | ||||
| 
 | ||||
| #include "OTAUpdater.h" | ||||
| #include "SDCardManager.h" | ||||
| #include "BoardConfig.h" | ||||
| 
 | ||||
| class OTAManager | ||||
| { | ||||
|     friend class SAB; | ||||
|     public: | ||||
|         ~OTAManager(); | ||||
| 
 | ||||
|         boolean init(void); | ||||
|         boolean isEnabled(void) const; | ||||
|         OTAUpdater& getOTAUpdater(void); | ||||
|     protected: | ||||
|         OTAManager(SDCardManager &sdCardManager, const BoardConfig &boardConfig); | ||||
|         OTAManager(); | ||||
|     private: | ||||
|         void updateStartedCb(void); | ||||
|         void updateFinishedCb(void); | ||||
|         void updateProgressdCb(int cur, int total); | ||||
|         void updateErrorCb(int err); | ||||
| 
 | ||||
|         OTAUpdater _otaUpdater; | ||||
|         SDCardManager *_sdCardManager = nullptr; | ||||
|         const BoardConfig * _boardConfig = nullptr; | ||||
|         boolean _isServiceEnabled = false; | ||||
| }; | ||||
| 
 | ||||
| #endif //OTAMANAGER_H
 | ||||
							
								
								
									
										231
									
								
								src/app/OTAUpdater.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								src/app/OTAUpdater.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,231 @@ | ||||
| #include "OTAUpdater.h" | ||||
| #include "HttpClient.h" | ||||
| 
 | ||||
| //#define DEBUG_OTA_UPDATER 
 | ||||
| 
 | ||||
| OTAUpdater::OTAUpdater(const char *serverAddress, const char *path, const char *ota_auth_key, uint16_t port) : _port(port) | ||||
| { | ||||
|   if(serverAddress) | ||||
|     _serverAddress = strdup(serverAddress); | ||||
|    | ||||
|   if(path) | ||||
|     _path = strdup(path); | ||||
| 
 | ||||
|   if(ota_auth_key) | ||||
|     _ota_auth_key = strdup(ota_auth_key); | ||||
| } | ||||
| 
 | ||||
| OTAUpdater::OTAUpdater(int httpClientTimeout,const char *serverAddress, const char *path, const char *ota_auth_key, uint16_t port) : ESP8266HTTPUpdate(httpClientTimeout), _port(port) | ||||
| { | ||||
|   if(serverAddress) | ||||
|     _serverAddress = strdup(serverAddress); | ||||
|    | ||||
|   if(path) | ||||
|     _path = strdup(path); | ||||
| 
 | ||||
|   if(ota_auth_key) | ||||
|     _ota_auth_key = strdup(ota_auth_key); | ||||
| } | ||||
|      | ||||
| OTAUpdater::~OTAUpdater() | ||||
| { | ||||
|   if(_publicKey != nullptr) | ||||
|     delete _publicKey; | ||||
|      | ||||
|   if(_hash != nullptr) | ||||
|     delete _hash; | ||||
|      | ||||
|   if(_signingVerifier != nullptr) | ||||
|     delete _signingVerifier; | ||||
| 
 | ||||
|   free(_serverAddress); | ||||
|   free(_path); | ||||
|   free(_ota_auth_key); | ||||
| } | ||||
| 
 | ||||
| //Enables the binary signing verification
 | ||||
| void OTAUpdater::enableSHA256UpdateVerification(const char *publicKey) | ||||
| { | ||||
|   if(_publicKey != nullptr) | ||||
|     delete _publicKey; | ||||
|      | ||||
|   if(_hash != nullptr) | ||||
|     delete _hash; | ||||
|      | ||||
|   if(_signingVerifier != nullptr) | ||||
|     delete _signingVerifier; | ||||
| 
 | ||||
|   _publicKey = new BearSSL::PublicKey(publicKey); | ||||
|   _hash = new BearSSL::HashSHA256(); | ||||
|   _signingVerifier = new BearSSL::SigningVerifier(_publicKey); | ||||
| 
 | ||||
|   Update.installSignature(_hash, _signingVerifier); | ||||
| } | ||||
| 
 | ||||
| void OTAUpdater::setServerAddress(const char *serverAddress) | ||||
| { | ||||
|   if(!serverAddress) | ||||
|     return; | ||||
| 
 | ||||
|   free(_serverAddress); | ||||
|   _serverAddress = strdup(serverAddress); | ||||
| } | ||||
| 
 | ||||
| void OTAUpdater::setPath(const char *path) | ||||
| { | ||||
|   //The path can be empty
 | ||||
|   if(!path) | ||||
|   { | ||||
|     free(_path); | ||||
|     _path = nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     free(_path); | ||||
|     _path = strdup(path); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void OTAUpdater::setOtaAuthKey(const char *ota_auth_key) | ||||
| { | ||||
|   //The authKey can be empty
 | ||||
|   if(!ota_auth_key) | ||||
|   { | ||||
|     free(_ota_auth_key); | ||||
|     _ota_auth_key = nullptr; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     free(_ota_auth_key); | ||||
|     _ota_auth_key = strdup(ota_auth_key); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void OTAUpdater::setPort(uint16_t port) | ||||
| { | ||||
|   _port = port; | ||||
| } | ||||
| 
 | ||||
| OTAUpdater::UpdateInfo OTAUpdater::fetchUpdateInfo(const char *softwareVersion, uint32_t timeout) | ||||
| { | ||||
|   HttpClient httpClient(_serverAddress, _path, _port, timeout); | ||||
|   UpdateInfo ui; | ||||
| 
 | ||||
|   if(!softwareVersion) | ||||
|   { | ||||
|     ui.info = OTAUpdater::UpdateInfo::HTTP_NO_UPDATE; | ||||
|     return ui; | ||||
|   } | ||||
| 
 | ||||
|   Dictionary<DictionaryHelper::StringEntity> getData; | ||||
|   getData.add("authKey", DictionaryHelper::StringEntity(_ota_auth_key)); | ||||
|   getData.add("checkonly", NULL); | ||||
| 
 | ||||
|   Dictionary<DictionaryHelper::StringEntity> headerData; | ||||
|   headerData.add("x-ESP8266-version",DictionaryHelper::StringEntity(softwareVersion)); | ||||
|   headerData.add("x-ESP8266-STA-MAC",DictionaryHelper::StringEntity(WiFi.macAddress().c_str())); | ||||
|   headerData.add("User-Agent",DictionaryHelper::StringEntity("ESP8266-http-Update")); | ||||
| 
 | ||||
|   if(httpClient.sendHttpQuery(HttpClient::HttpRequestMethod::GET, &getData, NULL, &headerData) == 0) | ||||
|   { | ||||
|     HttpConstants::HTTP_CODE result = httpClient.isReplyAvailable(1000); | ||||
|     switch(result) | ||||
|     { | ||||
|       case HttpConstants::HTTP_CODE::HTTP_CODE_OK: | ||||
|       { | ||||
|         char buffer[100]; | ||||
|         httpClient.readHttpBody((uint8_t *)buffer, 100); | ||||
|         #ifdef DEBUG_OTA_UPDATER | ||||
|         Serial.printf("Response from update service : %s\n", buffer); | ||||
|         #endif | ||||
|          | ||||
|         char *p = strstr_P(buffer, PSTR("bin_version")); | ||||
|         if(p) | ||||
|         { | ||||
|           p+=14; | ||||
|           char *end = strchr(p, '"'); | ||||
|           if(end) | ||||
|           { | ||||
|             *end = '\0'; | ||||
|              | ||||
|             ui.version = (char *)malloc(strlen(p) * sizeof(char) + 1); | ||||
|             if(ui.version) | ||||
|               strcpy(ui.version, p); | ||||
|           } | ||||
|          } | ||||
|         ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_AVAILABLE; | ||||
|       } | ||||
|         break; | ||||
|       case HttpConstants::HTTP_CODE::HTTP_CODE_NOT_MODIFIED: | ||||
|         ui.info = OTAUpdater::UpdateInfo::HTTP_NO_UPDATE; | ||||
|         break; | ||||
|       case HttpConstants::HTTP_CODE::HTTP_CODE_FORBIDDEN: | ||||
|         ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_AUTH_ERROR; | ||||
|         break; | ||||
|       case HttpConstants::HTTP_CODE::HTTP_CODE_NOT_FOUND: | ||||
|         ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_REACH_ERROR; | ||||
|         break;  | ||||
|       default: | ||||
|         #ifdef DEBUG_OTA_UPDATER | ||||
|         Serial.printf("HTTP ERROR CODE IS : %u\n", result); | ||||
|         #endif | ||||
|         ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_UNDEFINED_ERROR; | ||||
|     } | ||||
| 
 | ||||
|     httpClient.stop(); | ||||
|   } | ||||
|   else | ||||
|     ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_REACH_ERROR; | ||||
| 
 | ||||
|   return ui; | ||||
| } | ||||
| 
 | ||||
| #define DEBUG_OTA_UPDATER | ||||
| 
 | ||||
| HTTPUpdateResult OTAUpdater::update(const char *softwareVersion) | ||||
| { | ||||
|   if(!softwareVersion) | ||||
|   { | ||||
|     #ifdef DEBUG_OTA_UPDATER | ||||
|     Serial.printf("Missing softwareVersion !\n"); | ||||
|     #endif | ||||
|     return HTTPUpdateResult::HTTP_UPDATE_NO_UPDATES; | ||||
|   } | ||||
| 
 | ||||
|   if(!_serverAddress) | ||||
|   { | ||||
|     #ifdef DEBUG_OTA_UPDATER | ||||
|     Serial.printf("Missing server address !\n"); | ||||
|     #endif | ||||
|     return HTTPUpdateResult::HTTP_UPDATE_FAILED; | ||||
|   } | ||||
| 
 | ||||
|   //Depending on the presence or not of the path and the authKey, we compute the size we must allocate for the full path
 | ||||
|   uint16_t length = 1 /*for the \0*/; | ||||
|   length += _path ? strlen(_path) : 0; | ||||
|   length += _ota_auth_key ? strlen(_ota_auth_key) + 9/*for : ?authKey=*/ : 0; | ||||
| 
 | ||||
|   char *fullpath = (char *)malloc(length * sizeof(char)); | ||||
|   if(!fullpath)return HTTP_UPDATE_FAILED; | ||||
| 
 | ||||
|   fullpath[0] = '\0'; | ||||
| 
 | ||||
|   WiFiClient client; | ||||
| 
 | ||||
|   if(_path)strcpy(fullpath, _path); | ||||
|   if(_ota_auth_key) | ||||
|   { | ||||
|     strcat(fullpath, "?authKey="); | ||||
|     strcat(fullpath, _ota_auth_key); | ||||
|   } | ||||
| 
 | ||||
|   #ifdef DEBUG_OTA_UPDATER | ||||
|   Serial.printf("The fullpath is : %s\n", fullpath); | ||||
|   #endif | ||||
| 
 | ||||
|   HTTPUpdateResult result = ESP8266HTTPUpdate::update(client, _serverAddress, _port, fullpath, softwareVersion); | ||||
| 
 | ||||
|   free(fullpath); | ||||
|   return result; | ||||
| } | ||||
							
								
								
									
										103
									
								
								src/app/OTAUpdater.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/app/OTAUpdater.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| #ifndef OTAUPDATER_H | ||||
| #define OTAUPDATER_H | ||||
| #include <ESP8266httpUpdate.h> | ||||
| 
 | ||||
| #define OTAUPDATER_STRING //PSTR
 | ||||
| 
 | ||||
| class OTAUpdater : public ESP8266HTTPUpdate | ||||
| { | ||||
|   public: | ||||
|     struct UpdateInfo | ||||
|     { | ||||
|       enum HTTPUpdateInfo { | ||||
|                           HTTP_NO_UPDATE, //There is no new update available
 | ||||
|                           HTTP_UPDATE_AVAILABLE, //There is an update ready to be applied
 | ||||
|                           HTTP_UPDATE_AUTH_ERROR, //There was an error during the authentification process by the update service
 | ||||
|                           HTTP_UPDATE_REACH_ERROR, //Unable to reach the update service
 | ||||
|                           HTTP_UPDATE_UNDEFINED_ERROR | ||||
|                         }; | ||||
| 
 | ||||
|       UpdateInfo(){} | ||||
|       UpdateInfo(const UpdateInfo &object) | ||||
|       { | ||||
|         info = object.info; | ||||
|         if(object.version) | ||||
|         { | ||||
|           version = (char *) malloc((strlen(object.version) + 1) * sizeof(char)); | ||||
|           if(version != NULL) | ||||
|             strcpy(version, object.version); | ||||
|         } | ||||
|       } | ||||
|       ~UpdateInfo(){ dispose(); } | ||||
|       UpdateInfo& operator=(const UpdateInfo &object) | ||||
|       { | ||||
|         info = object.info; | ||||
|         if(version) | ||||
|         { | ||||
|           free(version);version = NULL; | ||||
|         } | ||||
|          | ||||
|         if(object.version) | ||||
|         { | ||||
|           version = (char *) malloc((strlen(object.version) + 1) * sizeof(char)); | ||||
|           if(version != NULL) | ||||
|             strcpy(version, object.version); | ||||
|         } | ||||
|         return *this; | ||||
|       } | ||||
|       void dispose() | ||||
|       { | ||||
|         if(version) | ||||
|         { | ||||
|           free(version);version = NULL; | ||||
|         } | ||||
|       } | ||||
|       const char *HTTPUpdateInfoToString(void) | ||||
|       { | ||||
|         switch(info) | ||||
|         { | ||||
|           case HTTP_NO_UPDATE: | ||||
|             return OTAUPDATER_STRING("HTTP_NO_UPDATE"); | ||||
|             break; | ||||
|           case HTTP_UPDATE_AVAILABLE: | ||||
|             return OTAUPDATER_STRING("HTTP_UPDATE_AVAILABLE"); | ||||
|             break; | ||||
|           case HTTP_UPDATE_AUTH_ERROR: | ||||
|             return OTAUPDATER_STRING("HTTP_UPDATE_AUTH_ERROR"); | ||||
|             break; | ||||
|           case HTTP_UPDATE_REACH_ERROR: | ||||
|             return OTAUPDATER_STRING("HTTP_UPDATE_REACH_ERROR"); | ||||
|             break; | ||||
|           default: | ||||
|             return OTAUPDATER_STRING("HTTP_UPDATE_UNDEFINED_ERROR"); | ||||
|             break; | ||||
|         } | ||||
|       } | ||||
|       HTTPUpdateInfo info = HTTP_NO_UPDATE; | ||||
|       char *version = NULL; | ||||
|     }; | ||||
|     OTAUpdater(const char *serverAddress = NULL, const char *path = NULL, const char *ota_auth_key = NULL, uint16_t port = 80); | ||||
|     OTAUpdater(int httpClientTimeout, const char *serverAddress, const char *path = NULL, const char *ota_auth_key = NULL, uint16_t port = 80); | ||||
|      | ||||
|     ~OTAUpdater(); | ||||
|     //Enables the binary signing verification
 | ||||
|     void enableSHA256UpdateVerification(const char *publicKey); | ||||
|     void setServerAddress(const char *serverAddress); | ||||
|     void setPath(const char *path = NULL); | ||||
|     void setOtaAuthKey(const char *ota_auth_key = NULL); | ||||
|     void setPort(uint16_t port = 80); | ||||
|     UpdateInfo fetchUpdateInfo(const char *softwareVersion, uint32_t timeout = 500); | ||||
|     HTTPUpdateResult update(const char *softwareVersion); | ||||
|   protected: | ||||
|     BearSSL::PublicKey *_publicKey = nullptr; | ||||
|     BearSSL::HashSHA256 *_hash = nullptr; | ||||
|     BearSSL::SigningVerifier *_signingVerifier = nullptr; | ||||
| 
 | ||||
|     char *_serverAddress = nullptr; | ||||
|     char *_path = nullptr; | ||||
|     char *_ota_auth_key = nullptr; | ||||
|     uint16_t _port; | ||||
|   private: | ||||
| }; | ||||
| 
 | ||||
| #endif //OTAUPDATER_H
 | ||||
| @ -6,6 +6,7 @@ _screenManager(_display, &_sdCardManager), | ||||
| _connectivityManager(_sdCardManager),  | ||||
| _webServer(80, &_sdCardManager, 10), | ||||
| _ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10), | ||||
| _otaManager(_sdCardManager, _boardConfig), | ||||
| _dbWSServer(81), | ||||
| _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire), | ||||
| _ioManager(_pcf), | ||||
| @ -21,6 +22,7 @@ _screenManager(_display, &_sdCardManager), | ||||
| _connectivityManager(_sdCardManager),  | ||||
| _webServer(webServerPort, &_sdCardManager, 10), | ||||
| _ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10), | ||||
| _otaManager(_sdCardManager, _boardConfig), | ||||
| _dbWSServer(81), | ||||
| _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),  | ||||
| _ioManager(_pcf), | ||||
| @ -39,12 +41,18 @@ void SAB::initCommonConfig() | ||||
|    | ||||
|   //We initialize the pins for the  I2C communication
 | ||||
|   Wire.begin(_boardConfig.getI2C_sda(), _boardConfig.getI2C_scl()); | ||||
|   if(!_rtc.begin()) _error |= RTC_BEGIN_ERR; | ||||
|   if(!_rtc.begin()) | ||||
|     _error |= RTC_BEGIN_ERR; | ||||
|   else | ||||
|   { | ||||
|     _rtcManager.setDateTime(_rtc.now()); | ||||
|   } | ||||
|   if(!_display.begin(SSD1306_SWITCHCAPVCC, _boardConfig.getI2C_screenAddress())){ _error |= DISP_BEGIN_ERR;} | ||||
| 
 | ||||
|   if(!_display.begin(SSD1306_SWITCHCAPVCC, _boardConfig.getI2C_screenAddress())) | ||||
|   {  | ||||
|     _error |= DISP_BEGIN_ERR; | ||||
|   } | ||||
| 
 | ||||
|   if(!_sdCardManager.mountSD()) | ||||
|   {  | ||||
|     _error |= SDCARD_INIT_ERR; | ||||
| @ -52,9 +60,11 @@ void SAB::initCommonConfig() | ||||
|     _boardConfig.getSPISpeed(), | ||||
|     _boardConfig.getSPI_SDCard_cs()); | ||||
|   } | ||||
| 
 | ||||
|   _screenManager.init(); | ||||
|   if(!_connectivityManager.connect()){ _error |= CONNECT_ERR;} | ||||
|   if(!_pcf.begin()){_error |= IO_INIT_ERR;} | ||||
|   if(!_otaManager.init()){_error |= OTA_INIT_ERR;} | ||||
| 
 | ||||
|   //We set the different servers :
 | ||||
|   _webServer.setWWWDir(WWW_DIR); | ||||
| @ -104,7 +114,12 @@ FTPServer<FTPClient>& SAB::getFtpServer() | ||||
|   return _ftpServer; | ||||
| } | ||||
| 
 | ||||
| IOManager& SAB::getIoManager() | ||||
| OTAManager& SAB::getOTAManager() | ||||
| { | ||||
|   return _otaManager; | ||||
| } | ||||
| 
 | ||||
| IOManager& SAB::getIOManager() | ||||
| { | ||||
|   return _ioManager; | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
| #include "IOManager.h" | ||||
| #include "TaskSchedulerManager.h" | ||||
| #include "PowerManager.h" | ||||
| #include "OTAManager.h" | ||||
| #include "versions.h" | ||||
| #include <Adafruit_SSD1306.h> | ||||
| #include <RTClib.h> | ||||
| @ -20,7 +21,7 @@ | ||||
| class SAB | ||||
| { | ||||
|   public: | ||||
|     enum Error {RTC_BEGIN_ERR = 1, DISP_BEGIN_ERR = 2, SDCARD_INIT_ERR = 4, IO_INIT_ERR = 8, CONNECT_ERR = 16}; | ||||
|     enum Error {RTC_BEGIN_ERR = 1, DISP_BEGIN_ERR = 2, SDCARD_INIT_ERR = 4, IO_INIT_ERR = 8, CONNECT_ERR = 16, OTA_INIT_ERR = 32}; | ||||
|    | ||||
|     SAB(); | ||||
|     SAB(const BoardConfig boardConfig, const unsigned int webServerPort = 80, const unsigned int ftpServerPort = 21); | ||||
| @ -33,10 +34,10 @@ class SAB | ||||
|     RTC_DS3231& getRTC_DS3231(); | ||||
|     SDCardManager& getSdCardManager(); | ||||
|     ConnectivityManager& getConnectivityManager(); | ||||
|     //WEBServerManager& getWebServerManager();
 | ||||
|     WEBServer<WEBClient>& getWebServer(); | ||||
|     FTPServer<FTPClient>& getFtpServer(); | ||||
|     IOManager& getIoManager(); | ||||
|     OTAManager& getOTAManager(); | ||||
|     IOManager& getIOManager(); | ||||
|     TaskSchedulerManager& getTaskSchedulerManager(); | ||||
|     PowerManager& getPowerManager(); | ||||
|     TimeSpan getUpTime() const; | ||||
| @ -56,10 +57,10 @@ class SAB | ||||
|     RTC_DS3231 _rtc; | ||||
|     RtcManager _rtcManager; | ||||
|     ConnectivityManager _connectivityManager; | ||||
|     //WEBServerManager _webServerManager;
 | ||||
|     WEBServer<WEBClient> _webServer; | ||||
|     FTPServer<FTPClient> _ftpServer; | ||||
|     DashboardWSServer    _dbWSServer; | ||||
|     OTAManager _otaManager; | ||||
|     DashboardWSServer _dbWSServer; | ||||
|     PCF8574 _pcf; | ||||
|     IOManager _ioManager; | ||||
|     TaskSchedulerManager _taskSchedulerManager; | ||||
|  | ||||
| @ -95,9 +95,10 @@ void setup() | ||||
|   sab.getWebServer().addApiRoutine("/sab/io/get/mode", &(ioGetModeApi), &sab, WEBServer<WEBClient>::GET); | ||||
|   sab.getWebServer().addApiRoutine("/sab/io/set/mode", &(ioSetModeApi), &sab, WEBServer<WEBClient>::GET); | ||||
|   sab.getWebServer().addApiRoutine("/sab/sw/version", &(swVersionApi), &sab, WEBServer<WEBClient>::GET); | ||||
|   sab.getWebServer().addApiRoutine("/sab/ota/update", &(otaUpdateApi), NULL, WEBServer<WEBClient>::POST); | ||||
|   sab.getWebServer().addApiRoutine("/sab/ota/update/upload", &(otaUpdateUploadApi), NULL, WEBServer<WEBClient>::POST); | ||||
|   sab.getWebServer().addApiRoutine("/sab/ota/update/device", &(otaUpdateRemoteApi), &sab, WEBServer<WEBClient>::GET); | ||||
| 
 | ||||
|   sab.getIoManager().setISROnIOChange(&(ioISR), GPIO_3_RX); | ||||
|   sab.getIOManager().setISROnIOChange(&(ioISR), GPIO_3_RX); | ||||
| 
 | ||||
|   sab.getTaskSchedulerManager().addTask((uint16_t)0, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setMillis(5000), &(task_blink), &sab); | ||||
|   sab.getTaskSchedulerManager().addTask(1, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setSeconds(10), &(task_sys_info), &v1p); | ||||
| @ -121,8 +122,8 @@ void loop() | ||||
|     vstap.ipAddr = sab.getConnectivityManager().localIP(); | ||||
|     vstap.sigStrength = sab.getConnectivityManager().RSSI(); | ||||
| 
 | ||||
|     sab.getIoManager().getPcf().digitalReadAll(vio.ioState); | ||||
|     sab.getIoManager().getPcf().getPinModeAll(vio.ioMode); | ||||
|     sab.getIOManager().getPcf().digitalReadAll(vio.ioState); | ||||
|     sab.getIOManager().getPcf().getPinModeAll(vio.ioMode); | ||||
| 
 | ||||
|     if(ioStateChange) | ||||
|     { | ||||
|  | ||||
| @ -35,10 +35,24 @@ typedef enum {  GPIO_0 = 0, | ||||
| #define STA_CFG_FILE "/CONFIG/STA.CFG" | ||||
| #define SCREEN_CFG_FILE "/CONFIG/SCREEN.CFG" | ||||
| #define SERVER_CFG_FILE "/CONFIG/SERVER.CFG" | ||||
| #define OTA_CFG_FILE "/CONFIG/OTA.CFG" | ||||
| #define WWW_DIR "/WWW" | ||||
| #define LOG_DIR "/LOGS" | ||||
| #define FTP_DIR "/FTP" | ||||
| 
 | ||||
| //OTA public key for binary verification
 | ||||
| const char otaVerificationPubKey[] PROGMEM = R"DEL( | ||||
| -----BEGIN PUBLIC KEY----- | ||||
| MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh6eFU0pdfir5CsQqs0v | ||||
| vi7ip7MtRuNgcMtjl7lpXwQuMG5yoso1iR+Fzbz+Cso4lcqarG5uHV8nKYWQ+C39 | ||||
| +3OfKx9LSfabCnRAeFFhXuGWEfRcZ9aeW3Jv0Mg2+3sTOfXQGjdgNwOAqZNrL4kr | ||||
| 574F+c3o/PAwlr4VLMy7KygorNnaYzC5JF1H5DhqaKNniKVEqGXiVQKW10C04SsM | ||||
| mGV/rKRSPpBVzyBrIf8GNPyVf7W4D0s9gSiCrRWMU2aU3tX35tezwlicsb86MKKM | ||||
| o9ySHAMsIihx3zdwAGOELxE47Ylodq9cwc53fz7pfcdyL+N6FKKWM0bYJAkwNhdJ | ||||
| NQIDAQAB | ||||
| -----END PUBLIC KEY----- | ||||
| )DEL"; | ||||
| 
 | ||||
| typedef enum { OR_0 = 2, OR_90 = 3, OR_180 = 0, OR_270 = 1 } Orientation; | ||||
| 
 | ||||
| typedef enum { BIT = 0, BYTE, KBIT, KBYTE, MBIT, MBYTE, GBIT, GBYTE } SizeUnit; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| boolean task_blink(void *pData) | ||||
| { | ||||
|   SAB *p = (SAB *) pData; | ||||
|   p->getIoManager().getPcf().togglePin(PCF8574::P2); | ||||
|   p->getIOManager().getPcf().togglePin(PCF8574::P2); | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| @ -19,17 +19,36 @@ boolean task_sys_info(void *pData) | ||||
| 
 | ||||
|   TimeSpan ts(p->sab->getUpTime()); | ||||
| 
 | ||||
|   Serial.printf_P(PSTR("BATT SENSING...\nUp Time : %d d %d h %d m %d s\nSystem error : %u\nStation IP : %s, %d dBm\nAP IP : %s\nWEB Server clients : %u\nMemory info:\n\tFree RAM : %u\n\tHeap frag : %u\n\tMax block %u\n"), | ||||
|   Serial.printf_P(PSTR("BATT SENSING...\nSoftware version : %s\nUp Time : %d d %d h %d m %d s\nSystem error : %u\nStation IP : %s, %d dBm\nAP IP : %s\nDevice MAC : %s\nWEB Server clients : %u\nMemory info:\n\tFree RAM : %u\n\tHeap frag : %u\n\tMax block %u\n"), | ||||
|   p->sab->getSoftVersion(), | ||||
|   ts.days(), ts.hours(), ts.minutes(), ts.seconds(), | ||||
|   p->sab->getError(), | ||||
|   p->sab->getConnectivityManager().localIP().toString().c_str(), | ||||
|   p->sab->getConnectivityManager().RSSI(), | ||||
|   p->sab->getConnectivityManager().softAPIP().toString().c_str(), | ||||
|   p->sab->getConnectivityManager().macAddress().c_str(), | ||||
|   p->sab->getWebServer().getConnectedClientsCount(), | ||||
|   freeRAM, | ||||
|   HEAPfrag, | ||||
|   biggestContigMemBlock); | ||||
|   p->powerInfo = p->sab->getPowerManager().getPowerInfo(); | ||||
| 
 | ||||
|   if(p->sab->getOTAManager().isEnabled()) | ||||
|   { | ||||
|     OTAUpdater::UpdateInfo updateInfo = p->sab->getOTAManager().getOTAUpdater().fetchUpdateInfo(p->sab->getSoftVersion()); | ||||
|     if(updateInfo.version != NULL) | ||||
|     { | ||||
|       Serial.printf("OTA : %s -> version(%s)\n", updateInfo.HTTPUpdateInfoToString(), updateInfo.version); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       Serial.printf("OTA : %s\n", updateInfo.HTTPUpdateInfoToString()); | ||||
|     } | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     Serial.println("OTA updates disabled"); | ||||
|   } | ||||
|    | ||||
|   return true; | ||||
| } | ||||
| @ -63,7 +82,7 @@ boolean task_post_data_logger(void * pData) | ||||
|     postData.add("post4", NULL); | ||||
|      | ||||
|    | ||||
|     if(p->client.sendHttpQuery(HttpClient::HttpRequestMethod::POST, &getData, &postData)) | ||||
|     if(p->client.sendHttpQuery(HttpClient::HttpRequestMethod::POST, &getData, &postData) == 0) | ||||
|     { | ||||
|       Serial.println("Send successful"); | ||||
|       p->rdy = false; | ||||
|  | ||||
| @ -44,5 +44,7 @@ | ||||
| //#define SOFT_VERSION "1.6.12" //WEBServer parsing http query parameters differently, allowing for longer URI and RAM savings.
 | ||||
| //#define SOFT_VERSION "1.6.13" //ScreenManager now providing and handling display auto power off functionality to save power as well as to fight OLED burn-in.
 | ||||
| //#define SOFT_VERSION "1.6.14" //Corrected a major stack overflow in the WEBServer and fixed a potential one in the FTPServer.
 | ||||
| #define SOFT_VERSION "1.6.15" //WEBServer now lists files and folder of a resource when it is a folder.
 | ||||
| //#define SOFT_VERSION "1.6.15" //WEBServer now lists files and folder of a resource when it is a folder.
 | ||||
| #define SOFT_VERSION "1.7.0"  //OTA update of the device is now possible through a rest API endpoint.
 | ||||
| 
 | ||||
| #endif //VERSIONS_H
 | ||||
|  | ||||
| @ -400,38 +400,38 @@ boolean ioSetLevelApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc | ||||
| 
 | ||||
|   if(HRD.getParams("P0") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P0,atoi(HRD.getParams("P0")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P0,atoi(HRD.getParams("P0")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P1") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P1,atoi(HRD.getParams("P1")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P1,atoi(HRD.getParams("P1")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P2") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P2,atoi(HRD.getParams("P2")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P2,atoi(HRD.getParams("P2")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P3") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P3,atoi(HRD.getParams("P3")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P3,atoi(HRD.getParams("P3")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P4") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P4,atoi(HRD.getParams("P4")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P4,atoi(HRD.getParams("P4")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P5") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P5,atoi(HRD.getParams("P5")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P5,atoi(HRD.getParams("P5")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P6") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P6,atoi(HRD.getParams("P6")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P6,atoi(HRD.getParams("P6")->getString())); | ||||
|   } | ||||
|   if(HRD.getParams("P7") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().digitalWrite(PCF8574::P7,atoi(HRD.getParams("P7")->getString())); | ||||
|     p->getIOManager().getPcf().digitalWrite(PCF8574::P7,atoi(HRD.getParams("P7")->getString())); | ||||
|   } | ||||
| 
 | ||||
|   p->getIoManager().getPcf().digitalReadAll(ioState);//We retrieve the IO state
 | ||||
|   p->getIOManager().getPcf().digitalReadAll(ioState);//We retrieve the IO state
 | ||||
|   sprintf(buffer,"{\"status\":\"ok\",\"P0\":\"%d\",\"P1\":\"%d\",\"P2\":\"%d\",\"P3\":\"%d\",\"P4\":\"%d\",\"P5\":\"%d\",\"P6\":\"%d\",\"P7\":\"%d\"}",ioState[0],ioState[1],ioState[2],ioState[3],ioState[4],ioState[5],ioState[6],ioState[7]); | ||||
|    | ||||
|   WEBServer<WEBClient>::sendHTTPHeader(wc, HttpConstants::httpMIMETypeToString(HttpConstants::APPLICATION_JSON), strlen(buffer)); | ||||
| @ -447,7 +447,7 @@ boolean ioGetModeApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, | ||||
|   char helperBuffer[20] = ""; | ||||
|   const char * const IN = "IN", * const OUT = "OUT"; | ||||
| 
 | ||||
|   p->getIoManager().getPcf().getPinModeAll(ioMode);//We retrieve the IO modes aka INPUT or OUTPUT
 | ||||
|   p->getIOManager().getPcf().getPinModeAll(ioMode);//We retrieve the IO modes aka INPUT or OUTPUT
 | ||||
| 
 | ||||
|   if(HRD.getParams.count() == 0)//We send every IO mode
 | ||||
|   { | ||||
| @ -521,38 +521,38 @@ boolean ioSetModeApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, | ||||
| 
 | ||||
|   if(HRD.getParams("P0") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P0,strcmp(HRD.getParams("P0")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P0,strcmp(HRD.getParams("P0")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P1") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P1,strcmp(HRD.getParams("P1")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P1,strcmp(HRD.getParams("P1")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P2") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P2,strcmp(HRD.getParams("P2")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P2,strcmp(HRD.getParams("P2")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P3") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P3,strcmp(HRD.getParams("P3")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P3,strcmp(HRD.getParams("P3")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P4") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P4,strcmp(HRD.getParams("P4")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P4,strcmp(HRD.getParams("P4")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P5") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P5,strcmp(HRD.getParams("P5")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P5,strcmp(HRD.getParams("P5")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P6") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P6,strcmp(HRD.getParams("P6")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P6,strcmp(HRD.getParams("P6")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
|   if(HRD.getParams("P7") != NULL) | ||||
|   { | ||||
|     p->getIoManager().getPcf().pinMode(PCF8574::P7,strcmp(HRD.getParams("P7")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|     p->getIOManager().getPcf().pinMode(PCF8574::P7,strcmp(HRD.getParams("P7")->getString(), IN) == 0 ? INPUT:OUTPUT); | ||||
|   } | ||||
| 
 | ||||
|   p->getIoManager().getPcf().getPinModeAll(ioMode);//We retrieve the IO modes aka INPUT or OUTPUT
 | ||||
|   p->getIOManager().getPcf().getPinModeAll(ioMode);//We retrieve the IO modes aka INPUT or OUTPUT
 | ||||
|   sprintf(buffer,"{\"status\":\"ok\",\"P0\":\"%s\",\"P1\":\"%s\",\"P2\":\"%s\",\"P3\":\"%s\",\"P4\":\"%s\",\"P5\":\"%s\",\"P6\":\"%s\",\"P7\":\"%s\"}",ioMode[0] ? OUT:IN,ioMode[1] ? OUT:IN,ioMode[2] ? OUT:IN,ioMode[3] ? OUT:IN,ioMode[4] ? OUT:IN,ioMode[5] ? OUT:IN,ioMode[6] ? OUT:IN,ioMode[7] ? OUT:IN); | ||||
|    | ||||
|   WEBServer<WEBClient>::sendHTTPHeader(wc, HttpConstants::httpMIMETypeToString(HttpConstants::APPLICATION_JSON), strlen(buffer)); | ||||
| @ -563,22 +563,22 @@ boolean ioSetModeApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, | ||||
| boolean swVersionApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, void *pData) | ||||
| { | ||||
|   (void)HRD; | ||||
|   (void)pData; | ||||
|   SAB *p = (SAB *)pData; | ||||
| 
 | ||||
|   char buffer[100] = ""; | ||||
| 
 | ||||
|   sprintf(buffer ,"{\"status\":\"ok\",\"version\":\"%s\"}", SOFT_VERSION); | ||||
|   sprintf(buffer ,"{\"status\":\"ok\",\"version\":\"%s\"}", p->getSoftVersion()); | ||||
| 
 | ||||
|   WEBServer<WEBClient>::sendHTTPHeader(wc, HttpConstants::httpMIMETypeToString(HttpConstants::APPLICATION_JSON), strlen(buffer)); | ||||
|   wc->print(buffer); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| boolean otaUpdateApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, void *pData) | ||||
| boolean otaUpdateUploadApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, void *pData) | ||||
| { | ||||
|   (void)HRD; | ||||
|   (void)pData; | ||||
|   Serial.printf("OTA Update resquest\n#"); | ||||
|   Serial.printf("OTA Update Upload resquest\n#"); | ||||
| 
 | ||||
|   char buffer[30] = ""; | ||||
|   size_t read(0), cnt(0); | ||||
| @ -602,3 +602,58 @@ boolean otaUpdateApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| boolean otaUpdateRemoteApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, void *pData) | ||||
| { | ||||
|   SAB *p = (SAB *)pData; | ||||
| 
 | ||||
|   char buffer[100] = ""; | ||||
|   boolean updateDevice(false); | ||||
| 
 | ||||
|   if(!p->getOTAManager().isEnabled()) | ||||
|   { | ||||
|     strcpy(buffer ,"{\"status\":\"ok\",\"ota\":\"disabled\"}"); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     OTAUpdater::UpdateInfo updateInfo = p->getOTAManager().getOTAUpdater().fetchUpdateInfo(p->getSoftVersion()); | ||||
|      | ||||
|     switch(updateInfo.info) | ||||
|     { | ||||
|       case OTAUpdater::UpdateInfo::HTTP_NO_UPDATE : | ||||
|         strcpy(buffer ,"{\"status\":\"ok\",\"ota\":\"enabled\",\"msg\":\"No update available\"}"); | ||||
|         break; | ||||
|       case OTAUpdater::UpdateInfo::HTTP_UPDATE_AUTH_ERROR : | ||||
|         strcpy(buffer ,"{\"status\":\"error\",\"ota\":\"enabled\",\"msg\":\"OTA auth error\"}"); | ||||
|         break; | ||||
|       case OTAUpdater::UpdateInfo::HTTP_UPDATE_AVAILABLE : | ||||
|         //Then we update the firmware
 | ||||
|         if(HRD.getParams("update") != NULL) | ||||
|         { | ||||
|           sprintf(buffer ,"{\"status\":\"ok\",\"ota\":\"enabled\",\"msg\":\"Updating the device, please wait\",\"version\":\"%s\"}", updateInfo.version); | ||||
|           updateDevice = true; | ||||
|         } | ||||
|         else //This means, we only want to get the new version number
 | ||||
|         { | ||||
|           sprintf(buffer ,"{\"status\":\"ok\",\"ota\":\"enabled\",\"msg\":\"Update available\",\"version\":\"%s\"}", updateInfo.version); | ||||
|         } | ||||
|         break; | ||||
|       case OTAUpdater::UpdateInfo::HTTP_UPDATE_REACH_ERROR : | ||||
|         strcpy(buffer ,"{\"status\":\"error\",\"ota\":\"enabled\",\"msg\":\"OTA reach error\"}"); | ||||
|         break; | ||||
|       default: | ||||
|         strcpy(buffer ,"{\"status\":\"error\",\"ota\":\"enabled\",\"msg\":\"Undefined error\"}"); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   WEBServer<WEBClient>::sendHTTPHeader(wc, HttpConstants::httpMIMETypeToString(HttpConstants::APPLICATION_JSON), strlen(buffer)); | ||||
|   wc->print(buffer); | ||||
| 
 | ||||
|   if(updateDevice) | ||||
|   { | ||||
|     p->getOTAManager().getOTAUpdater().update(p->getSoftVersion()); | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| @ -31,6 +31,7 @@ boolean ioSetLevelApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void* | ||||
| boolean ioGetModeApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| boolean ioSetModeApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| boolean swVersionApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| boolean otaUpdateApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| boolean otaUpdateUploadApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| boolean otaUpdateRemoteApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user