mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-05-30 09:48:27 +02:00
Merge branch 'dev' into beta
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/version.h"
|
||||
|
||||
#ifdef USE_STATUS_LED
|
||||
#include "esphome/components/status_led/status_led.h"
|
||||
@@ -32,10 +33,9 @@ void Application::setup() {
|
||||
|
||||
for (uint32_t i = 0; i < this->components_.size(); i++) {
|
||||
Component *component = this->components_[i];
|
||||
if (component->is_failed())
|
||||
continue;
|
||||
|
||||
component->call_setup();
|
||||
component->call();
|
||||
this->scheduler.process_to_add();
|
||||
if (component->can_proceed())
|
||||
continue;
|
||||
|
||||
@@ -44,10 +44,9 @@ void Application::setup() {
|
||||
|
||||
do {
|
||||
uint32_t new_app_state = STATUS_LED_WARNING;
|
||||
this->scheduler.call();
|
||||
for (uint32_t j = 0; j <= i; j++) {
|
||||
if (!this->components_[j]->is_failed()) {
|
||||
this->components_[j]->call_loop();
|
||||
}
|
||||
this->components_[j]->call();
|
||||
new_app_state |= this->components_[j]->get_component_state();
|
||||
this->app_state_ |= new_app_state;
|
||||
}
|
||||
@@ -57,13 +56,53 @@ void Application::setup() {
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "setup() finished successfully!");
|
||||
this->dump_config();
|
||||
this->schedule_dump_config();
|
||||
}
|
||||
void Application::dump_config() {
|
||||
ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
|
||||
void Application::loop() {
|
||||
uint32_t new_app_state = 0;
|
||||
const uint32_t start = millis();
|
||||
|
||||
for (auto component : this->components_) {
|
||||
component->dump_config();
|
||||
this->scheduler.call();
|
||||
for (Component *component : this->components_) {
|
||||
component->call();
|
||||
new_app_state |= component->get_component_state();
|
||||
this->app_state_ |= new_app_state;
|
||||
this->feed_wdt();
|
||||
}
|
||||
this->app_state_ = new_app_state;
|
||||
|
||||
const uint32_t end = millis();
|
||||
if (end - start > 200) {
|
||||
ESP_LOGV(TAG, "A component took a long time in a loop() cycle (%.1f s).", (end - start) / 1e3f);
|
||||
ESP_LOGV(TAG, "Components should block for at most 20-30ms in loop().");
|
||||
ESP_LOGV(TAG, "This will become a warning soon.");
|
||||
}
|
||||
|
||||
const uint32_t now = millis();
|
||||
|
||||
if (HighFrequencyLoopRequester::is_high_frequency()) {
|
||||
yield();
|
||||
} else {
|
||||
uint32_t delay_time = this->loop_interval_;
|
||||
if (now - this->last_loop_ < this->loop_interval_)
|
||||
delay_time = this->loop_interval_ - (now - this->last_loop_);
|
||||
|
||||
uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time);
|
||||
// next_schedule is max 0.5*delay_time
|
||||
// otherwise interval=0 schedules result in constant looping with almost no sleep
|
||||
next_schedule = std::max(next_schedule, delay_time / 2);
|
||||
delay_time = std::min(next_schedule, delay_time);
|
||||
delay(delay_time);
|
||||
}
|
||||
this->last_loop_ = now;
|
||||
|
||||
if (this->dump_config_at_ >= 0 && this->dump_config_at_ < this->components_.size()) {
|
||||
if (this->dump_config_at_ == 0) {
|
||||
ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
|
||||
}
|
||||
|
||||
this->components_[this->dump_config_at_]->dump_config();
|
||||
this->dump_config_at_++;
|
||||
}
|
||||
}
|
||||
void Application::loop() {
|
||||
@@ -116,7 +155,7 @@ void ICACHE_RAM_ATTR HOT Application::feed_wdt() {
|
||||
LAST_FEED = now;
|
||||
#ifdef USE_STATUS_LED
|
||||
if (status_led::global_status_led != nullptr) {
|
||||
status_led::global_status_led->call_loop();
|
||||
status_led::global_status_led->call();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/scheduler.h"
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
@@ -39,7 +40,7 @@ class Application {
|
||||
void pre_setup(const std::string &name, const char *compilation_time) {
|
||||
this->name_ = name;
|
||||
this->compilation_time_ = compilation_time;
|
||||
global_preferences.begin(this->name_);
|
||||
global_preferences.begin();
|
||||
}
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
@@ -109,8 +110,7 @@ class Application {
|
||||
*/
|
||||
void set_loop_interval(uint32_t loop_interval) { this->loop_interval_ = loop_interval; }
|
||||
|
||||
void dump_config();
|
||||
void schedule_dump_config() { this->dump_config_scheduled_ = true; }
|
||||
void schedule_dump_config() { this->dump_config_at_ = 0; }
|
||||
|
||||
void feed_wdt();
|
||||
|
||||
@@ -119,8 +119,12 @@ class Application {
|
||||
void safe_reboot();
|
||||
|
||||
void run_safe_shutdown_hooks() {
|
||||
for (auto *comp : this->components_)
|
||||
for (auto *comp : this->components_) {
|
||||
comp->on_safe_shutdown();
|
||||
}
|
||||
for (auto *comp : this->components_) {
|
||||
comp->on_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_app_state() const { return this->app_state_; }
|
||||
@@ -198,6 +202,8 @@ class Application {
|
||||
}
|
||||
#endif
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
protected:
|
||||
friend Component;
|
||||
|
||||
@@ -234,7 +240,7 @@ class Application {
|
||||
std::string compilation_time_;
|
||||
uint32_t last_loop_{0};
|
||||
uint32_t loop_interval_{16};
|
||||
bool dump_config_scheduled_{false};
|
||||
int dump_config_at_{-1};
|
||||
uint32_t app_state_{0};
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,15 @@ namespace esphome {
|
||||
|
||||
#define TEMPLATABLE_VALUE(type, name) TEMPLATABLE_VALUE_(type, name)
|
||||
|
||||
#define TEMPLATABLE_STRING_VALUE_(name) \
|
||||
protected: \
|
||||
TemplatableStringValue<Ts...> name##_{}; \
|
||||
\
|
||||
public: \
|
||||
template<typename V> void set_##name(V name) { this->name##_ = name; }
|
||||
|
||||
#define TEMPLATABLE_STRING_VALUE(name) TEMPLATABLE_STRING_VALUE_(name)
|
||||
|
||||
/** Base class for all automation conditions.
|
||||
*
|
||||
* @tparam Ts The template parameters to pass when executing.
|
||||
|
||||
@@ -73,7 +73,7 @@ template<typename... Ts> class ForCondition : public Condition<Ts...>, public Co
|
||||
bool check(Ts... x) override {
|
||||
if (!this->check_internal())
|
||||
return false;
|
||||
return millis() - this->last_inactive_ < this->time_.value(x...);
|
||||
return millis() - this->last_inactive_ >= this->time_.value(x...);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
+41
-120
@@ -1,5 +1,3 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
@@ -45,109 +43,50 @@ void Component::setup() {}
|
||||
void Component::loop() {}
|
||||
|
||||
void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||
const uint32_t now = millis();
|
||||
// only put offset in lower half
|
||||
uint32_t offset = 0;
|
||||
if (interval != 0)
|
||||
offset = (random_uint32() % interval) / 2;
|
||||
ESP_LOGVV(TAG, "set_interval(name='%s', interval=%u, offset=%u)", name.c_str(), interval, offset);
|
||||
|
||||
if (!name.empty()) {
|
||||
this->cancel_interval(name);
|
||||
}
|
||||
struct TimeFunction function = {
|
||||
.name = name,
|
||||
.type = TimeFunction::INTERVAL,
|
||||
.interval = interval,
|
||||
.last_execution = now - interval - offset,
|
||||
.f = std::move(f),
|
||||
.remove = false,
|
||||
};
|
||||
this->time_functions_.push_back(function);
|
||||
App.scheduler.set_interval(this, name, interval, std::move(f));
|
||||
}
|
||||
|
||||
bool Component::cancel_interval(const std::string &name) { // NOLINT
|
||||
return this->cancel_time_function_(name, TimeFunction::INTERVAL);
|
||||
return App.scheduler.cancel_interval(this, name);
|
||||
}
|
||||
|
||||
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
const uint32_t now = millis();
|
||||
ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout);
|
||||
|
||||
if (!name.empty()) {
|
||||
this->cancel_timeout(name);
|
||||
}
|
||||
struct TimeFunction function = {
|
||||
.name = name,
|
||||
.type = TimeFunction::TIMEOUT,
|
||||
.interval = timeout,
|
||||
.last_execution = now,
|
||||
.f = std::move(f),
|
||||
.remove = false,
|
||||
};
|
||||
this->time_functions_.push_back(function);
|
||||
return App.scheduler.set_timeout(this, name, timeout, std::move(f));
|
||||
}
|
||||
|
||||
bool Component::cancel_timeout(const std::string &name) { // NOLINT
|
||||
return this->cancel_time_function_(name, TimeFunction::TIMEOUT);
|
||||
return App.scheduler.cancel_timeout(this, name);
|
||||
}
|
||||
|
||||
void Component::call_loop() {
|
||||
this->loop_internal_();
|
||||
this->loop();
|
||||
}
|
||||
void Component::call_loop() { this->loop(); }
|
||||
|
||||
bool Component::cancel_time_function_(const std::string &name, TimeFunction::Type type) {
|
||||
// NOLINTNEXTLINE
|
||||
for (auto iter = this->time_functions_.begin(); iter != this->time_functions_.end(); iter++) {
|
||||
if (!iter->remove && iter->name == name && iter->type == type) {
|
||||
ESP_LOGVV(TAG, "Removing old time function %s.", iter->name.c_str());
|
||||
iter->remove = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Component::call_setup() {
|
||||
this->setup_internal_();
|
||||
this->setup();
|
||||
}
|
||||
void Component::call_setup() { this->setup(); }
|
||||
uint32_t Component::get_component_state() const { return this->component_state_; }
|
||||
void Component::loop_internal_() {
|
||||
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
||||
this->component_state_ |= COMPONENT_STATE_LOOP;
|
||||
|
||||
for (unsigned int i = 0; i < this->time_functions_.size(); i++) { // NOLINT
|
||||
const uint32_t now = millis();
|
||||
TimeFunction *tf = &this->time_functions_[i];
|
||||
if (tf->should_run(now)) {
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
const char *type =
|
||||
tf->type == TimeFunction::INTERVAL ? "interval" : (tf->type == TimeFunction::TIMEOUT ? "timeout" : "defer");
|
||||
ESP_LOGVV(TAG, "Running %s '%s':%u with interval=%u last_execution=%u (now=%u)", type, tf->name.c_str(), i,
|
||||
tf->interval, tf->last_execution, now);
|
||||
#endif
|
||||
|
||||
tf->f();
|
||||
// The vector might have reallocated due to new items
|
||||
tf = &this->time_functions_[i];
|
||||
|
||||
if (tf->type == TimeFunction::INTERVAL && tf->interval != 0) {
|
||||
const uint32_t amount = (now - tf->last_execution) / tf->interval;
|
||||
tf->last_execution += (amount * tf->interval);
|
||||
} else if (tf->type == TimeFunction::DEFER || tf->type == TimeFunction::TIMEOUT) {
|
||||
tf->remove = true;
|
||||
}
|
||||
}
|
||||
void Component::call() {
|
||||
uint32_t state = this->component_state_ & COMPONENT_STATE_MASK;
|
||||
switch (state) {
|
||||
case COMPONENT_STATE_CONSTRUCTION:
|
||||
// State Construction: Call setup and set state to setup
|
||||
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
||||
this->component_state_ |= COMPONENT_STATE_SETUP;
|
||||
this->call_setup();
|
||||
break;
|
||||
case COMPONENT_STATE_SETUP:
|
||||
// State setup: Call first loop and set state to loop
|
||||
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
||||
this->component_state_ |= COMPONENT_STATE_LOOP;
|
||||
this->call_loop();
|
||||
break;
|
||||
case COMPONENT_STATE_LOOP:
|
||||
// State loop: Call loop
|
||||
this->call_loop();
|
||||
break;
|
||||
case COMPONENT_STATE_FAILED:
|
||||
// State failed: Do nothing
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this->time_functions_.erase(std::remove_if(this->time_functions_.begin(), this->time_functions_.end(),
|
||||
[](const TimeFunction &tf) -> bool { return tf.remove; }),
|
||||
this->time_functions_.end());
|
||||
}
|
||||
void Component::setup_internal_() {
|
||||
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
||||
this->component_state_ |= COMPONENT_STATE_SETUP;
|
||||
}
|
||||
void Component::mark_failed() {
|
||||
ESP_LOGE(TAG, "Component was marked as failed.");
|
||||
@@ -155,29 +94,20 @@ void Component::mark_failed() {
|
||||
this->component_state_ |= COMPONENT_STATE_FAILED;
|
||||
this->status_set_error();
|
||||
}
|
||||
void Component::defer(std::function<void()> &&f) { this->defer("", std::move(f)); } // NOLINT
|
||||
bool Component::cancel_defer(const std::string &name) { // NOLINT
|
||||
return this->cancel_time_function_(name, TimeFunction::DEFER);
|
||||
void Component::defer(std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", 0, std::move(f));
|
||||
}
|
||||
bool Component::cancel_defer(const std::string &name) { // NOLINT
|
||||
return App.scheduler.cancel_timeout(this, name);
|
||||
}
|
||||
void Component::defer(const std::string &name, std::function<void()> &&f) { // NOLINT
|
||||
if (!name.empty()) {
|
||||
this->cancel_defer(name);
|
||||
}
|
||||
struct TimeFunction function = {
|
||||
.name = name,
|
||||
.type = TimeFunction::DEFER,
|
||||
.interval = 0,
|
||||
.last_execution = 0,
|
||||
.f = std::move(f),
|
||||
.remove = false,
|
||||
};
|
||||
this->time_functions_.push_back(function);
|
||||
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||
}
|
||||
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
this->set_timeout("", timeout, std::move(f));
|
||||
App.scheduler.set_timeout(this, "", timeout, std::move(f));
|
||||
}
|
||||
void Component::set_interval(uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||
this->set_interval("", interval, std::move(f));
|
||||
App.scheduler.set_interval(this, "", interval, std::move(f));
|
||||
}
|
||||
bool Component::is_failed() { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
|
||||
bool Component::can_proceed() { return true; }
|
||||
@@ -203,16 +133,15 @@ void Component::status_momentary_error(const std::string &name, uint32_t length)
|
||||
}
|
||||
void Component::dump_config() {}
|
||||
float Component::get_actual_setup_priority() const {
|
||||
return this->setup_priority_override_.value_or(this->get_setup_priority());
|
||||
if (isnan(this->setup_priority_override_))
|
||||
return this->get_setup_priority();
|
||||
return this->setup_priority_override_;
|
||||
}
|
||||
void Component::set_setup_priority(float priority) { this->setup_priority_override_ = priority; }
|
||||
|
||||
PollingComponent::PollingComponent(uint32_t update_interval) : Component(), update_interval_(update_interval) {}
|
||||
|
||||
void PollingComponent::call_setup() {
|
||||
// Call component internal setup.
|
||||
this->setup_internal_();
|
||||
|
||||
// Let the polling component subclass setup their HW.
|
||||
this->setup();
|
||||
|
||||
@@ -240,12 +169,4 @@ void Nameable::calc_object_id_() {
|
||||
}
|
||||
uint32_t Nameable::get_object_id_hash() { return this->object_id_hash_; }
|
||||
|
||||
bool Component::TimeFunction::should_run(uint32_t now) const {
|
||||
if (this->remove)
|
||||
return false;
|
||||
if (this->type == DEFER)
|
||||
return true;
|
||||
return this->interval != 4294967295UL && now - this->last_execution > this->interval;
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "esphome/core/optional.h"
|
||||
|
||||
@@ -91,18 +91,7 @@ class Component {
|
||||
*/
|
||||
virtual float get_loop_priority() const;
|
||||
|
||||
/** Public loop() functions. These will be called by the Application instance.
|
||||
*
|
||||
* Note: This should normally not be overriden, unless you know what you're doing.
|
||||
* They're basically to make creating custom components easier. For example the
|
||||
* SensorComponent can override these methods to not have the user call some super
|
||||
* methods within their custom sensors. These methods should ALWAYS call the loop_internal()
|
||||
* and setup_internal() methods.
|
||||
*
|
||||
* Basically, it handles stuff like interval/timeout functions and eventually calls loop().
|
||||
*/
|
||||
virtual void call_loop();
|
||||
virtual void call_setup();
|
||||
void call();
|
||||
|
||||
virtual void on_shutdown() {}
|
||||
virtual void on_safe_shutdown() {}
|
||||
@@ -138,6 +127,8 @@ class Component {
|
||||
void status_momentary_error(const std::string &name, uint32_t length = 5000);
|
||||
|
||||
protected:
|
||||
virtual void call_loop();
|
||||
virtual void call_setup();
|
||||
/** Set an interval function with a unique name. Empty name means no cancelling possible.
|
||||
*
|
||||
* This will call f every interval ms. Can be cancelled via CancelInterval().
|
||||
@@ -204,34 +195,8 @@ class Component {
|
||||
/// Cancel a defer callback using the specified name, name must not be empty.
|
||||
bool cancel_defer(const std::string &name); // NOLINT
|
||||
|
||||
void loop_internal_();
|
||||
void setup_internal_();
|
||||
|
||||
/// Internal struct for storing timeout/interval functions.
|
||||
struct TimeFunction {
|
||||
std::string name; ///< The name/id of this TimeFunction.
|
||||
enum Type { TIMEOUT, INTERVAL, DEFER } type; ///< The type of this TimeFunction. Either TIMEOUT, INTERVAL or DEFER.
|
||||
uint32_t interval; ///< The interval/timeout of this function.
|
||||
/// The last execution for interval functions and the time, SetInterval was called, for timeout functions.
|
||||
uint32_t last_execution;
|
||||
std::function<void()> f; ///< The function (or callback) itself.
|
||||
bool remove;
|
||||
|
||||
bool should_run(uint32_t now) const;
|
||||
};
|
||||
|
||||
/// Cancel an only time function. If name is empty, won't do anything.
|
||||
bool cancel_time_function_(const std::string &name, TimeFunction::Type type);
|
||||
|
||||
/** Storage for interval/timeout functions.
|
||||
*
|
||||
* Intentionally a vector despite its map-like nature, because of the
|
||||
* memory overhead.
|
||||
*/
|
||||
std::vector<TimeFunction> time_functions_;
|
||||
|
||||
uint32_t component_state_{0x0000}; ///< State of this component.
|
||||
optional<float> setup_priority_override_;
|
||||
float setup_priority_override_{NAN};
|
||||
};
|
||||
|
||||
/** This class simplifies creating components that periodically check a state.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
// This file is auto-generated! Do not edit!
|
||||
|
||||
#define ESPHOME_VERSION "dev"
|
||||
|
||||
#define USE_API
|
||||
#define USE_LOGGER
|
||||
#define USE_BINARY_SENSOR
|
||||
@@ -24,3 +22,4 @@
|
||||
#endif
|
||||
#define USE_TIME
|
||||
#define USE_DEEP_SLEEP
|
||||
#define USE_CAPTIVE_PORTAL
|
||||
|
||||
@@ -148,7 +148,7 @@ void ICACHE_RAM_ATTR HOT GPIOPin::digital_write(bool value) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void ISRInternalGPIOPin::digital_write(bool value) {
|
||||
void ICACHE_RAM_ATTR HOT ISRInternalGPIOPin::digital_write(bool value) {
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
if (this->pin_ != 16) {
|
||||
if (value != this->inverted_) {
|
||||
|
||||
+18
-2
@@ -4,6 +4,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "esphome/core/optional.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
@@ -160,6 +161,11 @@ template<int...> struct seq {}; // NOLINT
|
||||
template<int N, int... S> struct gens : gens<N - 1, N - 1, S...> {}; // NOLINT
|
||||
template<int... S> struct gens<0, S...> { using type = seq<S...>; }; // NOLINT
|
||||
|
||||
template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template<typename T, enable_if_t<!std::is_pointer<T>::value, int> = 0> T id(T value) { return value; }
|
||||
template<typename T, enable_if_t<std::is_pointer<T *>::value, int> = 0> T &id(T *value) { return *value; }
|
||||
|
||||
template<typename... X> class CallbackManager;
|
||||
|
||||
/** Simple helper class to allow having multiple subscribers to a signal.
|
||||
@@ -192,8 +198,6 @@ struct is_callable // NOLINT
|
||||
static constexpr auto value = decltype(test<T>(nullptr))::value; // NOLINT
|
||||
};
|
||||
|
||||
template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template<typename T, typename... X> class TemplatableValue {
|
||||
public:
|
||||
TemplatableValue() : type_(EMPTY) {}
|
||||
@@ -239,6 +243,18 @@ template<typename T, typename... X> class TemplatableValue {
|
||||
std::function<T(X...)> f_;
|
||||
};
|
||||
|
||||
template<typename... X> class TemplatableStringValue : public TemplatableValue<std::string, X...> {
|
||||
public:
|
||||
TemplatableStringValue() : TemplatableValue<std::string, X...>() {}
|
||||
|
||||
template<typename F, enable_if_t<!is_callable<F, X...>::value, int> = 0>
|
||||
TemplatableStringValue(F value) : TemplatableValue<std::string, X...>(value) {}
|
||||
|
||||
template<typename F, enable_if_t<is_callable<F, X...>::value, int> = 0>
|
||||
TemplatableStringValue(F f)
|
||||
: TemplatableValue<std::string, X...>([f](X... x) -> std::string { return to_string(f(x...)); }) {}
|
||||
};
|
||||
|
||||
void delay_microseconds_accurate(uint32_t usec);
|
||||
|
||||
template<typename T> class Deduplicator {
|
||||
|
||||
+28
-23
@@ -1,6 +1,6 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "log.h"
|
||||
#include "defines.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
#include "esphome/components/logger/logger.h"
|
||||
@@ -8,60 +8,65 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
int HOT esp_log_printf_(int level, const char *tag, const char *format, ...) { // NOLINT
|
||||
void HOT esp_log_printf_(int level, const char *tag, int line, const char *format, ...) { // NOLINT
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int ret = esp_log_vprintf_(level, tag, format, arg);
|
||||
esp_log_vprintf_(level, tag, line, format, arg);
|
||||
va_end(arg);
|
||||
return ret;
|
||||
}
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
int HOT esp_log_printf_(int level, const char *tag, const __FlashStringHelper *format, ...) {
|
||||
void HOT esp_log_printf_(int level, const char *tag, int line, const __FlashStringHelper *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int ret = esp_log_vprintf_(level, tag, format, arg);
|
||||
esp_log_vprintf_(level, tag, line, format, arg);
|
||||
va_end(arg);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int HOT esp_log_vprintf_(int level, const char *tag, const char *format, va_list args) { // NOLINT
|
||||
void HOT esp_log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) { // NOLINT
|
||||
#ifdef USE_LOGGER
|
||||
auto *log = logger::global_logger;
|
||||
if (log == nullptr)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
return log->log_vprintf_(level, tag, format, args);
|
||||
#else
|
||||
return 0;
|
||||
log->log_vprintf_(level, tag, line, format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
int HOT esp_log_vprintf_(int level, const char *tag, const __FlashStringHelper *format, va_list args) { // NOLINT
|
||||
void HOT esp_log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format,
|
||||
va_list args) { // NOLINT
|
||||
#ifdef USE_LOGGER
|
||||
auto *log = logger::global_logger;
|
||||
if (log == nullptr)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
return log->log_vprintf_(level, tag, format, args);
|
||||
#else
|
||||
return 0;
|
||||
log->log_vprintf_(level, tag, line, format, args);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
int HOT esp_idf_log_vprintf_(const char *format, va_list args) { // NOLINT
|
||||
#ifdef USE_LOGGER
|
||||
auto *log = logger::global_logger;
|
||||
if (log == nullptr)
|
||||
return 0;
|
||||
|
||||
return log->log_vprintf_(log->get_global_log_level(), "", format, args);
|
||||
#else
|
||||
return 0;
|
||||
size_t len = strlen(format);
|
||||
if (format[len - 1] == '\n') {
|
||||
// Remove trailing newline from format
|
||||
// Use locally stored
|
||||
static std::string FORMAT_COPY;
|
||||
FORMAT_COPY.clear();
|
||||
FORMAT_COPY.insert(0, format, len - 1);
|
||||
format = FORMAT_COPY.c_str();
|
||||
}
|
||||
|
||||
log->log_vprintf_(ESPHOME_LOG_LEVEL, "esp-idf", 0, format, args);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
+20
-29
@@ -20,9 +20,10 @@ namespace esphome {
|
||||
#define ESPHOME_LOG_LEVEL_ERROR 1
|
||||
#define ESPHOME_LOG_LEVEL_WARN 2
|
||||
#define ESPHOME_LOG_LEVEL_INFO 3
|
||||
#define ESPHOME_LOG_LEVEL_DEBUG 4
|
||||
#define ESPHOME_LOG_LEVEL_VERBOSE 5
|
||||
#define ESPHOME_LOG_LEVEL_VERY_VERBOSE 6
|
||||
#define ESPHOME_LOG_LEVEL_CONFIG 4
|
||||
#define ESPHOME_LOG_LEVEL_DEBUG 5
|
||||
#define ESPHOME_LOG_LEVEL_VERBOSE 6
|
||||
#define ESPHOME_LOG_LEVEL_VERY_VERBOSE 7
|
||||
|
||||
#ifndef ESPHOME_LOG_LEVEL
|
||||
#define ESPHOME_LOG_LEVEL ESPHOME_LOG_LEVEL_DEBUG
|
||||
@@ -43,38 +44,30 @@ namespace esphome {
|
||||
|
||||
#define ESPHOME_LOG_COLOR(COLOR) "\033[0;" COLOR "m"
|
||||
#define ESPHOME_LOG_BOLD(COLOR) "\033[1;" COLOR "m"
|
||||
|
||||
#define ESPHOME_LOG_COLOR_E ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED)
|
||||
#define ESPHOME_LOG_COLOR_W ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_YELLOW)
|
||||
#define ESPHOME_LOG_COLOR_I ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GREEN)
|
||||
#define ESPHOME_LOG_COLOR_C ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_MAGENTA)
|
||||
#define ESPHOME_LOG_COLOR_D ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_CYAN)
|
||||
#define ESPHOME_LOG_COLOR_V ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GRAY)
|
||||
#define ESPHOME_LOG_COLOR_VV ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_WHITE)
|
||||
#define ESPHOME_LOG_RESET_COLOR "\033[0m"
|
||||
|
||||
int esp_log_printf_(int level, const char *tag, const char *format, ...) // NOLINT
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
void esp_log_printf_(int level, const char *tag, int line, const char *format, ...) // NOLINT
|
||||
__attribute__((format(printf, 4, 5)));
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
int esp_log_printf_(int level, const char *tag, const __FlashStringHelper *format, ...);
|
||||
void esp_log_printf_(int level, const char *tag, int line, const __FlashStringHelper *format, ...);
|
||||
#endif
|
||||
int esp_log_vprintf_(int level, const char *tag, const char *format, va_list args); // NOLINT
|
||||
void esp_log_vprintf_(int level, const char *tag, int line, const char *format, va_list args); // NOLINT
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
int esp_log_vprintf_(int level, const char *tag, const __FlashStringHelper *format, va_list args);
|
||||
void esp_log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, va_list args);
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
#endif
|
||||
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
#define ESPHOME_LOG_FORMAT(tag, letter, format) \
|
||||
F(ESPHOME_LOG_COLOR_##letter "[" #letter "][%s:%03u]: " format ESPHOME_LOG_RESET_COLOR), tag, __LINE__
|
||||
#define ESPHOME_LOG_FORMAT(format) F(format)
|
||||
#else
|
||||
#define ESPHOME_LOG_FORMAT(tag, letter, format) \
|
||||
ESPHOME_LOG_COLOR_##letter "[" #letter "][%s:%03u]: " format ESPHOME_LOG_RESET_COLOR, tag, __LINE__
|
||||
#define ESPHOME_LOG_FORMAT(format) format
|
||||
#endif
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
#define esph_log_vv(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_VERY_VERBOSE, tag, ESPHOME_LOG_FORMAT(tag, VV, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_VERY_VERBOSE, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
#else
|
||||
@@ -83,7 +76,7 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
#define esph_log_v(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_VERBOSE, tag, ESPHOME_LOG_FORMAT(tag, V, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_VERBOSE, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_VERBOSE
|
||||
#else
|
||||
@@ -92,22 +85,20 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
||||
#define esph_log_d(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_DEBUG, tag, ESPHOME_LOG_FORMAT(tag, D, format), ##__VA_ARGS__)
|
||||
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_DEBUG, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
#define esph_log_config(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_DEBUG, tag, ESPHOME_LOG_FORMAT(tag, C, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_CONFIG, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_DEBUG
|
||||
#define ESPHOME_LOG_HAS_CONFIG
|
||||
#else
|
||||
#define esph_log_d(tag, format, ...)
|
||||
|
||||
#define esph_log_config(tag, format, ...)
|
||||
#endif
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO
|
||||
#define esph_log_i(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, tag, ESPHOME_LOG_FORMAT(tag, I, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_INFO
|
||||
#else
|
||||
@@ -116,7 +107,7 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_WARN
|
||||
#define esph_log_w(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_WARN, tag, ESPHOME_LOG_FORMAT(tag, W, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_WARN, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_WARN
|
||||
#else
|
||||
@@ -125,7 +116,7 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
|
||||
#define esph_log_e(tag, format, ...) \
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_ERROR, tag, ESPHOME_LOG_FORMAT(tag, E, format), ##__VA_ARGS__)
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_ERROR, tag, __LINE__, ESPHOME_LOG_FORMAT(format), ##__VA_ARGS__)
|
||||
|
||||
#define ESPHOME_LOG_HAS_ERROR
|
||||
#else
|
||||
|
||||
+122
-51
@@ -1,20 +1,25 @@
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
extern "C" {
|
||||
#include "spi_flash.h"
|
||||
}
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
|
||||
static const char *TAG = "preferences";
|
||||
|
||||
ESPPreferenceObject::ESPPreferenceObject() : rtc_offset_(0), length_words_(0), type_(0), data_(nullptr) {}
|
||||
ESPPreferenceObject::ESPPreferenceObject(size_t rtc_offset, size_t length, uint32_t type)
|
||||
: rtc_offset_(rtc_offset), length_words_(length), type_(type) {
|
||||
ESPPreferenceObject::ESPPreferenceObject() : offset_(0), length_words_(0), type_(0), data_(nullptr) {}
|
||||
ESPPreferenceObject::ESPPreferenceObject(size_t offset, size_t length, uint32_t type)
|
||||
: offset_(offset), length_words_(length), type_(type) {
|
||||
this->data_ = new uint32_t[this->length_words_ + 1];
|
||||
for (uint32_t i = 0; i < this->length_words_ + 1; i++)
|
||||
this->data_[i] = 0;
|
||||
@@ -29,7 +34,7 @@ bool ESPPreferenceObject::load_() {
|
||||
|
||||
bool valid = this->data_[this->length_words_] == this->calculate_crc_();
|
||||
|
||||
ESP_LOGVV(TAG, "LOAD %u: valid=%s, 0=0x%08X 1=0x%08X (Type=%u, CRC=0x%08X)", this->rtc_offset_, // NOLINT
|
||||
ESP_LOGVV(TAG, "LOAD %u: valid=%s, 0=0x%08X 1=0x%08X (Type=%u, CRC=0x%08X)", this->offset_, // NOLINT
|
||||
YESNO(valid), this->data_[0], this->data_[1], this->type_, this->calculate_crc_());
|
||||
return valid;
|
||||
}
|
||||
@@ -42,7 +47,7 @@ bool ESPPreferenceObject::save_() {
|
||||
this->data_[this->length_words_] = this->calculate_crc_();
|
||||
if (!this->save_internal_())
|
||||
return false;
|
||||
ESP_LOGVV(TAG, "SAVE %u: 0=0x%08X 1=0x%08X (Type=%u, CRC=0x%08X)", this->rtc_offset_, // NOLINT
|
||||
ESP_LOGVV(TAG, "SAVE %u: 0=0x%08X 1=0x%08X (Type=%u, CRC=0x%08X)", this->offset_, // NOLINT
|
||||
this->data_[0], this->data_[1], this->type_, this->calculate_crc_());
|
||||
return true;
|
||||
}
|
||||
@@ -54,6 +59,12 @@ bool ESPPreferenceObject::save_() {
|
||||
#define ESP_RTC_USER_MEM_SIZE_WORDS 128
|
||||
#define ESP_RTC_USER_MEM_SIZE_BYTES ESP_RTC_USER_MEM_SIZE_WORDS * 4
|
||||
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
#define ESP8266_FLASH_STORAGE_SIZE 128
|
||||
#else
|
||||
#define ESP8266_FLASH_STORAGE_SIZE 64
|
||||
#endif
|
||||
|
||||
static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) {
|
||||
if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
|
||||
return false;
|
||||
@@ -62,9 +73,7 @@ static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
static bool esp8266_preferences_modified = false;
|
||||
#endif
|
||||
static bool esp8266_flash_dirty = false;
|
||||
|
||||
static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) {
|
||||
if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
|
||||
@@ -75,29 +84,24 @@ static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) {
|
||||
}
|
||||
|
||||
auto *ptr = &ESP_RTC_USER_MEM[index];
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
if (*ptr != value) {
|
||||
esp8266_preferences_modified = true;
|
||||
}
|
||||
#endif
|
||||
*ptr = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
extern "C" uint32_t _SPIFFS_end;
|
||||
|
||||
static const uint32_t get_esp8266_flash_sector() { return (uint32_t(&_SPIFFS_end) - 0x40200000) / SPI_FLASH_SEC_SIZE; }
|
||||
static const uint32_t get_esp8266_flash_sector() {
|
||||
union {
|
||||
uint32_t *ptr;
|
||||
uint32_t uint;
|
||||
} data{};
|
||||
data.ptr = &_SPIFFS_end;
|
||||
return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
|
||||
}
|
||||
static const uint32_t get_esp8266_flash_address() { return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
|
||||
|
||||
static void load_esp8266_flash() {
|
||||
ESP_LOGVV(TAG, "Loading preferences from flash...");
|
||||
disable_interrupts();
|
||||
spi_flash_read(get_esp8266_flash_address(), ESP_RTC_USER_MEM, ESP_RTC_USER_MEM_SIZE_BYTES);
|
||||
enable_interrupts();
|
||||
}
|
||||
static void save_esp8266_flash() {
|
||||
if (!esp8266_preferences_modified)
|
||||
void ESPPreferences::save_esp8266_flash_() {
|
||||
if (!esp8266_flash_dirty)
|
||||
return;
|
||||
|
||||
ESP_LOGVV(TAG, "Saving preferences to flash...");
|
||||
@@ -109,31 +113,53 @@ static void save_esp8266_flash() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto write_res = spi_flash_write(get_esp8266_flash_address(), ESP_RTC_USER_MEM, ESP_RTC_USER_MEM_SIZE_BYTES);
|
||||
auto write_res = spi_flash_write(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
|
||||
enable_interrupts();
|
||||
if (write_res != SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGV(TAG, "Write ESP8266 flash failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
esp8266_preferences_modified = false;
|
||||
esp8266_flash_dirty = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ESPPreferenceObject::save_internal_() {
|
||||
if (this->in_flash_) {
|
||||
for (uint32_t i = 0; i <= this->length_words_; i++) {
|
||||
uint32_t j = this->offset_ + i;
|
||||
if (j >= ESP8266_FLASH_STORAGE_SIZE)
|
||||
return false;
|
||||
uint32_t v = this->data_[i];
|
||||
uint32_t *ptr = &global_preferences.flash_storage_[j];
|
||||
if (*ptr != v)
|
||||
esp8266_flash_dirty = true;
|
||||
*ptr = v;
|
||||
}
|
||||
global_preferences.save_esp8266_flash_();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i <= this->length_words_; i++) {
|
||||
if (!esp_rtc_user_mem_write(this->rtc_offset_ + i, this->data_[i]))
|
||||
if (!esp_rtc_user_mem_write(this->offset_ + i, this->data_[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
save_esp8266_flash();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
bool ESPPreferenceObject::load_internal_() {
|
||||
if (this->in_flash_) {
|
||||
for (uint32_t i = 0; i <= this->length_words_; i++) {
|
||||
uint32_t j = this->offset_ + i;
|
||||
if (j >= ESP8266_FLASH_STORAGE_SIZE)
|
||||
return false;
|
||||
this->data_[i] = global_preferences.flash_storage_[j];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i <= this->length_words_; i++) {
|
||||
if (!esp_rtc_user_mem_read(this->rtc_offset_ + i, &this->data_[i]))
|
||||
if (!esp_rtc_user_mem_read(this->offset_ + i, &this->data_[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -144,13 +170,26 @@ ESPPreferences::ESPPreferences()
|
||||
// which will be reset each time OTA occurs
|
||||
: current_offset_(0) {}
|
||||
|
||||
void ESPPreferences::begin(const std::string &name) {
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
load_esp8266_flash();
|
||||
#endif
|
||||
void ESPPreferences::begin() {
|
||||
this->flash_storage_ = new uint32_t[ESP8266_FLASH_STORAGE_SIZE];
|
||||
ESP_LOGVV(TAG, "Loading preferences from flash...");
|
||||
disable_interrupts();
|
||||
spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type) {
|
||||
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
|
||||
if (in_flash) {
|
||||
uint32_t start = this->current_flash_offset_;
|
||||
uint32_t end = start + length + 1;
|
||||
if (end > ESP8266_FLASH_STORAGE_SIZE)
|
||||
return {};
|
||||
auto pref = ESPPreferenceObject(start, length, type);
|
||||
pref.in_flash_ = true;
|
||||
this->current_flash_offset_ = end;
|
||||
return pref;
|
||||
}
|
||||
|
||||
uint32_t start = this->current_offset_;
|
||||
uint32_t end = start + length + 1;
|
||||
bool in_normal = start < 96;
|
||||
@@ -165,7 +204,7 @@ ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type
|
||||
|
||||
if (end > 128) {
|
||||
// Doesn't fit in data, return uninitialized preference obj.
|
||||
return ESPPreferenceObject();
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t rtc_offset;
|
||||
@@ -185,35 +224,67 @@ bool ESPPreferences::is_prevent_write() { return this->prevent_write_; }
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
bool ESPPreferenceObject::save_internal_() {
|
||||
if (global_preferences.nvs_handle_ == 0)
|
||||
return false;
|
||||
|
||||
char key[32];
|
||||
sprintf(key, "%u", this->rtc_offset_);
|
||||
sprintf(key, "%u", this->offset_);
|
||||
uint32_t len = (this->length_words_ + 1) * 4;
|
||||
size_t ret = global_preferences.preferences_.putBytes(key, this->data_, len);
|
||||
if (ret != len) {
|
||||
ESP_LOGV(TAG, "putBytes failed!");
|
||||
esp_err_t err = nvs_set_blob(global_preferences.nvs_handle_, key, this->data_, len);
|
||||
if (err) {
|
||||
ESP_LOGV(TAG, "nvs_set_blob('%s', len=%u) failed: %s", key, len, esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
err = nvs_commit(global_preferences.nvs_handle_);
|
||||
if (err) {
|
||||
ESP_LOGV(TAG, "nvs_commit('%s', len=%u) failed: %s", key, len, esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ESPPreferenceObject::load_internal_() {
|
||||
if (global_preferences.nvs_handle_ == 0)
|
||||
return false;
|
||||
|
||||
char key[32];
|
||||
sprintf(key, "%u", this->rtc_offset_);
|
||||
sprintf(key, "%u", this->offset_);
|
||||
uint32_t len = (this->length_words_ + 1) * 4;
|
||||
size_t ret = global_preferences.preferences_.getBytes(key, this->data_, len);
|
||||
if (ret != len) {
|
||||
ESP_LOGV(TAG, "getBytes failed!");
|
||||
|
||||
uint32_t actual_len;
|
||||
esp_err_t err = nvs_get_blob(global_preferences.nvs_handle_, key, nullptr, &actual_len);
|
||||
if (err) {
|
||||
ESP_LOGV(TAG, "nvs_get_blob('%s'): %s - the key might not be set yet", key, esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
if (actual_len != len) {
|
||||
ESP_LOGVV(TAG, "NVS length does not match. Assuming key changed (%u!=%u)", actual_len, len);
|
||||
return false;
|
||||
}
|
||||
err = nvs_get_blob(global_preferences.nvs_handle_, key, this->data_, &len);
|
||||
if (err) {
|
||||
ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", key, esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ESPPreferences::ESPPreferences() : current_offset_(0) {}
|
||||
void ESPPreferences::begin(const std::string &name) {
|
||||
const std::string key = truncate_string(name, 15);
|
||||
ESP_LOGV(TAG, "Opening preferences with key '%s'", key.c_str());
|
||||
this->preferences_.begin(key.c_str());
|
||||
void ESPPreferences::begin() {
|
||||
auto ns = truncate_string(App.get_name(), 15);
|
||||
esp_err_t err = nvs_open(ns.c_str(), NVS_READWRITE, &this->nvs_handle_);
|
||||
if (err) {
|
||||
ESP_LOGW(TAG, "nvs_open failed: %s - erasing NVS...", esp_err_to_name(err));
|
||||
nvs_flash_deinit();
|
||||
nvs_flash_erase();
|
||||
nvs_flash_init();
|
||||
|
||||
err = nvs_open(ns.c_str(), NVS_READWRITE, &this->nvs_handle_);
|
||||
if (err) {
|
||||
this->nvs_handle_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type) {
|
||||
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
|
||||
auto pref = ESPPreferenceObject(this->current_offset_, length, type);
|
||||
this->current_offset_++;
|
||||
return pref;
|
||||
|
||||
+29
-12
@@ -2,18 +2,15 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include <Preferences.h>
|
||||
#endif
|
||||
|
||||
#include "esphome/core/esphal.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
class ESPPreferenceObject {
|
||||
public:
|
||||
ESPPreferenceObject();
|
||||
ESPPreferenceObject(size_t rtc_offset, size_t length, uint32_t type);
|
||||
ESPPreferenceObject(size_t offset, size_t length, uint32_t type);
|
||||
|
||||
template<typename T> bool save(T *src);
|
||||
|
||||
@@ -22,6 +19,8 @@ class ESPPreferenceObject {
|
||||
bool is_initialized() const;
|
||||
|
||||
protected:
|
||||
friend class ESPPreferences;
|
||||
|
||||
bool save_();
|
||||
bool load_();
|
||||
bool save_internal_();
|
||||
@@ -29,18 +28,33 @@ class ESPPreferenceObject {
|
||||
|
||||
uint32_t calculate_crc_() const;
|
||||
|
||||
size_t rtc_offset_;
|
||||
size_t offset_;
|
||||
size_t length_words_;
|
||||
uint32_t type_;
|
||||
uint32_t *data_;
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
bool in_flash_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#ifdef USE_ESP8266_PREFERENCES_FLASH
|
||||
static bool DEFAULT_IN_FLASH = true;
|
||||
#else
|
||||
static bool DEFAULT_IN_FLASH = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
static bool DEFAULT_IN_FLASH = true;
|
||||
#endif
|
||||
|
||||
class ESPPreferences {
|
||||
public:
|
||||
ESPPreferences();
|
||||
void begin(const std::string &name);
|
||||
ESPPreferenceObject make_preference(size_t length, uint32_t type);
|
||||
template<typename T> ESPPreferenceObject make_preference(uint32_t type);
|
||||
void begin();
|
||||
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash = DEFAULT_IN_FLASH);
|
||||
template<typename T> ESPPreferenceObject make_preference(uint32_t type, bool in_flash = DEFAULT_IN_FLASH);
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
/** On the ESP8266, we can't override the first 128 bytes during OTA uploads
|
||||
@@ -59,17 +73,20 @@ class ESPPreferences {
|
||||
|
||||
uint32_t current_offset_;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
Preferences preferences_;
|
||||
uint32_t nvs_handle_;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
void save_esp8266_flash_();
|
||||
bool prevent_write_{false};
|
||||
uint32_t *flash_storage_;
|
||||
uint32_t current_flash_offset_;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern ESPPreferences global_preferences;
|
||||
|
||||
template<typename T> ESPPreferenceObject ESPPreferences::make_preference(uint32_t type) {
|
||||
return this->make_preference((sizeof(T) + 3) / 4, type);
|
||||
template<typename T> ESPPreferenceObject ESPPreferences::make_preference(uint32_t type, bool in_flash) {
|
||||
return this->make_preference((sizeof(T) + 3) / 4, type, in_flash);
|
||||
}
|
||||
|
||||
template<typename T> bool ESPPreferenceObject::save(T *src) {
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "scheduler.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
static const char *TAG = "scheduler";
|
||||
|
||||
static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
|
||||
|
||||
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
|
||||
std::function<void()> &&func) {
|
||||
const uint32_t now = this->millis_();
|
||||
|
||||
if (!name.empty())
|
||||
this->cancel_timeout(component, name);
|
||||
|
||||
if (timeout == SCHEDULER_DONT_RUN)
|
||||
return;
|
||||
|
||||
ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout);
|
||||
|
||||
auto *item = new SchedulerItem();
|
||||
item->component = component;
|
||||
item->name = name;
|
||||
item->type = SchedulerItem::TIMEOUT;
|
||||
item->timeout = timeout;
|
||||
item->last_execution = now;
|
||||
item->last_execution_major = this->millis_major_;
|
||||
item->f = std::move(func);
|
||||
item->remove = false;
|
||||
this->push_(item);
|
||||
}
|
||||
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
|
||||
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
|
||||
}
|
||||
void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval,
|
||||
std::function<void()> &&func) {
|
||||
const uint32_t now = this->millis_();
|
||||
|
||||
if (!name.empty())
|
||||
this->cancel_interval(component, name);
|
||||
|
||||
if (interval == SCHEDULER_DONT_RUN)
|
||||
return;
|
||||
|
||||
// only put offset in lower half
|
||||
uint32_t offset = 0;
|
||||
if (interval != 0)
|
||||
offset = (random_uint32() % interval) / 2;
|
||||
|
||||
ESP_LOGVV(TAG, "set_interval(name='%s', interval=%u, offset=%u)", name.c_str(), interval, offset);
|
||||
|
||||
auto *item = new SchedulerItem();
|
||||
item->component = component;
|
||||
item->name = name;
|
||||
item->type = SchedulerItem::INTERVAL;
|
||||
item->interval = interval;
|
||||
item->last_execution = now - offset;
|
||||
item->last_execution_major = this->millis_major_;
|
||||
if (item->last_execution > now)
|
||||
item->last_execution_major--;
|
||||
item->f = std::move(func);
|
||||
item->remove = false;
|
||||
this->push_(item);
|
||||
}
|
||||
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
|
||||
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
||||
}
|
||||
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
||||
if (this->empty_())
|
||||
return {};
|
||||
auto *item = this->items_[0];
|
||||
const uint32_t now = this->millis_();
|
||||
uint32_t next_time = item->last_execution + item->interval;
|
||||
if (next_time < now)
|
||||
return 0;
|
||||
return next_time - now;
|
||||
}
|
||||
void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
||||
const uint32_t now = this->millis_();
|
||||
this->process_to_add();
|
||||
|
||||
// Uncomment for debugging the scheduler:
|
||||
|
||||
// if (random_uint32() % 400 == 0) {
|
||||
// std::vector<SchedulerItem *> old_items = this->items_;
|
||||
// ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now);
|
||||
// while (!this->empty_()) {
|
||||
// auto *item = this->items_[0];
|
||||
// const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
// ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u",
|
||||
// type, item->name.c_str(), item->interval, item->last_execution, item->last_execution_major,
|
||||
// item->last_execution + item->interval);
|
||||
// this->pop_raw_();
|
||||
// }
|
||||
// ESP_LOGVV(TAG, "\n");
|
||||
// this->items_ = old_items;
|
||||
//}
|
||||
|
||||
while (!this->empty_()) {
|
||||
// Don't copy-by value yet
|
||||
auto *item = this->items_[0];
|
||||
if ((now - item->last_execution) < item->interval)
|
||||
// Not reached timeout yet, done for this call
|
||||
break;
|
||||
uint8_t major = item->last_execution_major;
|
||||
if (item->last_execution + item->interval < item->last_execution)
|
||||
major++;
|
||||
if (major != this->millis_major_)
|
||||
break;
|
||||
|
||||
// Don't run on failed components
|
||||
if (item->component != nullptr && item->component->is_failed()) {
|
||||
this->pop_raw_();
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
|
||||
item->interval, item->last_execution, now);
|
||||
#endif
|
||||
|
||||
// Warning: During f(), a lot of stuff can happen, including:
|
||||
// - timeouts/intervals get added, potentially invalidating vector pointers
|
||||
// - timeouts/intervals get cancelled
|
||||
item->f();
|
||||
|
||||
// Only pop after function call, this ensures we were reachable
|
||||
// during the function call and know if we were cancelled.
|
||||
this->pop_raw_();
|
||||
|
||||
if (item->remove) {
|
||||
// We were removed/cancelled in the function call, stop
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->type == SchedulerItem::INTERVAL) {
|
||||
if (item->interval != 0) {
|
||||
const uint32_t before = item->last_execution;
|
||||
const uint32_t amount = (now - item->last_execution) / item->interval;
|
||||
item->last_execution += amount * item->interval;
|
||||
if (item->last_execution < before)
|
||||
item->last_execution_major++;
|
||||
}
|
||||
this->push_(item);
|
||||
} else {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
this->process_to_add();
|
||||
}
|
||||
void HOT Scheduler::process_to_add() {
|
||||
for (auto *it : this->to_add_) {
|
||||
if (it->remove) {
|
||||
delete it;
|
||||
continue;
|
||||
}
|
||||
|
||||
this->items_.push_back(it);
|
||||
std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
||||
}
|
||||
this->to_add_.clear();
|
||||
}
|
||||
void HOT Scheduler::cleanup_() {
|
||||
while (!this->items_.empty()) {
|
||||
auto item = this->items_[0];
|
||||
if (!item->remove)
|
||||
return;
|
||||
|
||||
delete item;
|
||||
this->pop_raw_();
|
||||
}
|
||||
}
|
||||
void HOT Scheduler::pop_raw_() {
|
||||
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
||||
this->items_.pop_back();
|
||||
}
|
||||
void HOT Scheduler::push_(Scheduler::SchedulerItem *item) { this->to_add_.push_back(item); }
|
||||
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
|
||||
bool ret = false;
|
||||
for (auto *it : this->items_)
|
||||
if (it->component == component && it->name == name && it->type == type) {
|
||||
it->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
for (auto *it : this->to_add_)
|
||||
if (it->component == component && it->name == name && it->type == type) {
|
||||
it->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t Scheduler::millis_() {
|
||||
const uint32_t now = millis();
|
||||
if (now < this->last_millis_) {
|
||||
ESP_LOGD(TAG, "Incrementing scheduler major");
|
||||
this->millis_major_++;
|
||||
}
|
||||
return now;
|
||||
}
|
||||
|
||||
bool HOT Scheduler::SchedulerItem::cmp(Scheduler::SchedulerItem *a, Scheduler::SchedulerItem *b) {
|
||||
// min-heap
|
||||
// return true if *a* will happen after *b*
|
||||
uint32_t a_next_exec = a->last_execution + a->timeout;
|
||||
uint8_t a_next_exec_major = a->last_execution_major;
|
||||
if (a_next_exec < a->last_execution)
|
||||
a_next_exec_major++;
|
||||
|
||||
uint32_t b_next_exec = b->last_execution + b->timeout;
|
||||
uint8_t b_next_exec_major = b->last_execution_major;
|
||||
if (b_next_exec < b->last_execution)
|
||||
b_next_exec_major++;
|
||||
|
||||
if (a_next_exec_major != b_next_exec_major) {
|
||||
return a_next_exec_major > b_next_exec_major;
|
||||
}
|
||||
|
||||
return a_next_exec > b_next_exec;
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
class Component;
|
||||
|
||||
class Scheduler {
|
||||
public:
|
||||
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> &&func);
|
||||
bool cancel_timeout(Component *component, const std::string &name);
|
||||
void set_interval(Component *component, const std::string &name, uint32_t interval, std::function<void()> &&func);
|
||||
bool cancel_interval(Component *component, const std::string &name);
|
||||
|
||||
optional<uint32_t> next_schedule_in();
|
||||
|
||||
void call();
|
||||
|
||||
void process_to_add();
|
||||
|
||||
protected:
|
||||
struct SchedulerItem {
|
||||
Component *component;
|
||||
std::string name;
|
||||
enum Type { TIMEOUT, INTERVAL } type;
|
||||
union {
|
||||
uint32_t interval;
|
||||
uint32_t timeout;
|
||||
};
|
||||
uint32_t last_execution;
|
||||
std::function<void()> f;
|
||||
bool remove;
|
||||
uint8_t last_execution_major;
|
||||
|
||||
static bool cmp(SchedulerItem *a, SchedulerItem *b);
|
||||
};
|
||||
|
||||
uint32_t millis_();
|
||||
void cleanup_();
|
||||
void pop_raw_();
|
||||
void push_(SchedulerItem *item);
|
||||
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
|
||||
bool empty_() {
|
||||
this->cleanup_();
|
||||
return this->items_.empty();
|
||||
}
|
||||
|
||||
std::vector<SchedulerItem *> items_;
|
||||
std::vector<SchedulerItem *> to_add_;
|
||||
uint32_t last_millis_{0};
|
||||
uint8_t millis_major_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome
|
||||
+46
-72
@@ -1,6 +1,8 @@
|
||||
#include "esphome/core/util.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/version.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_WIFI
|
||||
#include "esphome/components/wifi/wifi_component.h"
|
||||
@@ -37,84 +39,56 @@ bool network_is_connected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void network_setup() {
|
||||
bool ready = true;
|
||||
#ifdef USE_ETHERNET
|
||||
if (ethernet::global_eth_component != nullptr) {
|
||||
ethernet::global_eth_component->call_setup();
|
||||
ready = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr) {
|
||||
wifi::global_wifi_component->call_setup();
|
||||
ready = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!ready) {
|
||||
#ifdef USE_ETHERNET
|
||||
if (ethernet::global_eth_component != nullptr) {
|
||||
ethernet::global_eth_component->call_loop();
|
||||
ready = ready || ethernet::global_eth_component->can_proceed();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr) {
|
||||
wifi::global_wifi_component->call_loop();
|
||||
ready = ready || wifi::global_wifi_component->can_proceed();
|
||||
}
|
||||
#endif
|
||||
|
||||
App.feed_wdt();
|
||||
}
|
||||
}
|
||||
void network_tick() {
|
||||
#ifdef USE_ETHERNET
|
||||
if (ethernet::global_eth_component != nullptr)
|
||||
ethernet::global_eth_component->call_loop();
|
||||
#endif
|
||||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
wifi::global_wifi_component->call_loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
void network_setup_mdns() {
|
||||
MDNS.begin(App.get_name().c_str());
|
||||
#ifdef USE_API
|
||||
if (api::global_api_server != nullptr) {
|
||||
MDNS.addService("esphomelib", "tcp", api::global_api_server->get_port());
|
||||
// DNS-SD (!=mDNS !) requires at least one TXT record for service discovery - let's add version
|
||||
MDNS.addServiceTxt("esphomelib", "tcp", "version", ESPHOME_VERSION);
|
||||
MDNS.addServiceTxt("esphomelib", "tcp", "address", network_get_address().c_str());
|
||||
} else {
|
||||
#endif
|
||||
// Publish "http" service if not using native API.
|
||||
// This is just to have *some* mDNS service so that .local resolution works
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addServiceTxt("http", "tcp", "version", ESPHOME_VERSION);
|
||||
#ifdef USE_API
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void network_tick_mdns() {
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
MDNS.update();
|
||||
bool mdns_setup;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string network_get_address() {
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
void network_setup_mdns(IPAddress address, int interface) {
|
||||
// Latest arduino framework breaks mDNS for AP interface
|
||||
// see https://github.com/esp8266/Arduino/issues/6114
|
||||
if (interface == 1)
|
||||
return;
|
||||
MDNS.begin(App.get_name().c_str(), address);
|
||||
mdns_setup = true;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
void network_setup_mdns() {
|
||||
MDNS.begin(App.get_name().c_str());
|
||||
#endif
|
||||
#ifdef USE_API
|
||||
if (api::global_api_server != nullptr) {
|
||||
MDNS.addService("esphomelib", "tcp", api::global_api_server->get_port());
|
||||
// DNS-SD (!=mDNS !) requires at least one TXT record for service discovery - let's add version
|
||||
MDNS.addServiceTxt("esphomelib", "tcp", "version", ESPHOME_VERSION);
|
||||
MDNS.addServiceTxt("esphomelib", "tcp", "address", network_get_address().c_str());
|
||||
} else {
|
||||
#endif
|
||||
// Publish "http" service if not using native API.
|
||||
// This is just to have *some* mDNS service so that .local resolution works
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addServiceTxt("http", "tcp", "version", ESPHOME_VERSION);
|
||||
#ifdef USE_API
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void network_tick_mdns() {
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
if (mdns_setup)
|
||||
MDNS.update();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string network_get_address() {
|
||||
#ifdef USE_ETHERNET
|
||||
if (ethernet::global_eth_component != nullptr)
|
||||
return ethernet::global_eth_component->get_use_address();
|
||||
if (ethernet::global_eth_component != nullptr)
|
||||
return ethernet::global_eth_component->get_use_address();
|
||||
#endif
|
||||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
return wifi::global_wifi_component->get_use_address();
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
return wifi::global_wifi_component->get_use_address();
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
+6
-2
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "IPAddress.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
@@ -10,9 +11,12 @@ bool network_is_connected();
|
||||
std::string network_get_address();
|
||||
|
||||
/// Manually set up the network stack (outside of the App.setup() loop, for example in OTA safe mode)
|
||||
void network_setup();
|
||||
void network_tick();
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
void network_setup_mdns(IPAddress address, int interface);
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
void network_setup_mdns();
|
||||
#endif
|
||||
void network_tick_mdns();
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
// This file is auto-generated! Do not edit!
|
||||
#define ESPHOME_VERSION "dev"
|
||||
Reference in New Issue
Block a user