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.

700 lines
22 KiB

7 years ago
7 years ago
7 years ago
  1. /*
  2. SENSOR MODULE
  3. Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if SENSOR_SUPPORT
  6. #include <vector>
  7. #include "filters/MaxFilter.h"
  8. #include "filters/MedianFilter.h"
  9. #include "filters/MovingAverageFilter.h"
  10. #include "sensors/BaseSensor.h"
  11. typedef struct {
  12. BaseSensor * sensor; // Sensor object
  13. BaseFilter * filter; // Filter object
  14. unsigned char local; // Local index in its provider
  15. unsigned char type; // Type of measurement
  16. unsigned char global; // Global index in its type
  17. double current; // Current (last) value, unfiltered
  18. double filtered; // Filtered (averaged) value
  19. double reported; // Last reported value
  20. double min_change; // Minimum value change to report
  21. } sensor_magnitude_t;
  22. std::vector<BaseSensor *> _sensors;
  23. std::vector<sensor_magnitude_t> _magnitudes;
  24. unsigned char _counts[MAGNITUDE_MAX];
  25. bool _sensor_realtime = API_REAL_TIME_VALUES;
  26. unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL;
  27. unsigned char _sensor_report_every = SENSOR_REPORT_EVERY;
  28. unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS;
  29. double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
  30. // -----------------------------------------------------------------------------
  31. // Private
  32. // -----------------------------------------------------------------------------
  33. String _magnitudeTopic(unsigned char type) {
  34. char buffer[16] = {0};
  35. if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer));
  36. return String(buffer);
  37. }
  38. unsigned char _magnitudeDecimals(unsigned char type) {
  39. if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type);
  40. return 0;
  41. }
  42. String _magnitudeUnits(unsigned char type) {
  43. char buffer[8] = {0};
  44. if (type < MAGNITUDE_MAX) {
  45. if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) {
  46. strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer));
  47. } else {
  48. strncpy_P(buffer, magnitude_units[type], sizeof(buffer));
  49. }
  50. }
  51. return String(buffer);
  52. }
  53. double _magnitudeProcess(unsigned char type, double value) {
  54. if (type == MAGNITUDE_TEMPERATURE) {
  55. if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32;
  56. value = value + _sensor_temperature_correction;
  57. }
  58. return roundTo(value, _magnitudeDecimals(type));
  59. }
  60. // -----------------------------------------------------------------------------
  61. #if WEB_SUPPORT
  62. void _sensorWebSocketSendData(JsonObject& root) {
  63. char buffer[10];
  64. bool hasTemperature = false;
  65. JsonArray& list = root.createNestedArray("magnitudes");
  66. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  67. sensor_magnitude_t magnitude = _magnitudes[i];
  68. unsigned char decimals = _magnitudeDecimals(magnitude.type);
  69. dtostrf(magnitude.current, 1-sizeof(buffer), decimals, buffer);
  70. JsonObject& element = list.createNestedObject();
  71. element["index"] = int(magnitude.global);
  72. element["type"] = int(magnitude.type);
  73. element["value"] = String(buffer);
  74. element["units"] = _magnitudeUnits(magnitude.type);
  75. element["description"] = magnitude.sensor->slot(magnitude.local);
  76. element["error"] = magnitude.sensor->error();
  77. if (magnitude.type == MAGNITUDE_TEMPERATURE) hasTemperature = true;
  78. }
  79. if (hasTemperature) root["temperatureVisible"] = 1;
  80. }
  81. void _sensorWebSocketStart(JsonObject& root) {
  82. for (unsigned char i=0; i<_sensors.size(); i++) {
  83. BaseSensor * sensor = _sensors[i];
  84. #if EMON_ANALOG_SUPPORT
  85. if (sensor->getID() == SENSOR_EMON_ANALOG_ID) {
  86. root["emonVisible"] = 1;
  87. root["pwrVoltage"] = ((EmonAnalogSensor *) sensor)->getVoltage();
  88. }
  89. #endif
  90. #if HLW8012_SUPPORT
  91. if (sensor->getID() == SENSOR_HLW8012_ID) {
  92. root["hlwVisible"] = 1;
  93. }
  94. #endif
  95. }
  96. if (_magnitudes.size() > 0) {
  97. root["sensorsVisible"] = 1;
  98. //root["apiRealTime"] = _sensor_realtime;
  99. root["tmpUnits"] = _sensor_temperature_units;
  100. root["tmpCorrection"] = _sensor_temperature_correction;
  101. root["snsRead"] = _sensor_read_interval / 1000;
  102. root["snsReport"] = _sensor_report_every;
  103. }
  104. /*
  105. // Sensors manifest
  106. JsonArray& manifest = root.createNestedArray("manifest");
  107. #if BMX280_SUPPORT
  108. BMX280Sensor::manifest(manifest);
  109. #endif
  110. // Sensors configuration
  111. JsonArray& sensors = root.createNestedArray("sensors");
  112. for (unsigned char i; i<_sensors.size(); i++) {
  113. JsonObject& sensor = sensors.createNestedObject();
  114. sensor["index"] = i;
  115. sensor["id"] = _sensors[i]->getID();
  116. _sensors[i]->getConfig(sensor);
  117. }
  118. */
  119. }
  120. void _sensorAPISetup() {
  121. for (unsigned char magnitude_id=0; magnitude_id<_magnitudes.size(); magnitude_id++) {
  122. sensor_magnitude_t magnitude = _magnitudes[magnitude_id];
  123. String topic = _magnitudeTopic(magnitude.type);
  124. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global);
  125. apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) {
  126. sensor_magnitude_t magnitude = _magnitudes[magnitude_id];
  127. unsigned char decimals = _magnitudeDecimals(magnitude.type);
  128. double value = _sensor_realtime ? magnitude.current : magnitude.filtered;
  129. dtostrf(value, 1-len, decimals, buffer);
  130. });
  131. }
  132. }
  133. #endif
  134. void _sensorTick() {
  135. for (unsigned char i=0; i<_sensors.size(); i++) {
  136. _sensors[i]->tick();
  137. }
  138. }
  139. void _sensorPre() {
  140. for (unsigned char i=0; i<_sensors.size(); i++) {
  141. _sensors[i]->pre();
  142. if (!_sensors[i]->status()) {
  143. DEBUG_MSG_P(PSTR("[SENSOR] Error reading data from %s (error: %d)\n"),
  144. _sensors[i]->description().c_str(),
  145. _sensors[i]->error()
  146. );
  147. }
  148. }
  149. }
  150. void _sensorPost() {
  151. for (unsigned char i=0; i<_sensors.size(); i++) {
  152. _sensors[i]->post();
  153. }
  154. }
  155. // -----------------------------------------------------------------------------
  156. // Sensor initialization
  157. // -----------------------------------------------------------------------------
  158. void _sensorInit() {
  159. #if ANALOG_SUPPORT
  160. {
  161. AnalogSensor * sensor = new AnalogSensor();
  162. _sensors.push_back(sensor);
  163. }
  164. #endif
  165. #if BH1750_SUPPORT
  166. {
  167. BH1750Sensor * sensor = new BH1750Sensor();
  168. sensor->setAddress(BH1750_ADDRESS);
  169. sensor->setMode(BH1750_MODE);
  170. _sensors.push_back(sensor);
  171. }
  172. #endif
  173. #if BMX280_SUPPORT
  174. {
  175. BMX280Sensor * sensor = new BMX280Sensor();
  176. sensor->setAddress(BMX280_ADDRESS);
  177. _sensors.push_back(sensor);
  178. }
  179. #endif
  180. #if DALLAS_SUPPORT
  181. {
  182. DallasSensor * sensor = new DallasSensor();
  183. sensor->setGPIO(DALLAS_PIN);
  184. _sensors.push_back(sensor);
  185. }
  186. #endif
  187. #if DHT_SUPPORT
  188. {
  189. DHTSensor * sensor = new DHTSensor();
  190. sensor->setGPIO(DHT_PIN);
  191. sensor->setType(DHT_TYPE);
  192. _sensors.push_back(sensor);
  193. }
  194. #endif
  195. #if DIGITAL_SUPPORT
  196. {
  197. DigitalSensor * sensor = new DigitalSensor();
  198. sensor->setGPIO(DIGITAL_PIN);
  199. sensor->setMode(DIGITAL_PIN_MODE);
  200. sensor->setDefault(DIGITAL_DEFAULT_STATE);
  201. _sensors.push_back(sensor);
  202. }
  203. #endif
  204. #if ECH1560_SUPPORT
  205. {
  206. ECH1560Sensor * sensor = new ECH1560Sensor();
  207. sensor->setCLK(ECH1560_CLK_PIN);
  208. sensor->setMISO(ECH1560_MISO_PIN);
  209. sensor->setInverted(ECH1560_INVERTED);
  210. _sensors.push_back(sensor);
  211. }
  212. #endif
  213. #if EMON_ADC121_SUPPORT
  214. {
  215. EmonADC121Sensor * sensor = new EmonADC121Sensor();
  216. sensor->setAddress(EMON_ADC121_I2C_ADDRESS);
  217. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  218. sensor->setReference(EMON_REFERENCE_VOLTAGE);
  219. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  220. _sensors.push_back(sensor);
  221. }
  222. #endif
  223. #if EMON_ADS1X15_SUPPORT
  224. {
  225. EmonADS1X15Sensor * sensor = new EmonADS1X15Sensor();
  226. sensor->setAddress(EMON_ADS1X15_I2C_ADDRESS);
  227. sensor->setType(EMON_ADS1X15_TYPE);
  228. sensor->setMask(EMON_ADS1X15_MASK);
  229. sensor->setGain(EMON_ADS1X15_GAIN);
  230. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  231. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  232. sensor->setCurrentRatio(1, EMON_CURRENT_RATIO);
  233. sensor->setCurrentRatio(2, EMON_CURRENT_RATIO);
  234. sensor->setCurrentRatio(3, EMON_CURRENT_RATIO);
  235. _sensors.push_back(sensor);
  236. }
  237. #endif
  238. #if EMON_ANALOG_SUPPORT
  239. {
  240. EmonAnalogSensor * sensor = new EmonAnalogSensor();
  241. sensor->setVoltage(EMON_MAINS_VOLTAGE);
  242. sensor->setReference(EMON_REFERENCE_VOLTAGE);
  243. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  244. _sensors.push_back(sensor);
  245. }
  246. #endif
  247. #if EVENTS_SUPPORT
  248. {
  249. EventSensor * sensor = new EventSensor();
  250. sensor->setGPIO(EVENTS_PIN);
  251. sensor->setMode(EVENTS_PIN_MODE);
  252. sensor->setDebounceTime(EVENTS_DEBOUNCE);
  253. sensor->setInterruptMode(EVENTS_INTERRUPT_MODE);
  254. _sensors.push_back(sensor);
  255. }
  256. #endif
  257. #if HLW8012_SUPPORT
  258. {
  259. HLW8012Sensor * sensor = new HLW8012Sensor();
  260. sensor->setSEL(HLW8012_SEL_PIN);
  261. sensor->setCF(HLW8012_CF_PIN);
  262. sensor->setCF1(HLW8012_CF1_PIN);
  263. sensor->setSELCurrent(HLW8012_SEL_CURRENT);
  264. _sensors.push_back(sensor);
  265. }
  266. #endif
  267. #if MHZ19_SUPPORT
  268. {
  269. MHZ19Sensor * sensor = new MHZ19Sensor();
  270. sensor->setRX(MHZ19_RX_PIN);
  271. sensor->setTX(MHZ19_TX_PIN);
  272. _sensors.push_back(sensor);
  273. }
  274. #endif
  275. #if PMSX003_SUPPORT
  276. {
  277. PMSX003Sensor * sensor = new PMSX003Sensor();
  278. sensor->setRX(PMS_RX_PIN);
  279. sensor->setTX(PMS_TX_PIN);
  280. _sensors.push_back(sensor);
  281. }
  282. #endif
  283. #if SHT3X_I2C_SUPPORT
  284. {
  285. SHT3XI2CSensor * sensor = new SHT3XI2CSensor();
  286. sensor->setAddress(SHT3X_I2C_ADDRESS);
  287. _sensors.push_back(sensor);
  288. }
  289. #endif
  290. #if SI7021_SUPPORT
  291. {
  292. SI7021Sensor * sensor = new SI7021Sensor();
  293. sensor->setAddress(SI7021_ADDRESS);
  294. _sensors.push_back(sensor);
  295. }
  296. #endif
  297. #if V9261F_SUPPORT
  298. {
  299. V9261FSensor * sensor = new V9261FSensor();
  300. sensor->setRX(V9261F_PIN);
  301. sensor->setInverted(V9261F_PIN_INVERSE);
  302. _sensors.push_back(sensor);
  303. }
  304. #endif
  305. }
  306. void _sensorConfigure() {
  307. double value;
  308. for (unsigned char i=0; i<_sensors.size(); i++) {
  309. #if EMON_ANALOG_SUPPORT
  310. if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) {
  311. EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
  312. if (value = getSetting("pwrExpectedP", 0).toInt() == 0) {
  313. value = getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat();
  314. if (value > 0) sensor->setCurrentRatio(0, value);
  315. } else {
  316. sensor->expectedPower(0, value);
  317. setSetting("pwrRatioC", sensor->getCurrentRatio(0));
  318. }
  319. if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
  320. sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
  321. delSetting("pwrRatioC");
  322. }
  323. sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
  324. }
  325. #endif // EMON_ANALOG_SUPPORT
  326. // Force sensor to reload config
  327. _sensors[i]->begin();
  328. #if HLW8012_SUPPORT
  329. if (_sensors[i]->getID() == SENSOR_HLW8012_ID) {
  330. HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i];
  331. if (value = getSetting("pwrExpectedC", 0).toFloat()) {
  332. sensor->expectedCurrent(value);
  333. setSetting("pwrRatioC", sensor->getCurrentRatio());
  334. } else {
  335. value = getSetting("pwrRatioC", 0).toFloat();
  336. if (value > 0) sensor->setCurrentRatio(value);
  337. }
  338. if (value = getSetting("pwrExpectedV", 0).toInt()) {
  339. sensor->expectedVoltage(value);
  340. setSetting("pwrRatioV", sensor->getVoltageRatio());
  341. } else {
  342. value = getSetting("pwrRatioV", 0).toFloat();
  343. if (value > 0) sensor->setVoltageRatio(value);
  344. }
  345. if (value = getSetting("pwrExpectedP", 0).toInt()) {
  346. sensor->expectedPower(value);
  347. setSetting("pwrRatioP", sensor->getPowerRatio());
  348. } else {
  349. value = getSetting("pwrRatioP", 0).toFloat();
  350. if (value > 0) sensor->setPowerRatio(value);
  351. }
  352. if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
  353. sensor->resetRatios();
  354. delSetting("pwrRatioC");
  355. delSetting("pwrRatioV");
  356. delSetting("pwrRatioP");
  357. }
  358. }
  359. #endif // HLW8012_SUPPORT
  360. }
  361. // General sensor settings
  362. _sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL).toInt(), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL);
  363. _sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY).toInt(), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY);
  364. _sensor_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
  365. _sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt();
  366. _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat();
  367. // Update filter sizes
  368. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  369. _magnitudes[i].filter->resize(_sensor_report_every);
  370. }
  371. // Save settings
  372. delSetting("pwrExpectedP");
  373. delSetting("pwrExpectedC");
  374. delSetting("pwrExpectedV");
  375. delSetting("pwrResetCalibration");
  376. //saveSettings();
  377. }
  378. void _magnitudesInit() {
  379. for (unsigned char i=0; i<_sensors.size(); i++) {
  380. BaseSensor * sensor = _sensors[i];
  381. DEBUG_MSG_P(PSTR("[SENSOR] %s\n"), sensor->description().c_str());
  382. if (sensor->error() != 0) DEBUG_MSG_P(PSTR("[SENSOR] -> ERROR %d\n"), sensor->error());
  383. for (unsigned char k=0; k<sensor->count(); k++) {
  384. unsigned char type = sensor->type(k);
  385. sensor_magnitude_t new_magnitude;
  386. new_magnitude.sensor = sensor;
  387. new_magnitude.local = k;
  388. new_magnitude.type = type;
  389. new_magnitude.global = _counts[type];
  390. new_magnitude.current = 0;
  391. new_magnitude.filtered = 0;
  392. new_magnitude.reported = 0;
  393. new_magnitude.min_change = 0;
  394. if (type == MAGNITUDE_DIGITAL) {
  395. new_magnitude.filter = new MaxFilter();
  396. } else if (type == MAGNITUDE_EVENTS) {
  397. new_magnitude.filter = new MovingAverageFilter();
  398. } else {
  399. new_magnitude.filter = new MedianFilter();
  400. }
  401. new_magnitude.filter->resize(_sensor_report_every);
  402. _magnitudes.push_back(new_magnitude);
  403. DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), _magnitudeTopic(type).c_str(), _counts[type]);
  404. _counts[type] = _counts[type] + 1;
  405. }
  406. }
  407. }
  408. // -----------------------------------------------------------------------------
  409. // Public
  410. // -----------------------------------------------------------------------------
  411. unsigned char sensorCount() {
  412. return _sensors.size();
  413. }
  414. unsigned char magnitudeCount() {
  415. return _magnitudes.size();
  416. }
  417. String magnitudeName(unsigned char index) {
  418. if (index < _magnitudes.size()) {
  419. sensor_magnitude_t magnitude = _magnitudes[index];
  420. return magnitude.sensor->slot(magnitude.local);
  421. }
  422. return String();
  423. }
  424. unsigned char magnitudeType(unsigned char index) {
  425. if (index < _magnitudes.size()) {
  426. return int(_magnitudes[index].type);
  427. }
  428. return MAGNITUDE_NONE;
  429. }
  430. unsigned char magnitudeIndex(unsigned char index) {
  431. if (index < _magnitudes.size()) {
  432. return int(_magnitudes[index].global);
  433. }
  434. return 0;
  435. }
  436. // -----------------------------------------------------------------------------
  437. void sensorSetup() {
  438. // Load sensors
  439. _sensorInit();
  440. // Configure stored values
  441. _sensorConfigure();
  442. // Load magnitudes
  443. _magnitudesInit();
  444. #if WEB_SUPPORT
  445. // Websockets
  446. wsOnSendRegister(_sensorWebSocketStart);
  447. wsOnSendRegister(_sensorWebSocketSendData);
  448. wsOnAfterParseRegister(_sensorConfigure);
  449. // API
  450. _sensorAPISetup();
  451. #endif
  452. }
  453. void sensorLoop() {
  454. static unsigned long last_update = 0;
  455. static unsigned long report_count = 0;
  456. if (_magnitudes.size() == 0) return;
  457. // Tick hook
  458. _sensorTick();
  459. // Check if we should read new data
  460. if (millis() - last_update > _sensor_read_interval) {
  461. last_update = millis();
  462. report_count = (report_count + 1) % _sensor_report_every;
  463. double current;
  464. double filtered;
  465. char buffer[64];
  466. // Pre-read hook
  467. _sensorPre();
  468. // Get readings
  469. for (unsigned char i=0; i<_magnitudes.size(); i++) {
  470. sensor_magnitude_t magnitude = _magnitudes[i];
  471. if (magnitude.sensor->status()) {
  472. unsigned char decimals = _magnitudeDecimals(magnitude.type);
  473. current = magnitude.sensor->value(magnitude.local);
  474. magnitude.filter->add(current);
  475. // Special case
  476. if (magnitude.type == MAGNITUDE_EVENTS) current = magnitude.filter->result();
  477. current = _magnitudeProcess(magnitude.type, current);
  478. _magnitudes[i].current = current;
  479. // Debug
  480. #if SENSOR_DEBUG
  481. {
  482. dtostrf(current, 1-sizeof(buffer), decimals, buffer);
  483. DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"),
  484. magnitude.sensor->slot(magnitude.local).c_str(),
  485. _magnitudeTopic(magnitude.type).c_str(),
  486. buffer,
  487. _magnitudeUnits(magnitude.type).c_str()
  488. );
  489. }
  490. #endif // SENSOR_DEBUG
  491. // Time to report (we do it every _sensor_report_every readings)
  492. if (report_count == 0) {
  493. filtered = magnitude.filter->result();
  494. magnitude.filter->reset();
  495. filtered = _magnitudeProcess(magnitude.type, filtered);
  496. _magnitudes[i].filtered = filtered;
  497. // Check if there is a minimum change threshold to report
  498. if (fabs(filtered - magnitude.reported) >= magnitude.min_change) {
  499. _magnitudes[i].reported = filtered;
  500. dtostrf(filtered, 1-sizeof(buffer), decimals, buffer);
  501. #if MQTT_SUPPORT
  502. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
  503. mqttSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
  504. } else {
  505. mqttSend(_magnitudeTopic(magnitude.type).c_str(), buffer);
  506. }
  507. #endif // MQTT_SUPPORT
  508. #if INFLUXDB_SUPPORT
  509. if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
  510. idbSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
  511. } else {
  512. idbSend(_magnitudeTopic(magnitude.type).c_str(), buffer);
  513. }
  514. #endif // INFLUXDB_SUPPORT
  515. #if THINGSPEAK_SUPPORT
  516. tspkEnqueueMeasurement(i, buffer);
  517. #endif
  518. #if DOMOTICZ_SUPPORT
  519. {
  520. char key[15];
  521. snprintf_P(key, sizeof(key), PSTR("dczMagnitude%d"), i);
  522. if (magnitude.type == MAGNITUDE_HUMIDITY) {
  523. int status;
  524. if (filtered > 70) {
  525. status = HUMIDITY_WET;
  526. } else if (filtered > 45) {
  527. status = HUMIDITY_COMFORTABLE;
  528. } else if (filtered > 30) {
  529. status = HUMIDITY_NORMAL;
  530. } else {
  531. status = HUMIDITY_DRY;
  532. }
  533. char status_buf[5];
  534. itoa(status, status_buf, 10);
  535. domoticzSend(key, buffer, status_buf);
  536. } else {
  537. domoticzSend(key, 0, buffer);
  538. }
  539. }
  540. #endif // DOMOTICZ_SUPPORT
  541. } // if (fabs(filtered - magnitude.reported) >= magnitude.min_change)
  542. } // if (report_count == 0)
  543. } // if (magnitude.sensor->status())
  544. } // for (unsigned char i=0; i<_magnitudes.size(); i++)
  545. // Post-read hook
  546. _sensorPost();
  547. #if WEB_SUPPORT
  548. wsSend(_sensorWebSocketSendData);
  549. #endif
  550. #if THINGSPEAK_SUPPORT
  551. if (report_count == 0) tspkFlush();
  552. #endif
  553. }
  554. }
  555. #endif // SENSOR_SUPPORT