Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
4.8 KiB

  1. /*
  2. API MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if WEB_SUPPORT
  6. #include <ESPAsyncTCP.h>
  7. #include <ESPAsyncWebServer.h>
  8. #include <ArduinoJson.h>
  9. #include <Ticker.h>
  10. Ticker _api_defer;
  11. typedef struct {
  12. char * url;
  13. char * key;
  14. apiGetCallbackFunction getFn = NULL;
  15. apiPutCallbackFunction putFn = NULL;
  16. } web_api_t;
  17. std::vector<web_api_t> _apis;
  18. // -----------------------------------------------------------------------------
  19. // API
  20. // -----------------------------------------------------------------------------
  21. bool _authAPI(AsyncWebServerRequest *request) {
  22. if (getSetting("apiEnabled", API_ENABLED).toInt() == 0) {
  23. DEBUG_MSG_P(PSTR("[WEBSERVER] HTTP API is not enabled\n"));
  24. request->send(403);
  25. return false;
  26. }
  27. if (!request->hasParam("apikey", (request->method() == HTTP_PUT))) {
  28. DEBUG_MSG_P(PSTR("[WEBSERVER] Missing apikey parameter\n"));
  29. request->send(403);
  30. return false;
  31. }
  32. AsyncWebParameter* p = request->getParam("apikey", (request->method() == HTTP_PUT));
  33. if (!p->value().equals(getSetting("apiKey"))) {
  34. DEBUG_MSG_P(PSTR("[WEBSERVER] Wrong apikey parameter\n"));
  35. request->send(403);
  36. return false;
  37. }
  38. return true;
  39. }
  40. bool _asJson(AsyncWebServerRequest *request) {
  41. bool asJson = false;
  42. if (request->hasHeader("Accept")) {
  43. AsyncWebHeader* h = request->getHeader("Accept");
  44. asJson = h->value().equals("application/json");
  45. }
  46. return asJson;
  47. }
  48. ArRequestHandlerFunction _bindAPI(unsigned int apiID) {
  49. return [apiID](AsyncWebServerRequest *request) {
  50. webLog(request);
  51. if (!_authAPI(request)) return;
  52. web_api_t api = _apis[apiID];
  53. // Check if its a PUT
  54. if (api.putFn != NULL) {
  55. if (request->hasParam("value", request->method() == HTTP_PUT)) {
  56. AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
  57. (api.putFn)((p->value()).c_str());
  58. }
  59. }
  60. // Get response from callback
  61. char value[API_BUFFER_SIZE];
  62. (api.getFn)(value, API_BUFFER_SIZE);
  63. // The response will be a 404 NOT FOUND if the resource is not available
  64. if (!value) {
  65. DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
  66. request->send(404);
  67. return;
  68. }
  69. DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
  70. // Format response according to the Accept header
  71. if (_asJson(request)) {
  72. char buffer[64];
  73. snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
  74. request->send(200, "application/json", buffer);
  75. } else {
  76. request->send(200, "text/plain", value);
  77. }
  78. };
  79. }
  80. void _onAPIs(AsyncWebServerRequest *request) {
  81. webLog(request);
  82. if (!_authAPI(request)) return;
  83. bool asJson = _asJson(request);
  84. String output;
  85. if (asJson) {
  86. DynamicJsonBuffer jsonBuffer;
  87. JsonObject& root = jsonBuffer.createObject();
  88. for (unsigned int i=0; i < _apis.size(); i++) {
  89. root[_apis[i].key] = _apis[i].url;
  90. }
  91. root.printTo(output);
  92. request->send(200, "application/json", output);
  93. } else {
  94. for (unsigned int i=0; i < _apis.size(); i++) {
  95. output += _apis[i].key + String(" -> ") + _apis[i].url + String("\n");
  96. }
  97. request->send(200, "text/plain", output);
  98. }
  99. }
  100. void _onRPC(AsyncWebServerRequest *request) {
  101. webLog(request);
  102. if (!_authAPI(request)) return;
  103. //bool asJson = _asJson(request);
  104. int response = 404;
  105. if (request->hasParam("action")) {
  106. AsyncWebParameter* p = request->getParam("action");
  107. String action = p->value();
  108. DEBUG_MSG_P(PSTR("[RPC] Action: %s\n"), action.c_str());
  109. if (action.equals("reset")) {
  110. response = 200;
  111. _api_defer.once_ms(100, []() {
  112. customReset(CUSTOM_RESET_RPC);
  113. ESP.restart();
  114. });
  115. }
  116. }
  117. request->send(response);
  118. }
  119. // -----------------------------------------------------------------------------
  120. void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn) {
  121. // Store it
  122. web_api_t api;
  123. char buffer[40];
  124. snprintf_P(buffer, sizeof(buffer), PSTR("/api/%s"), url);
  125. api.url = strdup(buffer);
  126. api.key = strdup(key);
  127. api.getFn = getFn;
  128. api.putFn = putFn;
  129. _apis.push_back(api);
  130. // Bind call
  131. unsigned int methods = HTTP_GET;
  132. if (putFn != NULL) methods += HTTP_PUT;
  133. webServer()->on(buffer, methods, _bindAPI(_apis.size() - 1));
  134. }
  135. void apiSetup() {
  136. webServer()->on("/apis", HTTP_GET, _onAPIs);
  137. webServer()->on("/rpc", HTTP_GET, _onRPC);
  138. }
  139. #endif // WEB_SUPPORT