mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
Move ESPTime into core esphome namespace (#4926)
* Prep-work for datetime entities * Fix some includes and remove some restrictions on printing time on displays * format * format * More formatting * Move function contents * Ignore clang-tidy
This commit is contained in:
parent
ce13979690
commit
302dea4169
31 changed files with 376 additions and 403 deletions
|
@ -442,7 +442,7 @@ uint8_t BedJetHub::write_notify_config_descriptor_(bool enable) {
|
|||
void BedJetHub::send_local_time() {
|
||||
if (this->time_id_.has_value()) {
|
||||
auto *time_id = *this->time_id_;
|
||||
time::ESPTime now = time_id->now();
|
||||
ESPTime now = time_id->now();
|
||||
if (now.is_valid()) {
|
||||
this->set_clock(now.hour, now.minute);
|
||||
ESP_LOGD(TAG, "Using time component to set BedJet clock: %d:%02d", now.hour, now.minute);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#include "esphome/core/time.h"
|
||||
#endif
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_sleep.h>
|
||||
|
@ -11,6 +11,7 @@
|
|||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#include "esphome/core/time.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
|
@ -170,7 +171,7 @@ template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
|
|||
if (after_time)
|
||||
timestamp += 60 * 60 * 24;
|
||||
|
||||
int32_t offset = time::ESPTime::timezone_offset();
|
||||
int32_t offset = ESPTime::timezone_offset();
|
||||
timestamp -= offset; // Change timestamp to utc
|
||||
const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
|
||||
this->deep_sleep_->set_sleep_duration(ms_left);
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include <utility>
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/color.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace display {
|
||||
|
@ -490,24 +490,21 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) {
|
|||
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||
this->trigger(from, to);
|
||||
}
|
||||
#ifdef USE_TIME
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format,
|
||||
time::ESPTime time) {
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) {
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) {
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, align, format, time);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, time::ESPTime time) {
|
||||
void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DisplayBuffer::start_clipping(Rect rect) {
|
||||
if (!this->clipping_rectangle_.empty()) {
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "display_color_utils.h"
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
#include "display_color_utils.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
#include "esphome/components/graph/graph.h"
|
||||
|
@ -263,7 +260,6 @@ class DisplayBuffer {
|
|||
*/
|
||||
void printf(int x, int y, Font *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
|
||||
|
||||
#ifdef USE_TIME
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
|
@ -274,7 +270,7 @@ class DisplayBuffer {
|
|||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time)
|
||||
void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 7, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
|
@ -286,7 +282,7 @@ class DisplayBuffer {
|
|||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time)
|
||||
void strftime(int x, int y, Font *font, Color color, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
|
@ -298,7 +294,7 @@ class DisplayBuffer {
|
|||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time)
|
||||
void strftime(int x, int y, Font *font, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
|
@ -309,9 +305,7 @@ class DisplayBuffer {
|
|||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, Font *font, const char *format, time::ESPTime time)
|
||||
__attribute__((format(strftime, 5, 0)));
|
||||
#endif
|
||||
void strftime(int x, int y, Font *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
|
||||
|
||||
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
|
|
|
@ -37,7 +37,7 @@ void DS1307Component::read_time() {
|
|||
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
time::ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10),
|
||||
ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10),
|
||||
.minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10),
|
||||
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
|
||||
.day_of_week = uint8_t(ds1307_.reg.weekday),
|
||||
|
|
|
@ -16,7 +16,7 @@ void GPSTime::from_tiny_gps_(TinyGPSPlus &tiny_gps) {
|
|||
if (tiny_gps.date.year() < 2019)
|
||||
return;
|
||||
|
||||
time::ESPTime val{};
|
||||
ESPTime val{};
|
||||
val.year = tiny_gps.date.year();
|
||||
val.month = tiny_gps.date.month();
|
||||
val.day_of_month = tiny_gps.date.day();
|
||||
|
|
|
@ -158,15 +158,13 @@ void LCDDisplay::clear() {
|
|||
for (uint8_t i = 0; i < this->rows_ * this->columns_; i++)
|
||||
this->buffer_[i] = ' ';
|
||||
}
|
||||
#ifdef USE_TIME
|
||||
void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, time::ESPTime time) {
|
||||
void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
this->print(column, row, buffer);
|
||||
}
|
||||
void LCDDisplay::strftime(const char *format, time::ESPTime time) { this->strftime(0, 0, format, time); }
|
||||
#endif
|
||||
void LCDDisplay::strftime(const char *format, ESPTime time) { this->strftime(0, 0, format, time); }
|
||||
void LCDDisplay::loadchar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
this->command_(LCD_DISPLAY_COMMAND_SET_CGRAM_ADDR | (location << 3));
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
@ -44,13 +40,10 @@ class LCDDisplay : public PollingComponent {
|
|||
/// Evaluate the printf-format and print the text at column=0 and row=0.
|
||||
void printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
#ifdef USE_TIME
|
||||
/// Evaluate the strftime-format and print the text at the specified column and row.
|
||||
void strftime(uint8_t column, uint8_t row, const char *format, time::ESPTime time)
|
||||
__attribute__((format(strftime, 4, 0)));
|
||||
void strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) __attribute__((format(strftime, 4, 0)));
|
||||
/// Evaluate the strftime-format and print the text at column=0 and row=0.
|
||||
void strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
#endif
|
||||
void strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
|
||||
/// Load custom char to given location
|
||||
void loadchar(uint8_t location, uint8_t charmap[]);
|
||||
|
|
|
@ -223,16 +223,14 @@ void MAX7219Component::set_intensity(uint8_t intensity) {
|
|||
}
|
||||
void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; }
|
||||
|
||||
#ifdef USE_TIME
|
||||
uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
||||
uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
return this->print(pos, buffer);
|
||||
return 0;
|
||||
}
|
||||
uint8_t MAX7219Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
||||
#endif
|
||||
uint8_t MAX7219Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||
|
||||
} // namespace max7219
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
|
@ -46,13 +42,11 @@ class MAX7219Component : public PollingComponent,
|
|||
/// Print `str` at position 0.
|
||||
uint8_t print(const char *str);
|
||||
|
||||
#ifdef USE_TIME
|
||||
/// Evaluate the strftime-format and print the result at the given position.
|
||||
uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
|
||||
/// Evaluate the strftime-format and print the result at position 0.
|
||||
uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
#endif
|
||||
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
|
||||
protected:
|
||||
void send_byte_(uint8_t a_register, uint8_t data);
|
||||
|
|
|
@ -325,18 +325,16 @@ uint8_t MAX7219Component::printdigitf(const char *format, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TIME
|
||||
uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, time::ESPTime time) {
|
||||
uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
return this->printdigit(pos, buffer);
|
||||
return 0;
|
||||
}
|
||||
uint8_t MAX7219Component::strftimedigit(const char *format, time::ESPTime time) {
|
||||
uint8_t MAX7219Component::strftimedigit(const char *format, ESPTime time) {
|
||||
return this->strftimedigit(0, format, time);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace max7219digit
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace max7219digit {
|
||||
|
||||
|
@ -88,13 +85,11 @@ class MAX7219Component : public PollingComponent,
|
|||
/// Print `str` at position 0.
|
||||
uint8_t printdigit(const char *str);
|
||||
|
||||
#ifdef USE_TIME
|
||||
/// Evaluate the strftime-format and print the result at the given position.
|
||||
uint8_t strftimedigit(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
uint8_t strftimedigit(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
|
||||
/// Evaluate the strftime-format and print the result at position 0.
|
||||
uint8_t strftimedigit(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
#endif
|
||||
uint8_t strftimedigit(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
|
||||
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#include "nextion_base.h"
|
||||
#include "nextion_component.h"
|
||||
|
@ -19,10 +21,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace nextion {
|
||||
|
||||
|
@ -318,13 +316,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
|||
* Changes the font of the component named `textveiw`. Font IDs are set in the Nextion Editor.
|
||||
*/
|
||||
void set_component_font(const char *component, uint8_t font_id) override;
|
||||
#ifdef USE_TIME
|
||||
/**
|
||||
* Send the current time to the nextion display.
|
||||
* @param time The time instance to send (get this with id(my_time).now() ).
|
||||
*/
|
||||
void set_nextion_rtc_time(time::ESPTime time);
|
||||
#endif
|
||||
void set_nextion_rtc_time(ESPTime time);
|
||||
|
||||
/**
|
||||
* Show the page with a given name.
|
||||
|
|
|
@ -219,8 +219,7 @@ void Nextion::filled_circle(int center_x, int center_y, int radius, Color color)
|
|||
display::ColorUtil::color_to_565(color));
|
||||
}
|
||||
|
||||
#ifdef USE_TIME
|
||||
void Nextion::set_nextion_rtc_time(time::ESPTime time) {
|
||||
void Nextion::set_nextion_rtc_time(ESPTime time) {
|
||||
this->add_no_result_to_queue_with_printf_("rtc0", "rtc0=%u", time.year);
|
||||
this->add_no_result_to_queue_with_printf_("rtc1", "rtc1=%u", time.month);
|
||||
this->add_no_result_to_queue_with_printf_("rtc2", "rtc2=%u", time.day_of_month);
|
||||
|
@ -228,7 +227,6 @@ void Nextion::set_nextion_rtc_time(time::ESPTime time) {
|
|||
this->add_no_result_to_queue_with_printf_("rtc4", "rtc4=%u", time.minute);
|
||||
this->add_no_result_to_queue_with_printf_("rtc5", "rtc5=%u", time.second);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace nextion
|
||||
} // namespace esphome
|
||||
|
|
|
@ -37,7 +37,7 @@ void PCF85063Component::read_time() {
|
|||
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||
return;
|
||||
}
|
||||
time::ESPTime rtc_time{
|
||||
ESPTime rtc_time{
|
||||
.second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10),
|
||||
.minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10),
|
||||
.hour = uint8_t(pcf85063_.reg.hour + 10u * pcf85063_.reg.hour_10),
|
||||
|
|
|
@ -37,7 +37,7 @@ num_t EquatorialCoordinate::declination_rad() const { return radians(declination
|
|||
num_t HorizontalCoordinate::elevation_rad() const { return radians(elevation); }
|
||||
num_t HorizontalCoordinate::azimuth_rad() const { return radians(azimuth); }
|
||||
|
||||
num_t julian_day(time::ESPTime moment) {
|
||||
num_t julian_day(ESPTime moment) {
|
||||
// p. 59
|
||||
// UT -> JD, TT -> JDE
|
||||
int y = moment.year;
|
||||
|
@ -54,7 +54,7 @@ num_t julian_day(time::ESPTime moment) {
|
|||
int b = 2 - a + a / 4;
|
||||
return ((int) (365.25 * (y + 4716))) + ((int) (30.6001 * (m + 1))) + d + b - 1524.5;
|
||||
}
|
||||
num_t delta_t(time::ESPTime moment) {
|
||||
num_t delta_t(ESPTime moment) {
|
||||
// approximation for 2005-2050 from NASA (https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html)
|
||||
int t = moment.year - 2000;
|
||||
return 62.92 + t * (0.32217 + t * 0.005589);
|
||||
|
@ -199,7 +199,7 @@ struct SunAtLocation {
|
|||
// see chapter 12, p. 87
|
||||
num_t jd = moment.jd();
|
||||
// eq 12.1, p.87; jd for 0h UT of this date
|
||||
time::ESPTime moment_0h = moment.dt;
|
||||
ESPTime moment_0h = moment.dt;
|
||||
moment_0h.hour = moment_0h.minute = moment_0h.second = 0;
|
||||
num_t jd0 = Moment{moment_0h}.jd();
|
||||
num_t t = (jd0 - 2451545) / 36525;
|
||||
|
@ -227,9 +227,9 @@ struct SunAtLocation {
|
|||
return HorizontalCoordinate{degrees(elevation_rad), degrees(azimuth_rad) + 180};
|
||||
}
|
||||
|
||||
optional<time::ESPTime> sunrise(time::ESPTime date, num_t zenith) const { return event(true, date, zenith); }
|
||||
optional<time::ESPTime> sunset(time::ESPTime date, num_t zenith) const { return event(false, date, zenith); }
|
||||
optional<time::ESPTime> event(bool rise, time::ESPTime date, num_t zenith) const {
|
||||
optional<ESPTime> sunrise(ESPTime date, num_t zenith) const { return event(true, date, zenith); }
|
||||
optional<ESPTime> sunset(ESPTime date, num_t zenith) const { return event(false, date, zenith); }
|
||||
optional<ESPTime> event(bool rise, ESPTime date, num_t zenith) const {
|
||||
// couldn't get the method described in chapter 15 to work,
|
||||
// so instead this is based on the algorithm in time4j
|
||||
// https://github.com/MenoData/Time4J/blob/master/base/src/main/java/net/time4j/calendar/astro/StdSolarCalculator.java
|
||||
|
@ -244,7 +244,7 @@ struct SunAtLocation {
|
|||
new_h = *x;
|
||||
} while (std::abs(new_h - old_h) >= 15);
|
||||
time_t new_timestamp = m.timestamp + (time_t) new_h;
|
||||
return time::ESPTime::from_epoch_local(new_timestamp);
|
||||
return ESPTime::from_epoch_local(new_timestamp);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -263,14 +263,14 @@ struct SunAtLocation {
|
|||
return hour_angle;
|
||||
}
|
||||
|
||||
time::ESPTime local_event_(time::ESPTime date, int hour) const {
|
||||
ESPTime local_event_(ESPTime date, int hour) const {
|
||||
// input date should be in UTC, and hour/minute/second fields 0
|
||||
num_t added_d = hour / 24.0 - location.longitude / 360;
|
||||
num_t jd = julian_day(date) + added_d;
|
||||
|
||||
num_t eot = SunAtTime(jd).equation_of_time() * 240;
|
||||
time_t new_timestamp = (time_t) (date.timestamp + added_d * 86400 - eot);
|
||||
return time::ESPTime::from_epoch_utc(new_timestamp);
|
||||
return ESPTime::from_epoch_utc(new_timestamp);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -287,7 +287,7 @@ HorizontalCoordinate Sun::calc_coords_() {
|
|||
*/
|
||||
return sun.true_coordinate(m);
|
||||
}
|
||||
optional<time::ESPTime> Sun::calc_event_(time::ESPTime date, bool rising, double zenith) {
|
||||
optional<ESPTime> Sun::calc_event_(ESPTime date, bool rising, double zenith) {
|
||||
SunAtLocation sun{location_};
|
||||
if (!date.is_valid())
|
||||
return {};
|
||||
|
@ -301,24 +301,20 @@ optional<time::ESPTime> Sun::calc_event_(time::ESPTime date, bool rising, double
|
|||
// We're calculating *next* sunrise/sunset, but calculated event
|
||||
// is today, so try again tomorrow
|
||||
time_t new_timestamp = today.timestamp + 24 * 60 * 60;
|
||||
today = time::ESPTime::from_epoch_utc(new_timestamp);
|
||||
today = ESPTime::from_epoch_utc(new_timestamp);
|
||||
it = sun.event(rising, today, zenith);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
optional<time::ESPTime> Sun::calc_event_(bool rising, double zenith) {
|
||||
optional<ESPTime> Sun::calc_event_(bool rising, double zenith) {
|
||||
auto it = Sun::calc_event_(this->time_->utcnow(), rising, zenith);
|
||||
return it;
|
||||
}
|
||||
|
||||
optional<time::ESPTime> Sun::sunrise(double elevation) { return this->calc_event_(true, 90 - elevation); }
|
||||
optional<time::ESPTime> Sun::sunset(double elevation) { return this->calc_event_(false, 90 - elevation); }
|
||||
optional<time::ESPTime> Sun::sunrise(time::ESPTime date, double elevation) {
|
||||
return this->calc_event_(date, true, 90 - elevation);
|
||||
}
|
||||
optional<time::ESPTime> Sun::sunset(time::ESPTime date, double elevation) {
|
||||
return this->calc_event_(date, false, 90 - elevation);
|
||||
}
|
||||
optional<ESPTime> Sun::sunrise(double elevation) { return this->calc_event_(true, 90 - elevation); }
|
||||
optional<ESPTime> Sun::sunset(double elevation) { return this->calc_event_(false, 90 - elevation); }
|
||||
optional<ESPTime> Sun::sunrise(ESPTime date, double elevation) { return this->calc_event_(date, true, 90 - elevation); }
|
||||
optional<ESPTime> Sun::sunset(ESPTime date, double elevation) { return this->calc_event_(date, false, 90 - elevation); }
|
||||
double Sun::elevation() { return this->calc_coords_().elevation; }
|
||||
double Sun::azimuth() { return this->calc_coords_().azimuth; }
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
|
||||
namespace esphome {
|
||||
|
@ -26,7 +28,7 @@ struct GeoLocation {
|
|||
};
|
||||
|
||||
struct Moment {
|
||||
time::ESPTime dt;
|
||||
ESPTime dt;
|
||||
|
||||
num_t jd() const;
|
||||
num_t jde() const;
|
||||
|
@ -57,18 +59,18 @@ class Sun {
|
|||
void set_latitude(double latitude) { location_.latitude = latitude; }
|
||||
void set_longitude(double longitude) { location_.longitude = longitude; }
|
||||
|
||||
optional<time::ESPTime> sunrise(double elevation);
|
||||
optional<time::ESPTime> sunset(double elevation);
|
||||
optional<time::ESPTime> sunrise(time::ESPTime date, double elevation);
|
||||
optional<time::ESPTime> sunset(time::ESPTime date, double elevation);
|
||||
optional<ESPTime> sunrise(double elevation);
|
||||
optional<ESPTime> sunset(double elevation);
|
||||
optional<ESPTime> sunrise(ESPTime date, double elevation);
|
||||
optional<ESPTime> sunset(ESPTime date, double elevation);
|
||||
|
||||
double elevation();
|
||||
double azimuth();
|
||||
|
||||
protected:
|
||||
internal::HorizontalCoordinate calc_coords_();
|
||||
optional<time::ESPTime> calc_event_(bool rising, double zenith);
|
||||
optional<time::ESPTime> calc_event_(time::ESPTime date, bool rising, double zenith);
|
||||
optional<ESPTime> calc_event_(bool rising, double zenith);
|
||||
optional<ESPTime> calc_event_(ESPTime date, bool rising, double zenith);
|
||||
|
||||
time::RealTimeClock *time_;
|
||||
internal::GeoLocation location_;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "esphome/components/sun/sun.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
|
@ -15,7 +17,7 @@ class SunTextSensor : public text_sensor::TextSensor, public PollingComponent {
|
|||
void set_format(const std::string &format) { format_ = format; }
|
||||
|
||||
void update() override {
|
||||
optional<time::ESPTime> res;
|
||||
optional<ESPTime> res;
|
||||
if (this->sunrise_) {
|
||||
res = this->parent_->sunrise(this->elevation_);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "automation.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include "real_time_clock.h"
|
||||
|
||||
#include <vector>
|
||||
|
|
|
@ -52,171 +52,5 @@ void RealTimeClock::apply_timezone_() {
|
|||
tzset();
|
||||
}
|
||||
|
||||
size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) {
|
||||
struct tm c_tm = this->to_c_tm();
|
||||
return ::strftime(buffer, buffer_len, format, &c_tm);
|
||||
}
|
||||
ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) {
|
||||
ESPTime res{};
|
||||
res.second = uint8_t(c_tm->tm_sec);
|
||||
res.minute = uint8_t(c_tm->tm_min);
|
||||
res.hour = uint8_t(c_tm->tm_hour);
|
||||
res.day_of_week = uint8_t(c_tm->tm_wday + 1);
|
||||
res.day_of_month = uint8_t(c_tm->tm_mday);
|
||||
res.day_of_year = uint16_t(c_tm->tm_yday + 1);
|
||||
res.month = uint8_t(c_tm->tm_mon + 1);
|
||||
res.year = uint16_t(c_tm->tm_year + 1900);
|
||||
res.is_dst = bool(c_tm->tm_isdst);
|
||||
res.timestamp = c_time;
|
||||
return res;
|
||||
}
|
||||
struct tm ESPTime::to_c_tm() {
|
||||
struct tm c_tm {};
|
||||
c_tm.tm_sec = this->second;
|
||||
c_tm.tm_min = this->minute;
|
||||
c_tm.tm_hour = this->hour;
|
||||
c_tm.tm_mday = this->day_of_month;
|
||||
c_tm.tm_mon = this->month - 1;
|
||||
c_tm.tm_year = this->year - 1900;
|
||||
c_tm.tm_wday = this->day_of_week - 1;
|
||||
c_tm.tm_yday = this->day_of_year - 1;
|
||||
c_tm.tm_isdst = this->is_dst;
|
||||
return c_tm;
|
||||
}
|
||||
std::string ESPTime::strftime(const std::string &format) {
|
||||
std::string timestr;
|
||||
timestr.resize(format.size() * 4);
|
||||
struct tm c_tm = this->to_c_tm();
|
||||
size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm);
|
||||
while (len == 0) {
|
||||
timestr.resize(timestr.size() * 2);
|
||||
len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm);
|
||||
}
|
||||
timestr.resize(len);
|
||||
return timestr;
|
||||
}
|
||||
|
||||
template<typename T> bool increment_time_value(T ¤t, uint16_t begin, uint16_t end) {
|
||||
current++;
|
||||
if (current >= end) {
|
||||
current = begin;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); }
|
||||
|
||||
static uint8_t days_in_month(uint8_t month, uint16_t year) {
|
||||
static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
uint8_t days = DAYS_IN_MONTH[month];
|
||||
if (month == 2 && is_leap_year(year))
|
||||
return 29;
|
||||
return days;
|
||||
}
|
||||
|
||||
void ESPTime::increment_second() {
|
||||
this->timestamp++;
|
||||
if (!increment_time_value(this->second, 0, 60))
|
||||
return;
|
||||
|
||||
// second roll-over, increment minute
|
||||
if (!increment_time_value(this->minute, 0, 60))
|
||||
return;
|
||||
|
||||
// minute roll-over, increment hour
|
||||
if (!increment_time_value(this->hour, 0, 24))
|
||||
return;
|
||||
|
||||
// hour roll-over, increment day
|
||||
increment_time_value(this->day_of_week, 1, 8);
|
||||
|
||||
if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) {
|
||||
// day of month roll-over, increment month
|
||||
increment_time_value(this->month, 1, 13);
|
||||
}
|
||||
|
||||
uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365;
|
||||
if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) {
|
||||
// day of year roll-over, increment year
|
||||
this->year++;
|
||||
}
|
||||
}
|
||||
void ESPTime::increment_day() {
|
||||
this->timestamp += 86400;
|
||||
|
||||
// increment day
|
||||
increment_time_value(this->day_of_week, 1, 8);
|
||||
|
||||
if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) {
|
||||
// day of month roll-over, increment month
|
||||
increment_time_value(this->month, 1, 13);
|
||||
}
|
||||
|
||||
uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365;
|
||||
if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) {
|
||||
// day of year roll-over, increment year
|
||||
this->year++;
|
||||
}
|
||||
}
|
||||
void ESPTime::recalc_timestamp_utc(bool use_day_of_year) {
|
||||
time_t res = 0;
|
||||
|
||||
if (!this->fields_in_range()) {
|
||||
this->timestamp = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 1970; i < this->year; i++)
|
||||
res += is_leap_year(i) ? 366 : 365;
|
||||
|
||||
if (use_day_of_year) {
|
||||
res += this->day_of_year - 1;
|
||||
} else {
|
||||
for (int i = 1; i < this->month; i++)
|
||||
res += days_in_month(i, this->year);
|
||||
|
||||
res += this->day_of_month - 1;
|
||||
}
|
||||
|
||||
res *= 24;
|
||||
res += this->hour;
|
||||
res *= 60;
|
||||
res += this->minute;
|
||||
res *= 60;
|
||||
res += this->second;
|
||||
this->timestamp = res;
|
||||
}
|
||||
|
||||
int32_t ESPTime::timezone_offset() {
|
||||
int32_t offset = 0;
|
||||
time_t now = ::time(nullptr);
|
||||
auto local = ESPTime::from_epoch_local(now);
|
||||
auto utc = ESPTime::from_epoch_utc(now);
|
||||
bool negative = utc.hour > local.hour && local.day_of_year <= utc.day_of_year;
|
||||
|
||||
if (utc.minute > local.minute) {
|
||||
local.minute += 60;
|
||||
local.hour -= 1;
|
||||
}
|
||||
offset += (local.minute - utc.minute) * 60;
|
||||
|
||||
if (negative) {
|
||||
offset -= (utc.hour - local.hour) * 3600;
|
||||
} else {
|
||||
if (utc.hour > local.hour) {
|
||||
local.hour += 24;
|
||||
}
|
||||
offset += (local.hour - utc.hour) * 3600;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; }
|
||||
bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; }
|
||||
bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; }
|
||||
bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; }
|
||||
bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; }
|
||||
|
||||
} // namespace time
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,106 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <cstdlib>
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <bitset>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace time {
|
||||
|
||||
/// A more user-friendly version of struct tm from time.h
|
||||
struct ESPTime {
|
||||
/** seconds after the minute [0-60]
|
||||
* @note second is generally 0-59; the extra range is to accommodate leap seconds.
|
||||
*/
|
||||
uint8_t second;
|
||||
/// minutes after the hour [0-59]
|
||||
uint8_t minute;
|
||||
/// hours since midnight [0-23]
|
||||
uint8_t hour;
|
||||
/// day of the week; sunday=1 [1-7]
|
||||
uint8_t day_of_week;
|
||||
/// day of the month [1-31]
|
||||
uint8_t day_of_month;
|
||||
/// day of the year [1-366]
|
||||
uint16_t day_of_year;
|
||||
/// month; january=1 [1-12]
|
||||
uint8_t month;
|
||||
/// year
|
||||
uint16_t year;
|
||||
/// daylight saving time flag
|
||||
bool is_dst;
|
||||
/// unix epoch time (seconds since UTC Midnight January 1, 1970)
|
||||
time_t timestamp;
|
||||
|
||||
/** Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
|
||||
* Up to buffer_len bytes are written.
|
||||
*
|
||||
* @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime
|
||||
*/
|
||||
size_t strftime(char *buffer, size_t buffer_len, const char *format);
|
||||
|
||||
/** Convert this ESPTime struct to a string as specified by the format argument.
|
||||
* @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime
|
||||
*
|
||||
* @warning This method uses dynamically allocated strings which can cause heap fragmentation with some
|
||||
* microcontrollers.
|
||||
*/
|
||||
std::string strftime(const std::string &format);
|
||||
|
||||
/// Check if this ESPTime is valid (all fields in range and year is greater than 2018)
|
||||
bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); }
|
||||
|
||||
/// Check if all time fields of this ESPTime are in range.
|
||||
bool fields_in_range() const {
|
||||
return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 &&
|
||||
this->day_of_week < 8 && this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 &&
|
||||
this->day_of_year < 367 && this->month > 0 && this->month < 13;
|
||||
}
|
||||
|
||||
/// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance.
|
||||
static ESPTime from_c_tm(struct tm *c_tm, time_t c_time);
|
||||
|
||||
/** Convert an UTC epoch timestamp to a local time ESPTime instance.
|
||||
*
|
||||
* @param epoch Seconds since 1st January 1970. In UTC.
|
||||
* @return The generated ESPTime
|
||||
*/
|
||||
static ESPTime from_epoch_local(time_t epoch) {
|
||||
struct tm *c_tm = ::localtime(&epoch);
|
||||
return ESPTime::from_c_tm(c_tm, epoch);
|
||||
}
|
||||
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
||||
*
|
||||
* @param epoch Seconds since 1st January 1970. In UTC.
|
||||
* @return The generated ESPTime
|
||||
*/
|
||||
static ESPTime from_epoch_utc(time_t epoch) {
|
||||
struct tm *c_tm = ::gmtime(&epoch);
|
||||
return ESPTime::from_c_tm(c_tm, epoch);
|
||||
}
|
||||
|
||||
/// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC).
|
||||
void recalc_timestamp_utc(bool use_day_of_year = true);
|
||||
|
||||
/// Convert this ESPTime instance back to a tm struct.
|
||||
struct tm to_c_tm();
|
||||
|
||||
static int32_t timezone_offset();
|
||||
|
||||
/// Increment this clock instance by one second.
|
||||
void increment_second();
|
||||
/// Increment this clock instance by one day.
|
||||
void increment_day();
|
||||
bool operator<(ESPTime other);
|
||||
bool operator<=(ESPTime other);
|
||||
bool operator==(ESPTime other);
|
||||
bool operator>=(ESPTime other);
|
||||
bool operator>(ESPTime other);
|
||||
};
|
||||
|
||||
/// The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock.
|
||||
///
|
||||
/// \note
|
||||
|
|
|
@ -368,16 +368,14 @@ uint8_t TM1637Display::printf(const char *format, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TIME
|
||||
uint8_t TM1637Display::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
||||
uint8_t TM1637Display::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
return this->print(pos, buffer);
|
||||
return 0;
|
||||
}
|
||||
uint8_t TM1637Display::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
||||
#endif
|
||||
uint8_t TM1637Display::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||
|
||||
} // namespace tm1637
|
||||
} // namespace esphome
|
||||
|
|
|
@ -3,13 +3,10 @@
|
|||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
|
@ -61,12 +58,10 @@ class TM1637Display : public PollingComponent {
|
|||
void add_tm1637_key(TM1637Key *tm1637_key) { this->tm1637_keys_.push_back(tm1637_key); }
|
||||
#endif
|
||||
|
||||
#ifdef USE_TIME
|
||||
/// Evaluate the strftime-format and print the result at the given position.
|
||||
uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
/// Evaluate the strftime-format and print the result at position 0.
|
||||
uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
#endif
|
||||
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
|
||||
protected:
|
||||
void bit_delay_();
|
||||
|
|
|
@ -211,16 +211,14 @@ uint8_t TM1638Component::printf(const char *format, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TIME
|
||||
uint8_t TM1638Component::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
||||
uint8_t TM1638Component::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
return this->print(pos, buffer);
|
||||
return 0;
|
||||
}
|
||||
uint8_t TM1638Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
||||
#endif
|
||||
uint8_t TM1638Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||
|
||||
//////////////// SPI ////////////////
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace tm1638 {
|
||||
|
||||
|
@ -52,12 +49,10 @@ class TM1638Component : public PollingComponent {
|
|||
void loop() override;
|
||||
uint8_t get_keys();
|
||||
|
||||
#ifdef USE_TIME
|
||||
/// Evaluate the strftime-format and print the result at the given position.
|
||||
uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||
/// Evaluate the strftime-format and print the result at position 0.
|
||||
uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
#endif
|
||||
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||
|
||||
void set_led(int led_pos, bool led_on_off);
|
||||
|
||||
|
|
|
@ -508,7 +508,7 @@ void Tuya::send_wifi_status_() {
|
|||
void Tuya::send_local_time_() {
|
||||
std::vector<uint8_t> payload;
|
||||
auto *time_id = *this->time_id_;
|
||||
time::ESPTime now = time_id->now();
|
||||
ESPTime now = time_id->now();
|
||||
if (now.is_valid()) {
|
||||
uint8_t year = now.year - 2000;
|
||||
uint8_t month = now.month;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#include "esphome/core/time.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
|
171
esphome/core/time.cpp
Normal file
171
esphome/core/time.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include "time.h" // NOLINT
|
||||
|
||||
namespace esphome {
|
||||
|
||||
size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) {
|
||||
struct tm c_tm = this->to_c_tm();
|
||||
return ::strftime(buffer, buffer_len, format, &c_tm);
|
||||
}
|
||||
ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) {
|
||||
ESPTime res{};
|
||||
res.second = uint8_t(c_tm->tm_sec);
|
||||
res.minute = uint8_t(c_tm->tm_min);
|
||||
res.hour = uint8_t(c_tm->tm_hour);
|
||||
res.day_of_week = uint8_t(c_tm->tm_wday + 1);
|
||||
res.day_of_month = uint8_t(c_tm->tm_mday);
|
||||
res.day_of_year = uint16_t(c_tm->tm_yday + 1);
|
||||
res.month = uint8_t(c_tm->tm_mon + 1);
|
||||
res.year = uint16_t(c_tm->tm_year + 1900);
|
||||
res.is_dst = bool(c_tm->tm_isdst);
|
||||
res.timestamp = c_time;
|
||||
return res;
|
||||
}
|
||||
struct tm ESPTime::to_c_tm() {
|
||||
struct tm c_tm {};
|
||||
c_tm.tm_sec = this->second;
|
||||
c_tm.tm_min = this->minute;
|
||||
c_tm.tm_hour = this->hour;
|
||||
c_tm.tm_mday = this->day_of_month;
|
||||
c_tm.tm_mon = this->month - 1;
|
||||
c_tm.tm_year = this->year - 1900;
|
||||
c_tm.tm_wday = this->day_of_week - 1;
|
||||
c_tm.tm_yday = this->day_of_year - 1;
|
||||
c_tm.tm_isdst = this->is_dst;
|
||||
return c_tm;
|
||||
}
|
||||
std::string ESPTime::strftime(const std::string &format) {
|
||||
std::string timestr;
|
||||
timestr.resize(format.size() * 4);
|
||||
struct tm c_tm = this->to_c_tm();
|
||||
size_t len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm);
|
||||
while (len == 0) {
|
||||
timestr.resize(timestr.size() * 2);
|
||||
len = ::strftime(×tr[0], timestr.size(), format.c_str(), &c_tm);
|
||||
}
|
||||
timestr.resize(len);
|
||||
return timestr;
|
||||
}
|
||||
|
||||
void ESPTime::increment_second() {
|
||||
this->timestamp++;
|
||||
if (!increment_time_value(this->second, 0, 60))
|
||||
return;
|
||||
|
||||
// second roll-over, increment minute
|
||||
if (!increment_time_value(this->minute, 0, 60))
|
||||
return;
|
||||
|
||||
// minute roll-over, increment hour
|
||||
if (!increment_time_value(this->hour, 0, 24))
|
||||
return;
|
||||
|
||||
// hour roll-over, increment day
|
||||
increment_time_value(this->day_of_week, 1, 8);
|
||||
|
||||
if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) {
|
||||
// day of month roll-over, increment month
|
||||
increment_time_value(this->month, 1, 13);
|
||||
}
|
||||
|
||||
uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365;
|
||||
if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) {
|
||||
// day of year roll-over, increment year
|
||||
this->year++;
|
||||
}
|
||||
}
|
||||
void ESPTime::increment_day() {
|
||||
this->timestamp += 86400;
|
||||
|
||||
// increment day
|
||||
increment_time_value(this->day_of_week, 1, 8);
|
||||
|
||||
if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) {
|
||||
// day of month roll-over, increment month
|
||||
increment_time_value(this->month, 1, 13);
|
||||
}
|
||||
|
||||
uint16_t days_in_year = (this->year % 4 == 0) ? 366 : 365;
|
||||
if (increment_time_value(this->day_of_year, 1, days_in_year + 1)) {
|
||||
// day of year roll-over, increment year
|
||||
this->year++;
|
||||
}
|
||||
}
|
||||
void ESPTime::recalc_timestamp_utc(bool use_day_of_year) {
|
||||
time_t res = 0;
|
||||
|
||||
if (!this->fields_in_range()) {
|
||||
this->timestamp = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 1970; i < this->year; i++)
|
||||
res += is_leap_year(i) ? 366 : 365;
|
||||
|
||||
if (use_day_of_year) {
|
||||
res += this->day_of_year - 1;
|
||||
} else {
|
||||
for (int i = 1; i < this->month; i++)
|
||||
res += days_in_month(i, this->year);
|
||||
|
||||
res += this->day_of_month - 1;
|
||||
}
|
||||
|
||||
res *= 24;
|
||||
res += this->hour;
|
||||
res *= 60;
|
||||
res += this->minute;
|
||||
res *= 60;
|
||||
res += this->second;
|
||||
this->timestamp = res;
|
||||
}
|
||||
|
||||
int32_t ESPTime::timezone_offset() {
|
||||
int32_t offset = 0;
|
||||
time_t now = ::time(nullptr);
|
||||
auto local = ESPTime::from_epoch_local(now);
|
||||
auto utc = ESPTime::from_epoch_utc(now);
|
||||
bool negative = utc.hour > local.hour && local.day_of_year <= utc.day_of_year;
|
||||
|
||||
if (utc.minute > local.minute) {
|
||||
local.minute += 60;
|
||||
local.hour -= 1;
|
||||
}
|
||||
offset += (local.minute - utc.minute) * 60;
|
||||
|
||||
if (negative) {
|
||||
offset -= (utc.hour - local.hour) * 3600;
|
||||
} else {
|
||||
if (utc.hour > local.hour) {
|
||||
local.hour += 24;
|
||||
}
|
||||
offset += (local.hour - utc.hour) * 3600;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; }
|
||||
bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; }
|
||||
bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; }
|
||||
bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; }
|
||||
bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; }
|
||||
|
||||
template<typename T> bool increment_time_value(T ¤t, uint16_t begin, uint16_t end) {
|
||||
current++;
|
||||
if (current >= end) {
|
||||
current = begin;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); }
|
||||
|
||||
static uint8_t days_in_month(uint8_t month, uint16_t year) {
|
||||
static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
uint8_t days = DAYS_IN_MONTH[month];
|
||||
if (month == 2 && is_leap_year(year))
|
||||
return 29;
|
||||
return days;
|
||||
}
|
||||
|
||||
} // namespace esphome
|
105
esphome/core/time.h
Normal file
105
esphome/core/time.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
template<typename T> bool increment_time_value(T ¤t, uint16_t begin, uint16_t end);
|
||||
|
||||
static bool is_leap_year(uint32_t year);
|
||||
|
||||
static uint8_t days_in_month(uint8_t month, uint16_t year);
|
||||
|
||||
/// A more user-friendly version of struct tm from time.h
|
||||
struct ESPTime {
|
||||
/** seconds after the minute [0-60]
|
||||
* @note second is generally 0-59; the extra range is to accommodate leap seconds.
|
||||
*/
|
||||
uint8_t second;
|
||||
/// minutes after the hour [0-59]
|
||||
uint8_t minute;
|
||||
/// hours since midnight [0-23]
|
||||
uint8_t hour;
|
||||
/// day of the week; sunday=1 [1-7]
|
||||
uint8_t day_of_week;
|
||||
/// day of the month [1-31]
|
||||
uint8_t day_of_month;
|
||||
/// day of the year [1-366]
|
||||
uint16_t day_of_year;
|
||||
/// month; january=1 [1-12]
|
||||
uint8_t month;
|
||||
/// year
|
||||
uint16_t year;
|
||||
/// daylight saving time flag
|
||||
bool is_dst;
|
||||
/// unix epoch time (seconds since UTC Midnight January 1, 1970)
|
||||
time_t timestamp;
|
||||
|
||||
/** Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
|
||||
* Up to buffer_len bytes are written.
|
||||
*
|
||||
* @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime
|
||||
*/
|
||||
size_t strftime(char *buffer, size_t buffer_len, const char *format);
|
||||
|
||||
/** Convert this ESPTime struct to a string as specified by the format argument.
|
||||
* @see https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html#index-strftime
|
||||
*
|
||||
* @warning This method uses dynamically allocated strings which can cause heap fragmentation with some
|
||||
* microcontrollers.
|
||||
*/
|
||||
std::string strftime(const std::string &format);
|
||||
|
||||
/// Check if this ESPTime is valid (all fields in range and year is greater than 2018)
|
||||
bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); }
|
||||
|
||||
/// Check if all time fields of this ESPTime are in range.
|
||||
bool fields_in_range() const {
|
||||
return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 &&
|
||||
this->day_of_week < 8 && this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 &&
|
||||
this->day_of_year < 367 && this->month > 0 && this->month < 13;
|
||||
}
|
||||
|
||||
/// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance.
|
||||
static ESPTime from_c_tm(struct tm *c_tm, time_t c_time);
|
||||
|
||||
/** Convert an UTC epoch timestamp to a local time ESPTime instance.
|
||||
*
|
||||
* @param epoch Seconds since 1st January 1970. In UTC.
|
||||
* @return The generated ESPTime
|
||||
*/
|
||||
static ESPTime from_epoch_local(time_t epoch) {
|
||||
struct tm *c_tm = ::localtime(&epoch);
|
||||
return ESPTime::from_c_tm(c_tm, epoch);
|
||||
}
|
||||
/** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
|
||||
*
|
||||
* @param epoch Seconds since 1st January 1970. In UTC.
|
||||
* @return The generated ESPTime
|
||||
*/
|
||||
static ESPTime from_epoch_utc(time_t epoch) {
|
||||
struct tm *c_tm = ::gmtime(&epoch);
|
||||
return ESPTime::from_c_tm(c_tm, epoch);
|
||||
}
|
||||
|
||||
/// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC).
|
||||
void recalc_timestamp_utc(bool use_day_of_year = true);
|
||||
|
||||
/// Convert this ESPTime instance back to a tm struct.
|
||||
struct tm to_c_tm();
|
||||
|
||||
static int32_t timezone_offset();
|
||||
|
||||
/// Increment this clock instance by one second.
|
||||
void increment_second();
|
||||
/// Increment this clock instance by one day.
|
||||
void increment_day();
|
||||
bool operator<(ESPTime other);
|
||||
bool operator<=(ESPTime other);
|
||||
bool operator==(ESPTime other);
|
||||
bool operator>=(ESPTime other);
|
||||
bool operator>(ESPTime other);
|
||||
};
|
||||
} // namespace esphome
|
Loading…
Reference in a new issue