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", |             "label": "Build", | ||||||
|             "type": "shell", |             "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":{ |             "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", |             "group": "build", | ||||||
|             "presentation": { |             "presentation": { | ||||||
| @ -23,9 +23,9 @@ | |||||||
|         { |         { | ||||||
|             "label": "Flash", |             "label": "Flash", | ||||||
|             "type": "shell", |             "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":{ |             "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", |             "group": "build", | ||||||
|             "presentation": { |             "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_ENABLED : 'true' | ||||||
| WEB_PORT : 80 | WEB_PORT : 80 | ||||||
| WEB_MAX_CLIENT : 0 | WEB_MAX_CLIENT : 0 | ||||||
|  | WEB_WWW_DIR : '/WWW' | ||||||
| FTP_ENABLED : 'true' | FTP_ENABLED : 'true' | ||||||
| FTP_LOGIN : 'ESP8266' | FTP_LOGIN : 'ESP8266' | ||||||
| FTP_PASSWORD : '12345678' | FTP_PASSWORD : '12345678' | ||||||
|  | FTP_ROOT_DIR : '/FTP' | ||||||
| FTP_PORT : 21 | FTP_PORT : 21 | ||||||
| FTP_DATA_PORT : 1024 | FTP_DATA_PORT : 1024 | ||||||
| FTP_MAX_CLIENT : 0 | FTP_MAX_CLIENT : 0 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ const uint16_t screenHeight, | |||||||
| const uint16_t I2C_IOExpanderAddress, | const uint16_t I2C_IOExpanderAddress, | ||||||
| const uint16_t _I2C_RTCFlashAddress, | const uint16_t _I2C_RTCFlashAddress, | ||||||
| const Pin SPI_SDCard_cs, | const Pin SPI_SDCard_cs, | ||||||
|  | const Pin onBoard_LED, | ||||||
| const Pin I2C_sda,  | const Pin I2C_sda,  | ||||||
| const Pin I2C_scl,  | const Pin I2C_scl,  | ||||||
| const Pin SPI_mosi, | 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_miso(SPI_miso == DEFAULT_PIN ? GPIO_12_MISO : SPI_miso), | ||||||
| _SPI_clk(SPI_clk == DEFAULT_PIN ? GPIO_14_CLK : SPI_clk), | _SPI_clk(SPI_clk == DEFAULT_PIN ? GPIO_14_CLK : SPI_clk), | ||||||
| _SPI_SDCard_cs(SPI_SDCard_cs == DEFAULT_PIN ? GPIO_2 : SPI_SDCard_cs), | _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_screenAddress(I2C_screenAddress), | ||||||
| _I2C_IOExpanderAddress(I2C_IOExpanderAddress), | _I2C_IOExpanderAddress(I2C_IOExpanderAddress), | ||||||
| _I2C_RTCFlashAddress(_I2C_RTCFlashAddress), | _I2C_RTCFlashAddress(_I2C_RTCFlashAddress), | ||||||
| @ -59,6 +61,11 @@ Pin BoardConfig::getSPI_SDCard_cs() const | |||||||
| 	return _SPI_SDCard_cs; | 	return _SPI_SDCard_cs; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Pin BoardConfig::getOnBoard_LED() const | ||||||
|  | { | ||||||
|  | 	return _onBoard_LED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| uint16_t BoardConfig::getI2C_screenAddress() const | uint16_t BoardConfig::getI2C_screenAddress() const | ||||||
| { | { | ||||||
| 	return _I2C_screenAddress; | 	return _I2C_screenAddress; | ||||||
| @ -69,12 +76,11 @@ uint16_t BoardConfig::getI2C_IOExpanderAddress() const | |||||||
| 	return _I2C_IOExpanderAddress; | 	return _I2C_IOExpanderAddress; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t BoardConfig::getRTCFlashAddress() const | uint16_t BoardConfig::getI2C_RTCFlashAddress() const | ||||||
| { | { | ||||||
| 	return _I2C_RTCFlashAddress; | 	return _I2C_RTCFlashAddress; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| uint32_t BoardConfig::getSPISpeed() const | uint32_t BoardConfig::getSPISpeed() const | ||||||
| { | { | ||||||
| 	return _SPISpeed; | 	return _SPISpeed; | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ class BoardConfig | |||||||
| 		const uint16_t I2C_IOExpanderAddress = 0x27, | 		const uint16_t I2C_IOExpanderAddress = 0x27, | ||||||
| 		const uint16_t _I2C_RTCFlashAddress = 0x0, | 		const uint16_t _I2C_RTCFlashAddress = 0x0, | ||||||
| 		const Pin SPI_SDCard_cs = GPIO_2, | 		const Pin SPI_SDCard_cs = GPIO_2, | ||||||
|  | 		const Pin onBoard_LED = GPIO_2, | ||||||
| 		const Pin I2C_sda = GPIO_4_SDA,  | 		const Pin I2C_sda = GPIO_4_SDA,  | ||||||
| 		const Pin I2C_scl = GPIO_5_SCL,  | 		const Pin I2C_scl = GPIO_5_SCL,  | ||||||
| 		const Pin SPI_mosi = GPIO_13_MOSI, | 		const Pin SPI_mosi = GPIO_13_MOSI, | ||||||
| @ -32,10 +33,11 @@ class BoardConfig | |||||||
| 		Pin getSPI_miso() const; | 		Pin getSPI_miso() const; | ||||||
| 		Pin getSPI_clk() const; | 		Pin getSPI_clk() const; | ||||||
| 		Pin getSPI_SDCard_cs() const; | 		Pin getSPI_SDCard_cs() const; | ||||||
|  | 		Pin getOnBoard_LED() const; | ||||||
| 		 | 		 | ||||||
| 		uint16_t getI2C_screenAddress() const; | 		uint16_t getI2C_screenAddress() const; | ||||||
| 		uint16_t getI2C_IOExpanderAddress() const; | 		uint16_t getI2C_IOExpanderAddress() const; | ||||||
| 		uint16_t getRTCFlashAddress() const; | 		uint16_t getI2C_RTCFlashAddress() const; | ||||||
| 		 | 		 | ||||||
| 		uint32_t getSPISpeed() const; | 		uint32_t getSPISpeed() const; | ||||||
| 		 | 		 | ||||||
| @ -51,6 +53,7 @@ class BoardConfig | |||||||
| 	const Pin _SPI_miso; | 	const Pin _SPI_miso; | ||||||
| 	const Pin _SPI_clk; | 	const Pin _SPI_clk; | ||||||
| 	const Pin _SPI_SDCard_cs; | 	const Pin _SPI_SDCard_cs; | ||||||
|  | 	const Pin _onBoard_LED; | ||||||
| 	 | 	 | ||||||
| 	//2) I2C Addresses
 | 	//2) I2C Addresses
 | ||||||
| 	const uint16_t _I2C_screenAddress; | 	const uint16_t _I2C_screenAddress; | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ void *CFGFileParser::parseFile() | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else if(readChar == ' ') _state = PARAM_SECTION; |             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) |                 if(_type == PARAMETER) | ||||||
|                 { |                 { | ||||||
| @ -100,7 +100,9 @@ void *CFGFileParser::parseFile() | |||||||
|                 else |                 else | ||||||
|                     _quotedValue = true; |                     _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);
 |                 //printf("%c",readChar);
 | ||||||
|                 if(_type == PARAMETER) |                 if(_type == PARAMETER) | ||||||
| @ -123,7 +125,7 @@ void *CFGFileParser::parseFile() | |||||||
|             _type = VALUE; |             _type = VALUE; | ||||||
|             if(readChar == '\'')_state = OPENING_QUOTE; |             if(readChar == '\'')_state = OPENING_QUOTE; | ||||||
|             else if(readChar == ' ') _state = PARAM_SECTION; |             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; |                 _state = PARAM_SECTION; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ public: | |||||||
|     { |     { | ||||||
|         if(_value == NULL) |         if(_value == NULL) | ||||||
|             return false; |             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;} |     const char *getParameter() const{return _parameter == NULL ? "" : _parameter;} | ||||||
|     bool isQuotedParameter()const{return _quotedParameter;} |     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) | HttpClient::HttpClient(const char *address, uint16_t port, uint32_t timeout) : WiFiClient(), _pAddress(address), _port(port) | ||||||
| { | { | ||||||
|   setTimeout(timeout); |   setTimeout(timeout); | ||||||
|   connectByHostOrIp(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HttpClient::HttpClient(const char *address, const char *resource, uint16_t port, uint32_t timeout) : HttpClient(address, port, timeout) | 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() | HttpClient::~HttpClient() | ||||||
| { | { | ||||||
|   if(_resource != NULL)free(_resource); |   if(connected()) | ||||||
|  |     stop(); | ||||||
|  |   if(_resource != NULL) | ||||||
|  |     free(_resource); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| boolean HttpClient::connectByHostOrIp() | boolean HttpClient::connectByHostOrIp() | ||||||
| @ -53,6 +55,17 @@ boolean HttpClient::connectByHostOrIp() | |||||||
|   #ifdef DEBUG_HTTP_CLIENT |   #ifdef DEBUG_HTTP_CLIENT | ||||||
|   Serial.printf("About to connect\n"); |   Serial.printf("About to connect\n"); | ||||||
|   #endif |   #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)) |   if(ipAddress.fromString(_pAddress)) | ||||||
|   { |   { | ||||||
|     _isIp = true; |     _isIp = true; | ||||||
| @ -93,12 +106,15 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | |||||||
|   //We reset this two flags
 |   //We reset this two flags
 | ||||||
|   _httpCode = HTTP_CODE::UNDEFINED_CODE; |   _httpCode = HTTP_CODE::UNDEFINED_CODE; | ||||||
|   _httpCodeParsed = false; |   _httpCodeParsed = false; | ||||||
|    | 
 | ||||||
|   #ifdef DEBUG_HTTP_CLIENT |   #ifdef DEBUG_HTTP_CLIENT | ||||||
|   if(_keepAlive) |   if(_keepAlive) | ||||||
|     Serial.printf("Link status : %d\n", status()); |     Serial.printf("Link status : %d\n", status()); | ||||||
|   #endif |   #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(!connected() || _connectionStatus == FAILED) | ||||||
|   { |   { | ||||||
|     if(_retries == _maxRetries) return -__LINE__; |     if(_retries == _maxRetries) return -__LINE__; | ||||||
| @ -111,9 +127,9 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | |||||||
|      |      | ||||||
|     #ifdef DEBUG_HTTP_CLIENT |     #ifdef DEBUG_HTTP_CLIENT | ||||||
|     if(_keepAlive) |     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 |     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 |     #endif | ||||||
|      |      | ||||||
|     if(!connectByHostOrIp()) |     if(!connectByHostOrIp()) | ||||||
| @ -131,7 +147,7 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | |||||||
|   if(connected()) |   if(connected()) | ||||||
|   { |   { | ||||||
|     #ifdef DEBUG_HTTP_CLIENT |     #ifdef DEBUG_HTTP_CLIENT | ||||||
|     Serial.printf("Server is listening\n", status()); |     Serial.printf("Server is listening\n"); | ||||||
|     #endif |     #endif | ||||||
|      |      | ||||||
|     switch(method) |     switch(method) | ||||||
| @ -142,6 +158,7 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | |||||||
|         //Here we send the parameters
 |         //Here we send the parameters
 | ||||||
|         sendUriWithGetParams(getData); |         sendUriWithGetParams(getData); | ||||||
|         sendHeader(HttpMIMEType::UNKNOWN_MIME, 0, headerData); |         sendHeader(HttpMIMEType::UNKNOWN_MIME, 0, headerData); | ||||||
|  |         flush(); //We force the send of the request to prevent any timeout on reception !
 | ||||||
|         break; |         break; | ||||||
|       case HttpRequestMethod::POST: |       case HttpRequestMethod::POST: | ||||||
|         //It is necessary to compute the content length
 |         //It is necessary to compute the content length
 | ||||||
| @ -150,17 +167,18 @@ int HttpClient::sendHttpQuery(HttpRequestMethod method, Dictionary<DictionaryHel | |||||||
|         sendUriWithGetParams(getData); |         sendUriWithGetParams(getData); | ||||||
|         sendHeader(HttpMIMEType::APPLICATION_X_WWW_FORM_URLENCODED, computeBodyLength(postData), headerData); |         sendHeader(HttpMIMEType::APPLICATION_X_WWW_FORM_URLENCODED, computeBodyLength(postData), headerData); | ||||||
|         sendPostData(postData); |         sendPostData(postData); | ||||||
|  |         flush(); //We force the send of the request to prevent any timeout on reception !
 | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         #ifdef DEBUG_HTTP_CLIENT |         #ifdef DEBUG_HTTP_CLIENT | ||||||
|         Serial.printf("Http verb unspecified\n", status()); |         Serial.printf("Http verb unspecified\n"); | ||||||
|         #endif |         #endif | ||||||
|         if(!_keepAlive)stop(); |         if(!_keepAlive)stop(); | ||||||
|         return -__LINE__; |         return -__LINE__; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 |    | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -274,7 +292,7 @@ HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout) | |||||||
|           #ifdef DEBUG_HTTP_CLIENT |           #ifdef DEBUG_HTTP_CLIENT | ||||||
|           safeSize = available() > 99 ? 99 : available(); |           safeSize = available() > 99 ? 99 : available(); | ||||||
|           buffer[peekBytes((uint8_t*)buffer,safeSize)] = '\0'; |           buffer[peekBytes((uint8_t*)buffer,safeSize)] = '\0'; | ||||||
|           Serial.printf("Body chunk is : %s\n",buffer); |           Serial.printf("Body chunk is : %s\n", buffer); | ||||||
|           #endif |           #endif | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
| @ -285,7 +303,7 @@ HttpClient::HTTP_CODE HttpClient::isReplyAvailable(uint16_t timeout) | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   #ifdef DEBUG_HTTP_CLIENT |   #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 |   #endif | ||||||
|    |    | ||||||
|   return _httpCode; |   return _httpCode; | ||||||
| @ -408,5 +426,20 @@ uint64_t HttpClient::computeBodyLength(Dictionary<DictionaryHelper::StringEntity | |||||||
| 
 | 
 | ||||||
| void HttpClient::setMaxRetries(int16_t retries) | 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); |     Dictionary<DictionaryHelper::StringEntity> *headerData = NULL); | ||||||
|     void keepAlive(boolean enabled); |     void keepAlive(boolean enabled); | ||||||
|     void setMaxRetries(int16_t retries); |     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); |     HTTP_CODE isReplyAvailable(uint16_t timeout = 10000); | ||||||
|      |      | ||||||
|     uint16_t readHttpBody(uint8_t *buffer, uint32_t size); |     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),  | _connectivityManager(_sdCardManager),  | ||||||
| _webServer(80, &_sdCardManager, 10), | _webServer(80, &_sdCardManager, 10), | ||||||
| _ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10), | _ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10), | ||||||
|  | _otaManager(_sdCardManager, _boardConfig), | ||||||
| _dbWSServer(81), | _dbWSServer(81), | ||||||
| _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire), | _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire), | ||||||
| _ioManager(_pcf), | _ioManager(_pcf), | ||||||
| @ -21,6 +22,7 @@ _screenManager(_display, &_sdCardManager), | |||||||
| _connectivityManager(_sdCardManager),  | _connectivityManager(_sdCardManager),  | ||||||
| _webServer(webServerPort, &_sdCardManager, 10), | _webServer(webServerPort, &_sdCardManager, 10), | ||||||
| _ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10), | _ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10), | ||||||
|  | _otaManager(_sdCardManager, _boardConfig), | ||||||
| _dbWSServer(81), | _dbWSServer(81), | ||||||
| _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),  | _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),  | ||||||
| _ioManager(_pcf), | _ioManager(_pcf), | ||||||
| @ -39,12 +41,18 @@ void SAB::initCommonConfig() | |||||||
|    |    | ||||||
|   //We initialize the pins for the  I2C communication
 |   //We initialize the pins for the  I2C communication
 | ||||||
|   Wire.begin(_boardConfig.getI2C_sda(), _boardConfig.getI2C_scl()); |   Wire.begin(_boardConfig.getI2C_sda(), _boardConfig.getI2C_scl()); | ||||||
|   if(!_rtc.begin()) _error |= RTC_BEGIN_ERR; |   if(!_rtc.begin()) | ||||||
|  |     _error |= RTC_BEGIN_ERR; | ||||||
|   else |   else | ||||||
|   { |   { | ||||||
|     _rtcManager.setDateTime(_rtc.now()); |     _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()) |   if(!_sdCardManager.mountSD()) | ||||||
|   {  |   {  | ||||||
|     _error |= SDCARD_INIT_ERR; |     _error |= SDCARD_INIT_ERR; | ||||||
| @ -52,9 +60,11 @@ void SAB::initCommonConfig() | |||||||
|     _boardConfig.getSPISpeed(), |     _boardConfig.getSPISpeed(), | ||||||
|     _boardConfig.getSPI_SDCard_cs()); |     _boardConfig.getSPI_SDCard_cs()); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   _screenManager.init(); |   _screenManager.init(); | ||||||
|   if(!_connectivityManager.connect()){ _error |= CONNECT_ERR;} |   if(!_connectivityManager.connect()){ _error |= CONNECT_ERR;} | ||||||
|   if(!_pcf.begin()){_error |= IO_INIT_ERR;} |   if(!_pcf.begin()){_error |= IO_INIT_ERR;} | ||||||
|  |   if(!_otaManager.init()){_error |= OTA_INIT_ERR;} | ||||||
| 
 | 
 | ||||||
|   //We set the different servers :
 |   //We set the different servers :
 | ||||||
|   _webServer.setWWWDir(WWW_DIR); |   _webServer.setWWWDir(WWW_DIR); | ||||||
| @ -104,7 +114,12 @@ FTPServer<FTPClient>& SAB::getFtpServer() | |||||||
|   return _ftpServer; |   return _ftpServer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| IOManager& SAB::getIoManager() | OTAManager& SAB::getOTAManager() | ||||||
|  | { | ||||||
|  |   return _otaManager; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IOManager& SAB::getIOManager() | ||||||
| { | { | ||||||
|   return _ioManager; |   return _ioManager; | ||||||
| } | } | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ | |||||||
| #include "IOManager.h" | #include "IOManager.h" | ||||||
| #include "TaskSchedulerManager.h" | #include "TaskSchedulerManager.h" | ||||||
| #include "PowerManager.h" | #include "PowerManager.h" | ||||||
|  | #include "OTAManager.h" | ||||||
| #include "versions.h" | #include "versions.h" | ||||||
| #include <Adafruit_SSD1306.h> | #include <Adafruit_SSD1306.h> | ||||||
| #include <RTClib.h> | #include <RTClib.h> | ||||||
| @ -20,7 +21,7 @@ | |||||||
| class SAB | class SAB | ||||||
| { | { | ||||||
|   public: |   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(); | ||||||
|     SAB(const BoardConfig boardConfig, const unsigned int webServerPort = 80, const unsigned int ftpServerPort = 21); |     SAB(const BoardConfig boardConfig, const unsigned int webServerPort = 80, const unsigned int ftpServerPort = 21); | ||||||
| @ -33,10 +34,10 @@ class SAB | |||||||
|     RTC_DS3231& getRTC_DS3231(); |     RTC_DS3231& getRTC_DS3231(); | ||||||
|     SDCardManager& getSdCardManager(); |     SDCardManager& getSdCardManager(); | ||||||
|     ConnectivityManager& getConnectivityManager(); |     ConnectivityManager& getConnectivityManager(); | ||||||
|     //WEBServerManager& getWebServerManager();
 |  | ||||||
|     WEBServer<WEBClient>& getWebServer(); |     WEBServer<WEBClient>& getWebServer(); | ||||||
|     FTPServer<FTPClient>& getFtpServer(); |     FTPServer<FTPClient>& getFtpServer(); | ||||||
|     IOManager& getIoManager(); |     OTAManager& getOTAManager(); | ||||||
|  |     IOManager& getIOManager(); | ||||||
|     TaskSchedulerManager& getTaskSchedulerManager(); |     TaskSchedulerManager& getTaskSchedulerManager(); | ||||||
|     PowerManager& getPowerManager(); |     PowerManager& getPowerManager(); | ||||||
|     TimeSpan getUpTime() const; |     TimeSpan getUpTime() const; | ||||||
| @ -56,10 +57,10 @@ class SAB | |||||||
|     RTC_DS3231 _rtc; |     RTC_DS3231 _rtc; | ||||||
|     RtcManager _rtcManager; |     RtcManager _rtcManager; | ||||||
|     ConnectivityManager _connectivityManager; |     ConnectivityManager _connectivityManager; | ||||||
|     //WEBServerManager _webServerManager;
 |  | ||||||
|     WEBServer<WEBClient> _webServer; |     WEBServer<WEBClient> _webServer; | ||||||
|     FTPServer<FTPClient> _ftpServer; |     FTPServer<FTPClient> _ftpServer; | ||||||
|     DashboardWSServer    _dbWSServer; |     OTAManager _otaManager; | ||||||
|  |     DashboardWSServer _dbWSServer; | ||||||
|     PCF8574 _pcf; |     PCF8574 _pcf; | ||||||
|     IOManager _ioManager; |     IOManager _ioManager; | ||||||
|     TaskSchedulerManager _taskSchedulerManager; |     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/get/mode", &(ioGetModeApi), &sab, WEBServer<WEBClient>::GET); | ||||||
|   sab.getWebServer().addApiRoutine("/sab/io/set/mode", &(ioSetModeApi), &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/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((uint16_t)0, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setMillis(5000), &(task_blink), &sab); | ||||||
|   sab.getTaskSchedulerManager().addTask(1, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setSeconds(10), &(task_sys_info), &v1p); |   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.ipAddr = sab.getConnectivityManager().localIP(); | ||||||
|     vstap.sigStrength = sab.getConnectivityManager().RSSI(); |     vstap.sigStrength = sab.getConnectivityManager().RSSI(); | ||||||
| 
 | 
 | ||||||
|     sab.getIoManager().getPcf().digitalReadAll(vio.ioState); |     sab.getIOManager().getPcf().digitalReadAll(vio.ioState); | ||||||
|     sab.getIoManager().getPcf().getPinModeAll(vio.ioMode); |     sab.getIOManager().getPcf().getPinModeAll(vio.ioMode); | ||||||
| 
 | 
 | ||||||
|     if(ioStateChange) |     if(ioStateChange) | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -35,10 +35,24 @@ typedef enum {  GPIO_0 = 0, | |||||||
| #define STA_CFG_FILE "/CONFIG/STA.CFG" | #define STA_CFG_FILE "/CONFIG/STA.CFG" | ||||||
| #define SCREEN_CFG_FILE "/CONFIG/SCREEN.CFG" | #define SCREEN_CFG_FILE "/CONFIG/SCREEN.CFG" | ||||||
| #define SERVER_CFG_FILE "/CONFIG/SERVER.CFG" | #define SERVER_CFG_FILE "/CONFIG/SERVER.CFG" | ||||||
|  | #define OTA_CFG_FILE "/CONFIG/OTA.CFG" | ||||||
| #define WWW_DIR "/WWW" | #define WWW_DIR "/WWW" | ||||||
| #define LOG_DIR "/LOGS" | #define LOG_DIR "/LOGS" | ||||||
| #define FTP_DIR "/FTP" | #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 { 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; | typedef enum { BIT = 0, BYTE, KBIT, KBYTE, MBIT, MBYTE, GBIT, GBYTE } SizeUnit; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| boolean task_blink(void *pData) | boolean task_blink(void *pData) | ||||||
| { | { | ||||||
|   SAB *p = (SAB *) pData; |   SAB *p = (SAB *) pData; | ||||||
|   p->getIoManager().getPcf().togglePin(PCF8574::P2); |   p->getIOManager().getPcf().togglePin(PCF8574::P2); | ||||||
| 
 | 
 | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
| @ -19,17 +19,36 @@ boolean task_sys_info(void *pData) | |||||||
| 
 | 
 | ||||||
|   TimeSpan ts(p->sab->getUpTime()); |   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(), |   ts.days(), ts.hours(), ts.minutes(), ts.seconds(), | ||||||
|   p->sab->getError(), |   p->sab->getError(), | ||||||
|   p->sab->getConnectivityManager().localIP().toString().c_str(), |   p->sab->getConnectivityManager().localIP().toString().c_str(), | ||||||
|   p->sab->getConnectivityManager().RSSI(), |   p->sab->getConnectivityManager().RSSI(), | ||||||
|   p->sab->getConnectivityManager().softAPIP().toString().c_str(), |   p->sab->getConnectivityManager().softAPIP().toString().c_str(), | ||||||
|  |   p->sab->getConnectivityManager().macAddress().c_str(), | ||||||
|   p->sab->getWebServer().getConnectedClientsCount(), |   p->sab->getWebServer().getConnectedClientsCount(), | ||||||
|   freeRAM, |   freeRAM, | ||||||
|   HEAPfrag, |   HEAPfrag, | ||||||
|   biggestContigMemBlock); |   biggestContigMemBlock); | ||||||
|   p->powerInfo = p->sab->getPowerManager().getPowerInfo(); |   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; |   return true; | ||||||
| } | } | ||||||
| @ -63,7 +82,7 @@ boolean task_post_data_logger(void * pData) | |||||||
|     postData.add("post4", NULL); |     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"); |       Serial.println("Send successful"); | ||||||
|       p->rdy = false; |       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.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.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.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
 | #endif //VERSIONS_H
 | ||||||
|  | |||||||
| @ -400,38 +400,38 @@ boolean ioSetLevelApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc | |||||||
| 
 | 
 | ||||||
|   if(HRD.getParams("P0") != NULL) |   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) |   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) |   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) |   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) |   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) |   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) |   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) |   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]); |   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)); |   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] = ""; |   char helperBuffer[20] = ""; | ||||||
|   const char * const IN = "IN", * const OUT = "OUT"; |   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
 |   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) |   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) |   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) |   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) |   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) |   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) |   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) |   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) |   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); |   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)); |   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) | boolean swVersionApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, void *pData) | ||||||
| { | { | ||||||
|   (void)HRD; |   (void)HRD; | ||||||
|   (void)pData; |   SAB *p = (SAB *)pData; | ||||||
| 
 | 
 | ||||||
|   char buffer[100] = ""; |   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)); |   WEBServer<WEBClient>::sendHTTPHeader(wc, HttpConstants::httpMIMETypeToString(HttpConstants::APPLICATION_JSON), strlen(buffer)); | ||||||
|   wc->print(buffer); |   wc->print(buffer); | ||||||
|   return true; |   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)HRD; | ||||||
|   (void)pData; |   (void)pData; | ||||||
|   Serial.printf("OTA Update resquest\n#"); |   Serial.printf("OTA Update Upload resquest\n#"); | ||||||
| 
 | 
 | ||||||
|   char buffer[30] = ""; |   char buffer[30] = ""; | ||||||
|   size_t read(0), cnt(0); |   size_t read(0), cnt(0); | ||||||
| @ -602,3 +602,58 @@ boolean otaUpdateApi(WEBServer<WEBClient>::HttpRequestData &HRD, WiFiClient *wc, | |||||||
| 
 | 
 | ||||||
|   return true; |   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 ioGetModeApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||||
| boolean ioSetModeApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | boolean ioSetModeApi(WEBServer<WEBClient>::HttpRequestData&, WiFiClient*, void*); | ||||||
| boolean swVersionApi(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 | #endif | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user