Thanks for the reply, I have kept working on it and discovered something that is likley obvious to others, but was not to me. I was on YouTube at the ShotokuTech channel and ran across this video (https://youtu.be/sBYHlvLupxw?si=eGCNm7QklhmY4slC), which reminded me that often pull-up or pull-down resistors are needed. I’m not sure why they were not needed for the BME680, but they are required for the CCS811 board. Anyway, with that and then a bit more tweaking, I was able to get the CCS811 to initialize, debug to serial, and transmit over LoRa using the following sketch:
/**
* This sketch was written starting with the "LoRAWAN_TTN" example
* from the "Heltec_ESP32_LoRa_V3" Library. It also uses portions of the
* "CCS811_test" example from the "Adafruit CCS811 Library". Modifications
* have been made to both contributions by Brandon J. Winters.
*
*
* FOR THIS EXAMPLE TO WORK, YOU MUST INSTALL THE "LoRaWAN_ESP32" LIBRARY USING
* THE LIBRARY MANAGER IN THE ARDUINO IDE.
*
* This code will send a two-byte LoRaWAN message every 15 minutes. The first
* byte is a simple 8-bit counter, the second is the ESP32 chip temperature
* directly after waking up from its 15 minute sleep in degrees celsius + 100.
*
* If your NVS partition does not have stored TTN / LoRaWAN provisioning
* information in it yet, you will be prompted for them on the serial port and
* they will be stored for subsequent use.
*
* See https://github.com/ropg/LoRaWAN_ESP32
*/
// Pause between sends in seconds, so this is every 15 minutes. (Delay will be
// longer if regulatory or TTN Fair Use Policy requires it.)
#define MINIMUM_DELAY 900
#include <heltec_unofficial.h>
#include <LoRaWAN_ESP32.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_CCS811.h>
LoRaWANNode* node;
extern TwoWire Wire1; //Setup Wire1 as second I2C bus
//create CCS811 sensor and give it the nickname "ccs"
Adafruit_CCS811 ccs;
//Setup sequatial counting for data transmissions
RTC_DATA_ATTR uint8_t count = 0; //for LoRa transmissions
RTC_DATA_ATTR uint8_t trans = 0; //for serial debugging
void setup() {
// put your setup code here, to run once:
Wire1.begin(41, 42); //SDA is pin 41 and SCL is pin 42 for second I2C bus
Serial.begin(115200); //begin serial communication at the defined baud rate
ccs.begin(0x5A, &Wire1); //start the ccs sensor at the indicated address on Wire1
Serial.println("CCS811 Test");
if(!ccs.begin()){
Serial.println("Failed to start sensor! Please check your wiring.");
while(1);
}
// Wait for the sensor to be ready
while(!ccs.available());
Serial.println("CCS811 found after wait");
// Obtain directly after deep sleep
// May or may not reflect room temperature, some correction needed
float temp = heltec_temperature();
Serial.println();
Serial.println(F("-------------------------"));
Serial.print("Consecutive Transmissions: ");
Serial.print(trans++);
Serial.println();
Serial.printf("Heltec Temperature: %.1f °C\n", temp);
if(ccs.available()){
if(!ccs.readData()){
Serial.print("CO2: ");
Serial.print(ccs.geteCO2());
Serial.print(" ppm");
Serial.println();
Serial.print("TVOC: ");
Serial.print(ccs.getTVOC());
Serial.print(" TVOC Units");
Serial.println();
Serial.println(F("-------------------------"));
}
else{
Serial.println("ERROR!");
while(1);
}
}
heltec_setup(); //for some reason this needs to be called after Wire1 and Serial for this board. I assume there is another way, but this seems to work also.
// initialize radio
Serial.println("Radio init");
int16_t state = radio.begin();
if (state != RADIOLIB_ERR_NONE) {
Serial.println("Radio did not initialize. We'll try again later.");
goToSleep();
}
node = persist.manage(&radio);
if (!node->isActivated()) {
Serial.println("Could not join network. We'll try again later.");
goToSleep();
}
// If we're still here, it means we joined, and we can send something
// Manages uplink intervals to the TTN Fair Use Policy
node->setDutyCycle(true, 1250);
//create LoRa data uplink structure and packet
uint8_t uplinkData[4];
uplinkData[0] = (count++); //sequantially adds one intiger to the value 'count' for each transmission, resets when RST button pushed
uplinkData[1] = (ccs.geteCO2() / 5); //max value to multiply by and keep under cap of 256 for uint8_t value
uplinkData[2] = (ccs.getTVOC() * 10); //max value to multiply by and keep under cap of 256 for uint8_t value
uplinkData[3] = (ccs.calculateTemperature() + 273.15); //zeros out the temperature, this may not be functioning correctly
//define LoRa downlink size
uint8_t downlinkData[256];
size_t lenDown = sizeof(downlinkData);
//Send of the LoRa data and establish wait for downlink
state = node->sendReceive(uplinkData, sizeof(uplinkData), 1, downlinkData, &lenDown);
if(state == RADIOLIB_ERR_NONE) {
Serial.println("Message sent, no downlink received.");
} else if (state > 0) {
Serial.println("Message sent, downlink received.");
} else {
Serial.printf("sendReceive returned error %d, we'll try again later.\n", state);
}
goToSleep(); // Does not return, program starts over next round
}
void loop()
{
// put your main code here, to run repeatedly:
}
void goToSleep() {
Serial.println("Going to deep sleep now");
// allows recall of the session after deepsleep
persist.saveSession(node);
// Calculate minimum duty cycle delay (per FUP & law!)
uint32_t interval = node->timeUntilUplink();
// And then pick it or our MINIMUM_DELAY, whichever is greater
uint32_t delayMs = max(interval, (uint32_t)MINIMUM_DELAY * 1000);
Serial.printf("Next TX in %i s\n", delayMs/1000);
Serial.println(F("*****-----*-----*-----*-----*-----*-----*-----*-----*-----*-----*-----*****"));
Serial.println();
delay(100); // So message prints
// and off to bed we go
heltec_deep_sleep(delayMs/1000);
}
This sketch sends data over LoRa to The Things Network and can be added as an end device there to any application. I am using the following JavaScript payload decoder in my application:
function Decoder(bytes, port) {
var decoded = {};
// Decode bytes to int
var testShort0 = (bytes[0]);
var testShort1 = (bytes[1] * 5);
var testShort2 = (bytes[2] / 10);
var testShort3 = (bytes[3]);
// Decode int
decoded.count = testShort0;
decoded.eCO2 = testShort1;
decoded.TVOC = testShort2;
decoded.temperature = testShort3;
return decoded;
}