Browse Source

first patch from homeautomation22

pull/345/head
DanielR92 3 years ago
parent
commit
8bf90775c8
  1. 22
      tools/esp8266/ahoywifi.cpp
  2. 4
      tools/esp8266/ahoywifi.h
  3. 54
      tools/esp8266/app.cpp
  4. 27
      tools/esp8266/app.h
  5. 6
      tools/esp8266/html/index.html
  6. 99
      tools/esp8266/sun.cpp
  7. 42
      tools/esp8266/sun.h
  8. 3
      tools/esp8266/webApi.cpp

22
tools/esp8266/ahoywifi.cpp

@ -12,7 +12,6 @@
// NTP CONFIG // NTP CONFIG
#define NTP_PACKET_SIZE 48 #define NTP_PACKET_SIZE 48
#define TIMEZONE 1 // Central European time +1
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -185,7 +184,6 @@ time_t ahoywifi::getNtpTime(void) {
WiFi.hostByName(mConfig->ntpAddr, timeServer); WiFi.hostByName(mConfig->ntpAddr, timeServer);
mUdp->begin(mConfig->ntpPort); mUdp->begin(mConfig->ntpPort);
sendNTPpacket(timeServer); sendNTPpacket(timeServer);
while(retry++ < 5) { while(retry++ < 5) {
@ -200,7 +198,6 @@ time_t ahoywifi::getNtpTime(void) {
secsSince1900 |= (buf[43] ); secsSince1900 |= (buf[43] );
date = secsSince1900 - 2208988800UL; // UTC time date = secsSince1900 - 2208988800UL; // UTC time
date += (TIMEZONE + offsetDayLightSaving(date)) * 3600;
break; break;
} }
else else
@ -231,22 +228,3 @@ void ahoywifi::sendNTPpacket(IPAddress& address) {
mUdp->write(buf, NTP_PACKET_SIZE); mUdp->write(buf, NTP_PACKET_SIZE);
mUdp->endPacket(); mUdp->endPacket();
} }
//-----------------------------------------------------------------------------
// calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
// from: https://forum.arduino.cc/index.php?topic=172044.msg1278536#msg1278536
time_t ahoywifi::offsetDayLightSaving (uint32_t local_t) {
//DPRINTLN(DBG_VERBOSE, F("wifi::offsetDayLightSaving"));
int m = month (local_t);
if(m < 3 || m > 10) return 0; // no DSL in Jan, Feb, Nov, Dez
if(m > 3 && m < 10) return 1; // DSL in Apr, May, Jun, Jul, Aug, Sep
int y = year (local_t);
int h = hour (local_t);
int hToday = (h + 24 * day(local_t));
if((m == 3 && hToday >= (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 4) % 7)))
|| (m == 10 && hToday < (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 1) % 7))) )
return 1;
else
return 0;
}

4
tools/esp8266/ahoywifi.h

@ -30,11 +30,9 @@ class ahoywifi {
bool setupStation(uint32_t timeout); bool setupStation(uint32_t timeout);
bool getApActive(void); bool getApActive(void);
time_t getNtpTime(void); time_t getNtpTime(void);
private: private:
void sendNTPpacket(IPAddress& address); void sendNTPpacket(IPAddress& address);
time_t offsetDayLightSaving (uint32_t local_t);
config_t *mConfig; config_t *mConfig;
sysConfig_t *mSysCfg; sysConfig_t *mSysCfg;

54
tools/esp8266/app.cpp

@ -44,6 +44,8 @@ void app::setup(uint32_t timeout) {
mWebInst = new web(this, &mSysConfig, &mConfig, &mStat, mVersion); mWebInst = new web(this, &mSysConfig, &mConfig, &mStat, mVersion);
mWebInst->setup(); mWebInst->setup();
mSun.setLocalization(52.6479, 13.6922); // ToDo: add lan/lon to setup, can also in app::loadEEpconfig or somewhere else in app.cpp
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -56,6 +58,8 @@ void app::loop(void) {
if(millis() - mPrevMillis >= 1000) { if(millis() - mPrevMillis >= 1000) {
mPrevMillis += 1000; mPrevMillis += 1000;
mUptimeSecs++; mUptimeSecs++;
if(0 != mUtcTimestamp)
mUtcTimestamp++;
if(0 != mTimestamp) if(0 != mTimestamp)
mTimestamp++; mTimestamp++;
} }
@ -67,7 +71,8 @@ void app::loop(void) {
if(mUpdateNtp) { if(mUpdateNtp) {
mUpdateNtp = false; mUpdateNtp = false;
mTimestamp = mWifi->getNtpTime(); mUtcTimestamp = mWifi->getNtpTime();
mTimestamp = mUtcTimestamp + ((TIMEZONE + offsetDayLightSaving(mUtcTimestamp)) * 3600);
DPRINTLN(DBG_INFO, "[NTP]: " + getDateTimeStr(mTimestamp)); DPRINTLN(DBG_INFO, "[NTP]: " + getDateTimeStr(mTimestamp));
} }
@ -149,6 +154,12 @@ void app::loop(void) {
mMqtt.loop(); mMqtt.loop();
if(checkTicker(&mTicker, 1000)) { if(checkTicker(&mTicker, 1000)) {
if(mTimestamp > 946684800 && mSun.LocalizationIsSet() && mTimestamp / 86400 > mLatestSunTimestamp / 86400) // update on reboot or new day
{
CalculateSunriseSunset(mTimestamp, &mSunrise, &mSunset);
mLatestSunTimestamp = mTimestamp;
}
if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) { if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) {
mMqttTicker = 0; mMqttTicker = 0;
mMqtt.isConnected(true); // really needed? See comment from HorstG-57 #176 mMqtt.isConnected(true); // really needed? See comment from HorstG-57 #176
@ -195,7 +206,8 @@ void app::loop(void) {
if(++mSendTicker >= mConfig.sendInterval) { if(++mSendTicker >= mConfig.sendInterval) {
mSendTicker = 0; mSendTicker = 0;
if(0 != mTimestamp) { bool DisableNightCommunication = false; // ToDo: Add option in setup to disable inverter communication at night
if(mUtcTimestamp > 946684800 && (!DisableNightCommunication || !mLatestSunTimestamp || (mTimestamp >= mSunrise && mTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
if(mConfig.serialDebug) if(mConfig.serialDebug)
DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX)); DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
@ -257,7 +269,7 @@ void app::loop(void) {
} }
} }
else if(mConfig.serialDebug) else if(mConfig.serialDebug)
DPRINTLN(DBG_WARN, F("time not set, can't request inverter!")); DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!"));
yield(); yield();
} }
} }
@ -379,7 +391,7 @@ void app::processPayload(bool retransmit) {
if(NULL == rec) if(NULL == rec)
DPRINTLN(DBG_ERROR, F("record is NULL!")); DPRINTLN(DBG_ERROR, F("record is NULL!"));
else { else {
rec->ts = mPayload[iv->id].ts; rec->ts = mPayload[iv->id].ts + ((TIMEZONE + offsetDayLightSaving(mUtcTimestamp)) * 3600);
for(uint8_t i = 0; i < rec->length; i++) { for(uint8_t i = 0; i < rec->length; i++) {
iv->addValue(i, payload, rec); iv->addValue(i, payload, rec);
yield(); yield();
@ -679,8 +691,10 @@ void app::resetSystem(void) {
mNtpRefreshInterval = NTP_REFRESH_INTERVAL; // [ms] mNtpRefreshInterval = NTP_REFRESH_INTERVAL; // [ms]
#ifdef AP_ONLY #ifdef AP_ONLY
mUtcTimestamp = 1;
mTimestamp = 1; mTimestamp = 1;
#else #else
mUtcTimestamp = 0;
mTimestamp = 0; mTimestamp = 0;
#endif #endif
@ -857,5 +871,35 @@ void app::resetPayload(Inverter<>* iv) {
mPayload[iv->id].maxPackId = 0; mPayload[iv->id].maxPackId = 0;
mPayload[iv->id].complete = false; mPayload[iv->id].complete = false;
mPayload[iv->id].requested = false; mPayload[iv->id].requested = false;
mPayload[iv->id].ts = mTimestamp; mPayload[iv->id].ts = mUtcTimestamp;
}
//-----------------------------------------------------------------------------
// calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
// from: https://forum.arduino.cc/index.php?topic=172044.msg1278536#msg1278536
uint8_t app::offsetDayLightSaving (uint32_t local_t) {
//DPRINTLN(DBG_VERBOSE, F("wifi::offsetDayLightSaving"));
int m = month (local_t);
if(m < 3 || m > 10) return 0; // no DSL in Jan, Feb, Nov, Dez
if(m > 3 && m < 10) return 1; // DSL in Apr, May, Jun, Jul, Aug, Sep
int y = year (local_t);
int h = hour (local_t);
int hToday = (h + 24 * day(local_t));
if((m == 3 && hToday >= (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 4) % 7)))
|| (m == 10 && hToday < (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 1) % 7))) )
return 1;
else
return 0;
}
bool app::CalculateSunriseSunset(uint32_t localTimestamp, uint32_t *localSunrise, uint32_t *localSunset) { // true = day; false = night
uint32_t UTC_Timestamp_Sunrise, UTC_Timestamp_Sunset;
mSun.getRiseSet(localTimestamp, UTC_Timestamp_Sunrise, UTC_Timestamp_Sunset); // local timestamp is only used to calculate today's calendar day
*localSunrise = UTC_Timestamp_Sunrise + ((TIMEZONE + offsetDayLightSaving(UTC_Timestamp_Sunrise)) * 3600); // sunrise in local time, OPTIONAL: Add an offset of +-seconds to the end of the line
*localSunset = UTC_Timestamp_Sunset + ((TIMEZONE + offsetDayLightSaving(UTC_Timestamp_Sunset)) * 3600); // sunset in local time, OPTIONAL: Add an offset of +-seconds to the end of the line
if(localTimestamp >= *localSunrise && localTimestamp <= *localSunset)
return true; // it is day
else
return false; // it is night
} }

27
tools/esp8266/app.h

@ -23,6 +23,9 @@
#include "mqtt.h" #include "mqtt.h"
#include "ahoywifi.h" #include "ahoywifi.h"
#include "web.h" #include "web.h"
#include "sun.h"
#define TIMEZONE 1 // Central European time +1
// hier läst sich das Verhalten der app in Bezug auf MQTT // hier läst sich das Verhalten der app in Bezug auf MQTT
// durch PER-Conpiler defines anpassen // durch PER-Conpiler defines anpassen
@ -117,7 +120,20 @@ class app {
if(0 == newTime) if(0 == newTime)
mUpdateNtp = true; mUpdateNtp = true;
else else
mTimestamp = newTime; {
mUtcTimestamp = newTime;
mTimestamp = mUtcTimestamp + ((TIMEZONE + offsetDayLightSaving(mUtcTimestamp)) * 3600);
}
}
inline uint32_t getSunrise(void) {
return mSunrise;
}
inline uint32_t getSunset(void) {
return mSunset;
}
inline uint32_t getLatestSunTimestamp(void) {
return mLatestSunTimestamp;
} }
void eraseSettings(bool all = false) { void eraseSettings(bool all = false) {
@ -234,6 +250,8 @@ class app {
DPRINTLN(DBG_VERBOSE, F(" - frag: ") + String(frag)); DPRINTLN(DBG_VERBOSE, F(" - frag: ") + String(frag));
} }
uint8_t offsetDayLightSaving(uint32_t local_t);
bool CalculateSunriseSunset(uint32_t localTimestamp, uint32_t *localSunrise, uint32_t *localSunset);
uint32_t mUptimeSecs; uint32_t mUptimeSecs;
uint32_t mPrevMillis; uint32_t mPrevMillis;
@ -246,6 +264,7 @@ class app {
bool mSettingsValid; bool mSettingsValid;
eep *mEep; eep *mEep;
uint32_t mUtcTimestamp;
uint32_t mTimestamp; uint32_t mTimestamp;
bool mUpdateNtp; bool mUpdateNtp;
@ -277,6 +296,12 @@ class app {
// serial // serial
uint16_t mSerialTicker; uint16_t mSerialTicker;
// sun
sun mSun;
uint32_t mSunrise;
uint32_t mSunset;
uint32_t mLatestSunTimestamp;
}; };
#endif /*__APP_H__*/ #endif /*__APP_H__*/

6
tools/esp8266/html/index.html

@ -17,6 +17,8 @@
</p> </p>
<p><span class="des">Uptime: </span><span id="uptime"></span></p> <p><span class="des">Uptime: </span><span id="uptime"></span></p>
<p><span class="des">ESP-Time: </span><span id="date"></span></p> <p><span class="des">ESP-Time: </span><span id="date"></span></p>
<p><span class="des">Sunrise: </span><span id="sunrise"></span></p>
<p><span class="des">Sunset: </span><span id="sunset"></span></p>
<p><span class="des">RSSI: </span><span id="wifi_rssi"></span>dBm</p> <p><span class="des">RSSI: </span><span id="wifi_rssi"></span>dBm</p>
<p> <p>
<span class="des">Statistics: </span> <span class="des">Statistics: </span>
@ -57,11 +59,15 @@
var hrs = parseInt(up / 3600) % 24; var hrs = parseInt(up / 3600) % 24;
var min = parseInt(up / 60) % 60; var min = parseInt(up / 60) % 60;
var sec = up % 60; var sec = up % 60;
var sunrise = new Date(obj["ts_sunrise"] * 1000);
var sunset = new Date(obj["ts_sunset"] * 1000);
document.getElementById("uptime").innerHTML = days + " Days, " document.getElementById("uptime").innerHTML = days + " Days, "
+ ("0"+hrs).substr(-2) + ":" + ("0"+hrs).substr(-2) + ":"
+ ("0"+min).substr(-2) + ":" + ("0"+min).substr(-2) + ":"
+ ("0"+sec).substr(-2); + ("0"+sec).substr(-2);
document.getElementById("date").innerHTML = date.toLocaleString('de-DE', {timeZone: 'UTC'}); document.getElementById("date").innerHTML = date.toLocaleString('de-DE', {timeZone: 'UTC'});
document.getElementById("sunrise").innerHTML = sunrise.toLocaleString('de-DE', {timeZone: 'UTC'});
document.getElementById("sunset").innerHTML = sunset.toLocaleString('de-DE', {timeZone: 'UTC'});
} }
function parseStat(obj) { function parseStat(obj) {

99
tools/esp8266/sun.cpp

@ -0,0 +1,99 @@
/*
sun.cpp - Library for calculating sunrise and sunset times based on current local time and position on Earth.
Calculations are based on Sunrise equation: https://en.wikipedia.org/wiki/Sunrise_equation
Input and output times are in Unix Timestamp format (seconds since Jan 1, 1970, 00:00:00).
Copyright (C) 2017 Nejc Planinsek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sun.h"
const float pi = 3.14159265;
/*
* Constructor. Latitude and longitude must be provided.
*/
void sun::setLocalization(float lat, float lon) {
_lat = lat;
_lon = lon;
}
bool sun::LocalizationIsSet() {
if (_lat && _lon)
return true;
else
return false;
}
/*
* Calculates sunrise and sunset times based on current time. All times are in Unix Timestamp format.
*/
void sun::getRiseSet(uint32_t unixTime, uint32_t &sunrise, uint32_t &sunset) {
// Convert Julian day to Unix Timestamp
uint32_t Jdate = unixTime / 86400 + 2440588;
// Number of days since Jan 1st, 2000 12:00
float n = Jdate - 2451545.0 + 0.0008;
// Mean solar noon
float Jstar = -_lon / 360 + n;
// Solar mean anomaly
float M = fmod((357.5291 + 0.98560028 * Jstar), 360);
// Equation of the center
float C = 1.9148 * sin(M / 360 * 2 * pi) + 0.02 * sin(2 * M / 360 * 2 * pi) + 0.0003 * sin(3 * M * 360 * 2 * pi);
// Ecliptic longitude
float lambda = fmod((M + C + 180 + 102.9372), 360);
// Solar transit
float Jtransit = Jstar + (0.0053 * sin(M / 360.0 * 2.0 * pi) - 0.0069 * sin(2.0 * (lambda / 360.0 * 2.0 * pi)));
// Declination of the sun
float delta = asin(sin(lambda / 360 * 2 * pi) * sin(23.44 / 360 * 2 * pi)) / (2 * pi) * 360;
// Hour angle
float omega0 = 360 / (2 * pi) * acos((sin(-0.83 / 360 * 2 * pi) - sin(_lat / 360 * 2 * pi) * sin(delta / 360 * 2 * pi)) / (cos(_lat / 360 * 2 * pi) * cos(delta / 360 * 2 * pi)));
// Julian day sunrise, sunset
float Jset = Jtransit + omega0 / 360;
float Jrise = Jtransit - omega0 / 360;
// Convert to Unix Timestamp
uint32_t unixRise = Jrise * 86400.0 + 946728000; // Convert days (incl. fraction) to seconds + offset 1/1/2000 12:00
uint32_t unixSet = Jset * 86400.0 + 946728000; // Convert days (incl. fraction) to seconds + offset 1/1/2000 12:00
sunrise = unixRise;
sunset = unixSet;
}
uint32_t sun::getRise(uint32_t unixTime) {
uint32_t rise;
uint32_t set;
getRiseSet(unixTime, rise, set);
return rise;
}
uint32_t sun::getSet(uint32_t unixTime) {
uint32_t rise;
uint32_t set;
getRiseSet(unixTime, rise, set);
return set;
}
uint32_t sun::getDayLength(uint32_t unixTime) {
uint32_t rise;
uint32_t set;
getRiseSet(unixTime, rise, set);
return set - rise;
}
uint32_t sun::getNightLength(uint32_t unixTime) {
uint32_t rise;
uint32_t set;
getRiseSet(unixTime, rise, set);
return 86400 - (set - rise);
}

42
tools/esp8266/sun.h

@ -0,0 +1,42 @@
/*
sun.h - Library for calculating sunrise and sunset times based on current local time and position on Earth.
Calculations are based on Sunrise equation: https://en.wikipedia.org/wiki/Sunrise_equation
Input and output times are in Unix Timestamp format (seconds since Jan 1, 1970, 00:00:00).
Copyright (C) 2017 Nejc Planinsek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SUN_H__
#define __SUN_H__
#include "Arduino.h"
class sun
{
public:
void setLocalization(float lat, float lon);
bool LocalizationIsSet();
void getRiseSet(uint32_t unixTime, uint32_t &sunrise, uint32_t &sunset);
uint32_t getRise(uint32_t unixTime);
uint32_t getSet(uint32_t unixTime);
uint32_t getDayLength(uint32_t unixTime);
uint32_t getNightLength(uint32_t unixTime);
private:
float _lat = 0.0;
float _lon = 0.0;
};
#endif /*__SUN_H__*/

3
tools/esp8266/webApi.cpp

@ -125,6 +125,9 @@ void webApi::getSystem(JsonObject obj) {
obj[F("build")] = String(AUTO_GIT_HASH); obj[F("build")] = String(AUTO_GIT_HASH);
obj[F("ts_uptime")] = mApp->getUptime(); obj[F("ts_uptime")] = mApp->getUptime();
obj[F("ts_now")] = mApp->getTimestamp(); obj[F("ts_now")] = mApp->getTimestamp();
obj[F("ts_sunrise")] = mApp->getSunrise();
obj[F("ts_sunset")] = mApp->getSunset();
obj[F("ts_sun_upd")] = mApp->getLatestSunTimestamp();
obj[F("wifi_rssi")] = WiFi.RSSI(); obj[F("wifi_rssi")] = WiFi.RSSI();
} }

Loading…
Cancel
Save