From 17fd9d5107d8ddbf51abcf8288c3088126cd9cdd Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Thu, 9 Apr 2020 16:12:42 +0200 Subject: [PATCH] web_server: Add cover calls to REST API (#999) Add the GET and POST handler for cover components. Also add covers to the index page although the Open/Close buttons that are shown for covers will need a few lines added to webserver-v1.js, without them they don't do anything. --- esphome/components/web_server/web_server.cpp | 85 ++++++++++++++++++++ esphome/components/web_server/web_server.h | 10 +++ 2 files changed, 95 insertions(+) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index c0708b763f..1f6cd10666 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -108,6 +108,12 @@ void WebServer::setup() { if (!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()) + client->send(this->cover_json(obj).c_str(), "state"); +#endif }); #ifdef USE_LOGGER @@ -180,6 +186,11 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { write_row(stream, obj, "text_sensor", ""); #endif +#ifdef USE_COVER + for (auto *obj : App.get_covers()) + write_row(stream, obj, "cover", ""); +#endif + stream->print(F("

See ESPHome Web API for " "REST API documentation.

" "

OTA Update

is_internal()) + return; + this->events_.send(this->cover_json(obj).c_str(), "state"); +} +void WebServer::handle_cover_request(AsyncWebServerRequest *request, UrlMatch match) { + for (cover::Cover *obj : App.get_covers()) { + if (obj->is_internal()) + continue; + if (obj->get_object_id() != match.id) + continue; + + if (request->method() == HTTP_GET) { + std::string data = this->cover_json(obj); + request->send(200, "text/json", data.c_str()); + continue; + } + + auto call = obj->make_call(); + if (match.method == "open") { + call.set_command_open(); + } else if (match.method == "close") { + call.set_command_close(); + } else if (match.method == "stop") { + call.set_command_stop(); + } else if (match.method != "set") { + request->send(404); + return; + } + + auto traits = obj->get_traits(); + if ((request->hasParam("position") && !traits.get_supports_position()) || + (request->hasParam("tilt") && !traits.get_supports_tilt())) { + request->send(409); + return; + } + + if (request->hasParam("position")) + call.set_position(request->getParam("position")->value().toFloat()); + if (request->hasParam("tilt")) + call.set_tilt(request->getParam("tilt")->value().toFloat()); + + this->defer([call]() mutable { call.perform(); }); + request->send(200); + return; + } + request->send(404); +} +std::string WebServer::cover_json(cover::Cover *obj) { + return json::build_json([obj](JsonObject &root) { + root["id"] = "cover-" + obj->get_object_id(); + root["state"] = obj->is_fully_closed() ? "CLOSED" : "OPEN"; + root["value"] = obj->position; + root["current_operation"] = cover::cover_operation_to_str(obj->current_operation); + + if (obj->get_traits().get_supports_tilt()) + root["tilt"] = obj->tilt; + }); +} +#endif + bool WebServer::canHandle(AsyncWebServerRequest *request) { if (request->url() == "/") return true; @@ -542,6 +615,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) { return true; #endif +#ifdef USE_COVER + if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "cover") + return true; +#endif + return false; } void WebServer::handleRequest(AsyncWebServerRequest *request) { @@ -610,6 +688,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { return; } #endif + +#ifdef USE_COVER + if (match.domain == "cover") { + this->handle_cover_request(request, match); + return; + } +#endif } bool WebServer::isRequestHandlerTrivial() { return false; } diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index def1cac0ea..b3bf2ef7f7 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -144,6 +144,16 @@ class WebServer : public Controller, public Component, public AsyncWebHandler { std::string text_sensor_json(text_sensor::TextSensor *obj, const std::string &value); #endif +#ifdef USE_COVER + void on_cover_update(cover::Cover *obj) override; + + /// Handle a cover request under '/cover//'. + void handle_cover_request(AsyncWebServerRequest *request, UrlMatch match); + + /// Dump the cover state as a JSON string. + std::string cover_json(cover::Cover *obj); +#endif + /// Override the web handler's canHandle method. bool canHandle(AsyncWebServerRequest *request) override; /// Override the web handler's handleRequest method.