EnvironmentSensorManager.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. #include "EnvironmentSensorManager.h"
  2. #if ENV_PIN_SDA && ENV_PIN_SCL
  3. #define TELEM_WIRE &Wire1 // Use Wire1 as the I2C bus for Environment Sensors
  4. #else
  5. #define TELEM_WIRE &Wire // Use default I2C bus for Environment Sensors
  6. #endif
  7. #ifdef ENV_INCLUDE_BME680
  8. #ifndef TELEM_BME680_ADDRESS
  9. #define TELEM_BME680_ADDRESS 0x76
  10. #endif
  11. #define TELEM_BME680_SEALEVELPRESSURE_HPA (1013.25)
  12. #include <Adafruit_BME680.h>
  13. static Adafruit_BME680 BME680(TELEM_WIRE);
  14. #endif
  15. #ifdef ENV_INCLUDE_BMP085
  16. #define TELEM_BMP085_SEALEVELPRESSURE_HPA (1013.25)
  17. #include <Adafruit_BMP085.h>
  18. static Adafruit_BMP085 BMP085;
  19. #endif
  20. #if ENV_INCLUDE_AHTX0
  21. #define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address
  22. #include <Adafruit_AHTX0.h>
  23. static Adafruit_AHTX0 AHTX0;
  24. #endif
  25. #if ENV_INCLUDE_BME280
  26. #ifndef TELEM_BME280_ADDRESS
  27. #define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address
  28. #endif
  29. #define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level
  30. #include <Adafruit_BME280.h>
  31. static Adafruit_BME280 BME280;
  32. #endif
  33. #if ENV_INCLUDE_BMP280
  34. #ifndef TELEM_BMP280_ADDRESS
  35. #define TELEM_BMP280_ADDRESS 0x76 // BMP280 environmental sensor I2C address
  36. #endif
  37. #define TELEM_BMP280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level
  38. #include <Adafruit_BMP280.h>
  39. static Adafruit_BMP280 BMP280(TELEM_WIRE);
  40. #endif
  41. #if ENV_INCLUDE_SHTC3
  42. #include <Adafruit_SHTC3.h>
  43. static Adafruit_SHTC3 SHTC3;
  44. #endif
  45. #if ENV_INCLUDE_SHT4X
  46. #define TELEM_SHT4X_ADDRESS 0x44 //0x44 - 0x46
  47. #include <SensirionI2cSht4x.h>
  48. static SensirionI2cSht4x SHT4X;
  49. #endif
  50. #if ENV_INCLUDE_LPS22HB
  51. #include <Arduino_LPS22HB.h>
  52. LPS22HBClass LPS22HB(*TELEM_WIRE);
  53. #endif
  54. #if ENV_INCLUDE_INA3221
  55. #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address
  56. #define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts
  57. #define TELEM_INA3221_NUM_CHANNELS 3
  58. #include <Adafruit_INA3221.h>
  59. static Adafruit_INA3221 INA3221;
  60. #endif
  61. #if ENV_INCLUDE_INA219
  62. #define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address
  63. #include <Adafruit_INA219.h>
  64. static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS);
  65. #endif
  66. #if ENV_INCLUDE_INA260
  67. #define TELEM_INA260_ADDRESS 0x41 // INA260 single channel current sensor I2C address
  68. #include <Adafruit_INA260.h>
  69. static Adafruit_INA260 INA260;
  70. #endif
  71. #if ENV_INCLUDE_INA226
  72. #define TELEM_INA226_ADDRESS 0x44
  73. #define TELEM_INA226_SHUNT_VALUE 0.100
  74. #define TELEM_INA226_MAX_AMP 0.8
  75. #include <INA226.h>
  76. static INA226 INA226(TELEM_INA226_ADDRESS, TELEM_WIRE);
  77. #endif
  78. #if ENV_INCLUDE_MLX90614
  79. #define TELEM_MLX90614_ADDRESS 0x5A // MLX90614 IR temperature sensor I2C address
  80. #include <Adafruit_MLX90614.h>
  81. static Adafruit_MLX90614 MLX90614;
  82. #endif
  83. #if ENV_INCLUDE_VL53L0X
  84. #define TELEM_VL53L0X_ADDRESS 0x29 // VL53L0X time-of-flight distance sensor I2C address
  85. #include <Adafruit_VL53L0X.h>
  86. static Adafruit_VL53L0X VL53L0X;
  87. #endif
  88. #if ENV_INCLUDE_RAK12035
  89. #define TELEM_RAK12035_ADDRESS 0x20 // RAK12035 Soil Moisture sensor I2C address
  90. #include "RAK12035_SoilMoisture.h"
  91. static RAK12035_SoilMoisture RAK12035;
  92. #endif
  93. #if ENV_INCLUDE_GPS && defined(RAK_BOARD) && !defined(RAK_WISMESH_TAG)
  94. #define RAK_WISBLOCK_GPS
  95. #endif
  96. #ifdef RAK_WISBLOCK_GPS
  97. static uint32_t gpsResetPin = 0;
  98. static bool i2cGPSFlag = false;
  99. static bool serialGPSFlag = false;
  100. #define TELEM_RAK12500_ADDRESS 0x42 //RAK12500 Ublox GPS via i2c
  101. #include <SparkFun_u-blox_GNSS_Arduino_Library.h>
  102. static SFE_UBLOX_GNSS ublox_GNSS;
  103. class RAK12500LocationProvider : public LocationProvider {
  104. long _lat = 0;
  105. long _lng = 0;
  106. long _alt = 0;
  107. int _sats = 0;
  108. long _epoch = 0;
  109. bool _fix = false;
  110. public:
  111. long getLatitude() override { return _lat; }
  112. long getLongitude() override { return _lng; }
  113. long getAltitude() override { return _alt; }
  114. long satellitesCount() override { return _sats; }
  115. bool isValid() override { return _fix; }
  116. long getTimestamp() override { return _epoch; }
  117. void sendSentence(const char * sentence) override { }
  118. void reset() override { }
  119. void begin() override { }
  120. void stop() override { }
  121. void loop() override {
  122. if (ublox_GNSS.getGnssFixOk(8)) {
  123. _fix = true;
  124. _lat = ublox_GNSS.getLatitude(2) / 10;
  125. _lng = ublox_GNSS.getLongitude(2) / 10;
  126. _alt = ublox_GNSS.getAltitude(2);
  127. _sats = ublox_GNSS.getSIV(2);
  128. } else {
  129. _fix = false;
  130. }
  131. _epoch = ublox_GNSS.getUnixEpoch(2);
  132. }
  133. bool isEnabled() override { return true; }
  134. };
  135. static RAK12500LocationProvider RAK12500_provider;
  136. #endif
  137. bool EnvironmentSensorManager::begin() {
  138. #if ENV_INCLUDE_GPS
  139. #ifdef RAK_WISBLOCK_GPS
  140. rakGPSInit(); //probe base board/sockets for GPS
  141. #else
  142. initBasicGPS();
  143. #endif
  144. #endif
  145. #if ENV_PIN_SDA && ENV_PIN_SCL
  146. #ifdef NRF52_PLATFORM
  147. Wire1.setPins(ENV_PIN_SDA, ENV_PIN_SCL);
  148. Wire1.setClock(100000);
  149. Wire1.begin();
  150. #else
  151. Wire1.begin(ENV_PIN_SDA, ENV_PIN_SCL, 100000);
  152. #endif
  153. MESH_DEBUG_PRINTLN("Second I2C initialized on pins SDA: %d SCL: %d", ENV_PIN_SDA, ENV_PIN_SCL);
  154. #endif
  155. #if ENV_INCLUDE_AHTX0
  156. if (AHTX0.begin(TELEM_WIRE, 0, TELEM_AHTX_ADDRESS)) {
  157. MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS);
  158. AHTX0_initialized = true;
  159. } else {
  160. AHTX0_initialized = false;
  161. MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS);
  162. }
  163. #endif
  164. #if ENV_INCLUDE_BME680
  165. if (BME680.begin(TELEM_BME680_ADDRESS)) {
  166. MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS);
  167. BME680_initialized = true;
  168. } else {
  169. BME680_initialized = false;
  170. MESH_DEBUG_PRINTLN("BME680 was not found at I2C address %02X", TELEM_BME680_ADDRESS);
  171. }
  172. #endif
  173. #if ENV_INCLUDE_BME280
  174. if (BME280.begin(TELEM_BME280_ADDRESS, TELEM_WIRE)) {
  175. MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS);
  176. MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID());
  177. // Reduce self-heating: single-shot conversions, light oversampling, long standby.
  178. BME280.setSampling(Adafruit_BME280::MODE_FORCED,
  179. Adafruit_BME280::SAMPLING_X1, // temperature
  180. Adafruit_BME280::SAMPLING_X1, // pressure
  181. Adafruit_BME280::SAMPLING_X1, // humidity
  182. Adafruit_BME280::FILTER_OFF,
  183. Adafruit_BME280::STANDBY_MS_1000);
  184. BME280_initialized = true;
  185. } else {
  186. BME280_initialized = false;
  187. MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS);
  188. }
  189. #endif
  190. #if ENV_INCLUDE_BMP280
  191. if (BMP280.begin(TELEM_BMP280_ADDRESS)) {
  192. MESH_DEBUG_PRINTLN("Found BMP280 at address: %02X", TELEM_BMP280_ADDRESS);
  193. MESH_DEBUG_PRINTLN("BMP sensor ID: %02X", BMP280.sensorID());
  194. BMP280_initialized = true;
  195. } else {
  196. BMP280_initialized = false;
  197. MESH_DEBUG_PRINTLN("BMP280 was not found at I2C address %02X", TELEM_BMP280_ADDRESS);
  198. }
  199. #endif
  200. #if ENV_INCLUDE_SHTC3
  201. if (SHTC3.begin(TELEM_WIRE)) {
  202. MESH_DEBUG_PRINTLN("Found sensor: SHTC3");
  203. SHTC3_initialized = true;
  204. } else {
  205. SHTC3_initialized = false;
  206. MESH_DEBUG_PRINTLN("SHTC3 was not found at I2C address %02X", 0x70);
  207. }
  208. #endif
  209. #if ENV_INCLUDE_SHT4X
  210. SHT4X.begin(*TELEM_WIRE, TELEM_SHT4X_ADDRESS);
  211. uint32_t serialNumber = 0;
  212. int16_t sht4x_error;
  213. sht4x_error = SHT4X.serialNumber(serialNumber);
  214. if (sht4x_error == 0) {
  215. MESH_DEBUG_PRINTLN("Found SHT4X at address: %02X", TELEM_SHT4X_ADDRESS);
  216. SHT4X_initialized = true;
  217. } else {
  218. SHT4X_initialized = false;
  219. MESH_DEBUG_PRINTLN("SHT4X was not found at I2C address %02X", TELEM_SHT4X_ADDRESS);
  220. }
  221. #endif
  222. #if ENV_INCLUDE_LPS22HB
  223. if (LPS22HB.begin()) {
  224. MESH_DEBUG_PRINTLN("Found sensor: LPS22HB");
  225. LPS22HB_initialized = true;
  226. } else {
  227. LPS22HB_initialized = false;
  228. MESH_DEBUG_PRINTLN("LPS22HB was not found at I2C address %02X", 0x5C);
  229. }
  230. #endif
  231. #if ENV_INCLUDE_INA3221
  232. if (INA3221.begin(TELEM_INA3221_ADDRESS, TELEM_WIRE)) {
  233. MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS);
  234. MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID());
  235. for(int i = 0; i < 3; i++) {
  236. INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE);
  237. }
  238. INA3221_initialized = true;
  239. } else {
  240. INA3221_initialized = false;
  241. MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS);
  242. }
  243. #endif
  244. #if ENV_INCLUDE_INA219
  245. if (INA219.begin(TELEM_WIRE)) {
  246. MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS);
  247. INA219_initialized = true;
  248. } else {
  249. INA219_initialized = false;
  250. MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS);
  251. }
  252. #endif
  253. #if ENV_INCLUDE_INA260
  254. if (INA260.begin(TELEM_INA260_ADDRESS, TELEM_WIRE)) {
  255. MESH_DEBUG_PRINTLN("Found INA260 at address: %02X", TELEM_INA260_ADDRESS);
  256. INA260_initialized = true;
  257. } else {
  258. INA260_initialized = false;
  259. MESH_DEBUG_PRINTLN("INA260 was not found at I2C address %02X", TELEM_INA260_ADDRESS);
  260. }
  261. #endif
  262. #if ENV_INCLUDE_INA226
  263. if (INA226.begin()) {
  264. MESH_DEBUG_PRINTLN("Found INA226 at address: %02X", TELEM_INA226_ADDRESS);
  265. INA226.setMaxCurrentShunt(TELEM_INA226_MAX_AMP, TELEM_INA226_SHUNT_VALUE);
  266. INA226_initialized = true;
  267. } else {
  268. INA226_initialized = false;
  269. MESH_DEBUG_PRINTLN("INA226 was not found at I2C address %02X", TELEM_INA226_ADDRESS);
  270. }
  271. #endif
  272. #if ENV_INCLUDE_MLX90614
  273. if (MLX90614.begin(TELEM_MLX90614_ADDRESS, TELEM_WIRE)) {
  274. MESH_DEBUG_PRINTLN("Found MLX90614 at address: %02X", TELEM_MLX90614_ADDRESS);
  275. MLX90614_initialized = true;
  276. } else {
  277. MLX90614_initialized = false;
  278. MESH_DEBUG_PRINTLN("MLX90614 was not found at I2C address %02X", TELEM_MLX90614_ADDRESS);
  279. }
  280. #endif
  281. #if ENV_INCLUDE_VL53L0X
  282. if (VL53L0X.begin(TELEM_VL53L0X_ADDRESS, false, TELEM_WIRE)) {
  283. MESH_DEBUG_PRINTLN("Found VL53L0X at address: %02X", TELEM_VL53L0X_ADDRESS);
  284. VL53L0X_initialized = true;
  285. } else {
  286. VL53L0X_initialized = false;
  287. MESH_DEBUG_PRINTLN("VL53L0X was not found at I2C address %02X", TELEM_VL53L0X_ADDRESS);
  288. }
  289. #endif
  290. #if ENV_INCLUDE_BMP085
  291. // First argument is MODE (aka oversampling)
  292. // choose ULTRALOWPOWER
  293. if (BMP085.begin(0, TELEM_WIRE)) {
  294. MESH_DEBUG_PRINTLN("Found sensor BMP085");
  295. BMP085_initialized = true;
  296. } else {
  297. BMP085_initialized = false;
  298. MESH_DEBUG_PRINTLN("BMP085 was not found at I2C address %02X", 0x77);
  299. }
  300. #endif
  301. #if ENV_INCLUDE_RAK12035
  302. RAK12035.setup(*TELEM_WIRE);
  303. if (RAK12035.begin(TELEM_RAK12035_ADDRESS)) {
  304. MESH_DEBUG_PRINTLN("Found sensor RAK12035 at address: %02X", TELEM_RAK12035_ADDRESS);
  305. RAK12035_initialized = true;
  306. } else {
  307. RAK12035_initialized = false;
  308. MESH_DEBUG_PRINTLN("RAK12035 was not found at I2C address %02X", TELEM_RAK12035_ADDRESS);
  309. }
  310. #endif
  311. return true;
  312. }
  313. bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
  314. next_available_channel = TELEM_CHANNEL_SELF + 1;
  315. if (requester_permissions & TELEM_PERM_LOCATION && gps_active) {
  316. telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); // allow lat/lon via telemetry even if no GPS is detected
  317. }
  318. if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
  319. #if ENV_INCLUDE_AHTX0
  320. if (AHTX0_initialized) {
  321. sensors_event_t humidity, temp;
  322. AHTX0.getEvent(&humidity, &temp);
  323. telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature);
  324. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
  325. }
  326. #endif
  327. #if ENV_INCLUDE_BME680
  328. if (BME680_initialized) {
  329. if (BME680.performReading()) {
  330. telemetry.addTemperature(TELEM_CHANNEL_SELF, BME680.temperature);
  331. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME680.humidity);
  332. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME680.pressure / 100);
  333. telemetry.addAltitude(TELEM_CHANNEL_SELF, 44330.0 * (1.0 - pow((BME680.pressure / 100) / TELEM_BME680_SEALEVELPRESSURE_HPA, 0.1903)));
  334. telemetry.addAnalogInput(next_available_channel, BME680.gas_resistance);
  335. next_available_channel++;
  336. }
  337. }
  338. #endif
  339. #if ENV_INCLUDE_BME280
  340. if (BME280_initialized) {
  341. if (BME280.takeForcedMeasurement()) { // trigger a fresh reading in forced mode
  342. telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature());
  343. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity());
  344. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure()/100);
  345. telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA));
  346. }
  347. }
  348. #endif
  349. #if ENV_INCLUDE_BMP280
  350. if (BMP280_initialized) {
  351. telemetry.addTemperature(TELEM_CHANNEL_SELF, BMP280.readTemperature());
  352. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BMP280.readPressure()/100);
  353. telemetry.addAltitude(TELEM_CHANNEL_SELF, BMP280.readAltitude(TELEM_BMP280_SEALEVELPRESSURE_HPA));
  354. }
  355. #endif
  356. #if ENV_INCLUDE_SHTC3
  357. if (SHTC3_initialized) {
  358. sensors_event_t humidity, temp;
  359. SHTC3.getEvent(&humidity, &temp);
  360. telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature);
  361. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
  362. }
  363. #endif
  364. #if ENV_INCLUDE_SHT4X
  365. if (SHT4X_initialized) {
  366. float sht4x_humidity, sht4x_temperature;
  367. int16_t sht4x_error;
  368. sht4x_error = SHT4X.measureLowestPrecision(sht4x_temperature, sht4x_humidity);
  369. if (sht4x_error == 0) {
  370. telemetry.addTemperature(TELEM_CHANNEL_SELF, sht4x_temperature);
  371. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, sht4x_humidity);
  372. }
  373. }
  374. #endif
  375. #if ENV_INCLUDE_LPS22HB
  376. if (LPS22HB_initialized) {
  377. telemetry.addTemperature(TELEM_CHANNEL_SELF, LPS22HB.readTemperature());
  378. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, LPS22HB.readPressure() * 10); // convert kPa to hPa
  379. }
  380. #endif
  381. #if ENV_INCLUDE_INA3221
  382. if (INA3221_initialized) {
  383. for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) {
  384. // add only enabled INA3221 channels to telemetry
  385. if (INA3221.isChannelEnabled(i)) {
  386. float voltage = INA3221.getBusVoltage(i);
  387. float current = INA3221.getCurrentAmps(i);
  388. telemetry.addVoltage(next_available_channel, voltage);
  389. telemetry.addCurrent(next_available_channel, current);
  390. telemetry.addPower(next_available_channel, voltage * current);
  391. next_available_channel++;
  392. }
  393. }
  394. }
  395. #endif
  396. #if ENV_INCLUDE_INA219
  397. if (INA219_initialized) {
  398. telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V());
  399. telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000);
  400. telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000);
  401. next_available_channel++;
  402. }
  403. #endif
  404. #if ENV_INCLUDE_INA260
  405. if (INA260_initialized) {
  406. telemetry.addVoltage(next_available_channel, INA260.readBusVoltage() / 1000);
  407. telemetry.addCurrent(next_available_channel, INA260.readCurrent() / 1000);
  408. telemetry.addPower(next_available_channel, INA260.readPower() / 1000);
  409. next_available_channel++;
  410. }
  411. #endif
  412. #if ENV_INCLUDE_INA226
  413. if (INA226_initialized) {
  414. telemetry.addVoltage(next_available_channel, INA226.getBusVoltage());
  415. telemetry.addCurrent(next_available_channel, INA226.getCurrent_mA() / 1000.0);
  416. telemetry.addPower(next_available_channel, INA226.getPower_mW() / 1000.0);
  417. next_available_channel++;
  418. }
  419. #endif
  420. #if ENV_INCLUDE_MLX90614
  421. if (MLX90614_initialized) {
  422. telemetry.addTemperature(TELEM_CHANNEL_SELF, MLX90614.readObjectTempC());
  423. telemetry.addTemperature(TELEM_CHANNEL_SELF + 1, MLX90614.readAmbientTempC());
  424. }
  425. #endif
  426. #if ENV_INCLUDE_VL53L0X
  427. if (VL53L0X_initialized) {
  428. VL53L0X_RangingMeasurementData_t measure;
  429. VL53L0X.rangingTest(&measure, false); // pass in 'true' to get debug data
  430. if (measure.RangeStatus != 4) { // phase failures
  431. telemetry.addDistance(TELEM_CHANNEL_SELF, measure.RangeMilliMeter / 1000.0f); // convert mm to m
  432. } else {
  433. telemetry.addDistance(TELEM_CHANNEL_SELF, 0.0f); // no valid measurement
  434. }
  435. }
  436. #endif
  437. #if ENV_INCLUDE_BMP085
  438. if (BMP085_initialized) {
  439. telemetry.addTemperature(TELEM_CHANNEL_SELF, BMP085.readTemperature());
  440. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BMP085.readPressure() / 100);
  441. telemetry.addAltitude(TELEM_CHANNEL_SELF, BMP085.readAltitude(TELEM_BMP085_SEALEVELPRESSURE_HPA * 100));
  442. }
  443. #endif
  444. #if ENV_INCLUDE_RAK12035
  445. if (RAK12035_initialized) {
  446. // RAK12035 Telemetry is Channel 2
  447. telemetry.addTemperature(2, RAK12035.get_sensor_temperature());
  448. telemetry.addPercentage(2, RAK12035.get_sensor_moisture());
  449. // RAK12035 CALIBRATION Telemetry is Channel 3, if enabled
  450. #ifdef ENABLE_RAK12035_CALIBRATION
  451. // Calibration Data Screen is Channel 3
  452. float cap = RAK12035.get_sensor_capacitance();
  453. float _wet = RAK12035.get_humidity_full();
  454. float _dry = RAK12035.get_humidity_zero();
  455. telemetry.addFrequency(3, cap);
  456. telemetry.addTemperature(3, _wet);
  457. telemetry.addPower(3, _dry);
  458. if(cap > _dry){
  459. RAK12035.set_humidity_zero(cap);
  460. }
  461. if(cap < _wet){
  462. RAK12035.set_humidity_full(cap);
  463. }
  464. #endif
  465. }
  466. #endif
  467. }
  468. return true;
  469. }
  470. int EnvironmentSensorManager::getNumSettings() const {
  471. int settings = 0;
  472. #if ENV_INCLUDE_GPS
  473. if (gps_detected) settings++; // only show GPS setting if GPS is detected
  474. #endif
  475. return settings;
  476. }
  477. const char* EnvironmentSensorManager::getSettingName(int i) const {
  478. int settings = 0;
  479. #if ENV_INCLUDE_GPS
  480. if (gps_detected && i == settings++) {
  481. return "gps";
  482. }
  483. #endif
  484. // convenient way to add params (needed for some tests)
  485. // if (i == settings++) return "param.2";
  486. return NULL;
  487. }
  488. const char* EnvironmentSensorManager::getSettingValue(int i) const {
  489. int settings = 0;
  490. #if ENV_INCLUDE_GPS
  491. if (gps_detected && i == settings++) {
  492. return gps_active ? "1" : "0";
  493. }
  494. #endif
  495. // convenient way to add params ...
  496. // if (i == settings++) return "2";
  497. return NULL;
  498. }
  499. bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) {
  500. #if ENV_INCLUDE_GPS
  501. if (gps_detected && strcmp(name, "gps") == 0) {
  502. if (strcmp(value, "0") == 0) {
  503. stop_gps();
  504. } else {
  505. start_gps();
  506. }
  507. return true;
  508. }
  509. if (strcmp(name, "gps_interval") == 0) {
  510. uint32_t interval_seconds = atoi(value);
  511. if (interval_seconds > 0) {
  512. gps_update_interval_sec = interval_seconds;
  513. } else {
  514. gps_update_interval_sec = 1; // Default to 1 second if 0
  515. }
  516. return true;
  517. }
  518. #endif
  519. return false; // not supported
  520. }
  521. #if ENV_INCLUDE_GPS
  522. void EnvironmentSensorManager::initBasicGPS() {
  523. Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
  524. #ifdef GPS_BAUD_RATE
  525. Serial1.begin(GPS_BAUD_RATE);
  526. #else
  527. Serial1.begin(9600);
  528. #endif
  529. // Try to detect if GPS is physically connected to determine if we should expose the setting
  530. _location->begin();
  531. _location->reset();
  532. #ifndef PIN_GPS_EN
  533. MESH_DEBUG_PRINTLN("No GPS wake/reset pin found for this board. Continuing on...");
  534. #endif
  535. // Give GPS a moment to power up and send data
  536. delay(1000);
  537. // We'll consider GPS detected if we see any data on Serial1
  538. #ifdef ENV_SKIP_GPS_DETECT
  539. gps_detected = true;
  540. #else
  541. gps_detected = (Serial1.available() > 0);
  542. #endif
  543. if (gps_detected) {
  544. MESH_DEBUG_PRINTLN("GPS detected");
  545. #ifdef PERSISTANT_GPS
  546. gps_active = true;
  547. return;
  548. #endif
  549. } else {
  550. MESH_DEBUG_PRINTLN("No GPS detected");
  551. }
  552. _location->stop();
  553. gps_active = false; //Set GPS visibility off until setting is changed
  554. }
  555. // gps code for rak might be moved to MicroNMEALoactionProvider
  556. // or make a new location provider ...
  557. #ifdef RAK_WISBLOCK_GPS
  558. void EnvironmentSensorManager::rakGPSInit(){
  559. Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
  560. #ifdef GPS_BAUD_RATE
  561. Serial1.begin(GPS_BAUD_RATE);
  562. #else
  563. Serial1.begin(9600);
  564. #endif
  565. //search for the correct IO standby pin depending on socket used
  566. if(gpsIsAwake(WB_IO2)){
  567. // MESH_DEBUG_PRINTLN("RAK base board is RAK19007/10");
  568. // MESH_DEBUG_PRINTLN("GPS is installed on Socket A");
  569. }
  570. else if(gpsIsAwake(WB_IO4)){
  571. // MESH_DEBUG_PRINTLN("RAK base board is RAK19003/9");
  572. // MESH_DEBUG_PRINTLN("GPS is installed on Socket C");
  573. }
  574. else if(gpsIsAwake(WB_IO5)){
  575. // MESH_DEBUG_PRINTLN("RAK base board is RAK19001/11");
  576. // MESH_DEBUG_PRINTLN("GPS is installed on Socket F");
  577. }
  578. else{
  579. MESH_DEBUG_PRINTLN("No GPS found");
  580. gps_active = false;
  581. gps_detected = false;
  582. Serial1.end();
  583. return;
  584. }
  585. #ifndef FORCE_GPS_ALIVE // for use with repeaters, until GPS toggle is implimented
  586. //Now that GPS is found and set up, set to sleep for initial state
  587. stop_gps();
  588. #endif
  589. }
  590. bool EnvironmentSensorManager::gpsIsAwake(uint8_t ioPin){
  591. //set initial waking state
  592. pinMode(ioPin,OUTPUT);
  593. digitalWrite(ioPin,LOW);
  594. delay(500);
  595. digitalWrite(ioPin,HIGH);
  596. delay(500);
  597. //Try to init RAK12500 on I2C
  598. if (ublox_GNSS.begin(Wire) == true){
  599. MESH_DEBUG_PRINTLN("RAK12500 GPS init correctly with pin %i",ioPin);
  600. ublox_GNSS.setI2COutput(COM_TYPE_UBX);
  601. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS);
  602. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GALILEO);
  603. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GLONASS);
  604. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_SBAS);
  605. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_BEIDOU);
  606. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_IMES);
  607. ublox_GNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_QZSS);
  608. ublox_GNSS.setMeasurementRate(1000);
  609. ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
  610. gpsResetPin = ioPin;
  611. i2cGPSFlag = true;
  612. gps_active = true;
  613. gps_detected = true;
  614. _location = &RAK12500_provider;
  615. return true;
  616. } else if (Serial1.available()) {
  617. MESH_DEBUG_PRINTLN("Serial GPS init correctly and is turned on");
  618. if(PIN_GPS_EN){
  619. gpsResetPin = PIN_GPS_EN;
  620. }
  621. serialGPSFlag = true;
  622. gps_active = true;
  623. gps_detected = true;
  624. return true;
  625. }
  626. pinMode(ioPin, INPUT);
  627. MESH_DEBUG_PRINTLN("GPS did not init with this IO pin... try the next");
  628. return false;
  629. }
  630. #endif
  631. void EnvironmentSensorManager::start_gps() {
  632. gps_active = true;
  633. #ifdef RAK_WISBLOCK_GPS
  634. pinMode(gpsResetPin, OUTPUT);
  635. digitalWrite(gpsResetPin, HIGH);
  636. return;
  637. #endif
  638. _location->begin();
  639. _location->reset();
  640. #ifndef PIN_GPS_EN
  641. MESH_DEBUG_PRINTLN("Start GPS is N/A on this board. Actual GPS state unchanged");
  642. #endif
  643. }
  644. void EnvironmentSensorManager::stop_gps() {
  645. gps_active = false;
  646. #ifdef RAK_WISBLOCK_GPS
  647. pinMode(gpsResetPin, OUTPUT);
  648. digitalWrite(gpsResetPin, LOW);
  649. return;
  650. #endif
  651. _location->stop();
  652. #ifndef PIN_GPS_EN
  653. MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged");
  654. #endif
  655. }
  656. void EnvironmentSensorManager::loop() {
  657. static long next_gps_update = 0;
  658. #if ENV_INCLUDE_GPS
  659. if (gps_active) {
  660. _location->loop();
  661. }
  662. if (millis() > next_gps_update) {
  663. if(gps_active){
  664. #ifdef RAK_WISBLOCK_GPS
  665. if ((i2cGPSFlag || serialGPSFlag) && _location->isValid()) {
  666. node_lat = ((double)_location->getLatitude())/1000000.;
  667. node_lon = ((double)_location->getLongitude())/1000000.;
  668. MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
  669. node_altitude = ((double)_location->getAltitude()) / 1000.0;
  670. MESH_DEBUG_PRINTLN("lat %f lon %f alt %f", node_lat, node_lon, node_altitude);
  671. }
  672. #else
  673. if (_location->isValid()) {
  674. node_lat = ((double)_location->getLatitude())/1000000.;
  675. node_lon = ((double)_location->getLongitude())/1000000.;
  676. MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
  677. node_altitude = ((double)_location->getAltitude()) / 1000.0;
  678. MESH_DEBUG_PRINTLN("lat %f lon %f alt %f", node_lat, node_lon, node_altitude);
  679. }
  680. #endif
  681. }
  682. next_gps_update = millis() + (gps_update_interval_sec * 1000);
  683. }
  684. #endif
  685. }
  686. #endif