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:
Jesse Hills 2023-06-09 10:24:44 +12:00 committed by GitHub
parent ce13979690
commit 302dea4169
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 376 additions and 403 deletions

View file

@ -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);

View file

@ -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>

View file

@ -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);

View file

@ -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()) {

View file

@ -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.
*

View file

@ -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),

View file

@ -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();

View file

@ -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));

View file

@ -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[]);

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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; }

View file

@ -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.

View file

@ -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

View file

@ -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),

View file

@ -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; }

View file

@ -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_;

View file

@ -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 {

View file

@ -1,5 +1,7 @@
#include "automation.h"
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {

View file

@ -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>

View file

@ -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(&timestr[0], timestr.size(), format.c_str(), &c_tm);
while (len == 0) {
timestr.resize(timestr.size() * 2);
len = ::strftime(&timestr[0], timestr.size(), format.c_str(), &c_tm);
}
timestr.resize(len);
return timestr;
}
template<typename T> bool increment_time_value(T &current, 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

View file

@ -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

View file

@ -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

View file

@ -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_();

View file

@ -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 ////////////////

View file

@ -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);

View file

@ -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;

View file

@ -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
View 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(&timestr[0], timestr.size(), format.c_str(), &c_tm);
while (len == 0) {
timestr.resize(timestr.size() * 2);
len = ::strftime(&timestr[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 &current, 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
View file

@ -0,0 +1,105 @@
#pragma once
#include <cstdlib>
#include <ctime>
#include <string>
namespace esphome {
template<typename T> bool increment_time_value(T &current, 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