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.
This commit is contained in:
Andrew Zaborowski 2020-04-09 16:12:42 +02:00 committed by GitHub
parent 8613c02d5c
commit 17fd9d5107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 95 additions and 0 deletions

View file

@ -108,6 +108,12 @@ void WebServer::setup() {
if (!obj->is_internal()) if (!obj->is_internal())
client->send(this->text_sensor_json(obj, obj->state).c_str(), "state"); client->send(this->text_sensor_json(obj, obj->state).c_str(), "state");
#endif #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 #ifdef USE_LOGGER
@ -180,6 +186,11 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
write_row(stream, obj, "text_sensor", ""); write_row(stream, obj, "text_sensor", "");
#endif #endif
#ifdef USE_COVER
for (auto *obj : App.get_covers())
write_row(stream, obj, "cover", "<button>Open</button><button>Close</button>");
#endif
stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for " stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "
"REST API documentation.</p>" "REST API documentation.</p>"
"<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input " "<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
@ -495,6 +506,68 @@ std::string WebServer::light_json(light::LightState *obj) {
} }
#endif #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::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) { bool WebServer::canHandle(AsyncWebServerRequest *request) {
if (request->url() == "/") if (request->url() == "/")
return true; return true;
@ -542,6 +615,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) {
return true; return true;
#endif #endif
#ifdef USE_COVER
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "cover")
return true;
#endif
return false; return false;
} }
void WebServer::handleRequest(AsyncWebServerRequest *request) { void WebServer::handleRequest(AsyncWebServerRequest *request) {
@ -610,6 +688,13 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
return; return;
} }
#endif #endif
#ifdef USE_COVER
if (match.domain == "cover") {
this->handle_cover_request(request, match);
return;
}
#endif
} }
bool WebServer::isRequestHandlerTrivial() { return false; } bool WebServer::isRequestHandlerTrivial() { return false; }

View file

@ -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); std::string text_sensor_json(text_sensor::TextSensor *obj, const std::string &value);
#endif #endif
#ifdef USE_COVER
void on_cover_update(cover::Cover *obj) override;
/// Handle a cover request under '/cover/<id>/<open/close/stop/set>'.
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. /// Override the web handler's canHandle method.
bool canHandle(AsyncWebServerRequest *request) override; bool canHandle(AsyncWebServerRequest *request) override;
/// Override the web handler's handleRequest method. /// Override the web handler's handleRequest method.