ESPNTPServer/src/ESPNTPServer.cpp
2019-07-18 09:33:52 -07:00

306 lines
8.0 KiB
C++

/*
* ESPNTPServer.cpp
*
* Copyright 2017 Christopher B. Liebman
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* Created on: Oct 29, 2017
* Author: liebman
*/
#include "ESPNTPServer.h"
#include "ESPNTPServerVersion.h"
#include "Log.h"
#include "DLogPrintWriter.h"
#include "DLogSyslogWriter.h"
#include "GPS.h"
#include "NTP.h"
#include "Display.h"
#include "Config.h"
DLog& dlog = DLog::getLog();
GPS gps(Serial, SYNC_PIN);
NTP ntp(gps);
Display display(gps, ntp, SDA_PIN, SCL_PIN);
Config config;
char devicename[32];
const char* SETUP_TAG = "setup";
const char* LOOP_TAG = "loop";
void logTimeFirst(DLogBuffer& buffer, DLogLevel level)
{
(void)level; // not used
struct timeval tv;
struct tm tm;
gps.getTime(&tv);
gmtime_r(&tv.tv_sec, &tm);
buffer.printf(F("%04d/%02d/%02d %02d:%02d:%02d.%06ld "),
tm.tm_year+1900,
tm.tm_mon+1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
tv.tv_usec);
}
void processOTA(const char* ota_url, const char* ota_fp)
{
static PROGMEM const char TAG[] = "processOTA";
dlog.info(FPSTR(TAG), F("OTA update"));
dlog.info(FPSTR(TAG), F("checking for OTA from: '%s'"), ota_url);
display.message("Starting OTA");
ESPhttpUpdate.rebootOnUpdate(false);
#ifdef USE_CERT_STORE
CertStore certStore;
#endif
WiFiClient *client = nullptr;
if (strncmp(ota_url, "https:", 6) == 0)
{
#ifdef USE_CERT_STORE
int numCerts = certStore.initCertStore(SPIFFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
dlog.info(FPSTR(TAG), F("Number of CA certs read: %d"), numCerts);
#endif
BearSSL::WiFiClientSecure *bear = new BearSSL::WiFiClientSecure();
#ifdef USE_CERT_STORE
// Integrate the cert store with this connection
dlog.info(FPSTR(TAG), F("adding cert store to connection"));
bear->setCertStore(&certStore);
#else
bear->setInsecure();
#endif
client = bear;
}
else
{
client = new WiFiClient;
}
t_httpUpdate_return ret = ESPhttpUpdate.update(*client, ota_url, "0.4");
String reason = ESPhttpUpdate.getLastErrorString();
switch(ret)
{
case HTTP_UPDATE_OK:
dlog.info(FPSTR(TAG), F("OTA update OK! restarting..."));
dlog.end();
display.message("Success!");
delay(10000);
ESP.restart();
break;
case HTTP_UPDATE_FAILED:
dlog.info(FPSTR(TAG), F("OTA update failed! reason:'%s'"), reason.c_str());
display.message("FAILED!");
delay(10000);
break;
case HTTP_UPDATE_NO_UPDATES:
dlog.info(FPSTR(TAG), F("OTA no updates! reason:'%s'"), reason.c_str());
display.message("NO Update!");
delay(10000);
break;
default:
dlog.info(FPSTR(TAG), F("OTA update WTF? unexpected return code: %d reason: '%s'"), ret, reason.c_str());
display.message("Unknown!");
delay(10000);
break;
}
}
void setup()
{
//delay(5000); // delay for IDE to re-open serial
//
// Setup DLog with Serial1, set the pre function to add the date/time
//
Serial1.begin(76800);
dlog.begin(new DLogPrintWriter(Serial1));
dlog.setPreFunc(&logTimeFirst);
//dlog.setLevel("GPS", DLogLevel::DLOG_LEVEL_DEBUG);
dlog.setLevel("Config", DLogLevel::DLOG_LEVEL_DEBUG);
dlog.info(SETUP_TAG, F("Startup!"));
snprintf(devicename, sizeof(devicename), "ESPNTP:%08x", ESP.getChipId());
dlog.info(SETUP_TAG, "Device name: %s", devicename);
dlog.info(SETUP_TAG, F("initializing display"));
display.begin();
dlog.info(SETUP_TAG, F("initializing serial for GPS"));
Serial.begin(9600);
Serial.swap();
dlog.info(SETUP_TAG, F("initializing GPS"));
display.message("Starting GPS");
gps.begin();
display.process();
bool force_config = false;
config.begin();
if (!config.load())
{
dlog.warning(SETUP_TAG, "no config found, forcing config portal!");
force_config = true;
}
// if the reset/config button is pressed then force config
if (digitalRead(CONFIG_PIN) == 0)
{
time_t start = millis();
while (digitalRead(CONFIG_PIN) == 0)
{
time_t delta = millis() - start;
if (!force_config && delta > CONFIG_DELAY)
{
dlog.info(SETUP_TAG, F("reset button held, forcing config!"));
force_config = true;
display.message("Force Config");
}
}
}
#if !defined(USE_NO_WIFI)
dlog.info(SETUP_TAG, F("initializing wifi"));
display.message("Starting WiFi");
WiFiSetup wifi(config, display, Serial1, false, devicename);
wifi.connect(force_config);
const char* syslog_host = config.getSyslogHost();
uint16_t syslog_port = config.getSyslogPort();
if (syslog_host != nullptr && strlen(syslog_host) > 0 && syslog_port != 0)
{
dlog.info(SETUP_TAG, "enabling syslog: '%s:%u'", syslog_host, syslog_port);
dlog.begin(new DLogSyslogWriter(syslog_host, syslog_port, devicename, ESPNTP_SERVER_VERSION));
}
const char* url = wifi.getOTAURL();
const char* fp = wifi.getOTAFP();
if (fp == nullptr)
{
fp = "";
}
if (url != nullptr)
{
processOTA(url, fp);
}
WiFiMode_t mode = WiFi.getMode();
dlog.error(SETUP_TAG, "WiFi mode: %d", mode);
#endif
display.process();
dlog.info(SETUP_TAG, F("initializing NTP"));
ntp.begin();
}
void loop()
{
static int last_wifi_status;
static IPAddress last_ip;
int wifi_status = WiFi.status();
if (wifi_status != last_wifi_status)
{
const char* status;
switch (wifi_status)
{
case WL_CONNECTED:
status = "CONNECTED";
break;
case WL_NO_SSID_AVAIL:
status = "NO_SSID";
break;
case WL_CONNECT_FAILED:
status = "FAILED";
break;
case WL_IDLE_STATUS:
status = "IDLE";
break;
case WL_DISCONNECTED:
status = "DISCONNECTED";
break;
default:
status = "<UNKNOWN>";
break;
}
dlog.info(LOOP_TAG, F("wifi status change %d -> %d '%s'"), last_wifi_status, wifi_status, status);
last_wifi_status = wifi_status;
}
IPAddress ip = WiFi.localIP();
if (ip != last_ip)
{
dlog.warning(LOOP_TAG, F("ip address change %s -> %s"), last_ip.toString().c_str(), ip.toString().c_str());
last_ip = ip;
}
#if 0
uint32_t m = millis();
if (m % 1000 == 0)
{
dlog.info("loop", "uptime: %lu millis: %lu", m);
}
#endif
gps.process();
static time_t last_seconds;
struct timeval tv;
gps.getTime(&tv);
if (tv.tv_sec != last_seconds)
{
if (tv.tv_sec != last_seconds && ((tv.tv_sec % 300) == 0 || gps.getValidDelay()))
{
dlog.info("loop", F("jitter:%lu valid_count:%lu valid:%s gpsvalid:%s numsat:%d heap:%ld valid_delay:%d"),
gps.getJitter(),
gps.getValidCount(),
gps.isValid() ? "true" : "false",
gps.isGPSValid() ? "true" : "false",
gps.getSatelliteCount(),
ESP.getFreeHeap(),
gps.getValidDelay());
}
if (tv.tv_sec < last_seconds)
{
dlog.warning(LOOP_TAG, F("OOPS: time went backwards: last:%lu now:%lu delta:%ld"), last_seconds, tv.tv_sec, tv.tv_sec-last_seconds);
}
display.process();
}
last_seconds = tv.tv_sec;
}