mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 01:08:03 +01:00
commit
fc94a5d0ee
18 changed files with 263 additions and 157 deletions
|
@ -23,7 +23,7 @@ static const char *const TAG = "api.connection";
|
||||||
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
||||||
|
|
||||||
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
|
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
|
||||||
: parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
|
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
|
||||||
this->proto_write_buffer_.reserve(64);
|
this->proto_write_buffer_.reserve(64);
|
||||||
|
|
||||||
#if defined(USE_API_PLAINTEXT)
|
#if defined(USE_API_PLAINTEXT)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "esphome/components/socket/socket.h"
|
#include "esphome/components/socket/socket.h"
|
||||||
#include "api_pb2.h"
|
#include "api_pb2.h"
|
||||||
#include "api_pb2_service.h"
|
#include "api_pb2_service.h"
|
||||||
#include "util.h"
|
|
||||||
#include "list_entities.h"
|
#include "list_entities.h"
|
||||||
#include "subscribe_state.h"
|
#include "subscribe_state.h"
|
||||||
#include "user_services.h"
|
#include "user_services.h"
|
||||||
|
|
|
@ -40,8 +40,7 @@ bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
|
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
|
||||||
ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client)
|
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
|
||||||
: ComponentIterator(server), client_(client) {}
|
|
||||||
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
||||||
auto resp = service->encode_list_service_response();
|
auto resp = service->encode_list_service_response();
|
||||||
return this->client_->send_list_entities_services_response(resp);
|
return this->client_->send_list_entities_services_response(resp);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/component_iterator.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
@ -11,7 +11,7 @@ class APIConnection;
|
||||||
|
|
||||||
class ListEntitiesIterator : public ComponentIterator {
|
class ListEntitiesIterator : public ComponentIterator {
|
||||||
public:
|
public:
|
||||||
ListEntitiesIterator(APIServer *server, APIConnection *client);
|
ListEntitiesIterator(APIConnection *client);
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
||||||
#endif
|
#endif
|
||||||
|
@ -60,5 +60,3 @@ class ListEntitiesIterator : public ComponentIterator {
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#include "api_server.h"
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "util.h"
|
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
|
@ -50,8 +50,7 @@ bool InitialStateIterator::on_select(select::Select *select) {
|
||||||
#ifdef USE_LOCK
|
#ifdef USE_LOCK
|
||||||
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); }
|
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); }
|
||||||
#endif
|
#endif
|
||||||
InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
|
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
|
||||||
: ComponentIterator(server), client_(client) {}
|
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/component_iterator.h"
|
||||||
#include "esphome/core/controller.h"
|
#include "esphome/core/controller.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
@ -12,7 +12,7 @@ class APIConnection;
|
||||||
|
|
||||||
class InitialStateIterator : public ComponentIterator {
|
class InitialStateIterator : public ComponentIterator {
|
||||||
public:
|
public:
|
||||||
InitialStateIterator(APIServer *server, APIConnection *client);
|
InitialStateIterator(APIConnection *client);
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,5 +55,3 @@ class InitialStateIterator : public ComponentIterator {
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#include "api_server.h"
|
|
||||||
|
|
|
@ -142,7 +142,6 @@ void IRAM_ATTR ESPOneWire::select(uint64_t address) {
|
||||||
void IRAM_ATTR ESPOneWire::reset_search() {
|
void IRAM_ATTR ESPOneWire::reset_search() {
|
||||||
this->last_discrepancy_ = 0;
|
this->last_discrepancy_ = 0;
|
||||||
this->last_device_flag_ = false;
|
this->last_device_flag_ = false;
|
||||||
this->last_family_discrepancy_ = 0;
|
|
||||||
this->rom_number_ = 0;
|
this->rom_number_ = 0;
|
||||||
}
|
}
|
||||||
uint64_t IRAM_ATTR ESPOneWire::search() {
|
uint64_t IRAM_ATTR ESPOneWire::search() {
|
||||||
|
@ -195,9 +194,6 @@ uint64_t IRAM_ATTR ESPOneWire::search() {
|
||||||
|
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
last_zero = id_bit_number;
|
last_zero = id_bit_number;
|
||||||
if (last_zero < 9) {
|
|
||||||
this->last_discrepancy_ = last_zero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,6 @@ class ESPOneWire {
|
||||||
|
|
||||||
ISRInternalGPIOPin pin_;
|
ISRInternalGPIOPin pin_;
|
||||||
uint8_t last_discrepancy_{0};
|
uint8_t last_discrepancy_{0};
|
||||||
uint8_t last_family_discrepancy_{0};
|
|
||||||
bool last_device_flag_{false};
|
bool last_device_flag_{false};
|
||||||
uint64_t rom_number_{0};
|
uint64_t rom_number_{0};
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,16 +16,24 @@ static const char *const TAG = "json";
|
||||||
static std::vector<char> global_json_build_buffer; // NOLINT
|
static std::vector<char> global_json_build_buffer; // NOLINT
|
||||||
|
|
||||||
std::string build_json(const json_build_t &f) {
|
std::string build_json(const json_build_t &f) {
|
||||||
// Here we are allocating as much heap memory as available minus 2kb to be safe
|
// Here we are allocating up to 5kb of memory,
|
||||||
|
// with the heap size minus 2kb to be safe if less than 5kb
|
||||||
// as we can not have a true dynamic sized document.
|
// as we can not have a true dynamic sized document.
|
||||||
// The excess memory is freed below with `shrinkToFit()`
|
// The excess memory is freed below with `shrinkToFit()`
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance)
|
const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#elif defined(USE_ESP32)
|
#elif defined(USE_ESP32)
|
||||||
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL) - 2048;
|
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DynamicJsonDocument json_document(free_heap);
|
const size_t request_size = std::min(free_heap - 2048, (size_t) 5120);
|
||||||
|
|
||||||
|
DynamicJsonDocument json_document(request_size);
|
||||||
|
if (json_document.memoryPool().buffer() == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, largest free heap block: %u bytes",
|
||||||
|
request_size, free_heap);
|
||||||
|
return "{}";
|
||||||
|
}
|
||||||
JsonObject root = json_document.to<JsonObject>();
|
JsonObject root = json_document.to<JsonObject>();
|
||||||
f(root);
|
f(root);
|
||||||
json_document.shrinkToFit();
|
json_document.shrinkToFit();
|
||||||
|
@ -36,27 +44,45 @@ std::string build_json(const json_build_t &f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_json(const std::string &data, const json_parse_t &f) {
|
void parse_json(const std::string &data, const json_parse_t &f) {
|
||||||
// Here we are allocating as much heap memory as available minus 2kb to be safe
|
// Here we are allocating 1.5 times the data size,
|
||||||
|
// with the heap size minus 2kb to be safe if less than that
|
||||||
// as we can not have a true dynamic sized document.
|
// as we can not have a true dynamic sized document.
|
||||||
// The excess memory is freed below with `shrinkToFit()`
|
// The excess memory is freed below with `shrinkToFit()`
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
const size_t free_heap = ESP.getMaxFreeBlockSize() - 2048; // NOLINT(readability-static-accessed-through-instance)
|
const size_t free_heap = ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#elif defined(USE_ESP32)
|
#elif defined(USE_ESP32)
|
||||||
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL) - 2048;
|
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
|
||||||
#endif
|
#endif
|
||||||
|
bool pass = false;
|
||||||
|
do {
|
||||||
|
const size_t request_size = std::min(free_heap - 2048, (size_t)(data.size() * 1.5));
|
||||||
|
|
||||||
DynamicJsonDocument json_document(free_heap);
|
DynamicJsonDocument json_document(request_size);
|
||||||
DeserializationError err = deserializeJson(json_document, data);
|
if (json_document.memoryPool().buffer() == nullptr) {
|
||||||
json_document.shrinkToFit();
|
ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, free heap: %u", request_size,
|
||||||
|
free_heap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeserializationError err = deserializeJson(json_document, data);
|
||||||
|
json_document.shrinkToFit();
|
||||||
|
|
||||||
JsonObject root = json_document.as<JsonObject>();
|
JsonObject root = json_document.as<JsonObject>();
|
||||||
|
|
||||||
if (err) {
|
if (err == DeserializationError::Ok) {
|
||||||
ESP_LOGW(TAG, "Parsing JSON failed.");
|
pass = true;
|
||||||
return;
|
f(root);
|
||||||
}
|
} else if (err == DeserializationError::NoMemory) {
|
||||||
|
if (request_size * 2 >= free_heap) {
|
||||||
f(root);
|
ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGW(TAG, "Increasing memory allocation.");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "JSON parse error: %s", err.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (!pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace json
|
} // namespace json
|
||||||
|
|
|
@ -473,6 +473,8 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_
|
||||||
App.reboot();
|
App.reboot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Delay here to allow power to stabilise before Wi-Fi/Ethernet is initialised.
|
||||||
|
delay(100); // NOLINT
|
||||||
App.setup();
|
App.setup();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Waiting for OTA attempt.");
|
ESP_LOGI(TAG, "Waiting for OTA attempt.");
|
||||||
|
|
97
esphome/components/web_server/list_entities.cpp
Normal file
97
esphome/components/web_server/list_entities.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#ifdef USE_ARDUINO
|
||||||
|
|
||||||
|
#include "list_entities.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
|
#include "web_server.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace web_server {
|
||||||
|
|
||||||
|
ListEntitiesIterator::ListEntitiesIterator(WebServer *web_server) : web_server_(web_server) {}
|
||||||
|
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
|
||||||
|
this->web_server_->events_.send(
|
||||||
|
this->web_server_->binary_sensor_json(binary_sensor, binary_sensor->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_COVER
|
||||||
|
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->cover_json(cover, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_FAN
|
||||||
|
bool ListEntitiesIterator::on_fan(fan::Fan *fan) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->fan_json(fan, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIGHT
|
||||||
|
bool ListEntitiesIterator::on_light(light::LightState *light) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->light_json(light, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SENSOR
|
||||||
|
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->sensor_json(sensor, sensor->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->switch_json(a_switch, a_switch->state, DETAIL_ALL).c_str(),
|
||||||
|
"state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BUTTON
|
||||||
|
bool ListEntitiesIterator::on_button(button::Button *button) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->button_json(button, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
|
||||||
|
this->web_server_->events_.send(
|
||||||
|
this->web_server_->text_sensor_json(text_sensor, text_sensor->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LOCK
|
||||||
|
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->lock_json(a_lock, a_lock->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CLIMATE
|
||||||
|
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->climate_json(climate, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
bool ListEntitiesIterator::on_number(number::Number *number) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->number_json(number, number->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SELECT
|
||||||
|
bool ListEntitiesIterator::on_select(select::Select *select) {
|
||||||
|
this->web_server_->events_.send(this->web_server_->select_json(select, select->state, DETAIL_ALL).c_str(), "state");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace web_server
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_ARDUINO
|
60
esphome/components/web_server/list_entities.h
Normal file
60
esphome/components/web_server/list_entities.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_ARDUINO
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/component_iterator.h"
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
namespace esphome {
|
||||||
|
namespace web_server {
|
||||||
|
|
||||||
|
class WebServer;
|
||||||
|
|
||||||
|
class ListEntitiesIterator : public ComponentIterator {
|
||||||
|
public:
|
||||||
|
ListEntitiesIterator(WebServer *web_server);
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_COVER
|
||||||
|
bool on_cover(cover::Cover *cover) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_FAN
|
||||||
|
bool on_fan(fan::Fan *fan) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIGHT
|
||||||
|
bool on_light(light::LightState *light) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SENSOR
|
||||||
|
bool on_sensor(sensor::Sensor *sensor) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
bool on_switch(switch_::Switch *a_switch) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BUTTON
|
||||||
|
bool on_button(button::Button *button) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CLIMATE
|
||||||
|
bool on_climate(climate::Climate *climate) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
bool on_number(number::Number *number) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SELECT
|
||||||
|
bool on_select(select::Select *select) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LOCK
|
||||||
|
bool on_lock(lock::Lock *a_lock) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WebServer *web_server_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace web_server
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_ARDUINO
|
|
@ -1,6 +1,7 @@
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
|
|
||||||
#include "web_server.h"
|
#include "web_server.h"
|
||||||
|
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/entity_base.h"
|
#include "esphome/core/entity_base.h"
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LOGGER
|
#ifdef USE_LOGGER
|
||||||
#include <esphome/components/logger/logger.h>
|
#include "esphome/components/logger/logger.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
|
@ -106,87 +107,7 @@ void WebServer::setup() {
|
||||||
}).c_str(),
|
}).c_str(),
|
||||||
"ping", millis(), 30000);
|
"ping", millis(), 30000);
|
||||||
|
|
||||||
#ifdef USE_SENSOR
|
this->entities_iterator_.begin(this->include_internal_);
|
||||||
for (auto *obj : App.get_sensors()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_SWITCH
|
|
||||||
for (auto *obj : App.get_switches()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->switch_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_BUTTON
|
|
||||||
for (auto *obj : App.get_buttons())
|
|
||||||
client->send(this->button_json(obj, DETAIL_ALL).c_str(), "state");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
|
||||||
for (auto *obj : App.get_binary_sensors()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->binary_sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_FAN
|
|
||||||
for (auto *obj : App.get_fans()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->fan_json(obj, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_LIGHT
|
|
||||||
for (auto *obj : App.get_lights()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->light_json(obj, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_TEXT_SENSOR
|
|
||||||
for (auto *obj : App.get_text_sensors()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->text_sensor_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_COVER
|
|
||||||
for (auto *obj : App.get_covers()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->cover_json(obj, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_NUMBER
|
|
||||||
for (auto *obj : App.get_numbers()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->number_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_SELECT
|
|
||||||
for (auto *obj : App.get_selects()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->select_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_CLIMATE
|
|
||||||
for (auto *obj : App.get_climates()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->climate_json(obj, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_LOCK
|
|
||||||
for (auto *obj : App.get_locks()) {
|
|
||||||
if (this->include_internal_ || !obj->is_internal())
|
|
||||||
client->send(this->lock_json(obj, obj->state, DETAIL_ALL).c_str(), "state");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifdef USE_LOGGER
|
#ifdef USE_LOGGER
|
||||||
|
@ -203,6 +124,7 @@ void WebServer::setup() {
|
||||||
|
|
||||||
this->set_interval(10000, [this]() { this->events_.send("", "ping", millis(), 30000); });
|
this->set_interval(10000, [this]() { this->events_.send("", "ping", millis(), 30000); });
|
||||||
}
|
}
|
||||||
|
void WebServer::loop() { this->entities_iterator_.advance(); }
|
||||||
void WebServer::dump_config() {
|
void WebServer::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "Web Server:");
|
ESP_LOGCONFIG(TAG, "Web Server:");
|
||||||
ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port());
|
ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port());
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
|
|
||||||
|
#include "list_entities.h"
|
||||||
|
|
||||||
#include "esphome/components/web_server_base/web_server_base.h"
|
#include "esphome/components/web_server_base/web_server_base.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/controller.h"
|
#include "esphome/core/controller.h"
|
||||||
|
@ -32,7 +34,7 @@ enum JsonDetail { DETAIL_ALL, DETAIL_STATE };
|
||||||
*/
|
*/
|
||||||
class WebServer : public Controller, public Component, public AsyncWebHandler {
|
class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
public:
|
public:
|
||||||
WebServer(web_server_base::WebServerBase *base) : base_(base) {}
|
WebServer(web_server_base::WebServerBase *base) : base_(base), entities_iterator_(ListEntitiesIterator(this)) {}
|
||||||
|
|
||||||
/** Set the URL to the CSS <link> that's sent to each client. Defaults to
|
/** Set the URL to the CSS <link> that's sent to each client. Defaults to
|
||||||
* https://esphome.io/_static/webserver-v1.min.css
|
* https://esphome.io/_static/webserver-v1.min.css
|
||||||
|
@ -76,6 +78,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
// (In most use cases you won't need these)
|
// (In most use cases you won't need these)
|
||||||
/// Setup the internal web server and register handlers.
|
/// Setup the internal web server and register handlers.
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
|
@ -217,8 +220,10 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
bool isRequestHandlerTrivial() override;
|
bool isRequestHandlerTrivial() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend ListEntitiesIterator;
|
||||||
web_server_base::WebServerBase *base_;
|
web_server_base::WebServerBase *base_;
|
||||||
AsyncEventSource events_{"/events"};
|
AsyncEventSource events_{"/events"};
|
||||||
|
ListEntitiesIterator entities_iterator_;
|
||||||
const char *css_url_{nullptr};
|
const char *css_url_{nullptr};
|
||||||
const char *css_include_{nullptr};
|
const char *css_include_{nullptr};
|
||||||
const char *js_url_{nullptr};
|
const char *js_url_{nullptr};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Constants used by esphome."""
|
"""Constants used by esphome."""
|
||||||
|
|
||||||
__version__ = "2022.3.0"
|
__version__ = "2022.3.1"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
#include "util.h"
|
#include "component_iterator.h"
|
||||||
#include "api_server.h"
|
|
||||||
#include "user_services.h"
|
|
||||||
#include "esphome/core/log.h"
|
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
|
|
||||||
namespace esphome {
|
#ifdef USE_API
|
||||||
namespace api {
|
#include "esphome/components/api/api_server.h"
|
||||||
|
#include "esphome/components/api/user_services.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
ComponentIterator::ComponentIterator(APIServer *server) : server_(server) {}
|
namespace esphome {
|
||||||
void ComponentIterator::begin() {
|
|
||||||
|
void ComponentIterator::begin(bool include_internal) {
|
||||||
this->state_ = IteratorState::BEGIN;
|
this->state_ = IteratorState::BEGIN;
|
||||||
this->at_ = 0;
|
this->at_ = 0;
|
||||||
|
this->include_internal_ = include_internal;
|
||||||
}
|
}
|
||||||
void ComponentIterator::advance() {
|
void ComponentIterator::advance() {
|
||||||
bool advance_platform = false;
|
bool advance_platform = false;
|
||||||
|
@ -32,7 +34,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *binary_sensor = App.get_binary_sensors()[this->at_];
|
auto *binary_sensor = App.get_binary_sensors()[this->at_];
|
||||||
if (binary_sensor->is_internal()) {
|
if (binary_sensor->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +49,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *cover = App.get_covers()[this->at_];
|
auto *cover = App.get_covers()[this->at_];
|
||||||
if (cover->is_internal()) {
|
if (cover->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +64,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *fan = App.get_fans()[this->at_];
|
auto *fan = App.get_fans()[this->at_];
|
||||||
if (fan->is_internal()) {
|
if (fan->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,7 +79,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *light = App.get_lights()[this->at_];
|
auto *light = App.get_lights()[this->at_];
|
||||||
if (light->is_internal()) {
|
if (light->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,7 +94,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *sensor = App.get_sensors()[this->at_];
|
auto *sensor = App.get_sensors()[this->at_];
|
||||||
if (sensor->is_internal()) {
|
if (sensor->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,7 +109,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *a_switch = App.get_switches()[this->at_];
|
auto *a_switch = App.get_switches()[this->at_];
|
||||||
if (a_switch->is_internal()) {
|
if (a_switch->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,7 +124,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *button = App.get_buttons()[this->at_];
|
auto *button = App.get_buttons()[this->at_];
|
||||||
if (button->is_internal()) {
|
if (button->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,7 +139,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *text_sensor = App.get_text_sensors()[this->at_];
|
auto *text_sensor = App.get_text_sensors()[this->at_];
|
||||||
if (text_sensor->is_internal()) {
|
if (text_sensor->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -146,20 +148,22 @@ void ComponentIterator::advance() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_API
|
||||||
case IteratorState ::SERVICE:
|
case IteratorState ::SERVICE:
|
||||||
if (this->at_ >= this->server_->get_user_services().size()) {
|
if (this->at_ >= api::global_api_server->get_user_services().size()) {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *service = this->server_->get_user_services()[this->at_];
|
auto *service = api::global_api_server->get_user_services()[this->at_];
|
||||||
success = this->on_service(service);
|
success = this->on_service(service);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
case IteratorState::CAMERA:
|
case IteratorState::CAMERA:
|
||||||
if (esp32_camera::global_esp32_camera == nullptr) {
|
if (esp32_camera::global_esp32_camera == nullptr) {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
if (esp32_camera::global_esp32_camera->is_internal()) {
|
if (esp32_camera::global_esp32_camera->is_internal() && !this->include_internal_) {
|
||||||
advance_platform = success = true;
|
advance_platform = success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -174,7 +178,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *climate = App.get_climates()[this->at_];
|
auto *climate = App.get_climates()[this->at_];
|
||||||
if (climate->is_internal()) {
|
if (climate->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -189,7 +193,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *number = App.get_numbers()[this->at_];
|
auto *number = App.get_numbers()[this->at_];
|
||||||
if (number->is_internal()) {
|
if (number->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,7 +208,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *select = App.get_selects()[this->at_];
|
auto *select = App.get_selects()[this->at_];
|
||||||
if (select->is_internal()) {
|
if (select->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -219,7 +223,7 @@ void ComponentIterator::advance() {
|
||||||
advance_platform = true;
|
advance_platform = true;
|
||||||
} else {
|
} else {
|
||||||
auto *a_lock = App.get_locks()[this->at_];
|
auto *a_lock = App.get_locks()[this->at_];
|
||||||
if (a_lock->is_internal()) {
|
if (a_lock->is_internal() && !this->include_internal_) {
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -244,10 +248,10 @@ void ComponentIterator::advance() {
|
||||||
}
|
}
|
||||||
bool ComponentIterator::on_end() { return true; }
|
bool ComponentIterator::on_end() { return true; }
|
||||||
bool ComponentIterator::on_begin() { return true; }
|
bool ComponentIterator::on_begin() { return true; }
|
||||||
bool ComponentIterator::on_service(UserServiceDescriptor *service) { return true; }
|
#ifdef USE_API
|
||||||
|
bool ComponentIterator::on_service(api::UserServiceDescriptor *service) { return true; }
|
||||||
|
#endif
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; }
|
bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace api
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
|
@ -1,23 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/helpers.h"
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/controller.h"
|
#include "esphome/core/controller.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
#include "esphome/components/esp32_camera/esp32_camera.h"
|
#include "esphome/components/esp32_camera/esp32_camera.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
|
||||||
|
|
||||||
class APIServer;
|
#ifdef USE_API
|
||||||
|
namespace api {
|
||||||
class UserServiceDescriptor;
|
class UserServiceDescriptor;
|
||||||
|
} // namespace api
|
||||||
|
#endif
|
||||||
|
|
||||||
class ComponentIterator {
|
class ComponentIterator {
|
||||||
public:
|
public:
|
||||||
ComponentIterator(APIServer *server);
|
void begin(bool include_internal = false);
|
||||||
|
|
||||||
void begin();
|
|
||||||
void advance();
|
void advance();
|
||||||
virtual bool on_begin();
|
virtual bool on_begin();
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
@ -44,7 +45,9 @@ class ComponentIterator {
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
|
virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
|
||||||
#endif
|
#endif
|
||||||
virtual bool on_service(UserServiceDescriptor *service);
|
#ifdef USE_API
|
||||||
|
virtual bool on_service(api::UserServiceDescriptor *service);
|
||||||
|
#endif
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
virtual bool on_camera(esp32_camera::ESP32Camera *camera);
|
virtual bool on_camera(esp32_camera::ESP32Camera *camera);
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,7 +93,9 @@ class ComponentIterator {
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
TEXT_SENSOR,
|
TEXT_SENSOR,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_API
|
||||||
SERVICE,
|
SERVICE,
|
||||||
|
#endif
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
CAMERA,
|
CAMERA,
|
||||||
#endif
|
#endif
|
||||||
|
@ -109,9 +114,7 @@ class ComponentIterator {
|
||||||
MAX,
|
MAX,
|
||||||
} state_{IteratorState::NONE};
|
} state_{IteratorState::NONE};
|
||||||
size_t at_{0};
|
size_t at_{0};
|
||||||
|
bool include_internal_{false};
|
||||||
APIServer *server_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace api
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
Loading…
Reference in a new issue