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.

2156 lines
69 KiB

7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
  1. /*
  2. SENSOR MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if SENSOR_SUPPORT
  6. #include <vector>
  7. #include <float.h>
  8. #include "broker.h"
  9. #include "mqtt.h"
  10. #include "relay.h"
  11. #include "terminal.h"
  12. #include "ws.h"
  13. //--------------------------------------------------------------------------------
  14. PROGMEM const unsigned char magnitude_decimals[] = {
  15. 0,
  16. 1, 0, 2, // THP
  17. 3, 0, 0, 0, 0, 0, 0, 0, // Power decimals
  18. 0, 0, 0, // analog, digital, event
  19. 0, 0, 0, // PM
  20. 0, 0,
  21. 0, 0, 3, // UVA, UVB, UVI
  22. 3, 0,
  23. 4, 4, // Geiger Counter decimals
  24. 0,
  25. 0, 0, 0, 3 // NO2, CO, Ohms, pH
  26. };
  27. PROGMEM const char magnitude_unknown_topic[] = "unknown";
  28. PROGMEM const char magnitude_temperature_topic[] = "temperature";
  29. PROGMEM const char magnitude_humidity_topic[] = "humidity";
  30. PROGMEM const char magnitude_pressure_topic[] = "pressure";
  31. PROGMEM const char magnitude_current_topic[] = "current";
  32. PROGMEM const char magnitude_voltage_topic[] = "voltage";
  33. PROGMEM const char magnitude_active_power_topic[] = "power";
  34. PROGMEM const char magnitude_apparent_power_topic[] = "apparent";
  35. PROGMEM const char magnitude_reactive_power_topic[] = "reactive";
  36. PROGMEM const char magnitude_power_factor_topic[] = "factor";
  37. PROGMEM const char magnitude_energy_topic[] = "energy";
  38. PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta";
  39. PROGMEM const char magnitude_analog_topic[] = "analog";
  40. PROGMEM const char magnitude_digital_topic[] = "digital";
  41. PROGMEM const char magnitude_event_topic[] = "event";
  42. PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0";
  43. PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5";
  44. PROGMEM const char magnitude_pm10_topic[] = "pm10";
  45. PROGMEM const char magnitude_co2_topic[] = "co2";
  46. PROGMEM const char magnitude_lux_topic[] = "lux";
  47. PROGMEM const char magnitude_uva_topic[] = "uva";
  48. PROGMEM const char magnitude_uvb_topic[] = "uvb";
  49. PROGMEM const char magnitude_uvi_topic[] = "uvi";
  50. PROGMEM const char magnitude_distance_topic[] = "distance";
  51. PROGMEM const char magnitude_hcho_topic[] = "hcho";
  52. PROGMEM const char magnitude_geiger_cpm_topic[] = "ldr_cpm"; // local dose rate [Counts per minute]
  53. PROGMEM const char magnitude_geiger_sv_topic[] = "ldr_uSvh"; // local dose rate [µSievert per hour]
  54. PROGMEM const char magnitude_count_topic[] = "count";
  55. PROGMEM const char magnitude_no2_topic[] = "no2";
  56. PROGMEM const char magnitude_co_topic[] = "co";
  57. PROGMEM const char magnitude_resistance_topic[] = "resistance";
  58. PROGMEM const char magnitude_ph_topic[] = "ph";
  59. PROGMEM const char* const magnitude_topics[] = {
  60. magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic,
  61. magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_topic,
  62. magnitude_active_power_topic, magnitude_apparent_power_topic, magnitude_reactive_power_topic,
  63. magnitude_power_factor_topic, magnitude_energy_topic, magnitude_energy_delta_topic,
  64. magnitude_analog_topic, magnitude_digital_topic, magnitude_event_topic,
  65. magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic,
  66. magnitude_co2_topic, magnitude_lux_topic,
  67. magnitude_uva_topic, magnitude_uvb_topic, magnitude_uvi_topic,
  68. magnitude_distance_topic, magnitude_hcho_topic,
  69. magnitude_geiger_cpm_topic, magnitude_geiger_sv_topic,
  70. magnitude_count_topic,
  71. magnitude_no2_topic, magnitude_co_topic, magnitude_resistance_topic, magnitude_ph_topic
  72. };
  73. PROGMEM const char magnitude_empty[] = "";
  74. PROGMEM const char magnitude_celsius[] = "°C";
  75. PROGMEM const char magnitude_fahrenheit[] = "°F";
  76. PROGMEM const char magnitude_percentage[] = "%";
  77. PROGMEM const char magnitude_hectopascals[] = "hPa";
  78. PROGMEM const char magnitude_amperes[] = "A";
  79. PROGMEM const char magnitude_volts[] = "V";
  80. PROGMEM const char magnitude_watts[] = "W";
  81. PROGMEM const char magnitude_kw[] = "kW";
  82. PROGMEM const char magnitude_VA[] = "VA";
  83. PROGMEM const char magnitude_kVA[] = "kVA";
  84. PROGMEM const char magnitude_VAR[] = "VAR";
  85. PROGMEM const char magnitude_kVAR[] = "kVAR";
  86. PROGMEM const char magnitude_joules[] = "J";
  87. PROGMEM const char magnitude_kwh[] = "kWh";
  88. PROGMEM const char magnitude_ugm3[] = "µg/m³";
  89. PROGMEM const char magnitude_ppm[] = "ppm";
  90. PROGMEM const char magnitude_lux[] = "lux";
  91. PROGMEM const char magnitude_distance[] = "m";
  92. PROGMEM const char magnitude_mgm3[] = "mg/m³";
  93. PROGMEM const char magnitude_geiger_cpm[] = "cpm"; // Counts per Minute: Unit of local dose rate (Geiger counting)
  94. PROGMEM const char magnitude_geiger_sv[] = "µSv/h"; // µSievert per hour: 2nd unit of local dose rate (Geiger counting)
  95. PROGMEM const char magnitude_resistance[] = "ohm";
  96. PROGMEM const char* const magnitude_units[] = {
  97. magnitude_empty, magnitude_celsius, magnitude_percentage,
  98. magnitude_hectopascals, magnitude_amperes, magnitude_volts,
  99. magnitude_watts, magnitude_VA, magnitude_VAR,
  100. magnitude_percentage, magnitude_joules, magnitude_joules,
  101. magnitude_empty, magnitude_empty, magnitude_empty,
  102. magnitude_ugm3, magnitude_ugm3, magnitude_ugm3,
  103. magnitude_ppm, magnitude_lux,
  104. magnitude_empty, magnitude_empty, magnitude_empty,
  105. magnitude_distance, magnitude_mgm3,
  106. magnitude_geiger_cpm, magnitude_geiger_sv, // Geiger counter units
  107. magnitude_empty, //
  108. magnitude_ppm, magnitude_ppm, // NO2 & CO2
  109. magnitude_resistance,
  110. magnitude_empty // pH
  111. };
  112. //--------------------------------------------------------------------------------
  113. #include "filters/LastFilter.h"
  114. #include "filters/MaxFilter.h"
  115. #include "filters/MedianFilter.h"
  116. #include "filters/MovingAverageFilter.h"
  117. #include "sensors/BaseSensor.h"
  118. #if AM2320_SUPPORT
  119. #include "sensors/AM2320Sensor.h"
  120. #endif
  121. #if ANALOG_SUPPORT
  122. #include "sensors/AnalogSensor.h"
  123. #endif
  124. #if BH1750_SUPPORT
  125. #include "sensors/BH1750Sensor.h"
  126. #endif
  127. #if BMP180_SUPPORT
  128. #include "sensors/BMP180Sensor.h"
  129. #endif
  130. #if BMX280_SUPPORT
  131. #include "sensors/BMX280Sensor.h"
  132. #endif
  133. #if CSE7766_SUPPORT
  134. #include "sensors/CSE7766Sensor.h"
  135. #endif
  136. #if DALLAS_SUPPORT
  137. #include "sensors/DallasSensor.h"
  138. #endif
  139. #if DHT_SUPPORT
  140. #include "sensors/DHTSensor.h"
  141. #endif
  142. #if DIGITAL_SUPPORT
  143. #include "sensors/DigitalSensor.h"
  144. #endif
  145. #if ECH1560_SUPPORT
  146. #include "sensors/ECH1560Sensor.h"
  147. #endif
  148. #if EMON_ADC121_SUPPORT
  149. #include "sensors/EmonADC121Sensor.h"
  150. #endif
  151. #if EMON_ADS1X15_SUPPORT
  152. #include "sensors/EmonADS1X15Sensor.h"
  153. #endif
  154. #if EMON_ANALOG_SUPPORT
  155. #include "sensors/EmonAnalogSensor.h"
  156. #endif
  157. #if EVENTS_SUPPORT
  158. #include "sensors/EventSensor.h"
  159. #endif
  160. #if EZOPH_SUPPORT
  161. #include "sensors/EZOPHSensor.h"
  162. #endif
  163. #if GEIGER_SUPPORT
  164. #include "sensors/GeigerSensor.h"
  165. #endif
  166. #if GUVAS12SD_SUPPORT
  167. #include "sensors/GUVAS12SDSensor.h"
  168. #endif
  169. #if HLW8012_SUPPORT
  170. #include "sensors/HLW8012Sensor.h"
  171. #endif
  172. #if LDR_SUPPORT
  173. #include "sensors/LDRSensor.h"
  174. #endif
  175. #if MAX6675_SUPPORT
  176. #include "sensors/MAX6675Sensor.h"
  177. #endif
  178. #if MICS2710_SUPPORT
  179. #include "sensors/MICS2710Sensor.h"
  180. #endif
  181. #if MICS5525_SUPPORT
  182. #include "sensors/MICS5525Sensor.h"
  183. #endif
  184. #if MHZ19_SUPPORT
  185. #include "sensors/MHZ19Sensor.h"
  186. #endif
  187. #if NTC_SUPPORT
  188. #include "sensors/NTCSensor.h"
  189. #endif
  190. #if SDS011_SUPPORT
  191. #include "sensors/SDS011Sensor.h"
  192. #endif
  193. #if SENSEAIR_SUPPORT
  194. #include "sensors/SenseAirSensor.h"
  195. #endif
  196. #if PMSX003_SUPPORT
  197. #include "sensors/PMSX003Sensor.h"
  198. #endif
  199. #if PULSEMETER_SUPPORT
  200. #include "sensors/PulseMeterSensor.h"
  201. #endif
  202. #if PZEM004T_SUPPORT
  203. #include "sensors/PZEM004TSensor.h"
  204. #endif
  205. #if SHT3X_I2C_SUPPORT
  206. #include "sensors/SHT3XI2CSensor.h"
  207. #endif
  208. #if SI7021_SUPPORT
  209. #include "sensors/SI7021Sensor.h"
  210. #endif
  211. #if SONAR_SUPPORT
  212. #include "sensors/SonarSensor.h"
  213. #endif
  214. #if T6613_SUPPORT
  215. #include "sensors/T6613Sensor.h"
  216. #endif
  217. #if TMP3X_SUPPORT
  218. #include "sensors/TMP3XSensor.h"
  219. #endif
  220. #if V9261F_SUPPORT
  221. #include "sensors/V9261FSensor.h"
  222. #endif
  223. #if VEML6075_SUPPORT
  224. #include "sensors/VEML6075Sensor.h"
  225. #endif
  226. #if VL53L1X_SUPPORT
  227. #include "sensors/VL53L1XSensor.h"
  228. #endif
  229. #if ADE7953_SUPPORT
  230. #include "sensors/ADE7953Sensor.h"
  231. #endif
  232. //--------------------------------------------------------------------------------
  233. struct sensor_magnitude_t {
  234. BaseSensor * sensor; // Sensor object
  235. BaseFilter * filter; // Filter object
  236. unsigned char local; // Local index in its provider
  237. unsigned char type; // Type of measurement
  238. unsigned char decimals; // Number of decimals in textual representation
  239. unsigned char global; // Global index in its type
  240. double last; // Last raw value from sensor (unfiltered)
  241. double reported; // Last reported value
  242. double min_change; // Minimum value change to report
  243. double max_change; // Maximum value change to report
  244. };
  245. std::vector<BaseSensor *> _sensors;
  246. std::vector<sensor_magnitude_t> _magnitudes;
  247. bool _sensors_ready = false;
  248. unsigned char _counts[MAGNITUDE_MAX];
  249. bool _sensor_realtime = API_REAL_TIME_VALUES;
  250. unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL;
  251. unsigned char _sensor_report_every = SENSOR_REPORT_EVERY;
  252. unsigned char _sensor_save_every = SENSOR_SAVE_EVERY;
  253. unsigned char _sensor_power_units = SENSOR_POWER_UNITS;
  254. unsigned char _sensor_energy_units = SENSOR_ENERGY_UNITS;
  255. unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS;
  256. double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
  257. double _sensor_humidity_correction = SENSOR_HUMIDITY_CORRECTION;
  258. double _sensor_lux_correction = SENSOR_LUX_CORRECTION;
  259. #if PZEM004T_SUPPORT
  260. PZEM004TSensor *pzem004t_sensor;
  261. #endif
  262. String _sensor_energy_reset_ts = String();
  263. // -----------------------------------------------------------------------------
  264. // Private
  265. // -----------------------------------------------------------------------------
  266. unsigned char _magnitudeDecimals(unsigned char type) {
  267. // Hardcoded decimals (these should be linked to the unit, instead of the magnitude)
  268. if (type == MAGNITUDE_ANALOG) return ANALOG_DECIMALS;
  269. if (type == MAGNITUDE_ENERGY ||
  270. type == MAGNITUDE_ENERGY_DELTA) {
  271. _sensor_energy_units = getSetting("eneUnits", (unsigned char)SENSOR_ENERGY_UNITS);
  272. if (_sensor_energy_units == ENERGY_KWH) return 3;
  273. }
  274. if (type == MAGNITUDE_POWER_ACTIVE ||
  275. type == MAGNITUDE_POWER_APPARENT ||
  276. type == MAGNITUDE_POWER_REACTIVE) {
  277. if (_sensor_power_units == POWER_KILOWATTS) return 3;
  278. }
  279. if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type);
  280. return 0;
  281. }
  282. double _magnitudeProcess(unsigned char type, unsigned char decimals, double value) {
  283. // Hardcoded conversions (these should be linked to the unit, instead of the magnitude)
  284. if (type == MAGNITUDE_TEMPERATURE) {
  285. if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32;
  286. value = value + _sensor_temperature_correction;
  287. }
  288. if (type == MAGNITUDE_HUMIDITY) {
  289. value = constrain(value + _sensor_humidity_correction, 0, 100);
  290. }
  291. if (type == MAGNITUDE_LUX) {
  292. value = value + _sensor_lux_correction;
  293. }
  294. if (type == MAGNITUDE_ENERGY ||
  295. type == MAGNITUDE_ENERGY_DELTA) {
  296. if (_sensor_energy_units == ENERGY_KWH) value = value / 3600000;
  297. }
  298. if (type == MAGNITUDE_POWER_ACTIVE ||
  299. type == MAGNITUDE_POWER_APPARENT ||
  300. type == MAGNITUDE_POWER_REACTIVE) {
  301. if (_sensor_power_units == POWER_KILOWATTS) value = value / 1000;
  302. }
  303. return roundTo(value, decimals);
  304. }
  305. // -----------------------------------------------------------------------------
  306. #if WEB_SUPPORT
  307. //void _sensorWebSocketMagnitudes(JsonObject& root, const String& ws_name, const String& conf_name) {
  308. template<typename T> void _sensorWebSocketMagnitudes(JsonObject& root, T prefix) {
  309. // ws produces flat list <prefix>Magnitudes
  310. const String ws_name = String(prefix) + "Magnitudes";
  311. // config uses <prefix>Magnitude<index> (cut 's')
  312. const String conf_name = ws_name.substring(0, ws_name.length() - 1);
  313. JsonObject& list = root.createNestedObject(ws_name);
  314. list["size"] = magnitudeCount();
  315. //JsonArray& name = list.createNestedArray("name");
  316. JsonArray& type = list.createNestedArray("type");
  317. JsonArray& index = list.createNestedArray("index");
  318. JsonArray& idx = list.createNestedArray("idx");
  319. for (unsigned char i=0; i<magnitudeCount(); ++i) {
  320. //name.add(magnitudeName(i));
  321. type.add(magnitudeType(i));
  322. index.add(magnitudeIndex(i));
  323. idx.add(getSetting({conf_name, i}, 0));
  324. }
  325. }
  326. /*
  327. template<typename T> void _sensorWebSocketMagnitudes(JsonObject& root, T prefix) {
  328. // ws produces flat list <prefix>Magnitudes
  329. const String ws_name = String(prefix) + "Magnitudes";
  330. // config uses <prefix>Magnitude<index> (cut 's')
  331. const String conf_name = ws_name.substring(0, ws_name.length() - 1);
  332. _sensorWebSocketMagnitudes(root, ws_name, conf_name);
  333. }
  334. */
  335. bool _sensorWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  336. if (strncmp(key, "pwr", 3) == 0) return true;
  337. if (strncmp(key, "sns", 3) == 0) return true;
  338. if (strncmp(key, "tmp", 3) == 0) return true;
  339. if (strncmp(key, "hum", 3) == 0) return true;
  340. if (strncmp(key, "ene", 3) == 0) return true;
  341. if (strncmp(key, "lux", 3) == 0) return true;
  342. return false;
  343. }
  344. void _sensorWebSocketOnVisible(JsonObject& root) {
  345. root["snsVisible"] = 1;
  346. for (auto& magnitude : _magnitudes) {
  347. if (magnitude.type == MAGNITUDE_TEMPERATURE) root["temperatureVisible"] = 1;
  348. if (magnitude.type == MAGNITUDE_HUMIDITY) root["humidityVisible"] = 1;
  349. #if MICS2710_SUPPORT || MICS5525_SUPPORT
  350. if (magnitude.type == MAGNITUDE_CO || magnitude.type == MAGNITUDE_NO2) root["micsVisible"] = 1;
  351. #endif
  352. }
  353. }
  354. void _sensorWebSocketMagnitudesConfig(JsonObject& root) {
  355. JsonObject& magnitudes = root.createNestedObject("magnitudesConfig");
  356. uint8_t size = 0;
  357. JsonArray& index = magnitudes.createNestedArray("index");
  358. JsonArray& type = magnitudes.createNestedArray("type");
  359. JsonArray& units = magnitudes.createNestedArray("units");
  360. JsonArray& description = magnitudes.createNestedArray("description");
  361. for (unsigned char i=0; i<magnitudeCount(); i++) {
  362. sensor_magnitude_t magnitude = _magnitudes[i];
  363. if (magnitude.type == MAGNITUDE_EVENT) continue;
  364. ++size;
  365. index.add<uint8_t>(magnitude.global);
  366. type.add<uint8_t>(magnitude.type);
  367. units.add(magnitudeUnits(magnitude.type));
  368. if (magnitude.type == MAGNITUDE_ENERGY) {
  369. if (_sensor_energy_reset_ts.length() == 0) _sensorResetTS();
  370. description.add(magnitude.sensor->slot(magnitude.local) + String(" (since ") + _sensor_energy_reset_ts + String(")"));
  371. } else {
  372. description.add(magnitude.sensor->slot(magnitude.local));
  373. }
  374. }
  375. magnitudes["size"] = size;
  376. }
  377. void _sensorWebSocketSendData(JsonObject& root) {
  378. char buffer[64];
  379. JsonObject& magnitudes = root.createNestedObject("magnitudes");
  380. uint8_t size = 0;
  381. JsonArray& value = magnitudes.createNestedArray("value");
  382. JsonArray& error = magnitudes.createNestedArray("error");
  383. for (unsigned char i=0; i<magnitudeCount(); i++) {
  384. sensor_magnitude_t magnitude = _magnitudes[i];
  385. if (magnitude.type == MAGNITUDE_EVENT) continue;
  386. ++size;
  387. double value_show = _magnitudeProcess(magnitude.type, magnitude.decimals, magnitude.last);
  388. dtostrf(value_show, 1, magnitude.decimals, buffer);
  389. value.add(buffer);
  390. error.add(magnitude.sensor->error());
  391. }
  392. magnitudes["size"] = size;
  393. }
  394. void _sensorWebSocketOnConnected(JsonObject& root) {
  395. for (unsigned char i=0; i<_sensors.size(); i++) {
  396. BaseSensor * sensor = _sensors[i];
  397. UNUSED(sensor);
  398. #if EMON_ANALOG_SUPPORT
  399. if (sensor->getID() == SENSOR_EMON_ANALOG_ID) {
  400. root["emonVisible"] = 1;
  401. root["pwrVisible"] = 1;
  402. root["pwrVoltage"] = ((EmonAnalogSensor *) sensor)->getVoltage();
  403. }
  404. #endif
  405. #if HLW8012_SUPPORT
  406. if (sensor->getID() == SENSOR_HLW8012_ID) {
  407. root["hlwVisible"] = 1;
  408. root["pwrVisible"] = 1;
  409. }
  410. #endif
  411. #if CSE7766_SUPPORT
  412. if (sensor->getID() == SENSOR_CSE7766_ID) {
  413. root["cseVisible"] = 1;
  414. root["pwrVisible"] = 1;
  415. }
  416. #endif
  417. #if V9261F_SUPPORT
  418. if (sensor->getID() == SENSOR_V9261F_ID) {
  419. root["pwrVisible"] = 1;
  420. }
  421. #endif
  422. #if ECH1560_SUPPORT
  423. if (sensor->getID() == SENSOR_ECH1560_ID) {
  424. root["pwrVisible"] = 1;
  425. }
  426. #endif
  427. #if PZEM004T_SUPPORT
  428. if (sensor->getID() == SENSOR_PZEM004T_ID) {
  429. root["pzemVisible"] = 1;
  430. root["pwrVisible"] = 1;
  431. }
  432. #endif
  433. #if PULSEMETER_SUPPORT
  434. if (sensor->getID() == SENSOR_PULSEMETER_ID) {
  435. root["pmVisible"] = 1;
  436. root["pwrRatioE"] = ((PulseMeterSensor *) sensor)->getEnergyRatio();
  437. }
  438. #endif
  439. }
  440. if (magnitudeCount()) {
  441. //root["apiRealTime"] = _sensor_realtime;
  442. root["pwrUnits"] = _sensor_power_units;
  443. root["eneUnits"] = _sensor_energy_units;
  444. root["tmpUnits"] = _sensor_temperature_units;
  445. root["tmpCorrection"] = _sensor_temperature_correction;
  446. root["humCorrection"] = _sensor_humidity_correction;
  447. root["snsRead"] = _sensor_read_interval / 1000;
  448. root["snsReport"] = _sensor_report_every;
  449. root["snsSave"] = _sensor_save_every;
  450. _sensorWebSocketMagnitudesConfig(root);
  451. }
  452. /*
  453. // Sensors manifest
  454. JsonArray& manifest = root.createNestedArray("manifest");
  455. #if BMX280_SUPPORT
  456. BMX280Sensor::manifest(manifest);
  457. #endif
  458. // Sensors configuration
  459. JsonArray& sensors = root.createNestedArray("sensors");
  460. for (unsigned char i; i<_sensors.size(); i++) {
  461. JsonObject& sensor = sensors.createNestedObject();
  462. sensor["index"] = i;
  463. sensor["id"] = _sensors[i]->getID();
  464. _sensors[i]->getConfig(sensor);
  465. }
  466. */
  467. }
  468. #endif // WEB_SUPPORT
  469. #if API_SUPPORT
  470. void _sensorAPISetup() {
  471. for (unsigned char magnitude_id=0; magnitude_id<_magnitudes.size(); magnitude_id++) {
  472. sensor_magnitude_t magnitude = _magnitudes[magnitude_id];
  473. String topic = magnitudeTopic(magnitude.type);
  474. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global);
  475. apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) {
  476. sensor_magnitude_t magnitude = _magnitudes[magnitude_id];
  477. double value = _sensor_realtime ? magnitude.last : magnitude.reported;
  478. dtostrf(value, 1, magnitude.decimals, buffer);
  479. });
  480. }
  481. }
  482. #endif // API_SUPPORT
  483. #if TERMINAL_SUPPORT
  484. void _sensorInitCommands() {
  485. terminalRegisterCommand(F("MAGNITUDES"), [](Embedis* e) {
  486. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  487. sensor_magnitude_t magnitude = _magnitudes[i];
  488. DEBUG_MSG_P(PSTR("[SENSOR] * %2d: %s @ %s (%s/%d)\n"),
  489. i,
  490. magnitudeTopic(magnitude.type).c_str(),
  491. magnitude.sensor->slot(magnitude.local).c_str(),
  492. magnitudeTopic(magnitude.type).c_str(),
  493. magnitude.global
  494. );
  495. }
  496. terminalOK();
  497. });
  498. #if PZEM004T_SUPPORT
  499. terminalRegisterCommand(F("PZ.ADDRESS"), [](Embedis* e) {
  500. if (e->argc == 1) {
  501. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  502. unsigned char dev_count = pzem004t_sensor->getAddressesCount();
  503. for(unsigned char dev = 0; dev < dev_count; dev++) {
  504. DEBUG_MSG_P(PSTR("Device %d/%s\n"), dev, pzem004t_sensor->getAddress(dev).c_str());
  505. }
  506. terminalOK();
  507. } else if(e->argc == 2) {
  508. IPAddress addr;
  509. if (addr.fromString(String(e->argv[1]))) {
  510. if(pzem004t_sensor->setDeviceAddress(&addr)) {
  511. terminalOK();
  512. }
  513. } else {
  514. terminalError(F("Invalid address argument"));
  515. }
  516. } else {
  517. terminalError(F("Wrong arguments"));
  518. }
  519. });
  520. terminalRegisterCommand(F("PZ.RESET"), [](Embedis* e) {
  521. if(e->argc > 2) {
  522. terminalError(F("Wrong arguments"));
  523. } else {
  524. unsigned char init = e->argc == 2 ? String(e->argv[1]).toInt() : 0;
  525. unsigned char limit = e->argc == 2 ? init +1 : pzem004t_sensor->getAddressesCount();
  526. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  527. for(unsigned char dev = init; dev < limit; dev++) {
  528. float offset = pzem004t_sensor->resetEnergy(dev);
  529. _sensorEnergyTotal(dev, offset);
  530. DEBUG_MSG_P(PSTR("Device %d/%s - Offset: %s\n"), dev, pzem004t_sensor->getAddress(dev).c_str(), String(offset).c_str());
  531. }
  532. terminalOK();
  533. }
  534. });
  535. terminalRegisterCommand(F("PZ.VALUE"), [](Embedis* e) {
  536. if(e->argc > 2) {
  537. terminalError(F("Wrong arguments"));
  538. } else {
  539. unsigned char init = e->argc == 2 ? String(e->argv[1]).toInt() : 0;
  540. unsigned char limit = e->argc == 2 ? init +1 : pzem004t_sensor->getAddressesCount();
  541. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
  542. for(unsigned char dev = init; dev < limit; dev++) {
  543. DEBUG_MSG_P(PSTR("Device %d/%s - Current: %s Voltage: %s Power: %s Energy: %s\n"), //
  544. dev,
  545. pzem004t_sensor->getAddress(dev).c_str(),
  546. String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_CURRENT_INDEX)).c_str(),
  547. String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_VOLTAGE_INDEX)).c_str(),
  548. String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_POWER_ACTIVE_INDEX)).c_str(),
  549. String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_ENERGY_INDEX)).c_str());
  550. }
  551. terminalOK();
  552. }
  553. });
  554. #endif
  555. }
  556. #endif
  557. void _sensorTick() {
  558. for (unsigned char i=0; i<_sensors.size(); i++) {
  559. _sensors[i]->tick();
  560. }
  561. }
  562. void _sensorPre() {
  563. for (unsigned char i=0; i<_sensors.size(); i++) {
  564. _sensors[i]->pre();
  565. if (!_sensors[i]->status()) {
  566. DEBUG_MSG_P(PSTR("[SENSOR] Error reading data from %s (error: %d)\n"),
  567. _sensors[i]->description().c_str(),
  568. _sensors[i]->error()
  569. );
  570. }
  571. }
  572. }
  573. void _sensorPost() {
  574. for (unsigned char i=0; i<_sensors.size(); i++) {
  575. _sensors[i]->post();
  576. }
  577. }
  578. void _sensorResetTS() {
  579. #if NTP_SUPPORT
  580. if (ntpSynced()) {
  581. if (_sensor_energy_reset_ts.length() == 0) {
  582. _sensor_energy_reset_ts = ntpDateTime(now() - millis() / 1000);
  583. } else {
  584. _sensor_energy_reset_ts = ntpDateTime(now());
  585. }
  586. } else {
  587. _sensor_energy_reset_ts = String();
  588. }
  589. setSetting("snsResetTS", _sensor_energy_reset_ts);
  590. #endif
  591. }
  592. double _sensorEnergyTotal(unsigned char index) {
  593. double value = 0;
  594. if (rtcmemStatus() && (index < (sizeof(Rtcmem->energy) / sizeof(*Rtcmem->energy)))) {
  595. value = Rtcmem->energy[index];
  596. } else {
  597. value = (_sensor_save_every > 0) ? getSetting<double>({"eneTotal", index}, 0.) : 0.;
  598. }
  599. return value;
  600. }
  601. double _sensorEnergyTotal() {
  602. return _sensorEnergyTotal(0);
  603. }
  604. void _sensorEnergyTotal(unsigned char index, double value) {
  605. static unsigned long save_count = 0;
  606. // Save to EEPROM every '_sensor_save_every' readings
  607. if (_sensor_save_every > 0) {
  608. save_count = (save_count + 1) % _sensor_save_every;
  609. if (0 == save_count) {
  610. setSetting({"eneTotal", index}, value);
  611. saveSettings();
  612. }
  613. }
  614. // Always save to RTCMEM
  615. if (index < (sizeof(Rtcmem->energy) / sizeof(*Rtcmem->energy))) {
  616. Rtcmem->energy[index] = value;
  617. }
  618. }
  619. // -----------------------------------------------------------------------------
  620. // Sensor initialization
  621. // -----------------------------------------------------------------------------
  622. void _sensorLoad() {
  623. /*
  624. This is temporal, in the future sensors will be initialized based on
  625. soft configuration (data stored in EEPROM config) so you will be able
  626. to define and configure new sensors on the fly
  627. At the time being, only enabled sensors (those with *_SUPPORT to 1) are being
  628. loaded and initialized here. If you want to add new sensors of the same type
  629. just duplicate the block and change the arguments for the set* methods.
  630. Check the DHT block below for an example
  631. */
  632. #if AM2320_SUPPORT
  633. {
  634. AM2320Sensor * sensor = new AM2320Sensor();
  635. sensor->setAddress(AM2320_ADDRESS);
  636. _sensors.push_back(sensor);
  637. }
  638. #endif
  639. #if ANALOG_SUPPORT
  640. {
  641. AnalogSensor * sensor = new AnalogSensor();
  642. sensor->setSamples(ANALOG_SAMPLES);
  643. sensor->setDelay(ANALOG_DELAY);
  644. //CICM For analog scaling
  645. sensor->setFactor(ANALOG_FACTOR);
  646. sensor->setOffset(ANALOG_OFFSET);
  647. _sensors.push_back(sensor);
  648. }
  649. #endif
  650. #if BH1750_SUPPORT
  651. {
  652. BH1750Sensor * sensor = new BH1750Sensor();
  653. sensor->setAddress(BH1750_ADDRESS);
  654. sensor->setMode(BH1750_MODE);
  655. _sensors.push_back(sensor);
  656. }
  657. #endif
  658. #if BMP180_SUPPORT
  659. {
  660. BMP180Sensor * sensor = new BMP180Sensor();
  661. sensor->setAddress(BMP180_ADDRESS);
  662. _sensors.push_back(sensor);
  663. }
  664. #endif
  665. #if BMX280_SUPPORT
  666. {
  667. // Support up to two sensors with full auto-discovery.
  668. const unsigned char number = constrain(getSetting<int>("bmx280Number", BMX280_NUMBER), 1, 2);
  669. // For second sensor, if BMX280_ADDRESS is 0x00 then auto-discover
  670. // otherwise choose the other unnamed sensor address
  671. const auto first = getSetting("bmx280Address", BMX280_ADDRESS);
  672. const auto second = (first == 0x00) ? 0x00 : (0x76 + 0x77 - first);
  673. const decltype(first) address_map[2] { first, second };
  674. for (unsigned char n=0; n < number; ++n) {
  675. BMX280Sensor * sensor = new BMX280Sensor();
  676. sensor->setAddress(address_map[n]);
  677. _sensors.push_back(sensor);
  678. }
  679. }
  680. #endif
  681. #if CSE7766_SUPPORT
  682. {
  683. CSE7766Sensor * sensor = new CSE7766Sensor();
  684. sensor->setRX(CSE7766_PIN);
  685. _sensors.push_back(sensor);
  686. }
  687. #endif
  688. #if DALLAS_SUPPORT
  689. {
  690. DallasSensor * sensor = new DallasSensor();
  691. sensor->setGPIO(DALLAS_PIN);
  692. _sensors.push_back(sensor);
  693. }
  694. #endif
  695. #if DHT_SUPPORT
  696. {
  697. DHTSensor * sensor = new DHTSensor();
  698. sensor->setGPIO(DHT_PIN);
  699. sensor->setType(DHT_TYPE);
  700. _sensors.push_back(sensor);
  701. }
  702. #endif
  703. /*
  704. // Example on how to add a second DHT sensor
  705. // DHT2_PIN and DHT2_TYPE should be defined in sensors.h file
  706. #if DHT_SUPPORT
  707. {
  708. DHTSensor * sensor = new DHTSensor();
  709. sensor->setGPIO(DHT2_PIN);
  710. sensor->setType(DHT2_TYPE);
  711. _sensors.push_back(sensor);
  712. }
  713. #endif
  714. */
  715. #if DIGITAL_SUPPORT
  716. {
  717. #if (DIGITAL1_PIN != GPIO_NONE)
  718. {
  719. DigitalSensor * sensor = new DigitalSensor();
  720. sensor->setGPIO(DIGITAL1_PIN);
  721. sensor->setMode(DIGITAL1_PIN_MODE);
  722. sensor->setDefault(DIGITAL1_DEFAULT_STATE);
  723. _sensors.push_back(sensor);
  724. }
  725. #endif
  726. #if (DIGITAL2_PIN != GPIO_NONE)
  727. {
  728. DigitalSensor * sensor = new DigitalSensor();
  729. sensor->setGPIO(DIGITAL2_PIN);
  730. sensor->setMode(DIGITAL2_PIN_MODE);
  731. sensor->setDefault(DIGITAL2_DEFAULT_STATE);
  732. _sensors.push_back(sensor);
  733. }
  734. #endif
  735. #if (DIGITAL3_PIN != GPIO_NONE)
  736. {
  737. DigitalSensor * sensor = new DigitalSensor();
  738. sensor->setGPIO(DIGITAL3_PIN);
  739. sensor->setMode(DIGITAL3_PIN_MODE);
  740. sensor->setDefault(DIGITAL3_DEFAULT_STATE);
  741. _sensors.push_back(sensor);
  742. }
  743. #endif
  744. #if (DIGITAL4_PIN != GPIO_NONE)
  745. {
  746. DigitalSensor * sensor = new DigitalSensor();
  747. sensor->setGPIO(DIGITAL4_PIN);
  748. sensor->setMode(DIGITAL4_PIN_MODE);
  749. sensor->setDefault(DIGITAL4_DEFAULT_STATE);
  750. _sensors.push_back(sensor);
  751. }
  752. #endif
  753. #if (DIGITAL5_PIN != GPIO_NONE)
  754. {
  755. DigitalSensor * sensor = new DigitalSensor();
  756. sensor->setGPIO(DIGITAL5_PIN);
  757. sensor->setMode(DIGITAL5_PIN_MODE);
  758. sensor->setDefault(DIGITAL5_DEFAULT_STATE);
  759. _sensors.push_back(sensor);
  760. }
  761. #endif
  762. #if (DIGITAL6_PIN != GPIO_NONE)
  763. {
  764. DigitalSensor * sensor = new DigitalSensor();
  765. sensor->setGPIO(DIGITAL6_PIN);
  766. sensor->setMode(DIGITAL6_PIN_MODE);
  767. sensor->setDefault(DIGITAL6_DEFAULT_STATE);
  768. _sensors.push_back(sensor);
  769. }
  770. #endif
  771. #if (DIGITAL7_PIN != GPIO_NONE)
  772. {
  773. DigitalSensor * sensor = new DigitalSensor();
  774. sensor->setGPIO(DIGITAL7_PIN);
  775. sensor->setMode(DIGITAL7_PIN_MODE);
  776. sensor->setDefault(DIGITAL7_DEFAULT_STATE);
  777. _sensors.push_back(sensor);
  778. }
  779. #endif
  780. #if (DIGITAL8_PIN != GPIO_NONE)
  781. {
  782. DigitalSensor * sensor = new DigitalSensor();
  783. sensor->setGPIO(DIGITAL8_PIN);
  784. sensor->setMode(DIGITAL8_PIN_MODE);
  785. sensor->setDefault(DIGITAL8_DEFAULT_STATE);
  786. _sensors.push_back(sensor);
  787. }
  788. #endif
  789. }
  790. #endif
  791. #if ECH1560_SUPPORT
  792. {
  793. ECH1560Sensor * sensor = new ECH1560Sensor();
  794. sensor->setCLK(ECH1560_CLK_PIN);
  795. sensor->setMISO(ECH1560_MISO_PIN);
  796. sensor->setInverted(ECH1560_INVERTED);
  797. _sensors.push_back(sensor);
  798. }
  799. #endif
  800. #if EMON_ADC121_SUPPORT
  801. {
  802. EmonADC121Sensor * sensor = new EmonADC121Sensor();
  803. sensor->setAddress(EMON_ADC121_I2C_ADDRESS);
  804. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  805. sensor->setReference(EMON_REFERENCE_VOLTAGE);
  806. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  807. _sensors.push_back(sensor);
  808. }
  809. #endif
  810. #if EMON_ADS1X15_SUPPORT
  811. {
  812. EmonADS1X15Sensor * sensor = new EmonADS1X15Sensor();
  813. sensor->setAddress(EMON_ADS1X15_I2C_ADDRESS);
  814. sensor->setType(EMON_ADS1X15_TYPE);
  815. sensor->setMask(EMON_ADS1X15_MASK);
  816. sensor->setGain(EMON_ADS1X15_GAIN);
  817. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  818. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  819. sensor->setCurrentRatio(1, EMON_CURRENT_RATIO);
  820. sensor->setCurrentRatio(2, EMON_CURRENT_RATIO);
  821. sensor->setCurrentRatio(3, EMON_CURRENT_RATIO);
  822. _sensors.push_back(sensor);
  823. }
  824. #endif
  825. #if EMON_ANALOG_SUPPORT
  826. {
  827. EmonAnalogSensor * sensor = new EmonAnalogSensor();
  828. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  829. sensor->setReference(EMON_REFERENCE_VOLTAGE);
  830. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  831. _sensors.push_back(sensor);
  832. }
  833. #endif
  834. #if EVENTS_SUPPORT
  835. {
  836. #if (EVENTS1_PIN != GPIO_NONE)
  837. {
  838. EventSensor * sensor = new EventSensor();
  839. sensor->setGPIO(EVENTS1_PIN);
  840. sensor->setTrigger(EVENTS1_TRIGGER);
  841. sensor->setPinMode(EVENTS1_PIN_MODE);
  842. sensor->setDebounceTime(EVENTS1_DEBOUNCE);
  843. sensor->setInterruptMode(EVENTS1_INTERRUPT_MODE);
  844. _sensors.push_back(sensor);
  845. }
  846. #endif
  847. #if (EVENTS2_PIN != GPIO_NONE)
  848. {
  849. EventSensor * sensor = new EventSensor();
  850. sensor->setGPIO(EVENTS2_PIN);
  851. sensor->setTrigger(EVENTS2_TRIGGER);
  852. sensor->setPinMode(EVENTS2_PIN_MODE);
  853. sensor->setDebounceTime(EVENTS2_DEBOUNCE);
  854. sensor->setInterruptMode(EVENTS2_INTERRUPT_MODE);
  855. _sensors.push_back(sensor);
  856. }
  857. #endif
  858. #if (EVENTS3_PIN != GPIO_NONE)
  859. {
  860. EventSensor * sensor = new EventSensor();
  861. sensor->setGPIO(EVENTS3_PIN);
  862. sensor->setTrigger(EVENTS3_TRIGGER);
  863. sensor->setPinMode(EVENTS3_PIN_MODE);
  864. sensor->setDebounceTime(EVENTS3_DEBOUNCE);
  865. sensor->setInterruptMode(EVENTS3_INTERRUPT_MODE);
  866. _sensors.push_back(sensor);
  867. }
  868. #endif
  869. #if (EVENTS4_PIN != GPIO_NONE)
  870. {
  871. EventSensor * sensor = new EventSensor();
  872. sensor->setGPIO(EVENTS4_PIN);
  873. sensor->setTrigger(EVENTS4_TRIGGER);
  874. sensor->setPinMode(EVENTS4_PIN_MODE);
  875. sensor->setDebounceTime(EVENTS4_DEBOUNCE);
  876. sensor->setInterruptMode(EVENTS4_INTERRUPT_MODE);
  877. _sensors.push_back(sensor);
  878. }
  879. #endif
  880. #if (EVENTS5_PIN != GPIO_NONE)
  881. {
  882. EventSensor * sensor = new EventSensor();
  883. sensor->setGPIO(EVENTS5_PIN);
  884. sensor->setTrigger(EVENTS5_TRIGGER);
  885. sensor->setPinMode(EVENTS5_PIN_MODE);
  886. sensor->setDebounceTime(EVENTS5_DEBOUNCE);
  887. sensor->setInterruptMode(EVENTS5_INTERRUPT_MODE);
  888. _sensors.push_back(sensor);
  889. }
  890. #endif
  891. #if (EVENTS6_PIN != GPIO_NONE)
  892. {
  893. EventSensor * sensor = new EventSensor();
  894. sensor->setGPIO(EVENTS6_PIN);
  895. sensor->setTrigger(EVENTS6_TRIGGER);
  896. sensor->setPinMode(EVENTS6_PIN_MODE);
  897. sensor->setDebounceTime(EVENTS6_DEBOUNCE);
  898. sensor->setInterruptMode(EVENTS6_INTERRUPT_MODE);
  899. _sensors.push_back(sensor);
  900. }
  901. #endif
  902. #if (EVENTS7_PIN != GPIO_NONE)
  903. {
  904. EventSensor * sensor = new EventSensor();
  905. sensor->setGPIO(EVENTS7_PIN);
  906. sensor->setTrigger(EVENTS7_TRIGGER);
  907. sensor->setPinMode(EVENTS7_PIN_MODE);
  908. sensor->setDebounceTime(EVENTS7_DEBOUNCE);
  909. sensor->setInterruptMode(EVENTS7_INTERRUPT_MODE);
  910. _sensors.push_back(sensor);
  911. }
  912. #endif
  913. #if (EVENTS8_PIN != GPIO_NONE)
  914. {
  915. EventSensor * sensor = new EventSensor();
  916. sensor->setGPIO(EVENTS8_PIN);
  917. sensor->setTrigger(EVENTS8_TRIGGER);
  918. sensor->setPinMode(EVENTS8_PIN_MODE);
  919. sensor->setDebounceTime(EVENTS8_DEBOUNCE);
  920. sensor->setInterruptMode(EVENTS8_INTERRUPT_MODE);
  921. _sensors.push_back(sensor);
  922. }
  923. #endif
  924. }
  925. #endif
  926. #if GEIGER_SUPPORT
  927. {
  928. GeigerSensor * sensor = new GeigerSensor(); // Create instance of thr Geiger module.
  929. sensor->setGPIO(GEIGER_PIN); // Interrupt pin of the attached geiger counter board.
  930. sensor->setMode(GEIGER_PIN_MODE); // This pin is an input.
  931. sensor->setDebounceTime(GEIGER_DEBOUNCE); // Debounce time 25ms, because https://github.com/Trickx/espurna/wiki/Geiger-counter
  932. sensor->setInterruptMode(GEIGER_INTERRUPT_MODE); // Interrupt triggering: edge detection rising.
  933. sensor->setCPM2SievertFactor(GEIGER_CPM2SIEVERT); // Conversion factor from counts per minute to µSv/h
  934. _sensors.push_back(sensor);
  935. }
  936. #endif
  937. #if GUVAS12SD_SUPPORT
  938. {
  939. GUVAS12SDSensor * sensor = new GUVAS12SDSensor();
  940. sensor->setGPIO(GUVAS12SD_PIN);
  941. _sensors.push_back(sensor);
  942. }
  943. #endif
  944. #if SONAR_SUPPORT
  945. {
  946. SonarSensor * sensor = new SonarSensor();
  947. sensor->setEcho(SONAR_ECHO);
  948. sensor->setIterations(SONAR_ITERATIONS);
  949. sensor->setMaxDistance(SONAR_MAX_DISTANCE);
  950. sensor->setTrigger(SONAR_TRIGGER);
  951. _sensors.push_back(sensor);
  952. }
  953. #endif
  954. #if HLW8012_SUPPORT
  955. {
  956. HLW8012Sensor * sensor = new HLW8012Sensor();
  957. sensor->setSEL(getSetting("snsHlw8012SelGPIO", HLW8012_SEL_PIN));
  958. sensor->setCF(getSetting("snsHlw8012CfGPIO", HLW8012_CF_PIN));
  959. sensor->setCF1(getSetting("snsHlw8012Cf1GPIO", HLW8012_CF1_PIN));
  960. sensor->setSELCurrent(HLW8012_SEL_CURRENT);
  961. _sensors.push_back(sensor);
  962. }
  963. #endif
  964. #if LDR_SUPPORT
  965. {
  966. LDRSensor * sensor = new LDRSensor();
  967. sensor->setSamples(LDR_SAMPLES);
  968. sensor->setDelay(LDR_DELAY);
  969. sensor->setType(LDR_TYPE);
  970. sensor->setPhotocellPositionOnGround(LDR_ON_GROUND);
  971. sensor->setResistor(LDR_RESISTOR);
  972. sensor->setPhotocellParameters(LDR_MULTIPLICATION, LDR_POWER);
  973. _sensors.push_back(sensor);
  974. }
  975. #endif
  976. #if MHZ19_SUPPORT
  977. {
  978. MHZ19Sensor * sensor = new MHZ19Sensor();
  979. sensor->setRX(MHZ19_RX_PIN);
  980. sensor->setTX(MHZ19_TX_PIN);
  981. if (getSetting("mhz19CalibrateAuto", false)) {
  982. sensor->setCalibrateAuto(true);
  983. }
  984. _sensors.push_back(sensor);
  985. }
  986. #endif
  987. #if MICS2710_SUPPORT
  988. {
  989. MICS2710Sensor * sensor = new MICS2710Sensor();
  990. sensor->setAnalogGPIO(MICS2710_NOX_PIN);
  991. sensor->setPreHeatGPIO(MICS2710_PRE_PIN);
  992. sensor->setRL(MICS2710_RL);
  993. _sensors.push_back(sensor);
  994. }
  995. #endif
  996. #if MICS5525_SUPPORT
  997. {
  998. MICS5525Sensor * sensor = new MICS5525Sensor();
  999. sensor->setAnalogGPIO(MICS5525_RED_PIN);
  1000. sensor->setRL(MICS5525_RL);
  1001. _sensors.push_back(sensor);
  1002. }
  1003. #endif
  1004. #if NTC_SUPPORT
  1005. {
  1006. NTCSensor * sensor = new NTCSensor();
  1007. sensor->setSamples(NTC_SAMPLES);
  1008. sensor->setDelay(NTC_DELAY);
  1009. sensor->setUpstreamResistor(NTC_R_UP);
  1010. sensor->setDownstreamResistor(NTC_R_DOWN);
  1011. sensor->setBeta(NTC_BETA);
  1012. sensor->setR0(NTC_R0);
  1013. sensor->setT0(NTC_T0);
  1014. _sensors.push_back(sensor);
  1015. }
  1016. #endif
  1017. #if PMSX003_SUPPORT
  1018. {
  1019. PMSX003Sensor * sensor = new PMSX003Sensor();
  1020. #if PMS_USE_SOFT
  1021. sensor->setRX(PMS_RX_PIN);
  1022. sensor->setTX(PMS_TX_PIN);
  1023. #else
  1024. sensor->setSerial(& PMS_HW_PORT);
  1025. #endif
  1026. sensor->setType(PMS_TYPE);
  1027. _sensors.push_back(sensor);
  1028. }
  1029. #endif
  1030. #if PULSEMETER_SUPPORT
  1031. {
  1032. PulseMeterSensor * sensor = new PulseMeterSensor();
  1033. sensor->setGPIO(PULSEMETER_PIN);
  1034. sensor->setEnergyRatio(PULSEMETER_ENERGY_RATIO);
  1035. sensor->setInterruptMode(PULSEMETER_INTERRUPT_ON);
  1036. sensor->setDebounceTime(PULSEMETER_DEBOUNCE);
  1037. _sensors.push_back(sensor);
  1038. }
  1039. #endif
  1040. #if PZEM004T_SUPPORT
  1041. {
  1042. String addresses = getSetting("pzemAddr", F(PZEM004T_ADDRESSES));
  1043. if (!addresses.length()) {
  1044. DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T Error: no addresses are configured\n"));
  1045. return;
  1046. }
  1047. PZEM004TSensor * sensor = pzem004t_sensor = new PZEM004TSensor();
  1048. sensor->setAddresses(addresses.c_str());
  1049. if (getSetting("pzemSoft", 1 == PZEM004T_USE_SOFT)) {
  1050. sensor->setRX(getSetting("pzemRX", PZEM004T_RX_PIN));
  1051. sensor->setTX(getSetting("pzemTX", PZEM004T_TX_PIN));
  1052. } else {
  1053. sensor->setSerial(& PZEM004T_HW_PORT);
  1054. }
  1055. // Read saved energy offset
  1056. unsigned char dev_count = sensor->getAddressesCount();
  1057. for(unsigned char dev = 0; dev < dev_count; dev++) {
  1058. float value = _sensorEnergyTotal(dev);
  1059. if (value > 0) sensor->resetEnergy(dev, value);
  1060. }
  1061. _sensors.push_back(sensor);
  1062. }
  1063. #endif
  1064. #if SENSEAIR_SUPPORT
  1065. {
  1066. SenseAirSensor * sensor = new SenseAirSensor();
  1067. sensor->setRX(SENSEAIR_RX_PIN);
  1068. sensor->setTX(SENSEAIR_TX_PIN);
  1069. _sensors.push_back(sensor);
  1070. }
  1071. #endif
  1072. #if SDS011_SUPPORT
  1073. {
  1074. SDS011Sensor * sensor = new SDS011Sensor();
  1075. sensor->setRX(SDS011_RX_PIN);
  1076. sensor->setTX(SDS011_TX_PIN);
  1077. _sensors.push_back(sensor);
  1078. }
  1079. #endif
  1080. #if SHT3X_I2C_SUPPORT
  1081. {
  1082. SHT3XI2CSensor * sensor = new SHT3XI2CSensor();
  1083. sensor->setAddress(SHT3X_I2C_ADDRESS);
  1084. _sensors.push_back(sensor);
  1085. }
  1086. #endif
  1087. #if SI7021_SUPPORT
  1088. {
  1089. SI7021Sensor * sensor = new SI7021Sensor();
  1090. sensor->setAddress(SI7021_ADDRESS);
  1091. _sensors.push_back(sensor);
  1092. }
  1093. #endif
  1094. #if T6613_SUPPORT
  1095. {
  1096. T6613Sensor * sensor = new T6613Sensor();
  1097. sensor->setRX(T6613_RX_PIN);
  1098. sensor->setTX(T6613_TX_PIN);
  1099. _sensors.push_back(sensor);
  1100. }
  1101. #endif
  1102. #if TMP3X_SUPPORT
  1103. {
  1104. TMP3XSensor * sensor = new TMP3XSensor();
  1105. sensor->setType(TMP3X_TYPE);
  1106. _sensors.push_back(sensor);
  1107. }
  1108. #endif
  1109. #if V9261F_SUPPORT
  1110. {
  1111. V9261FSensor * sensor = new V9261FSensor();
  1112. sensor->setRX(V9261F_PIN);
  1113. sensor->setInverted(V9261F_PIN_INVERSE);
  1114. _sensors.push_back(sensor);
  1115. }
  1116. #endif
  1117. #if MAX6675_SUPPORT
  1118. {
  1119. MAX6675Sensor * sensor = new MAX6675Sensor();
  1120. sensor->setCS(MAX6675_CS_PIN);
  1121. sensor->setSO(MAX6675_SO_PIN);
  1122. sensor->setSCK(MAX6675_SCK_PIN);
  1123. _sensors.push_back(sensor);
  1124. }
  1125. #endif
  1126. #if VEML6075_SUPPORT
  1127. {
  1128. VEML6075Sensor * sensor = new VEML6075Sensor();
  1129. sensor->setIntegrationTime(VEML6075_INTEGRATION_TIME);
  1130. sensor->setDynamicMode(VEML6075_DYNAMIC_MODE);
  1131. _sensors.push_back(sensor);
  1132. }
  1133. #endif
  1134. #if VL53L1X_SUPPORT
  1135. {
  1136. VL53L1XSensor * sensor = new VL53L1XSensor();
  1137. sensor->setInterMeasurementPeriod(VL53L1X_INTER_MEASUREMENT_PERIOD);
  1138. sensor->setDistanceMode(VL53L1X_DISTANCE_MODE);
  1139. sensor->setMeasurementTimingBudget(VL53L1X_MEASUREMENT_TIMING_BUDGET);
  1140. _sensors.push_back(sensor);
  1141. }
  1142. #endif
  1143. #if EZOPH_SUPPORT
  1144. {
  1145. EZOPHSensor * sensor = new EZOPHSensor();
  1146. sensor->setRX(EZOPH_RX_PIN);
  1147. sensor->setTX(EZOPH_TX_PIN);
  1148. _sensors.push_back(sensor);
  1149. }
  1150. #endif
  1151. #if ADE7953_SUPPORT
  1152. {
  1153. ADE7953Sensor * sensor = new ADE7953Sensor();
  1154. sensor->setAddress(ADE7953_ADDRESS);
  1155. _sensors.push_back(sensor);
  1156. }
  1157. #endif
  1158. }
  1159. void _sensorCallback(unsigned char i, unsigned char type, double value) {
  1160. DEBUG_MSG_P(PSTR("[SENSOR] Sensor #%u callback, type %u, payload: '%s'\n"), i, type, String(value).c_str());
  1161. for (unsigned char k=0; k<_magnitudes.size(); k++) {
  1162. if ((_sensors[i] == _magnitudes[k].sensor) && (type == _magnitudes[k].type)) {
  1163. _sensorReport(k, value);
  1164. return;
  1165. }
  1166. }
  1167. }
  1168. void _sensorInit() {
  1169. _sensors_ready = true;
  1170. _sensor_save_every = getSetting<int>("snsSave", 0);
  1171. for (unsigned char i=0; i<_sensors.size(); i++) {
  1172. // Do not process an already initialized sensor
  1173. if (_sensors[i]->ready()) continue;
  1174. DEBUG_MSG_P(PSTR("[SENSOR] Initializing %s\n"), _sensors[i]->description().c_str());
  1175. // Force sensor to reload config
  1176. _sensors[i]->begin();
  1177. if (!_sensors[i]->ready()) {
  1178. if (_sensors[i]->error() != 0) DEBUG_MSG_P(PSTR("[SENSOR] -> ERROR %d\n"), _sensors[i]->error());
  1179. _sensors_ready = false;
  1180. continue;
  1181. }
  1182. // Initialize magnitudes
  1183. for (unsigned char k=0; k<_sensors[i]->count(); k++) {
  1184. unsigned char type = _sensors[i]->type(k);
  1185. signed char decimals = _sensors[i]->decimals(type);
  1186. if (decimals < 0) decimals = _magnitudeDecimals(type);
  1187. sensor_magnitude_t new_magnitude;
  1188. new_magnitude.sensor = _sensors[i];
  1189. new_magnitude.local = k;
  1190. new_magnitude.type = type;
  1191. new_magnitude.decimals = (unsigned char) decimals;
  1192. new_magnitude.global = _counts[type];
  1193. new_magnitude.last = 0;
  1194. new_magnitude.reported = 0;
  1195. new_magnitude.min_change = 0;
  1196. new_magnitude.max_change = 0;
  1197. // TODO: find a proper way to extend this to min/max of any magnitude
  1198. if (MAGNITUDE_ENERGY == type) {
  1199. new_magnitude.max_change = getSetting("eneMaxDelta", ENERGY_MAX_CHANGE);
  1200. } else if (MAGNITUDE_TEMPERATURE == type) {
  1201. new_magnitude.min_change = getSetting("tmpMinDelta", TEMPERATURE_MIN_CHANGE);
  1202. } else if (MAGNITUDE_HUMIDITY == type) {
  1203. new_magnitude.min_change = getSetting("humMinDelta", HUMIDITY_MIN_CHANGE);
  1204. }
  1205. if (MAGNITUDE_ENERGY == type) {
  1206. new_magnitude.filter = new LastFilter();
  1207. } else if (MAGNITUDE_DIGITAL == type) {
  1208. new_magnitude.filter = new MaxFilter();
  1209. } else if (MAGNITUDE_COUNT == type || MAGNITUDE_GEIGER_CPM == type || MAGNITUDE_GEIGER_SIEVERT == type) { // For geiger counting moving average filter is the most appropriate if needed at all.
  1210. new_magnitude.filter = new MovingAverageFilter();
  1211. } else {
  1212. new_magnitude.filter = new MedianFilter();
  1213. }
  1214. new_magnitude.filter->resize(_sensor_report_every);
  1215. _magnitudes.push_back(new_magnitude);
  1216. DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), magnitudeTopic(type).c_str(), _counts[type]);
  1217. _counts[type] = _counts[type] + 1;
  1218. }
  1219. // Hook callback
  1220. _sensors[i]->onEvent([i](unsigned char type, double value) {
  1221. _sensorCallback(i, type, value);
  1222. });
  1223. // Custom initializations
  1224. #if MICS2710_SUPPORT
  1225. if (_sensors[i]->getID() == SENSOR_MICS2710_ID) {
  1226. MICS2710Sensor * sensor = (MICS2710Sensor *) _sensors[i];
  1227. sensor->setR0(getSetting("snsR0", MICS2710_R0));
  1228. }
  1229. #endif // MICS2710_SUPPORT
  1230. #if MICS5525_SUPPORT
  1231. if (_sensors[i]->getID() == SENSOR_MICS5525_ID) {
  1232. MICS5525Sensor * sensor = (MICS5525Sensor *) _sensors[i];
  1233. sensor->setR0(getSetting("snsR0", MICS5525_R0));
  1234. }
  1235. #endif // MICS5525_SUPPORT
  1236. #if EMON_ANALOG_SUPPORT
  1237. if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) {
  1238. EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
  1239. sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO));
  1240. sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE));
  1241. double value = _sensorEnergyTotal();
  1242. if (value > 0) sensor->resetEnergy(0, value);
  1243. }
  1244. #endif // EMON_ANALOG_SUPPORT
  1245. #if HLW8012_SUPPORT
  1246. if (_sensors[i]->getID() == SENSOR_HLW8012_ID) {
  1247. HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i];
  1248. double value;
  1249. value = getSetting("pwrRatioC", HLW8012_CURRENT_RATIO);
  1250. if (value > 0) sensor->setCurrentRatio(value);
  1251. value = getSetting("pwrRatioV", HLW8012_VOLTAGE_RATIO);
  1252. if (value > 0) sensor->setVoltageRatio(value);
  1253. value = getSetting("pwrRatioP", HLW8012_POWER_RATIO);
  1254. if (value > 0) sensor->setPowerRatio(value);
  1255. value = _sensorEnergyTotal();
  1256. if (value > 0) sensor->resetEnergy(value);
  1257. }
  1258. #endif // HLW8012_SUPPORT
  1259. #if ADE7953_SUPPORT
  1260. if (_sensors[i]->getID() == SENSOR_ADE7953_ID) {
  1261. ADE7953Sensor * sensor = (ADE7953Sensor *) _sensors[i];
  1262. unsigned int dev_count = sensor->getTotalDevices();
  1263. for(unsigned char dev = 0; dev < dev_count; dev++) {
  1264. double value = _sensorEnergyTotal(dev);
  1265. if (value > 0) sensor->resetEnergy(dev, value);
  1266. }
  1267. }
  1268. #endif // ADE7953_SUPPORT
  1269. #if CSE7766_SUPPORT
  1270. if (_sensors[i]->getID() == SENSOR_CSE7766_ID) {
  1271. CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i];
  1272. double value;
  1273. value = getSetting("pwrRatioC", 0.0);
  1274. if (value > 0) sensor->setCurrentRatio(value);
  1275. value = getSetting("pwrRatioV", 0.0);
  1276. if (value > 0) sensor->setVoltageRatio(value);
  1277. value = getSetting("pwrRatioP", 0.0);
  1278. if (value > 0) sensor->setPowerRatio(value);
  1279. value = _sensorEnergyTotal();
  1280. if (value > 0) sensor->resetEnergy(value);
  1281. }
  1282. #endif // CSE7766_SUPPORT
  1283. #if PULSEMETER_SUPPORT
  1284. if (_sensors[i]->getID() == SENSOR_PULSEMETER_ID) {
  1285. PulseMeterSensor * sensor = (PulseMeterSensor *) _sensors[i];
  1286. sensor->setEnergyRatio(getSetting("pwrRatioE", sensor->getEnergyRatio()));
  1287. }
  1288. #endif // PULSEMETER_SUPPORT
  1289. }
  1290. }
  1291. void _sensorConfigure() {
  1292. // General sensor settings for reporting and saving
  1293. _sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL);
  1294. _sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY);
  1295. _sensor_save_every = getSetting("snsSave", SENSOR_SAVE_EVERY);
  1296. _sensor_realtime = getSetting("apiRealTime", 1 == API_REAL_TIME_VALUES);
  1297. // Units are configured globally atm
  1298. _sensor_power_units = getSetting("pwrUnits", SENSOR_POWER_UNITS);
  1299. _sensor_energy_units = getSetting("eneUnits", SENSOR_ENERGY_UNITS);
  1300. _sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS);
  1301. // ...same with corrections
  1302. _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION);
  1303. _sensor_humidity_correction = getSetting("humCorrection", SENSOR_HUMIDITY_CORRECTION);
  1304. _sensor_lux_correction = getSetting("luxCorrection", SENSOR_LUX_CORRECTION);
  1305. // energy reset should be timestamped
  1306. _sensor_energy_reset_ts = getSetting("snsResetTS");
  1307. // Specific sensor settings
  1308. for (unsigned char i=0; i<_sensors.size(); i++) {
  1309. #if MICS2710_SUPPORT
  1310. if (_sensors[i]->getID() == SENSOR_MICS2710_ID) {
  1311. if (getSetting("snsResetCalibration", false)) {
  1312. MICS2710Sensor * sensor = (MICS2710Sensor *) _sensors[i];
  1313. sensor->calibrate();
  1314. setSetting("snsR0", sensor->getR0());
  1315. }
  1316. }
  1317. #endif // MICS2710_SUPPORT
  1318. #if MICS5525_SUPPORT
  1319. if (_sensors[i]->getID() == SENSOR_MICS5525_ID) {
  1320. if (getSetting("snsResetCalibration", false)) {
  1321. MICS5525Sensor * sensor = (MICS5525Sensor *) _sensors[i];
  1322. sensor->calibrate();
  1323. setSetting("snsR0", sensor->getR0());
  1324. }
  1325. }
  1326. #endif // MICS5525_SUPPORT
  1327. #if EMON_ANALOG_SUPPORT
  1328. if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) {
  1329. double value;
  1330. EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
  1331. if ((value = getSetting("pwrExpectedP", 0))) {
  1332. sensor->expectedPower(0, value);
  1333. setSetting("pwrRatioC", sensor->getCurrentRatio(0));
  1334. }
  1335. if (getSetting("pwrResetCalibration", false)) {
  1336. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  1337. delSetting("pwrRatioC");
  1338. }
  1339. if (getSetting("pwrResetE", false)) {
  1340. sensor->resetEnergy();
  1341. delSetting({"eneTotal", 0});
  1342. _sensorResetTS();
  1343. }
  1344. sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE));
  1345. }
  1346. #endif // EMON_ANALOG_SUPPORT
  1347. #if EMON_ADC121_SUPPORT
  1348. if (_sensors[i]->getID() == SENSOR_EMON_ADC121_ID) {
  1349. EmonADC121Sensor * sensor = (EmonADC121Sensor *) _sensors[i];
  1350. if (getSetting("pwrResetE", false)) {
  1351. sensor->resetEnergy();
  1352. delSetting({"eneTotal", 0});
  1353. _sensorResetTS();
  1354. }
  1355. }
  1356. #endif
  1357. #if EMON_ADS1X15_SUPPORT
  1358. if (_sensors[i]->getID() == SENSOR_EMON_ADS1X15_ID) {
  1359. EmonADS1X15Sensor * sensor = (EmonADS1X15Sensor *) _sensors[i];
  1360. if (getSetting("pwrResetE", false)) {
  1361. sensor->resetEnergy();
  1362. delSetting({"eneTotal", 0});
  1363. _sensorResetTS();
  1364. }
  1365. }
  1366. #endif
  1367. #if HLW8012_SUPPORT
  1368. if (_sensors[i]->getID() == SENSOR_HLW8012_ID) {
  1369. double value;
  1370. HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i];
  1371. if ((value = getSetting("pwrExpectedC", 0.0))) {
  1372. sensor->expectedCurrent(value);
  1373. setSetting("pwrRatioC", sensor->getCurrentRatio());
  1374. }
  1375. if ((value = getSetting("pwrExpectedV", 0.0))) {
  1376. sensor->expectedVoltage(value);
  1377. setSetting("pwrRatioV", sensor->getVoltageRatio());
  1378. }
  1379. if ((value = getSetting("pwrExpectedP", 0.0))) {
  1380. sensor->expectedPower(value);
  1381. setSetting("pwrRatioP", sensor->getPowerRatio());
  1382. }
  1383. if (getSetting("pwrResetE", false)) {
  1384. sensor->resetEnergy();
  1385. delSetting({"eneTotal", 0});
  1386. _sensorResetTS();
  1387. }
  1388. if (getSetting("pwrResetCalibration", false)) {
  1389. sensor->resetRatios();
  1390. delSetting("pwrRatioC");
  1391. delSetting("pwrRatioV");
  1392. delSetting("pwrRatioP");
  1393. }
  1394. }
  1395. #endif // HLW8012_SUPPORT
  1396. #if CSE7766_SUPPORT
  1397. if (_sensors[i]->getID() == SENSOR_CSE7766_ID) {
  1398. double value;
  1399. CSE7766Sensor * sensor = (CSE7766Sensor *) _sensors[i];
  1400. if ((value = getSetting("pwrExpectedC", 0.0))) {
  1401. sensor->expectedCurrent(value);
  1402. setSetting("pwrRatioC", sensor->getCurrentRatio());
  1403. }
  1404. if ((value = getSetting("pwrExpectedV", 0.0))) {
  1405. sensor->expectedVoltage(value);
  1406. setSetting("pwrRatioV", sensor->getVoltageRatio());
  1407. }
  1408. if ((value = getSetting("pwrExpectedP", 0.0))) {
  1409. sensor->expectedPower(value);
  1410. setSetting("pwrRatioP", sensor->getPowerRatio());
  1411. }
  1412. if (getSetting("pwrResetE", false)) {
  1413. sensor->resetEnergy();
  1414. delSetting({"eneTotal", 0});
  1415. _sensorResetTS();
  1416. }
  1417. if (getSetting("pwrResetCalibration", false)) {
  1418. sensor->resetRatios();
  1419. delSetting("pwrRatioC");
  1420. delSetting("pwrRatioV");
  1421. delSetting("pwrRatioP");
  1422. }
  1423. }
  1424. #endif // CSE7766_SUPPORT
  1425. #if PULSEMETER_SUPPORT
  1426. if (_sensors[i]->getID() == SENSOR_PULSEMETER_ID) {
  1427. PulseMeterSensor * sensor = (PulseMeterSensor *) _sensors[i];
  1428. if (getSetting("pwrResetE", false)) {
  1429. sensor->resetEnergy();
  1430. delSetting({"eneTotal", 0});
  1431. _sensorResetTS();
  1432. }
  1433. sensor->setEnergyRatio(getSetting<unsigned long>("pwrRatioE", sensor->getEnergyRatio()));
  1434. }
  1435. #endif // PULSEMETER_SUPPORT
  1436. #if PZEM004T_SUPPORT
  1437. if (_sensors[i]->getID() == SENSOR_PZEM004T_ID) {
  1438. PZEM004TSensor * sensor = (PZEM004TSensor *) _sensors[i];
  1439. if (getSetting("pwrResetE", false)) {
  1440. unsigned char dev_count = sensor->getAddressesCount();
  1441. for(unsigned char dev = 0; dev < dev_count; dev++) {
  1442. sensor->resetEnergy(dev, 0);
  1443. delSetting({"eneTotal", dev});
  1444. }
  1445. _sensorResetTS();
  1446. }
  1447. }
  1448. #endif // PZEM004T_SUPPORT
  1449. #if ADE7953_SUPPORT
  1450. if (_sensors[i]->getID() == SENSOR_ADE7953_ID) {
  1451. ADE7953Sensor * sensor = (ADE7953Sensor *) _sensors[i];
  1452. if (getSetting("pwrResetE", false)) {
  1453. unsigned char dev_count = sensor->getTotalDevices();
  1454. for(unsigned char dev = 0; dev < dev_count; dev++) {
  1455. sensor->resetEnergy(dev);
  1456. delSetting({"eneTotal", dev});
  1457. }
  1458. _sensorResetTS();
  1459. }
  1460. }
  1461. #endif // ADE7953_SUPPORT
  1462. }
  1463. // Update filter sizes and reset energy if needed
  1464. {
  1465. const bool reset_saved_energy = 0 == _sensor_save_every;
  1466. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  1467. _magnitudes[i].filter->resize(_sensor_report_every);
  1468. if ((_magnitudes[i].type == MAGNITUDE_ENERGY) && reset_saved_energy) {
  1469. delSetting({"eneTotal", _magnitudes[i].global});
  1470. }
  1471. }
  1472. }
  1473. // Remove calibration values
  1474. // TODO: do not use settings for one-shot calibration
  1475. delSetting("snsResetCalibration");
  1476. delSetting("pwrExpectedP");
  1477. delSetting("pwrExpectedC");
  1478. delSetting("pwrExpectedV");
  1479. delSetting("pwrResetCalibration");
  1480. delSetting("pwrResetE");
  1481. saveSettings();
  1482. }
  1483. void _sensorReport(unsigned char index, double value) {
  1484. sensor_magnitude_t magnitude = _magnitudes[index];
  1485. unsigned char decimals = magnitude.decimals;
  1486. // XXX: ensure that the received 'value' will fit here
  1487. // dtostrf 2nd arg only controls leading zeroes and the
  1488. // 3rd is only for the part after the dot
  1489. char buffer[64];
  1490. dtostrf(value, 1, decimals, buffer);
  1491. #if BROKER_SUPPORT
  1492. SensorReportBroker::Publish(magnitudeTopic(magnitude.type), magnitude.global, value, buffer);
  1493. #endif
  1494. #if MQTT_SUPPORT
  1495. mqttSend(magnitudeTopicIndex(index).c_str(), buffer);
  1496. #if SENSOR_PUBLISH_ADDRESSES
  1497. char topic[32];
  1498. snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str());
  1499. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
  1500. mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
  1501. } else {
  1502. mqttSend(topic, magnitude.sensor->address(magnitude.local).c_str());
  1503. }
  1504. #endif // SENSOR_PUBLISH_ADDRESSES
  1505. #endif // MQTT_SUPPORT
  1506. #if THINGSPEAK_SUPPORT
  1507. tspkEnqueueMeasurement(index, buffer);
  1508. #endif
  1509. #if DOMOTICZ_SUPPORT
  1510. {
  1511. char key[15];
  1512. snprintf_P(key, sizeof(key), PSTR("dczMagnitude%d"), index);
  1513. if (magnitude.type == MAGNITUDE_HUMIDITY) {
  1514. int status;
  1515. if (value > 70) {
  1516. status = HUMIDITY_WET;
  1517. } else if (value > 45) {
  1518. status = HUMIDITY_COMFORTABLE;
  1519. } else if (value > 30) {
  1520. status = HUMIDITY_NORMAL;
  1521. } else {
  1522. status = HUMIDITY_DRY;
  1523. }
  1524. char status_buf[5];
  1525. itoa(status, status_buf, 10);
  1526. domoticzSend(key, buffer, status_buf);
  1527. } else {
  1528. domoticzSend(key, 0, buffer);
  1529. }
  1530. }
  1531. #endif // DOMOTICZ_SUPPORT
  1532. }
  1533. // -----------------------------------------------------------------------------
  1534. // Public
  1535. // -----------------------------------------------------------------------------
  1536. unsigned char sensorCount() {
  1537. return _sensors.size();
  1538. }
  1539. unsigned char magnitudeCount() {
  1540. return _magnitudes.size();
  1541. }
  1542. String magnitudeName(unsigned char index) {
  1543. if (index < _magnitudes.size()) {
  1544. sensor_magnitude_t magnitude = _magnitudes[index];
  1545. return magnitude.sensor->slot(magnitude.local);
  1546. }
  1547. return String();
  1548. }
  1549. unsigned char magnitudeType(unsigned char index) {
  1550. if (index < _magnitudes.size()) {
  1551. return int(_magnitudes[index].type);
  1552. }
  1553. return MAGNITUDE_NONE;
  1554. }
  1555. double magnitudeValue(unsigned char index) {
  1556. if (index < _magnitudes.size()) {
  1557. return _sensor_realtime ? _magnitudes[index].last : _magnitudes[index].reported;
  1558. }
  1559. return DBL_MIN;
  1560. }
  1561. unsigned char magnitudeIndex(unsigned char index) {
  1562. if (index < _magnitudes.size()) {
  1563. return int(_magnitudes[index].global);
  1564. }
  1565. return 0;
  1566. }
  1567. String magnitudeTopic(unsigned char type) {
  1568. char buffer[16] = {0};
  1569. if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer));
  1570. return String(buffer);
  1571. }
  1572. String magnitudeTopicIndex(unsigned char index) {
  1573. char topic[32] = {0};
  1574. if (index < _magnitudes.size()) {
  1575. sensor_magnitude_t magnitude = _magnitudes[index];
  1576. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
  1577. snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.global);
  1578. } else {
  1579. snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str());
  1580. }
  1581. }
  1582. return String(topic);
  1583. }
  1584. String magnitudeUnits(unsigned char type) {
  1585. char buffer[8] = {0};
  1586. if (type < MAGNITUDE_MAX) {
  1587. if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) {
  1588. strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer));
  1589. } else if (
  1590. (type == MAGNITUDE_ENERGY || type == MAGNITUDE_ENERGY_DELTA) &&
  1591. (_sensor_energy_units == ENERGY_KWH)) {
  1592. strncpy_P(buffer, magnitude_kwh, sizeof(buffer));
  1593. } else if (
  1594. (type == MAGNITUDE_POWER_ACTIVE ) && (_sensor_power_units == POWER_KILOWATTS)) {
  1595. strncpy_P(buffer, magnitude_kw, sizeof(buffer));
  1596. } else if (
  1597. (type == MAGNITUDE_POWER_APPARENT ) && (_sensor_power_units == POWER_KILOWATTS )) {
  1598. strncpy_P(buffer, magnitude_kVA, sizeof(buffer));
  1599. } else if (
  1600. (type == MAGNITUDE_POWER_REACTIVE) && (_sensor_power_units == POWER_KILOWATTS )) {
  1601. strncpy_P(buffer, magnitude_kVAR, sizeof(buffer));
  1602. } else {
  1603. strncpy_P(buffer, magnitude_units[type], sizeof(buffer));
  1604. }
  1605. }
  1606. return String(buffer);
  1607. }
  1608. // -----------------------------------------------------------------------------
  1609. void sensorSetup() {
  1610. // Backwards compatibility
  1611. moveSetting("eneTotal", "eneTotal0");
  1612. moveSetting("powerUnits", "pwrUnits");
  1613. moveSetting("energyUnits", "eneUnits");
  1614. // Update PZEM004T energy total across multiple devices
  1615. moveSettings("pzEneTotal", "eneTotal");
  1616. // Load sensors
  1617. _sensorLoad();
  1618. _sensorInit();
  1619. // Configure stored values
  1620. _sensorConfigure();
  1621. // Websockets
  1622. #if WEB_SUPPORT
  1623. wsRegister()
  1624. .onVisible(_sensorWebSocketOnVisible)
  1625. .onConnected(_sensorWebSocketOnConnected)
  1626. .onData(_sensorWebSocketSendData)
  1627. .onKeyCheck(_sensorWebSocketOnKeyCheck);
  1628. #endif
  1629. // API
  1630. #if API_SUPPORT
  1631. _sensorAPISetup();
  1632. #endif
  1633. // Terminal
  1634. #if TERMINAL_SUPPORT
  1635. _sensorInitCommands();
  1636. #endif
  1637. // Main callbacks
  1638. espurnaRegisterLoop(sensorLoop);
  1639. espurnaRegisterReload(_sensorConfigure);
  1640. }
  1641. void sensorLoop() {
  1642. // Check if we still have uninitialized sensors
  1643. static unsigned long last_init = 0;
  1644. if (!_sensors_ready) {
  1645. if (millis() - last_init > SENSOR_INIT_INTERVAL) {
  1646. last_init = millis();
  1647. _sensorInit();
  1648. }
  1649. }
  1650. if (_magnitudes.size() == 0) return;
  1651. // Tick hook
  1652. _sensorTick();
  1653. // Check if we should read new data
  1654. static unsigned long last_update = 0;
  1655. static unsigned long report_count = 0;
  1656. if (millis() - last_update > _sensor_read_interval) {
  1657. last_update = millis();
  1658. report_count = (report_count + 1) % _sensor_report_every;
  1659. double value_raw; // holds the raw value as the sensor returns it
  1660. double value_show; // holds the processed value applying units and decimals
  1661. double value_filtered; // holds the processed value applying filters, and the units and decimals
  1662. // Pre-read hook
  1663. _sensorPre();
  1664. // Get the first relay state
  1665. #if RELAY_SUPPORT && SENSOR_POWER_CHECK_STATUS
  1666. bool relay_off = (relayCount() == 1) && (relayStatus(0) == 0);
  1667. #endif
  1668. // Get readings
  1669. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  1670. sensor_magnitude_t magnitude = _magnitudes[i];
  1671. if (magnitude.sensor->status()) {
  1672. // -------------------------------------------------------------
  1673. // Instant value
  1674. // -------------------------------------------------------------
  1675. value_raw = magnitude.sensor->value(magnitude.local);
  1676. // Completely remove spurious values if relay is OFF
  1677. #if RELAY_SUPPORT && SENSOR_POWER_CHECK_STATUS
  1678. if (relay_off) {
  1679. if (magnitude.type == MAGNITUDE_POWER_ACTIVE ||
  1680. magnitude.type == MAGNITUDE_POWER_REACTIVE ||
  1681. magnitude.type == MAGNITUDE_POWER_APPARENT ||
  1682. magnitude.type == MAGNITUDE_CURRENT ||
  1683. magnitude.type == MAGNITUDE_ENERGY_DELTA
  1684. ) {
  1685. value_raw = 0;
  1686. }
  1687. }
  1688. #endif
  1689. _magnitudes[i].last = value_raw;
  1690. // -------------------------------------------------------------
  1691. // Processing (filters)
  1692. // -------------------------------------------------------------
  1693. magnitude.filter->add(value_raw);
  1694. // Special case for MovingAverageFilter
  1695. if (MAGNITUDE_COUNT == magnitude.type ||
  1696. MAGNITUDE_GEIGER_CPM ==magnitude. type ||
  1697. MAGNITUDE_GEIGER_SIEVERT == magnitude.type) {
  1698. value_raw = magnitude.filter->result();
  1699. }
  1700. // -------------------------------------------------------------
  1701. // Procesing (units and decimals)
  1702. // -------------------------------------------------------------
  1703. value_show = _magnitudeProcess(magnitude.type, magnitude.decimals, value_raw);
  1704. #if BROKER_SUPPORT
  1705. {
  1706. char buffer[64];
  1707. dtostrf(value_show, 1-sizeof(buffer), magnitude.decimals, buffer);
  1708. SensorReadBroker::Publish(magnitudeTopic(magnitude.type), magnitude.global, value_show, buffer);
  1709. }
  1710. #endif
  1711. // -------------------------------------------------------------
  1712. // Debug
  1713. // -------------------------------------------------------------
  1714. #if SENSOR_DEBUG
  1715. {
  1716. char buffer[64];
  1717. dtostrf(value_show, 1, magnitude.decimals, buffer);
  1718. DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"),
  1719. magnitude.sensor->slot(magnitude.local).c_str(),
  1720. magnitudeTopic(magnitude.type).c_str(),
  1721. buffer,
  1722. magnitudeUnits(magnitude.type).c_str()
  1723. );
  1724. }
  1725. #endif // SENSOR_DEBUG
  1726. // -------------------------------------------------------------
  1727. // Report
  1728. // (we do it every _sensor_report_every readings)
  1729. // -------------------------------------------------------------
  1730. bool report = (0 == report_count);
  1731. if ((MAGNITUDE_ENERGY == magnitude.type) && (magnitude.max_change > 0)) {
  1732. // for MAGNITUDE_ENERGY, filtered value is last value
  1733. report = (fabs(value_show - magnitude.reported) >= magnitude.max_change);
  1734. } // if ((MAGNITUDE_ENERGY == magnitude.type) && (magnitude.max_change > 0))
  1735. if (report) {
  1736. value_filtered = magnitude.filter->result();
  1737. value_filtered = _magnitudeProcess(magnitude.type, magnitude.decimals, value_filtered);
  1738. magnitude.filter->reset();
  1739. // Check if there is a minimum change threshold to report
  1740. if (fabs(value_filtered - magnitude.reported) >= magnitude.min_change) {
  1741. _magnitudes[i].reported = value_filtered;
  1742. _sensorReport(i, value_filtered);
  1743. } // if (fabs(value_filtered - magnitude.reported) >= magnitude.min_change)
  1744. // Persist total energy value
  1745. if (MAGNITUDE_ENERGY == magnitude.type) {
  1746. _sensorEnergyTotal(magnitude.global, value_raw);
  1747. }
  1748. } // if (report_count == 0)
  1749. } // if (magnitude.sensor->status())
  1750. } // for (unsigned char i=0; i<_magnitudes.size(); i++)
  1751. // Post-read hook
  1752. _sensorPost();
  1753. #if WEB_SUPPORT
  1754. wsPost(_sensorWebSocketSendData);
  1755. #endif
  1756. #if THINGSPEAK_SUPPORT
  1757. if (report_count == 0) tspkFlush();
  1758. #endif
  1759. }
  1760. }
  1761. #endif // SENSOR_SUPPORT