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.

252 lines
7.9 KiB

6 years ago
  1. // -----------------------------------------------------------------------------
  2. // BME280/BMP280 Sensor over I2C
  3. // Uses SparkFun BME280 library
  4. // Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
  5. // -----------------------------------------------------------------------------
  6. #if SENSOR_SUPPORT && BMX280_SUPPORT
  7. #pragma once
  8. #include "Arduino.h"
  9. #include "I2CSensor.h"
  10. #include <SparkFunBME280.h>
  11. #define BMX280_CHIP_BMP280 0x58
  12. #define BMX280_CHIP_BME280 0x60
  13. class BMX280Sensor : public I2CSensor {
  14. public:
  15. static unsigned char addresses[2];
  16. // ---------------------------------------------------------------------
  17. // Public
  18. // ---------------------------------------------------------------------
  19. BMX280Sensor(): I2CSensor() {
  20. _sensor_id = SENSOR_BMX280_ID;
  21. _bme = new BME280();
  22. }
  23. ~BMX280Sensor() {
  24. delete _bme;
  25. }
  26. // ---------------------------------------------------------------------
  27. // Sensor API
  28. // ---------------------------------------------------------------------
  29. // Initialization method, must be idempotent
  30. void begin() {
  31. if (!_dirty) return;
  32. _dirty = false;
  33. _chip = 0;
  34. // I2C auto-discover
  35. _address = _begin_i2c(_address, sizeof(BMX280Sensor::addresses), BMX280Sensor::addresses);
  36. if (_address == 0) return;
  37. // Init
  38. _init();
  39. }
  40. // Descriptive name of the sensor
  41. String description() {
  42. char buffer[20];
  43. snprintf(buffer, sizeof(buffer), "%s @ I2C (0x%02X)", _chip == BMX280_CHIP_BME280 ? "BME280" : "BMP280", _address);
  44. return String(buffer);
  45. }
  46. // Type for slot # index
  47. unsigned char type(unsigned char index) {
  48. if (index < _count) {
  49. _error = SENSOR_ERROR_OK;
  50. unsigned char i = 0;
  51. #if BMX280_TEMPERATURE > 0
  52. if (index == i++) return MAGNITUDE_TEMPERATURE;
  53. #endif
  54. #if BMX280_PRESSURE > 0
  55. if (index == i++) return MAGNITUDE_PRESSURE;
  56. #endif
  57. #if BMX280_HUMIDITY > 0
  58. if (_chip == BMX280_CHIP_BME280) {
  59. if (index == i) return MAGNITUDE_HUMIDITY;
  60. }
  61. #endif
  62. }
  63. _error = SENSOR_ERROR_OUT_OF_RANGE;
  64. return MAGNITUDE_NONE;
  65. }
  66. // Pre-read hook (usually to populate registers with up-to-date data)
  67. virtual void pre() {
  68. if (_chip == 0) {
  69. _error = SENSOR_ERROR_UNKNOWN_ID;
  70. return;
  71. }
  72. _error = SENSOR_ERROR_OK;
  73. #if BMX280_MODE == 1
  74. forceRead();
  75. #endif
  76. }
  77. // Current value for slot # index
  78. double value(unsigned char index) {
  79. if (index < _count) {
  80. _error = SENSOR_ERROR_OK;
  81. unsigned char i = 0;
  82. #if BMX280_TEMPERATURE > 0
  83. if (index == i++) return _bme->readTempC();
  84. #endif
  85. #if BMX280_PRESSURE > 0
  86. if (index == i++) return _bme->readFloatPressure() / 100;
  87. #endif
  88. #if BMX280_HUMIDITY > 0
  89. if (_chip == BMX280_CHIP_BME280) {
  90. if (index == i) return _bme->readFloatHumidity();
  91. }
  92. #endif
  93. }
  94. _error = SENSOR_ERROR_OUT_OF_RANGE;
  95. return 0;
  96. }
  97. // Load the configuration manifest
  98. static void manifest(JsonArray& sensors) {
  99. char buffer[10];
  100. JsonObject& sensor = sensors.createNestedObject();
  101. sensor["sensor_id"] = SENSOR_BMX280_ID;
  102. JsonArray& fields = sensor.createNestedArray("fields");
  103. {
  104. JsonObject& field = fields.createNestedObject();
  105. field["tag"] = UI_TAG_SELECT;
  106. field["name"] = "address";
  107. field["label"] = "Address";
  108. JsonArray& options = field.createNestedArray("options");
  109. {
  110. JsonObject& option = options.createNestedObject();
  111. option["name"] = "auto";
  112. option["value"] = 0;
  113. }
  114. for (unsigned char i=0; i< sizeof(BMX280Sensor::addresses); i++) {
  115. JsonObject& option = options.createNestedObject();
  116. snprintf(buffer, sizeof(buffer), "0x%02X", BMX280Sensor::addresses[i]);
  117. option["name"] = String(buffer);
  118. option["value"] = BMX280Sensor::addresses[i];
  119. }
  120. }
  121. };
  122. void getConfig(JsonObject& root) {
  123. root["sensor_id"] = _sensor_id;
  124. root["address"] = _address;
  125. };
  126. void setConfig(JsonObject& root) {
  127. if (root.containsKey("address")) setAddress(root["address"]);
  128. };
  129. protected:
  130. void _init() {
  131. _bme->settings.commInterface = I2C_MODE;
  132. _bme->settings.I2CAddress = _address;
  133. _bme->settings.runMode = BMX280_MODE;
  134. _bme->settings.tStandby = 0;
  135. _bme->settings.filter = 0;
  136. _bme->settings.tempOverSample = BMX280_TEMPERATURE;
  137. _bme->settings.pressOverSample = BMX280_PRESSURE;
  138. _bme->settings.humidOverSample = BMX280_HUMIDITY;
  139. // Fix when not measuring temperature, t_fine should have a sensible value
  140. if (BMX280_TEMPERATURE == 0) _bme->t_fine = 100000; // aprox 20ºC
  141. // Make sure sensor had enough time to turn on. BMX280 requires 2ms to start up
  142. delay(10);
  143. // Check sensor correctly initialized
  144. _chip = _bme->begin();
  145. if ((_chip != BMX280_CHIP_BME280) && (_chip != BMX280_CHIP_BMP280)) {
  146. _chip = 0;
  147. i2cReleaseLock(_address);
  148. _error = SENSOR_ERROR_UNKNOWN_ID;
  149. }
  150. #if BMX280_TEMPERATURE > 0
  151. ++_count;
  152. #endif
  153. #if BMX280_PRESSURE > 0
  154. ++_count;
  155. #endif
  156. #if BMX280_HUMIDITY > 0
  157. if (_chip == BMX280_CHIP_BME280) ++_count;
  158. #endif
  159. _measurement_delay = measurementTime();
  160. }
  161. unsigned long measurementTime() {
  162. // Measurement Time (as per BMX280 datasheet section 9.1)
  163. // T_max(ms) = 1.25
  164. // + (2.3 * T_oversampling)
  165. // + (2.3 * P_oversampling + 0.575)
  166. // + (2.4 * H_oversampling + 0.575)
  167. // ~ 9.3ms for current settings
  168. double t = 1.25;
  169. #if BMX280_TEMPERATURE > 0
  170. t += (2.3 * BMX280_TEMPERATURE);
  171. #endif
  172. #if BMX280_PRESSURE > 0
  173. t += (2.3 * BMX280_PRESSURE + 0.575);
  174. #endif
  175. #if BMX280_HUMIDITY > 0
  176. if (_chip == BMX280_CHIP_BME280) {
  177. t += (2.4 * BMX280_HUMIDITY + 0.575);
  178. }
  179. #endif
  180. return round(t + 1); // round up
  181. }
  182. void forceRead() {
  183. // We set the sensor in "forced mode" to force a reading.
  184. // After the reading the sensor will go back to sleep mode.
  185. uint8_t value = _bme->readRegister(BME280_CTRL_MEAS_REG);
  186. value = (value & 0xFC) + 0x01;
  187. _bme->writeRegister(BME280_CTRL_MEAS_REG, value);
  188. delay(_measurement_delay);
  189. }
  190. // ---------------------------------------------------------------------
  191. BME280 * _bme = NULL;
  192. unsigned char _chip;
  193. unsigned long _measurement_delay;
  194. };
  195. // Static inizializations
  196. unsigned char BMX280Sensor::addresses[2] = {0x76, 0x77};
  197. #endif // SENSOR_SUPPORT && BMX280_SUPPORT