mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
Optionally show internal components on the web server (#2627)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
parent
adf48246a9
commit
6f07421911
7 changed files with 67 additions and 78 deletions
|
@ -12,6 +12,7 @@ from esphome.const import (
|
|||
CONF_AUTH,
|
||||
CONF_USERNAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_INCLUDE_INTERNAL,
|
||||
CONF_OTA,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
|
@ -42,6 +43,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||
cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id(
|
||||
web_server_base.WebServerBase
|
||||
),
|
||||
cv.Optional(CONF_INCLUDE_INTERNAL, default=False): cv.boolean,
|
||||
cv.Optional(CONF_OTA, default=True): cv.boolean,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
@ -75,3 +77,4 @@ async def to_code(config):
|
|||
path = CORE.relative_config_path(config[CONF_JS_INCLUDE])
|
||||
with open(file=path, mode="r", encoding="utf-8") as myfile:
|
||||
cg.add(var.set_js_include(myfile.read()))
|
||||
cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL]))
|
||||
|
|
|
@ -31,10 +31,10 @@ static const char *const TAG = "web_server";
|
|||
|
||||
void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action,
|
||||
const std::function<void(AsyncResponseStream &stream, EntityBase *obj)> &action_func = nullptr) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
stream->print("<tr class=\"");
|
||||
stream->print(klass.c_str());
|
||||
if (obj->is_internal())
|
||||
stream->print(" internal");
|
||||
stream->print("\" id=\"");
|
||||
stream->print(klass.c_str());
|
||||
stream->print("-");
|
||||
|
@ -83,7 +83,7 @@ void WebServer::set_js_include(const char *js_include) { this->js_include_ = js_
|
|||
|
||||
void WebServer::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up web server...");
|
||||
this->setup_controller();
|
||||
this->setup_controller(this->include_internal_);
|
||||
this->base_->init();
|
||||
|
||||
this->events_.onConnect([this](AsyncEventSourceClient *client) {
|
||||
|
@ -92,55 +92,55 @@ void WebServer::setup() {
|
|||
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->sensor_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->switch_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->binary_sensor_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->fan_json(obj).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->light_json(obj).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->text_sensor_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->cover_json(obj).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->number_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects())
|
||||
if (!obj->is_internal())
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
client->send(this->select_json(obj, obj->state).c_str(), "state");
|
||||
#endif
|
||||
});
|
||||
|
@ -188,57 +188,66 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
|||
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors())
|
||||
write_row(stream, obj, "sensor", "");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "sensor", "");
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches())
|
||||
write_row(stream, obj, "switch", "<button>Toggle</button>");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "switch", "<button>Toggle</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors())
|
||||
write_row(stream, obj, "binary_sensor", "");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "binary_sensor", "");
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans())
|
||||
write_row(stream, obj, "fan", "<button>Toggle</button>");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "fan", "<button>Toggle</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights())
|
||||
write_row(stream, obj, "light", "<button>Toggle</button>");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "light", "<button>Toggle</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors())
|
||||
write_row(stream, obj, "text_sensor", "");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "text_sensor", "");
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers())
|
||||
write_row(stream, obj, "cover", "<button>Open</button><button>Close</button>");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "cover", "<button>Open</button><button>Close</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers())
|
||||
write_row(stream, obj, "number", "");
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "number", "");
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects())
|
||||
write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
select::Select *select = (select::Select *) obj;
|
||||
stream.print("<select>");
|
||||
stream.print("<option></option>");
|
||||
for (auto const &option : select->traits.get_options()) {
|
||||
stream.print("<option>");
|
||||
stream.print(option.c_str());
|
||||
stream.print("</option>");
|
||||
}
|
||||
stream.print("</select>");
|
||||
});
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
select::Select *select = (select::Select *) obj;
|
||||
stream.print("<select>");
|
||||
stream.print("<option></option>");
|
||||
for (auto const &option : select->traits.get_options()) {
|
||||
stream.print("<option>");
|
||||
stream.print(option.c_str());
|
||||
stream.print("</option>");
|
||||
}
|
||||
stream.print("</select>");
|
||||
});
|
||||
#endif
|
||||
|
||||
stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "
|
||||
|
@ -293,8 +302,6 @@ void WebServer::on_sensor_update(sensor::Sensor *obj, float state) {
|
|||
}
|
||||
void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (sensor::Sensor *obj : App.get_sensors()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->sensor_json(obj, obj->state);
|
||||
|
@ -321,8 +328,6 @@ void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::s
|
|||
}
|
||||
void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (text_sensor::TextSensor *obj : App.get_text_sensors()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->text_sensor_json(obj, obj->state);
|
||||
|
@ -353,8 +358,6 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value) {
|
|||
}
|
||||
void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (switch_::Switch *obj : App.get_switches()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
|
||||
|
@ -381,8 +384,6 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM
|
|||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
this->events_.send(this->binary_sensor_json(obj, state).c_str(), "state");
|
||||
}
|
||||
std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool value) {
|
||||
|
@ -394,8 +395,6 @@ std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool
|
|||
}
|
||||
void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->binary_sensor_json(obj, obj->state);
|
||||
|
@ -407,11 +406,7 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con
|
|||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
void WebServer::on_fan_update(fan::FanState *obj) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
this->events_.send(this->fan_json(obj).c_str(), "state");
|
||||
}
|
||||
void WebServer::on_fan_update(fan::FanState *obj) { this->events_.send(this->fan_json(obj).c_str(), "state"); }
|
||||
std::string WebServer::fan_json(fan::FanState *obj) {
|
||||
return json::build_json([obj](JsonObject &root) {
|
||||
root["id"] = "fan-" + obj->get_object_id();
|
||||
|
@ -442,8 +437,6 @@ std::string WebServer::fan_json(fan::FanState *obj) {
|
|||
}
|
||||
void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (fan::FanState *obj : App.get_fans()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
|
||||
|
@ -504,15 +497,9 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
|||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
void WebServer::on_light_update(light::LightState *obj) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
this->events_.send(this->light_json(obj).c_str(), "state");
|
||||
}
|
||||
void WebServer::on_light_update(light::LightState *obj) { this->events_.send(this->light_json(obj).c_str(), "state"); }
|
||||
void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (light::LightState *obj : App.get_lights()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
|
||||
|
@ -579,15 +566,9 @@ std::string WebServer::light_json(light::LightState *obj) {
|
|||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
void WebServer::on_cover_update(cover::Cover *obj) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
this->events_.send(this->cover_json(obj).c_str(), "state");
|
||||
}
|
||||
void WebServer::on_cover_update(cover::Cover *obj) { this->events_.send(this->cover_json(obj).c_str(), "state"); }
|
||||
void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (cover::Cover *obj : App.get_covers()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
|
||||
|
@ -646,8 +627,6 @@ void WebServer::on_number_update(number::Number *obj, float state) {
|
|||
}
|
||||
void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->number_json(obj, obj->state);
|
||||
|
@ -673,8 +652,6 @@ void WebServer::on_select_update(select::Select *obj, const std::string &state)
|
|||
}
|
||||
void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (obj->is_internal())
|
||||
continue;
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -58,6 +58,12 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
|||
*/
|
||||
void set_js_include(const char *js_include);
|
||||
|
||||
/** Determine whether internal components should be displayed on the web server.
|
||||
* Defaults to false.
|
||||
*
|
||||
* @param include_internal Whether internal components should be displayed.
|
||||
*/
|
||||
void set_include_internal(bool include_internal) { include_internal_ = include_internal; }
|
||||
/** Set whether or not the webserver should expose the OTA form and handler.
|
||||
*
|
||||
* @param allow_ota.
|
||||
|
@ -188,6 +194,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
|||
const char *css_include_{nullptr};
|
||||
const char *js_url_{nullptr};
|
||||
const char *js_include_{nullptr};
|
||||
bool include_internal_{false};
|
||||
bool allow_ota_{true};
|
||||
};
|
||||
|
||||
|
|
|
@ -286,6 +286,7 @@ CONF_ILLUMINANCE = "illuminance"
|
|||
CONF_IMPEDANCE = "impedance"
|
||||
CONF_IMPORT_ACTIVE_ENERGY = "import_active_energy"
|
||||
CONF_IMPORT_REACTIVE_ENERGY = "import_reactive_energy"
|
||||
CONF_INCLUDE_INTERNAL = "include_internal"
|
||||
CONF_INCLUDES = "includes"
|
||||
CONF_INDEX = "index"
|
||||
CONF_INDOOR = "indoor"
|
||||
|
|
|
@ -4,64 +4,64 @@
|
|||
|
||||
namespace esphome {
|
||||
|
||||
void Controller::setup_controller() {
|
||||
void Controller::setup_controller(bool include_internal) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](bool state) { this->on_binary_sensor_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_fan_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_new_remote_values_callback([this, obj]() { this->on_light_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](float state) { this->on_sensor_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](bool state) { this->on_switch_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_cover_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](const std::string &state) { this->on_text_sensor_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
for (auto *obj : App.get_climates()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_climate_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](float state) { this->on_number_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (!obj->is_internal())
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](const std::string &state) { this->on_select_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace esphome {
|
|||
|
||||
class Controller {
|
||||
public:
|
||||
void setup_controller();
|
||||
void setup_controller(bool include_internal = false);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state){};
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,7 @@ web_server:
|
|||
auth:
|
||||
username: admin
|
||||
password: admin
|
||||
include_internal: true
|
||||
|
||||
time:
|
||||
- platform: sntp
|
||||
|
|
Loading…
Reference in a new issue