Skip to content

Commit 001b996

Browse files
committed
RAK4631: BME680 add and GPS cleanup
- Added the BME680 environment sensor functionality - Added the GPS Repeater env for those wanting it - Cleaned up the GPS and other RAK4631SensorManager code Verified build and functionality on normal and GPS repeater and companion envs. IAQ readout is still a work in progress, but a placeholder can be seen on Channel 2 of the app telemetry.
1 parent 213f01c commit 001b996

File tree

3 files changed

+285
-42
lines changed

3 files changed

+285
-42
lines changed

variants/rak4631/platformio.ini

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ lib_deps =
2323
${nrf52840_base.lib_deps}
2424
adafruit/Adafruit SSD1306 @ ^2.5.13
2525
stevemarple/MicroNMEA @ ^2.0.6
26-
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
2726

2827
[env:RAK_4631_Repeater]
2928
extends = rak4631
@@ -41,6 +40,30 @@ build_src_filter = ${rak4631.build_src_filter}
4140
+<helpers/ui/SSD1306Display.cpp>
4241
+<../examples/simple_repeater>
4342

43+
[env:RAK_4631_GPS_Repeater]
44+
extends = rak4631
45+
build_flags =
46+
${rak4631.build_flags}
47+
-D DISPLAY_CLASS=SSD1306Display
48+
-D ADVERT_NAME='"RAK4631 GPS Repeater"'
49+
-D ADVERT_LAT=0.0
50+
-D ADVERT_LON=0.0
51+
-D ADMIN_PASSWORD='"password"'
52+
-D MAX_NEIGHBOURS=8
53+
-D FORCE_GPS_ALIVE=1
54+
-D ENV_INCLUDE_GPS=1
55+
-D ENV_INCLUDE_BME680=1
56+
; -D MESH_PACKET_LOGGING=1
57+
; -D MESH_DEBUG=1
58+
build_src_filter = ${rak4631.build_src_filter}
59+
+<helpers/ui/SSD1306Display.cpp>
60+
+<../examples/simple_repeater>
61+
lib_deps =
62+
${rak4631.lib_deps}
63+
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
64+
https://github.com/boschsensortec/Bosch-BSEC2-Library
65+
https://github.com/boschsensortec/Bosch-BME68x-Library
66+
4467
[env:RAK_4631_room_server]
4568
extends = rak4631
4669
build_flags =
@@ -104,6 +127,7 @@ build_flags =
104127
-D BLE_DEBUG_LOGGING=1
105128
-D OFFLINE_QUEUE_SIZE=256
106129
-D ENV_INCLUDE_GPS=1
130+
-D ENV_INCLUDE_BME680=1
107131
; -D MESH_PACKET_LOGGING=1
108132
; -D MESH_DEBUG=1
109133
build_src_filter = ${rak4631.build_src_filter}
@@ -112,6 +136,9 @@ build_src_filter = ${rak4631.build_src_filter}
112136
+<../examples/companion_radio>
113137
lib_deps =
114138
${rak4631.lib_deps}
139+
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
140+
https://github.com/boschsensortec/Bosch-BSEC2-Library
141+
https://github.com/boschsensortec/Bosch-BME68x-Library
115142
densaugeo/base64 @ ~1.4.0
116143

117144
[env:RAK_4631_terminal_chat]

variants/rak4631/target.cpp

Lines changed: 234 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ RAK4631SensorManager sensors = RAK4631SensorManager(nmea);
1919
RAK4631SensorManager sensors;
2020
#endif
2121

22+
#if ENV_INCLUDE_BME680
23+
#ifndef TELEM_BME680_ADDRESS
24+
#define TELEM_BME680_ADDRESS 0x76 // BME680 environmental sensor I2C address
25+
#endif
26+
#include <bsec2.h>
27+
static Bsec2 BME680;
28+
float rawPressure = 0;
29+
float rawTemperature = 0;
30+
float compTemperature = 0;
31+
float rawHumidity = 0;
32+
float compHumidity = 0;
33+
float readIAQ = 0;
34+
float readCO2 = 0;
35+
#endif
36+
2237
#ifdef DISPLAY_CLASS
2338
DISPLAY_CLASS display;
2439
#endif
@@ -43,6 +58,10 @@ void scanDevices(TwoWire *w)
4358
Serial.println("\tFound RAK12500 GPS Sensor");
4459
deviceOnline |= RAK12500_ONLINE;
4560
break;
61+
case 0x76:
62+
Serial.println("\tFound RAK1906 Environment Sensor");
63+
deviceOnline |= BME680_ONLINE;
64+
break;
4665
default:
4766
Serial.print("\tI2C device found at address 0x");
4867
if (addr < 16) {
@@ -137,7 +156,7 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
137156
ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
138157
disStandbyPin = ioPin;
139158
gps_active = true;
140-
gps_present = true;
159+
gps_detected = true;
141160
return true;
142161
}
143162
else
@@ -147,83 +166,266 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
147166
}
148167
#endif
149168

169+
#if ENV_INCLUDE_BME680
170+
void checkBMEStatus(Bsec2 bsec)
171+
{
172+
if (bsec.status < BSEC_OK)
173+
{
174+
MESH_DEBUG_PRINTLN("BSEC error code : %f", String(bsec.status));
175+
}
176+
else if (bsec.status > BSEC_OK)
177+
{
178+
MESH_DEBUG_PRINTLN("BSEC warning code : %f", String(bsec.status));
179+
}
180+
181+
if (bsec.sensor.status < BME68X_OK)
182+
{
183+
MESH_DEBUG_PRINTLN("BME68X error code : %f", String(bsec.sensor.status));
184+
}
185+
else if (bsec.sensor.status > BME68X_OK)
186+
{
187+
MESH_DEBUG_PRINTLN("BME68X warning code : %f", String(bsec.sensor.status));
188+
}
189+
}
190+
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
191+
{
192+
if (!outputs.nOutputs)
193+
{
194+
MESH_DEBUG_PRINTLN("No new data to report out");
195+
return;
196+
}
197+
198+
MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", String((int) (outputs.output[0].time_stamp / INT64_C(1000000))));
199+
for (uint8_t i = 0; i < outputs.nOutputs; i++)
200+
{
201+
const bsecData output = outputs.output[i];
202+
switch (output.sensor_id)
203+
{
204+
case BSEC_OUTPUT_IAQ:
205+
MESH_DEBUG_PRINTLN("\tIAQ = %f", String(output.signal));
206+
MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", String((int) output.accuracy));
207+
break;
208+
case BSEC_OUTPUT_RAW_TEMPERATURE:
209+
rawTemperature = output.signal;
210+
MESH_DEBUG_PRINTLN("\tTemperature = %f", String(output.signal));
211+
break;
212+
case BSEC_OUTPUT_RAW_PRESSURE:
213+
rawPressure = output.signal;
214+
MESH_DEBUG_PRINTLN("\tPressure = %f", String(output.signal));
215+
break;
216+
case BSEC_OUTPUT_RAW_HUMIDITY:
217+
rawHumidity = output.signal;
218+
MESH_DEBUG_PRINTLN("\tHumidity = %f", String(output.signal));
219+
break;
220+
case BSEC_OUTPUT_RAW_GAS:
221+
MESH_DEBUG_PRINTLN("\tGas resistance = %f", String(output.signal));
222+
break;
223+
case BSEC_OUTPUT_STABILIZATION_STATUS:
224+
MESH_DEBUG_PRINTLN("\tStabilization status = %f", String(output.signal));
225+
break;
226+
case BSEC_OUTPUT_RUN_IN_STATUS:
227+
MESH_DEBUG_PRINTLN("\tRun in status = %f", String(output.signal));
228+
break;
229+
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
230+
compTemperature = output.signal;
231+
MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", String(output.signal));
232+
break;
233+
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
234+
compHumidity = output.signal;
235+
MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", String(output.signal));
236+
break;
237+
case BSEC_OUTPUT_STATIC_IAQ:
238+
readIAQ = output.signal;
239+
MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", String(output.signal));
240+
break;
241+
case BSEC_OUTPUT_CO2_EQUIVALENT:
242+
readCO2 = output.signal;
243+
MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", String(output.signal));
244+
break;
245+
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
246+
MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", String(output.signal));
247+
break;
248+
case BSEC_OUTPUT_GAS_PERCENTAGE:
249+
MESH_DEBUG_PRINTLN("\tGas percentage = %f", String(output.signal));
250+
break;
251+
case BSEC_OUTPUT_COMPENSATED_GAS:
252+
MESH_DEBUG_PRINTLN("\tCompensated gas = %f", String(output.signal));
253+
break;
254+
default:
255+
break;
256+
}
257+
}
258+
}
259+
#endif
260+
150261
bool RAK4631SensorManager::begin() {
151262

152263
#ifdef MESH_DEBUG
153264
scanDevices(&Wire);
154265
#endif
155266

156-
#if ENV_INCLUDE_GPS
157-
//search for the correct IO standby pin depending on socket used
158-
if(gpsIsAwake(P_GPS_STANDBY_A)){
159-
MESH_DEBUG_PRINTLN("GPS is on socket A");
160-
}
161-
else if(gpsIsAwake(P_GPS_STANDBY_C)){
162-
MESH_DEBUG_PRINTLN("GPS is on socket C");
163-
}
164-
else if(gpsIsAwake(P_GPS_STANDBY_F)){
165-
MESH_DEBUG_PRINTLN("GPS is on socket F");
166-
}
167-
else{
168-
MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F");
169-
gps_active = false;
170-
gps_present = false;
171-
return false;
172-
}
267+
#if ENV_INCLUDE_GPS
268+
//search for the correct IO standby pin depending on socket used
269+
if(gpsIsAwake(P_GPS_STANDBY_A)){
270+
MESH_DEBUG_PRINTLN("GPS is on socket A");
271+
}
272+
else if(gpsIsAwake(P_GPS_STANDBY_C)){
273+
MESH_DEBUG_PRINTLN("GPS is on socket C");
274+
}
275+
else if(gpsIsAwake(P_GPS_STANDBY_F)){
276+
MESH_DEBUG_PRINTLN("GPS is on socket F");
277+
}
278+
else{
279+
MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F");
280+
gps_active = false;
281+
gps_detected = false;
282+
return false;
283+
}
173284

174-
//Now that GPS is found and set up, set to sleep for initial state
175-
stop_gps();
176-
#endif
285+
#ifndef FORCE_GPS_ALIVE
286+
//Now that GPS is found and set up, set to sleep for initial state
287+
stop_gps();
288+
#endif
289+
#endif
290+
291+
#if ENV_INCLUDE_BME680
292+
293+
bsecSensor sensorList[4] = {
294+
BSEC_OUTPUT_IAQ,
295+
// BSEC_OUTPUT_RAW_TEMPERATURE,
296+
BSEC_OUTPUT_RAW_PRESSURE,
297+
// BSEC_OUTPUT_RAW_HUMIDITY,
298+
// BSEC_OUTPUT_RAW_GAS,
299+
// BSEC_OUTPUT_STABILIZATION_STATUS,
300+
// BSEC_OUTPUT_RUN_IN_STATUS,
301+
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
302+
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
303+
// BSEC_OUTPUT_STATIC_IAQ,
304+
// BSEC_OUTPUT_CO2_EQUIVALENT,
305+
// BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
306+
// BSEC_OUTPUT_GAS_PERCENTAGE,
307+
// BSEC_OUTPUT_COMPENSATED_GAS
308+
};
309+
310+
if(!BME680.begin(TELEM_BME680_ADDRESS, Wire)){
311+
checkBMEStatus(BME680);
312+
bme680_present = false;
313+
bme680_active = false;
314+
return false;
315+
}
316+
317+
MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS);
318+
bme680_present = true;
319+
bme680_active = true;
320+
321+
if (SAMPLING_RATE == BSEC_SAMPLE_RATE_ULP)
322+
{
323+
BME680.setTemperatureOffset(BSEC_SAMPLE_RATE_ULP);
324+
}
325+
else if (SAMPLING_RATE == BSEC_SAMPLE_RATE_LP)
326+
{
327+
BME680.setTemperatureOffset(TEMP_OFFSET_LP);
328+
}
329+
330+
if (!BME680.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLING_RATE))
331+
{
332+
checkBMEStatus(BME680);
333+
}
334+
335+
BME680.attachCallback(newDataCallback);
336+
337+
#endif
177338
}
178339

179-
#if ENV_INCLUDE_GPS
180340
bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
341+
#ifdef ENV_INCLUDE_GPS
181342
if (requester_permissions & TELEM_PERM_LOCATION && gps_active) { // does requester have permission?
182343
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
183344
}
345+
#endif
346+
347+
if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
348+
349+
#if ENV_INCLUDE_BME680
350+
if (bme680_active) {
351+
telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature);
352+
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity);
353+
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure);
354+
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readIAQ);
355+
}
356+
#endif
357+
}
184358
return true;
185359
}
186360

187361
void RAK4631SensorManager::loop() {
188362
static long next_update = 0;
189363

364+
#ifdef ENV_INCLUDE_GPS
190365
_nmea->loop();
366+
#endif
191367

192-
if (millis() > next_update && gps_active) {
193-
node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
194-
node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
195-
node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
196-
MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
368+
if (millis() > next_update) {
197369

370+
#ifdef ENV_INCLUDE_GPS
371+
if(gps_active){
372+
node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
373+
node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
374+
node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
375+
MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
376+
}
377+
#endif
378+
379+
#ifdef ENV_INCLUDE_BME680
380+
if(bme680_active){
381+
if (!BME680.run()){
382+
checkBMEStatus(BME680);
383+
}
384+
}
385+
#endif
198386
next_update = millis() + 1000;
199387
}
388+
200389
}
201390

202-
int RAK4631SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
391+
int RAK4631SensorManager::getNumSettings() const {
392+
#if ENV_INCLUDE_GPS
393+
return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected
394+
#else
395+
return 0;
396+
#endif
397+
}
203398

204399
const char* RAK4631SensorManager::getSettingName(int i) const {
205-
return i == 0 ? "gps" : NULL;
400+
#if ENV_INCLUDE_GPS
401+
return (gps_detected && i == 0) ? "gps" : NULL;
402+
#else
403+
return NULL;
404+
#endif
206405
}
207406

208407
const char* RAK4631SensorManager::getSettingValue(int i) const {
209-
if (i == 0) {
408+
#if ENV_INCLUDE_GPS
409+
if (gps_detected && i == 0) {
210410
return gps_active ? "1" : "0";
211411
}
412+
#endif
212413
return NULL;
213414
}
214415

215416
bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) {
216-
if (strcmp(name, "gps") == 0) {
417+
#if ENV_INCLUDE_GPS
418+
if (gps_detected && strcmp(name, "gps") == 0) {
217419
if (strcmp(value, "0") == 0) {
218420
stop_gps();
219421
} else {
220422
start_gps();
221423
}
222424
return true;
223425
}
426+
#endif
224427
return false; // not supported
225428
}
226-
#endif
227429

228430
mesh::LocalIdentity radio_new_identity() {
229431
RadioNoiseListener rng(radio);

0 commit comments

Comments
 (0)