mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					fc94a5d0ee | ||
| 
						 | 
					24029cc918 | ||
| 
						 | 
					9a9d5964ee | ||
| 
						 | 
					4e4a512107 | ||
| 
						 | 
					0729ed538e | ||
| 
						 | 
					24b75b7ed6 | 
@@ -23,7 +23,7 @@ static const char *const TAG = "api.connection";
 | 
			
		||||
static const int ESP32_CAMERA_STOP_STREAM = 5000;
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
#if defined(USE_API_PLAINTEXT)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#include "esphome/components/socket/socket.h"
 | 
			
		||||
#include "api_pb2.h"
 | 
			
		||||
#include "api_pb2_service.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "list_entities.h"
 | 
			
		||||
#include "subscribe_state.h"
 | 
			
		||||
#include "user_services.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -40,8 +40,7 @@ bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->s
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
 | 
			
		||||
ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client)
 | 
			
		||||
    : ComponentIterator(server), client_(client) {}
 | 
			
		||||
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
 | 
			
		||||
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
 | 
			
		||||
  auto resp = service->encode_list_service_response();
 | 
			
		||||
  return this->client_->send_list_entities_services_response(resp);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/component_iterator.h"
 | 
			
		||||
#include "esphome/core/defines.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace api {
 | 
			
		||||
@@ -11,7 +11,7 @@ class APIConnection;
 | 
			
		||||
 | 
			
		||||
class ListEntitiesIterator : public ComponentIterator {
 | 
			
		||||
 public:
 | 
			
		||||
  ListEntitiesIterator(APIServer *server, APIConnection *client);
 | 
			
		||||
  ListEntitiesIterator(APIConnection *client);
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -60,5 +60,3 @@ class ListEntitiesIterator : public ComponentIterator {
 | 
			
		||||
 | 
			
		||||
}  // namespace api
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#include "api_server.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
#include "proto.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
 
 | 
			
		||||
@@ -50,8 +50,7 @@ bool InitialStateIterator::on_select(select::Select *select) {
 | 
			
		||||
#ifdef USE_LOCK
 | 
			
		||||
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); }
 | 
			
		||||
#endif
 | 
			
		||||
InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
 | 
			
		||||
    : ComponentIterator(server), client_(client) {}
 | 
			
		||||
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
 | 
			
		||||
 | 
			
		||||
}  // namespace api
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/component_iterator.h"
 | 
			
		||||
#include "esphome/core/controller.h"
 | 
			
		||||
#include "esphome/core/defines.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace api {
 | 
			
		||||
@@ -12,7 +12,7 @@ class APIConnection;
 | 
			
		||||
 | 
			
		||||
class InitialStateIterator : public ComponentIterator {
 | 
			
		||||
 public:
 | 
			
		||||
  InitialStateIterator(APIServer *server, APIConnection *client);
 | 
			
		||||
  InitialStateIterator(APIConnection *client);
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -55,5 +55,3 @@ class InitialStateIterator : public ComponentIterator {
 | 
			
		||||
 | 
			
		||||
}  // namespace api
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#include "api_server.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -142,7 +142,6 @@ void IRAM_ATTR ESPOneWire::select(uint64_t address) {
 | 
			
		||||
void IRAM_ATTR ESPOneWire::reset_search() {
 | 
			
		||||
  this->last_discrepancy_ = 0;
 | 
			
		||||
  this->last_device_flag_ = false;
 | 
			
		||||
  this->last_family_discrepancy_ = 0;
 | 
			
		||||
  this->rom_number_ = 0;
 | 
			
		||||
}
 | 
			
		||||
uint64_t IRAM_ATTR ESPOneWire::search() {
 | 
			
		||||
@@ -195,9 +194,6 @@ uint64_t IRAM_ATTR ESPOneWire::search() {
 | 
			
		||||
 | 
			
		||||
        if (!branch) {
 | 
			
		||||
          last_zero = id_bit_number;
 | 
			
		||||
          if (last_zero < 9) {
 | 
			
		||||
            this->last_discrepancy_ = last_zero;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,6 @@ class ESPOneWire {
 | 
			
		||||
 | 
			
		||||
  ISRInternalGPIOPin pin_;
 | 
			
		||||
  uint8_t last_discrepancy_{0};
 | 
			
		||||
  uint8_t last_family_discrepancy_{0};
 | 
			
		||||
  bool last_device_flag_{false};
 | 
			
		||||
  uint64_t rom_number_{0};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -16,16 +16,24 @@ static const char *const TAG = "json";
 | 
			
		||||
static std::vector<char> global_json_build_buffer;  // NOLINT
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
  // The excess memory is freed below with `shrinkToFit()`
 | 
			
		||||
#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)
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
  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>();
 | 
			
		||||
  f(root);
 | 
			
		||||
  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) {
 | 
			
		||||
  // 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.
 | 
			
		||||
  // The excess memory is freed below with `shrinkToFit()`
 | 
			
		||||
#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)
 | 
			
		||||
  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
 | 
			
		||||
  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);
 | 
			
		||||
  DeserializationError err = deserializeJson(json_document, data);
 | 
			
		||||
  json_document.shrinkToFit();
 | 
			
		||||
    DynamicJsonDocument json_document(request_size);
 | 
			
		||||
    if (json_document.memoryPool().buffer() == nullptr) {
 | 
			
		||||
      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) {
 | 
			
		||||
    ESP_LOGW(TAG, "Parsing JSON failed.");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  f(root);
 | 
			
		||||
    if (err == DeserializationError::Ok) {
 | 
			
		||||
      pass = true;
 | 
			
		||||
      f(root);
 | 
			
		||||
    } else if (err == DeserializationError::NoMemory) {
 | 
			
		||||
      if (request_size * 2 >= free_heap) {
 | 
			
		||||
        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
 | 
			
		||||
 
 | 
			
		||||
@@ -473,6 +473,8 @@ bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_
 | 
			
		||||
      App.reboot();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Delay here to allow power to stabilise before Wi-Fi/Ethernet is initialised.
 | 
			
		||||
    delay(100);  // NOLINT
 | 
			
		||||
    App.setup();
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
#include "web_server.h"
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
@@ -17,7 +18,7 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LOGGER
 | 
			
		||||
#include <esphome/components/logger/logger.h>
 | 
			
		||||
#include "esphome/components/logger/logger.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_FAN
 | 
			
		||||
@@ -106,87 +107,7 @@ void WebServer::setup() {
 | 
			
		||||
                 }).c_str(),
 | 
			
		||||
                 "ping", millis(), 30000);
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SENSOR
 | 
			
		||||
    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
 | 
			
		||||
    this->entities_iterator_.begin(this->include_internal_);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LOGGER
 | 
			
		||||
@@ -203,6 +124,7 @@ void WebServer::setup() {
 | 
			
		||||
 | 
			
		||||
  this->set_interval(10000, [this]() { this->events_.send("", "ping", millis(), 30000); });
 | 
			
		||||
}
 | 
			
		||||
void WebServer::loop() { this->entities_iterator_.advance(); }
 | 
			
		||||
void WebServer::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Web Server:");
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Address: %s:%u", network::get_use_address().c_str(), this->base_->get_port());
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
 | 
			
		||||
#include "list_entities.h"
 | 
			
		||||
 | 
			
		||||
#include "esphome/components/web_server_base/web_server_base.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/controller.h"
 | 
			
		||||
@@ -32,7 +34,7 @@ enum JsonDetail { DETAIL_ALL, DETAIL_STATE };
 | 
			
		||||
 */
 | 
			
		||||
class WebServer : public Controller, public Component, public AsyncWebHandler {
 | 
			
		||||
 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
 | 
			
		||||
   * 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)
 | 
			
		||||
  /// Setup the internal web server and register handlers.
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void loop() override;
 | 
			
		||||
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
 | 
			
		||||
@@ -217,8 +220,10 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
 | 
			
		||||
  bool isRequestHandlerTrivial() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  friend ListEntitiesIterator;
 | 
			
		||||
  web_server_base::WebServerBase *base_;
 | 
			
		||||
  AsyncEventSource events_{"/events"};
 | 
			
		||||
  ListEntitiesIterator entities_iterator_;
 | 
			
		||||
  const char *css_url_{nullptr};
 | 
			
		||||
  const char *css_include_{nullptr};
 | 
			
		||||
  const char *js_url_{nullptr};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2022.3.0"
 | 
			
		||||
__version__ = "2022.3.1"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,18 @@
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "api_server.h"
 | 
			
		||||
#include "user_services.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "component_iterator.h"
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace api {
 | 
			
		||||
#ifdef USE_API
 | 
			
		||||
#include "esphome/components/api/api_server.h"
 | 
			
		||||
#include "esphome/components/api/user_services.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
ComponentIterator::ComponentIterator(APIServer *server) : server_(server) {}
 | 
			
		||||
void ComponentIterator::begin() {
 | 
			
		||||
namespace esphome {
 | 
			
		||||
 | 
			
		||||
void ComponentIterator::begin(bool include_internal) {
 | 
			
		||||
  this->state_ = IteratorState::BEGIN;
 | 
			
		||||
  this->at_ = 0;
 | 
			
		||||
  this->include_internal_ = include_internal;
 | 
			
		||||
}
 | 
			
		||||
void ComponentIterator::advance() {
 | 
			
		||||
  bool advance_platform = false;
 | 
			
		||||
@@ -32,7 +34,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *binary_sensor = App.get_binary_sensors()[this->at_];
 | 
			
		||||
        if (binary_sensor->is_internal()) {
 | 
			
		||||
        if (binary_sensor->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -47,7 +49,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *cover = App.get_covers()[this->at_];
 | 
			
		||||
        if (cover->is_internal()) {
 | 
			
		||||
        if (cover->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -62,7 +64,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *fan = App.get_fans()[this->at_];
 | 
			
		||||
        if (fan->is_internal()) {
 | 
			
		||||
        if (fan->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -77,7 +79,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *light = App.get_lights()[this->at_];
 | 
			
		||||
        if (light->is_internal()) {
 | 
			
		||||
        if (light->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -92,7 +94,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *sensor = App.get_sensors()[this->at_];
 | 
			
		||||
        if (sensor->is_internal()) {
 | 
			
		||||
        if (sensor->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -107,7 +109,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *a_switch = App.get_switches()[this->at_];
 | 
			
		||||
        if (a_switch->is_internal()) {
 | 
			
		||||
        if (a_switch->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -122,7 +124,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *button = App.get_buttons()[this->at_];
 | 
			
		||||
        if (button->is_internal()) {
 | 
			
		||||
        if (button->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -137,7 +139,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *text_sensor = App.get_text_sensors()[this->at_];
 | 
			
		||||
        if (text_sensor->is_internal()) {
 | 
			
		||||
        if (text_sensor->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -146,20 +148,22 @@ void ComponentIterator::advance() {
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_API
 | 
			
		||||
    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;
 | 
			
		||||
      } 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);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP32_CAMERA
 | 
			
		||||
    case IteratorState::CAMERA:
 | 
			
		||||
      if (esp32_camera::global_esp32_camera == nullptr) {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        if (esp32_camera::global_esp32_camera->is_internal()) {
 | 
			
		||||
        if (esp32_camera::global_esp32_camera->is_internal() && !this->include_internal_) {
 | 
			
		||||
          advance_platform = success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -174,7 +178,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *climate = App.get_climates()[this->at_];
 | 
			
		||||
        if (climate->is_internal()) {
 | 
			
		||||
        if (climate->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -189,7 +193,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *number = App.get_numbers()[this->at_];
 | 
			
		||||
        if (number->is_internal()) {
 | 
			
		||||
        if (number->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -204,7 +208,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *select = App.get_selects()[this->at_];
 | 
			
		||||
        if (select->is_internal()) {
 | 
			
		||||
        if (select->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -219,7 +223,7 @@ void ComponentIterator::advance() {
 | 
			
		||||
        advance_platform = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        auto *a_lock = App.get_locks()[this->at_];
 | 
			
		||||
        if (a_lock->is_internal()) {
 | 
			
		||||
        if (a_lock->is_internal() && !this->include_internal_) {
 | 
			
		||||
          success = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -244,10 +248,10 @@ void ComponentIterator::advance() {
 | 
			
		||||
}
 | 
			
		||||
bool ComponentIterator::on_end() { 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
 | 
			
		||||
bool ComponentIterator::on_camera(esp32_camera::ESP32Camera *camera) { return true; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace api
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,23 +1,24 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/controller.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32_CAMERA
 | 
			
		||||
#include "esphome/components/esp32_camera/esp32_camera.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace api {
 | 
			
		||||
 | 
			
		||||
class APIServer;
 | 
			
		||||
#ifdef USE_API
 | 
			
		||||
namespace api {
 | 
			
		||||
class UserServiceDescriptor;
 | 
			
		||||
}  // namespace api
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class ComponentIterator {
 | 
			
		||||
 public:
 | 
			
		||||
  ComponentIterator(APIServer *server);
 | 
			
		||||
 | 
			
		||||
  void begin();
 | 
			
		||||
  void begin(bool include_internal = false);
 | 
			
		||||
  void advance();
 | 
			
		||||
  virtual bool on_begin();
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
@@ -44,7 +45,9 @@ class ComponentIterator {
 | 
			
		||||
#ifdef USE_TEXT_SENSOR
 | 
			
		||||
  virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
 | 
			
		||||
#endif
 | 
			
		||||
  virtual bool on_service(UserServiceDescriptor *service);
 | 
			
		||||
#ifdef USE_API
 | 
			
		||||
  virtual bool on_service(api::UserServiceDescriptor *service);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP32_CAMERA
 | 
			
		||||
  virtual bool on_camera(esp32_camera::ESP32Camera *camera);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -90,7 +93,9 @@ class ComponentIterator {
 | 
			
		||||
#ifdef USE_TEXT_SENSOR
 | 
			
		||||
    TEXT_SENSOR,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_API
 | 
			
		||||
    SERVICE,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP32_CAMERA
 | 
			
		||||
    CAMERA,
 | 
			
		||||
#endif
 | 
			
		||||
@@ -109,9 +114,7 @@ class ComponentIterator {
 | 
			
		||||
    MAX,
 | 
			
		||||
  } state_{IteratorState::NONE};
 | 
			
		||||
  size_t at_{0};
 | 
			
		||||
 | 
			
		||||
  APIServer *server_;
 | 
			
		||||
  bool include_internal_{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace api
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
		Reference in New Issue
	
	Block a user