Implemented timezone lookup
Very unstable at the moment, likely due to SSL's memory requirements combined with my lack of optimization
This commit is contained in:
parent
d1126e70d3
commit
d9d9b45956
@ -138,18 +138,18 @@ const uint8_t EmbeddedBundleCSS[] PROGMEM = {
|
||||
0x7c,0xa6,0x30,0x1c,0xa6,0xe2,0xcf,0x16,0x49,0xdb,0xf3,0x71,0x71,0x7e,0xbd,0x3c,0x9e,0x14,0xa0,0x3d,
|
||||
0x7d,0x80,0x56,0x2e,0x92,0xf8,0xa9,0xab,0xbe,0xf4,0x26,0x09,0x74,0x2e,0x7f,0x02,0x69,0x71,0xc2,0x42,
|
||||
0x98,0xff,0xe5,0x24,0x17,0x54,0x17,0xd4,0xf5,0x64,0x54,0xdf,0xf1,0x12,0x08,0x4b,0xda,0x2c,0x60,0xbc,
|
||||
0x20,0xd9,0x6a,0x13,0xe2,0xde,0x86,0xfd,0x05,0x81,0x37,0x62,0xb5,0xde,0x5f,0xae,0x5e,0x31,0xb7,0xfb,
|
||||
0x35,0x2d,0xf9,0x09,0x7b,0x2b,0x86,0x2a,0x1b,0x4a,0xfd,0xf7,0x9d,0xb6,0xfa,0x19,0x44,0xcf,0xc2,0xf5,
|
||||
0x20,0xdf,0xb8,0xb6,0xb9,0x54,0x71,0x74,0x27,0x46,0x12,0x2d,0x2c,0x74,0x92,0x20,0xb9,0xce,0x30,0x20,
|
||||
0x67,0x8b,0xea,0x7b,0x8a,0x37,0x74,0xa3,0xd9,0x43,0x1f,0x5e,0x6f,0xc7,0x0b,0xf6,0xf9,0xda,0x0c,0xfb,
|
||||
0x8c,0x9b,0x06,0x9d,0x70,0x37,0xbd,0x26,0x54,0xd0,0x6c,0x76,0xe6,0xe9,0x15,0x11,0x1c,0xfd,0x05,0x5d,
|
||||
0x8c,0x4b,0xa6,0xdc,0xe8,0x11,0x2a,0x9f,0x3f,0x9a,0x70,0xc3,0xdf,0x96,0x18,0x8f,0x98,0xde,0xae,0x50,
|
||||
0x81,0xf3,0xf9,0xf9,0x3f,0x79,0xbb,0x55,0xd1,0xd6,0xd8,0xdb,0x66,0xc4,0x06,0xff,0xb2,0x44,0x9e,0xa8,
|
||||
0xc9,0x4c,0xb8,0xdf,0xca,0xe1,0x43,0x43,0x68,0xe8,0xee,0x1e,0x94,0x08,0x28,0x9b,0x8f,0x45,0xa5,0xb9,
|
||||
0x39,0x29,0x48,0xcf,0x9d,0x9d,0x16,0x72,0xe6,0xf0,0xce,0x0a,0x40,0xcb,0xcc,0x46,0x11,0x8f,0xf5,0x72,
|
||||
0x51,0xa3,0x9f,0x17,0x99,0x2b,0xe2,0x48,0x85,0x83,0x8a,0xb5,0x50,0x09,0x79,0x1b,0xf8,0x78,0x57,0x0b,
|
||||
0x78,0xe3,0xf5,0x98,0x12,0x28,0x44,0x9d,0x21,0x71,0x5f,0xbf,0x43,0x63,0xc5,0x97,0xbd,0x76,0x7d,0xc3,
|
||||
0x55,0xc2,0x0a,0x02,0x7b,0x30,0x4e,0xa7,0x7b,0x87,0xf6,0x82,0xf1,0x73,0x8c,0xde,0xc4,0xfa,0xc4,0xde,
|
||||
0x07,0x29,0xff,0x03,0xbb,0xba,0x32,0x32,0x37,0x2e,0x00,0x00};
|
||||
0x20,0xd9,0x6a,0x13,0xe2,0xde,0x86,0xfd,0x05,0x81,0x37,0x62,0xb5,0xde,0x5f,0xae,0x5e,0x71,0xb5,0x3b,
|
||||
0x64,0x7c,0xb0,0xf1,0xae,0x39,0xc9,0x4f,0xd8,0x58,0x31,0x94,0xd8,0x50,0xe7,0xbf,0xef,0xa8,0xd5,0xb3,
|
||||
0x17,0x0d,0x0b,0xd7,0x83,0x64,0xe3,0xda,0xe3,0x52,0x65,0xd1,0x1d,0x17,0x49,0xb4,0xb0,0xca,0x49,0x76,
|
||||
0xe4,0x3a,0xc3,0x80,0x9c,0x2a,0xaa,0x2f,0x29,0xde,0x50,0x8c,0x66,0x03,0x7d,0x78,0xbd,0x1d,0xaf,0xd6,
|
||||
0xe7,0x6b,0x33,0xec,0x33,0x6e,0x1a,0x74,0xc2,0xdd,0xf4,0x8e,0x50,0x41,0xb3,0xd9,0x81,0xa7,0x57,0x44,
|
||||
0x70,0xf4,0x17,0x74,0x31,0x2e,0x99,0x72,0xa3,0xe7,0xa7,0x7c,0xf8,0x68,0x62,0x0d,0x7f,0x55,0x62,0x3c,
|
||||
0x5f,0x7a,0xbb,0x42,0x05,0xce,0xe7,0x87,0xff,0xe4,0xd5,0x56,0x45,0x5b,0x63,0x63,0x9b,0x11,0x1b,0xfc,
|
||||
0xcb,0x12,0x49,0xa2,0x26,0x2d,0xe1,0x4e,0x2b,0xc7,0x0e,0x0d,0xa1,0xa1,0xbb,0x78,0x50,0xc2,0x9f,0x6c,
|
||||
0x3e,0x16,0x92,0xe6,0xe6,0xa4,0x20,0x3d,0x77,0x76,0x54,0xc8,0x69,0xc3,0x3b,0xd3,0x7f,0x2d,0x33,0x1b,
|
||||
0x45,0x3c,0xd0,0xcb,0x15,0x8d,0x7e,0x5e,0x64,0xae,0x88,0x23,0x55,0x0d,0x2a,0xd6,0x42,0x19,0xe4,0x6d,
|
||||
0xe0,0xe3,0x5d,0x2d,0xe0,0x8d,0x77,0x63,0x4a,0x94,0x10,0x45,0x86,0xc4,0x7d,0xfd,0x02,0x8d,0x55,0x5e,
|
||||
0xf6,0xda,0xdd,0x0d,0x57,0x09,0xab,0x06,0xec,0xc1,0x38,0x9d,0xee,0x05,0xda,0x0b,0xc6,0xcf,0x31,0x7a,
|
||||
0x13,0xeb,0x13,0x7b,0x1f,0xa4,0xfc,0x0f,0x98,0xb1,0x01,0x7f,0x34,0x2e,0x00,0x00};
|
||||
|
||||
#endif
|
||||
|
4576
src/assets/js.h
4576
src/assets/js.h
File diff suppressed because it is too large
Load Diff
@ -29,4 +29,16 @@ void assignChar(char** field, const char* newValue)
|
||||
}
|
||||
else
|
||||
*field = nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool sameStr(const char* value1, const char* value2)
|
||||
{
|
||||
if ((value1 == nullptr) != (value2 == nullptr))
|
||||
return true;
|
||||
|
||||
if (value1 == nullptr)
|
||||
return false;
|
||||
|
||||
return strcmp(value1, value2) == 0;
|
||||
}
|
@ -10,5 +10,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void assignChar(char** field, const char* newValue);
|
||||
bool sameStr(const char* value1, const char* value2);
|
||||
|
||||
#endif
|
@ -21,6 +21,8 @@ static const char* MotionTriggerSettingsFile = "/motiontriggers.json";
|
||||
|
||||
static const char* DefaultAPSSIDPrefix = "Stairs-";
|
||||
|
||||
static const char* DefaultNTPServer = "pool.ntp.org";
|
||||
|
||||
// Timeout when in AP + station mode (otherwise trying to connect
|
||||
// to the STA will block the AP)
|
||||
static const uint32_t StationModeTimeout = 30000;
|
||||
@ -28,4 +30,8 @@ static const uint32_t StationModeTimeout = 30000;
|
||||
static const uint16_t APButtonHoldTime = 5000;
|
||||
|
||||
|
||||
// Only used if the timezone has not been succesfully retrieved yet, otherwise
|
||||
// the configurable NTP interval is used
|
||||
static const uint32_t TimezoneRetryInterval = 60000;
|
||||
|
||||
#endif
|
@ -29,5 +29,7 @@ bool shouldReboot = false;
|
||||
uint32_t currentTime;
|
||||
|
||||
NTPClient* ntpClient = nullptr;
|
||||
bool hasTimezone = false;
|
||||
uint32_t timezoneOffset = 0;
|
||||
|
||||
IPAddress emptyIP(0, 0, 0, 0);
|
||||
|
@ -41,6 +41,8 @@ extern bool shouldReboot;
|
||||
extern uint32_t currentTime;
|
||||
|
||||
extern NTPClient* ntpClient;
|
||||
extern bool hasTimezone;
|
||||
extern uint32_t timezoneOffset;
|
||||
|
||||
extern IPAddress emptyIP;
|
||||
|
||||
|
@ -9,7 +9,9 @@
|
||||
//#include <ESPAsyncTCP.h>
|
||||
#include <WiFiUDP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#include <TimeLib.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
extern "C" {
|
||||
#include <user_interface.h>
|
||||
|
@ -63,6 +63,9 @@ void updateDebugStatus()
|
||||
|
||||
_d(day(time)); _d("-"); _d(month(time)); _d("-"); _d(year(time)); _d(" ");
|
||||
_d(hour(time)); _d(":"); _d(minute(time)); _d(":"); _dln(second(time));
|
||||
|
||||
_d("Status :: offset: ");
|
||||
_dln(timezoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,13 @@ uint32_t lastTimeTriggerChecked = 0;
|
||||
TimeTrigger* lastTimeTrigger = nullptr;
|
||||
TimeTrigger* activeTimeTrigger = nullptr;
|
||||
|
||||
uint32_t lastTimezoneUpdate = 0;
|
||||
AsyncClient* timezoneClient = nullptr;
|
||||
char* response = nullptr;
|
||||
uint16_t responseSize = 0;
|
||||
|
||||
static const uint16_t ResponseMaxSize = 1024;
|
||||
|
||||
|
||||
void initMotionPins()
|
||||
{
|
||||
@ -19,6 +26,136 @@ void initMotionPins()
|
||||
}
|
||||
|
||||
|
||||
void parseResponse()
|
||||
{
|
||||
if (response == nullptr || responseSize == 0)
|
||||
return;
|
||||
|
||||
_dln("Timezone :: response:");
|
||||
_dln(response);
|
||||
|
||||
char* data = response;
|
||||
if (strncmp(data, "HTTP/1.0 ", 9) != 0)
|
||||
{
|
||||
_dln("Timezone :: not an HTTP response");
|
||||
return;
|
||||
}
|
||||
|
||||
data += 9;
|
||||
if (strncmp(data, "200", 3) != 0)
|
||||
{
|
||||
_dln("Timezone :: invalid HTTP status code");
|
||||
return;
|
||||
}
|
||||
|
||||
data = strstr(data, "\r\n\r\n");
|
||||
if (data == nullptr)
|
||||
{
|
||||
_dln("Timezone :: end of HTTP headers not found");
|
||||
return;
|
||||
}
|
||||
|
||||
data += 4;
|
||||
|
||||
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(5) + 200);
|
||||
JsonObject& root = jsonBuffer.parseObject(data);
|
||||
|
||||
if (!sameStr(root["status"], "OK"))
|
||||
{
|
||||
_dln("Timezone :: invalid status in response");
|
||||
return;
|
||||
}
|
||||
|
||||
timezoneOffset = root["rawOffset"];
|
||||
hasTimezone = true;
|
||||
}
|
||||
|
||||
|
||||
void updateTimezone()
|
||||
{
|
||||
if (timezoneClient != nullptr)
|
||||
return;
|
||||
|
||||
timezoneClient = new AsyncClient();
|
||||
if (!timezoneClient)
|
||||
return;
|
||||
|
||||
timezoneClient->onError([](void* arg, AsyncClient* client, int error)
|
||||
{
|
||||
_d("Timezone :: error ");
|
||||
_dln(error);
|
||||
|
||||
timezoneClient = nullptr;
|
||||
delete client;
|
||||
|
||||
lastTimezoneUpdate = currentTime;
|
||||
}, nullptr);
|
||||
|
||||
timezoneClient->onConnect([](void* arg, AsyncClient* client)
|
||||
{
|
||||
response = (char*)malloc(ResponseMaxSize + 1);
|
||||
responseSize = 0;
|
||||
timezoneClient->onError(nullptr, nullptr);
|
||||
|
||||
client->onDisconnect([](void * arg, AsyncClient * c)
|
||||
{
|
||||
timezoneClient = nullptr;
|
||||
delete c;
|
||||
|
||||
lastTimezoneUpdate = currentTime;
|
||||
|
||||
parseResponse();
|
||||
free(response);
|
||||
response = nullptr;
|
||||
}, nullptr);
|
||||
|
||||
client->onData([](void* arg, AsyncClient* c, void* data, size_t len)
|
||||
{
|
||||
uint16_t copyLen = responseSize == ResponseMaxSize ? 0 :
|
||||
responseSize + len > ResponseMaxSize ? ResponseMaxSize - responseSize :
|
||||
len;
|
||||
|
||||
if (copyLen > 0)
|
||||
{
|
||||
memcpy(response + responseSize, data, copyLen);
|
||||
responseSize += copyLen;
|
||||
response[responseSize] = 0;
|
||||
}
|
||||
}, nullptr);
|
||||
|
||||
|
||||
uint32_t timestamp = ntpClient->getEpochTime();
|
||||
String request = "GET /maps/api/timezone/json?location=" +
|
||||
String(systemSettings->latitude(), 7) + "," + String(systemSettings->longitude(), 7) +
|
||||
"8×tamp=" +
|
||||
String(timestamp);
|
||||
|
||||
_d("Timezone :: request: ");
|
||||
_dln(request);
|
||||
|
||||
if (systemSettings->mapsAPIKey() != nullptr)
|
||||
request = request + "&key=" + systemSettings->mapsAPIKey();
|
||||
|
||||
request = request + " HTTP/1.0\r\nHost: maps.googleapis.com\r\n\r\n";
|
||||
client->write(request.c_str());
|
||||
}, nullptr);
|
||||
|
||||
_d("Timezone :: available heap: ");
|
||||
_dln(ESP.getFreeHeap());
|
||||
|
||||
if(!timezoneClient->connect("maps.googleapis.com", 443, true))
|
||||
{
|
||||
_dln("Timezone :: failed to connect to host");
|
||||
|
||||
AsyncClient * client = timezoneClient;
|
||||
timezoneClient = nullptr;
|
||||
delete client;
|
||||
|
||||
lastTimezoneUpdate = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void updateNTPClient()
|
||||
{
|
||||
if (ntpClient == nullptr && WiFi.status() == WL_CONNECTED &&
|
||||
@ -31,14 +168,30 @@ void updateNTPClient()
|
||||
}
|
||||
|
||||
|
||||
if (ntpClient != nullptr)
|
||||
// Only update if we're not in the middle of a transition, as it will block
|
||||
// the loop until the NTP server responds or times out (up to a second)
|
||||
if (ntpClient != nullptr && !stairs->inTransition())
|
||||
{
|
||||
ntpClient->update();
|
||||
|
||||
// Lat/lng 0,0 is off the African coast, I think we can safely assume nobody
|
||||
// will have WiFi enabled stair lighting at that location.
|
||||
if (timezoneClient == nullptr && systemSettings->latitude() && systemSettings->longitude())
|
||||
{
|
||||
uint32_t interval = hasTimezone ? systemSettings->ntpInterval() * 60 * 1000 : TimezoneRetryInterval;
|
||||
if (lastTimezoneUpdate == 0 || currentTime - lastTimezoneUpdate > interval)
|
||||
{
|
||||
updateTimezone();
|
||||
lastTimezoneUpdate = currentTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void updateTimeTrigger()
|
||||
{
|
||||
if (ntpClient == nullptr || !timeTriggerSettings->enabled())
|
||||
if (ntpClient == nullptr || !hasTimezone || !timeTriggerSettings->enabled())
|
||||
{
|
||||
activeTimeTrigger = nullptr;
|
||||
return;
|
||||
@ -65,10 +218,8 @@ void updateTimeTrigger()
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO apply timezone offset
|
||||
|
||||
tmElements_t time;
|
||||
breakTime(epochTime, time);
|
||||
breakTime(epochTime + timezoneOffset, time);
|
||||
|
||||
activeTimeTrigger = timeTriggerSettings->getActiveTrigger(time);
|
||||
|
||||
|
@ -65,11 +65,11 @@ bool ConnectionSettings::fromJson(char* data, bool* changed)
|
||||
if (!(jsonAccessPoint || jsonStation))
|
||||
jsonAccessPoint = true;
|
||||
|
||||
if ((jsonHostname != hostname()) ||
|
||||
if ((!sameStr(jsonHostname, hostname())) ||
|
||||
(jsonAccessPoint != flag(AccessPoint)) ||
|
||||
(jsonStation != flag(StationMode)) ||
|
||||
(jsonSSID != ssid()) ||
|
||||
(jsonPassword != password()) ||
|
||||
(!sameStr(jsonSSID, ssid())) ||
|
||||
(!sameStr(jsonPassword, password())) ||
|
||||
(jsonDHCP != flag(DHCP)) ||
|
||||
(jsonIP != ip()) ||
|
||||
(jsonSubnetMask != subnetMask()) ||
|
||||
|
@ -68,6 +68,9 @@ bool SystemSettings::fromJson(char* data, bool* changed)
|
||||
uint16_t jsonPWMDriverFrequency = root["pwmFrequency"];
|
||||
const char* jsonMapAPIKey = root["mapsAPIKey"];
|
||||
|
||||
if (jsonNTPServer == nullptr) jsonNTPServer = DefaultNTPServer;
|
||||
if (jsonNTPInterval == 0) jsonNTPInterval = 5;
|
||||
|
||||
if (jsonPinLEDAP == 0) jsonPinLEDAP = pinLEDAP();
|
||||
if (jsonPinLEDSTA == 0) jsonPinLEDSTA = pinLEDSTA();
|
||||
if (jsonPinAPButton == 0) jsonPinAPButton = pinAPButton();
|
||||
@ -85,10 +88,10 @@ bool SystemSettings::fromJson(char* data, bool* changed)
|
||||
(jsonPinPWMDriverSCL != pinPWMDriverSCL()) ||
|
||||
(jsonPWMDriverAddress != pwmDriverAddress()) ||
|
||||
(jsonPWMDriverFrequency != pwmDriverFrequency()) ||
|
||||
(jsonMapAPIKey != mapsAPIKey()) ||
|
||||
(!sameStr(jsonMapAPIKey, mapsAPIKey())) ||
|
||||
(jsonLat != latitude()) ||
|
||||
(jsonLng != longitude()) ||
|
||||
(jsonNTPServer != ntpServer()) ||
|
||||
(!sameStr(jsonNTPServer, ntpServer())) ||
|
||||
(jsonNTPInterval != ntpInterval()))
|
||||
{
|
||||
latitude(jsonLat);
|
||||
|
@ -17,7 +17,7 @@
|
||||
class SystemSettings : public AbstractJsonSettings
|
||||
{
|
||||
private:
|
||||
char* mNTPServer = nullptr;
|
||||
char* mNTPServer;
|
||||
uint32_t mNTPInterval = 5;
|
||||
|
||||
double mLatitude = 0;
|
||||
@ -39,6 +39,12 @@ class SystemSettings : public AbstractJsonSettings
|
||||
virtual const char* getDebugPrefix() { return "SystemSettings"; };
|
||||
|
||||
public:
|
||||
SystemSettings()
|
||||
{
|
||||
assignChar(&mNTPServer, DefaultNTPServer);
|
||||
}
|
||||
|
||||
|
||||
void toJson(Print &print);
|
||||
bool fromJson(char* data, bool* changed);
|
||||
|
||||
|
@ -34,6 +34,8 @@ class Stairs
|
||||
void init(PCA9685* pwmDriver);
|
||||
void tick();
|
||||
|
||||
bool inTransition() { return mTick; }
|
||||
|
||||
uint8_t get(uint8_t step, bool target = true);
|
||||
void set(uint8_t step, uint8_t brightness, uint16_t transitionTime = 0, uint16_t startTime = 0);
|
||||
void setAll(uint8_t brightness, uint16_t transitionTime = 0, uint16_t startTime = 0);
|
||||
|
2
web/dist/bundle.css
vendored
2
web/dist/bundle.css
vendored
File diff suppressed because one or more lines are too long
2
web/dist/bundle.js
vendored
2
web/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -293,7 +293,7 @@ input[disabled]
|
||||
|
||||
.notificationContainer
|
||||
{
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 2rem;
|
||||
z-index: 666;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user