mirror of
https://github.com/esphome/esphome.git
synced 2025-04-14 06:40:32 +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
@ -442,7 +442,7 @@ uint8_t BedJetHub::write_notify_config_descriptor_(bool enable) {
|
|||||||
void BedJetHub::send_local_time() {
|
void BedJetHub::send_local_time() {
|
||||||
if (this->time_id_.has_value()) {
|
if (this->time_id_.has_value()) {
|
||||||
auto *time_id = *this->time_id_;
|
auto *time_id = *this->time_id_;
|
||||||
time::ESPTime now = time_id->now();
|
ESPTime now = time_id->now();
|
||||||
if (now.is_valid()) {
|
if (now.is_valid()) {
|
||||||
this->set_clock(now.hour, now.minute);
|
this->set_clock(now.hour, now.minute);
|
||||||
ESP_LOGD(TAG, "Using time component to set BedJet clock: %d:%02d", 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
|
#ifdef USE_TIME
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <esp_gattc_api.h>
|
#include <esp_gattc_api.h>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/helpers.h"
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
#include <esp_sleep.h>
|
#include <esp_sleep.h>
|
||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#ifdef USE_TIME
|
#ifdef USE_TIME
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@ -170,7 +171,7 @@ template<typename... Ts> class EnterDeepSleepAction : public Action<Ts...> {
|
|||||||
if (after_time)
|
if (after_time)
|
||||||
timestamp += 60 * 60 * 24;
|
timestamp += 60 * 60 * 24;
|
||||||
|
|
||||||
int32_t offset = time::ESPTime::timezone_offset();
|
int32_t offset = ESPTime::timezone_offset();
|
||||||
timestamp -= offset; // Change timestamp to utc
|
timestamp -= offset; // Change timestamp to utc
|
||||||
const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
|
const uint32_t ms_left = (timestamp - timestamp_now) * 1000;
|
||||||
this->deep_sleep_->set_sleep_duration(ms_left);
|
this->deep_sleep_->set_sleep_duration(ms_left);
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/color.h"
|
#include "esphome/core/color.h"
|
||||||
#include "esphome/core/log.h"
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace display {
|
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))
|
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||||
this->trigger(from, to);
|
this->trigger(from, to);
|
||||||
}
|
}
|
||||||
#ifdef USE_TIME
|
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
||||||
void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format,
|
|
||||||
time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
this->print(x, y, font, color, align, buffer);
|
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);
|
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);
|
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);
|
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void DisplayBuffer::start_clipping(Rect rect) {
|
void DisplayBuffer::start_clipping(Rect rect) {
|
||||||
if (!this->clipping_rectangle_.empty()) {
|
if (!this->clipping_rectangle_.empty()) {
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
#pragma once
|
#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 <cstdarg>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "display_color_utils.h"
|
||||||
#ifdef USE_TIME
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/core/component.h"
|
||||||
#endif
|
#include "esphome/core/defines.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#ifdef USE_GRAPH
|
#ifdef USE_GRAPH
|
||||||
#include "esphome/components/graph/graph.h"
|
#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)));
|
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`.
|
/** 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.
|
* @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 format The strftime format to use.
|
||||||
* @param time The time to format.
|
* @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)));
|
__attribute__((format(strftime, 7, 0)));
|
||||||
|
|
||||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
/** 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 format The strftime format to use.
|
||||||
* @param time The time to format.
|
* @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)));
|
__attribute__((format(strftime, 6, 0)));
|
||||||
|
|
||||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
/** 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 format The strftime format to use.
|
||||||
* @param time The time to format.
|
* @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)));
|
__attribute__((format(strftime, 6, 0)));
|
||||||
|
|
||||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
/** 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 format The strftime format to use.
|
||||||
* @param time The time to format.
|
* @param time The time to format.
|
||||||
*/
|
*/
|
||||||
void strftime(int x, int y, Font *font, const char *format, time::ESPTime time)
|
void strftime(int x, int y, Font *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
|
||||||
__attribute__((format(strftime, 5, 0)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||||
*
|
*
|
||||||
|
@ -37,14 +37,14 @@ void DS1307Component::read_time() {
|
|||||||
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||||
return;
|
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),
|
.minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10),
|
||||||
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
|
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
|
||||||
.day_of_week = uint8_t(ds1307_.reg.weekday),
|
.day_of_week = uint8_t(ds1307_.reg.weekday),
|
||||||
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
|
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
|
||||||
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||||
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
|
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
|
||||||
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)};
|
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)};
|
||||||
rtc_time.recalc_timestamp_utc(false);
|
rtc_time.recalc_timestamp_utc(false);
|
||||||
if (!rtc_time.is_valid()) {
|
if (!rtc_time.is_valid()) {
|
||||||
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
|
||||||
|
@ -16,7 +16,7 @@ void GPSTime::from_tiny_gps_(TinyGPSPlus &tiny_gps) {
|
|||||||
if (tiny_gps.date.year() < 2019)
|
if (tiny_gps.date.year() < 2019)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
time::ESPTime val{};
|
ESPTime val{};
|
||||||
val.year = tiny_gps.date.year();
|
val.year = tiny_gps.date.year();
|
||||||
val.month = tiny_gps.date.month();
|
val.month = tiny_gps.date.month();
|
||||||
val.day_of_month = tiny_gps.date.day();
|
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++)
|
for (uint8_t i = 0; i < this->rows_ * this->columns_; i++)
|
||||||
this->buffer_[i] = ' ';
|
this->buffer_[i] = ' ';
|
||||||
}
|
}
|
||||||
#ifdef USE_TIME
|
void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) {
|
||||||
void LCDDisplay::strftime(uint8_t column, uint8_t row, const char *format, time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
this->print(column, row, buffer);
|
this->print(column, row, buffer);
|
||||||
}
|
}
|
||||||
void LCDDisplay::strftime(const char *format, time::ESPTime time) { this->strftime(0, 0, format, time); }
|
void LCDDisplay::strftime(const char *format, ESPTime time) { this->strftime(0, 0, format, time); }
|
||||||
#endif
|
|
||||||
void LCDDisplay::loadchar(uint8_t location, uint8_t charmap[]) {
|
void LCDDisplay::loadchar(uint8_t location, uint8_t charmap[]) {
|
||||||
location &= 0x7; // we only have 8 locations 0-7
|
location &= 0x7; // we only have 8 locations 0-7
|
||||||
this->command_(LCD_DISPLAY_COMMAND_SET_CGRAM_ADDR | (location << 3));
|
this->command_(LCD_DISPLAY_COMMAND_SET_CGRAM_ADDR | (location << 3));
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -44,13 +40,10 @@ class LCDDisplay : public PollingComponent {
|
|||||||
/// Evaluate the printf-format and print the text at column=0 and row=0.
|
/// Evaluate the printf-format and print the text at column=0 and row=0.
|
||||||
void printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
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.
|
/// 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)
|
void strftime(uint8_t column, uint8_t row, const char *format, ESPTime time) __attribute__((format(strftime, 4, 0)));
|
||||||
__attribute__((format(strftime, 4, 0)));
|
|
||||||
/// Evaluate the strftime-format and print the text at column=0 and row=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)));
|
void strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Load custom char to given location
|
/// Load custom char to given location
|
||||||
void loadchar(uint8_t location, uint8_t charmap[]);
|
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; }
|
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, ESPTime time) {
|
||||||
uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return this->print(pos, buffer);
|
return this->print(pos, buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint8_t MAX7219Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
uint8_t MAX7219Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace max7219
|
} // namespace max7219
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "esphome/components/spi/spi.h"
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
@ -46,13 +42,11 @@ class MAX7219Component : public PollingComponent,
|
|||||||
/// Print `str` at position 0.
|
/// Print `str` at position 0.
|
||||||
uint8_t print(const char *str);
|
uint8_t print(const char *str);
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
/// 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.
|
/// 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)));
|
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void send_byte_(uint8_t a_register, uint8_t data);
|
void send_byte_(uint8_t a_register, uint8_t data);
|
||||||
|
@ -325,18 +325,16 @@ uint8_t MAX7219Component::printdigitf(const char *format, ...) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TIME
|
uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, ESPTime time) {
|
||||||
uint8_t MAX7219Component::strftimedigit(uint8_t pos, const char *format, time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return this->printdigit(pos, buffer);
|
return this->printdigit(pos, buffer);
|
||||||
return 0;
|
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);
|
return this->strftimedigit(0, format, time);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace max7219digit
|
} // namespace max7219digit
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#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/display/display_buffer.h"
|
||||||
#include "esphome/components/spi/spi.h"
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace max7219digit {
|
namespace max7219digit {
|
||||||
|
|
||||||
@ -88,13 +85,11 @@ class MAX7219Component : public PollingComponent,
|
|||||||
/// Print `str` at position 0.
|
/// Print `str` at position 0.
|
||||||
uint8_t printdigit(const char *str);
|
uint8_t printdigit(const char *str);
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
/// 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.
|
/// 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)));
|
uint8_t strftimedigit(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
|
||||||
|
|
||||||
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
|
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include "esphome/components/uart/uart.h"
|
#include "esphome/components/uart/uart.h"
|
||||||
#include "nextion_base.h"
|
#include "nextion_base.h"
|
||||||
#include "nextion_component.h"
|
#include "nextion_component.h"
|
||||||
@ -19,10 +21,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace nextion {
|
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.
|
* 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;
|
void set_component_font(const char *component, uint8_t font_id) override;
|
||||||
#ifdef USE_TIME
|
|
||||||
/**
|
/**
|
||||||
* Send the current time to the nextion display.
|
* Send the current time to the nextion display.
|
||||||
* @param time The time instance to send (get this with id(my_time).now() ).
|
* @param time The time instance to send (get this with id(my_time).now() ).
|
||||||
*/
|
*/
|
||||||
void set_nextion_rtc_time(time::ESPTime time);
|
void set_nextion_rtc_time(ESPTime time);
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the page with a given name.
|
* 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));
|
display::ColorUtil::color_to_565(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TIME
|
void Nextion::set_nextion_rtc_time(ESPTime time) {
|
||||||
void Nextion::set_nextion_rtc_time(time::ESPTime time) {
|
|
||||||
this->add_no_result_to_queue_with_printf_("rtc0", "rtc0=%u", time.year);
|
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_("rtc1", "rtc1=%u", time.month);
|
||||||
this->add_no_result_to_queue_with_printf_("rtc2", "rtc2=%u", time.day_of_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_("rtc4", "rtc4=%u", time.minute);
|
||||||
this->add_no_result_to_queue_with_printf_("rtc5", "rtc5=%u", time.second);
|
this->add_no_result_to_queue_with_printf_("rtc5", "rtc5=%u", time.second);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace nextion
|
} // namespace nextion
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -37,7 +37,7 @@ void PCF85063Component::read_time() {
|
|||||||
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
time::ESPTime rtc_time{
|
ESPTime rtc_time{
|
||||||
.second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10),
|
.second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10),
|
||||||
.minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10),
|
.minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10),
|
||||||
.hour = uint8_t(pcf85063_.reg.hour + 10u * pcf85063_.reg.hour_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::elevation_rad() const { return radians(elevation); }
|
||||||
num_t HorizontalCoordinate::azimuth_rad() const { return radians(azimuth); }
|
num_t HorizontalCoordinate::azimuth_rad() const { return radians(azimuth); }
|
||||||
|
|
||||||
num_t julian_day(time::ESPTime moment) {
|
num_t julian_day(ESPTime moment) {
|
||||||
// p. 59
|
// p. 59
|
||||||
// UT -> JD, TT -> JDE
|
// UT -> JD, TT -> JDE
|
||||||
int y = moment.year;
|
int y = moment.year;
|
||||||
@ -54,7 +54,7 @@ num_t julian_day(time::ESPTime moment) {
|
|||||||
int b = 2 - a + a / 4;
|
int b = 2 - a + a / 4;
|
||||||
return ((int) (365.25 * (y + 4716))) + ((int) (30.6001 * (m + 1))) + d + b - 1524.5;
|
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)
|
// approximation for 2005-2050 from NASA (https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html)
|
||||||
int t = moment.year - 2000;
|
int t = moment.year - 2000;
|
||||||
return 62.92 + t * (0.32217 + t * 0.005589);
|
return 62.92 + t * (0.32217 + t * 0.005589);
|
||||||
@ -199,7 +199,7 @@ struct SunAtLocation {
|
|||||||
// see chapter 12, p. 87
|
// see chapter 12, p. 87
|
||||||
num_t jd = moment.jd();
|
num_t jd = moment.jd();
|
||||||
// eq 12.1, p.87; jd for 0h UT of this date
|
// 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;
|
moment_0h.hour = moment_0h.minute = moment_0h.second = 0;
|
||||||
num_t jd0 = Moment{moment_0h}.jd();
|
num_t jd0 = Moment{moment_0h}.jd();
|
||||||
num_t t = (jd0 - 2451545) / 36525;
|
num_t t = (jd0 - 2451545) / 36525;
|
||||||
@ -227,9 +227,9 @@ struct SunAtLocation {
|
|||||||
return HorizontalCoordinate{degrees(elevation_rad), degrees(azimuth_rad) + 180};
|
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<ESPTime> sunrise(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<ESPTime> sunset(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> event(bool rise, ESPTime date, num_t zenith) const {
|
||||||
// couldn't get the method described in chapter 15 to work,
|
// couldn't get the method described in chapter 15 to work,
|
||||||
// so instead this is based on the algorithm in time4j
|
// 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
|
// 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;
|
new_h = *x;
|
||||||
} while (std::abs(new_h - old_h) >= 15);
|
} while (std::abs(new_h - old_h) >= 15);
|
||||||
time_t new_timestamp = m.timestamp + (time_t) new_h;
|
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:
|
protected:
|
||||||
@ -263,14 +263,14 @@ struct SunAtLocation {
|
|||||||
return hour_angle;
|
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
|
// input date should be in UTC, and hour/minute/second fields 0
|
||||||
num_t added_d = hour / 24.0 - location.longitude / 360;
|
num_t added_d = hour / 24.0 - location.longitude / 360;
|
||||||
num_t jd = julian_day(date) + added_d;
|
num_t jd = julian_day(date) + added_d;
|
||||||
|
|
||||||
num_t eot = SunAtTime(jd).equation_of_time() * 240;
|
num_t eot = SunAtTime(jd).equation_of_time() * 240;
|
||||||
time_t new_timestamp = (time_t) (date.timestamp + added_d * 86400 - eot);
|
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);
|
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_};
|
SunAtLocation sun{location_};
|
||||||
if (!date.is_valid())
|
if (!date.is_valid())
|
||||||
return {};
|
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
|
// We're calculating *next* sunrise/sunset, but calculated event
|
||||||
// is today, so try again tomorrow
|
// is today, so try again tomorrow
|
||||||
time_t new_timestamp = today.timestamp + 24 * 60 * 60;
|
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);
|
it = sun.event(rising, today, zenith);
|
||||||
}
|
}
|
||||||
return it;
|
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);
|
auto it = Sun::calc_event_(this->time_->utcnow(), rising, zenith);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<time::ESPTime> Sun::sunrise(double elevation) { return this->calc_event_(true, 90 - elevation); }
|
optional<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<ESPTime> Sun::sunset(double elevation) { return this->calc_event_(false, 90 - elevation); }
|
||||||
optional<time::ESPTime> Sun::sunrise(time::ESPTime date, double elevation) {
|
optional<ESPTime> Sun::sunrise(ESPTime date, double elevation) { return this->calc_event_(date, true, 90 - 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); }
|
||||||
}
|
|
||||||
optional<time::ESPTime> Sun::sunset(time::ESPTime date, double elevation) {
|
|
||||||
return this->calc_event_(date, false, 90 - elevation);
|
|
||||||
}
|
|
||||||
double Sun::elevation() { return this->calc_coords_().elevation; }
|
double Sun::elevation() { return this->calc_coords_().elevation; }
|
||||||
double Sun::azimuth() { return this->calc_coords_().azimuth; }
|
double Sun::azimuth() { return this->calc_coords_().azimuth; }
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@ -26,7 +28,7 @@ struct GeoLocation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Moment {
|
struct Moment {
|
||||||
time::ESPTime dt;
|
ESPTime dt;
|
||||||
|
|
||||||
num_t jd() const;
|
num_t jd() const;
|
||||||
num_t jde() const;
|
num_t jde() const;
|
||||||
@ -57,18 +59,18 @@ class Sun {
|
|||||||
void set_latitude(double latitude) { location_.latitude = latitude; }
|
void set_latitude(double latitude) { location_.latitude = latitude; }
|
||||||
void set_longitude(double longitude) { location_.longitude = longitude; }
|
void set_longitude(double longitude) { location_.longitude = longitude; }
|
||||||
|
|
||||||
optional<time::ESPTime> sunrise(double elevation);
|
optional<ESPTime> sunrise(double elevation);
|
||||||
optional<time::ESPTime> sunset(double elevation);
|
optional<ESPTime> sunset(double elevation);
|
||||||
optional<time::ESPTime> sunrise(time::ESPTime date, double elevation);
|
optional<ESPTime> sunrise(ESPTime date, double elevation);
|
||||||
optional<time::ESPTime> sunset(time::ESPTime date, double elevation);
|
optional<ESPTime> sunset(ESPTime date, double elevation);
|
||||||
|
|
||||||
double elevation();
|
double elevation();
|
||||||
double azimuth();
|
double azimuth();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
internal::HorizontalCoordinate calc_coords_();
|
internal::HorizontalCoordinate calc_coords_();
|
||||||
optional<time::ESPTime> calc_event_(bool rising, double zenith);
|
optional<ESPTime> calc_event_(bool rising, double zenith);
|
||||||
optional<time::ESPTime> calc_event_(time::ESPTime date, bool rising, double zenith);
|
optional<ESPTime> calc_event_(ESPTime date, bool rising, double zenith);
|
||||||
|
|
||||||
time::RealTimeClock *time_;
|
time::RealTimeClock *time_;
|
||||||
internal::GeoLocation location_;
|
internal::GeoLocation location_;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include "esphome/components/sun/sun.h"
|
#include "esphome/components/sun/sun.h"
|
||||||
#include "esphome/components/text_sensor/text_sensor.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 set_format(const std::string &format) { format_ = format; }
|
||||||
|
|
||||||
void update() override {
|
void update() override {
|
||||||
optional<time::ESPTime> res;
|
optional<ESPTime> res;
|
||||||
if (this->sunrise_) {
|
if (this->sunrise_) {
|
||||||
res = this->parent_->sunrise(this->elevation_);
|
res = this->parent_->sunrise(this->elevation_);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "automation.h"
|
#include "automation.h"
|
||||||
|
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include "real_time_clock.h"
|
#include "real_time_clock.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -52,171 +52,5 @@ void RealTimeClock::apply_timezone_() {
|
|||||||
tzset();
|
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 time
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -1,106 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstdlib>
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include <bitset>
|
#include "esphome/core/time.h"
|
||||||
#include <cstdlib>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace time {
|
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.
|
/// The RealTimeClock class exposes common timekeeping functions via the device's local real-time clock.
|
||||||
///
|
///
|
||||||
/// \note
|
/// \note
|
||||||
|
@ -368,16 +368,14 @@ uint8_t TM1637Display::printf(const char *format, ...) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TIME
|
uint8_t TM1637Display::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||||
uint8_t TM1637Display::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return this->print(pos, buffer);
|
return this->print(pos, buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint8_t TM1637Display::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
uint8_t TM1637Display::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace tm1637
|
} // namespace tm1637
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -3,13 +3,10 @@
|
|||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
#endif
|
#endif
|
||||||
@ -61,12 +58,10 @@ class TM1637Display : public PollingComponent {
|
|||||||
void add_tm1637_key(TM1637Key *tm1637_key) { this->tm1637_keys_.push_back(tm1637_key); }
|
void add_tm1637_key(TM1637Key *tm1637_key) { this->tm1637_keys_.push_back(tm1637_key); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
/// 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.
|
/// 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)));
|
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void bit_delay_();
|
void bit_delay_();
|
||||||
|
@ -211,16 +211,14 @@ uint8_t TM1638Component::printf(const char *format, ...) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TIME
|
uint8_t TM1638Component::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||||
uint8_t TM1638Component::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return this->print(pos, buffer);
|
return this->print(pos, buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint8_t TM1638Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
uint8_t TM1638Component::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||||
#endif
|
|
||||||
|
|
||||||
//////////////// SPI ////////////////
|
//////////////// SPI ////////////////
|
||||||
|
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/automation.h"
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tm1638 {
|
namespace tm1638 {
|
||||||
|
|
||||||
@ -52,12 +49,10 @@ class TM1638Component : public PollingComponent {
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
uint8_t get_keys();
|
uint8_t get_keys();
|
||||||
|
|
||||||
#ifdef USE_TIME
|
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
/// 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.
|
/// 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)));
|
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
|
||||||
|
|
||||||
void set_led(int led_pos, bool led_on_off);
|
void set_led(int led_pos, bool led_on_off);
|
||||||
|
|
||||||
|
@ -508,7 +508,7 @@ void Tuya::send_wifi_status_() {
|
|||||||
void Tuya::send_local_time_() {
|
void Tuya::send_local_time_() {
|
||||||
std::vector<uint8_t> payload;
|
std::vector<uint8_t> payload;
|
||||||
auto *time_id = *this->time_id_;
|
auto *time_id = *this->time_id_;
|
||||||
time::ESPTime now = time_id->now();
|
ESPTime now = time_id->now();
|
||||||
if (now.is_valid()) {
|
if (now.is_valid()) {
|
||||||
uint8_t year = now.year - 2000;
|
uint8_t year = now.year - 2000;
|
||||||
uint8_t month = now.month;
|
uint8_t month = now.month;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#ifdef USE_TIME
|
#ifdef USE_TIME
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#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…
x
Reference in New Issue
Block a user