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.

241 lines
6.4 KiB

Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
Terminal: change command-line parser (#2247) Change the underlying command line handling: - switch to a custom parser, inspired by redis / sds - update terminalRegisterCommand signature, pass only bare minimum - clean-up `help` & `commands`. update settings `set`, `get` and `del` - allow our custom test suite to run command-line tests - clean-up Stream IO to allow us to print large things into debug stream (for example, `eeprom.dump`) - send parsing errors to the debug log As a proof of concept, introduce `TERMINAL_MQTT_SUPPORT` and `TERMINAL_WEB_API_SUPPORT` - MQTT subscribes to the `<root>/cmd/set` and sends response to the `<root>/cmd`. We can't output too much, as we don't have any large-send API. - Web API listens to the `/api/cmd?apikey=...&line=...` (or PUT, params inside the body). This one is intended as a possible replacement of the `API_SUPPORT`. Internals introduce a 'task' around the AsyncWebServerRequest object that will simulate what WiFiClient does and push data into it continuously, switching between CONT and SYS. Both are experimental. We only accept a single command and not every command is updated to use Print `ctx.output` object. We are also somewhat limited by the Print / Stream overall, perhaps I am overestimating the usefulness of Arduino compatibility to such an extent :) Web API handler can also sometimes show only part of the result, whenever the command tries to yield() by itself waiting for something. Perhaps we would need to create a custom request handler for that specific use-case.
4 years ago
  1. /*
  2. SETTINGS MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #pragma once
  6. #include "espurna.h"
  7. #include <functional>
  8. #include <utility>
  9. #include <vector>
  10. #include <ArduinoJson.h>
  11. #include <Embedis.h>
  12. #include "broker.h"
  13. BrokerDeclare(ConfigBroker, void(const String& key, const String& value));
  14. // --------------------------------------------------------------------------
  15. class settings_key_t {
  16. public:
  17. settings_key_t(const char* value, unsigned char index) :
  18. value(value), index(index)
  19. {}
  20. settings_key_t(const String& value, unsigned char index) :
  21. value(value), index(index)
  22. {}
  23. settings_key_t(const char* value) :
  24. value(value), index(-1)
  25. {}
  26. settings_key_t(const String& value) :
  27. value(value), index(-1)
  28. {}
  29. settings_key_t(const __FlashStringHelper* value) :
  30. value(value), index(-1)
  31. {}
  32. settings_key_t() :
  33. value(), index(-1)
  34. {}
  35. bool match(const char* _value) const {
  36. return (value == _value) || (toString() == _value);
  37. }
  38. bool match(const String& _value) const {
  39. return (value == _value) || (toString() == _value);
  40. }
  41. String toString() const;
  42. explicit operator String () const {
  43. return toString();
  44. }
  45. private:
  46. const String value;
  47. int index;
  48. };
  49. using settings_move_key_t = std::pair<settings_key_t, settings_key_t>;
  50. using settings_filter_t = std::function<String(String& value)>;
  51. // --------------------------------------------------------------------------
  52. struct settings_cfg_t {
  53. String& setting;
  54. const char* key;
  55. const char* default_value;
  56. };
  57. using settings_cfg_list_t = std::initializer_list<settings_cfg_t>;
  58. // --------------------------------------------------------------------------
  59. namespace settings {
  60. namespace internal {
  61. uint32_t u32fromString(const String& string, int base);
  62. template <typename T>
  63. using convert_t = T(*)(const String& value);
  64. template <typename T>
  65. T convert(const String& value);
  66. // --------------------------------------------------------------------------
  67. template <>
  68. float convert(const String& value);
  69. template <>
  70. double convert(const String& value);
  71. template <>
  72. int convert(const String& value);
  73. template <>
  74. long convert(const String& value);
  75. template <>
  76. bool convert(const String& value);
  77. template <>
  78. unsigned long convert(const String& value);
  79. template <>
  80. unsigned int convert(const String& value);
  81. template <>
  82. unsigned short convert(const String& value);
  83. template <>
  84. unsigned char convert(const String& value);
  85. template<typename T>
  86. String serialize(const T& value);
  87. template<typename T>
  88. String serialize(const T& value) {
  89. return String(value);
  90. }
  91. } // namespace settings::internal
  92. } // namespace settings
  93. // --------------------------------------------------------------------------
  94. struct settings_key_match_t {
  95. using match_f = bool(*)(const char* key);
  96. using key_f = const String(*)(const String& key);
  97. match_f match;
  98. key_f key;
  99. };
  100. void settingsRegisterDefaults(const settings_key_match_t& matcher);
  101. String settingsQueryDefaults(const String& key);
  102. // --------------------------------------------------------------------------
  103. void moveSetting(const String& from, const String& to);
  104. void moveSetting(const String& from, const String& to, unsigned int index);
  105. void moveSettings(const String& from, const String& to);
  106. template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert>
  107. R getSetting(const settings_key_t& key, R defaultValue) __attribute__((noinline));
  108. template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert>
  109. R getSetting(const settings_key_t& key, R defaultValue) {
  110. String value;
  111. if (!Embedis::get(key.toString(), value)) {
  112. return defaultValue;
  113. }
  114. return Rfunc(value);
  115. }
  116. template<>
  117. String getSetting(const settings_key_t& key, String defaultValue);
  118. String getSetting(const settings_key_t& key);
  119. String getSetting(const settings_key_t& key, const char* defaultValue);
  120. String getSetting(const settings_key_t& key, const __FlashStringHelper* defaultValue);
  121. template<typename T>
  122. bool setSetting(const settings_key_t& key, const T& value) {
  123. return Embedis::set(key.toString(), String(value));
  124. }
  125. template<>
  126. bool setSetting(const settings_key_t& key, const String& value);
  127. bool delSetting(const settings_key_t& key);
  128. bool hasSetting(const settings_key_t& key);
  129. void saveSettings();
  130. void resetSettings();
  131. void settingsGetJson(JsonObject& data);
  132. bool settingsRestoreJson(char* json_string, size_t json_buffer_size = 1024);
  133. bool settingsRestoreJson(JsonObject& data);
  134. size_t settingsKeyCount();
  135. String settingsKeyName(unsigned int index);
  136. std::vector<String> settingsKeys();
  137. void settingsProcessConfig(const settings_cfg_list_t& config, settings_filter_t filter = nullptr);
  138. unsigned long settingsSize();
  139. void migrate();
  140. void settingsSetup();
  141. // -----------------------------------------------------------------------------
  142. // Deprecated implementation
  143. // -----------------------------------------------------------------------------
  144. template <typename T>
  145. String getSetting(const String& key, unsigned char index, T defaultValue)
  146. __attribute__((deprecated("getSetting({key, index}, default) should be used instead")));
  147. template<typename T>
  148. bool setSetting(const String& key, unsigned char index, T value)
  149. __attribute__((deprecated("setSetting({key, index}, value) should be used instead")));
  150. template<typename T>
  151. bool hasSetting(const String& key, unsigned char index)
  152. __attribute__((deprecated("hasSetting({key, index}) should be used instead")));
  153. template<typename T>
  154. bool delSetting(const String& key, unsigned char index)
  155. __attribute__((deprecated("delSetting({key, index}) should be used instead")));
  156. // --------------------------------------------------------------------------
  157. template<typename T>
  158. String getSetting(const String& key, unsigned char index, T defaultValue) {
  159. return getSetting({key, index}, defaultValue);
  160. }
  161. template<typename T>
  162. bool setSetting(const String& key, unsigned char index, T value) {
  163. return setSetting({key, index}, value);
  164. }
  165. template<typename T>
  166. bool hasSetting(const String& key, unsigned char index) {
  167. return hasSetting({key, index});
  168. }
  169. template<typename T>
  170. bool delSetting(const String& key, unsigned char index) {
  171. return delSetting({key, index});
  172. }