xsns_07_sht1x.ino 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. xsns_07_sht1x.ino - SHT1x temperature and sensor support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef USE_I2C
  16. #ifdef USE_SHT
  17. /*********************************************************************************************\
  18. * SHT1x - Temperature and Humidy
  19. *
  20. * Reading temperature and humidity takes about 320 milliseconds!
  21. * Source: Marinus vd Broek https://github.com/ESP8266nu/ESPEasy
  22. *
  23. * I2C Address: None
  24. \*********************************************************************************************/
  25. #define XSNS_07 7
  26. enum {
  27. SHT1X_CMD_MEASURE_TEMP = B00000011,
  28. SHT1X_CMD_MEASURE_RH = B00000101,
  29. SHT1X_CMD_SOFT_RESET = B00011110
  30. };
  31. uint8_t sht_sda_pin;
  32. uint8_t sht_scl_pin;
  33. uint8_t sht_type = 0;
  34. char sht_types[] = "SHT1X";
  35. uint8_t sht_valid = 0;
  36. float sht_temperature = 0;
  37. float sht_humidity = 0;
  38. boolean ShtReset(void)
  39. {
  40. pinMode(sht_sda_pin, INPUT_PULLUP);
  41. pinMode(sht_scl_pin, OUTPUT);
  42. delay(11);
  43. for (byte i = 0; i < 9; i++) {
  44. digitalWrite(sht_scl_pin, HIGH);
  45. digitalWrite(sht_scl_pin, LOW);
  46. }
  47. boolean success = ShtSendCommand(SHT1X_CMD_SOFT_RESET);
  48. delay(11);
  49. return success;
  50. }
  51. boolean ShtSendCommand(const byte cmd)
  52. {
  53. pinMode(sht_sda_pin, OUTPUT);
  54. // Transmission Start sequence
  55. digitalWrite(sht_sda_pin, HIGH);
  56. digitalWrite(sht_scl_pin, HIGH);
  57. digitalWrite(sht_sda_pin, LOW);
  58. digitalWrite(sht_scl_pin, LOW);
  59. digitalWrite(sht_scl_pin, HIGH);
  60. digitalWrite(sht_sda_pin, HIGH);
  61. digitalWrite(sht_scl_pin, LOW);
  62. // Send the command (address must be 000b)
  63. shiftOut(sht_sda_pin, sht_scl_pin, MSBFIRST, cmd);
  64. // Wait for ACK
  65. boolean ackerror = false;
  66. digitalWrite(sht_scl_pin, HIGH);
  67. pinMode(sht_sda_pin, INPUT_PULLUP);
  68. if (digitalRead(sht_sda_pin) != LOW) {
  69. ackerror = true;
  70. }
  71. digitalWrite(sht_scl_pin, LOW);
  72. delayMicroseconds(1); // Give the sensor time to release the data line
  73. if (digitalRead(sht_sda_pin) != HIGH) {
  74. ackerror = true;
  75. }
  76. if (ackerror) {
  77. sht_type = 0;
  78. AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_SHT1 D_SENSOR_DID_NOT_ACK_COMMAND));
  79. }
  80. return (!ackerror);
  81. }
  82. boolean ShtAwaitResult(void)
  83. {
  84. // Maximum 320ms for 14 bit measurement
  85. for (byte i = 0; i < 16; i++) {
  86. if (LOW == digitalRead(sht_sda_pin)) {
  87. return true;
  88. }
  89. delay(20);
  90. }
  91. AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_SHT1 D_SENSOR_BUSY));
  92. sht_type = 0;
  93. return false;
  94. }
  95. int ShtReadData(void)
  96. {
  97. int val = 0;
  98. // Read most significant byte
  99. val = shiftIn(sht_sda_pin, sht_scl_pin, 8);
  100. val <<= 8;
  101. // Send ACK
  102. pinMode(sht_sda_pin, OUTPUT);
  103. digitalWrite(sht_sda_pin, LOW);
  104. digitalWrite(sht_scl_pin, HIGH);
  105. digitalWrite(sht_scl_pin, LOW);
  106. pinMode(sht_sda_pin, INPUT_PULLUP);
  107. // Read least significant byte
  108. val |= shiftIn(sht_sda_pin, sht_scl_pin, 8);
  109. // Keep DATA pin high to skip CRC
  110. digitalWrite(sht_scl_pin, HIGH);
  111. digitalWrite(sht_scl_pin, LOW);
  112. return val;
  113. }
  114. boolean ShtRead(void)
  115. {
  116. if (sht_valid) { sht_valid--; }
  117. if (!ShtReset()) { return false; }
  118. if (!ShtSendCommand(SHT1X_CMD_MEASURE_TEMP)) { return false; }
  119. if (!ShtAwaitResult()) { return false; }
  120. float tempRaw = ShtReadData();
  121. if (!ShtSendCommand(SHT1X_CMD_MEASURE_RH)) { return false; }
  122. if (!ShtAwaitResult()) { return false; }
  123. float humRaw = ShtReadData();
  124. // Temperature conversion coefficients from SHT1X datasheet for version 4
  125. const float d1 = -39.7; // 3.5V
  126. const float d2 = 0.01; // 14-bit
  127. sht_temperature = d1 + (tempRaw * d2);
  128. const float c1 = -2.0468;
  129. const float c2 = 0.0367;
  130. const float c3 = -1.5955E-6;
  131. const float t1 = 0.01;
  132. const float t2 = 0.00008;
  133. float rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw;
  134. sht_humidity = (sht_temperature - 25) * (t1 + t2 * humRaw) + rhLinear;
  135. sht_temperature = ConvertTemp(sht_temperature);
  136. SetGlobalValues(sht_temperature, sht_humidity);
  137. sht_valid = SENSOR_MAX_MISS;
  138. return true;
  139. }
  140. /********************************************************************************************/
  141. void ShtDetect(void)
  142. {
  143. if (sht_type) {
  144. return;
  145. }
  146. sht_sda_pin = pin[GPIO_I2C_SDA];
  147. sht_scl_pin = pin[GPIO_I2C_SCL];
  148. if (ShtRead()) {
  149. sht_type = 1;
  150. AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_SHT1X_FOUND));
  151. } else {
  152. Wire.begin(sht_sda_pin, sht_scl_pin);
  153. sht_type = 0;
  154. }
  155. }
  156. void ShtEverySecond(void)
  157. {
  158. if (sht_type && !(uptime %4)) { // Update every 4 seconds
  159. // 344mS
  160. if (!ShtRead()) {
  161. AddLogMissed(sht_types, sht_valid);
  162. // if (!sht_valid) { sht_type = 0; }
  163. }
  164. }
  165. }
  166. void ShtShow(boolean json)
  167. {
  168. if (sht_valid) {
  169. char temperature[33];
  170. dtostrfd(sht_temperature, Settings.flag2.temperature_resolution, temperature);
  171. char humidity[33];
  172. dtostrfd(sht_humidity, Settings.flag2.humidity_resolution, humidity);
  173. if (json) {
  174. snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, sht_types, temperature, humidity);
  175. #ifdef USE_DOMOTICZ
  176. if (0 == tele_period) {
  177. DomoticzTempHumSensor(temperature, humidity);
  178. }
  179. #endif // USE_DOMOTICZ
  180. #ifdef USE_KNX
  181. if (0 == tele_period) {
  182. KnxSensor(KNX_TEMPERATURE, sht_temperature);
  183. KnxSensor(KNX_HUMIDITY, sht_humidity);
  184. }
  185. #endif // USE_KNX
  186. #ifdef USE_WEBSERVER
  187. } else {
  188. snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, sht_types, temperature, TempUnit());
  189. snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, sht_types, humidity);
  190. #endif // USE_WEBSERVER
  191. }
  192. }
  193. }
  194. /*********************************************************************************************\
  195. * Interface
  196. \*********************************************************************************************/
  197. boolean Xsns07(byte function)
  198. {
  199. boolean result = false;
  200. if (i2c_flg) {
  201. switch (function) {
  202. // case FUNC_PREP_BEFORE_TELEPERIOD: // As this is not a real I2C device it may interfere with other sensors
  203. case FUNC_INIT: // Move detection to restart only removing interference
  204. ShtDetect();
  205. break;
  206. case FUNC_EVERY_SECOND:
  207. ShtEverySecond();
  208. break;
  209. case FUNC_JSON_APPEND:
  210. ShtShow(1);
  211. break;
  212. #ifdef USE_WEBSERVER
  213. case FUNC_WEB_APPEND:
  214. ShtShow(0);
  215. break;
  216. #endif // USE_WEBSERVER
  217. }
  218. }
  219. return result;
  220. }
  221. #endif // USE_SHT
  222. #endif // USE_I2C