diff --git a/src/esphomelib/application.cpp b/src/esphomelib/application.cpp index 8c701f48..529ab586 100644 --- a/src/esphomelib/application.cpp +++ b/src/esphomelib/application.cpp @@ -54,7 +54,7 @@ void Application::setup() { assert(this->application_state_ == COMPONENT_STATE_CONSTRUCTION && "setup() called twice."); ESP_LOGV(TAG, "Sorting components by setup priority..."); std::stable_sort(this->components_.begin(), this->components_.end(), [](const Component *a, const Component *b) { - return a->get_setup_priority() > b->get_setup_priority(); + return a->get_actual_setup_priority() > b->get_actual_setup_priority(); }); for (uint32_t i = 0; i < this->components_.size(); i++) { @@ -86,11 +86,18 @@ void Application::setup() { this->application_state_ = COMPONENT_STATE_SETUP; + ESP_LOGI(TAG, "setup() finished successfully!"); + if (this->compilation_time_.empty()) { ESP_LOGI(TAG, "You're running esphomelib v" ESPHOMELIB_VERSION); } else { ESP_LOGI(TAG, "You're running esphomelib v" ESPHOMELIB_VERSION " compiled on %s", this->compilation_time_.c_str()); } + + for (uint32_t i = 0; i < this->components_.size(); i++) { + Component *component = this->components_[i]; + component->dump_config(); + } } void HOT Application::loop() { diff --git a/src/esphomelib/application.h b/src/esphomelib/application.h index fc78f0d8..4b63797a 100644 --- a/src/esphomelib/application.h +++ b/src/esphomelib/application.h @@ -301,6 +301,12 @@ class Application { display::Nextion *make_nextion(UARTComponent *parent, uint32_t update_interval = 5000); #endif + template + GlobalVariableComponent *make_global_variable(); + + template + GlobalVariableComponent *make_global_variable(T initial_value); + @@ -1366,6 +1372,16 @@ Automation *Application::make_automation(Trigger *trigger) { return new Automation(trigger); } +template +GlobalVariableComponent *Application::make_global_variable() { + return this->register_component(new GlobalVariableComponent()); +} + +template +GlobalVariableComponent *Application::make_global_variable(T initial_value) { + return this->register_component(new GlobalVariableComponent(initial_value)); +} + ESPHOMELIB_NAMESPACE_END #endif //ESPHOMELIB_APPLICATION_H diff --git a/src/esphomelib/automation.cpp b/src/esphomelib/automation.cpp index 0356b12b..b9b01a90 100644 --- a/src/esphomelib/automation.cpp +++ b/src/esphomelib/automation.cpp @@ -30,6 +30,9 @@ ShutdownTrigger::ShutdownTrigger() { void LoopTrigger::loop() { this->trigger(); } +float LoopTrigger::get_setup_priority() const { + return setup_priority::HARDWARE_LATE; +} RangeCondition::RangeCondition() = default; diff --git a/src/esphomelib/automation.h b/src/esphomelib/automation.h index ddac6a10..d0834f9b 100644 --- a/src/esphomelib/automation.h +++ b/src/esphomelib/automation.h @@ -5,6 +5,7 @@ #include "esphomelib/component.h" #include "esphomelib/helpers.h" #include "esphomelib/defines.h" +#include "esphomelib/esppreferences.h" ESPHOMELIB_NAMESPACE_BEGIN @@ -94,6 +95,7 @@ class ShutdownTrigger : public Trigger { class LoopTrigger : public Trigger, public Component { public: void loop() override; + float get_setup_priority() const override; }; template @@ -130,6 +132,7 @@ class DelayAction : public Action, public Component { void set_delay(uint32_t delay); void play(T x) override; + float get_setup_priority() const override; protected: TemplatableValue delay_{0}; }; @@ -211,6 +214,29 @@ class Automation { ActionList actions_; }; +template +class GlobalVariableComponent : public Component { + public: + explicit GlobalVariableComponent(); + explicit GlobalVariableComponent(T initial_value); + + T &value(); + + void setup() override; + + float get_setup_priority() const override; + + void loop() override; + + void set_restore_value(uint32_t name_hash); + + protected: + T value_{}; + T prev_value_{}; + bool restore_value_{false}; + uint32_t name_hash_{}; + ESPPreferenceObject rtc_; +}; // =============== TEMPLATE DEFINITIONS =============== @@ -279,6 +305,10 @@ template void DelayAction::set_delay(uint32_t delay) { this->delay_ = delay; } +template +float DelayAction::get_setup_priority() const { + return setup_priority::HARDWARE; +} template Condition *Automation::add_condition(Condition *condition) { @@ -427,6 +457,47 @@ ScriptExecuteAction *Script::make_execute_action() { return new ScriptExecuteAction(this); } +template +GlobalVariableComponent::GlobalVariableComponent() { + +} +template +GlobalVariableComponent::GlobalVariableComponent(T initial_value) + : value_(initial_value) { + +} +template +T &GlobalVariableComponent::value() { + return this->value_; +} +template +void GlobalVariableComponent::setup() { + if (this->restore_value_) { + this->rtc_ = global_preferences.make_preference(1944399030U ^ this->name_hash_); + this->rtc_.load(&this->value_); + } + memcpy(&this->prev_value_, &this->value_, sizeof(T)); +} +template +float GlobalVariableComponent::get_setup_priority() const { + return setup_priority::HARDWARE; +} +template +void GlobalVariableComponent::loop() { + if (this->restore_value_) { + int diff = memcmp(&this->value_, &this->prev_value_, sizeof(T)); + if (diff != 0) { + this->rtc_.save(&this->value_); + memcpy(&this->prev_value_, &this->value_, sizeof(T)); + } + } +} +template +void GlobalVariableComponent::set_restore_value(uint32_t name_hash) { + this->restore_value_ = true; + this->name_hash_ = name_hash; +} + ESPHOMELIB_NAMESPACE_END #endif //ESPHOMELIB_AUTOMATION_H diff --git a/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.cpp b/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.cpp index 8b8a6744..e3f7b227 100644 --- a/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.cpp +++ b/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.cpp @@ -15,9 +15,32 @@ void ESP32TouchComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up ESP32 Touch Hub..."); touch_pad_init(); -#ifdef ESPHOMELIB_LOG_HAS_CONFIG - ESP_LOGCONFIG(TAG, " Meas cycle: %.2fms", this->meas_cycle_ / (8000000.0f / 1000.0f)); - ESP_LOGCONFIG(TAG, " Sleep cycle: %.2fms", this->sleep_cycle_ / (150000.0f / 1000.0f)); + if (this->iir_filter_enabled_()) { + touch_pad_filter_start(this->iir_filter_); + } + + touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); + touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, + this->voltage_attenuation_); + + for (auto *child : this->children_) { + // Disable interrupt threshold + touch_pad_config(child->get_touch_pad(), 0); + } + + add_shutdown_hook([this](const char *cause) { + if (this->iir_filter_enabled_()) { + touch_pad_filter_stop(); + touch_pad_filter_delete(); + } + touch_pad_deinit(); + }); +} + +void ESP32TouchComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Config for ESP32 Touch Hub:"); + ESP_LOGCONFIG(TAG, " Meas cycle: %.2fms", this->meas_cycle_ / (8000000.0f / 1000.0f)); + ESP_LOGCONFIG(TAG, " Sleep cycle: %.2fms", this->sleep_cycle_ / (150000.0f / 1000.0f)); const char *lv_s; switch (this->low_voltage_reference_) { @@ -27,7 +50,7 @@ void ESP32TouchComponent::setup() { case TOUCH_LVOLT_0V8: lv_s = "0.8V"; break; default: lv_s = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " Low Voltage Reference: %s", lv_s); + ESP_LOGCONFIG(TAG, " Low Voltage Reference: %s", lv_s); const char *hv_s; switch (this->high_voltage_reference_) { @@ -37,7 +60,7 @@ void ESP32TouchComponent::setup() { case TOUCH_HVOLT_2V7: hv_s = "2.7V"; break; default: hv_s = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " High Voltage Reference: %s", hv_s); + ESP_LOGCONFIG(TAG, " High Voltage Reference: %s", hv_s); const char *atten_s; switch (this->voltage_attenuation_) { @@ -47,39 +70,24 @@ void ESP32TouchComponent::setup() { case TOUCH_HVOLT_ATTEN_0V: atten_s = "0V"; break; default: atten_s = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); -#endif + ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); + if (this->iir_filter_enabled_()) { ESP_LOGCONFIG(TAG, " IIR Filter: %ums", this->iir_filter_); touch_pad_filter_start(this->iir_filter_); } else { - ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); + ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); } if (this->setup_mode_) { - ESP_LOGCONFIG(TAG, " Setup Mode ENABLED!"); + ESP_LOGCONFIG(TAG, " Setup Mode ENABLED!"); } - touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); - touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, - this->voltage_attenuation_); - for (auto *child : this->children_) { - // Disable interrupt threshold - touch_pad_config(child->get_touch_pad(), 0); - - ESP_LOGCONFIG(TAG, " Pad '%s'", child->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Touch Pad: T%d", child->get_touch_pad()); - ESP_LOGCONFIG(TAG, " Threshold: %u", child->get_threshold()); + ESP_LOGCONFIG(TAG, " Pad '%s'", child->get_name().c_str()); + ESP_LOGCONFIG(TAG, " Touch Pad: T%d", child->get_touch_pad()); + ESP_LOGCONFIG(TAG, " Threshold: %u", child->get_threshold()); } - - add_shutdown_hook([this](const char *cause) { - if (this->iir_filter_enabled_()) { - touch_pad_filter_stop(); - touch_pad_filter_delete(); - } - touch_pad_deinit(); - }); } void ESP32TouchComponent::loop() { diff --git a/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.h b/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.h index 1cb3a5a7..3d926790 100644 --- a/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.h +++ b/src/esphomelib/binary_sensor/esp32_touch_binary_sensor.h @@ -166,6 +166,7 @@ class ESP32TouchComponent : public Component { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/binary_sensor/filter.cpp b/src/esphomelib/binary_sensor/filter.cpp index b9878453..9d6be24a 100644 --- a/src/esphomelib/binary_sensor/filter.cpp +++ b/src/esphomelib/binary_sensor/filter.cpp @@ -22,6 +22,9 @@ optional DelayedOnFilter::new_value(bool value) { return false; } } +float DelayedOnFilter::get_setup_priority() const { + return setup_priority::HARDWARE; +} void Filter::output(bool value) { if (this->next_ == nullptr) { @@ -51,6 +54,9 @@ optional DelayedOffFilter::new_value(bool value) { return true; } } +float DelayedOffFilter::get_setup_priority() const { + return setup_priority::HARDWARE; +} optional InvertFilter::new_value(bool value) { return !value; @@ -82,6 +88,9 @@ void HeartbeatFilter::setup() { this->output(*this->value_); }); } +float HeartbeatFilter::get_setup_priority() const { + return setup_priority::HARDWARE; +} } // namespace binary_sensor ESPHOMELIB_NAMESPACE_END diff --git a/src/esphomelib/binary_sensor/filter.h b/src/esphomelib/binary_sensor/filter.h index c3ca4d81..72d567e9 100644 --- a/src/esphomelib/binary_sensor/filter.h +++ b/src/esphomelib/binary_sensor/filter.h @@ -34,6 +34,8 @@ class DelayedOnFilter : public Filter, public Component { optional new_value(bool value) override; + float get_setup_priority() const override; + protected: uint32_t delay_; }; @@ -44,6 +46,8 @@ class DelayedOffFilter : public Filter, public Component { optional new_value(bool value) override; + float get_setup_priority() const override; + protected: uint32_t delay_; }; @@ -56,6 +60,8 @@ class HeartbeatFilter : public Filter, public Component { void setup(); + float get_setup_priority() const override; + protected: uint32_t interval_; optional value_{}; diff --git a/src/esphomelib/binary_sensor/gpio_binary_sensor_component.cpp b/src/esphomelib/binary_sensor/gpio_binary_sensor_component.cpp index 531fbb98..5403a7c5 100644 --- a/src/esphomelib/binary_sensor/gpio_binary_sensor_component.cpp +++ b/src/esphomelib/binary_sensor/gpio_binary_sensor_component.cpp @@ -19,6 +19,11 @@ void GPIOBinarySensorComponent::setup() { this->publish_state(this->last_state_); } +void GPIOBinarySensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "GPIO Binary Sensor '%s':", this->name_.c_str()); + LOG_PIN(" Pin: ", this->pin_); +} + void GPIOBinarySensorComponent::loop() { bool new_state = this->pin_->digital_read(); if (this->last_state_ != new_state) { @@ -30,7 +35,6 @@ void GPIOBinarySensorComponent::loop() { float GPIOBinarySensorComponent::get_setup_priority() const { return setup_priority::HARDWARE; } - GPIOBinarySensorComponent::GPIOBinarySensorComponent(const std::string &name, GPIOPin *pin) : BinarySensor(name), pin_(pin) { diff --git a/src/esphomelib/binary_sensor/gpio_binary_sensor_component.h b/src/esphomelib/binary_sensor/gpio_binary_sensor_component.h index fbefa2de..c9c1bed4 100644 --- a/src/esphomelib/binary_sensor/gpio_binary_sensor_component.h +++ b/src/esphomelib/binary_sensor/gpio_binary_sensor_component.h @@ -29,6 +29,7 @@ class GPIOBinarySensorComponent : public BinarySensor, public Component { // (In most use cases you won't need these) /// Setup pin void setup() override; + void dump_config() override; /// Hardware priority float get_setup_priority() const override; /// Check sensor diff --git a/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.cpp b/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.cpp index 3b70e8c2..86471ca9 100644 --- a/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.cpp +++ b/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.cpp @@ -16,15 +16,17 @@ std::string MQTTBinarySensorComponent::component_type() const { } void MQTTBinarySensorComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT binary sensor '%s'...", this->binary_sensor_->get_name().c_str()); - if (!this->binary_sensor_->get_device_class().empty()) { - ESP_LOGCONFIG(TAG, " Device Class: '%s'", this->binary_sensor_->get_device_class().c_str()); - } - auto f = std::bind(&MQTTBinarySensorComponent::publish_state, this, std::placeholders::_1); this->binary_sensor_->add_on_state_callback(f); } +void MQTTBinarySensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Binary Sensor '%s':", this->binary_sensor_->get_name().c_str()); + if (!this->binary_sensor_->get_device_class().empty()) { + ESP_LOGCONFIG(TAG, " Device Class: '%s'", this->binary_sensor_->get_device_class().c_str()); + } + LOG_MQTT_COMPONENT(true, false) +} MQTTBinarySensorComponent::MQTTBinarySensorComponent(BinarySensor *binary_sensor) : MQTTComponent(), binary_sensor_(binary_sensor) { @@ -32,6 +34,7 @@ MQTTBinarySensorComponent::MQTTBinarySensorComponent(BinarySensor *binary_sensor std::string MQTTBinarySensorComponent::friendly_name() const { return this->binary_sensor_->get_name(); } + void MQTTBinarySensorComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) { if (!this->binary_sensor_->get_device_class().empty()) root["device_class"] = this->binary_sensor_->get_device_class(); @@ -41,7 +44,6 @@ void MQTTBinarySensorComponent::send_discovery(JsonObject &root, mqtt::SendDisco root["payload_off"] = mqtt::global_mqtt_client->get_availability().payload_not_available; config.command_topic = false; } - void MQTTBinarySensorComponent::send_initial_state() { if (this->binary_sensor_->has_state()) this->publish_state(this->binary_sensor_->state); diff --git a/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.h b/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.h index 4a043dd7..50295ba1 100644 --- a/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.h +++ b/src/esphomelib/binary_sensor/mqtt_binary_sensor_component.h @@ -30,6 +30,8 @@ class MQTTBinarySensorComponent : public mqtt::MQTTComponent { /// Send discovery. void setup() override; + void dump_config() override; + /// Send Home Assistant discovery info void send_discovery(JsonObject &obj, mqtt::SendDiscoveryConfig &config) override; diff --git a/src/esphomelib/binary_sensor/pn532_component.cpp b/src/esphomelib/binary_sensor/pn532_component.cpp index 9b32aec7..3bada92f 100644 --- a/src/esphomelib/binary_sensor/pn532_component.cpp +++ b/src/esphomelib/binary_sensor/pn532_component.cpp @@ -45,14 +45,14 @@ void PN532Component::setup() { this->buffer_[3] = 0x01; // use IRQ pin, actually we don't need it but can't hurt either if (!this->pn532_write_command_check_ack_(4)) { - ESP_LOGE(TAG, "Writing SAM command failed!"); + this->error_code_ = WRITING_SAM_COMMAND_FAILED; this->mark_failed(); return; } this->pn532_read_data_(8); if (this->buffer_[5] != 0x15) { - ESP_LOGE(TAG, "Reading SAM command result failed!"); + this->error_code_ = READING_SAM_COMMAND_FAILED; this->mark_failed(); return; } @@ -249,6 +249,21 @@ PN532Component::PN532Component(SPIComponent *parent, GPIOPin *cs, uint32_t updat bool PN532Component::msb_first() { return false; } +void PN532Component::dump_config() { + ESP_LOGCONFIG(TAG, "PN532:"); + switch (this->error_code_) { + case NONE:break; + case WRITING_SAM_COMMAND_FAILED: + ESP_LOGE(TAG, "Writing SAM command failed!"); + break; + case READING_SAM_COMMAND_FAILED: + ESP_LOGE(TAG, "Reading SAM command result failed!"); + break; + } + + LOG_PIN(" CS Pin: ", this->cs_); + LOG_UPDATE_INTERVAL(this); +} PN532BinarySensor::PN532BinarySensor(const std::string &name, const std::vector &uid, uint32_t update_interval) : BinarySensor(name), uid_(uid) { diff --git a/src/esphomelib/binary_sensor/pn532_component.h b/src/esphomelib/binary_sensor/pn532_component.h index 9872dbdb..4b64ffef 100644 --- a/src/esphomelib/binary_sensor/pn532_component.h +++ b/src/esphomelib/binary_sensor/pn532_component.h @@ -23,6 +23,8 @@ class PN532Component : public PollingComponent, public SPIDevice { void setup() override; + void dump_config() override; + void update() override; float get_setup_priority() const override; @@ -48,6 +50,11 @@ class PN532Component : public PollingComponent, public SPIDevice { std::vector binary_sensors_; std::vector triggers_; std::vector last_uid_; + enum PN532Error { + NONE = 0, + WRITING_SAM_COMMAND_FAILED, + READING_SAM_COMMAND_FAILED, + } error_code_{NONE}; }; class PN532BinarySensor : public binary_sensor::BinarySensor { diff --git a/src/esphomelib/binary_sensor/rdm6300.cpp b/src/esphomelib/binary_sensor/rdm6300.cpp index 7eec59e9..0cc4480c 100644 --- a/src/esphomelib/binary_sensor/rdm6300.cpp +++ b/src/esphomelib/binary_sensor/rdm6300.cpp @@ -74,9 +74,6 @@ void RDM6300Component::loop() { RDM6300BinarySensor *RDM6300Component::make_card(const std::string &name, uint32_t id) { return new RDM6300BinarySensor(name, id); } -void RDM6300Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up RDM6300..."); -} float RDM6300Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/binary_sensor/rdm6300.h b/src/esphomelib/binary_sensor/rdm6300.h index e23d27c2..4d0cd470 100644 --- a/src/esphomelib/binary_sensor/rdm6300.h +++ b/src/esphomelib/binary_sensor/rdm6300.h @@ -22,7 +22,6 @@ class RDM6300Component : public Component, public UARTDevice { RDM6300BinarySensor *make_card(const std::string &name, uint32_t id); - void setup() override; float get_setup_priority() const override; protected: diff --git a/src/esphomelib/component.cpp b/src/esphomelib/component.cpp index 788ccfce..fd3b8b6d 100644 --- a/src/esphomelib/component.cpp +++ b/src/esphomelib/component.cpp @@ -14,9 +14,9 @@ namespace setup_priority { const float PRE_HARDWARE = 110.0f; const float HARDWARE = 100.0f; const float POST_HARDWARE = 90.0f; +const float HARDWARE_LATE = 50.0f; const float WIFI = 10.0f; const float MQTT_CLIENT = 7.5f; -const float HARDWARE_LATE = 0.0f; const float MQTT_COMPONENT = -5.0f; const float LATE = -10.0f; @@ -51,6 +51,7 @@ void Component::loop() { } void Component::set_interval(const std::string &name, uint32_t interval, std::function &&f) { + const uint32_t now = millis(); // only put offset in lower half uint32_t offset = 0; if (interval != 0) @@ -62,7 +63,7 @@ void Component::set_interval(const std::string &name, uint32_t interval, std::fu .name = name, .type = TimeFunction::INTERVAL, .interval = interval, - .last_execution = millis() - interval - offset, + .last_execution = now - interval - offset, .f = std::move(f), .remove = false, }; @@ -74,6 +75,7 @@ bool Component::cancel_interval(const std::string &name) { } void Component::set_timeout(const std::string &name, uint32_t timeout, std::function &&f) { + const uint32_t now = millis(); ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout); this->cancel_timeout(name); @@ -81,7 +83,7 @@ void Component::set_timeout(const std::string &name, uint32_t timeout, std::func .name = name, .type = TimeFunction::TIMEOUT, .interval = timeout, - .last_execution = millis(), + .last_execution = now, .f = std::move(f), .remove = false, }; @@ -117,8 +119,6 @@ uint32_t Component::get_component_state() const { return this->component_state_; } void Component::loop_internal() { - assert((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_SETUP || - (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP); this->component_state_ &= ~COMPONENT_STATE_MASK; this->component_state_ |= COMPONENT_STATE_LOOP; @@ -154,7 +154,6 @@ void Component::loop_internal() { ); } void Component::setup_internal() { - assert((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_CONSTRUCTION); this->component_state_ &= ~COMPONENT_STATE_MASK; this->component_state_ |= COMPONENT_STATE_SETUP; } @@ -224,6 +223,15 @@ void Component::status_momentary_error(const std::string &name, uint32_t length) this->status_clear_error(); }); } +void Component::dump_config() { + +} +float Component::get_actual_setup_priority() const { + return this->setup_priority_override_.value_or(this->get_setup_priority()); +} +void Component::set_setup_priority(float priority) { + this->setup_priority_override_ = priority; +} PollingComponent::PollingComponent(uint32_t update_interval) : Component(), update_interval_(update_interval) {} @@ -236,7 +244,6 @@ void PollingComponent::setup_() { this->setup(); // Register interval. - ESP_LOGCONFIG(TAG, " Update interval: %ums", this->get_update_interval()); this->set_interval("update", this->get_update_interval(), [this]() { this->update(); }); } diff --git a/src/esphomelib/component.h b/src/esphomelib/component.h index 8ab0ce99..c0748ef3 100644 --- a/src/esphomelib/component.h +++ b/src/esphomelib/component.h @@ -2,9 +2,9 @@ #define ESPHOMELIB_COMPONENT_H #include -#include #include #include "esphomelib/defines.h" +#include "esphomelib/helpers.h" ESPHOMELIB_NAMESPACE_BEGIN @@ -14,9 +14,9 @@ namespace setup_priority { extern const float PRE_HARDWARE; ///< only for internal components that are necessary for hardware component initialization (like i2c bus) extern const float HARDWARE; ///< for hardware initialization, but only where it's really necessary (like outputs) extern const float POST_HARDWARE; +extern const float HARDWARE_LATE; extern const float WIFI; ///< for WiFi initialization extern const float MQTT_CLIENT; ///< for the MQTT client initialization -extern const float HARDWARE_LATE; extern const float MQTT_COMPONENT; ///< for MQTT component initialization extern const float LATE; @@ -34,6 +34,8 @@ extern const uint32_t STATUS_LED_ERROR; extern uint32_t global_state; +#define LOG_UPDATE_INTERVAL(this) ESP_LOGCONFIG(TAG, " Update Interval: %u", this->get_update_interval()); + /** The base class for all esphomelib components. * * esphomelib uses components to separate code for self-contained units such as @@ -67,6 +69,8 @@ class Component { */ virtual void loop(); + virtual void dump_config(); + /** priority of setup(). higher -> executed earlier * * Defaults to 0. @@ -75,6 +79,10 @@ class Component { */ virtual float get_setup_priority() const; + float get_actual_setup_priority() const; + + void set_setup_priority(float priority); + /** priority of loop(). higher -> executed earlier * * Defaults to 0. @@ -220,6 +228,7 @@ class Component { std::vector time_functions_; uint32_t component_state_{0x0000}; ///< State of this component. + optional setup_priority_override_; }; /** This class simplifies creating components that periodically check a state. diff --git a/src/esphomelib/cover/mqtt_cover_component.cpp b/src/esphomelib/cover/mqtt_cover_component.cpp index e9e54267..2184892d 100644 --- a/src/esphomelib/cover/mqtt_cover_component.cpp +++ b/src/esphomelib/cover/mqtt_cover_component.cpp @@ -13,11 +13,6 @@ static const char *TAG = "cover.mqtt"; MQTTCoverComponent::MQTTCoverComponent(Cover *cover) : cover_(cover) {} void MQTTCoverComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT cover '%s'...", this->friendly_name().c_str()); - if (this->cover_->optimistic()) { - ESP_LOGCONFIG(TAG, " Optimistic: YES"); - } - this->cover_->add_on_publish_state_callback([this](CoverState state) { this->publish_state(state); }); @@ -37,14 +32,21 @@ void MQTTCoverComponent::setup() { }); } +void MQTTCoverComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT cover '%s':", this->cover_->get_name().c_str()); + if (this->cover_->optimistic()) { + ESP_LOGCONFIG(TAG, " Optimistic: YES"); + } + LOG_MQTT_COMPONENT(true, true) +} void MQTTCoverComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) { if (this->cover_->optimistic()) root["optimistic"] = true; } + std::string MQTTCoverComponent::component_type() const { return "cover"; } - std::string MQTTCoverComponent::friendly_name() const { return this->cover_->get_name(); } diff --git a/src/esphomelib/cover/mqtt_cover_component.h b/src/esphomelib/cover/mqtt_cover_component.h index f4ab02a8..320b387d 100644 --- a/src/esphomelib/cover/mqtt_cover_component.h +++ b/src/esphomelib/cover/mqtt_cover_component.h @@ -24,6 +24,8 @@ class MQTTCoverComponent : public mqtt::MQTTComponent { void publish_state(cover::CoverState state); + void dump_config() override; + protected: std::string component_type() const override; std::string friendly_name() const override; diff --git a/src/esphomelib/deep_sleep_component.cpp b/src/esphomelib/deep_sleep_component.cpp index 2e9652d1..f47e18b1 100644 --- a/src/esphomelib/deep_sleep_component.cpp +++ b/src/esphomelib/deep_sleep_component.cpp @@ -14,20 +14,27 @@ static const char *TAG = "deep_sleep"; void DeepSleepComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); - if (this->sleep_duration_.has_value()) - ESP_LOGCONFIG(TAG, " Sleep Duration: %llu ms", *this->sleep_duration_ / 1000); if (this->run_duration_.has_value()) + this->set_timeout(*this->run_duration_, [this](){ + this->begin_sleep_(); + }); +} +void DeepSleepComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); + if (this->sleep_duration_.has_value()) { + ESP_LOGCONFIG(TAG, " Sleep Duration: %llu ms", *this->sleep_duration_ / 1000); + } + if (this->run_duration_.has_value()) { ESP_LOGCONFIG(TAG, " Run Duration: %u ms", *this->run_duration_); - if (this->loop_cycles_.has_value()) + } + if (this->loop_cycles_.has_value()) { ESP_LOGCONFIG(TAG, " Loop Cycles: %u", *this->loop_cycles_); + } #ifdef ARDUINO_ARCH_ESP32 - if (this->wakeup_pin_.has_value()) - ESP_LOGCONFIG(TAG, " Wakeup Pin: %u %s", (*this->wakeup_pin_)->get_pin(), (*this->wakeup_pin_)->is_inverted() ? "LOW" : "HIGH"); + if (this->wakeup_pin_.has_value()) { + LOG_PIN(" Wakeup Pin: ", *this->wakeup_pin_); + } #endif - if (this->run_duration_.has_value()) - this->set_timeout(*this->run_duration_, [this](){ - this->begin_sleep_(); - }); } void DeepSleepComponent::loop() { if (this->loop_cycles_.has_value()) { diff --git a/src/esphomelib/deep_sleep_component.h b/src/esphomelib/deep_sleep_component.h index 880c959a..1ed9f8da 100644 --- a/src/esphomelib/deep_sleep_component.h +++ b/src/esphomelib/deep_sleep_component.h @@ -58,6 +58,7 @@ class DeepSleepComponent : public Component { void set_run_duration(uint32_t time_ms); void setup() override; + void dump_config() override; void loop() override; float get_loop_priority() const override; float get_setup_priority() const override; diff --git a/src/esphomelib/display/display.cpp b/src/esphomelib/display/display.cpp index 53e3bd26..3c372aef 100644 --- a/src/esphomelib/display/display.cpp +++ b/src/esphomelib/display/display.cpp @@ -303,6 +303,19 @@ void DisplayBuffer::do_update() { (*this->writer_)(*this); } } +const char *DisplayBuffer::rotation_str_() { + switch (this->rotation_) { + case DISPLAY_ROTATION_90_DEGREES: + return "90°"; + case DISPLAY_ROTATION_180_DEGREES: + return "180°"; + case DISPLAY_ROTATION_270_DEGREES: + return "270°"; + case DISPLAY_ROTATION_0_DEGREES: + default: + return "0°"; + } +} #ifdef USE_TIME void DisplayBuffer::strftime(int x, int y, Font *font, int color, TextAlign align, const char *format, time::EsphomelibTime time) { diff --git a/src/esphomelib/display/display.h b/src/esphomelib/display/display.h index a58c8bca..f5373588 100644 --- a/src/esphomelib/display/display.h +++ b/src/esphomelib/display/display.h @@ -287,6 +287,8 @@ class DisplayBuffer { void do_update(); + const char *rotation_str_(); + uint8_t *buffer_{nullptr}; DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES}; optional writer_{}; diff --git a/src/esphomelib/display/lcd_display.cpp b/src/esphomelib/display/lcd_display.cpp index a2032142..211a4526 100644 --- a/src/esphomelib/display/lcd_display.cpp +++ b/src/esphomelib/display/lcd_display.cpp @@ -195,6 +195,19 @@ void GPIOLCDDisplay::setup() { } LCDDisplay::setup(); } +void GPIOLCDDisplay::dump_config() { + ESP_LOGCONFIG(TAG, "GPIO LCD Display:"); + ESP_LOGCONFIG(TAG, " Columns: %u, Rows: %u", this->columns_, this->rows_); + LOG_PIN(" RS Pin: ", this->rs_pin_); + LOG_PIN(" RW Pin: ", this->rw_pin_); + LOG_PIN(" Enable Pin: ", this->enable_pin_); + + for (uint8_t i = 0; i < (this->is_four_bit_mode_() ? 4 : 8); i++) { + ESP_LOGCONFIG(TAG, " Data Pin %u" LOG_PIN_PATTERN, i, LOG_PIN_ARGS(this->data_pins_[i])); + } + + LOG_UPDATE_INTERVAL(this); +} void GPIOLCDDisplay::set_data_pins(const GPIOOutputPin &d0, const GPIOOutputPin &d1, const GPIOOutputPin &d2, @@ -258,15 +271,23 @@ GPIOLCDDisplay::GPIOLCDDisplay(uint8_t columns, uint8_t rows, uint32_t update_in #ifdef USE_LCD_DISPLAY_PCF8574 void PCF8574LCDDisplay::setup() { - ESP_LOGCONFIG(TAG, "Setting up PCF8574 LCD Display with address=0x%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up PCF8574 LCD Display..."); if (!this->write_bytes(0x08, nullptr, 0)) { - ESP_LOGE(TAG, "Communication with PCF6574 LCD Display failed!"); this->mark_failed(); return; } LCDDisplay::setup(); } +void PCF8574LCDDisplay::dump_config() { + ESP_LOGCONFIG(TAG, "PCF8574 LCD Display:"); + ESP_LOGCONFIG(TAG, " Columns: %u, Rows: %u", this->columns_, this->rows_); + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with LCD Display failed!"); + } +} bool PCF8574LCDDisplay::is_four_bit_mode_() { return true; } diff --git a/src/esphomelib/display/lcd_display.h b/src/esphomelib/display/lcd_display.h index 1bb702eb..11a5b05e 100644 --- a/src/esphomelib/display/lcd_display.h +++ b/src/esphomelib/display/lcd_display.h @@ -78,6 +78,7 @@ class GPIOLCDDisplay : public LCDDisplay { void set_enable_pin(const GPIOOutputPin &enable); void set_rs_pin(const GPIOOutputPin &rs); void set_rw_pin(const GPIOOutputPin &rw); + void dump_config() override; protected: bool is_four_bit_mode_() override; void write_n_bits(uint8_t value, uint8_t n) override; @@ -93,6 +94,7 @@ class PCF8574LCDDisplay : public LCDDisplay, public I2CDevice { public: PCF8574LCDDisplay(I2CComponent *parent, uint8_t columns, uint8_t rows, uint8_t address = 0x3F, uint32_t update_interval = 1000); void setup() override; + void dump_config() override; protected: bool is_four_bit_mode_() override; void write_n_bits(uint8_t value, uint8_t n) override; diff --git a/src/esphomelib/display/max7219.cpp b/src/esphomelib/display/max7219.cpp index 4d047e1b..dab6fcab 100644 --- a/src/esphomelib/display/max7219.cpp +++ b/src/esphomelib/display/max7219.cpp @@ -123,7 +123,6 @@ float MAX7219Component::get_setup_priority() const { void MAX7219Component::setup() { ESP_LOGCONFIG(TAG, "Setting up MAX7219..."); this->spi_setup(); - ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_); this->buffer_ = new uint8_t[this->num_chips_ * 8]; for (uint8_t i = 0; i < this->num_chips_ * 8; i++) this->buffer_[i] = 0; @@ -137,6 +136,13 @@ void MAX7219Component::setup() { // power up this->send_to_all_(MAX7219_REGISTER_SHUTDOWN, 1); } +void MAX7219Component::dump_config() { + ESP_LOGCONFIG(TAG, "MAX7219:"); + ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_); + ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_); + LOG_PIN(" CS Pin: ", this->cs_); + LOG_UPDATE_INTERVAL(this); +} void MAX7219Component::display() { for (uint8_t i = 0; i < 8; i++) { diff --git a/src/esphomelib/display/max7219.h b/src/esphomelib/display/max7219.h index a1c99c3b..f96f1a3a 100644 --- a/src/esphomelib/display/max7219.h +++ b/src/esphomelib/display/max7219.h @@ -27,6 +27,8 @@ class MAX7219Component : public PollingComponent, public SPIDevice { void setup() override; + void dump_config() override; + void update() override; float get_setup_priority() const override; diff --git a/src/esphomelib/display/ssd1306.cpp b/src/esphomelib/display/ssd1306.cpp index a65934eb..ec0b394c 100644 --- a/src/esphomelib/display/ssd1306.cpp +++ b/src/esphomelib/display/ssd1306.cpp @@ -225,6 +225,19 @@ void SSD1306::init_reset_() { this->reset_pin_->digital_write(true); } } +const char *SSD1306::model_str_() { + switch (this->model_) { + case SSD1306_MODEL_128_32: return "SSD1306 128x32"; + case SSD1306_MODEL_128_64: return "SSD1306 128x64"; + case SSD1306_MODEL_96_16: return "SSD1306 96x16"; + case SSD1306_MODEL_64_48: return "SSD1306 64x48"; + case SH1106_MODEL_128_32: return "SH1106 128x32"; + case SH1106_MODEL_128_64: return "SH1106 128x64"; + case SH1106_MODEL_96_16: return "SH1106 96x16"; + case SH1106_MODEL_64_48: return "SH1106 64x48"; + default: return "Unknown"; + } +} #ifdef USE_SPI bool SPISSD1306::msb_first() { @@ -238,6 +251,16 @@ void SPISSD1306::setup() { this->init_reset_(); SSD1306::setup(); } +void SPISSD1306::dump_config() { + ESP_LOGCONFIG(TAG, "SPI SSD1306:"); + ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); + LOG_PIN(" CS Pin: ", this->cs_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + ESP_LOGCONFIG(TAG, " External VCC: %s", YESNO(this->external_vcc_)); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_UPDATE_INTERVAL(this); +} void SPISSD1306::command(uint8_t value) { this->dc_pin_->digital_write(false); this->enable(); @@ -277,18 +300,30 @@ bool SPISSD1306::high_speed() { #ifdef USE_I2C void I2CSSD1306::setup() { ESP_LOGCONFIG(TAG, "Setting up I2C SSD1306..."); - this->init_reset_(); this->parent_->begin_transmission_(this->address_); if (!this->parent_->end_transmission_(this->address_)) { - ESP_LOGE(TAG, "Communication with SSD1306 failed!"); + this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; } SSD1306::setup(); } +void I2CSSD1306::dump_config() { + ESP_LOGCONFIG(TAG, "I2C SSD1306:"); + LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Model: %s", this->model_str_()); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + ESP_LOGCONFIG(TAG, " External VCC: %s", YESNO(this->external_vcc_)); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_UPDATE_INTERVAL(this); + + if (this->error_code_ == COMMUNICATION_FAILED) { + ESP_LOGE(TAG, "Communication with SSD1306 failed!"); + } +} void I2CSSD1306::command(uint8_t value) { this->write_byte(0x00, value); } diff --git a/src/esphomelib/display/ssd1306.h b/src/esphomelib/display/ssd1306.h index 43eda84a..52907239 100644 --- a/src/esphomelib/display/ssd1306.h +++ b/src/esphomelib/display/ssd1306.h @@ -53,6 +53,7 @@ class SSD1306 : public PollingComponent, public DisplayBuffer { int get_height_internal_() override; int get_width_internal_() override; size_t get_buffer_length_(); + const char *model_str_(); SSD1306Model model_{SSD1306_MODEL_128_64}; GPIOPin *reset_pin_{nullptr}; @@ -66,6 +67,8 @@ class SPISSD1306 : public SSD1306, public SPIDevice { void setup() override; + void dump_config() override; + protected: void command(uint8_t value) override; @@ -82,9 +85,15 @@ class I2CSSD1306 : public SSD1306, public I2CDevice { public: I2CSSD1306(I2CComponent *parent, uint32_t update_interval = 1000); void setup() override; + void dump_config() override; protected: void command(uint8_t value) override; void write_display_data() override; + + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED + } error_code_{NONE}; }; #endif diff --git a/src/esphomelib/display/waveshare_epaper.cpp b/src/esphomelib/display/waveshare_epaper.cpp index 6bad83bb..0552605d 100644 --- a/src/esphomelib/display/waveshare_epaper.cpp +++ b/src/esphomelib/display/waveshare_epaper.cpp @@ -169,6 +169,26 @@ void WaveshareEPaperTypeA::setup() { this->command(WAVESHARE_EPAPER_COMMAND_DATA_ENTRY_MODE_SETTING); this->data(0x03); // from top left to bottom right } +void WaveshareEPaperTypeA::dump_config() { + ESP_LOGCONFIG(TAG, "Waveshare E-Paper:"); + switch (this->model_) { + case WAVESHARE_EPAPER_1_54_IN: + ESP_LOGCONFIG(TAG, " Model: 1.54in"); + break; + case WAVESHARE_EPAPER_2_13_IN: + ESP_LOGCONFIG(TAG, " Model: 2.13in"); + break; + case WAVESHARE_EPAPER_2_9_IN: + ESP_LOGCONFIG(TAG, " Model: 2.9in"); + break; + } + ESP_LOGCONFIG(TAG, " Full Update Every: %u", this->full_update_every_); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} void HOT WaveshareEPaperTypeA::display() { if (!this->wait_until_idle_()) { this->status_set_warning(); @@ -436,6 +456,15 @@ int WaveshareEPaper2P7In::get_height_internal_() { } WaveshareEPaper2P7In::WaveshareEPaper2P7In(SPIComponent *parent, GPIOPin *cs, GPIOPin *dc_pin, uint32_t update_interval) : WaveshareEPaper(parent, cs, dc_pin, update_interval) {} +void WaveshareEPaper2P7In::dump_config() { + ESP_LOGCONFIG(TAG, "Waveshare E-Paper:"); + ESP_LOGCONFIG(TAG, " Model: 2.7in"); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} static const uint8_t LUT_VCOM_DC_4_2[] = { 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, @@ -560,6 +589,15 @@ int WaveshareEPaper4P2In::get_height_internal_() { } WaveshareEPaper4P2In::WaveshareEPaper4P2In(SPIComponent *parent, GPIOPin *cs, GPIOPin *dc_pin, uint32_t update_interval) : WaveshareEPaper(parent, cs, dc_pin, update_interval) {} +void WaveshareEPaper4P2In::dump_config() { + ESP_LOGCONFIG(TAG, "Waveshare E-Paper:"); + ESP_LOGCONFIG(TAG, " Model: 4.2in"); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} void WaveshareEPaper7P5In::setup() { this->setup_pins(); @@ -639,6 +677,15 @@ int WaveshareEPaper7P5In::get_height_internal_() { } WaveshareEPaper7P5In::WaveshareEPaper7P5In(SPIComponent *parent, GPIOPin *cs, GPIOPin *dc_pin, uint32_t update_interval) : WaveshareEPaper(parent, cs, dc_pin, update_interval) {} +void WaveshareEPaper7P5In::dump_config() { + ESP_LOGCONFIG(TAG, "Waveshare E-Paper:"); + ESP_LOGCONFIG(TAG, " Model: 7.5in"); + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_str_()); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} } // namespace display diff --git a/src/esphomelib/display/waveshare_epaper.h b/src/esphomelib/display/waveshare_epaper.h index 0b779bd2..6415087a 100644 --- a/src/esphomelib/display/waveshare_epaper.h +++ b/src/esphomelib/display/waveshare_epaper.h @@ -57,6 +57,8 @@ class WaveshareEPaperTypeA : public WaveshareEPaper { void setup() override; + void dump_config() override; + void display() override; void set_full_update_every(uint32_t full_update_every); @@ -86,6 +88,8 @@ class WaveshareEPaper2P7In : public WaveshareEPaper { void display() override; + void dump_config() override; + protected: int get_width_internal_() override; @@ -99,6 +103,8 @@ class WaveshareEPaper4P2In : public WaveshareEPaper { void display() override; + void dump_config() override; + protected: int get_width_internal_() override; @@ -112,6 +118,8 @@ class WaveshareEPaper7P5In : public WaveshareEPaper { void display() override; + void dump_config() override; + protected: int get_width_internal_() override; diff --git a/src/esphomelib/esp32_ble_tracker.cpp b/src/esphomelib/esp32_ble_tracker.cpp index a6409c96..eb7e8b9f 100644 --- a/src/esphomelib/esp32_ble_tracker.cpp +++ b/src/esphomelib/esp32_ble_tracker.cpp @@ -59,15 +59,20 @@ XiaomiDevice *ESP32BLETracker::make_xiaomi_device(std::array address void ESP32BLETracker::setup() { global_esp32_ble_tracker = this; - xTaskCreatePinnedToCore( - ESP32BLETracker::ble_core_task, - "ble_task", // name - 10000, // stack size (in words) - nullptr, // input params - 1, // priority - nullptr, // Handle, not needed - 0 // core - ); + if (!ESP32BLETracker::ble_setup()) { + this->mark_failed(); + return; + } + + global_esp32_ble_tracker->start_scan(true); +} + +void ESP32BLETracker::loop() { + auto ret = xSemaphoreTake(semaphore_scan_end, 0L); + if (ret) { + xSemaphoreGive(semaphore_scan_end); + global_esp32_ble_tracker->start_scan(false); + } } void ESP32BLETracker::ble_core_task(void *params) { @@ -78,20 +83,20 @@ void ESP32BLETracker::ble_core_task(void *params) { } } -void ESP32BLETracker::ble_setup() { +bool ESP32BLETracker::ble_setup() { semaphore_scan_end = xSemaphoreCreateMutex(); // Initialize non-volatile storage for the bluetooth controller esp_err_t err = nvs_flash_init(); if (err != ESP_OK) { ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); - return; + return false; } // Initialize the bluetooth controller with the default configuration if (!btStart()) { ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); - return; + return false; } esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); @@ -99,17 +104,17 @@ void ESP32BLETracker::ble_setup() { err = esp_bluedroid_init(); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err); - return; + return false; } err = esp_bluedroid_enable(); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err); - return; + return false; } err = esp_ble_gap_register_callback(ESP32BLETracker::gap_event_handler); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err); - return; + return false; } // Empty name @@ -119,21 +124,13 @@ void ESP32BLETracker::ble_setup() { err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err); - return; + return false; } // BLE takes some time to be fully set up, 200ms should be more than enough delay(200); - bool first = true; - - while (true) { - global_esp32_ble_tracker->start_scan(first); - first = false; - // wait for result - xSemaphoreTake(semaphore_scan_end, portMAX_DELAY); - xSemaphoreGive(semaphore_scan_end); - } + return true; } void ESP32BLETracker::start_scan(bool first) { diff --git a/src/esphomelib/esp32_ble_tracker.h b/src/esphomelib/esp32_ble_tracker.h index bd4f7de9..a4dd63a8 100644 --- a/src/esphomelib/esp32_ble_tracker.h +++ b/src/esphomelib/esp32_ble_tracker.h @@ -86,12 +86,14 @@ class ESP32BLETracker : public Component { /// Setup the FreeRTOS task and the Bluetooth stack. void setup() override; + void loop() override; + uint32_t get_scan_interval() const; protected: static void ble_core_task(void *params); /// The FreeRTOS task managing the bluetooth interface. - static void ble_setup(); + static bool ble_setup(); /// Start a single scan by setting up the parameters and doing some esp-idf calls. void start_scan(bool first); /// Callback that will handle all GAP events and redistribute them to other callbacks. diff --git a/src/esphomelib/esp_one_wire.cpp b/src/esphomelib/esp_one_wire.cpp index 51de7839..7559bb34 100644 --- a/src/esphomelib/esp_one_wire.cpp +++ b/src/esphomelib/esp_one_wire.cpp @@ -209,6 +209,9 @@ std::vector ESPOneWire::search_vec() { void ESPOneWire::skip() { this->write8(0xCC); // skip ROM } +GPIOPin *ESPOneWire::get_pin() { + return this->pin_; +} ESPHOMELIB_NAMESPACE_END diff --git a/src/esphomelib/esp_one_wire.h b/src/esphomelib/esp_one_wire.h index 612c17d7..1d935eca 100644 --- a/src/esphomelib/esp_one_wire.h +++ b/src/esphomelib/esp_one_wire.h @@ -64,6 +64,8 @@ class ESPOneWire { /// Helper that wraps search in a std::vector. std::vector search_vec(); + GPIOPin *get_pin(); + protected: /// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer. inline uint8_t *rom_number8_() { return reinterpret_cast(&this->rom_number); } diff --git a/src/esphomelib/esphal.cpp b/src/esphomelib/esphal.cpp index cd055b9e..470a71c2 100644 --- a/src/esphomelib/esphal.cpp +++ b/src/esphomelib/esphal.cpp @@ -24,10 +24,9 @@ GPIOPin::GPIOPin(uint8_t pin, uint8_t mode, bool inverted) } -void print_pin_mode(uint8_t pin, uint8_t mode) { -#ifdef ESPHOMELIB_LOG_HAS_CONFIG +const char *GPIOPin::get_pin_mode_name() const { const char *mode_s; - switch (mode) { + switch (this->mode_) { case INPUT: mode_s = "INPUT"; break; case OUTPUT: mode_s = "OUTPUT"; break; case INPUT_PULLUP: mode_s = "INPUT_PULLUP"; break; @@ -56,8 +55,8 @@ void print_pin_mode(uint8_t pin, uint8_t mode) { default: mode_s = "UNKNOWN"; break; } - ESP_LOGCONFIG(TAG, " GPIO Pin %u with mode %s", pin, mode_s); -#endif + + return mode_s; } unsigned char GPIOPin::get_pin() const { @@ -71,7 +70,6 @@ bool GPIOPin::is_inverted() const { return this->inverted_; } void GPIOPin::setup() { - print_pin_mode(this->pin_, this->mode_); this->pin_mode(this->mode_); } bool ICACHE_RAM_ATTR HOT GPIOPin::digital_read() { diff --git a/src/esphomelib/esphal.h b/src/esphomelib/esphal.h index 74df692a..d9754aaa 100644 --- a/src/esphomelib/esphal.h +++ b/src/esphomelib/esphal.h @@ -22,6 +22,10 @@ ESPHOMELIB_NAMESPACE_BEGIN +#define LOG_PIN(prefix, pin) if (pin != nullptr) {ESP_LOGCONFIG(TAG, prefix LOG_PIN_PATTERN, LOG_PIN_ARGS(pin));} +#define LOG_PIN_PATTERN "GPIO%u (Mode: %s%s)" +#define LOG_PIN_ARGS(pin) (pin)->get_pin(), (pin)->get_pin_mode_name(), ((pin)->is_inverted() ? ", INVERTED" : "") + /** A high-level abstraction class that can expose a pin together with useful options like pinMode. * * Set the parameters for this at construction time and use setup() to apply them. The inverted parameter will @@ -52,6 +56,7 @@ class GPIOPin { /// Get the GPIO pin number. uint8_t get_pin() const; + const char *get_pin_mode_name() const; /// Get the pinMode of this pin. uint8_t get_mode() const; /// Return whether this pin shall be treated as inverted. (for example active-low) diff --git a/src/esphomelib/esppreferences.cpp b/src/esphomelib/esppreferences.cpp index 02d112e6..4798aa83 100644 --- a/src/esphomelib/esppreferences.cpp +++ b/src/esphomelib/esppreferences.cpp @@ -10,98 +10,176 @@ ESPHOMELIB_NAMESPACE_BEGIN static const char *TAG = "preferences"; ESPPreferenceObject::ESPPreferenceObject() - : rtc_offset_(0), length_(0), type_(0), data_(nullptr) { + : 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_(length), type_(type) { - this->length_ = ((this->length_ + 3) / 4) * 4; - this->data_ = new uint32_t[this->total_length_uint()]; - for (uint32_t i = 0; i < this->total_length_uint(); i++) + : rtc_offset_(rtc_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; } -uint32_t &ESPPreferenceObject::operator[](int i) { - if (!this->is_initialized()) - return this->type_; - return this->data()[i]; -} -bool ESPPreferenceObject::load() { +bool ESPPreferenceObject::load_() { if (!this->is_initialized()) { ESP_LOGV(TAG, "Load Pref Not initialized!"); return false; } - this->load_internal_(); - bool valid = this->data_[0] == this->type_ && - this->data_[this->total_length_uint() - 1] == this->calculate_crc_(); + if (!this->load_internal_()) + return false; - ESP_LOGVV(TAG, "LOAD %u: valid=%d, 0=%u 1=%u 2=%u (Type=%u, CRC=%u)", - this->rtc_offset_, valid ? 1:0, this->data_[0], this->data_[1], this->data_[2], + bool valid = this->data_[this->length_words_] == this->calculate_crc_(); + + ESP_LOGVV(TAG, "LOAD %u: valid=%s, 0=%u 1=%u (Type=%u, CRC=%u)", + this->rtc_offset_, YESNO(valid), this->data_[0], this->data_[1], this->type_, this->calculate_crc_()); return valid; } -void ESPPreferenceObject::save() { +bool ESPPreferenceObject::save_() { if (!this->is_initialized()) { ESP_LOGV(TAG, "Save Pref Not initialized!"); - return; + return false; } - this->data_[0] = this->type_; - this->data_[this->total_length_uint() - 1] = this->calculate_crc_(); - this->save_internal_(); - ESP_LOGVV(TAG, "SAVE %u: 0=%u 1=%u 2=%u (Type=%u, CRC=%u)", - this->rtc_offset_, this->data_[0], this->data_[1], this->data_[2], + this->data_[this->length_words_] = this->calculate_crc_(); + if (!this->save_internal_()) + return false; + ESP_LOGVV(TAG, "SAVE %u: 0=%u 1=%u (Type=%u, CRC=%u)", + this->rtc_offset_, this->data_[0], this->data_[1], this->type_, this->calculate_crc_()); + return true; } #ifdef ARDUINO_ARCH_ESP8266 -void ESPPreferenceObject::save_internal_() { - ESP.rtcUserMemoryWrite(this->rtc_offset_, this->data_, this->total_length_bytes()); + +#define ESP_RTC_USER_MEM_START 0x60001200 +#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START) +#define ESP_RTC_USER_MEM_SIZE_WORDS 128 + +static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) { + if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) { + return false; + } + *dest = ESP_RTC_USER_MEM[index]; + return true; +} + +static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) { + if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) { + return false; + } + if (index < 32 && global_preferences.is_prevent_write()) { + return false; + } + + ESP_RTC_USER_MEM[index] = value; + return true; } -void ESPPreferenceObject::load_internal_() { - ESP.rtcUserMemoryRead(this->rtc_offset_, this->data_, this->total_length_bytes()); + +bool ESPPreferenceObject::save_internal_() { + for (uint32_t i = 0; i <= this->length_words_; i++) { + if (!esp_rtc_user_mem_write(this->rtc_offset_ + i, this->data_[i])) + return false; + } + return true; +} +bool ESPPreferenceObject::load_internal_() { + for (uint32_t i = 0; i <= this->length_words_; i++) { + if (!esp_rtc_user_mem_read(this->rtc_offset_ + i, &this->data_[i])) + return false; + } + return true; } +ESPPreferences::ESPPreferences() + // offset starts from start of user RTC mem (64 words before that are reserved for system), + // an additional 32 words at the start of user RTC are for eboot (OTA, see eboot_command.h), + // which will be reset each time OTA occurs + : current_offset_(0) { + +} + void ESPPreferences::begin(const std::string &name) { } + +ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type) { + uint32_t start = this->current_offset_; + uint32_t end = start + length + 1; + bool in_normal = start < 96; + // Normal: offset 0-95 maps to RTC offset 32 - 127, + // Eboot: offset 96-127 maps to RTC offset 0 - 31 words + if (in_normal && end > 96) { + // start is in normal but end is not -> switch to Eboot + this->current_offset_ = start = 96; + end = start + length + 1; + in_normal = false; + } + + if (end > 128) { + // Doesn't fit in data, return uninitialized preference obj. + return ESPPreferenceObject(); + } + + uint32_t rtc_offset; + if (in_normal) { + rtc_offset = start + 32; + } else { + rtc_offset = start - 96; + } + + auto pref = ESPPreferenceObject(rtc_offset, length, type); + this->current_offset_ += length + 1; + return pref; +} +void ESPPreferences::prevent_write(bool prevent) { + this->prevent_write_ = prevent; +} +bool ESPPreferences::is_prevent_write() { + return this->prevent_write_; +} #endif #ifdef ARDUINO_ARCH_ESP32 -void ESPPreferenceObject::save_internal_() { +bool ESPPreferenceObject::save_internal_() { char key[32]; sprintf(key, "%u", this->rtc_offset_); - size_t ret = global_preferences.preferences_.putBytes(key, this->data_, this->total_length_bytes()); - if (ret != this->total_length_bytes()) { + 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!"); + return false; } + return true; } -void ESPPreferenceObject::load_internal_() { +bool ESPPreferenceObject::load_internal_() { char key[32]; sprintf(key, "%u", this->rtc_offset_); - size_t ret = global_preferences.preferences_.getBytes(key, this->data_, this->total_length_bytes()); - if (ret != this->total_length_bytes()) { + 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!"); + 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()); } -#endif -size_t ESPPreferenceObject::total_length_bytes() const { - // type + data + CRC - return this->length_ + 2 * sizeof(uint32_t); -} -size_t ESPPreferenceObject::total_length_uint() const { - return this->length_ / sizeof(uint32_t) + 2; -} -uint32_t *ESPPreferenceObject::data() const { - return &this->data_[1]; +ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type) { + auto pref = ESPPreferenceObject(this->current_offset_, length, type); + this->current_offset_++; + return pref; } +#endif uint32_t ESPPreferenceObject::calculate_crc_() const { - uint32_t crc = 42; - for (size_t i = 1; i < this->total_length_uint() - 1; i++) { + uint32_t crc = this->type_; + for (size_t i = 0; i < this->length_words_; i++) { crc ^= (this->data_[i] * 2654435769UL) >> 1; } return crc; @@ -110,12 +188,6 @@ bool ESPPreferenceObject::is_initialized() const { return this->data_ != nullptr; } -ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type) { - auto pref = ESPPreferenceObject(this->current_offset_, length, type); - this->current_offset_ += pref.total_length_bytes(); - return pref; -} - ESPPreferences global_preferences; ESPHOMELIB_NAMESPACE_END diff --git a/src/esphomelib/esppreferences.h b/src/esphomelib/esppreferences.h index 02d82fe9..076368c8 100644 --- a/src/esphomelib/esppreferences.h +++ b/src/esphomelib/esppreferences.h @@ -16,71 +16,90 @@ class ESPPreferenceObject { public: ESPPreferenceObject(); ESPPreferenceObject(size_t rtc_offset, size_t length, uint32_t type); - uint32_t &operator[] (int i); - - void save(); template - void save(T *src); - - bool load(); + bool save(T *src); template bool load(T *dest); - size_t total_length_bytes() const; - size_t total_length_uint() const; - - uint32_t *data() const; - bool is_initialized() const; protected: - void save_internal_(); - void load_internal_(); + bool save_(); + bool load_(); + bool save_internal_(); + bool load_internal_(); uint32_t calculate_crc_() const; size_t rtc_offset_; - size_t length_; + size_t length_words_; uint32_t type_; uint32_t *data_; }; class ESPPreferences { public: + ESPPreferences(); void begin(const std::string &name); ESPPreferenceObject make_preference(size_t length, uint32_t type); template ESPPreferenceObject make_preference(uint32_t type); + template + ESPPreferenceObject make_preference(uint32_t type, const std::string &str); + +#ifdef ARDUINO_ARCH_ESP8266 + /** On the ESP8266, we can't override the first 128 bytes during OTA uploads + * as the eboot parameters are stored there. Writing there during an OTA upload + * would invalidate applying the new firmware. During normal operation, we use + * this part of the RTC user memory, but stop writing to it during OTA uploads. + * + * @param prevent Whether to prevent writing to the first 32 words of RTC user memory. + */ + void prevent_write(bool prevent); + bool is_prevent_write(); +#endif + protected: friend ESPPreferenceObject; - uint32_t current_offset_{100}; + uint32_t current_offset_; #ifdef ARDUINO_ARCH_ESP32 Preferences preferences_; #endif +#ifdef ARDUINO_ARCH_ESP8266 + bool prevent_write_{false}; +#endif }; extern ESPPreferences global_preferences; template ESPPreferenceObject esphomelib::ESPPreferences::make_preference(uint32_t type) { - return this->make_preference(sizeof(T), type); + return this->make_preference((sizeof(T) + 3) / 4, type); +} + +template +ESPPreferenceObject ESPPreferences::make_preference(uint32_t type, const std::string &str) { + type ^= std::hash{}(str); + return make_preference(type); } template -void ESPPreferenceObject::save(T *src) { - memcpy(this->data(), src, sizeof(T)); - this->save(); +bool ESPPreferenceObject::save(T *src) { + if (!this->is_initialized()) + return false; + memcpy(this->data_, src, sizeof(T)); + return this->save_(); } template bool ESPPreferenceObject::load(T *dest) { - if (!this->load()) + if (!this->load_()) return false; - memcpy(dest, this->data(), sizeof(T)); + memcpy(dest, this->data_, sizeof(T)); return true; } diff --git a/src/esphomelib/fan/basic_fan_component.cpp b/src/esphomelib/fan/basic_fan_component.cpp index 32094ed0..e646a20d 100644 --- a/src/esphomelib/fan/basic_fan_component.cpp +++ b/src/esphomelib/fan/basic_fan_component.cpp @@ -38,9 +38,21 @@ void BasicFanComponent::set_state(FanState *state) { this->state_ = state; } void BasicFanComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up Basic Fan '%s'...", this->state_->get_name().c_str()); this->state_->add_on_state_callback([this]() { this->next_update_ = true; }); } +void BasicFanComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Fan '%s':", this->state_->get_name().c_str()); + if (this->oscillating_output_ != nullptr) { + ESP_LOGCONFIG(TAG, " Oscillation: YES"); + } + if (this->binary_output_ == nullptr) { + ESP_LOGCONFIG(TAG, " Mode: Binary"); + } else { + ESP_LOGCONFIG(TAG, " Mode: Speed"); + ESP_LOGCONFIG(TAG, " Speeds: Low=%.0f%% Medium=%.0f%% High=%.0f%%", + this->low_speed_ * 100.0f, this->medium_speed_ * 100.0f, this->high_speed_ * 100.0f); + } +} void BasicFanComponent::loop() { if (!this->next_update_) { return; diff --git a/src/esphomelib/fan/basic_fan_component.h b/src/esphomelib/fan/basic_fan_component.h index d0cbcdfb..293e77d7 100644 --- a/src/esphomelib/fan/basic_fan_component.h +++ b/src/esphomelib/fan/basic_fan_component.h @@ -43,6 +43,7 @@ class BasicFanComponent : public Component { FanState *get_state() const; void set_state(FanState *state); void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/fan/fan_state.cpp b/src/esphomelib/fan/fan_state.cpp index 730941f6..9d93f64c 100644 --- a/src/esphomelib/fan/fan_state.cpp +++ b/src/esphomelib/fan/fan_state.cpp @@ -43,7 +43,7 @@ struct FanStateRTCState { }; void FanState::setup() { - this->rtc_ = global_preferences.make_preference(1569162164UL); + this->rtc_ = global_preferences.make_preference(1569162164UL, this->name_); FanStateRTCState recovered; if (!this->rtc_.load(&recovered)) return; @@ -74,7 +74,7 @@ FanState::StateCall &FanState::StateCall::set_speed(FanSpeed speed) { this->speed_ = speed; return *this; } -void FanState::StateCall::perform() { +void FanState::StateCall::perform() const { if (this->binary_state_.has_value()) { this->state_->state = *this->binary_state_; } diff --git a/src/esphomelib/fan/fan_state.h b/src/esphomelib/fan/fan_state.h index 29797c4c..77132b9e 100644 --- a/src/esphomelib/fan/fan_state.h +++ b/src/esphomelib/fan/fan_state.h @@ -71,7 +71,7 @@ class FanState : public Nameable, public Component { FanState::StateCall &set_speed(FanSpeed speed); FanState::StateCall &set_speed(const char *speed); - void perform(); + void perform() const; protected: FanState *const state_; diff --git a/src/esphomelib/fan/mqtt_fan_component.cpp b/src/esphomelib/fan/mqtt_fan_component.cpp index ff98436d..46a189c1 100644 --- a/src/esphomelib/fan/mqtt_fan_component.cpp +++ b/src/esphomelib/fan/mqtt_fan_component.cpp @@ -23,10 +23,6 @@ std::string MQTTFanComponent::component_type() const { return "fan"; } void MQTTFanComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT fan '%s'...", this->state_->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Supports speed: %s", this->state_->get_traits().supports_speed() ? "YES" : "NO"); - ESP_LOGCONFIG(TAG, " Supports oscillation: %s", this->state_->get_traits().supports_oscillation() ? "YES" : "NO"); - this->subscribe(this->get_command_topic(), [this](const std::string &payload) { auto val = parse_on_off(payload.c_str()); switch (val) { diff --git a/src/esphomelib/helpers.cpp b/src/esphomelib/helpers.cpp index e40c0e56..25e937ff 100644 --- a/src/esphomelib/helpers.cpp +++ b/src/esphomelib/helpers.cpp @@ -173,15 +173,45 @@ std::string uint32_to_string(uint32_t num) { snprintf(buffer, sizeof(buffer), "%04X%04X", address16[1], address16[0]); return std::string(buffer); } -std::string build_json(const json_build_t &f) { +static char *global_json_build_buffer = nullptr; +static size_t global_json_build_buffer_size = 0; + +void reserve_global_json_build_buffer(size_t required_size) { + if (global_json_build_buffer_size == 0 || global_json_build_buffer_size < required_size) { + delete [] global_json_build_buffer; + global_json_build_buffer_size = std::max(required_size, global_json_build_buffer_size * 2); + + size_t remainder = global_json_build_buffer_size % 16U; + if (remainder != 0) + global_json_build_buffer_size += 16 - remainder; + + global_json_build_buffer = new char[global_json_build_buffer_size]; + } +} + +const char *build_json(const json_build_t &f, size_t *length) { global_json_buffer.clear(); JsonObject &root = global_json_buffer.createObject(); f(root); - std::string buffer; - root.printTo(buffer); - return buffer; + // The Json buffer size gives us a good estimate for the required size. + // Usually, it's a bit larger than the actual required string size + // | JSON Buffer Size | String Size | + // Discovery | 388 | 351 | + // Discovery | 372 | 356 | + // Discovery | 336 | 311 | + // Discovery | 408 | 393 | + reserve_global_json_build_buffer(global_json_buffer.size()); + size_t bytes_written = root.printTo(global_json_build_buffer, global_json_build_buffer_size); + + if (bytes_written == global_json_build_buffer_size) { + reserve_global_json_build_buffer(root.measureLength() + 1); + bytes_written = root.printTo(global_json_build_buffer, global_json_build_buffer_size); + } + + *length = bytes_written; + return global_json_build_buffer; } void parse_json(const std::string &data, const json_parse_t &f) { global_json_buffer.clear(); @@ -213,7 +243,7 @@ CallbackManager shutdown_hooks; CallbackManager safe_shutdown_hooks; void reboot(const char *cause) { - ESP_LOGI(TAG, "Forcing a reboot... Cause: '%s'", cause); + ESP_LOGI(TAG, "Forcing a reboot... Reason: '%s'", cause); run_shutdown_hooks(cause); ESP.restart(); // restart() doesn't always end execution @@ -225,7 +255,7 @@ void add_shutdown_hook(std::function &&f) { shutdown_hooks.add(std::move(f)); } void safe_reboot(const char *cause) { - ESP_LOGI(TAG, "Rebooting safely... Cause: '%s'", cause); + ESP_LOGI(TAG, "Rebooting safely... Reason: '%s'", cause); run_safe_shutdown_hooks(cause); ESP.restart(); // restart() doesn't always end execution @@ -326,6 +356,11 @@ void ICACHE_RAM_ATTR HOT feed_wdt() { last_feed = now; #endif } +std::string build_json(const json_build_t &f) { + size_t len; + const char *c_str = build_json(f, &len); + return std::string(c_str, len); +} template uint32_t reverse_bits(uint32_t x) { @@ -395,6 +430,10 @@ void VectorJsonBuffer::reserve(size_t size) { this->capacity_ = target_capacity; } +size_t VectorJsonBuffer::size() const { + return this->size_; +} + VectorJsonBuffer global_json_buffer; ESPHOMELIB_NAMESPACE_END diff --git a/src/esphomelib/helpers.h b/src/esphomelib/helpers.h index 256a5841..08519eb2 100644 --- a/src/esphomelib/helpers.h +++ b/src/esphomelib/helpers.h @@ -72,6 +72,8 @@ void run_safe_shutdown_hooks(const char *cause); std::string to_lowercase_underscore(std::string s); /// Build a JSON string with the provided json build function. +const char *build_json(const json_build_t &f, size_t *length); + std::string build_json(const json_build_t &f); /// Parse a JSON string and run the provided json parse function if it's valid. @@ -290,6 +292,8 @@ class VectorJsonBuffer : public ArduinoJson::Internals::JsonBufferBasewire_->begin(this->sda_pin_, this->scl_pin_); this->wire_->setClock(this->frequency_); } -void I2CComponent::loop() { - if (this->scan_ && App.is_fully_setup()) { - this->scan_ = false; +void I2CComponent::dump_config() { + ESP_LOGCONFIG(TAG, "I2C Bus:"); + ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); + ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); + ESP_LOGCONFIG(TAG, " Frequency: %u Hz", this->frequency_); + if (this->scan_) { ESP_LOGI(TAG, "Scanning i2c bus for active devices..."); uint8_t found = 0; for (uint8_t address = 8; address < 120; address++) { @@ -187,7 +189,7 @@ bool I2CComponent::write_byte_16(uint8_t address, uint8_t register_, uint16_t da } I2CDevice::I2CDevice(I2CComponent *parent, uint8_t address) : address_(address), parent_(parent) { - assert(this->parent_ != nullptr && "You have to setup i2c first!"); + } void I2CDevice::set_address(uint8_t address) { diff --git a/src/esphomelib/i2c_component.h b/src/esphomelib/i2c_component.h index ea2d1169..3d124c9c 100644 --- a/src/esphomelib/i2c_component.h +++ b/src/esphomelib/i2c_component.h @@ -10,6 +10,8 @@ ESPHOMELIB_NAMESPACE_BEGIN +#define LOG_I2C_DEVICE(this) ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + /** The I2CComponent is the base of esphomelib's i2c communication. * * It handles setting up the bus (with pins, clock frequency) and provides nice helper functions to @@ -122,8 +124,7 @@ class I2CComponent : public Component { /// Setup the i2c. bus void setup() override; - /// Do an address range scan if necessary. - void loop() override; + void dump_config() override; /// Set a very high setup priority to make sure it's loaded before all other hardware. float get_setup_priority() const override; diff --git a/src/esphomelib/io/pcf8574_component.cpp b/src/esphomelib/io/pcf8574_component.cpp index bdefcc92..bb00f368 100644 --- a/src/esphomelib/io/pcf8574_component.cpp +++ b/src/esphomelib/io/pcf8574_component.cpp @@ -31,6 +31,14 @@ void PCF8574Component::setup() { this->write_gpio_(); this->read_gpio_(); } +void PCF8574Component::dump_config() { + ESP_LOGCONFIG(TAG, "PCF8574:"); + ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, " Is PCF8575: %s", YESNO(this->pcf8575_)); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with PCF8574 failed!"); + } +} bool PCF8574Component::digital_read_(uint8_t pin) { this->read_gpio_(); return this->input_mask_ & (1 << pin); @@ -59,7 +67,7 @@ void PCF8574Component::pin_mode_(uint8_t pin, uint8_t mode) { this->port_mask_ &= ~(1 << pin); break; default: - assert(false); + break; } this->write_gpio_(); @@ -107,14 +115,9 @@ bool PCF8574Component::write_gpio_() { return true; } PCF8574GPIOInputPin PCF8574Component::make_input_pin(uint8_t pin, uint8_t mode, bool inverted) { - assert(mode == PCF8574_INPUT || mode == PCF8574_INPUT_PULLUP); - if (this->pcf8575_) { assert(pin < 16); } - else { assert(pin < 8); } return {this, pin, mode, inverted}; } PCF8574GPIOOutputPin PCF8574Component::make_output_pin(uint8_t pin, bool inverted) { - if (this->pcf8575_) { assert(pin < 16); } - else { assert(pin < 8); } return {this, pin, PCF8574_OUTPUT, inverted}; } float PCF8574Component::get_setup_priority() const { diff --git a/src/esphomelib/io/pcf8574_component.h b/src/esphomelib/io/pcf8574_component.h index fa8b721d..50f3c1e6 100644 --- a/src/esphomelib/io/pcf8574_component.h +++ b/src/esphomelib/io/pcf8574_component.h @@ -65,6 +65,8 @@ class PCF8574Component : public Component, public I2CDevice { float get_setup_priority() const override; + void dump_config() override; + protected: bool read_gpio_(); diff --git a/src/esphomelib/light/fast_led_light_output.cpp b/src/esphomelib/light/fast_led_light_output.cpp index 8f524c46..c509681c 100644 --- a/src/esphomelib/light/fast_led_light_output.cpp +++ b/src/esphomelib/light/fast_led_light_output.cpp @@ -29,7 +29,6 @@ void FastLEDLightOutputComponent::write_state(LightState *state) { } void FastLEDLightOutputComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up FastLED light..."); - assert(this->controller_ != nullptr && "You need to add LEDs to this controller!"); this->controller_->init(); this->controller_->setLeds(this->leds_, this->num_leds_); this->controller_->setCorrection(this->correction_); @@ -38,6 +37,14 @@ void FastLEDLightOutputComponent::setup() { } ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_); } +void FastLEDLightOutputComponent::dump_config() { + ESP_LOGCONFIG(TAG, "FastLED light:"); + ESP_LOGCONFIG(TAG, " Num LEDs: %u", this->num_leds_); + ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_); + ESP_LOGCONFIG(TAG, " Color Correction: red=%.0f%% green=%.0f%% blue=%.0f%%", + this->correction_.red / 2.55f, this->correction_.green / 2.55f, this->correction_.blue / 2.55f); + +} void FastLEDLightOutputComponent::loop() { if (!this->next_show_) return; diff --git a/src/esphomelib/light/fast_led_light_output.h b/src/esphomelib/light/fast_led_light_output.h index b4c1fc4a..d48ef984 100644 --- a/src/esphomelib/light/fast_led_light_output.h +++ b/src/esphomelib/light/fast_led_light_output.h @@ -334,6 +334,7 @@ class FastLEDLightOutputComponent : public LightOutput, public Component { LightTraits get_traits() override; void write_state(LightState *state) override; void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/light/light_state.cpp b/src/esphomelib/light/light_state.cpp index a75fcf0e..304b4dce 100644 --- a/src/esphomelib/light/light_state.cpp +++ b/src/esphomelib/light/light_state.cpp @@ -156,7 +156,7 @@ struct LightStateRTCState { void LightState::setup() { ESP_LOGCONFIG(TAG, "Setting up light '%s'...", this->get_name().c_str()); - this->rtc_ = global_preferences.make_preference(617215407UL); + this->rtc_ = global_preferences.make_preference(617215407UL, this->name_); LightStateRTCState recovered; if (!this->rtc_.load(&recovered)) return; @@ -390,7 +390,7 @@ LightState::StateCall &LightState::StateCall::parse_json(JsonObject &root) { return *this; } -void LightState::StateCall::perform() { +void LightState::StateCall::perform() const { // use remote values for fallback LightColorValues v = this->state_->get_remote_values(); LightTraits traits = this->state_->get_traits(); diff --git a/src/esphomelib/light/light_state.h b/src/esphomelib/light/light_state.h index 611dad83..cb023cdf 100644 --- a/src/esphomelib/light/light_state.h +++ b/src/esphomelib/light/light_state.h @@ -118,7 +118,7 @@ class LightState : public Nameable, public Component { LightState::StateCall &parse_color_json(JsonObject &root); LightState::StateCall &parse_json(JsonObject &root); - void perform(); + void perform() const; protected: LightState *state_; diff --git a/src/esphomelib/light/mqtt_json_light_component.cpp b/src/esphomelib/light/mqtt_json_light_component.cpp index d441458c..5ba88024 100644 --- a/src/esphomelib/light/mqtt_json_light_component.cpp +++ b/src/esphomelib/light/mqtt_json_light_component.cpp @@ -17,8 +17,6 @@ std::string MQTTJSONLightComponent::component_type() const { } void MQTTJSONLightComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT light..."); - this->subscribe_json(this->get_command_topic(), [&](JsonObject &root) { this->state_->make_call().parse_json(root).perform(); }); @@ -72,6 +70,10 @@ void MQTTJSONLightComponent::send_initial_state() { bool MQTTJSONLightComponent::is_internal() { return this->state_->is_internal(); } +void MQTTJSONLightComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Light '%s':", this->state_->get_name().c_str()); + LOG_MQTT_COMPONENT(true, true) +} } // namespace light diff --git a/src/esphomelib/light/mqtt_json_light_component.h b/src/esphomelib/light/mqtt_json_light_component.h index d2add165..50f7d862 100644 --- a/src/esphomelib/light/mqtt_json_light_component.h +++ b/src/esphomelib/light/mqtt_json_light_component.h @@ -20,6 +20,8 @@ class MQTTJSONLightComponent : public mqtt::MQTTComponent { void setup() override; + void dump_config() override; + void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override; void send_initial_state() override; diff --git a/src/esphomelib/log.h b/src/esphomelib/log.h index 4d2c1673..bef5612f 100644 --- a/src/esphomelib/log.h +++ b/src/esphomelib/log.h @@ -151,5 +151,7 @@ int esp_idf_log_vprintf_(const char *format, va_list args); ((byte) & 0x04 ? '1' : '0'), \ ((byte) & 0x02 ? '1' : '0'), \ ((byte) & 0x01 ? '1' : '0') +#define YESNO(b) ((b) ? "YES" : "NO") +#define ONOFF(b) ((b) ? "ON" : "OFF") #endif //ESPHOMELIB_LOG_H diff --git a/src/esphomelib/log_component.cpp b/src/esphomelib/log_component.cpp index c425352a..eadb3504 100644 --- a/src/esphomelib/log_component.cpp +++ b/src/esphomelib/log_component.cpp @@ -10,14 +10,20 @@ ESPHOMELIB_NAMESPACE_BEGIN -static const char *TAG = "log_component"; +static const char *TAG = "logger"; int LogComponent::log_vprintf_(int level, const char *tag, const char *format, va_list args) { - auto it = this->log_levels_.find(tag); + // Uses std::vector<> for low memory footprint, though the vector + // could be sorted to minimize lookup times. This feature isn't used that + // much anyway so it doesn't matter too much. int max_level = this->global_log_level_; - if (it != this->log_levels_.end()) - max_level = it->second; + for (auto &it : this->log_levels_) { + if (it.tag == tag) { + max_level = it.level; + break; + } + } if (level > max_level) return 0; @@ -60,7 +66,7 @@ void LogComponent::set_global_log_level(int log_level) { this->global_log_level_ = log_level; } void LogComponent::set_log_level(const std::string &tag, int log_level) { - this->log_levels_[tag] = log_level; + this->log_levels_.push_back(LogLevelOverride{tag, log_level}); } size_t LogComponent::get_tx_buffer_size() const { return this->tx_buffer_.capacity(); diff --git a/src/esphomelib/log_component.h b/src/esphomelib/log_component.h index 5ef38e8a..250a1317 100644 --- a/src/esphomelib/log_component.h +++ b/src/esphomelib/log_component.h @@ -62,7 +62,11 @@ class LogComponent : public Component { uint32_t baud_rate_; std::vector tx_buffer_; int global_log_level_{ESPHOMELIB_LOG_LEVEL}; - std::unordered_map log_levels_; + struct LogLevelOverride { + std::string tag; + int level; + }; + std::vector log_levels_; CallbackManager log_callback_{}; }; diff --git a/src/esphomelib/mqtt/mqtt_client_component.cpp b/src/esphomelib/mqtt/mqtt_client_component.cpp index 9a4c018f..53a83724 100644 --- a/src/esphomelib/mqtt/mqtt_client_component.cpp +++ b/src/esphomelib/mqtt/mqtt_client_component.cpp @@ -18,58 +18,22 @@ MQTTClientComponent::MQTTClientComponent(const MQTTCredentials &credentials, con void MQTTClientComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up MQTT..."); - ESP_LOGCONFIG(TAG, " Server Address: %s:%u", this->credentials_.address.c_str(), this->credentials_.port); - ESP_LOGCONFIG(TAG, " Username: '%s'", this->credentials_.username.c_str()); - ESP_LOGCONFIG(TAG, " Password: '%s'", this->credentials_.password.c_str()); if (this->credentials_.client_id.empty()) this->credentials_.client_id = generate_hostname(this->topic_prefix_); - ESP_LOGCONFIG(TAG, " Client ID: '%s'", this->credentials_.client_id.c_str()); - if (!this->discovery_info_.prefix.empty()) { - ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str()); - ESP_LOGCONFIG(TAG, " Discovery retain: %s", this->discovery_info_.retain ? "true" : "false"); - } this->mqtt_client_.onMessage([this](char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total){ std::string payload_s(payload, len); std::string topic_s(topic); this->on_message(topic_s, payload_s); }); this->mqtt_client_.onDisconnect([this](AsyncMqttClientDisconnectReason reason) { - const char *reason_s = nullptr; - switch (reason) { - case AsyncMqttClientDisconnectReason::TCP_DISCONNECTED: - reason_s = "TCP disconnected"; - break; - case AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: - reason_s = "Unacceptable Protocol Version"; - break; - case AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED: - reason_s = "Identifier Rejected"; - break; - case AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE: - reason_s = "Server Unavailable"; - break; - case AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS: - reason_s = "Malformed Credentials"; - break; - case AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED: - reason_s = "Not Authorized"; - break; - case AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE: - reason_s = "Not Enough Space"; - break; - case AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT: - reason_s = "TLS Bad Fingerprint"; - break; - default: - reason_s = "Unknown"; - break; - } - ESP_LOGW(TAG, "MQTT Disconnected: %s.", reason_s); + this->state_ = MQTT_CLIENT_DISCONNECTED; + this->disconnect_reason_ = reason; }); if (this->is_log_message_enabled()) { global_log_component->add_on_log_callback([this](int level, const char *message) { - if (level <= this->log_level_ && this->mqtt_client_.connected() && this->state_ == MQTT_CLIENT_CONNECTED) { - this->publish(this->log_message_.topic, message, this->log_message_.qos, this->log_message_.retain); + if (level <= this->log_level_ && this->is_connected()) { + this->publish(this->log_message_.topic, message, strlen(message), + this->log_message_.qos, this->log_message_.retain); } }); } @@ -78,6 +42,7 @@ void MQTTClientComponent::setup() { if (!this->shutdown_message_.topic.empty()) { yield(); this->publish(this->shutdown_message_); + yield(); } this->mqtt_client_.disconnect(true); }); @@ -85,6 +50,23 @@ void MQTTClientComponent::setup() { this->last_connected_ = millis(); this->start_connect(); } +void MQTTClientComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT:"); + ESP_LOGCONFIG(TAG, " Server Address: %s:%u", this->credentials_.address.c_str(), this->credentials_.port); + ESP_LOGCONFIG(TAG, " Username: '%s'", this->credentials_.username.c_str()); + ESP_LOGCONFIG(TAG, " Client ID: '%s'", this->credentials_.client_id.c_str()); + if (!this->discovery_info_.prefix.empty()) { + ESP_LOGCONFIG(TAG, " Discovery prefix: '%s'", this->discovery_info_.prefix.c_str()); + ESP_LOGCONFIG(TAG, " Discovery retain: %s", YESNO(this->discovery_info_.retain)); + } + ESP_LOGCONFIG(TAG, " Topic Prefix: '%s'", this->topic_prefix_.c_str()); + if (!this->log_message_.topic.empty()) { + ESP_LOGCONFIG(TAG, " Log Topic: '%s'", this->log_message_.topic.c_str()); + } + if (!this->availability_.topic.empty()) { + ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str()); + } +} bool MQTTClientComponent::can_proceed() { return this->is_connected(); } @@ -131,6 +113,9 @@ void MQTTClientComponent::check_connected() { this->state_ = MQTT_CLIENT_CONNECTED; this->status_clear_warning(); ESP_LOGI(TAG, "MQTT Connected!"); + // MQTT Client needs some time to be fully set up. + delay(100); + if (!this->birth_message_.topic.empty()) this->publish(this->birth_message_); @@ -142,9 +127,51 @@ void MQTTClientComponent::check_connected() { } void MQTTClientComponent::loop() { + if (this->disconnect_reason_.has_value()) { + const char *reason_s = nullptr; + switch (*this->disconnect_reason_) { + case AsyncMqttClientDisconnectReason::TCP_DISCONNECTED: + reason_s = "TCP disconnected"; + break; + case AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: + reason_s = "Unacceptable Protocol Version"; + break; + case AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED: + reason_s = "Identifier Rejected"; + break; + case AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE: + reason_s = "Server Unavailable"; + break; + case AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS: + reason_s = "Malformed Credentials"; + break; + case AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED: + reason_s = "Not Authorized"; + break; + case AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE: + reason_s = "Not Enough Space"; + break; + case AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT: + reason_s = "TLS Bad Fingerprint"; + break; + default: + reason_s = "Unknown"; + break; + } + if (!global_wifi_component->is_connected()) { + reason_s = "WiFi disconnected"; + } + ESP_LOGW(TAG, "MQTT Disconnected: %s.", reason_s); + this->disconnect_reason_.reset(); + } + + const uint32_t now = millis(); + switch (this->state_) { case MQTT_CLIENT_DISCONNECTED: - this->start_connect(); + if (now - this->connect_begin_ > 5000) { + this->start_connect(); + } break; case MQTT_CLIENT_CONNECTING: this->check_connected(); @@ -155,7 +182,7 @@ void MQTTClientComponent::loop() { ESP_LOGW(TAG, "Lost MQTT Client connection!"); this->start_connect(); } else { - this->last_connected_ = millis(); + this->last_connected_ = now; } break; } @@ -163,7 +190,6 @@ void MQTTClientComponent::loop() { if (millis() - this->last_connected_ > this->reboot_timeout_ && this->reboot_timeout_ != 0) { ESP_LOGE(TAG, " Can't connect to MQTT... Restarting..."); reboot("mqtt"); - return; } } @@ -172,7 +198,7 @@ void MQTTClientComponent::set_keep_alive(uint16_t keep_alive_s) { } void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) { - ESP_LOGD(TAG, "Subscribing to topic='%s' qos=%u...", topic.c_str(), qos); + ESP_LOGV(TAG, "Subscribing to topic='%s' qos=%u...", topic.c_str(), qos); MQTTSubscription subscription{ .topic = topic, .qos = qos, @@ -185,7 +211,7 @@ void MQTTClientComponent::subscribe(const std::string &topic, mqtt_callback_t ca } void MQTTClientComponent::subscribe_json(const std::string &topic, json_parse_t callback, uint8_t qos) { - ESP_LOGD(TAG, "Subscribing to topic='%s' qos=%u with JSON...", topic.c_str(), qos); + ESP_LOGV(TAG, "Subscribing to topic='%s' qos=%u with JSON...", topic.c_str(), qos); auto f = std::bind(&parse_json, std::placeholders::_1, callback); MQTTSubscription subscription{ .topic = topic, @@ -199,22 +225,31 @@ void MQTTClientComponent::subscribe_json(const std::string &topic, json_parse_t } void MQTTClientComponent::publish(const std::string &topic, const std::string &payload, uint8_t qos, bool retain) { + this->publish(topic, payload.data(), payload.size(), qos, retain); +} + +void MQTTClientComponent::publish(const std::string &topic, const char *payload, size_t payload_length, + uint8_t qos, bool retain) { + if (!this->is_connected()) { + // critical components will re-transmit their messages + return; + } bool logging_topic = topic == this->log_message_.topic; if (!logging_topic) { - ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d)", topic.c_str(), payload.c_str(), retain); + ESP_LOGV(TAG, "Publish(topic='%s' payload='%s' retain=%d)", topic.c_str(), payload, retain); } this->loop(); - uint16_t ret = this->mqtt_client_.publish(topic.c_str(), qos, retain, payload.data(), payload.length()); + uint16_t ret = this->mqtt_client_.publish(topic.c_str(), qos, retain, payload, payload_length); yield(); - if (ret == 0 && !logging_topic) { - yield(); - ret = this->mqtt_client_.publish(topic.c_str(), qos, retain, payload.data(), payload.length()); + if (ret == 0 && !logging_topic && this->is_connected()) { + delay(5); + ret = this->mqtt_client_.publish(topic.c_str(), qos, retain, payload, payload_length); if (ret == 0) { ESP_LOGW(TAG, "Publish failed!"); this->status_momentary_warning("publish", 5000); } - yield(); + delay(1); } } @@ -306,8 +341,9 @@ void MQTTClientComponent::recalculate_availability() { this->availability_.payload_not_available = this->last_will_.payload; } void MQTTClientComponent::publish_json(const std::string &topic, const json_build_t &f, uint8_t qos, bool retain) { - std::string message = build_json(f); - this->publish(topic, message, qos, retain); + size_t len; + const char *message = build_json(f, &len); + this->publish(topic, message, len, qos, retain); } void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this->log_message_ = std::move(message); diff --git a/src/esphomelib/mqtt/mqtt_client_component.h b/src/esphomelib/mqtt/mqtt_client_component.h index 1ef06940..0e63ffa0 100644 --- a/src/esphomelib/mqtt/mqtt_client_component.h +++ b/src/esphomelib/mqtt/mqtt_client_component.h @@ -185,6 +185,9 @@ class MQTTClientComponent : public Component { */ void publish(const std::string &topic, const std::string &payload, uint8_t qos = 0, bool retain = false); + void publish(const std::string &topic, const char *payload, size_t payload_length, + uint8_t qos = 0, bool retain = false); + /** Construct and send a JSON MQTT message. * * @param topic The topic. @@ -195,6 +198,7 @@ class MQTTClientComponent : public Component { /// Setup the MQTT client, registering a bunch of callbacks and attempting to connect. void setup() override; + void dump_config() override; /// Reconnect if required void loop() override; /// MQTT client setup priority @@ -256,6 +260,7 @@ class MQTTClientComponent : public Component { uint32_t reboot_timeout_{60000}; uint32_t connect_begin_; uint32_t last_connected_{0}; + optional disconnect_reason_{}; }; extern MQTTClientComponent *global_mqtt_client; diff --git a/src/esphomelib/mqtt/mqtt_component.h b/src/esphomelib/mqtt/mqtt_component.h index 6d9cda55..fcb54e29 100644 --- a/src/esphomelib/mqtt/mqtt_component.h +++ b/src/esphomelib/mqtt/mqtt_component.h @@ -16,6 +16,11 @@ struct SendDiscoveryConfig { const char *platform{"mqtt"}; ///< The platform of this component. Defaults to "mqtt". }; +#define LOG_MQTT_COMPONENT(state_topic, command_topic) \ + if (state_topic) { ESP_LOGCONFIG(TAG, " State Topic: '%s'", this->get_state_topic().c_str()); } \ + if (command_topic) { ESP_LOGCONFIG(TAG, " Command Topic: '%s'", this->get_command_topic().c_str()); } \ + + /** MQTTComponent is the base class for all components that interact with MQTT to expose * certain functionality or data from actuators or sensors to clients. * diff --git a/src/esphomelib/ota_component.cpp b/src/esphomelib/ota_component.cpp index 1fd32090..6903f2df 100644 --- a/src/esphomelib/ota_component.cpp +++ b/src/esphomelib/ota_component.cpp @@ -29,8 +29,6 @@ uint8_t OTA_VERSION_1_0 = 1; #endif void OTAComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up OTA..."); - ESP_LOGCONFIG(TAG, " port: %u", this->port_); this->server_ = new WiFiServer(this->port_); this->server_->begin(); @@ -40,10 +38,8 @@ void OTAComponent::setup() { #ifdef ARDUINO_ARCH_ESP32 add_shutdown_hook([this](const char *cause) { - if (strcmp(cause, "ota") != 0) { - this->server_->close(); - MDNS.end(); - } + this->server_->close(); + MDNS.end(); }); #endif #else @@ -68,6 +64,9 @@ void OTAComponent::setup() { ESP_LOGI(TAG, "OTA starting..."); this->ota_triggered_ = true; this->at_ota_progress_message_ = 0; +#ifdef ARDUINO_ARCH_ESP8266 + global_preferences.prevent_write(true); +#endif this->status_set_warning(); #ifdef USE_STATUS_LED global_state |= STATUS_LED_WARNING; @@ -114,6 +113,9 @@ void OTAComponent::setup() { this->ota_triggered_ = false; this->status_clear_warning(); this->status_momentary_error("onerror", 5000); +#ifdef ARDUINO_ARCH_ESP8266 + global_preferences.prevent_write(false); +#endif }); ArduinoOTA.begin(); #endif @@ -121,14 +123,21 @@ void OTAComponent::setup() { if (this->has_safe_mode_) { add_safe_shutdown_hook([this](const char *cause) { - if (strcmp(cause, "ota") != 0) - this->clean_rtc(); + this->clean_rtc(); }); + } - if (this->safe_mode_rtc_value_ > 1) { - ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %d restarts", - this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_); - } + this->dump_config(); +} +void OTAComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Over-The-Air Updates:"); + ESP_LOGCONFIG(TAG, " Address: %s:%u", WiFi.localIP().toString().c_str(), this->port_); + if (!this->password_.empty()) { + ESP_LOGCONFIG(TAG, " Using Password."); + } + if (this->has_safe_mode_ && this->safe_mode_rtc_value_ > 1) { + ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %d restarts", + this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_); } } @@ -147,7 +156,7 @@ void OTAComponent::loop() { this->has_safe_mode_ = false; // successful boot, reset counter ESP_LOGI(TAG, "Boot seems successful, resetting boot loop counter."); - this->write_rtc_(0); + this->clean_rtc(); } } @@ -273,6 +282,10 @@ void OTAComponent::handle_() { } ESP_LOGV(TAG, "OTA size is %u bytes", ota_size); +#ifdef ARDUINO_ARCH_ESP8266 + global_preferences.prevent_write(true); +#endif + if (!Update.begin(ota_size, U_FLASH)) { #ifdef ARDUINO_ARCH_ESP8266 StreamString ss; @@ -366,6 +379,9 @@ void OTAComponent::handle_() { } #endif this->status_momentary_error("onerror", 5000); +#ifdef ARDUINO_ARCH_ESP8266 + global_preferences.prevent_write(false); +#endif } size_t OTAComponent::wait_receive_(uint8_t *buf, size_t bytes) { @@ -439,7 +455,7 @@ void OTAComponent::start_safe_mode(uint8_t num_attempts, uint32_t enable_time) { this->safe_mode_start_time_ = millis(); this->safe_mode_enable_time_ = enable_time; this->safe_mode_num_attempts_ = num_attempts; - this->rtc_ = global_preferences.make_preference(4, 669657188UL); + this->rtc_ = global_preferences.make_preference(669657188UL); this->safe_mode_rtc_value_ = this->read_rtc_(); ESP_LOGCONFIG(TAG, "There have been %u suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_); @@ -478,13 +494,13 @@ void OTAComponent::start_safe_mode(uint8_t num_attempts, uint32_t enable_time) { } } void OTAComponent::write_rtc_(uint8_t val) { - this->rtc_[0] = val; - this->rtc_.save(); + this->rtc_.save(&val); } uint8_t OTAComponent::read_rtc_() { - if (!this->rtc_.load()) + uint8_t val; + if (!this->rtc_.load(&val)) return 0; - return this->rtc_[0]; + return val; } void OTAComponent::clean_rtc() { this->write_rtc_(0); diff --git a/src/esphomelib/ota_component.h b/src/esphomelib/ota_component.h index e69f11ff..509e5d29 100644 --- a/src/esphomelib/ota_component.h +++ b/src/esphomelib/ota_component.h @@ -97,6 +97,7 @@ class OTAComponent : public Component { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; float get_setup_priority() const override; void loop() override; diff --git a/src/esphomelib/output/binary_output.h b/src/esphomelib/output/binary_output.h index 00fc9700..6fb511c5 100644 --- a/src/esphomelib/output/binary_output.h +++ b/src/esphomelib/output/binary_output.h @@ -18,6 +18,9 @@ class TurnOffAction; template class TurnOnAction; +#define LOG_BINARY_OUTPUT(this) \ + if (this->inverted_) { ESP_LOGCONFIG(TAG, " Inverted: YES"); } \ + /** The base class for all binary outputs i.e. outputs that can only be switched on/off. * * This interface class provides one method you need to override in order to create a binary output diff --git a/src/esphomelib/output/esp8266_pwm_output.cpp b/src/esphomelib/output/esp8266_pwm_output.cpp index 8e0c0a1d..57c480ae 100644 --- a/src/esphomelib/output/esp8266_pwm_output.cpp +++ b/src/esphomelib/output/esp8266_pwm_output.cpp @@ -10,13 +10,19 @@ ESPHOMELIB_NAMESPACE_BEGIN namespace output { +static const char *TAG = "output.esp8266_pwm"; + ESP8266PWMOutput::ESP8266PWMOutput(const GPIOOutputPin &pin) : pin_(pin) {} void ESP8266PWMOutput::setup() { - assert(this->pin_.get_pin() <= 16); this->pin_.setup(); this->turn_off(); } +void ESP8266PWMOutput::dump_config() { + ESP_LOGCONFIG(TAG, "ESP8266 PWM:"); + LOG_PIN(" Pin: ", &this->pin_); + LOG_FLOAT_OUTPUT(this); +} void ESP8266PWMOutput::write_state(float state) { const uint16_t max_duty = 1023; auto duty = static_cast(state * max_duty); diff --git a/src/esphomelib/output/esp8266_pwm_output.h b/src/esphomelib/output/esp8266_pwm_output.h index edc3aa8a..c87d0fd4 100644 --- a/src/esphomelib/output/esp8266_pwm_output.h +++ b/src/esphomelib/output/esp8266_pwm_output.h @@ -35,6 +35,7 @@ class ESP8266PWMOutput : public FloatOutput, public Component { /// Initialize pin void setup() override; + void dump_config() override; /// HARDWARE setup_priority float get_setup_priority() const override; /// Override FloatOutput's write_state for analogWrite diff --git a/src/esphomelib/output/float_output.h b/src/esphomelib/output/float_output.h index 1cf42088..72390607 100644 --- a/src/esphomelib/output/float_output.h +++ b/src/esphomelib/output/float_output.h @@ -15,6 +15,10 @@ namespace output { template class SetLevelAction; +#define LOG_FLOAT_OUTPUT(this) \ + LOG_BINARY_OUTPUT(this) \ + if (this->max_power_ != 1.0f) { ESP_LOGCONFIG(TAG, " Max Power: %.1f%%", this->max_power_ * 100.0f); } + /** Base class for all output components that can output a variable level, like PWM. * * Floating Point Outputs always use output values in the range from 0.0 to 1.0 (inclusive), where 0.0 means off diff --git a/src/esphomelib/output/gpio_binary_output_component.cpp b/src/esphomelib/output/gpio_binary_output_component.cpp index 3ab77e3b..d5b395b7 100644 --- a/src/esphomelib/output/gpio_binary_output_component.cpp +++ b/src/esphomelib/output/gpio_binary_output_component.cpp @@ -22,6 +22,11 @@ void GPIOBinaryOutputComponent::setup() { this->pin_->setup(); this->pin_->digital_write(false); } +void GPIOBinaryOutputComponent::dump_config() { + ESP_LOGCONFIG(TAG, "GPIO Binary Output:"); + LOG_PIN(" Pin:", this->pin_); + LOG_BINARY_OUTPUT(this); +} float GPIOBinaryOutputComponent::get_setup_priority() const { return setup_priority::HARDWARE; diff --git a/src/esphomelib/output/gpio_binary_output_component.h b/src/esphomelib/output/gpio_binary_output_component.h index f6aa203a..04834fde 100644 --- a/src/esphomelib/output/gpio_binary_output_component.h +++ b/src/esphomelib/output/gpio_binary_output_component.h @@ -35,6 +35,7 @@ class GPIOBinaryOutputComponent : public BinaryOutput, public Component { /// Set pin mode. void setup() override; + void dump_config() override; /// Hardware setup priority. float get_setup_priority() const override; diff --git a/src/esphomelib/output/pca9685_output_component.cpp b/src/esphomelib/output/pca9685_output_component.cpp index 5bfdb5a4..571af6e5 100644 --- a/src/esphomelib/output/pca9685_output_component.cpp +++ b/src/esphomelib/output/pca9685_output_component.cpp @@ -45,8 +45,7 @@ PCA9685OutputComponent::PCA9685OutputComponent(I2CComponent *parent, float frequ } void PCA9685OutputComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up PCA9685OutputComponent."); - ESP_LOGCONFIG(TAG, " Mode: 0x%02X", this->mode_); + ESP_LOGCONFIG(TAG, "Setting up PCA9685OutputComponent..."); ESP_LOGV(TAG, " Resetting devices..."); if (!this->write_bytes(PCA9685_REGISTER_SOFTWARE_RESET, nullptr, 0)) { @@ -63,8 +62,6 @@ void PCA9685OutputComponent::setup() { return; } - ESP_LOGCONFIG(TAG, " Frequency: %.0f", this->frequency_); - int pre_scaler = (25000000 / (4096 * this->frequency_)) - 1; if (pre_scaler > 255) pre_scaler = 255; if (pre_scaler < 3) pre_scaler = 3; @@ -96,6 +93,15 @@ void PCA9685OutputComponent::setup() { this->loop(); } +void PCA9685OutputComponent::dump_config() { + ESP_LOGCONFIG(TAG, "PCA9685:"); + ESP_LOGCONFIG(TAG, " Mode: 0x%02X", this->mode_); + ESP_LOGCONFIG(TAG, " Frequency: %.0f Hz", this->frequency_); + if (this->is_failed()) { + ESP_LOGE(TAG, "Setting up PCA9685 failed!"); + } +} + void PCA9685OutputComponent::loop() { if (this->min_channel_ == 0xFF || !this->update_) return; @@ -147,7 +153,6 @@ void PCA9685OutputComponent::set_channel_value(uint8_t channel, uint16_t value) PCA9685OutputComponent::Channel *PCA9685OutputComponent::create_channel(uint8_t channel, PowerSupplyComponent *power_supply, float max_power) { - ESP_LOGV(TAG, "Getting channel %d...", channel); this->min_channel_ = std::min(this->min_channel_, channel); this->max_channel_ = std::max(this->max_channel_, channel); auto *c = new Channel(this, channel); diff --git a/src/esphomelib/output/pca9685_output_component.h b/src/esphomelib/output/pca9685_output_component.h index 2b09be41..50e8dc0e 100644 --- a/src/esphomelib/output/pca9685_output_component.h +++ b/src/esphomelib/output/pca9685_output_component.h @@ -52,6 +52,7 @@ class PCA9685OutputComponent : public Component, public I2CDevice { /// Setup the PCA9685. void setup() override; + void dump_config() override; /// HARDWARE setup_priority float get_setup_priority() const override; /// Send new values if they were updated. diff --git a/src/esphomelib/power_supply_component.cpp b/src/esphomelib/power_supply_component.cpp index fb6b439a..04b9af94 100644 --- a/src/esphomelib/power_supply_component.cpp +++ b/src/esphomelib/power_supply_component.cpp @@ -24,6 +24,12 @@ void PowerSupplyComponent::setup() { this->pin_->digital_write(false); }); } +void PowerSupplyComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Power Supply:"); + LOG_PIN(" Pin: ", this->pin_); + ESP_LOGCONFIG(TAG, " Time to enable: %u ms", this->enable_time_); + ESP_LOGCONFIG(TAG, " Keep on time: %.1f s", this->keep_on_time_ / 1000.0f); +} float PowerSupplyComponent::get_setup_priority() const { return setup_priority::PRE_HARDWARE; @@ -55,7 +61,7 @@ void PowerSupplyComponent::request_high_power() { if (this->active_requests_ == 0) { // we need to enable the power supply. // cancel old timeout if it exists because we now definitely have a high power mode. - ESP_LOGI(TAG, "Enabling power supply."); + ESP_LOGD(TAG, "Enabling power supply."); delay(this->enable_time_); } this->enabled_ = true; @@ -66,8 +72,6 @@ void PowerSupplyComponent::request_high_power() { void PowerSupplyComponent::unrequest_high_power() { this->active_requests_--; - assert(this->active_requests_ >= 0 && "Some component unrequested high power mode twice!"); - if (this->active_requests_ < 0) { // if asserts are disabled we're just going to use 0 as our now counter. this->active_requests_ = 0; @@ -76,7 +80,7 @@ void PowerSupplyComponent::unrequest_high_power() { if (this->active_requests_ == 0) { // set timeout for power supply off this->set_timeout("power-supply-off", this->keep_on_time_, [this](){ - ESP_LOGI(TAG, "Disabling power supply."); + ESP_LOGD(TAG, "Disabling power supply."); this->pin_->digital_write(false); this->enabled_ = false; }); diff --git a/src/esphomelib/power_supply_component.h b/src/esphomelib/power_supply_component.h index 4a387079..74b88bb4 100644 --- a/src/esphomelib/power_supply_component.h +++ b/src/esphomelib/power_supply_component.h @@ -59,6 +59,7 @@ class PowerSupplyComponent : public Component { // (In most use cases you won't need these) /// Register callbacks. void setup() override; + void dump_config() override; /// Hardware setup priority (+1). float get_setup_priority() const override; diff --git a/src/esphomelib/remote/remote_protocol.h b/src/esphomelib/remote/remote_protocol.h index 332c59ce..334470b9 100644 --- a/src/esphomelib/remote/remote_protocol.h +++ b/src/esphomelib/remote/remote_protocol.h @@ -36,6 +36,7 @@ class RemoteControlComponentBase { #ifdef ARDUINO_ARCH_ESP32 rmt_channel_t channel_{RMT_CHANNEL_0}; uint8_t clock_divider_{80}; + esp_err_t error_code_{ESP_OK}; #endif }; diff --git a/src/esphomelib/remote/remote_receiver.cpp b/src/esphomelib/remote/remote_receiver.cpp index dc120f77..6723458d 100644 --- a/src/esphomelib/remote/remote_receiver.cpp +++ b/src/esphomelib/remote/remote_receiver.cpp @@ -127,52 +127,59 @@ float RemoteReceiverComponent::get_setup_priority() const { #ifdef ARDUINO_ARCH_ESP32 void RemoteReceiverComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up Remote Receiver..."); rmt_config_t rmt{}; - ESP_LOGCONFIG(TAG, "Configuring ESP32 RMT peripheral..."); - ESP_LOGCONFIG(TAG, " Channel: %u", this->channel_); rmt.channel = this->channel_; - ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_->get_pin()); rmt.gpio_num = gpio_num_t(this->pin_->get_pin()); - ESP_LOGCONFIG(TAG, " Clock Divider: %u", this->clock_divider_); rmt.clk_div = this->clock_divider_; rmt.mem_block_num = 1; rmt.rmt_mode = RMT_MODE_RX; if (this->filter_us_ == 0) { rmt.rx_config.filter_en = false; } else { - ESP_LOGCONFIG(TAG, " Filter: %u us (%u ticks)", this->filter_us_, this->from_microseconds(this->filter_us_)); rmt.rx_config.filter_en = true; rmt.rx_config.filter_ticks_thresh = this->from_microseconds(this->filter_us_); } - ESP_LOGCONFIG(TAG, " Idle threshold: %u us (%u ticks)", this->idle_us_, this->from_microseconds(this->idle_us_)); rmt.rx_config.idle_threshold = this->from_microseconds(this->idle_us_); esp_err_t error = rmt_config(&rmt); if (error != ESP_OK) { - ESP_LOGE(TAG, "Configuring RMT remote failed: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } error = rmt_driver_install(this->channel_, this->buffer_size_, 0); if (error != ESP_OK) { - ESP_LOGE(TAG, "Installing RMT driver failed: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_); if (error != ESP_OK) { - ESP_LOGE(TAG, "Getting RMT ringbuf handle failed: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } error = rmt_rx_start(this->channel_, true); if (error != ESP_OK) { - ESP_LOGE(TAG, "Starting RMT for receiving failed: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } } +void RemoteReceiverComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Receiver:"); + LOG_PIN(" Pin: ", this->pin_); + ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); + ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); + ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); + ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); + ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); + if (this->is_failed()) { + ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + } +} void RemoteReceiverComponent::loop() { size_t len = 0; @@ -295,8 +302,6 @@ void RemoteReceiverComponent::setup() { this->buffer_ = new uint32_t[this->buffer_size_]; // First index is a space. if (this->pin_->digital_read()) { - ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " - "invert the signal using 'inverted: True' !"); this->buffer_write_at_ = this->buffer_read_at_ = 1; this->buffer_[1] = 0; this->buffer_[0] = 0; @@ -307,6 +312,18 @@ void RemoteReceiverComponent::setup() { auto intr = std::bind(&RemoteReceiverComponent::gpio_intr, this); attachInterrupt(this->pin_->get_pin(), intr, CHANGE); } +void RemoteReceiverComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Receiver:"); + LOG_PIN(" Pin: ", this->pin_); + if (this->pin_->digital_read()) { + ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " + "invert the signal using 'inverted: True' !"); + } + ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_); + ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); + ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_); + ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_); +} void RemoteReceiverComponent::loop() { // copy write at to local variables, as it's volatile diff --git a/src/esphomelib/remote/remote_receiver.h b/src/esphomelib/remote/remote_receiver.h index d4dcd597..d257149b 100644 --- a/src/esphomelib/remote/remote_receiver.h +++ b/src/esphomelib/remote/remote_receiver.h @@ -112,6 +112,7 @@ class RemoteReceiverComponent : public RemoteControlComponentBase, public Compon explicit RemoteReceiverComponent(GPIOPin *pin); void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/remote/remote_transmitter.cpp b/src/esphomelib/remote/remote_transmitter.cpp index 3f13c223..d06ae5ad 100644 --- a/src/esphomelib/remote/remote_transmitter.cpp +++ b/src/esphomelib/remote/remote_transmitter.cpp @@ -96,17 +96,29 @@ void RemoteTransmitterComponent::setup() { } +void RemoteTransmitterComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Transmitter..."); + ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); + ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); + LOG_PIN(" Pin: ", this->pin_); + + if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) { + ESP_LOGCONFIG(TAG, " Carrier Frequency: %uHz", this->current_carrier_frequency_); + ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); + } + + if (this->is_failed()) { + ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_)); + } +} + void RemoteTransmitterComponent::configure_rmt() { rmt_config_t c{}; - ESP_LOGCONFIG(TAG, "Configuring Remote Transmitter..."); c.rmt_mode = RMT_MODE_TX; c.channel = this->channel_; - ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); c.clk_div = this->clock_divider_; - ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); c.gpio_num = gpio_num_t(this->pin_->get_pin()); - ESP_LOGCONFIG(TAG, " GPIO Pin: %u", this->pin_->get_pin()); c.mem_block_num = 1; c.tx_config.loop_en = false; @@ -115,27 +127,21 @@ void RemoteTransmitterComponent::configure_rmt() { } else { c.tx_config.carrier_en = true; c.tx_config.carrier_freq_hz = this->current_carrier_frequency_; - ESP_LOGCONFIG(TAG, " Carrier Frequency: %uHz", this->current_carrier_frequency_); c.tx_config.carrier_duty_percent = this->carrier_duty_percent_; - ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); } c.tx_config.idle_output_en = true; if (!this->pin_->is_inverted()) { - ESP_LOGV(TAG, " Carrier level: HIGH"); c.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; - ESP_LOGV(TAG, " Idle level: LOW"); c.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; } else { c.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; - ESP_LOGV(TAG, " Carrier level: LOW"); c.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH; - ESP_LOGV(TAG, " Idle level: HIGH"); } esp_err_t error = rmt_config(&c); if (error != ESP_OK) { - ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } @@ -143,7 +149,7 @@ void RemoteTransmitterComponent::configure_rmt() { if (!this->initialized_) { error = rmt_driver_install(this->channel_, 0, 0); if (error != ESP_OK) { - ESP_LOGE(TAG, "Error while installing RMT driver: %s", esp_err_to_name(error)); + this->error_code_ = error; this->mark_failed(); return; } @@ -213,6 +219,13 @@ void RemoteTransmitterComponent::setup() { this->pin_->setup(); this->pin_->digital_write(false); } + +void RemoteTransmitterComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Remote Transmitter..."); + ESP_LOGCONFIG(TAG, " Carrier Duty: %u%%", this->carrier_duty_percent_); + LOG_PIN(" Pin: ", this->pin_); +} + void RemoteTransmitterComponent::calculate_on_off_time_(uint32_t carrier_frequency, uint32_t *on_time_period, uint32_t *off_time_period) { @@ -231,7 +244,7 @@ void RemoteTransmitterComponent::send_(RemoteTransmitData *data, uint32_t send_t for (uint32_t i = 0; i < send_times; i++) { uint32_t on_time, off_time; this->calculate_on_off_time_(data->get_carrier_frequency(), &on_time, &off_time); - ESP_LOGD(TAG, "Sending..."); + ESP_LOGD(TAG, "Sending remote code..."); ESP.wdtFeed(); disable_interrupts(); diff --git a/src/esphomelib/remote/remote_transmitter.h b/src/esphomelib/remote/remote_transmitter.h index aead4103..58a51261 100644 --- a/src/esphomelib/remote/remote_transmitter.h +++ b/src/esphomelib/remote/remote_transmitter.h @@ -71,6 +71,8 @@ class RemoteTransmitterComponent : public RemoteControlComponentBase, public Com void setup() override; + void dump_config() override; + float get_setup_priority() const override; void set_carrier_duty_percent(uint8_t carrier_duty_percent); diff --git a/src/esphomelib/sensor/adc.cpp b/src/esphomelib/sensor/adc.cpp index b56fbaad..4562b8ae 100644 --- a/src/esphomelib/sensor/adc.cpp +++ b/src/esphomelib/sensor/adc.cpp @@ -32,6 +32,34 @@ void ADCSensorComponent::setup() { analogSetPinAttenuation(this->pin_.get_pin(), this->attenuation_); #endif } +void ADCSensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "ADC '%s':", this->get_name().c_str()); +#ifdef ARDUINO_ARCH_ESP8266 + #ifdef USE_ADC_SENSOR_VCC + ESP_LOGCONFIG(TAG, " Pin: VCC"); + #else + LOG_PIN(" Pin: ", &this->pin_); + #endif +#endif +#ifdef ARDUINO_ARCH_ESP32 + LOG_PIN(" Pin: ", &this->pin_); + switch (this->attenuation_) { + case ADC_0db: + ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)"); + break; + case ADC_2_5db: + ESP_LOGCONFIG(TAG, " Attenuation: 2.5db (max 1.5V)"); + break; + case ADC_6db: + ESP_LOGCONFIG(TAG, " Attenuation: 6db (max 2.2V)"); + break; + case ADC_11db: + ESP_LOGCONFIG(TAG, " Attenuation: 11db (max 3.9V)"); + break; + } +#endif + LOG_UPDATE_INTERVAL(this); +} float ADCSensorComponent::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/adc.h b/src/esphomelib/sensor/adc.h index a70aaea8..7a6c941b 100644 --- a/src/esphomelib/sensor/adc.h +++ b/src/esphomelib/sensor/adc.h @@ -45,6 +45,7 @@ class ADCSensorComponent : public PollingSensorComponent { void update() override; /// Setup ADc void setup() override; + void dump_config() override; /// Unit of measurement: "V". std::string unit_of_measurement() override; /// Icon: "mdi:flash". diff --git a/src/esphomelib/sensor/ads1115_component.cpp b/src/esphomelib/sensor/ads1115_component.cpp index 81afc2fe..9d55041d 100644 --- a/src/esphomelib/sensor/ads1115_component.cpp +++ b/src/esphomelib/sensor/ads1115_component.cpp @@ -17,10 +17,8 @@ static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; void ADS1115Component::setup() { ESP_LOGCONFIG(TAG, "Setting up ADS1115..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02x", this->address_); uint16_t value; if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) { - ESP_LOGE(TAG, "Connection to ADS1115 with address 0x%02x failed.", this->address_); this->mark_failed(); return; } @@ -65,15 +63,24 @@ void ADS1115Component::setup() { return; } for (auto *sensor : this->sensors_) { - ESP_LOGCONFIG(TAG, " Sensor %s", sensor->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer()); - ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain()); - this->set_interval(sensor->get_name(), sensor->update_interval(), [this, sensor]{ this->request_measurement_(sensor); }); } } +void ADS1115Component::dump_config() { + ESP_LOGCONFIG(TAG, "Setting up ADS1115..."); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with ADS1115 failed!"); + } + + for (auto *sensor : this->sensors_) { + ESP_LOGCONFIG(TAG, " Sensor %s", sensor->get_name().c_str()); + ESP_LOGCONFIG(TAG, " Multiplexer: %u", sensor->get_multiplexer()); + ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain()); + } +} float ADS1115Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/ads1115_component.h b/src/esphomelib/sensor/ads1115_component.h index e2bad48b..7cbc35be 100644 --- a/src/esphomelib/sensor/ads1115_component.h +++ b/src/esphomelib/sensor/ads1115_component.h @@ -73,6 +73,7 @@ class ADS1115Component : public Component, public I2CDevice { // (In most use cases you won't need these) /// Set up the internal sensor array. void setup() override; + void dump_config() override; /// HARDWARE_LATE setup priority float get_setup_priority() const override; diff --git a/src/esphomelib/sensor/bh1750_sensor.cpp b/src/esphomelib/sensor/bh1750_sensor.cpp index a3eaa494..bbe3daa7 100644 --- a/src/esphomelib/sensor/bh1750_sensor.cpp +++ b/src/esphomelib/sensor/bh1750_sensor.cpp @@ -23,15 +23,19 @@ BH1750Sensor::BH1750Sensor(I2CComponent *parent, const std::string &name, : PollingSensorComponent(name, update_interval), I2CDevice(parent, address) {} void BH1750Sensor::setup() { - ESP_LOGCONFIG(TAG, "Setting up BS1750..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + ESP_LOGCONFIG(TAG, "Setting up BH1750 '%s'...", this->name_.c_str()); if (!this->write_bytes(BH1750_COMMAND_POWER_ON, nullptr, 0)) { - ESP_LOGE(TAG, "Communication with BH1750 failed!"); this->mark_failed(); return; } +} +void BH1750Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "BH1750 '%s':", this->name_.c_str()); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with BH1750 failed!"); + } -#ifdef ESPHOMELIB_LOG_HAS_CONFIG const char *resolution_s; switch (this->resolution_) { case BH1750_RESOLUTION_0P5_LX: resolution_s = "0.5"; break; @@ -39,8 +43,8 @@ void BH1750Sensor::setup() { case BH1750_RESOLUTION_4P0_LX: resolution_s = "4"; break; default: resolution_s = "Unknown"; break; } - ESP_LOGCONFIG(TAG, " Resolution: %s", resolution_s); -#endif + ESP_LOGCONFIG(TAG, " Resolution: %s", resolution_s); + LOG_UPDATE_INTERVAL(this); } void BH1750Sensor::update() { diff --git a/src/esphomelib/sensor/bh1750_sensor.h b/src/esphomelib/sensor/bh1750_sensor.h index 3448e7c7..da2b6085 100644 --- a/src/esphomelib/sensor/bh1750_sensor.h +++ b/src/esphomelib/sensor/bh1750_sensor.h @@ -40,6 +40,7 @@ class BH1750Sensor : public PollingSensorComponent, public I2CDevice { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; void update() override; float get_setup_priority() const override; std::string unit_of_measurement() override; diff --git a/src/esphomelib/sensor/bme280_component.cpp b/src/esphomelib/sensor/bme280_component.cpp index 2d8bd7a0..1ffcb763 100644 --- a/src/esphomelib/sensor/bme280_component.cpp +++ b/src/esphomelib/sensor/bme280_component.cpp @@ -88,10 +88,14 @@ static const char* iir_filter_to_str(BME280IIRFilter filter) { void BME280Component::setup() { ESP_LOGCONFIG(TAG, "Setting up BME280..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); uint8_t chip_id = 0; - if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id) || chip_id != 0x60) { - ESP_LOGE(TAG, "Communication with BME280 failed! Chip ID: %02X", chip_id); + if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + if (chip_id != 0x60) { + this->error_code_ = WRONG_CHIP_ID; this->mark_failed(); return; } @@ -118,11 +122,6 @@ void BME280Component::setup() { this->calibration_.h5 = read_u8(BME280_REGISTER_DIG_H5 + 1) << 4 | (read_u8(BME280_REGISTER_DIG_H5) >> 4); this->calibration_.h6 = read_u8(BME280_REGISTER_DIG_H6); - ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); - ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); - ESP_LOGCONFIG(TAG, " Humidity Oversampling: %s", oversampling_to_str(this->humidity_oversampling_)); - ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); - uint8_t humid_register = 0; if (!this->read_byte(BME280_REGISTER_CONTROLHUMID, &humid_register)) { this->mark_failed(); @@ -148,8 +147,29 @@ void BME280Component::setup() { return; } } +void BME280Component::dump_config() { + ESP_LOGCONFIG(TAG, "BME280:"); + LOG_I2C_DEVICE(this); + switch (this->error_code_) { + case COMMUNICATION_FAILED: + ESP_LOGE(TAG, "Communication with BME280 failed!"); + break; + case WRONG_CHIP_ID: + ESP_LOGE(TAG, "BMP280 has wrong chip ID! Is it a BMP280?"); + break; + case NONE: + default: + break; + } + + ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); + ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); + ESP_LOGCONFIG(TAG, " Humidity Oversampling: %s", oversampling_to_str(this->humidity_oversampling_)); + ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); + LOG_UPDATE_INTERVAL(this); +} float BME280Component::get_setup_priority() const { - return Component::get_setup_priority(); + return setup_priority::HARDWARE_LATE; } inline uint8_t oversampling_to_time(BME280Oversampling over_sampling) { diff --git a/src/esphomelib/sensor/bme280_component.h b/src/esphomelib/sensor/bme280_component.h index f3fd9dc1..87ec4e90 100644 --- a/src/esphomelib/sensor/bme280_component.h +++ b/src/esphomelib/sensor/bme280_component.h @@ -90,6 +90,7 @@ class BME280Component : public PollingComponent, public I2CDevice { BME280HumiditySensor *get_humidity_sensor() const; void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; @@ -112,6 +113,11 @@ class BME280Component : public PollingComponent, public I2CDevice { BME280TemperatureSensor *temperature_sensor_; BME280PressureSensor *pressure_sensor_; BME280HumiditySensor *humidity_sensor_; + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + WRONG_CHIP_ID, + } error_code_{NONE}; }; } // namespace sensor diff --git a/src/esphomelib/sensor/bme680_component.cpp b/src/esphomelib/sensor/bme680_component.cpp index fb8e4cab..512095d2 100644 --- a/src/esphomelib/sensor/bme680_component.cpp +++ b/src/esphomelib/sensor/bme680_component.cpp @@ -71,10 +71,8 @@ static const char* iir_filter_to_str(BME680IIRFilter filter) { void BME680Component::setup() { ESP_LOGCONFIG(TAG, "Setting up BME680..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); uint8_t chip_id; if (!this->read_byte(BME680_REGISTER_CHIPID, &chip_id) || chip_id != 0x61) { - ESP_LOGE(TAG, "Communication with BME680 failed!"); this->mark_failed(); return; } @@ -133,17 +131,6 @@ void BME680Component::setup() { this->calibration_.ambient_temperature = 25; // prime ambient temperature - ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); - ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); - ESP_LOGCONFIG(TAG, " Humidity Oversampling: %s", oversampling_to_str(this->humidity_oversampling_)); - ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); - if (this->heater_duration_ == 0 || this->heater_temperature_ == 0) { - ESP_LOGCONFIG(TAG, " Heater OFF"); - } else { - ESP_LOGCONFIG(TAG, " Heater temperature=%u°C duration=%ums", - this->heater_temperature_, this->heater_duration_); - } - // Config register uint8_t config_register; if (!this->read_byte(BME680_REGISTER_CONFIG, &config_register)) { @@ -217,6 +204,26 @@ void BME680Component::setup() { } } +void BME680Component::dump_config() { + ESP_LOGCONFIG(TAG, "BME680:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with BME680 failed!"); + } + + ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); + ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); + ESP_LOGCONFIG(TAG, " Humidity Oversampling: %s", oversampling_to_str(this->humidity_oversampling_)); + ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); + if (this->heater_duration_ == 0 || this->heater_temperature_ == 0) { + ESP_LOGCONFIG(TAG, " Heater OFF"); + } else { + ESP_LOGCONFIG(TAG, " Heater temperature=%u°C duration=%ums", + this->heater_temperature_, this->heater_duration_); + } + LOG_UPDATE_INTERVAL(this); +} + float BME680Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/bme680_component.h b/src/esphomelib/sensor/bme680_component.h index bb675f80..233782f0 100644 --- a/src/esphomelib/sensor/bme680_component.h +++ b/src/esphomelib/sensor/bme680_component.h @@ -109,6 +109,7 @@ class BME680Component : public PollingComponent, public I2CDevice { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/bmp085_component.cpp b/src/esphomelib/sensor/bmp085_component.cpp index b9252074..b648dcf0 100644 --- a/src/esphomelib/sensor/bmp085_component.cpp +++ b/src/esphomelib/sensor/bmp085_component.cpp @@ -31,10 +31,8 @@ void BMP085Component::update() { } void BMP085Component::setup() { ESP_LOGCONFIG(TAG, "Setting up BMP085..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); uint8_t data[22]; if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) { - ESP_LOGE(TAG, "Connection to BMP085 failed."); this->mark_failed(); return; } @@ -52,6 +50,14 @@ void BMP085Component::setup() { this->calibration_.mc = ((data[18] & 0xFF) << 8) | (data[19] & 0xFF); this->calibration_.md = ((data[20] & 0xFF) << 8) | (data[21] & 0xFF); } +void BMP085Component::dump_config() { + ESP_LOGCONFIG(TAG, "BMP085:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Connection with BMP085 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} BMP085Component::BMP085Component(I2CComponent *parent, const std::string &temperature_name, const std::string &pressure_name, uint32_t update_interval) diff --git a/src/esphomelib/sensor/bmp085_component.h b/src/esphomelib/sensor/bmp085_component.h index 4169d498..4b373a47 100644 --- a/src/esphomelib/sensor/bmp085_component.h +++ b/src/esphomelib/sensor/bmp085_component.h @@ -38,6 +38,7 @@ class BMP085Component : public PollingComponent, public I2CDevice { void update() override; /// Setup the sensor and test for a connection. void setup() override; + void dump_config() override; float get_setup_priority() const override; diff --git a/src/esphomelib/sensor/bmp280_component.cpp b/src/esphomelib/sensor/bmp280_component.cpp index 4d644d57..7378721d 100644 --- a/src/esphomelib/sensor/bmp280_component.cpp +++ b/src/esphomelib/sensor/bmp280_component.cpp @@ -61,10 +61,14 @@ static const char* iir_filter_to_str(BMP280IIRFilter filter) { void BMP280Component::setup() { ESP_LOGCONFIG(TAG, "Setting up BMP280..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); uint8_t chip_id = 0; - if (!this->read_byte(0xD0, &chip_id) || chip_id != 0x58) { - ESP_LOGE(TAG, "Communication with BMP280 failed! Chip ID: %02X", chip_id); + if (!this->read_byte(0xD0, &chip_id)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + if (chip_id != 0x58) { + this->error_code_ = WRONG_CHIP_ID; this->mark_failed(); return; } @@ -84,10 +88,6 @@ void BMP280Component::setup() { this->calibration_.p8 = read_s16_le(0x9C); this->calibration_.p9 = read_s16_le(0x9E); - ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); - ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); - ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); - uint8_t config_register = 0; if (!this->read_byte(BMP280_REGISTER_CONFIG, &config_register)) { this->mark_failed(); @@ -101,8 +101,27 @@ void BMP280Component::setup() { return; } } +void BMP280Component::dump_config() { + ESP_LOGCONFIG(TAG, "BMP280:"); + LOG_I2C_DEVICE(this); + switch (this->error_code_) { + case COMMUNICATION_FAILED: + ESP_LOGE(TAG, "Communication with BMP280 failed!"); + break; + case WRONG_CHIP_ID: + ESP_LOGE(TAG, "BMP280 has wrong chip ID! Is it a BME280?"); + break; + case NONE: + default: + break; + } + + ESP_LOGCONFIG(TAG, " Temperature Oversampling: %s", oversampling_to_str(this->temperature_oversampling_)); + ESP_LOGCONFIG(TAG, " Pressure Oversampling: %s", oversampling_to_str(this->pressure_oversampling_)); + ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_)); +} float BMP280Component::get_setup_priority() const { - return Component::get_setup_priority(); + return setup_priority::HARDWARE_LATE; } inline uint8_t oversampling_to_time(BMP280Oversampling over_sampling) { diff --git a/src/esphomelib/sensor/bmp280_component.h b/src/esphomelib/sensor/bmp280_component.h index f072738a..8788b95f 100644 --- a/src/esphomelib/sensor/bmp280_component.h +++ b/src/esphomelib/sensor/bmp280_component.h @@ -78,6 +78,7 @@ class BMP280Component : public PollingComponent, public I2CDevice { BMP280PressureSensor *get_pressure_sensor() const; void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; @@ -96,6 +97,11 @@ class BMP280Component : public PollingComponent, public I2CDevice { BMP280IIRFilter iir_filter_{BMP280_IIR_FILTER_OFF}; BMP280TemperatureSensor *temperature_sensor_; BMP280PressureSensor *pressure_sensor_; + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + WRONG_CHIP_ID, + } error_code_{NONE}; }; } // namespace sensor diff --git a/src/esphomelib/sensor/cse7766.cpp b/src/esphomelib/sensor/cse7766.cpp index 25499ca9..b951ccaf 100644 --- a/src/esphomelib/sensor/cse7766.cpp +++ b/src/esphomelib/sensor/cse7766.cpp @@ -11,9 +11,6 @@ namespace sensor { static const char *TAG = "sensor.cse7766"; -void CSE7766Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up CSE7766..."); -} void CSE7766Component::loop() { const uint32_t now = millis(); if (now - this->last_transmission_ >= 500) { diff --git a/src/esphomelib/sensor/cse7766.h b/src/esphomelib/sensor/cse7766.h index 53a6059c..b157a1fb 100644 --- a/src/esphomelib/sensor/cse7766.h +++ b/src/esphomelib/sensor/cse7766.h @@ -28,7 +28,6 @@ class CSE7766Component : public Component, public UARTDevice { CSE7766PowerSensor *make_power_sensor(const std::string &name); - void setup() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/sensor/dallas_component.cpp b/src/esphomelib/sensor/dallas_component.cpp index 9f3ee0b4..ebb3db5b 100644 --- a/src/esphomelib/sensor/dallas_component.cpp +++ b/src/esphomelib/sensor/dallas_component.cpp @@ -39,56 +39,67 @@ void DallasComponent::set_one_wire(ESPOneWire *one_wire) { } void DallasComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); - ESP_LOGCONFIG(TAG, " Want device count: %u", this->sensors_.size()); yield(); disable_interrupts(); std::vector raw_sensors = this->one_wire_->search_vec(); enable_interrupts(); - std::vector out; + for (auto &address : raw_sensors) { + std::string s = uint64_to_string(address); + auto *address8 = reinterpret_cast(&address); + if (crc8(address8, 7) != address8[7]) { + ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", s.c_str()); + continue; + } + if (address8[0] != DALLAS_MODEL_DS18S20 && address8[0] != DALLAS_MODEL_DS1822 && + address8[0] != DALLAS_MODEL_DS18B20 && address8[0] != DALLAS_MODEL_DS1825 && + address8[0] != DALLAS_MODEL_DS28EA00) { + ESP_LOGW(TAG, "Unknown device type 0x%02X.", address8[0]); + continue; + } + this->found_sensors_.push_back(address); + } - if (raw_sensors.empty()) { - ESP_LOGE(TAG, "Found no sensors!"); - } else { - ESP_LOGD(TAG, "Found sensors:"); - for (auto &address : raw_sensors) { - std::string s = uint64_to_string(address); - auto *address8 = reinterpret_cast(&address); - if (crc8(address8, 7) != address8[7]) { - ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", s.c_str()); - continue; - } - if (address8[0] != DALLAS_MODEL_DS18S20 && address8[0] != DALLAS_MODEL_DS1822 && - address8[0] != DALLAS_MODEL_DS18B20 && address8[0] != DALLAS_MODEL_DS1825 && - address8[0] != DALLAS_MODEL_DS28EA00) { - ESP_LOGW(TAG, "Unknown device type 0x%02X.", address8[0]); + for (auto sensor : this->sensors_) { + if (sensor->get_index().has_value()) { + if (*sensor->get_index() >= this->found_sensors_.size()) { + this->status_set_error(); continue; } + sensor->set_address(this->found_sensors_[*sensor->get_index()]); + } + + if (!sensor->setup_sensor_()) { + this->status_set_error(); + } + } +} +void DallasComponent::dump_config() { + ESP_LOGCONFIG(TAG, "DallasComponent:"); + LOG_PIN(" Pin: ", this->one_wire_->get_pin()); + + if (this->found_sensors_.empty()) { + ESP_LOGW(TAG, " Found no sensors!"); + } else { + ESP_LOGD(TAG, " Found sensors:"); + for (auto &address : this->found_sensors_) { + std::string s = uint64_to_string(address); ESP_LOGD(TAG, " 0x%s", s.c_str()); - out.push_back(address); } } for (auto sensor : this->sensors_) { - ESP_LOGCONFIG(TAG, "Device '%s':", sensor->get_name().c_str()); - if (sensor->get_address() == 0) { - ESP_LOGCONFIG(TAG, " Index %u", sensor->get_index()); - if (sensor->get_index() >= out.size()) { + ESP_LOGCONFIG(TAG, " Device '%s':", sensor->get_name().c_str()); + if (sensor->get_index().has_value()) { + ESP_LOGCONFIG(TAG, " Index %u", *sensor->get_index()); + if (*sensor->get_index() >= this->found_sensors_.size()) { ESP_LOGE(TAG, "Couldn't find sensor by index - not connected. Proceeding without it."); - this->status_set_error(); continue; } - sensor->set_address(out[sensor->get_index()]); - ESP_LOGCONFIG(TAG, " -> Address: %s", sensor->get_address_name().c_str()); - } else { - ESP_LOGCONFIG(TAG, " Address: %s", sensor->get_address_name().c_str()); } + ESP_LOGCONFIG(TAG, " Address: %s", sensor->get_address_name().c_str()); ESP_LOGCONFIG(TAG, " Resolution: %u", sensor->get_resolution()); - - if (!sensor->setup_sensor_()) { - this->status_set_error(); - } } } @@ -175,7 +186,7 @@ uint8_t DallasTemperatureSensor::get_resolution() const { void DallasTemperatureSensor::set_resolution(uint8_t resolution) { this->resolution_ = resolution; } -uint8_t DallasTemperatureSensor::get_index() const { +optional DallasTemperatureSensor::get_index() const { return this->index_; } void DallasTemperatureSensor::set_index(uint8_t index) { diff --git a/src/esphomelib/sensor/dallas_component.h b/src/esphomelib/sensor/dallas_component.h index 21cab0d6..f233c1fd 100644 --- a/src/esphomelib/sensor/dallas_component.h +++ b/src/esphomelib/sensor/dallas_component.h @@ -51,6 +51,7 @@ class DallasComponent : public PollingComponent { /// Set up individual sensors and update intervals. void setup() override; + void dump_config() override; /// HARDWARE_LATE setup priority. float get_setup_priority() const override; @@ -61,6 +62,7 @@ class DallasComponent : public PollingComponent { protected: ESPOneWire *one_wire_; std::vector sensors_; + std::vector found_sensors_; }; /// Internal class that helps us create multiple sensors for one Dallas hub. @@ -84,7 +86,7 @@ class DallasTemperatureSensor : public EmptyPollingParentSensor<1, ICON_EMPTY, U /// Set the 64-bit unsigned address for this sensor. void set_address(uint64_t address); /// Get the index of this sensor. (0 if using address.) - uint8_t get_index() const; + optional get_index() const; /// Set the index of this sensor. If using index, address will be set after setup. void set_index(uint8_t index); /// Get the set resolution for this sensor. @@ -104,7 +106,7 @@ class DallasTemperatureSensor : public EmptyPollingParentSensor<1, ICON_EMPTY, U std::string unique_id() override; protected: uint64_t address_; - uint8_t index_; + optional index_; uint8_t resolution_; std::string address_name_; @@ -117,4 +119,4 @@ ESPHOMELIB_NAMESPACE_END #endif //USE_DALLAS_SENSOR -#endif //ESPHOMELIB_SENSOR_DALLAS_COMPONENT_H \ No newline at end of file +#endif //ESPHOMELIB_SENSOR_DALLAS_COMPONENT_H diff --git a/src/esphomelib/sensor/dht12_component.cpp b/src/esphomelib/sensor/dht12_component.cpp index ce776c33..ee64364a 100644 --- a/src/esphomelib/sensor/dht12_component.cpp +++ b/src/esphomelib/sensor/dht12_component.cpp @@ -48,14 +48,20 @@ void DHT12Component::update() { this->status_clear_warning(); } void DHT12Component::setup() { - ESP_LOGD(TAG, "Setting up DHT12..."); + ESP_LOGCONFIG(TAG, "Setting up DHT12..."); uint8_t data[5]; if (!this->read_data_(data)) { - ESP_LOGE(TAG, "Communication with DHT12 on 0x%02X failed!", this->address_); this->mark_failed(); return; } } +void DHT12Component::dump_config() { + ESP_LOGD(TAG, "DHT12:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with DHT12 failed!"); + } +} float DHT12Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/dht12_component.h b/src/esphomelib/sensor/dht12_component.h index ba15790a..9751effe 100644 --- a/src/esphomelib/sensor/dht12_component.h +++ b/src/esphomelib/sensor/dht12_component.h @@ -24,6 +24,7 @@ class DHT12Component : public PollingComponent, public I2CDevice { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; DHT12TemperatureSensor *get_temperature_sensor() const; diff --git a/src/esphomelib/sensor/dht_component.cpp b/src/esphomelib/sensor/dht_component.cpp index 1d047dfd..f7b21040 100644 --- a/src/esphomelib/sensor/dht_component.cpp +++ b/src/esphomelib/sensor/dht_component.cpp @@ -31,22 +31,34 @@ void DHTComponent::setup() { this->pin_->setup(); this->pin_->digital_write(true); } +void DHTComponent::dump_config() { + ESP_LOGCONFIG(TAG, "DHT:"); + LOG_PIN(" Pin: ", this->pin_); + if (this->is_auto_detect_) { + ESP_LOGCONFIG(TAG, " Auto-detected model: %s", this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22"); + } else if (this->model_ == DHT_MODEL_DHT11) { + ESP_LOGCONFIG(TAG, " Model: DHT11"); + } else { + ESP_LOGCONFIG(TAG, " Model: DHT22 (or equivalent)"); + } + + LOG_UPDATE_INTERVAL(this); +} void DHTComponent::update() { float temperature, humidity; + bool error; if (this->model_ == DHT_MODEL_AUTO_DETECT) { this->model_ = DHT_MODEL_DHT22; - bool error = this->read_sensor_(&temperature, &humidity, false); + error = this->read_sensor_(&temperature, &humidity, false); if (error) { this->model_ = DHT_MODEL_DHT11; - ESP_LOGCONFIG(TAG, "Auto-detected model DHT11. Override with the 'model:' configuration option"); - } else { - ESP_LOGCONFIG(TAG, "Auto-detected model DHT22. Override with the 'model:' configuration option"); + return; } - return; + } else { + error = this->read_sensor_(&temperature, &humidity, true); } - bool error = this->read_sensor_(&temperature, &humidity, true); if (error) { ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity); @@ -54,8 +66,11 @@ void DHTComponent::update() { this->humidity_sensor_->publish_state(humidity); this->status_clear_warning(); } else { - ESP_LOGW(TAG, "Invalid readings! Please check your wiring (pull-up resistor, pin_ number) and " - "consider manually specifying the DHT model using the model option. Error code: %d", error); + const char *str = ""; + if (this->is_auto_detect_) { + str = " and consider manually specifying the DHT model using the model option"; + } + ESP_LOGW(TAG, "Invalid readings! Please check your wiring (pull-up resistor, pin_ number)%s.", str); this->status_set_warning(); } } @@ -65,6 +80,7 @@ float DHTComponent::get_setup_priority() const { } void DHTComponent::set_dht_model(DHTModel model) { this->model_ = model; + this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT; } DHTTemperatureSensor *DHTComponent::get_temperature_sensor() const { return this->temperature_sensor_; diff --git a/src/esphomelib/sensor/dht_component.h b/src/esphomelib/sensor/dht_component.h index 25d1208c..2f0b2c3e 100644 --- a/src/esphomelib/sensor/dht_component.h +++ b/src/esphomelib/sensor/dht_component.h @@ -54,6 +54,7 @@ class DHTComponent : public PollingComponent { /// Set up the pins and check connection. void setup() override; + void dump_config() override; /// Update sensor values and push them to the frontend. void update() override; /// HARDWARE_LATE setup priority. @@ -64,6 +65,7 @@ class DHTComponent : public PollingComponent { GPIOPin *pin_; DHTModel model_{DHT_MODEL_AUTO_DETECT}; + bool is_auto_detect_{false}; DHTTemperatureSensor *temperature_sensor_; DHTHumiditySensor *humidity_sensor_; }; diff --git a/src/esphomelib/sensor/duty_cycle_sensor.cpp b/src/esphomelib/sensor/duty_cycle_sensor.cpp index 3d5e2541..ddd33131 100644 --- a/src/esphomelib/sensor/duty_cycle_sensor.cpp +++ b/src/esphomelib/sensor/duty_cycle_sensor.cpp @@ -13,13 +13,12 @@ static const char *TAG = "sensor.duty_cycle"; DutyCycleSensor::DutyCycleSensor(const std::string &name, GPIOPin *pin, uint32_t update_interval) : PollingSensorComponent(name, update_interval), pin_(pin) { - this->pin_number_ = pin->get_pin(); - this->pin_inverted_ = pin->is_inverted(); + } DutyCycleSensor *duty_cycle_sensors = nullptr; -void ICACHE_RAM_ATTR DutyCycleSensor::gpio_intr() { +void ICACHE_RAM_ATTR HOT DutyCycleSensor::gpio_intr() { DutyCycleSensor *sensor = duty_cycle_sensors; while (sensor != nullptr) { sensor->on_interrupt(); @@ -45,8 +44,13 @@ void DutyCycleSensor::setup() { attachInterrupt(this->pin_->get_pin(), gpio_intr, CHANGE); } -void ICACHE_RAM_ATTR DutyCycleSensor::on_interrupt() { - const bool new_level = digitalRead(this->pin_number_) != int(this->pin_inverted_); +void DutyCycleSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Duty Cycle Sensor '%s':", this->name_.c_str()); + LOG_PIN(" Pin: ", this->pin_); + LOG_UPDATE_INTERVAL(this); +} +void ICACHE_RAM_ATTR HOT DutyCycleSensor::on_interrupt() { + const bool new_level = this->pin_->digital_read(); if (new_level == this->last_level_) return; this->last_level_ = new_level; @@ -85,6 +89,9 @@ std::string DutyCycleSensor::icon() { int8_t DutyCycleSensor::accuracy_decimals() { return 1; } +float DutyCycleSensor::get_setup_priority() const { + return setup_priority::HARDWARE_LATE; +} } // namespace sensor diff --git a/src/esphomelib/sensor/duty_cycle_sensor.h b/src/esphomelib/sensor/duty_cycle_sensor.h index 6fde9742..aa0a5e59 100644 --- a/src/esphomelib/sensor/duty_cycle_sensor.h +++ b/src/esphomelib/sensor/duty_cycle_sensor.h @@ -16,6 +16,8 @@ class DutyCycleSensor : public PollingSensorComponent { DutyCycleSensor(const std::string &name, GPIOPin *pin, uint32_t update_interval = 15000); void setup() override; + float get_setup_priority() const override; + void dump_config() override; void update() override; std::string unit_of_measurement() override; std::string icon() override; @@ -31,9 +33,6 @@ class DutyCycleSensor : public PollingSensorComponent { volatile uint32_t on_time_{0}; volatile bool last_level_{false}; DutyCycleSensor *next_; - // Store the pin number locally, due to IRAM_ATTR - uint8_t pin_number_; - bool pin_inverted_; }; extern DutyCycleSensor *duty_cycle_sensors; diff --git a/src/esphomelib/sensor/filter.cpp b/src/esphomelib/sensor/filter.cpp index 298f03ae..1626c5e1 100644 --- a/src/esphomelib/sensor/filter.cpp +++ b/src/esphomelib/sensor/filter.cpp @@ -215,6 +215,9 @@ DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) { } +float DebounceFilter::get_setup_priority() const { + return setup_priority::HARDWARE; +} HeartbeatFilter::HeartbeatFilter(uint32_t time_period) : time_period_(time_period), last_input_(NAN) { @@ -234,6 +237,9 @@ void HeartbeatFilter::setup() { this->output_(this->last_input_); }); } +float HeartbeatFilter::get_setup_priority() const { + return setup_priority::HARDWARE; +} } // namespace sensor diff --git a/src/esphomelib/sensor/filter.h b/src/esphomelib/sensor/filter.h index 41da0be8..876ada14 100644 --- a/src/esphomelib/sensor/filter.h +++ b/src/esphomelib/sensor/filter.h @@ -188,6 +188,8 @@ class DebounceFilter : public Filter, public Component { optional new_value(float value) override; + float get_setup_priority() const override; + protected: uint32_t time_period_; }; @@ -202,6 +204,8 @@ class HeartbeatFilter : public Filter, public Component { uint32_t expected_interval(uint32_t input) override; + float get_setup_priority() const override; + protected: uint32_t time_period_; float last_input_; diff --git a/src/esphomelib/sensor/hdc1080_component.cpp b/src/esphomelib/sensor/hdc1080_component.cpp index 95ad42f7..5af32483 100644 --- a/src/esphomelib/sensor/hdc1080_component.cpp +++ b/src/esphomelib/sensor/hdc1080_component.cpp @@ -37,11 +37,18 @@ void HDC1080Component::setup() { }; if (this->write_bytes(HDC1080_CMD_CONFIGURATION, data, 2)) { - ESP_LOGE(TAG, "Connection to HDC1080 failed"); this->mark_failed(); return; } } +void HDC1080Component::dump_config() { + ESP_LOGCONFIG(TAG, "HDC1080:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with HDC1080 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} void HDC1080Component::update() { uint16_t raw_temp; if (!this->read_byte_16(HDC1080_CMD_TEMPERATURE, &raw_temp, 9)) { diff --git a/src/esphomelib/sensor/hdc1080_component.h b/src/esphomelib/sensor/hdc1080_component.h index eb4e7c6c..e75b56ae 100644 --- a/src/esphomelib/sensor/hdc1080_component.h +++ b/src/esphomelib/sensor/hdc1080_component.h @@ -31,6 +31,7 @@ class HDC1080Component : public PollingComponent, public I2CDevice { // (In most use cases you won't need these) /// Setup the sensor and check for connection. void setup() override; + void dump_config() override; /// Retrieve the latest sensor values. This operation takes approximately 16ms. void update() override; diff --git a/src/esphomelib/sensor/hlw8012.cpp b/src/esphomelib/sensor/hlw8012.cpp index 59413d44..e5d0f2f2 100644 --- a/src/esphomelib/sensor/hlw8012.cpp +++ b/src/esphomelib/sensor/hlw8012.cpp @@ -30,6 +30,16 @@ void HLW8012Component::setup() { return; } } +void HLW8012Component::dump_config() { + ESP_LOGCONFIG(TAG, "HLW8012:"); + LOG_PIN(" SEL Pin: ", this->sel_pin_); + LOG_PIN(" CF Pin: ", this->cf_.get_pin()); + LOG_PIN(" CF1 Pin: ", this->cf1_.get_pin()); + ESP_LOGCONFIG(TAG, " Change measurement mode every %u", this->change_mode_every_); + ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f); + ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_); + LOG_UPDATE_INTERVAL(this); +} float HLW8012Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/hlw8012.h b/src/esphomelib/sensor/hlw8012.h index 18c888d1..af662d79 100644 --- a/src/esphomelib/sensor/hlw8012.h +++ b/src/esphomelib/sensor/hlw8012.h @@ -36,6 +36,7 @@ class HLW8012Component : public PollingComponent { HLW8012Component(GPIOPin *sel_pin, uint8_t cf_pin, uint8_t cf1_pin, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/hmc5883l.cpp b/src/esphomelib/sensor/hmc5883l.cpp index ae1b1dfc..bea21e94 100644 --- a/src/esphomelib/sensor/hmc5883l.cpp +++ b/src/esphomelib/sensor/hmc5883l.cpp @@ -31,13 +31,13 @@ void HMC5883LComponent::setup() { if (!this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_A, &id[0]) || !this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_B, &id[1]) || !this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_C, &id[2])) { - ESP_LOGE(TAG, "Communication with HMC5883L failed!"); + this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; } if (id[0] != 0x48 || id[1] != 0x34 || id[2] != 0x33) { - ESP_LOGE(TAG, "The ID registers don't match - Is this really an HMC5883L?"); + this->error_code_ = ID_REGISTERS; this->mark_failed(); return; } @@ -50,6 +50,7 @@ void HMC5883LComponent::setup() { // 0b000000xx << 0 Measurement Mode - 0b00=high impedance on load config_a |= 0b00000000; if (!this->write_byte(HMC5883L_REGISTER_CONFIG_A, config_a)) { + this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; } @@ -57,6 +58,7 @@ void HMC5883LComponent::setup() { uint8_t config_b = 0; config_b |= this->range_ << 5; if (!this->write_byte(HMC5883L_REGISTER_CONFIG_B, config_b)) { + this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; } @@ -66,10 +68,22 @@ void HMC5883LComponent::setup() { mode |= 0b00; if (!this->write_byte(HMC5883L_REGISTER_MODE, mode)) { + this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; } } +void HMC5883LComponent::dump_config() { + ESP_LOGCONFIG(TAG, "HMC5883L:"); + LOG_I2C_DEVICE(this); + if (this->error_code_ == COMMUNICATION_FAILED) { + ESP_LOGE(TAG, "Communication with HMC5883L failed!"); + } else if (this->error_code_ == ID_REGISTERS) { + ESP_LOGE(TAG, "The ID registers don't match - Is this really an HMC5883L?"); + } + + LOG_UPDATE_INTERVAL(this); +} float HMC5883LComponent::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/hmc5883l.h b/src/esphomelib/sensor/hmc5883l.h index ebbb1e55..31e2edab 100644 --- a/src/esphomelib/sensor/hmc5883l.h +++ b/src/esphomelib/sensor/hmc5883l.h @@ -31,6 +31,7 @@ class HMC5883LComponent : public PollingComponent, public I2CDevice { HMC5883LComponent(I2CComponent *parent, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; @@ -47,6 +48,11 @@ class HMC5883LComponent : public PollingComponent, public I2CDevice { HMC5883LFieldStrengthSensor *y_sensor_; HMC5883LFieldStrengthSensor *z_sensor_; HMC5883LHeadingSensor *heading_sensor_; + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + ID_REGISTERS, + } error_code_; }; } // namespace sensor diff --git a/src/esphomelib/sensor/htu21d_component.cpp b/src/esphomelib/sensor/htu21d_component.cpp index f4cd034b..6272228c 100644 --- a/src/esphomelib/sensor/htu21d_component.cpp +++ b/src/esphomelib/sensor/htu21d_component.cpp @@ -33,7 +33,6 @@ void HTU21DComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up HTU21D..."); if (!this->write_bytes(HTU21D_REGISTER_RESET, nullptr, 0)) { - ESP_LOGE(TAG, "Connection to HTU21D failed."); this->mark_failed(); return; } @@ -41,6 +40,14 @@ void HTU21DComponent::setup() { // Wait for software reset to complete delay(15); } +void HTU21DComponent::dump_config() { + ESP_LOGCONFIG(TAG, "HTU21D:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with HTU21D failed!"); + } + LOG_UPDATE_INTERVAL(this); +} void HTU21DComponent::update() { uint16_t raw_temperature; if (!this->read_byte_16(HTU21D_REGISTER_TEMPERATURE, &raw_temperature, 50)) { diff --git a/src/esphomelib/sensor/htu21d_component.h b/src/esphomelib/sensor/htu21d_component.h index 49b78e58..d1db5f3d 100644 --- a/src/esphomelib/sensor/htu21d_component.h +++ b/src/esphomelib/sensor/htu21d_component.h @@ -37,6 +37,7 @@ class HTU21DComponent : public PollingComponent, public I2CDevice { /// Setup (reset) the sensor and check connection. void setup() override; + void dump_config() override; /// Update the sensor values (temperature+humidity). void update() override; diff --git a/src/esphomelib/sensor/hx711.cpp b/src/esphomelib/sensor/hx711.cpp index 0bd94b1a..63601470 100644 --- a/src/esphomelib/sensor/hx711.cpp +++ b/src/esphomelib/sensor/hx711.cpp @@ -19,6 +19,13 @@ void HX711Sensor::setup() { // Read sensor once without publishing to set the gain this->read_sensor_(nullptr); } + +void HX711Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "HX711 '%s':", this->name_.c_str()); + LOG_PIN(" DOUT Pin: ", this->dout_pin_); + LOG_PIN(" SCK Pin: ", this->sck_pin_); + LOG_UPDATE_INTERVAL(this); +} float HX711Sensor::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/hx711.h b/src/esphomelib/sensor/hx711.h index e7531880..3d488022 100644 --- a/src/esphomelib/sensor/hx711.h +++ b/src/esphomelib/sensor/hx711.h @@ -22,6 +22,7 @@ class HX711Sensor : public PollingSensorComponent { HX711Sensor(const std::string &name, GPIOPin *dout, GPIOPin *sck, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/ina219.cpp b/src/esphomelib/sensor/ina219.cpp index b3e8be26..7088ca91 100644 --- a/src/esphomelib/sensor/ina219.cpp +++ b/src/esphomelib/sensor/ina219.cpp @@ -39,11 +39,10 @@ static const uint8_t INA219_REGISTER_CURRENT = 0x04; static const uint8_t INA219_REGISTER_CALIBRATION = 0x05; void INA219Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up INA219 with address=0x%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up INA219..."); // Config Register // 0bx000000000000000 << 15 RESET Bit (1 -> trigger reset) if (!this->write_byte_16(INA219_REGISTER_CONFIG, 0x8000)) { - ESP_LOGE(TAG, "Resetting INA219 failed!"); this->mark_failed(); return; } @@ -135,6 +134,19 @@ void INA219Component::setup() { } } +void INA219Component::dump_config() { + ESP_LOGCONFIG(TAG, "INA219:"); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with INA219 failed!"); + this->mark_failed(); + return; + } + + LOG_UPDATE_INTERVAL(this); +} + float INA219Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/ina219.h b/src/esphomelib/sensor/ina219.h index e4cf053c..e45c4773 100644 --- a/src/esphomelib/sensor/ina219.h +++ b/src/esphomelib/sensor/ina219.h @@ -23,6 +23,7 @@ class INA219Component : public PollingComponent, public I2CDevice { float shunt_resistance_ohm, float max_current_a, float max_voltage_v, uint8_t address = 0x40, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/ina3221.cpp b/src/esphomelib/sensor/ina3221.cpp index d0b331f0..0e25fd6e 100644 --- a/src/esphomelib/sensor/ina3221.cpp +++ b/src/esphomelib/sensor/ina3221.cpp @@ -26,11 +26,10 @@ static const uint8_t INA3221_REGISTER_CHANNEL3_BUS_VOLTAGE = 0x06; // A0 = SCL -> 0x43 void INA3221Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up INA3221 with address=%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up INA3221..."); // Config Register // 0bx000000000000000 << 15 RESET Bit (1 -> trigger reset) if (!this->write_byte_16(INA3221_REGISTER_CONFIG, 0x8000)) { - ESP_LOGE(TAG, "Resetting INA219Component failed!"); this->mark_failed(); return; } @@ -59,7 +58,16 @@ void INA3221Component::setup() { this->mark_failed(); return; } +} + +void INA3221Component::dump_config() { + ESP_LOGCONFIG(TAG, "INA3221:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with INA3221 failed!"); + } + LOG_UPDATE_INTERVAL(this); } inline uint8_t ina3221_bus_voltage_register(int channel) { diff --git a/src/esphomelib/sensor/ina3221.h b/src/esphomelib/sensor/ina3221.h index 1129acd8..57e70678 100644 --- a/src/esphomelib/sensor/ina3221.h +++ b/src/esphomelib/sensor/ina3221.h @@ -20,6 +20,7 @@ class INA3221Component : public PollingComponent, public I2CDevice { public: INA3221Component(I2CComponent *parent, uint8_t address = 0x40, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; void update() override; float get_setup_priority() const override; diff --git a/src/esphomelib/sensor/max6675_sensor.cpp b/src/esphomelib/sensor/max6675_sensor.cpp index fa2220c5..293f4fb0 100644 --- a/src/esphomelib/sensor/max6675_sensor.cpp +++ b/src/esphomelib/sensor/max6675_sensor.cpp @@ -25,9 +25,14 @@ void MAX6675Sensor::update() { } void MAX6675Sensor::setup() { - ESP_LOGCONFIG(TAG, "Setting up MAX6675Sensor '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Setting up MAX6675Sensor '%s'...", this->name_.c_str()); this->spi_setup(); } +void MAX6675Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "MAX6675 '%s':", this->name_.c_str()); + LOG_PIN(" CS Pin: ", this->cs_); + LOG_UPDATE_INTERVAL(this); +} float MAX6675Sensor::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/max6675_sensor.h b/src/esphomelib/sensor/max6675_sensor.h index 1c0284f1..67bcf6e9 100644 --- a/src/esphomelib/sensor/max6675_sensor.h +++ b/src/esphomelib/sensor/max6675_sensor.h @@ -17,6 +17,7 @@ class MAX6675Sensor : public PollingSensorComponent, public SPIDevice { MAX6675Sensor(const std::string &name, SPIComponent *parent, GPIOPin *cs, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/mhz19_component.cpp b/src/esphomelib/sensor/mhz19_component.cpp index ecefebcd..88016afc 100644 --- a/src/esphomelib/sensor/mhz19_component.cpp +++ b/src/esphomelib/sensor/mhz19_component.cpp @@ -78,9 +78,6 @@ MHZ19TemperatureSensor *MHZ19Component::make_temperature_sensor(const std::strin MHZ19CO2Sensor *MHZ19Component::get_co2_sensor() const { return this->co2_sensor_; } -void MHZ19Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up MHZ19..."); -} float MHZ19Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/mhz19_component.h b/src/esphomelib/sensor/mhz19_component.h index a1d3f509..64e3cb83 100644 --- a/src/esphomelib/sensor/mhz19_component.h +++ b/src/esphomelib/sensor/mhz19_component.h @@ -20,9 +20,7 @@ class MHZ19Component : public PollingComponent, public UARTDevice { public: MHZ19Component(UARTComponent *parent, const std::string &name, uint32_t update_interval = 15000); - - void setup() override; - + float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/mpu6050_component.cpp b/src/esphomelib/sensor/mpu6050_component.cpp index b000a3a8..4b9e7ce0 100644 --- a/src/esphomelib/sensor/mpu6050_component.cpp +++ b/src/esphomelib/sensor/mpu6050_component.cpp @@ -36,22 +36,21 @@ MPU6050Component::MPU6050Component(I2CComponent *parent, uint8_t address, uint32 } void MPU6050Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up MPU6050 on address 0x%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up MPU6050..."); uint8_t who_am_i; if (!this->read_byte(MPU6050_REGISTER_WHO_AM_I, &who_am_i) || who_am_i != 0x68) { - ESP_LOGE(TAG, "Can't communicate with MPU6050."); this->mark_failed(); return; } - ESP_LOGV(TAG, " Setting up Power Management..."); + ESP_LOGV(TAG, " Setting up Power Management..."); // Setup power management uint8_t power_management; if (!this->read_byte(MPU6050_REGISTER_POWER_MANAGEMENT_1, &power_management)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Input power_management: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(power_management)); + ESP_LOGV(TAG, " Input power_management: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(power_management)); // Set clock source - X-Gyro power_management &= 0b11111000; power_management |= MPU6050_CLOCK_SOURCE_X_GYRO; @@ -59,29 +58,29 @@ void MPU6050Component::setup() { power_management &= ~(1 << MPU6050_BIT_SLEEP_ENABLED); // Enable temperature power_management &= ~(1 << MPU6050_BIT_TEMPERATURE_DISABLED); - ESP_LOGV(TAG, " Output power_management: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(power_management)); + ESP_LOGV(TAG, " Output power_management: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(power_management)); if (!this->write_byte(MPU6050_REGISTER_POWER_MANAGEMENT_1, power_management)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Setting up Gyro Config..."); + ESP_LOGV(TAG, " Setting up Gyro Config..."); // Set scale - 2000DPS uint8_t gyro_config; if (!this->read_byte(MPU6050_REGISTER_GYRO_CONFIG, &gyro_config)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Input gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); + ESP_LOGV(TAG, " Input gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); gyro_config &= 0b11100111; gyro_config |= MPU6050_SCALE_2000_DPS << 3; - ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); + ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config)); if (!this->write_byte(MPU6050_REGISTER_GYRO_CONFIG, gyro_config)) { this->mark_failed(); return; } - ESP_LOGV(TAG, " Setting up Accel Config..."); + ESP_LOGV(TAG, " Setting up Accel Config..."); // Set range - 2G uint8_t accel_config; if (!this->read_byte(MPU6050_REGISTER_ACCEL_CONFIG, &accel_config)) { @@ -97,6 +96,14 @@ void MPU6050Component::setup() { return; } } +void MPU6050Component::dump_config() { + ESP_LOGCONFIG(TAG, "MPU6050:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with MPU6050 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} void MPU6050Component::update() { ESP_LOGV(TAG, " Updating MPU6050..."); diff --git a/src/esphomelib/sensor/mpu6050_component.h b/src/esphomelib/sensor/mpu6050_component.h index 3112a0e0..3439a681 100644 --- a/src/esphomelib/sensor/mpu6050_component.h +++ b/src/esphomelib/sensor/mpu6050_component.h @@ -22,6 +22,7 @@ class MPU6050Component : public PollingComponent, public I2CDevice { explicit MPU6050Component(I2CComponent *parent, uint8_t address = 0x68, uint32_t update_interval = 15000); void setup() override; + void dump_config() override; void update() override; diff --git a/src/esphomelib/sensor/mqtt_sensor_component.cpp b/src/esphomelib/sensor/mqtt_sensor_component.cpp index c2efa274..2df7468c 100644 --- a/src/esphomelib/sensor/mqtt_sensor_component.cpp +++ b/src/esphomelib/sensor/mqtt_sensor_component.cpp @@ -20,19 +20,24 @@ MQTTSensorComponent::MQTTSensorComponent(Sensor *sensor) } void MQTTSensorComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT Sensor '%s'...", this->sensor_->get_name().c_str()); + auto f = std::bind(&MQTTSensorComponent::publish_state, this, std::placeholders::_1); + this->sensor_->add_on_state_callback(f); +} + +void MQTTSensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Sensor '%s':", this->sensor_->get_name().c_str()); if (this->get_expire_after() > 0) { - ESP_LOGCONFIG(TAG, " Expire After: %us", this->get_expire_after() / 1000); + ESP_LOGCONFIG(TAG, " Expire After: %us", this->get_expire_after() / 1000); + } + ESP_LOGCONFIG(TAG, " Unit of Measurement: '%s'", this->sensor_->get_unit_of_measurement().c_str()); + ESP_LOGCONFIG(TAG, " Accuracy Decimals: %d", this->sensor_->get_accuracy_decimals()); + if (!this->sensor_->get_icon().empty()) { + ESP_LOGCONFIG(TAG, " Icon: '%s'", this->sensor_->get_icon().c_str()); } - ESP_LOGCONFIG(TAG, " Unit of Measurement: '%s'", this->sensor_->get_unit_of_measurement().c_str()); - ESP_LOGCONFIG(TAG, " Accuracy Decimals: %i", this->sensor_->get_accuracy_decimals()); - ESP_LOGCONFIG(TAG, " Icon: '%s'", this->sensor_->get_icon().c_str()); if (!this->sensor_->unique_id().empty()) { - ESP_LOGCONFIG(TAG, " Unique ID: '%s'", this->sensor_->unique_id().c_str()); + ESP_LOGCONFIG(TAG, " Unique ID: '%s'", this->sensor_->unique_id().c_str()); } - - auto f = std::bind(&MQTTSensorComponent::publish_state, this, std::placeholders::_1); - this->sensor_->add_on_state_callback(f); + LOG_MQTT_COMPONENT(true, false) } std::string MQTTSensorComponent::component_type() const { diff --git a/src/esphomelib/sensor/mqtt_sensor_component.h b/src/esphomelib/sensor/mqtt_sensor_component.h index 478a9c27..c0cbac44 100644 --- a/src/esphomelib/sensor/mqtt_sensor_component.h +++ b/src/esphomelib/sensor/mqtt_sensor_component.h @@ -38,6 +38,8 @@ class MQTTSensorComponent : public mqtt::MQTTComponent { /// Override setup. void setup() override; + void dump_config() override; + /// Get the expire_after in milliseconds used for Home Assistant discovery, first checks override. uint32_t get_expire_after() const; diff --git a/src/esphomelib/sensor/mqtt_subscribe_sensor.cpp b/src/esphomelib/sensor/mqtt_subscribe_sensor.cpp index 4dfa40c0..00e7eb22 100644 --- a/src/esphomelib/sensor/mqtt_subscribe_sensor.cpp +++ b/src/esphomelib/sensor/mqtt_subscribe_sensor.cpp @@ -38,6 +38,10 @@ float MQTTSubscribeSensor::get_setup_priority() const { void MQTTSubscribeSensor::set_qos(uint8_t qos) { this->qos_ = qos; } +void MQTTSubscribeSensor::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Subscribe Sensor '%s':", this->name_.c_str()); + ESP_LOGCONFIG(TAG, " Topic: %s", this->topic_.c_str()); +} } // namespace sensor diff --git a/src/esphomelib/sensor/mqtt_subscribe_sensor.h b/src/esphomelib/sensor/mqtt_subscribe_sensor.h index 09eff70c..d85ce4a0 100644 --- a/src/esphomelib/sensor/mqtt_subscribe_sensor.h +++ b/src/esphomelib/sensor/mqtt_subscribe_sensor.h @@ -17,6 +17,7 @@ class MQTTSubscribeSensor : public Sensor, public Component { MQTTSubscribeSensor(const std::string &name, std::string topic); void setup() override; + void dump_config() override; float get_setup_priority() const override; void set_qos(uint8_t qos); diff --git a/src/esphomelib/sensor/ms5611.cpp b/src/esphomelib/sensor/ms5611.cpp index c5dd5d07..83942f5f 100644 --- a/src/esphomelib/sensor/ms5611.cpp +++ b/src/esphomelib/sensor/ms5611.cpp @@ -19,21 +19,27 @@ static const uint8_t MS5611_CMD_CONV_D2 = 0x50; static const uint8_t MS5611_CMD_READ_PROM = 0xA2; void MS5611Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up MS5611 with address=0x%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up MS5611..."); if (!this->write_bytes(MS5611_CMD_RESET, nullptr, 0)) { - ESP_LOGE(TAG, "Communication with MS5611 failed!"); this->mark_failed(); return; } delay(100); for (uint8_t offset = 0; offset < 6; offset++) { if (!this->read_byte_16(MS5611_CMD_READ_PROM + (offset * 2), &this->prom[offset])) { - ESP_LOGE(TAG, "Reading byte %d from MS5611 PROM failed!", offset); this->mark_failed(); return; } } } +void MS5611Component::dump_config() { + ESP_LOGCONFIG(TAG, "MS5611:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with MS5611 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} float MS5611Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } @@ -97,7 +103,7 @@ void MS5611Component::calculate_values(uint32_t raw_temperature, uint32_t raw_pr const float pressure = ((raw_pressure * pressure_sensitivity) / 2097152.0f - pressure_offset) / 3276800.0f; - ESP_LOGCONFIG(TAG, "Got temperature=%0.02f°C pressure=%0.01fhPa", temperature, pressure); + ESP_LOGD(TAG, "Got temperature=%0.02f°C pressure=%0.01fhPa", temperature, pressure); this->temperature_sensor_->publish_state(temperature); this->pressure_sensor_->publish_state(pressure); // hPa diff --git a/src/esphomelib/sensor/ms5611.h b/src/esphomelib/sensor/ms5611.h index edc8a479..d90c6012 100644 --- a/src/esphomelib/sensor/ms5611.h +++ b/src/esphomelib/sensor/ms5611.h @@ -21,6 +21,7 @@ class MS5611Component : public PollingComponent, public I2CDevice { uint32_t update_interval = 15000); void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/pmsx003.cpp b/src/esphomelib/sensor/pmsx003.cpp index 2ddfed18..cd28363a 100644 --- a/src/esphomelib/sensor/pmsx003.cpp +++ b/src/esphomelib/sensor/pmsx003.cpp @@ -11,9 +11,6 @@ namespace sensor { static const char *TAG = "sensor.pmsx003"; -void PMSX003Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up PMS5003..."); -} void PMSX003Component::loop() { const uint32_t now = millis(); if (now - this->last_transmission_ >= 500) { diff --git a/src/esphomelib/sensor/pmsx003.h b/src/esphomelib/sensor/pmsx003.h index 167c1047..da4f8937 100644 --- a/src/esphomelib/sensor/pmsx003.h +++ b/src/esphomelib/sensor/pmsx003.h @@ -51,7 +51,6 @@ class PMSX003Component : public UARTDevice, public Component { public: PMSX003Component(UARTComponent *parent, PMSX003Type type); - void setup() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/sensor/pulse_counter.cpp b/src/esphomelib/sensor/pulse_counter.cpp index 74c1579e..580278bf 100644 --- a/src/esphomelib/sensor/pulse_counter.cpp +++ b/src/esphomelib/sensor/pulse_counter.cpp @@ -38,6 +38,10 @@ void PulseCounterSensorComponent::set_edge_mode(PulseCounterCountMode rising_edg const char *EDGE_MODE_TO_STRING[] = {"DISABLE", "INCREMENT", "DECREMENT"}; +GPIOPin *PulseCounterBase::get_pin() { + return this->pin_; +} + #ifdef ARDUINO_ARCH_ESP8266 void ICACHE_RAM_ATTR HOT PulseCounterBase::gpio_intr() { const uint32_t now = micros(); @@ -155,15 +159,21 @@ pulse_counter_t PulseCounterBase::read_raw_value_() { #endif void PulseCounterSensorComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up pulse counter '%s'...", this->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->rising_edge_mode_]); - ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->falling_edge_mode_]); + ESP_LOGCONFIG(TAG, "Setting up pulse counter '%s'...", this->name_.c_str()); if (!this->pulse_counter_setup_()) { this->mark_failed(); return; } } +void PulseCounterSensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Pulse Counter '%s':", this->name_.c_str()); + LOG_PIN(" Pin: ", this->pin_); + ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->rising_edge_mode_]); + ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->falling_edge_mode_]); + ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %u µs", this->filter_us_); +} + void PulseCounterSensorComponent::update() { pulse_counter_t raw = this->read_raw_value_(); float value = (60000.0f * raw) / float(this->get_update_interval()); // per minute diff --git a/src/esphomelib/sensor/pulse_counter.h b/src/esphomelib/sensor/pulse_counter.h index c93e191f..110960e8 100644 --- a/src/esphomelib/sensor/pulse_counter.h +++ b/src/esphomelib/sensor/pulse_counter.h @@ -35,6 +35,8 @@ class PulseCounterBase { bool pulse_counter_setup_(); pulse_counter_t read_raw_value_(); + GPIOPin *get_pin(); + protected: #ifdef ARDUINO_ARCH_ESP8266 void gpio_intr(); @@ -89,6 +91,7 @@ class PulseCounterSensorComponent : public PollingSensorComponent, public PulseC void setup() override; void update() override; float get_setup_priority() const override; + void dump_config() override; }; #ifdef ARDUINO_ARCH_ESP32 diff --git a/src/esphomelib/sensor/rotary_encoder.cpp b/src/esphomelib/sensor/rotary_encoder.cpp index 6d9cc654..39a7be9f 100644 --- a/src/esphomelib/sensor/rotary_encoder.cpp +++ b/src/esphomelib/sensor/rotary_encoder.cpp @@ -83,23 +83,27 @@ RotaryEncoderSensor::RotaryEncoderSensor(const std::string &name, GPIOPin *pin_a this->clear_filters(); } void RotaryEncoderSensor::setup() { - ESP_LOGCONFIG(TAG, "Setting up Rotary Encoder '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Setting up Rotary Encoder '%s'...", this->name_.c_str()); int interrupt_a = digitalPinToInterrupt(this->pin_a_->get_pin()); - ESP_LOGCONFIG(TAG, " Pin A: %u (interrupt %d)", this->pin_a_->get_pin(), interrupt_a); this->pin_a_->setup(); attachInterrupt(interrupt_a, RotaryEncoderSensor::encoder_isr_, CHANGE); int interrupt_b = digitalPinToInterrupt(this->pin_b_->get_pin()); - ESP_LOGCONFIG(TAG, " Pin B: %u (interrupt %d)", this->pin_b_->get_pin(), interrupt_b); this->pin_b_->setup(); attachInterrupt(interrupt_b, RotaryEncoderSensor::encoder_isr_, CHANGE); if (this->pin_i_ != nullptr) { - ESP_LOGCONFIG(TAG, " Pin I: %u", this->pin_i_->get_pin()); this->pin_i_->setup(); } global_rotary_encoders_.push_back(this); } + +void RotaryEncoderSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Rotary Encoder '%s':", this->name_.c_str()); + LOG_PIN(" Pin A: ", this->pin_a_); + LOG_PIN(" Pin B: ", this->pin_b_); + LOG_PIN(" Pin I: ", this->pin_i_); +} void ICACHE_RAM_ATTR RotaryEncoderSensor::encoder_isr_() { for (auto *encoder : global_rotary_encoders_) { encoder->process_state_machine_(); diff --git a/src/esphomelib/sensor/rotary_encoder.h b/src/esphomelib/sensor/rotary_encoder.h index dea363a7..8e5722f4 100644 --- a/src/esphomelib/sensor/rotary_encoder.h +++ b/src/esphomelib/sensor/rotary_encoder.h @@ -39,6 +39,7 @@ class RotaryEncoderSensor : public Sensor, public Component { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; void loop() override; std::string unit_of_measurement() override; std::string icon() override; diff --git a/src/esphomelib/sensor/sht3xd_component.cpp b/src/esphomelib/sensor/sht3xd_component.cpp index f0d0ccde..481e5ec1 100644 --- a/src/esphomelib/sensor/sht3xd_component.cpp +++ b/src/esphomelib/sensor/sht3xd_component.cpp @@ -36,9 +36,7 @@ SHT3XDComponent::SHT3XDComponent(I2CComponent *parent, void SHT3XDComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SHT3xD..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); if (!this->write_command(SHT3XD_COMMAND_READ_SERIAL_NUMBER)) { - ESP_LOGE(TAG, "Communication with SHT3xD failed!"); this->mark_failed(); return; } @@ -49,11 +47,19 @@ void SHT3XDComponent::setup() { return; } uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]); + ESP_LOGV(TAG, " Serial Number: 0x%08X", serial_number); std::string base = uint32_to_string(serial_number); - ESP_LOGCONFIG(TAG, " Serial Number: 0x%08X", serial_number); this->temperature_sensor_->unique_id_ = base + "-temperature"; this->humidity_sensor_->unique_id_ = base + "-humidity"; } +void SHT3XDComponent::dump_config() { + ESP_LOGCONFIG(TAG, "SHT3xD:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with SHT3xD failed!"); + } + LOG_UPDATE_INTERVAL(this); +} float SHT3XDComponent::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/sht3xd_component.h b/src/esphomelib/sensor/sht3xd_component.h index 2baf1c33..2b4acf33 100644 --- a/src/esphomelib/sensor/sht3xd_component.h +++ b/src/esphomelib/sensor/sht3xd_component.h @@ -28,6 +28,7 @@ class SHT3XDComponent : public PollingComponent, public I2CDevice { SHT3XDHumiditySensor *get_humidity_sensor() const; void setup() override; + void dump_config() override; float get_setup_priority() const override; void update() override; diff --git a/src/esphomelib/sensor/tcs34725.cpp b/src/esphomelib/sensor/tcs34725.cpp index 0d30c6e4..1dd73352 100644 --- a/src/esphomelib/sensor/tcs34725.cpp +++ b/src/esphomelib/sensor/tcs34725.cpp @@ -24,10 +24,9 @@ static const uint8_t TCS34725_REGISTER_GDATAL = TCS34725_COMMAND_BIT | 0x18; static const uint8_t TCS34725_REGISTER_BDATAL = TCS34725_COMMAND_BIT | 0x1A; void TCS34725Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up TCS34725 with address=0x%02X...", this->address_); + ESP_LOGCONFIG(TAG, "Setting up TCS34725..."); uint8_t id; if (!this->read_byte(TCS34725_REGISTER_ID, &id)) { - ESP_LOGE(TAG, "Communication with TCS34725 failed!"); this->mark_failed(); return; } @@ -50,6 +49,15 @@ void TCS34725Component::setup() { return; } } + +void TCS34725Component::dump_config() { + ESP_LOGCONFIG(TAG, "TCS34725:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with TCS34725 failed!"); + } + LOG_UPDATE_INTERVAL(this); +} float TCS34725Component::get_setup_priority() const { return setup_priority::HARDWARE_LATE; } diff --git a/src/esphomelib/sensor/tcs34725.h b/src/esphomelib/sensor/tcs34725.h index 7043db20..aa923f80 100644 --- a/src/esphomelib/sensor/tcs34725.h +++ b/src/esphomelib/sensor/tcs34725.h @@ -49,6 +49,8 @@ class TCS34725Component : public PollingComponent, public I2CDevice { void setup() override; float get_setup_priority() const override; void update() override; + void dump_config() override; + protected: TCS35725ColorChannelSensor *clear_sensor_{nullptr}; TCS35725ColorChannelSensor *red_sensor_{nullptr}; diff --git a/src/esphomelib/sensor/template_sensor.cpp b/src/esphomelib/sensor/template_sensor.cpp index 4146c0bf..eebe3d23 100644 --- a/src/esphomelib/sensor/template_sensor.cpp +++ b/src/esphomelib/sensor/template_sensor.cpp @@ -3,11 +3,14 @@ #ifdef USE_TEMPLATE_SENSOR #include "esphomelib/sensor/template_sensor.h" +#include "esphomelib/log.h" ESPHOMELIB_NAMESPACE_BEGIN namespace sensor { +static const char *TAG = "sensor.template"; + TemplateSensor::TemplateSensor(const std::string &name, uint32_t update_interval) : PollingSensorComponent(name, update_interval) { @@ -24,6 +27,10 @@ float TemplateSensor::get_setup_priority() const { void TemplateSensor::set_template(std::function()> &&f) { this->f_ = std::move(f); } +void TemplateSensor::dump_config() { + ESP_LOGCONFIG(TAG, "Template Sensor '%s':", this->name_.c_str()); + LOG_UPDATE_INTERVAL(this); +} } // namespace sensor diff --git a/src/esphomelib/sensor/template_sensor.h b/src/esphomelib/sensor/template_sensor.h index 967d12f8..b313cd36 100644 --- a/src/esphomelib/sensor/template_sensor.h +++ b/src/esphomelib/sensor/template_sensor.h @@ -20,6 +20,8 @@ class TemplateSensor : public PollingSensorComponent { void update() override; + void dump_config() override; + float get_setup_priority() const override; protected: diff --git a/src/esphomelib/sensor/total_daily_energy.cpp b/src/esphomelib/sensor/total_daily_energy.cpp index cca02032..ac1d26b7 100644 --- a/src/esphomelib/sensor/total_daily_energy.cpp +++ b/src/esphomelib/sensor/total_daily_energy.cpp @@ -10,11 +10,11 @@ ESPHOMELIB_NAMESPACE_BEGIN namespace sensor { void TotalDailyEnergy::setup() { - this->pref_ = global_preferences.make_preference(1436924412UL); + this->pref_ = global_preferences.make_preference(1436924412UL, this->name_); float recovered; if (this->pref_.load(&recovered)) { - this->publish_state(recovered); + this->publish_state_and_save_(recovered); } else { this->publish_state_and_save_(0); } diff --git a/src/esphomelib/sensor/tsl2561_sensor.cpp b/src/esphomelib/sensor/tsl2561_sensor.cpp index ed7fadd0..d41e6bfa 100644 --- a/src/esphomelib/sensor/tsl2561_sensor.cpp +++ b/src/esphomelib/sensor/tsl2561_sensor.cpp @@ -29,10 +29,8 @@ TSL2561Sensor::TSL2561Sensor(I2CComponent *parent, const std::string &name, void TSL2561Sensor::setup() { ESP_LOGCONFIG(TAG, "Setting up TSL2561..."); - ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); uint8_t id; if (!this->tsl2561_read_byte(TSL2561_REGISTER_ID, &id)) { - ESP_LOGE(TAG, "Communication with TSL2561 on address 0x%02X failed!", this->address_); this->mark_failed(); return; } @@ -43,26 +41,28 @@ void TSL2561Sensor::setup() { return; } - if (this->gain_ == TSL2561_GAIN_1X) { - ESP_LOGCONFIG(TAG, " Gain: 1x"); - } else if (this->gain_ == TSL2561_GAIN_16X) { - ESP_LOGCONFIG(TAG, " Gain: 16x"); - } timing &= ~0b00010000; timing |= this->gain_ == TSL2561_GAIN_16X ? 0b00010000 : 0; timing &= ~0b00000011; timing |= this->integration_time_ & 0b11; - if (this->integration_time_ == TSL2561_INTEGRATION_14MS) { - ESP_LOGCONFIG(TAG, " Integration time: 14ms"); - } else if (this->integration_time_ == TSL2561_INTEGRATION_101MS) { - ESP_LOGCONFIG(TAG, " Integration time: 101ms"); - } else if (this->integration_time_ == TSL2561_INTEGRATION_402MS) { - ESP_LOGCONFIG(TAG, " Integration time: 402ms"); - } this->write_byte(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, timing); } +void TSL2561Sensor::dump_config() { + ESP_LOGCONFIG(TAG, "TSL2561:"); + LOG_I2C_DEVICE(this); + + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with TSL2561 failed!"); + } + + int gain = this->gain_ == TSL2561_GAIN_1X ? 1 : 16; + ESP_LOGCONFIG(TAG, " Gain: %dx", gain); + ESP_LOGCONFIG(TAG, " Integration Time: %.1f ms", this->get_integration_time_ms_()); + + LOG_UPDATE_INTERVAL(this); +} void TSL2561Sensor::update() { // Power on if (!this->tsl2561_write_byte(TSL2561_REGISTER_CONTROL, 0b00000011)) { diff --git a/src/esphomelib/sensor/tsl2561_sensor.h b/src/esphomelib/sensor/tsl2561_sensor.h index 44a5c868..24f35e61 100644 --- a/src/esphomelib/sensor/tsl2561_sensor.h +++ b/src/esphomelib/sensor/tsl2561_sensor.h @@ -73,6 +73,7 @@ class TSL2561Sensor : public PollingSensorComponent, public I2CDevice { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; void update() override; std::string unit_of_measurement() override; std::string icon() override; diff --git a/src/esphomelib/sensor/ultrasonic_sensor.cpp b/src/esphomelib/sensor/ultrasonic_sensor.cpp index 143ee9f4..465989cc 100644 --- a/src/esphomelib/sensor/ultrasonic_sensor.cpp +++ b/src/esphomelib/sensor/ultrasonic_sensor.cpp @@ -22,13 +22,17 @@ UltrasonicSensorComponent::UltrasonicSensorComponent(const std::string &name, } void UltrasonicSensorComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up Ultrasonic Sensor..."); - ESP_LOGCONFIG(TAG, " Echo Pin: GPIO%d", this->echo_pin_->get_pin()); this->echo_pin_->setup(); - ESP_LOGCONFIG(TAG, " Trigger Pin: GPIO%d", this->trigger_pin_->get_pin()); this->trigger_pin_->setup(); this->trigger_pin_->digital_write(false); - ESP_LOGCONFIG(TAG, " Pulse time: %uµs", this->pulse_time_us_); - ESP_LOGCONFIG(TAG, " Timeout: %uµs", this->timeout_us_); +} +void UltrasonicSensorComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Ultrasonic Sensor '%s':", this->name_.c_str()); + LOG_PIN(" Echo Pin: ", this->echo_pin_); + LOG_PIN(" Trigger Pin: ", this->trigger_pin_); + ESP_LOGCONFIG(TAG, " Pulse time: %u µs", this->pulse_time_us_); + ESP_LOGCONFIG(TAG, " Timeout: %u µs", this->timeout_us_); + LOG_UPDATE_INTERVAL(this); } void UltrasonicSensorComponent::update() { this->trigger_pin_->digital_write(true); diff --git a/src/esphomelib/sensor/ultrasonic_sensor.h b/src/esphomelib/sensor/ultrasonic_sensor.h index b6a1f89c..c2c89947 100644 --- a/src/esphomelib/sensor/ultrasonic_sensor.h +++ b/src/esphomelib/sensor/ultrasonic_sensor.h @@ -58,6 +58,7 @@ class UltrasonicSensorComponent : public PollingSensorComponent { /// Set up pins and register interval. void setup() override; + void dump_config() override; void update() override; diff --git a/src/esphomelib/sensor/wifi_signal_sensor.cpp b/src/esphomelib/sensor/wifi_signal_sensor.cpp index 6657741f..ad8f4549 100644 --- a/src/esphomelib/sensor/wifi_signal_sensor.cpp +++ b/src/esphomelib/sensor/wifi_signal_sensor.cpp @@ -33,7 +33,7 @@ std::string WiFiSignalSensor::unique_id() { return get_mac_address() + "-wifisignal"; } float WiFiSignalSensor::get_setup_priority() const { - return setup_priority::HARDWARE_LATE; + return setup_priority::WIFI; } } // namespace sensor diff --git a/src/esphomelib/spi_component.cpp b/src/esphomelib/spi_component.cpp index 9545824d..64a427d0 100644 --- a/src/esphomelib/spi_component.cpp +++ b/src/esphomelib/spi_component.cpp @@ -101,6 +101,12 @@ void SPIComponent::setup() { this->mosi_->digital_write(false); } } +void SPIComponent::dump_config() { + ESP_LOGCONFIG(TAG, "SPI bus:"); + LOG_PIN(" CLK Pin: ", this->clk_); + LOG_PIN(" MISO Pin: ", this->miso_); + LOG_PIN(" MOSI Pin: ", this->mosi_); +} float SPIComponent::get_setup_priority() const { return setup_priority::PRE_HARDWARE; } diff --git a/src/esphomelib/spi_component.h b/src/esphomelib/spi_component.h index 34def533..66e44eb6 100644 --- a/src/esphomelib/spi_component.h +++ b/src/esphomelib/spi_component.h @@ -16,6 +16,8 @@ class SPIComponent : public Component { void setup() override; + void dump_config() override; + uint8_t read_byte(); void read_array(uint8_t *data, size_t length); diff --git a/src/esphomelib/status_led.cpp b/src/esphomelib/status_led.cpp index 3af79ac1..6fe909fa 100644 --- a/src/esphomelib/status_led.cpp +++ b/src/esphomelib/status_led.cpp @@ -19,6 +19,10 @@ void StatusLEDComponent::setup() { this->pin_->setup(); this->pin_->digital_write(false); } +void StatusLEDComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Status LED:"); + LOG_PIN(" Pin: ", this->pin_); +} void StatusLEDComponent::loop() { if ((global_state & STATUS_LED_ERROR) != 0u) { this->pin_->digital_write(millis() % 250u < 150u); diff --git a/src/esphomelib/status_led.h b/src/esphomelib/status_led.h index efbe613a..b94a6b85 100644 --- a/src/esphomelib/status_led.h +++ b/src/esphomelib/status_led.h @@ -15,6 +15,7 @@ class StatusLEDComponent : public Component { explicit StatusLEDComponent(GPIOPin *pin); void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; float get_loop_priority() const override; diff --git a/src/esphomelib/stepper/a4988.cpp b/src/esphomelib/stepper/a4988.cpp index 1681774d..74d3ca83 100644 --- a/src/esphomelib/stepper/a4988.cpp +++ b/src/esphomelib/stepper/a4988.cpp @@ -12,7 +12,7 @@ namespace stepper { static const char *TAG = "stepper.a4988"; void A4988::setup() { - ESP_LOGCONFIG(TAG, "Setting up A4988 stepper driver..."); + ESP_LOGCONFIG(TAG, "Setting up A4988..."); if (this->sleep_pin_ != nullptr) { this->sleep_pin_->setup(); this->sleep_pin_->digital_write(false); @@ -22,6 +22,13 @@ void A4988::setup() { this->dir_pin_->setup(); this->dir_pin_->digital_write(false); } +void A4988::dump_config() { + ESP_LOGCONFIG(TAG, "A4988:"); + LOG_PIN(" Step Pin: ", this->step_pin_); + LOG_PIN(" Dir Pin: ", this->dir_pin_); + LOG_PIN(" Sleep Pin: ", this->sleep_pin_); + LOG_STEPPER(this); +} void A4988::loop() { if (this->sleep_pin_ != nullptr) { this->sleep_pin_->digital_write(!this->has_reached_target()); diff --git a/src/esphomelib/stepper/a4988.h b/src/esphomelib/stepper/a4988.h index 49c81239..8abe77fd 100644 --- a/src/esphomelib/stepper/a4988.h +++ b/src/esphomelib/stepper/a4988.h @@ -18,6 +18,7 @@ class A4988 : public Stepper, public Component { A4988(GPIOPin *step_pin, GPIOPin *dir_pin); void set_sleep_pin(const GPIOOutputPin &sleep_pin); void setup() override; + void dump_config() override; void loop() override; float get_setup_priority() const override; diff --git a/src/esphomelib/stepper/stepper.h b/src/esphomelib/stepper/stepper.h index ac50de1e..4c25c9c2 100644 --- a/src/esphomelib/stepper/stepper.h +++ b/src/esphomelib/stepper/stepper.h @@ -18,6 +18,11 @@ class SetTargetAction; template class ReportPositionAction; +#define LOG_STEPPER(this) \ + ESP_LOGCONFIG(TAG, " Acceleration: %.0f steps/s^2", this->acceleration_); \ + ESP_LOGCONFIG(TAG, " Deceleration: %.0f steps/s^2", this->deceleration_); \ + ESP_LOGCONFIG(TAG, " Max Speed: %.0f steps/s", this->max_speed_); + class Stepper { public: void set_target(int32_t steps); diff --git a/src/esphomelib/switch_/gpio_switch.cpp b/src/esphomelib/switch_/gpio_switch.cpp index cdb13646..d0247538 100644 --- a/src/esphomelib/switch_/gpio_switch.cpp +++ b/src/esphomelib/switch_/gpio_switch.cpp @@ -20,15 +20,21 @@ float GPIOSwitch::get_setup_priority() const { return setup_priority::HARDWARE; } void GPIOSwitch::setup() { - ESP_LOGCONFIG(TAG, "Setting up GPIO Switch '%s'...", this->get_name().c_str()); + ESP_LOGCONFIG(TAG, "Setting up GPIO Switch '%s'...", this->name_.c_str()); this->pin_->setup(); bool restored = this->get_initial_state().value_or(false); + ESP_LOGD(TAG, " Restored state %s", ONOFF(restored)); if (restored) { this->turn_on(); } else { this->turn_off(); } } +void GPIOSwitch::dump_config() { + ESP_LOGCONFIG(TAG, "GPIO Switch '%s':", this->name_.c_str()); + LOG_PIN(" Pin: ", this->pin_); + LOG_SWITCH(this); +} void GPIOSwitch::write_state(bool state) { this->pin_->digital_write(state); this->publish_state(state); diff --git a/src/esphomelib/switch_/gpio_switch.h b/src/esphomelib/switch_/gpio_switch.h index 3e256a5d..115961e6 100644 --- a/src/esphomelib/switch_/gpio_switch.h +++ b/src/esphomelib/switch_/gpio_switch.h @@ -22,6 +22,7 @@ class GPIOSwitch : public Switch, public Component { float get_setup_priority() const override; void setup() override; + void dump_config() override; protected: void write_state(bool state) override; diff --git a/src/esphomelib/switch_/mqtt_switch_component.cpp b/src/esphomelib/switch_/mqtt_switch_component.cpp index d27aa375..fc1a1b7c 100644 --- a/src/esphomelib/switch_/mqtt_switch_component.cpp +++ b/src/esphomelib/switch_/mqtt_switch_component.cpp @@ -20,12 +20,6 @@ MQTTSwitchComponent::MQTTSwitchComponent(switch_::Switch *switch_) } void MQTTSwitchComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT switch '%s'", this->switch_->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Icon: '%s'", this->switch_->get_icon().c_str()); - if (this->switch_->optimistic()) { - ESP_LOGCONFIG(TAG, " Optimistic: YES"); - } - this->subscribe(this->get_command_topic(), [&](const std::string &payload) { switch (parse_on_off(payload.c_str())) { case PARSE_ON: @@ -50,6 +44,16 @@ void MQTTSwitchComponent::setup() { }); }); } +void MQTTSwitchComponent::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT switch '%s': ", this->switch_->get_name().c_str()); + if (!this->switch_->get_icon().empty()) { + ESP_LOGCONFIG(TAG, " Icon: '%s'", this->switch_->get_icon().c_str()); + } + if (this->switch_->optimistic()) { + ESP_LOGCONFIG(TAG, " Optimistic: YES"); + } + LOG_MQTT_COMPONENT(true, true); +} std::string MQTTSwitchComponent::component_type() const { return "switch"; @@ -71,7 +75,6 @@ std::string MQTTSwitchComponent::friendly_name() const { } void MQTTSwitchComponent::publish_state(bool state) { const char *state_s = state ? "ON" : "OFF"; - ESP_LOGD(TAG, "'%s': Sending state %s", this->friendly_name().c_str(), state_s); this->send_message(this->get_state_topic(), state_s); } diff --git a/src/esphomelib/switch_/mqtt_switch_component.h b/src/esphomelib/switch_/mqtt_switch_component.h index 9c3ceb98..6ed88155 100644 --- a/src/esphomelib/switch_/mqtt_switch_component.h +++ b/src/esphomelib/switch_/mqtt_switch_component.h @@ -24,6 +24,7 @@ class MQTTSwitchComponent : public mqtt::MQTTComponent { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) void setup() override; + void dump_config() override; void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override; diff --git a/src/esphomelib/switch_/switch.cpp b/src/esphomelib/switch_/switch.cpp index 72359c7f..0c3124a6 100644 --- a/src/esphomelib/switch_/switch.cpp +++ b/src/esphomelib/switch_/switch.cpp @@ -42,17 +42,17 @@ void Switch::toggle() { this->write_state(this->inverted_ == this->state); } optional Switch::get_initial_state() { - this->rtc_ = global_preferences.make_preference(4, 2704004739UL); - if (!this->rtc_.load()) + this->rtc_ = global_preferences.make_preference(2704004739UL, this->name_); + bool initial_state; + if (!this->rtc_.load(&initial_state)) return {}; - bool initial_state = this->rtc_[0]; return initial_state; } void Switch::publish_state(bool state) { this->state = state != this->inverted_; - this->rtc_[0] = this->state ? 1 : 0; - this->rtc_.save(); + this->rtc_.save(&this->state); + ESP_LOGD(TAG, "'%s': Sending state %s", this->name_.c_str(), ONOFF(state)); this->state_callback_.call(this->state); } bool Switch::optimistic() { diff --git a/src/esphomelib/switch_/switch.h b/src/esphomelib/switch_/switch.h index 9e5b9d2e..2b07918c 100644 --- a/src/esphomelib/switch_/switch.h +++ b/src/esphomelib/switch_/switch.h @@ -21,6 +21,9 @@ class TurnOffAction; template class TurnOnAction; +#define LOG_SWITCH(this) \ + if (this->inverted_) { ESP_LOGCONFIG(TAG, " Inverted: YES"); } + /** Base class for all switches. * * A switch is basically just a combination of a binary sensor (for reporting switch values) diff --git a/src/esphomelib/switch_/template_switch.cpp b/src/esphomelib/switch_/template_switch.cpp index 722d10c9..538743a5 100644 --- a/src/esphomelib/switch_/template_switch.cpp +++ b/src/esphomelib/switch_/template_switch.cpp @@ -3,11 +3,14 @@ #ifdef USE_TEMPLATE_SWITCH #include "esphomelib/switch_/template_switch.h" +#include "esphomelib/log.h" ESPHOMELIB_NAMESPACE_BEGIN namespace switch_ { +static const char *TAG = "switch.template"; + TemplateSwitch::TemplateSwitch(const std::string &name) : Switch(name), Component(), turn_on_trigger_(new Trigger()), turn_off_trigger_(new Trigger()) { @@ -57,13 +60,21 @@ void TemplateSwitch::setup() { if (!this->restore_state_) return; - bool restored = this->get_initial_state().value_or(false); - if (restored) { + auto restored = this->get_initial_state(); + if (!restored.has_value()) + return; + + ESP_LOGD(TAG, " Restored state %s", ONOFF(*restored)); + if (*restored) { this->turn_on(); } else { this->turn_off(); } } +void TemplateSwitch::dump_config() { + ESP_LOGCONFIG(TAG, "Template Switch '%s':", this->name_.c_str()); + LOG_SWITCH(this); +} void TemplateSwitch::set_restore_state(bool restore_state) { this->restore_state_ = restore_state; } diff --git a/src/esphomelib/switch_/template_switch.h b/src/esphomelib/switch_/template_switch.h index 2d1fc12f..7981fdd7 100644 --- a/src/esphomelib/switch_/template_switch.h +++ b/src/esphomelib/switch_/template_switch.h @@ -17,6 +17,7 @@ class TemplateSwitch : public Switch, public Component { explicit TemplateSwitch(const std::string &name); void setup() override; + void dump_config() override; void set_state_lambda(std::function()> &&f); void set_restore_state(bool restore_state); diff --git a/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.cpp b/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.cpp index 2cd40e14..44a8fe03 100644 --- a/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.cpp +++ b/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.cpp @@ -9,6 +9,8 @@ ESPHOMELIB_NAMESPACE_BEGIN namespace text_sensor { +static const char *TAG = "text_sensor.mqtt_subscribe"; + MQTTSubscribeTextSensor::MQTTSubscribeTextSensor(const std::string &name, std::string topic) : TextSensor(name), topic_(std::move(topic)) { @@ -24,6 +26,10 @@ float MQTTSubscribeTextSensor::get_setup_priority() const { void MQTTSubscribeTextSensor::set_qos(uint8_t qos) { this->qos_ = qos; } +void MQTTSubscribeTextSensor::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Subscribe Text Sensor '%s':", this->name_.c_str()); + ESP_LOGCONFIG(TAG, " Topic: %s", this->topic_.c_str()); +} } // namespace text_sensor diff --git a/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.h b/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.h index 8ec7eac9..b9775599 100644 --- a/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.h +++ b/src/esphomelib/text_sensor/mqtt_subscribe_text_sensor.h @@ -18,6 +18,7 @@ class MQTTSubscribeTextSensor : public TextSensor, public Component { MQTTSubscribeTextSensor(const std::string &name, std::string topic); void setup() override; + void dump_config() override; float get_setup_priority() const override; void set_qos(uint8_t qos); diff --git a/src/esphomelib/text_sensor/mqtt_text_sensor.cpp b/src/esphomelib/text_sensor/mqtt_text_sensor.cpp index 19ca28f6..3df28a7b 100644 --- a/src/esphomelib/text_sensor/mqtt_text_sensor.cpp +++ b/src/esphomelib/text_sensor/mqtt_text_sensor.cpp @@ -25,15 +25,21 @@ void MQTTTextSensor::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig config.command_topic = false; } void MQTTTextSensor::setup() { - ESP_LOGCONFIG(TAG, "Setting up MQTT Text Sensor '%s'...", this->sensor_->get_name().c_str()); - ESP_LOGCONFIG(TAG, " Icon: '%s'", this->sensor_->get_icon().c_str()); - if (!this->sensor_->unique_id().empty()) { - ESP_LOGCONFIG(TAG, " Unique ID: '%s'", this->sensor_->unique_id().c_str()); - } - auto f = std::bind(&MQTTTextSensor::publish_state, this, std::placeholders::_1); this->sensor_->add_on_state_callback(f); } + +void MQTTTextSensor::dump_config() { + ESP_LOGCONFIG(TAG, "MQTT Text Sensor '%s':", this->sensor_->get_name().c_str()); + if (!this->sensor_->get_icon().empty()) { + ESP_LOGCONFIG(TAG, " Icon: '%s'", this->sensor_->get_icon().c_str()); + } + if (!this->sensor_->unique_id().empty()) { + ESP_LOGCONFIG(TAG, " Unique ID: '%s'", this->sensor_->unique_id().c_str()); + } + LOG_MQTT_COMPONENT(true, false); +} + void MQTTTextSensor::publish_state(const std::string &value) { this->send_message(this->get_state_topic(), value); } diff --git a/src/esphomelib/text_sensor/mqtt_text_sensor.h b/src/esphomelib/text_sensor/mqtt_text_sensor.h index 9994154c..f81d8a6b 100644 --- a/src/esphomelib/text_sensor/mqtt_text_sensor.h +++ b/src/esphomelib/text_sensor/mqtt_text_sensor.h @@ -21,6 +21,8 @@ class MQTTTextSensor : public mqtt::MQTTComponent { void setup() override; + void dump_config() override; + void publish_state(const std::string &value); void send_initial_state() override; diff --git a/src/esphomelib/time/rtc_component.cpp b/src/esphomelib/time/rtc_component.cpp index 21de5165..ceeb1975 100644 --- a/src/esphomelib/time/rtc_component.cpp +++ b/src/esphomelib/time/rtc_component.cpp @@ -237,6 +237,9 @@ void CronTrigger::add_days_of_week(const std::vector &days_of_week) { for (uint8_t it : days_of_week) this->add_day_of_week(it); } +float CronTrigger::get_setup_priority() const { + return setup_priority::HARDWARE; +} } // namespace time diff --git a/src/esphomelib/time/rtc_component.h b/src/esphomelib/time/rtc_component.h index 07249465..173f9311 100644 --- a/src/esphomelib/time/rtc_component.h +++ b/src/esphomelib/time/rtc_component.h @@ -90,6 +90,7 @@ class CronTrigger : public Trigger, public Component { void add_days_of_week(const std::vector &days_of_week); bool matches(const EsphomelibTime &time); void loop() override; + float get_setup_priority() const override; protected: std::bitset<61> seconds_; diff --git a/src/esphomelib/time/sntp_component.cpp b/src/esphomelib/time/sntp_component.cpp index f7327e0d..c22f6fa3 100644 --- a/src/esphomelib/time/sntp_component.cpp +++ b/src/esphomelib/time/sntp_component.cpp @@ -48,6 +48,13 @@ void SNTPComponent::setup() { #endif sntp_init(); } +void SNTPComponent::dump_config() { + ESP_LOGCONFIG(TAG, "SNTP Time:"); + ESP_LOGCONFIG(TAG, " Server 1: '%s'", this->server_1_.c_str()); + ESP_LOGCONFIG(TAG, " Server 2: '%s'", this->server_2_.c_str()); + ESP_LOGCONFIG(TAG, " Server 3: '%s'", this->server_3_.c_str()); + ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str()); +} void SNTPComponent::set_servers(const std::string &server_1, const std::string &server_2, const std::string &server_3) { @@ -68,7 +75,7 @@ void SNTPComponent::loop() { char buf[128]; time.strftime(buf, sizeof(buf), "%c"); - ESP_LOGD(TAG, "Got time: %s", buf); + ESP_LOGD(TAG, "Synchronized time: %s", buf); this->has_time_ = true; } diff --git a/src/esphomelib/time/sntp_component.h b/src/esphomelib/time/sntp_component.h index db4a69d8..70df7a0a 100644 --- a/src/esphomelib/time/sntp_component.h +++ b/src/esphomelib/time/sntp_component.h @@ -23,6 +23,7 @@ class SNTPComponent : public RealTimeClockComponent { SNTPComponent(); void setup() override; + void dump_config() override; /// Change the servers used by SNTP for timekeeping void set_servers(const std::string &server_1, const std::string &server_2, diff --git a/src/esphomelib/uart_component.cpp b/src/esphomelib/uart_component.cpp index 130472b8..54d2e6c5 100644 --- a/src/esphomelib/uart_component.cpp +++ b/src/esphomelib/uart_component.cpp @@ -50,6 +50,13 @@ void UARTComponent::setup() { this->hw_serial_->begin(this->baud_rate_, SERIAL_8N1, this->rx_pin_, this->tx_pin_); } +void UARTComponent::dump_config() { + ESP_LOGCONFIG(TAG, "UART Bus:"); + ESP_LOGCONFIG(TAG, " TX Pin: GPIO%d", this->tx_pin_); + ESP_LOGCONFIG(TAG, " RX Pin: GPIO%d", this->rx_pin_); + ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); +} + void UARTComponent::write_byte(uint8_t data) { this->hw_serial_->write(data); ESP_LOGVV(TAG, " Wrote 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(data), data); @@ -111,19 +118,26 @@ void UARTComponent::flush() { #ifdef ARDUINO_ARCH_ESP8266 void UARTComponent::setup() { - ESP_LOGCONFIG(TAG, "Setting up UART..."); - ESP_LOGCONFIG(TAG, " TX Pin: %d", this->tx_pin_); - ESP_LOGCONFIG(TAG, " RX Pin: %d", this->rx_pin_); - ESP_LOGCONFIG(TAG, " Baud Rate: %u", this->baud_rate_); + ESP_LOGCONFIG(TAG, "Setting up UART bus..."); if (this->hw_serial_ != nullptr) { - ESP_LOGCONFIG(TAG, " Using default serial interface."); this->hw_serial_->begin(this->baud_rate_); } else { - ESP_LOGCONFIG(TAG, " Using software serial"); this->sw_serial_->setup(this->tx_pin_, this->rx_pin_, this->baud_rate_); } } +void UARTComponent::dump_config() { + ESP_LOGCONFIG(TAG, "UART Bus:"); + ESP_LOGCONFIG(TAG, " TX Pin: GPIO%d", this->tx_pin_); + ESP_LOGCONFIG(TAG, " RX Pin: GPIO%d", this->rx_pin_); + ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_); + if (this->hw_serial_ != nullptr) { + ESP_LOGCONFIG(TAG, " Using hardware serial interface."); + } else { + ESP_LOGCONFIG(TAG, " Using software serial"); + } +} + void UARTComponent::write_byte(uint8_t data) { if (this->hw_serial_ != nullptr) { this->hw_serial_->write(data); diff --git a/src/esphomelib/uart_component.h b/src/esphomelib/uart_component.h index 38970451..7b8e2896 100644 --- a/src/esphomelib/uart_component.h +++ b/src/esphomelib/uart_component.h @@ -49,6 +49,8 @@ class UARTComponent : public Component { void setup() override; + void dump_config() override; + void write_byte(uint8_t data); void write_array(const uint8_t *data, size_t len); diff --git a/src/esphomelib/web_server.cpp b/src/esphomelib/web_server.cpp index 4e5e5c1a..566abc93 100644 --- a/src/esphomelib/web_server.cpp +++ b/src/esphomelib/web_server.cpp @@ -79,7 +79,7 @@ void WebServer::set_port(uint16_t port) { } void WebServer::setup() { - ESP_LOGCONFIG(TAG, "Setting up web server on port %u...", this->port_); + ESP_LOGCONFIG(TAG, "Setting up web server..."); this->server_ = new AsyncWebServer(this->port_); MDNS.addService("http", "tcp", this->port_); @@ -131,8 +131,12 @@ void WebServer::setup() { this->events_.send("", "ping", millis(), 30000); }); } +void WebServer::dump_config() { + ESP_LOGCONFIG(TAG, "Web Server:"); + ESP_LOGCONFIG(TAG, " Address: %s:%u", WiFi.localIP().toString().c_str(), this->port_); +} float WebServer::get_setup_priority() const { - return setup_priority::MQTT_CLIENT; + return setup_priority::WIFI - 1.0f; } void WebServer::handle_update_request(AsyncWebServerRequest *request) { @@ -357,13 +361,19 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, UrlMatch m std::string data = this->switch_json(obj, obj->state); request->send(200, "text/json", data.c_str()); } else if (match.method == "toggle") { - obj->toggle(); + this->defer([obj] () { + obj->toggle(); + }); request->send(200); } else if (match.method == "turn_on") { - obj->turn_on(); + this->defer([obj] () { + obj->turn_on(); + }); request->send(200); } else if (match.method == "turn_off") { - obj->turn_off(); + this->defer([obj] () { + obj->turn_off(); + }); request->send(200); } else { request->send(404); @@ -439,7 +449,9 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, UrlMatch matc std::string data = this->fan_json(obj); request->send(200, "text/json", data.c_str()); } else if (match.method == "toggle") { - obj->toggle().perform(); + this->defer([obj] () { + obj->toggle().perform(); + }); request->send(200); } else if (match.method == "turn_on") { auto call = obj->turn_on(); @@ -451,19 +463,28 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, UrlMatch matc String speed = request->getParam("oscillation")->value(); auto val = parse_on_off(speed.c_str()); switch (val) { - case PARSE_ON:call.set_oscillating(true); + case PARSE_ON: + call.set_oscillating(true); break; - case PARSE_OFF:call.set_oscillating(false); + case PARSE_OFF: + call.set_oscillating(false); break; - case PARSE_TOGGLE:call.set_oscillating(!obj->oscillating); + case PARSE_TOGGLE: + call.set_oscillating(!obj->oscillating); break; - case PARSE_NONE:request->send(404); + case PARSE_NONE: + request->send(404); return; } } + this->defer([call] () { + call.perform(); + }); request->send(200); } else if (match.method == "turn_off") { - obj->turn_off().perform(); + this->defer([obj] () { + obj->turn_off().perform(); + }); request->send(200); } else { request->send(404); @@ -492,7 +513,9 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, UrlMatch ma std::string data = this->light_json(obj); request->send(200, "text/json", data.c_str()); } else if (match.method == "toggle") { - obj->toggle().perform(); + this->defer([obj] () { + obj->toggle().perform(); + }); request->send(200); } else if (match.method == "turn_on") { auto call = obj->turn_on(); @@ -522,7 +545,9 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, UrlMatch ma call.set_effect(effect); } - call.perform(); + this->defer([call] () { + call.perform(); + }); request->send(200); } else if (match.method == "turn_off") { auto call = obj->turn_off(); @@ -530,7 +555,9 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, UrlMatch ma uint32_t length = request->getParam("transition")->value().toFloat() * 1000; call.set_transition_length(length); } - call.perform(); + this->defer([call] () { + call.perform(); + }); request->send(200); } else { request->send(404); diff --git a/src/esphomelib/web_server.h b/src/esphomelib/web_server.h index 4717c363..ea3258f1 100644 --- a/src/esphomelib/web_server.h +++ b/src/esphomelib/web_server.h @@ -59,6 +59,8 @@ class WebServer : public StoringController, public Component, public AsyncWebHan /// Setup the internal web server and register handlers. void setup() override; + void dump_config() override; + /// MQTT setup priority. float get_setup_priority() const override; diff --git a/src/esphomelib/wifi_component.cpp b/src/esphomelib/wifi_component.cpp index 883bcc2c..ca35158f 100644 --- a/src/esphomelib/wifi_component.cpp +++ b/src/esphomelib/wifi_component.cpp @@ -27,7 +27,8 @@ void WiFiComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up WiFi..."); #ifdef ARDUINO_ARCH_ESP32 - WiFi.onEvent(on_wifi_event); + auto f = std::bind(&WiFiComponent::on_wifi_event, this, std::placeholders::_1, std::placeholders::_2); + WiFi.onEvent(f); #endif WiFi.persistent(false); @@ -67,41 +68,39 @@ void WiFiComponent::setup() { } delay(10); - if (this->power_save_.has_value()) { #ifdef ARDUINO_ARCH_ESP32 - wifi_ps_type_t power_save; - switch (*this->power_save_) { - case WIFI_POWER_SAVE_LIGHT: - power_save = WIFI_PS_MIN_MODEM; - break; - case WIFI_POWER_SAVE_HIGH: - power_save = WIFI_PS_MAX_MODEM; - break; - case WIFI_POWER_SAVE_NONE: - default: - power_save = WIFI_PS_NONE; - break; - } - esp_wifi_set_ps(power_save); + wifi_ps_type_t power_save; + switch (this->power_save_) { + case WIFI_POWER_SAVE_LIGHT: + power_save = WIFI_PS_MIN_MODEM; + break; + case WIFI_POWER_SAVE_HIGH: + power_save = WIFI_PS_MAX_MODEM; + break; + case WIFI_POWER_SAVE_NONE: + default: + power_save = WIFI_PS_NONE; + break; + } + esp_wifi_set_ps(power_save); #endif #ifdef ARDUINO_ARCH_ESP8266 - sleep_type_t power_save; - switch (*this->power_save_) { - case WIFI_POWER_SAVE_LIGHT: - power_save = LIGHT_SLEEP_T; - break; - case WIFI_POWER_SAVE_HIGH: - power_save = MODEM_SLEEP_T; - break; - case WIFI_POWER_SAVE_NONE: - default: - power_save = NONE_SLEEP_T; - break; - } - wifi_set_sleep_type(power_save); -#endif + sleep_type_t power_save; + switch (this->power_save_) { + case WIFI_POWER_SAVE_LIGHT: + power_save = LIGHT_SLEEP_T; + break; + case WIFI_POWER_SAVE_HIGH: + power_save = MODEM_SLEEP_T; + break; + case WIFI_POWER_SAVE_NONE: + default: + power_save = NONE_SLEEP_T; + break; } + wifi_set_sleep_type(power_save); +#endif this->start_connecting(); } else if (this->has_ap()) { @@ -122,12 +121,17 @@ void WiFiComponent::loop() { case WIFI_COMPONENT_STATE_STA_CONNECTED: case WIFI_COMPONENT_STATE_AP_STA_CONNECTED: { - if (WiFi.status() == WL_CONNECTED) { - this->last_connected_ = now; - } else { +#ifdef ARDUINO_ARCH_ESP32 + if (this->error_from_callback_) { + this->handle_error_from_callback(); + } else +#endif + if (WiFi.status() != WL_CONNECTED) { ESP_LOGW(TAG, "WiFi Connection lost... Reconnecting..."); this->status_set_warning(); this->retry_connect(); + } else { + this->last_connected_ = now; } break; } @@ -148,7 +152,7 @@ WiFiComponent::WiFiComponent() { } #ifdef ARDUINO_ARCH_ESP32 -void WiFiComponent::on_wifi_event(WiFiEvent_t event) { +void WiFiComponent::on_wifi_event(system_event_id_t event, system_event_info_t info) { #ifdef ESPHOMELIB_LOG_HAS_VERBOSE const char *event_name; switch (event) { @@ -190,9 +194,10 @@ void WiFiComponent::on_wifi_event(WiFiEvent_t event) { #endif if (event == SYSTEM_EVENT_STA_DISCONNECTED) { - // The arduino core has a bug where WiFi.status() is still set to connected even though - // it received a disconnected event. - global_wifi_component->retry_connect(); + uint8_t reason = info.disconnected.reason; + if (reason == WIFI_REASON_AUTH_EXPIRE || (reason >= WIFI_REASON_BEACON_TIMEOUT && WIFI_REASON_AUTH_FAIL)) { + this->error_from_callback_ = true; + } } } #endif @@ -211,12 +216,12 @@ void WiFiComponent::setup_ap_config() { this->status_set_error(); } - ESP_LOGCONFIG(TAG, " AP SSID: '%s'", this->ap_.ssid.c_str()); - ESP_LOGCONFIG(TAG, " AP Password: '%s'", this->ap_.password.c_str()); + ESP_LOGCONFIG(TAG, " AP SSID: '%s'", this->ap_.ssid.c_str()); + ESP_LOGCONFIG(TAG, " AP Password: '%s'", this->ap_.password.c_str()); if (this->ap_.manual_ip.has_value()) { - ESP_LOGCONFIG(TAG, " AP Static IP: '%s'", this->ap_.manual_ip->static_ip.toString().c_str()); - ESP_LOGCONFIG(TAG, " AP Gateway: '%s'", this->ap_.manual_ip->gateway.toString().c_str()); - ESP_LOGCONFIG(TAG, " AP Subnet: '%s'", this->ap_.manual_ip->subnet.toString().c_str()); + ESP_LOGCONFIG(TAG, " AP Static IP: '%s'", this->ap_.manual_ip->static_ip.toString().c_str()); + ESP_LOGCONFIG(TAG, " AP Gateway: '%s'", this->ap_.manual_ip->gateway.toString().c_str()); + ESP_LOGCONFIG(TAG, " AP Subnet: '%s'", this->ap_.manual_ip->subnet.toString().c_str()); ret = WiFi.softAPConfig(this->ap_.manual_ip->static_ip, this->ap_.manual_ip->gateway, this->ap_.manual_ip->subnet); @@ -247,7 +252,7 @@ void WiFiComponent::setup_ap_config() { } ESP_LOGD(TAG, "WiFi AP set up."); - ESP_LOGCONFIG(TAG, " IP Address: %s", WiFi.softAPIP().toString().c_str()); + ESP_LOGCONFIG(TAG, " IP Address: %s", WiFi.softAPIP().toString().c_str()); if (!this->has_sta()) { this->state_ = WIFI_COMPONENT_STATE_AP; @@ -271,8 +276,6 @@ void WiFiComponent::set_sta(const WiFiAp &ap) { } void WiFiComponent::start_connecting() { - assert(this->has_sta()); - ESP_LOGI(TAG, "WiFi Connecting to '%s'...", this->sta_.ssid.c_str()); this->status_set_warning(); @@ -318,21 +321,34 @@ void WiFiComponent::start_connecting() { this->action_started_ = millis(); } +static void print_connect_params() { + uint8_t *bssid = WiFi.BSSID(); + ESP_LOGCONFIG(TAG, " SSID: '%s'", WiFi.SSID().c_str()); + ESP_LOGCONFIG(TAG, " IP Address: %s", WiFi.localIP().toString().c_str()); + ESP_LOGCONFIG(TAG, " BSSID: %02X:%02X:%02X:%02X:%02X:%02X", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + ESP_LOGCONFIG(TAG, " Channel: %d", WiFi.channel()); + ESP_LOGCONFIG(TAG, " Subnet: %s", WiFi.subnetMask().toString().c_str()); + ESP_LOGCONFIG(TAG, " Gateway: %s", WiFi.gatewayIP().toString().c_str()); + ESP_LOGCONFIG(TAG, " DNS1: %s", WiFi.dnsIP(0).toString().c_str()); + ESP_LOGCONFIG(TAG, " DNS2: %s", WiFi.dnsIP(1).toString().c_str()); +} + +void WiFiComponent::dump_config() { + ESP_LOGCONFIG(TAG, "WiFi:"); + print_connect_params(); +} + void WiFiComponent::check_connecting_finished() { wl_status_t status = WiFi.status(); if (status == WL_CONNECTED) { ESP_LOGI(TAG, "WiFi connected!"); - uint8_t *bssid = WiFi.BSSID(); - ESP_LOGCONFIG(TAG, " SSID: %s", WiFi.SSID().c_str()); - ESP_LOGCONFIG(TAG, " BSSID: %02X:%02X:%02X:%02X:%02X:%02X", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - ESP_LOGCONFIG(TAG, " Channel: %d", WiFi.channel()); - ESP_LOGCONFIG(TAG, " IP Address: %s", WiFi.localIP().toString().c_str()); - ESP_LOGCONFIG(TAG, " Subnet: %s", WiFi.subnetMask().toString().c_str()); - ESP_LOGCONFIG(TAG, " Gateway: %s", WiFi.gatewayIP().toString().c_str()); - ESP_LOGCONFIG(TAG, " DNS1: %s", WiFi.dnsIP(0).toString().c_str()); - ESP_LOGCONFIG(TAG, " DNS2: %s", WiFi.dnsIP(1).toString().c_str()); + print_connect_params(); this->status_clear_warning(); + this->cooldown_reconnect_.reset(); +#ifdef ARDUINO_ARCH_ESP32 + this->error_from_callback_ = false; +#endif if (this->has_ap()) { ESP_LOGD(TAG, "Disabling AP..."); @@ -344,23 +360,19 @@ void WiFiComponent::check_connecting_finished() { return; } - if (status == WL_NO_SSID_AVAIL) { - ESP_LOGW(TAG, "WiFi network can not be found anymore."); - this->retry_connect(); - return; - } - - if (status == WL_CONNECT_FAILED) { - ESP_LOGW(TAG, "Connecting to WiFi network failed. Are the credentials wrong?"); + uint32_t now = millis(); + if (now - this->action_started_ > 30000) { + ESP_LOGW(TAG, "Timeout while connecting to WiFi."); this->retry_connect(); return; } - if (millis() - this->action_started_ > 30000) { - ESP_LOGW(TAG, "Timeout while connecting to WiFi."); - this->retry_connect(); +#ifdef ARDUINO_ARCH_ESP32 + if (this->error_from_callback_) { + this->handle_error_from_callback(); return; } +#endif if (status == WL_IDLE_STATUS || status == WL_DISCONNECTED || status == WL_CONNECTION_LOST) { // WL_DISCONNECTED is set while not connected yet. @@ -369,6 +381,23 @@ void WiFiComponent::check_connecting_finished() { return; } + if (this->cooldown_reconnect_.has_value() && now - *this->cooldown_reconnect_ < 2000) { + return; + } + this->cooldown_reconnect_ = now; + + if (status == WL_NO_SSID_AVAIL) { + ESP_LOGW(TAG, "WiFi network can not be found anymore."); + this->retry_connect(); + return; + } + + if (status == WL_CONNECT_FAILED) { + ESP_LOGW(TAG, "Connecting to WiFi network failed. Are the credentials wrong?"); + this->retry_connect(); + return; + } + ESP_LOGW(TAG, "WiFi Unknown connection status %d", status); delay(100); } @@ -413,6 +442,16 @@ bool WiFiComponent::is_connected() { void WiFiComponent::set_power_save_mode(WiFiPowerSaveMode power_save) { this->power_save_ = power_save; } +#ifdef ARDUINO_ARCH_ESP32 +void WiFiComponent::handle_error_from_callback() { + this->error_from_callback_ = false; + WiFi.enableSTA(false); + if (this->has_ap() && this->state_ == WIFI_COMPONENT_STATE_AP_STA_CONNECTED) { + this->setup_ap_config(); + } + this->start_connecting(); +} +#endif WiFiComponent *global_wifi_component; diff --git a/src/esphomelib/wifi_component.h b/src/esphomelib/wifi_component.h index 11c233f7..e7458be3 100644 --- a/src/esphomelib/wifi_component.h +++ b/src/esphomelib/wifi_component.h @@ -148,6 +148,7 @@ class WiFiComponent : public Component { // (In most use cases you won't need these) /// Setup WiFi interface. void setup() override; + void dump_config() override; /// WIFI setup_priority. float get_setup_priority() const override; float get_loop_priority() const override; @@ -163,7 +164,9 @@ class WiFiComponent : public Component { #ifdef ARDUINO_ARCH_ESP32 /// Used for logging WiFi events. - static void on_wifi_event(WiFiEvent_t event); + void on_wifi_event(system_event_id_t event, system_event_info_t info); + + void handle_error_from_callback(); #endif std::string hostname_; @@ -176,7 +179,11 @@ class WiFiComponent : public Component { uint8_t num_retried_{0}; uint32_t last_connected_{0}; uint32_t reboot_timeout_{60000}; - optional power_save_{}; + WiFiPowerSaveMode power_save_{WIFI_POWER_SAVE_NONE}; + optional cooldown_reconnect_{}; +#ifdef ARDUINO_ARCH_ESP32 + bool error_from_callback_{false}; +#endif }; extern WiFiComponent *global_wifi_component;