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.

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