fetch time from ntp server

master
Kenneth Barbour 2020-06-18 22:22:04 -04:00
parent 5d3f61a1b4
commit 9b43bbcdb3
4 changed files with 140 additions and 2 deletions

View File

@ -6,6 +6,7 @@
#include "update.h"
#include "bme280.h"
#include "config.h"
#include "time.h"
#ifndef SERIAL_BAUD
#define SERIAL_BAUD 74880
@ -71,6 +72,7 @@ void setup()
//
bme280_init();
uweather_time_init();
uweather_update_init();
}
@ -79,5 +81,6 @@ void loop()
{
uweather_web_handle();
uweather_update_handle();
uweather_time_handle();
delay(10);
}

118
src/time.cpp 100644
View File

@ -0,0 +1,118 @@
#include <time.h>
#include <Arduino.h>
#include <WiFiUdp.h>
#include <ESP8266WiFi.h>
#include "config.h"
#define LOCAL_NTP_PORT 2390
#define NTP_RETRY_INTERVAL 300000
#define DEFAULT_NTP_HOST "time.nist.gov"
#define NTP_PACKET_SIZE 48
enum state { INIT, SENT, IDLE, NO_HOST} ntp_state;
byte packet_buffer[NTP_PACKET_SIZE]; // NTP timestamp is in the first 48 bytes
WiFiUDP udp;
unsigned long time_offset = 0;
unsigned long ntp_timestamp = 0;
unsigned long retry_at = 0;
IPAddress host;
const char* ntp_get_hostname()
{
const char* host_in_cfg = (const char*) Config._data.ntp_host;
if (host_in_cfg[0] == '\0') {
return DEFAULT_NTP_HOST;
}
return host_in_cfg;
}
void uweather_time_init()
{
ntp_state = state::INIT;
time_offset = 0;
ntp_timestamp = 0;
retry_at = 0;
udp.begin(LOCAL_NTP_PORT);
}
void uweather_time_handle()
{
switch (ntp_state) {
case state::INIT:
{
if (!WiFi.isConnected())
return;
// resolve ntp hostname
const char* hostname = ntp_get_hostname();
if (!WiFi.hostByName(hostname, host)) {
ntp_state = state::NO_HOST;
Serial.printf("Unable to resolve ntp host: %s\n", hostname);
retry_at = millis() + NTP_RETRY_INTERVAL;
break;
}
// send packet to ntp server
Serial.printf("Sending ntp packet to %s\n", hostname);
memset(packet_buffer, 0, NTP_PACKET_SIZE);
packet_buffer[0] = 0b11100011; // LI, Version, Mode
packet_buffer[1] = 0;
packet_buffer[2] = 6;
packet_buffer[3] = 0xEC;
packet_buffer[12] = 49;
packet_buffer[13] = 0x4E;
packet_buffer[14] = 49;
packet_buffer[15] = 52;
udp.beginPacket(host, 123);
udp.write(packet_buffer, NTP_PACKET_SIZE);
udp.endPacket();
ntp_state = state::SENT;
}
case state::SENT:
{
int cb = udp.parsePacket();
if (!cb) break;
udp.read(packet_buffer, NTP_PACKET_SIZE);
unsigned long high = word(packet_buffer[40], packet_buffer[41]);
unsigned long low = word(packet_buffer[42], packet_buffer[43]);
unsigned long secs = (high << 16 | low) - 2208988800UL; // subtract 70 years from time
time_offset = millis();
ntp_timestamp = secs;
ntp_state = state::IDLE;
Serial.printf("Received NTP response, current timestamp is %lu\n", secs);
}
case state::IDLE:
break;
case state::NO_HOST:
if (millis() > retry_at) {
state::INIT;
}
break;
default:
break;
}
}
bool has_timestamp()
{
return ntp_timestamp > 0;
}
void set_timestamp(unsigned long ts)
{
time_offset = millis() / 1000;
ntp_timestamp = ts;
}
unsigned long timestamp(unsigned long milliseconds)
{
if (!has_timestamp()) return 0;
return (milliseconds / 1000) - time_offset + ntp_timestamp;
}
unsigned long current_timestamp()
{
return timestamp(millis());
}

10
src/time.h 100644
View File

@ -0,0 +1,10 @@
#ifndef _UWEATHER_NTP_H_
#define _UWEATHER_NTP_H_
void uweather_time_init();
void uweather_time_handle();
unsigned long timestamp(unsigned long);
unsigned long current_timestamp();
#endif /** End _UWEATHER_NTP_H_ include guard */

View File

@ -6,6 +6,7 @@
#include <QueryString.h>
#include "config.h"
#include "version.h"
#include "time.h"
/**
* How long to wait after the OK to shutdown before no longer
@ -80,13 +81,19 @@ void handle_firmware(HttpRequest& req, HttpResponse& res)
void handle_weather_current(HttpRequest& req, HttpResponse& res)
{
char buff[3][10] = {};
char buff[4][10] = {};
unsigned long now = current_timestamp();
dtostrf(BME.readTemperature(), 2, 1, buff[0]);
dtostrf(BME.readPressure(), 2, 1, buff[1]);
dtostrf(BME.readHumidity(), 2, 1, buff[2]);
if (now) {
sprintf(buff[3], "%d", now);
} else {
strcpy(buff[3], "null");
}
Serial.printf("temp= %s, pres= %s, hum=%s\r\n", buff[0], buff[1], buff[2]);
res.headers.set("Content-Type", "application/json");
content.printf("{\"time\": null, \"temperature\": %s, \"pressure\": %s, \"humidity\": %s}", buff[0], buff[1], buff[2]);
content.printf("{\"time\": %s, \"temperature\": %s, \"pressure\": %s, \"humidity\": %s}", buff[3], buff[0], buff[1], buff[2]);
}
// Handle WiFi Scan