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.

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