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.

247 lines
7.8 KiB

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