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.

436 lines
15 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
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
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. // PZEM004T based power monitor
  3. // Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. // -----------------------------------------------------------------------------
  5. // Connection Diagram:
  6. // -------------------
  7. //
  8. // Needed when connecting multiple PZEM004T devices on the same UART
  9. // *You must set the PZEM004T device address prior using this configuration*
  10. //
  11. // +---------+
  12. // | ESPurna | +VCC
  13. // | Node | ^
  14. // | G T R | |
  15. // +-+--+--+-+ R (10K)
  16. // | | | |
  17. // | | +-----------------+---------------+---------------+
  18. // | +-----------------+--|------------+--|------------+ |
  19. // +-----------------+--|--|---------+--|--|---------+ | |
  20. // | | | | | | | | |
  21. // | | V | | V | | V
  22. // | | - | | - | | -
  23. // +-+--+--+-+ +-+--+--+-+ +-+--+--+-+
  24. // | G R T | | G R T | | G R T |
  25. // |PZEM-004T| |PZEM-004T| |PZEM-004T|
  26. // | Module | | Module | | Module |
  27. // +---------+ +---------+ +---------+
  28. //
  29. // Where:
  30. // ------
  31. // G = GND
  32. // R = ESPurna UART RX
  33. // T = ESPurna UART TX
  34. // V = Small Signal Schottky Diode, like BAT43,
  35. // Cathode to PZEM TX, Anode to Espurna RX
  36. // R = Resistor to VCC, 10K
  37. //
  38. // More Info:
  39. // ----------
  40. // See ESPurna Wiki - https://github.com/xoseperez/espurna/wiki/Sensor-PZEM004T
  41. //
  42. // Reference:
  43. // ----------
  44. // UART/TTL-Serial network with single master and multiple slaves:
  45. // http://cool-emerald.blogspot.com/2009/10/multidrop-network-for-rs232.html
  46. #if SENSOR_SUPPORT && PZEM004T_SUPPORT
  47. #pragma once
  48. #include <Arduino.h>
  49. #include <PZEM004T.h>
  50. #include "BaseSensor.h"
  51. #include "BaseEmonSensor.h"
  52. #include "../sensor.h"
  53. #include "../terminal.h"
  54. #define PZ_MAGNITUDE_COUNT 4
  55. #define PZ_MAGNITUDE_CURRENT_INDEX 0
  56. #define PZ_MAGNITUDE_VOLTAGE_INDEX 1
  57. #define PZ_MAGNITUDE_POWER_ACTIVE_INDEX 2
  58. #define PZ_MAGNITUDE_ENERGY_INDEX 3
  59. class PZEM004TSensor : public BaseEmonSensor {
  60. private:
  61. // We can only create a single instance of the sensor class.
  62. PZEM004TSensor() : BaseEmonSensor(0) {
  63. _sensor_id = SENSOR_PZEM004T_ID;
  64. }
  65. ~PZEM004TSensor() {
  66. if (_pzem) delete _pzem;
  67. PZEM004TSensor::instance = nullptr;
  68. }
  69. public:
  70. static PZEM004TSensor* instance;
  71. static PZEM004TSensor* create() {
  72. if (PZEM004TSensor::instance) return PZEM004TSensor::instance;
  73. PZEM004TSensor::instance = new PZEM004TSensor();
  74. return PZEM004TSensor::instance;
  75. }
  76. // ---------------------------------------------------------------------
  77. // We can't modify PZEM values, just ignore this
  78. void resetEnergy() override {}
  79. void resetEnergy(unsigned char) override {}
  80. void resetEnergy(unsigned char, sensor::Energy) override {}
  81. // Override Base methods that deal with _energy[]
  82. size_t countDevices() override {
  83. return _addresses.size();
  84. }
  85. double getEnergy(unsigned char index) override {
  86. return _readings[index].energy;
  87. }
  88. sensor::Energy totalEnergy(unsigned char index) override {
  89. return getEnergy(index);
  90. }
  91. // ---------------------------------------------------------------------
  92. void setRX(unsigned char pin_rx) {
  93. if (_pin_rx == pin_rx) return;
  94. _pin_rx = pin_rx;
  95. _dirty = true;
  96. }
  97. void setTX(unsigned char pin_tx) {
  98. if (_pin_tx == pin_tx) return;
  99. _pin_tx = pin_tx;
  100. _dirty = true;
  101. }
  102. void setSerial(HardwareSerial * serial) {
  103. _serial = serial;
  104. _dirty = true;
  105. }
  106. // Set the devices physical addresses managed by this sensor
  107. void setAddresses(const char *addresses) {
  108. char const * sep = " ";
  109. char tokens[strlen(addresses) + 1];
  110. strlcpy(tokens, addresses, sizeof(tokens));
  111. char *address = tokens;
  112. int i = 0;
  113. address = strtok(address, sep);
  114. while (address != 0 && i++ < PZEM004T_MAX_DEVICES) {
  115. IPAddress addr;
  116. reading_t reading;
  117. reading.current = PZEM_ERROR_VALUE;
  118. reading.voltage = PZEM_ERROR_VALUE;
  119. reading.power = PZEM_ERROR_VALUE;
  120. reading.energy = PZEM_ERROR_VALUE;
  121. if (addr.fromString(address)) {
  122. _addresses.push_back(addr);
  123. _readings.push_back(reading);
  124. }
  125. address = strtok(0, sep);
  126. }
  127. _count = _addresses.size() * PZ_MAGNITUDE_COUNT;
  128. _dirty = true;
  129. }
  130. // Get device physical address based on the device index
  131. String getAddress(unsigned char dev) {
  132. return _addresses[dev].toString();
  133. }
  134. // Set the device physical address
  135. bool setDeviceAddress(IPAddress *addr) {
  136. while(_busy) { yield(); };
  137. _busy = true;
  138. bool res = _pzem->setAddress(*addr);
  139. _busy = false;
  140. return res;
  141. }
  142. // ---------------------------------------------------------------------
  143. unsigned char getRX() {
  144. return _pin_rx;
  145. }
  146. unsigned char getTX() {
  147. return _pin_tx;
  148. }
  149. // ---------------------------------------------------------------------
  150. // Sensor API
  151. // ---------------------------------------------------------------------
  152. // Initialization method, must be idempotent
  153. void begin() {
  154. if (!_dirty) return;
  155. if (_pzem) delete _pzem;
  156. if (_serial) {
  157. _pzem = new PZEM004T(_serial);
  158. if ((_pin_tx == 15) && (_pin_rx == 13)) {
  159. _serial->flush();
  160. _serial->swap();
  161. }
  162. } else {
  163. _pzem = new PZEM004T(_pin_rx, _pin_tx);
  164. }
  165. if(_addresses.size() == 1) _pzem->setAddress(_addresses[0]);
  166. _ready = true;
  167. _dirty = false;
  168. }
  169. // Descriptive name of the sensor
  170. String description() {
  171. char buffer[27];
  172. if (_serial) {
  173. snprintf(buffer, sizeof(buffer), "PZEM004T @ HwSerial");
  174. } else {
  175. snprintf(buffer, sizeof(buffer), "PZEM004T @ SwSerial(%u,%u)", _pin_rx, _pin_tx);
  176. }
  177. return String(buffer);
  178. }
  179. // Descriptive name of the slot # index
  180. String description(unsigned char index) {
  181. auto dev = local(index);
  182. char buffer[25];
  183. snprintf(buffer, sizeof(buffer), "(%u/%s)", dev, getAddress(dev).c_str());
  184. return description() + String(buffer);
  185. };
  186. // Address of the sensor (it could be the GPIO or I2C address)
  187. String address(unsigned char index) {
  188. return _addresses[local(index)].toString();
  189. }
  190. // Convert slot # to a magnitude #
  191. unsigned char local(unsigned char index) override {
  192. return index / PZ_MAGNITUDE_COUNT;
  193. }
  194. // Type for slot # index
  195. unsigned char type(unsigned char index) {
  196. index = index - (local(index) * PZ_MAGNITUDE_COUNT);
  197. if (index == PZ_MAGNITUDE_CURRENT_INDEX) return MAGNITUDE_CURRENT;
  198. if (index == PZ_MAGNITUDE_VOLTAGE_INDEX) return MAGNITUDE_VOLTAGE;
  199. if (index == PZ_MAGNITUDE_POWER_ACTIVE_INDEX) return MAGNITUDE_POWER_ACTIVE;
  200. if (index == PZ_MAGNITUDE_ENERGY_INDEX) return MAGNITUDE_ENERGY;
  201. return MAGNITUDE_NONE;
  202. }
  203. // Current value for slot # index
  204. double value(unsigned char index) {
  205. double response = 0.0;
  206. int dev = index / PZ_MAGNITUDE_COUNT;
  207. index = index - (dev * PZ_MAGNITUDE_COUNT);
  208. switch (index) {
  209. case PZ_MAGNITUDE_CURRENT_INDEX:
  210. response = _readings[dev].current;
  211. break;
  212. case PZ_MAGNITUDE_VOLTAGE_INDEX:
  213. response = _readings[dev].voltage;
  214. break;
  215. case PZ_MAGNITUDE_POWER_ACTIVE_INDEX:
  216. response = _readings[dev].power;
  217. break;
  218. case PZ_MAGNITUDE_ENERGY_INDEX: {
  219. response = _readings[dev].energy;
  220. break;
  221. }
  222. default:
  223. break;
  224. }
  225. if (response < 0.0) {
  226. response = 0.0;
  227. }
  228. return response;
  229. }
  230. // Post-read hook (usually to reset things)
  231. void post() {
  232. _error = SENSOR_ERROR_OK;
  233. }
  234. // Loop-like method, call it in your main loop
  235. void tick() {
  236. static unsigned char dev = 0;
  237. static unsigned char magnitude = 0;
  238. static unsigned long last_millis = 0;
  239. if (_busy || millis() - last_millis < PZEM004T_READ_INTERVAL) return;
  240. _busy = true;
  241. // Clear buffer in case of late response(Timeout)
  242. if (_serial) {
  243. while(_serial->available() > 0) _serial->read();
  244. } else {
  245. // This we cannot do it from outside the library
  246. }
  247. tickStoreReading(dev, magnitude);
  248. if(++dev == _addresses.size()) {
  249. dev = 0;
  250. last_millis = millis();
  251. if(++magnitude == PZ_MAGNITUDE_COUNT) {
  252. magnitude = 0;
  253. }
  254. }
  255. _busy = false;
  256. }
  257. protected:
  258. // ---------------------------------------------------------------------
  259. // Protected
  260. // ---------------------------------------------------------------------
  261. void tickStoreReading(unsigned char dev, unsigned char magnitude) {
  262. float read = PZEM_ERROR_VALUE;
  263. float* readings_p = nullptr;
  264. switch (magnitude) {
  265. case PZ_MAGNITUDE_CURRENT_INDEX:
  266. read = _pzem->current(_addresses[dev]);
  267. readings_p = &_readings[dev].current;
  268. break;
  269. case PZ_MAGNITUDE_VOLTAGE_INDEX:
  270. read = _pzem->voltage(_addresses[dev]);
  271. readings_p = &_readings[dev].voltage;
  272. break;
  273. case PZ_MAGNITUDE_POWER_ACTIVE_INDEX:
  274. read = _pzem->power(_addresses[dev]);
  275. readings_p = &_readings[dev].power;
  276. break;
  277. case PZ_MAGNITUDE_ENERGY_INDEX:
  278. read = _pzem->energy(_addresses[dev]);
  279. readings_p = &_readings[dev].energy;
  280. break;
  281. default:
  282. _busy = false;
  283. return;
  284. }
  285. if (read == PZEM_ERROR_VALUE) {
  286. _error = SENSOR_ERROR_TIMEOUT;
  287. } else {
  288. *readings_p = read;
  289. }
  290. }
  291. struct reading_t {
  292. float voltage;
  293. float current;
  294. float power;
  295. float energy;
  296. };
  297. unsigned int _pin_rx = PZEM004T_RX_PIN;
  298. unsigned int _pin_tx = PZEM004T_TX_PIN;
  299. bool _busy = false;
  300. std::vector<reading_t> _readings;
  301. std::vector<IPAddress> _addresses;
  302. HardwareSerial * _serial = NULL;
  303. PZEM004T * _pzem = NULL;
  304. };
  305. PZEM004TSensor* PZEM004TSensor::instance = nullptr;
  306. #if TERMINAL_SUPPORT
  307. void pzem004tInitCommands() {
  308. terminalRegisterCommand(F("PZ.ADDRESS"), [](const terminal::CommandContext& ctx) {
  309. if (!PZEM004TSensor::instance) return;
  310. if (ctx.argc == 1) {
  311. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  312. unsigned char dev_count = PZEM004TSensor::instance->countDevices();
  313. for(unsigned char dev = 0; dev < dev_count; dev++) {
  314. DEBUG_MSG_P(PSTR("Device %d/%s\n"), dev, PZEM004TSensor::instance->getAddress(dev).c_str());
  315. }
  316. terminalOK();
  317. } else if(ctx.argc == 2) {
  318. IPAddress addr;
  319. if (addr.fromString(ctx.argv[1])) {
  320. if(PZEM004TSensor::instance->setDeviceAddress(&addr)) {
  321. terminalOK();
  322. }
  323. } else {
  324. terminalError(F("Invalid address argument"));
  325. }
  326. } else {
  327. terminalError(F("Wrong arguments"));
  328. }
  329. });
  330. terminalRegisterCommand(F("PZ.RESET"), [](const terminal::CommandContext& ctx) {
  331. if(ctx.argc > 2) {
  332. terminalError(F("Wrong arguments"));
  333. } else {
  334. unsigned char init = ctx.argc == 2 ? ctx.argv[1].toInt() : 0;
  335. unsigned char limit = ctx.argc == 2 ? init +1 : PZEM004TSensor::instance->countDevices();
  336. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  337. for(unsigned char dev = init; dev < limit; dev++) {
  338. PZEM004TSensor::instance->resetEnergy(dev);
  339. }
  340. terminalOK();
  341. }
  342. });
  343. terminalRegisterCommand(F("PZ.VALUE"), [](const terminal::CommandContext& ctx) {
  344. if(ctx.argc > 2) {
  345. terminalError(F("Wrong arguments"));
  346. } else {
  347. unsigned char init = ctx.argc == 2 ? ctx.argv[1].toInt() : 0;
  348. unsigned char limit = ctx.argc == 2 ? init +1 : PZEM004TSensor::instance->countDevices();
  349. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  350. for(unsigned char dev = init; dev < limit; dev++) {
  351. DEBUG_MSG_P(PSTR("Device %d/%s - Current: %s Voltage: %s Power: %s Energy: %s\n"), //
  352. dev,
  353. PZEM004TSensor::instance->getAddress(dev).c_str(),
  354. String(PZEM004TSensor::instance->value(dev * PZ_MAGNITUDE_CURRENT_INDEX)).c_str(),
  355. String(PZEM004TSensor::instance->value(dev * PZ_MAGNITUDE_VOLTAGE_INDEX)).c_str(),
  356. String(PZEM004TSensor::instance->value(dev * PZ_MAGNITUDE_POWER_ACTIVE_INDEX)).c_str(),
  357. String(PZEM004TSensor::instance->value(dev * PZ_MAGNITUDE_ENERGY_INDEX)).c_str());
  358. }
  359. terminalOK();
  360. }
  361. });
  362. }
  363. #endif // TERMINAL_SUPPORT == 1
  364. #endif // SENSOR_SUPPORT && PZEM004T_SUPPORT