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.

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