Skip to content

Instantly share code, notes, and snippets.

@Conplug
Last active November 25, 2019 06:21
Show Gist options
  • Save Conplug/c7014cf9f4129de6e9c3250286563390 to your computer and use it in GitHub Desktop.
Save Conplug/c7014cf9f4129de6e9c3250286563390 to your computer and use it in GitHub Desktop.
NTP Clock, DHT11, Light Sensor(BH1750), PMS5003T, PMS3003
//
// Copyright (c) 2019 Conplug (https://conplug.com.tw)
// Author: Hartman Hsieh
//
// Description :
//
// Building Configurations:
// Board : NodeMCU 1.0(ESP-12E Module)
// Flash Size : 4M(1M SPIFFS)
//
// Connections :
// "DFRobot Gravity I2C LCD1602" => "IIC0" ( "NMNR_EX V1.0" )
// "Light Sensor BH1750" => "IIC1" ( "NMNR_EX V1.0" )
// "Dust Sensor PMS5003T" => "JD8D7" ( "NMNR_EX V1.0" )
// "DFRobot DHT11 Sensor" => "JD3" ( "NMNR_EX V1.0" )
// "POT_BTN V1.0" => "JA0D4" ( "NMNR_EX V1.0" )
// "Light Meter" => "IIC2" ( "NMNR_EX V1.0" )
//
// Required Library :
// https://github.com/PaulStoffregen/Time
// https://github.com/bearwaterfall/DFRobot_LCD-master
// https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
// https://github.com/Conplug/Conplug_UnifiedLcd
// https://github.com/beegee-tokyo/DHTesp
// https://github.com/Conplug/Conplug_PMS5003T
// https://github.com/claws/BH1750
//
#define ENABLE_HTTPS_UPDATE 1
#define ENABLE_PMS 1
#define ENABLE_LIGHT_METER_BH1750 1
#include <Wire.h> // IIC bus
#include <FS.h> // SPIFFS
const float FwVersion = 1.3;
//
// Wifi SSID and password
//
const char ssid[] = ""; // your network SSID (name)
const char pass[] = ""; // your network password
//
// DHT pin defines
//
#define DHTPIN D3
//
// Button PIN
//
const int BUTTON_PIN = D4;
//
// Potentiometer PIN
//
const int POT_PIN = A0;
//
// The file would be saved in SPIFFS.
//
const String CFG_FILE_NAME = "ntpclock.cfg";
//
// IIC LCD Module
//
#include "Conplug_UnifiedLcd.h"
Conplug_UnifiedLcd* Lcd = 0;
//
// Library for Time function
//
#include <TimeLib.h>
//
// ESP8266 Wifi library
//
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h> // HTTPS
#include <WiFiUdp.h>
// NTP Servers:
static const char ntpServerName[] = "us.pool.ntp.org";
//static const char ntpServerName[] = "time.nist.gov";
//static const char ntpServerName[] = "time-a.timefreq.bldrdoc.gov";
//static const char ntpServerName[] = "time-b.timefreq.bldrdoc.gov";
//static const char ntpServerName[] = "time-c.timefreq.bldrdoc.gov";
const int timeZone = 8; // Taipei Time
//const int timeZone = -5; // Eastern Standard Time (USA)
//const int timeZone = -4; // Eastern Daylight Time (USA)
//const int timeZone = -8; // Pacific Standard Time (USA)
//const int timeZone = -7; // Pacific Daylight Time (USA)
WiFiUDP Udp;
unsigned int localPort = 8888; // local port to listen for UDP packets
//
// Function definitions
//
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
const char* WeekDays[] = {"Sun", "Mon","Tue","Wed","Thu","Fri","Sat"}; // Days Of The Week
#if ENABLE_HTTPS_UPDATE == 1
#include <ESP8266httpUpdate.h>
#endif // #if ENABLE_HTTPS_UPDATE == 1
//
// Include DHT header file.
//
#include "DHTesp.h"
DHTesp Dht;
#if ENABLE_LIGHT_METER_BH1750 == 1
#include <BH1750.h>
BH1750* LightMeter;
#endif // #if ENABLE_LIGHT_METER_BH1750 == 1
#include "SoftwareSerial.h"
SoftwareSerial SerialSensor(D7, D8); // RX:D7, TX:D8
#if ENABLE_PMS == 1
//
// PMS3003, PMS5003T
//
#include "Conplug_PMS5003T.h"
Conplug_PMS5003T Pms(&SerialSensor);
#endif // #if ENABLE_PMS == 1
//
// Function definitions
//
void ICACHE_RAM_ATTR IntCallback();
void DisplayDht11();
void DisplayLight();
void DisplayPms();
//
// Global variable
//
unsigned long PreviousClick = 0;
unsigned long PreviousDisplay = 0;
unsigned long PreviousDhtReading = 0;
unsigned long PreviousLuxReading = 0;
unsigned long PreviousPmsReading = 0;
//
// Sensor values
//
float h = 0.0;
float t = 0.0;
float lux = 0.0;
uint8_t BuffPms[MAX_PMS_DATA_SIZE];
PMS5003T_DATA* pd;
unsigned long PreviousGetFwVer = 0;
float FwVerOnServer = 0.0;
#define CFG_DATA_FLAG_ACTIVE 1
const int MAX_CFGDATA_DATA_SIZE = 48; // String size is 48-1
struct CFG_DATA {
char Type[6]; // Max size is 5
char Data[MAX_CFGDATA_DATA_SIZE];
uint8_t Flag;
};
const int MAX_CFGDATA_COUNT = 16;
CFG_DATA CfgData[MAX_CFGDATA_COUNT];
const String CFG_DATA_FLAG_DESC[3] = {"", "ACTIVE", "DEL"};
const int GLOBAL_WIFI_SSID_LIST_COUNT = 5;
String GlobalWifiSsidList[GLOBAL_WIFI_SSID_LIST_COUNT] = {"","","","",""};
#define SENSOR_INDEX_DHT11 0
#define SENSOR_INDEX_LIGHT 1
#define SENSOR_INDEX_PMS 2
typedef void (*SensorDisplay)();
SensorDisplay SensorDisplayArr[8] = {
DisplayDht11,
DisplayLight,
DisplayPms
};
int SensorDetectedArr[8];
int SensorDetectedCount = 0;
int PmsErrCount = 0;
void setup()
{
Wire.begin(); // Join IIC bus
pinMode(POT_PIN, INPUT);
pinMode(BUTTON_PIN, INPUT);
Serial.begin(9600);
//
// Clear the array memory
//
memset(&(CfgData[0]), 0, sizeof(CFG_DATA) * MAX_CFGDATA_COUNT);
//
// Parsing CFG file in FFS and saving in array - CfgData.
//
ParsingCfg();
//
// Initialize LCD module
//
Lcd = new Conplug_UnifiedLcd(16, 2);
Lcd->init();
Lcd->setCursor(0, 0);
Lcd->print("conplug.com.tw ");
Lcd->setCursor(0, 1);
Lcd->print("FW:");
Lcd->print(FwVersion, 1);
Lcd->print(" ");
//
// Add hardcoding SSID setting to array - GlobalWifiSsidList.
//
int wifi_ssid_index = 0;
if((strlen(ssid) > 0) && (strlen(pass) > 0)) {
GlobalWifiSsidList[wifi_ssid_index] = ssid;
GlobalWifiSsidList[wifi_ssid_index] += ",";
GlobalWifiSsidList[wifi_ssid_index] += pass;
wifi_ssid_index++;
}
//
// Add SSID settings that is saved in SPIFFS config file.
//
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
if(wifi_ssid_index > GLOBAL_WIFI_SSID_LIST_COUNT) break;
//
// Skip the data that is not active.
//
if(CfgData[i].Flag != CFG_DATA_FLAG_ACTIVE)
continue;
String cfg_data_type = CfgData[i].Type;
if(cfg_data_type.equalsIgnoreCase("SSID")) {
GlobalWifiSsidList[wifi_ssid_index] = CfgData[i].Data;
wifi_ssid_index++;
}
}
//
// Connect to WIFI APs.
//
WifiConn(GlobalWifiSsidList, wifi_ssid_index);
//
// Display current firmware version.
//
Lcd->setCursor(0, 1);
Lcd->print("FW:");
Lcd->print(FwVersion, 1);
Lcd->print(" ");
//
// Sensor initialize and detect
// Sensors must be initialized later.
//
SensorInit();
#if ENABLE_HTTPS_UPDATE == 1
if(digitalRead(BUTTON_PIN) && (analogRead(POT_PIN) >= 512)) {
delay(1500);
if(digitalRead(BUTTON_PIN) && (analogRead(POT_PIN) >= 512)) {
//
// Get the newest firmware version on server.
//
DisplayTypeFwVer();
//
// Start flashing.
//
FlashFirmware();
while(1){delay(60 * 60 * 1000);}
}
}
#endif // #if ENABLE_HTTPS_UPDATE == 1
//
// NTP function
//
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(Udp.localPort());
Serial.println("waiting for sync");
setSyncProvider(getNtpTime); // set the external time provider
setSyncInterval(36000); // set the number of seconds between re-sync
//attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), IntCallback, RISING);
}
//
// Sensor initialize and detect
//
void SensorInit() {
//
// Clear the array memory
//
memset(&(SensorDetectedArr[0]), 0, sizeof(SensorDetectedArr));
//
// DHT Sensor initialize and detect
//
//Dht.setup(DHTPIN, DHTesp::AUTO_DETECT);
Dht.setup(DHTPIN, DHTesp::DHT11);
//delay(200);
h = Dht.getHumidity();
t = Dht.getTemperature();
if (isnan(h) || isnan(t))
SensorDetectedArr[SENSOR_INDEX_DHT11] = 0;
else
SensorDetectedArr[SENSOR_INDEX_DHT11] = 1;
//
// Light Sensor initialize and detect
//
#if ENABLE_LIGHT_METER_BH1750 == 1
Serial.println("LightMeter (BH1750)...");
LightMeter = new BH1750();
//delay(200);
if(LightMeter->begin())
SensorDetectedArr[SENSOR_INDEX_LIGHT] = 1;
else
SensorDetectedArr[SENSOR_INDEX_LIGHT] = 0;
#endif // #if ENABLE_LIGHT_METER_BH1750 == 1
//
// PMS5003T initialize and detect
//
#if ENABLE_PMS == 1
Serial.println("Init PMS5003T...");
Pms.begin();
if(Pms.readPms()) {
Serial.println("PMSX003 initialize successfully.");
SensorDetectedArr[SENSOR_INDEX_PMS] = 1;
}
else {
Serial.println("PMSX003 initialize unsuccessfully.");
SensorDetectedArr[SENSOR_INDEX_PMS] = 0;
}
#endif // #if ENABLE_PMS == 1
//
// Calculate the detected sensor count.
//
for(int i = 0; i < (sizeof(SensorDetectedArr) / sizeof(int)); i++) {
if(SensorDetectedArr[i]) SensorDetectedCount++;
Serial.print("SensorDetectedArr[");
Serial.print(i);
Serial.print("]=");
Serial.println(SensorDetectedArr[i]);
}
}
void loop()
{
int DisplayIndex = 0;
int PotValue = analogRead(POT_PIN);
//
// Detect PMS5003T or PMS3003 again.
//
if((millis() < (20 * 1000)) && (SensorDetectedArr[SENSOR_INDEX_PMS] == 0)) {
//
// Detect PMS again.
//
if(Pms.readPms())
SensorDetectedArr[SENSOR_INDEX_PMS] = 1;
//
// Calculate the detected sensor count.
//
SensorDetectedCount = 0;
for(int i = 0; i < (sizeof(SensorDetectedArr) / sizeof(int)); i++) {
if(SensorDetectedArr[i]) SensorDetectedCount++;
Serial.print("SensorDetectedArr[");
Serial.print(i);
Serial.print("]=");
Serial.println(SensorDetectedArr[i]);
}
}
if(PotValue < ((1024 / (3 + SensorDetectedCount)) * (DisplayIndex + 1))) {
DisplayType1();
}
DisplayIndex++;
if((PotValue >= ((1024 / (3 + SensorDetectedCount)) * DisplayIndex)) && (PotValue < ((1024 / (3 + SensorDetectedCount)) * (DisplayIndex + 1)))) {
DisplayType2();
}
DisplayIndex++;
//
// Display detected sensor values.
//
for(int i = 0; i < (sizeof(SensorDetectedArr) / sizeof(int)); i++) {
if(SensorDetectedArr[i]) {
if((PotValue >= ((1024 / (3 + SensorDetectedCount)) * DisplayIndex)) && (PotValue < ((1024 / (3 + SensorDetectedCount)) * (DisplayIndex + 1)))) {
//
// Execute the sensor display function.
//
SensorDisplayArr[i]();
}
DisplayIndex++;
}
}
if(PotValue >= ((1024 / (3 + SensorDetectedCount)) * DisplayIndex)) {
DisplayTypeFwVer();
}
DisplayIndex++;
//
// Read command from user.
//
if (Serial.available()) {
char line_buff[64] = {0};
int ci = 0;
memset(&(line_buff[0]), 0, 64); // Clear the data.
while(Serial.available()) {
char c = Serial.read();
if(c == ';') { // reach command ending char - ';'
line_buff[ci] = 0;
String str_temp = line_buff;
Serial.print("INPUT LENGTH = ");
Serial.println(ci);
ParsingCmd(&str_temp);
ci = 0;
break;
}
else if(c == '\r') {} // Skip char - CR('\r')(0x0d)
else if(c == '\n') {} // Skip char - LF('\n')(0x0a)
else {
line_buff[ci] = c;
Serial.print(line_buff[ci], HEX);
Serial.print(" ");
ci++;
}
delay(30);
}
}
}
void ICACHE_RAM_ATTR IntCallback(){
unsigned long MillisTemp = millis();
if ((MillisTemp - PreviousClick) > 500) { // Debouncing
Serial.println("Button Click");
PreviousClick = MillisTemp;
}
}
//
// Display Date, Time, Humidity and Temperature
//
void DisplayType1()
{
boolean pms_read_ok = false;
if ((millis() - PreviousDhtReading) > (Dht.getMinimumSamplingPeriod() * 2)) {
//
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
//
h = Dht.getHumidity();
//
// Read temperature as Celsius (the default)
//
t = Dht.getTemperature();
//
// Check if any reads failed and exit early (to try again).
//
if (isnan(h) || isnan(t)) {
//Serial.println("Failed to read from DHT sensor!");
}
else
SensorDetectedArr[SENSOR_INDEX_DHT11] = 1;
PreviousDhtReading = millis();
}
//
// Print YEAR-MONTH-DAY
//
Lcd->setCursor(0, 0);
Lcd->print(year());
Lcd->print("-");
PrintLcdDigits(month());
Lcd->print("-");
PrintLcdDigits(day());
Lcd->print(" ");
Lcd->setCursor(16 - 5, 0); // Align right
if(SensorDetectedArr[SENSOR_INDEX_DHT11]) {
Lcd->printf("%2.1f", t);
Lcd->print("C");
}
else if(SensorDetectedArr[SENSOR_INDEX_PMS]) {
#if ENABLE_PMS == 1
PMS5003T_DATA* pd = 0;
//
// Running readPms before running pm2_5, temp, humi and readDeviceType.
//
if(pd = Pms.readPms()) {
pms_read_ok = true;
if(Pms.pm2_5() < 16)
Lcd->printf("%5s", "GOOD");
else if((Pms.pm2_5() >= 16) && (Pms.pm2_5() < 35))
Lcd->printf("%5s", "FAIR");
else
Lcd->printf("%5s", "POOR");
}
else {
PmsErrCount++;
}
#endif // #if ENABLE_PMS == 1
}
else {
Lcd->print(" ");
}
//
// Print HOUR:MIN:SEC WEEK
//
Lcd->setCursor(0, 1);
PrintLcdDigits(hour());
Lcd->print(":");
PrintLcdDigits(minute());
Lcd->print(":");
PrintLcdDigits(second());
Lcd->print(" ");
Lcd->print(WeekDays[weekday() - 1]);
Lcd->print(" ");
Lcd->setCursor(16 - 3, 1); // Align right
if(SensorDetectedArr[SENSOR_INDEX_DHT11]) {
Lcd->printf("%2d", (int)h);
Lcd->print("%");
}
else if(SensorDetectedArr[SENSOR_INDEX_PMS]) {
#if ENABLE_PMS == 1
//
// Check the sign characters.
//
if(pms_read_ok && (Pms.readDeviceType() == Conplug_PMS5003T::PMS5003T)) {
Lcd->printf("%2d", (int)(Pms.temp()));
Lcd->print("C");
}
#endif // #if ENABLE_PMS == 1
}
else {
Lcd->print(" ");
}
}
//
// Display Date and Time
//
void DisplayType2()
{
//
// Print YEAR-MONTH-DAY
//
Lcd->setCursor(0, 0);
Lcd->print(" ");
Lcd->print(year());
Lcd->print("-");
PrintLcdDigits(month());
Lcd->print("-");
PrintLcdDigits(day());
Lcd->print(" ");
//
// Print HOUR:MIN:SEC WEEK
//
Lcd->setCursor(0, 1);
Lcd->print(" ");
PrintLcdDigits(hour());
Lcd->print(":");
PrintLcdDigits(minute());
Lcd->print(":");
PrintLcdDigits(second());
Lcd->print(" ");
Lcd->print(WeekDays[weekday() - 1]);
Lcd->print(" ");
}
//
// Display Humidity and Temperature
//
void DisplayDht11()
{
if ((millis() - PreviousDhtReading) > (Dht.getMinimumSamplingPeriod() * 2)) {
//
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
//
h = Dht.getHumidity();
//
// Read temperature as Celsius (the default)
//
t = Dht.getTemperature();
//
// Check if any reads failed and exit early (to try again).
//
if (isnan(h) || isnan(t)) {
//Serial.println("Failed to read from DHT sensor!");
}
PreviousDhtReading = millis();
}
Lcd->setCursor(0, 0);
Lcd->print("Temp: ");
Lcd->print(t, 1);
Lcd->print("C");
Lcd->setCursor(0, 1);
Lcd->print("Humidity: ");
Lcd->print(h, 0);
Lcd->print("%");
}
//
// Display
//
void DisplayLight()
{
#if ENABLE_LIGHT_METER_BH1750 == 1
if ((millis() - PreviousLuxReading) > 500) {
lux = LightMeter->readLightLevel();
PreviousLuxReading = millis();
}
#endif // #if ENABLE_LIGHT_METER_BH1750 == 1
//
// Print HOUR:MIN:SEC WEEK
//
Lcd->setCursor(0, 0);
Lcd->print(" ");
PrintLcdDigits(hour());
Lcd->print(":");
PrintLcdDigits(minute());
Lcd->print(":");
PrintLcdDigits(second());
Lcd->print(" ");
Lcd->print(WeekDays[weekday() - 1]);
Lcd->print(" ");
Lcd->setCursor(0, 1);
Lcd->print("Light:");
Lcd->printf("%7d LX", (int)lux); // Align right
}
//
// Display PMS5003T(PM2.5, Humidity and Temperature)
//
void DisplayPms()
{
#if ENABLE_PMS == 1
if((millis() - PreviousPmsReading) > 1500) { // 1.5 second
PMS5003T_DATA* pd = 0;
//
// Running readPms before running pm2_5, temp, humi and readDeviceType.
//
if(pd = Pms.readPms()) {
Lcd->setCursor(0, 0);
Lcd->print("PM2.5: ");
Lcd->print(Pms.pm2_5());
Lcd->print("ug/m3 ");
if(Pms.readDeviceType() == Conplug_PMS5003T::PMS5003T) {
Lcd->setCursor(0, 1);
Lcd->print((float)(Pms.temp()), 1);
Lcd->print("C ");
Lcd->print((float)(Pms.humi()), 1);
Lcd->print("% ");
}
else {
Lcd->setCursor(0, 1);
Lcd->print(" ");
}
}
else {
Serial.println("PMS data format is wrong.");
Serial.println(Pms.LastErr);
PmsErrCount++;
}
//Lcd->setCursor(13, 1);
//Lcd->printf("%3d", PmsErrCount);
PreviousPmsReading = millis();
}
#endif // #if ENABLE_PMS == 1
}
//
// Display the newest firmware version on server.
//
void DisplayTypeFwVer() {
if(FwVerOnServer == 0.0) {
Lcd->setCursor(0, 0);
Lcd->print("Checking... ");
Lcd->setCursor(0, 1);
Lcd->print(" ");
if((PreviousGetFwVer == 0) || ((millis() - PreviousGetFwVer) > (60 * 60 * 1000))) { // 60 minutes
//
// Connect to server to get the newest firmware version.
//
std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
client->setInsecure();
HTTPClient https;
if (https.begin(*client, "https://conplug.com.tw/iot/fw.php")) { // HTTPS
Serial.println("[HTTPS] GET...");
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server?
if (httpCode == HTTP_CODE_OK) {
String payload = https.getString();
Serial.print("The newest firmware version on server is ");
Serial.println(payload);
const char* c = payload.c_str();
if(isDigit(c[0]) && (c[1] == '.') && isDigit(c[2]) && (payload.length() == 3)) { // Check the result is a float.
FwVerOnServer = payload.toFloat();
}
}
}
else {
Serial.printf("[HTTPS] GET... failed, error: %s\n\r", https.errorToString(httpCode).c_str());
}
https.end();
}
else {
Serial.printf("[HTTPS] Unable to connect\n\r");
}
PreviousGetFwVer = millis();
}
}
else {
Lcd->setCursor(0, 0);
Lcd->print("Newest Firmware ");
Lcd->setCursor(0, 1);
Lcd->print("On Server : ");
Lcd->print(FwVerOnServer, 1);
Lcd->print(" ");
}
}
int WifiConn(const String* WifiSsidList, const int Count) {
//
// Try to connect to WIFI APs in WifiSsidList.
//
for(int i = 0; i < Count; i++) {
//
// The string format should be:
// ssid_pass = "ssid,pass"
//
String ssid_pass = WifiSsidList[i];
int pos = ssid_pass.indexOf(",");
if(pos == -1) continue; // format error, skip.
String tmp_ssid = ssid_pass.substring(0, pos);
tmp_ssid.trim();
String tmp_pass = ssid_pass.substring(pos + 1); // +1 to skip char - ','
tmp_pass.trim();
Serial.print("Connecting to ");
Serial.print(tmp_ssid);
Serial.print(",");
Serial.println(tmp_pass);
WiFi.begin(tmp_ssid, tmp_pass);
Lcd->setCursor(0, 1);
Lcd->print(tmp_ssid);
Lcd->print(" ");
//
// Waiting for WIFI connection
//
unsigned long WifiConnectingTimeout = millis();
while (WiFi.status() != WL_CONNECTED) {
//
// Waiting for 15 seconds
//
if((millis() - WifiConnectingTimeout) > 15000) { // 15 seconds
break;
}
delay(500);
Lcd->setCursor(14, 1);
Lcd->print((int)((millis() - WifiConnectingTimeout) / 1000));
}
if(WiFi.status() == WL_CONNECTED)
break;
}
Serial.print("IP number assigned by DHCP is ");
Serial.println(WiFi.localIP());
if(WiFi.status() == WL_CONNECTED)
return 0; // Success
else
return 2; // Failure
}
//
// CFG File Format:
// SSID=SSID,PASSWORD
// DVTP=1
//
void ParsingCfg() {
String file_name = "/" + CFG_FILE_NAME;
SPIFFS.begin();
// open the file for reading:
File cfg_file = SPIFFS.open(file_name, "r");
char line_buff[64] = {0};
int index = 0;
memset(&(line_buff[0]), 0, 64); // Clear the data.
if (cfg_file) {
Serial.println(file_name);
index = 0;
// read from the file until there's nothing else in it:
while (cfg_file.available()) {
char c = cfg_file.read();
if (c == '\r') {
}
else if (c == '\n') {
line_buff[index] = 0;
ParsingCfgLine(line_buff);
//Serial.println(line_buff);
index = 0;
}
else {
line_buff[index] = c;
index++;
//Serial.write(line_buff[index]);
}
}
if (index != 0) {
line_buff[index] = 0;
ParsingCfgLine(line_buff);
//Serial.println(line_buff);
}
// close the file:
cfg_file.close();
}
else {
//
// if the file didn't open, print an error:
//
Serial.print("error opening ");
Serial.println(file_name);
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
if(CfgData[i].Type[0] == 0) { // empty
//
// Create a cfg file and add one line - "DVTP=2".
//
strcpy(CfgData[i].Type, "DVTP");
strcpy(CfgData[i].Data, "2");
CfgData[i].Flag = CFG_DATA_FLAG_ACTIVE;
SaveCfgFile();
break;
}
}
}
}
void ParsingCfgLine(const char* Line) {
ParsingCfgLine(Line, -1);
}
//
// CFG Line Format:
// SSID=SSID,PASSWORD
//
// if(Index == -1) Add a new CFG data
// else Modify the data of CfgData[Index]
//
void ParsingCfgLine(const char* Line, int Index) {
String line_temp = Line;
int target_index = -1;
//
// Find out the target index in CfgData array.
//
if(Index == -1) { // Add a new CFG data
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
if(CfgData[i].Type[0] == 0) { // Found an empty data.
target_index = i;
break;
}
}
}
else { // Modify one CFG data
if(Index < MAX_CFGDATA_COUNT) { // in range
if(CfgData[Index].Type[0] != 0) { // not empty
target_index = Index;
}
}
}
if(target_index != -1) {
int pos = line_temp.indexOf("=");
String str_temp = line_temp.substring(0, pos);
str_temp.trim();
//Serial.print(str_temp);
//Serial.print(" ");
strncpy(CfgData[target_index].Type, str_temp.c_str(), 5); // max size is 5
str_temp = line_temp.substring(pos + 1); // +1 is for skipping '='
str_temp.trim();
//Serial.println(str_temp);
strncpy(CfgData[target_index].Data, str_temp.c_str(), MAX_CFGDATA_DATA_SIZE - 1); // max string size is MAX_CFGDATA_DATA_SIZE - 1
CfgData[target_index].Flag = CFG_DATA_FLAG_ACTIVE;
}
}
//
// Save array - CfgData to SPIFFS config file.
//
void SaveCfgFile () {
//
// The path in FFS
//
String file_name = "/" + CFG_FILE_NAME;
File cfg_file = SPIFFS.open(file_name, "w+");
if (cfg_file) {
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
//
// Skip the data that is not active.
//
if(CfgData[i].Flag != CFG_DATA_FLAG_ACTIVE)
continue;
cfg_file.print(CfgData[i].Type);
cfg_file.print("=");
cfg_file.println(CfgData[i].Data);
}
//
// close the file
//
cfg_file.close();
}
else {
//
// if the file didn't open, print an error:
//
Serial.print("error opening ");
Serial.println(file_name);
//
// close the file:
//
cfg_file.close();
}
}
//
// Parsing command that received from serial port.
//
void ParsingCmd(String* Line) {
Line->trim();
String str_temp = "";
int first_space_index = Line->indexOf(" ");
Serial.print("COMMAND : ");
Serial.println(*Line);
if(first_space_index == -1) {
if (Line->equalsIgnoreCase("ls")) {
Serial.println("List data in config file.");
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
if(CfgData[i].Type[0] != 0) {
Serial.print("(");
Serial.print(i);
Serial.print(")\t");
Serial.print(CfgData[i].Type);
Serial.print("\t");
Serial.print(CfgData[i].Data);
Serial.print("\t");
Serial.println(CFG_DATA_FLAG_DESC[CfgData[i].Flag]);
}
}
}
}
else {
//
// Command line format:
// add SSID=NAME,PASS
// | +----------CfgData array data
// +---------------CfgData array type
//
String str_cmd = Line->substring(0, first_space_index);
if (str_cmd.equalsIgnoreCase("add")) {
Serial.println("Add data to config file.");
int pos = indexOfNot(Line, ' ', first_space_index);
str_temp = Line->substring(pos);
str_temp.trim();
ParsingCfgLine(str_temp.c_str()); // Add the cfg data.
SaveCfgFile(); // Save to FFS
}
//
// Command line format:
// del 2
// +-----------------CfgData array index
//
else if (str_cmd.equalsIgnoreCase("del")) {
Serial.println("Delete data in config file.");
int pos = indexOfNot(Line, ' ', first_space_index);
str_temp = Line->substring(pos);
str_temp.trim();
if(isValidNumber(str_temp)) {
int cfg_data_index = str_temp.toInt();
if(cfg_data_index < MAX_CFGDATA_COUNT) {
Serial.print("DELETE (");
Serial.print(cfg_data_index);
Serial.println(")");
memset(&(CfgData[cfg_data_index]), 0, sizeof(CFG_DATA)); // Clear the data.
SaveCfgFile(); // Save to FFS
}
}
}
//
// Command line format:
// mod 2 SSID=NAME,PASS
// | | +----------CfgData array data
// | +---------------CfgData array type
// +-----------------CfgData array index
//
else if (str_cmd.equalsIgnoreCase("mod")) {
Serial.println("Modify data in config file.");
int pos = indexOfNot(Line, ' ', first_space_index);
int pos2 = Line->indexOf(" ", pos);
str_temp = Line->substring(pos, pos2); // Grab "CfgData array index" in command line
str_temp.trim();
if(isValidNumber(str_temp)) { // Check the "CfgData array index" is a number
int cfg_data_index = str_temp.toInt(); // Transform it to int
if(cfg_data_index < MAX_CFGDATA_COUNT) {
for(int i = 0; i < MAX_CFGDATA_COUNT; i++) {
if((i == cfg_data_index) && (CfgData[i].Type[0] != 0)) {
pos = indexOfNot(Line, ' ', pos2);
str_temp = Line->substring(pos); // Grab "CfgData array type and data" in command line
Serial.print("MODIFY (");
Serial.print(i);
Serial.print(") TO ");
Serial.println(str_temp);
ParsingCfgLine(str_temp.c_str(), i); // modify it
SaveCfgFile(); // Save to FFS
}
}
}
}
}
}
}
//
// Find the first char index that doesn't equal to val.
//
int indexOfNot(String* str, char val, int from) {
const char* c = str->c_str();
int pos = from;
for(pos = from; pos < str->length(); pos++) {
if(c[pos] != val) break;
}
if(pos == str->length())
return -1;
else
return pos;
}
boolean isValidNumber(String str)
{
boolean isNum=false;
if(!(str.charAt(0) == '+' || str.charAt(0) == '-' || isDigit(str.charAt(0)))) return false;
for(byte i=1;i<str.length();i++)
{
if(!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) return false;
}
return true;
}
#if ENABLE_HTTPS_UPDATE == 1
void FlashFirmware() {
String err_msg = "";
if(FwVerOnServer != 0.0) {
std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
client->setInsecure(); // For HTTPS
Lcd->setCursor(0, 0);
Lcd->print("Flashing... ");
Lcd->setCursor(0, 1);
Lcd->print(" ");
//
// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
//
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
String url = "https://conplug.com.tw/iot/bin/ntpclock_";
url += String(FwVerOnServer, 1);
url += ".bin";
Serial.println("Download firmware for flashing.");
Serial.println(url);
t_httpUpdate_return ret = ESPhttpUpdate.update(*client, url);
switch (ret) {
case HTTP_UPDATE_FAILED:
err_msg = ESPhttpUpdate.getLastErrorString();
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), err_msg.c_str());
Lcd->setCursor(0, 0);
Lcd->print("ERROR:");
Lcd->print(err_msg.substring(0, 10));
Lcd->print(" ");
Lcd->setCursor(0, 1);
Lcd->print(err_msg.substring(10));
Lcd->print(" ");
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("HTTP_UPDATE_OK");
break;
}
}
}
#endif // #if ENABLE_HTTPS_UPDATE == 1
void PrintLcdDigits(int digits)
{
if (digits < 10)
Lcd->print('0');
Lcd->print(digits);
}
/*-------- NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
time_t getNtpTime()
{
IPAddress ntpServerIP; // NTP server's ip address
for (int i = 0; i < 6; i++) { // Retry 6 times if "No NTP Response"
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
// get a random server from the pool
WiFi.hostByName(ntpServerName, ntpServerIP);
Serial.print(ntpServerName);
Serial.print(": ");
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response :-(");
delay(500);
}
return 0; // return 0 if unable to get the time
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment