Thingspeak IoT Server Connectivity issue

Hi,

My team has been sending data to Thingspeak IoT to analyze outputs of our system. The data is successfully making it to the Particle servers but is struggling to communicate with the thingspeak servers, producing DNS errors. We haven’t made any changes to our setup and it occasionally ports data over to Thingspeak. We checked the API keys for the Data channels that we have in our code and even changed the API keys and updated our code but are still seeing this issue. We’ve seen it on our E402 and the Argons we’re using. Is this a solvable issue? Seems like it’s a server issue that’s out of our control.

Thanks!

Hey-

That sounds frustrating! Can you share the code you are using and any error messages you receive?Looking at the Thingspeak library, are you calling Thingspeak correctly? It’s strange that the data occasionally shows up and does suggest a Thingspeak server issue but there are definitely other possibilities.

Hi Colleen,

Thank you for your help. I’m attaching the code here, let me know if there is anything else you need. We see returns of 200 when it goes through then -301 when it fails. Thats the continuous error we’re seeing:

/*
 * Project cwl_panama
 * Description: code base
 * Author: Amit
 * Date: 04/19/2023
 */

#include <Adafruit_BusIO_Register.h>
#include "VEDirect.h"
#include "Adafruit_AHTX0.h"
#include <DS18B20.h>
#include <SdFat.h>
#include <Adafruit_AM2315.h>
#include <Adafruit_BME280.h>
#include <ThingSpeak.h>
#include <adafruit-sht31.h>
#include "Serial4/Serial4.h"

TCPClient client;

// hardware definitions
#define SOLID_LOADCELL_PIN A1
#define LIQUID_LOADCELL_PIN A0
#define FAN1_PWM_PIN B0
#define FAN2_PWM_PIN B1
#define FAN3_PWM_PIN B2
#define FAN4_PWM_PIN B3
#define SD_CS_PIN SS
#define DS_DATA D6
#define TCAADDR 0x70
#define N_SAMPLE 3000 // number of samples to average for load cell measurements

// sensor declarations
DS18B20 ds18b20(DS_DATA, true); // Sets Pin D3 as data pin and the only sensor on bus
int floatSwitchHeaterPin = C5;  // 0 (LOW) is good, 1 (HIGH) is bad. HIGH = water overflowing from liquid cart = bad.
int heaterRelayPin = D3;
// DS18 liquidTempSensor(DS_DATA);

// ve_direct declarations
int32_t VE_soc, VE_power, VE_voltage, VE_current;
uint8_t VE_alarm;
VEDirect myve(Serial4);
bool connected = false;


SdFat SD;
File myFile;
Adafruit_AHTX0 aht1;
Adafruit_AHTX0 aht2;
Adafruit_AHTX0 aht3;
Adafruit_SHT31 sht31 = Adafruit_SHT31();
int pwmFreq = 25000; // recommended PWM frequency for Orion fans

// particle variable input selections - set to true if components are being used
int logDelay = 300;                        // particle variable to determine seconds between logs (300s = 5min)
bool ambientTRHEnabled = true;             // set to true if ambient TRH sensor connected
bool externalTRHEnabled = false;           // set to true if external TRH sensor connected
bool internalTRHEnabled = true;            // set to true if internal TRH sensor connected
bool veEnabled = true;                     // set to true if VE.Direct connected
bool microSDEnabled = true;                // set to true if using microSD card for data backup
bool liquidTempEnabled = true;             // set to true if using DS18B20 liquid temperature sensor
bool debugEnabled = false;                 // set to true if to enable debug mode (with particle publishes)
int fan1Speed = 20;                        // set the speed of fan 1 (percent, default = 100%)
int fan2Speed = 20;                        // set the speed of fan 2 (percent, default = 100%)
int fan3Speed = 20;                        // set the speed of fan 2 (percent, default = 100%)
int fan4Speed = 20;                        // set the speed of fan 3 (percent, default = 100%)
int fanSpeed = 20;                         // set the speed of all fans (percent, default = 100%)
bool heaterRelayOn = true;                 // boolean indicating if the heater is on
bool inlineFanRelayOn = false;             // boolean indicating if the inline fan relay is on
bool heaterFloatSwitchTriggered = false;   // boolean indicating if the heater float switch is triggered
bool overflowFloatSwitchTriggered = false; // boolean indicating if the overflow float switch is triggered
bool warningLEDOn = false;                 // boolean indicating if the warning LED is turned on

unsigned long myChannelNumber1 = 1779954;
String myWriteAPIKey1 = "O1VQM8OQZ58A0K1M";
unsigned long myChannelNumber2 = 1779955;
String myWriteAPIKey2 = "ALBZGMTUZR2VB0V4";

// particle function declarations - updates which inputs are being used
int enableAmbientTRH(String command);
int enableExternalTRH(String command);
int enableInternalTRH(String command);
int enableVEDIRECT(String command);
int enableSD(String command);
int enableliquidTemp(String command);
int enableDebugMode(String command);
int updateChannelNumber1(String command);
int updateWriteAPIKey1(String command);
int updateChannelNumber2(String command);
int updateWriteAPIKey2(String command);
int updateLogDelay(String command);
int setFan1Speed(String command);
int setFan2Speed(String command);
int setFan3Speed(String command);
int setFan4Speed(String command);
int setAllFansSpeed(String command);
int forceTurnOnWarningLED(String command);

// configuration variables
const int MAXRETRY = 4;        // maximum number of times to try reading data from DS18B20
unsigned long lastLog = 0;     // initialize variable to record the last data log
unsigned long currentTime = 0; // initialize variable to record the current time

// data storage variables
float solidLoadCell = 0;
float liquidLoadCell = 0;
float ambientTemperature = 0;
float ambientHumidity = 0;
float externalTemperature = 0;
float externalHumidity = 0;
float internalTemperature = 0;
float internalHumidity = 0;
float liquidTemperature = 0;
float batterySoC = 0;

void setup()
{

    // startup diagnostics

    // flash LEDs
    pinMode(C1, OUTPUT); // sets the digital pin C1 (LED_1) as output
    digitalWrite(C1, HIGH);
    delay(5000);
    digitalWrite(C1, LOW);
    delay(5000);
    digitalWrite(C1, HIGH);
    delay(5000);
    digitalWrite(D2, HIGH);

    // Boot-up messages
    Particle.publish("Starting up device.");
    Particle.publish("Running code changewater.ino");
    Particle.publish("Date 2023.03.03");

    // Register particle variables
    Particle.variable("ambTRHEnabled", ambientTRHEnabled);
    Particle.variable("extTRHEnabled", externalTRHEnabled);
    Particle.variable("intTRHEnabled", internalTRHEnabled);
    Particle.variable("liquidTEnabled", liquidTempEnabled);
    Particle.variable("vedirectEnabled", veEnabled);
    Particle.variable("sdEnabled", microSDEnabled);
    Particle.variable("debugModeEnabled", debugEnabled);
    Particle.variable("myChannelNumber1", myChannelNumber1);
    Particle.variable("myWriteAPIKey1", myWriteAPIKey1);
    Particle.variable("myChannelNumber2", myChannelNumber2);
    Particle.variable("myWriteAPIKey2", myWriteAPIKey2);
    Particle.variable("fanSpeed", fanSpeed);

    // Register particle functions
    Particle.function("enableAmbientTRH", enableExternalTRH);
    Particle.function("enableExternalTRH", enableExternalTRH);
    Particle.function("enableInternalTRH", enableInternalTRH);
    Particle.function("enableLiquidTemp", enableliquidTemp);
    Particle.function("enableVEDirect", enableVEDIRECT);
    Particle.function("enableSD", enableSD);
    Particle.function("updateChannelNumber1", updateChannelNumber1);
    Particle.function("updateWriteAPIKey1", updateWriteAPIKey1);
    Particle.function("updateChannelNumber2", updateChannelNumber2);
    Particle.function("updateWriteAPIKey2", updateWriteAPIKey2);
    Particle.function("updateLogDelay", updateLogDelay);
    Particle.function("setAllFansSpeed", setAllFansSpeed);
    // Particle.function("forceTurnOnWarningLED", forceTurnOnWarningLED);
    Particle.function("enableDebugMode", enableDebugMode);

    Wire.begin();
    ThingSpeak.begin(client);

    delay(5000);

    // Initialize sensors
    initialize_TRH();
    read_TRH();
    Particle.publish("Sensor initialization completed.");

    delay(2000);

    // Initialize fans
    initialize_fans();

    // Initialize microSD card and write the header file
    initialize_sd();

    pinMode(floatSwitchHeaterPin, INPUT_PULLUP); // sets pin as input
    int float1 = digitalRead(floatSwitchHeaterPin);
    String tempstring = "float1: " + (String)float1;
    Particle.publish(tempstring);

    pinMode(C5, INPUT_PULLUP); // sets the digital pin C1 (LED_1) as output
    int float2 = digitalRead(C5);
    tempstring = "float2: " + (String)float2;
    Particle.publish(tempstring);

    Particle.publish("Setup Complete");

    delay(5000);
}

void loop()
{
    // read input from load cells and take NSAMPLE point average
    read_loadcells();

    // read data from DS18B20
    read_DS18B20();

    // read data from the TRH sensors
    read_TRH();

    // turn on or off the heater
    toggle_heater();

    //read ve.direct
    readVEDirect();

    // delay until next upload time
    delay(logDelay * 1000 - (millis() % (logDelay * 1000)));
    currentTime = Time.now();

    // post data to thingspeak
    if (currentTime >= lastLog + logDelay)
    {
        post_data_thingspeak();
    }

    // store data to sd as a backup
    write_data_sd();
}

/*
**  Particle functions
*/

/*
**  Particle function enableExternalTRH
**  Enables data collection the external TRH sensor
**  0 = off, 1 = on
*/
int enableExternalTRH(String command)
{
    if (command.toInt() == 1)
    {
        externalTRHEnabled = true;
        return 1;
    }
    else
    {
        externalTRHEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableInternalTRH
**  Enables data collection the internal TRH sensor
**  0 = off, 1 = on
*/
int enableInternalTRH(String command)
{
    if (command.toInt() == 1)
    {
        internalTRHEnabled = true;
        return 1;
    }
    else
    {
        internalTRHEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableAmbientTRH
**  Enables data collection the ambient TRH sensor
**  0 = off, 1 = on
*/
int enableAmbientTRH(String command)
{
    if (command.toInt() == 1)
    {
        ambientTRHEnabled = true;
        return 1;
    }
    else
    {
        ambientTRHEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableVEDIRECT
**  Enables data collection from the ve.direct port
**  0 = off, 1 = on
*/
int enableVEDIRECT(String command)
{
    if (command.toInt() == 1)
    {
        veEnabled = true;
        return 1;
    }
    else
    {
        veEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableSD
**  Enables data storage to the microSD card
**  0 = off, 1 = on
*/
int enableSD(String command)
{
    if (command.toInt() == 1)
    {
        microSDEnabled = true;
        return 1;
    }
    else
    {
        microSDEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableLiquidTemp
**  Enables data collection using the DS18B20 liquid temperature sensor
**  0 = off, 1 = on
*/
int enableliquidTemp(String command)
{
    if (command.toInt() == 1)
    {
        liquidTempEnabled = true;
        return 1;
    }
    else
    {
        liquidTempEnabled = false;
        return 0;
    }
}

/*
**  Particle function enableDebugMode
**  Enables debug mode with additional particle.publish calls
**  0 = off, 1 = on
*/
int enableDebugMode(String command)
{
    if (command.toInt() == 1)
    {
        debugEnabled = true;
        return 1;
    }
    else
    {
        debugEnabled = false;
        return 0;
    }
}

/*
**  Particle function updateChannelNumber1
**  Sets the channel number 1 to write data on Thingspeak
**  Contains performance data
*/
int updateChannelNumber1(String command)
{
    myChannelNumber1 = atol(command.c_str());
    return 1;
}

/*
**  Particle function updateChannelNumber2
**  Sets the channel number 2 to write data on Thingspeak
**  Contains usage state data
*/
int updateChannelNumber2(String command)
{
    myChannelNumber2 = atol(command.c_str());
    return 1;
}

/*
**  Particle function updateLogDelay
**  Sets the delay in seconds between logged data samples
*/
int updateLogDelay(String command)
{
    logDelay = atol(command.c_str());
    return 1;
}

/*
**  Particle function updateWriteAPIKey1
**  Sets the WriteAPIKey2 to write data on Thingspeak
*/
int updateWriteAPIKey1(String command)
{
    myWriteAPIKey1 = command;
    return 1;
}

/*
**  Particle function updateWriteAPIKey2
**  Sets the WriteAPIKey2 to write data on Thingspeak
*/
int updateWriteAPIKey2(String command)
{
    myWriteAPIKey2 = command;
    return 1;
}

/*
**  Particle function setFan1Speed
**  Manually set the speed for fan 1 from 0-100(%)
*/
int setFan1Speed(String command)
{
    fan1Speed = map(command.toInt(), 0, 100, 0, 255);
    analogWrite(FAN1_PWM_PIN, fan1Speed, pwmFreq);
    return 1;
}

/*
**  Particle function setFan2Speed
**  Manually set the speed for fan 2 from 0-100(%)
*/
int setFan2Speed(String command)
{
    fan2Speed = map(command.toInt(), 0, 100, 0, 255);
    analogWrite(FAN2_PWM_PIN, fan2Speed, pwmFreq);
    return 1;
}

/*
**  Particle function setFan3Speed
**  Manually set the speed for fan 3 from 0-100(%)
*/
int setFan3Speed(String command)
{
    fan3Speed = map(command.toInt(), 0, 100, 0, 255);
    analogWrite(FAN3_PWM_PIN, fan3Speed, pwmFreq);
    return 1;
}

/*
**  Particle function setFan4Speed
**  Manually set the speed for fan 4 from 0-100(%)
*/
int setFan4Speed(String command)
{
    fan4Speed = map(command.toInt(), 0, 100, 0, 255);
    analogWrite(FAN4_PWM_PIN, fan4Speed, pwmFreq);
    return 1;
}

/*
**  Particle function setAllFansSpeed
**  Manually set the speed for all fans from 0-100(%)
*/
int setAllFansSpeed(String command)
{
    fanSpeed = map(command.toInt(), 0, 100, 0, 255);

    fan1Speed = fanSpeed;
    fan2Speed = fanSpeed;
    fan3Speed = fanSpeed;
    fan4Speed = fanSpeed;

    analogWrite(FAN1_PWM_PIN, fan1Speed, pwmFreq);
    analogWrite(FAN2_PWM_PIN, fan2Speed, pwmFreq);
    analogWrite(FAN3_PWM_PIN, fan3Speed, pwmFreq);
    analogWrite(FAN4_PWM_PIN, fan4Speed, pwmFreq);
    return 1;
}

/*
**  Particle function turnOnWarningLED
**  Turns on the warning LED. Sets warning LED override flag
*/
int forceTurnOnWarningLED(String command)
{
    warningLEDOn = atol(command.c_str());
    if (warningLEDOn)
    {

        return 1;
    }
    else
    {
        return 0;
    }
}

/*
** Function postDataThingspeak
** posts data to thingspeak channels
** channel1: solid loadcell, liquid loadcell, internalT, internal RH, ambient T, ambient RH, liquid T, battery SoC
** channel2: states for fan speed, heater relay, inline fan relay, heater float switch, overflow float switch, warning LED
*/
void post_data_thingspeak()
{
    int attempts = 0;
    int err1 = 0;
    do
    {
        // set fields one at a time for channel 1 - contains performance data
        ThingSpeak.setField(1, solidLoadCell);
        ThingSpeak.setField(2, liquidLoadCell);
        ThingSpeak.setField(3, internalTemperature);
        ThingSpeak.setField(4, internalHumidity);
        ThingSpeak.setField(5, ambientTemperature);
        ThingSpeak.setField(6, ambientHumidity);
        ThingSpeak.setField(7, liquidTemperature);
        ThingSpeak.setField(8, batterySoC);

        // Write the fields that you've set all at once.
        err1 = ThingSpeak.writeFields(myChannelNumber1, myWriteAPIKey1.c_str());

        if (debugEnabled)
        {
            String tempstring = "Data posted to ThingSpeak Ch1: " + (String)err1;
            Particle.publish(tempstring);
        }

    } while (err1 != 200 && attempts++ < 5);

    attempts = 0;
    int err2 = 0;
    do
    {
        // set fields one at a time for channel 2 - contains usage state data
        ThingSpeak.setField(1, fanSpeed);
        ThingSpeak.setField(2, heaterRelayOn);
        ThingSpeak.setField(3, inlineFanRelayOn);
        ThingSpeak.setField(4, heaterFloatSwitchTriggered);
        ThingSpeak.setField(5, overflowFloatSwitchTriggered);
        ThingSpeak.setField(6, warningLEDOn);

        // Write the fields that you've set all at once.
        err2 = ThingSpeak.writeFields(myChannelNumber2, myWriteAPIKey2.c_str());
        if (debugEnabled)
        {
            String tempstring = "Data posted to ThingSpeak Ch2: " + (String)err2;
            Particle.publish(tempstring);
        }
    } while (err2 != 200 && attempts++ < 5);

    lastLog = currentTime;
}

/*
**  Function toggle_heater
**  Function turns off heater if heater float switch is off, turns on heater if heater float switch is on
*/
void toggle_heater()
{
    if (digitalRead(floatSwitchHeaterPin) == HIGH)
    {
        turnHeaterOn(true);
    }
    else
    {
        turnHeaterOn(false);
    }
}

/*
**  Function turnHeaterOn
**  Function turns on and off heater depending on input
*/
void turnHeaterOn(bool state)
{
    if (state == true)
    {
        digitalWrite(heaterRelayPin, HIGH);
    }
    else
    {
        digitalWrite(heaterRelayPin, LOW);
    }
}

/*
**  Function initializeFans
**  Function to set the fan pins and pwm settings
*/
void initialize_fans()
{
    pinMode(FAN1_PWM_PIN, OUTPUT);          // sets the pin as output
    analogWriteResolution(FAN1_PWM_PIN, 8); // sets analogWrite resolution to 8 bits

    pinMode(FAN2_PWM_PIN, OUTPUT);          // sets the pin as output
    analogWriteResolution(FAN2_PWM_PIN, 8); // sets analogWrite resolution to 8 bits

    pinMode(FAN3_PWM_PIN, OUTPUT);          // sets the pin as output
    analogWriteResolution(FAN3_PWM_PIN, 8); // sets analogWrite resolution to 8 bits

    pinMode(FAN4_PWM_PIN, OUTPUT);          // sets the pin as output
    analogWriteResolution(FAN4_PWM_PIN, 8); // sets analogWrite resolution to 8 bits

    analogWrite(FAN1_PWM_PIN, fan1Speed, pwmFreq);
    analogWrite(FAN2_PWM_PIN, fan2Speed, pwmFreq);
    analogWrite(FAN3_PWM_PIN, fan3Speed, pwmFreq);
    analogWrite(FAN4_PWM_PIN, fan4Speed, pwmFreq);
}

/*
**  Function readVEDirect
**  Reads data from smartshunt using VE.Direct protocol
*/
void readVEDirect()
{   
    if(veEnabled)
    {
        // Read the data
        if (myve.begin())
        {
            VE_soc = myve.read(VE_SOC);
            VE_power = myve.read(VE_POWER);
            VE_voltage = myve.read(VE_VOLTAGE);
            VE_current = myve.read(VE_CURRENT);
            VE_alarm = myve.read(VE_ALARM);    
            connected = true;
            if (debugEnabled)
            {
                Particle.publish("State of Charge (SOC): ", String(VE_soc, DEC));
                Particle.publish("Voltage: ",String(VE_voltage, DEC));
            }
        }
        else {
            connected = false;
            if (debugEnabled) {
                Particle.publish("Could not open serial port to VE device");
            }
        }
        
        if(connected) { 
            myve.read(VE_DUMP);
        }
    }
}

/*
**  Function tcaseselect
**  Function to choose I2C multiplexer slot. Takes an int input to select SD/SC port.
*/
void tcaselect(uint8_t i)
{
    if (i > 7)
        return;

    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << i);
    Wire.endTransmission();
}

/*
**  Function read_DS18B20
**  Function to get data from the DS18B20 temperature sensor
**  If liquidTempEnabled = true, attempt to read the DS18B20 output a total of MAXRETRY times.
**  Store data in liquidTemperature.
*/
void read_DS18B20()
{
    String tempstring = "";
    if (liquidTempEnabled)
    {
        float _temp;
        int i = 0;

        do
        {
            _temp = ds18b20.getTemperature();
        } while (!ds18b20.crcCheck() && MAXRETRY > i++);

        if (i < MAXRETRY)
        {
            liquidTemperature = _temp;
            if (debugEnabled)
            {
                tempstring = "liquidTemp: " + (String)liquidTemperature;
                Particle.publish(tempstring);
            }
        }
        else
        {
            liquidTemperature = 0;
            if (debugEnabled)
            {
                Particle.publish("Error reading liquid temperature.");
            }
        }
    }
}

/*
**  Function read_loadcells
**
**  Take a an average of N_SAMPLE values from load cells and convert them to a true voltage
**  Records values in global floats solidLoadCell (wired to A1) and liquidLoadCell (wired to A0)
**  Voltage scaled to 3.3V (not 5V)
*/
void read_loadcells()
{
    int loadCellavg = 0;
    analogRead(SOLID_LOADCELL_PIN); // throwaway read to prevent interference between analog 1 and analog 2
    for (int i = 0; i < N_SAMPLE; i++)
    {
        loadCellavg += analogRead(SOLID_LOADCELL_PIN);
        delay(20); // add delay for better accuracy
    }
    solidLoadCell = loadCellavg / N_SAMPLE * (3.3 / 4095);
    delay(1000);
    solidLoadCell = analogRead(SOLID_LOADCELL_PIN) * (3.3 / 4095);
    if (debugEnabled)
    {
        String tempstring = "SolidLC: " + (String)solidLoadCell;
        Particle.publish(tempstring);
    }

    loadCellavg = 0;
    analogRead(LIQUID_LOADCELL_PIN); // throwaway read to prevent interference between analog 1 and analog 2
    for (int i = 0; i < N_SAMPLE; i++)
    {
        loadCellavg += analogRead(LIQUID_LOADCELL_PIN);
        delay(10); // add delay for better accuracy
    }
    liquidLoadCell = loadCellavg / N_SAMPLE * (3.3 / 4095);
    delay(1000);
    if (debugEnabled)
    {
        String tempstring = "LiquidLC: " + (String)liquidLoadCell;
        Particle.publish(tempstring);
    }
}

/*
**  Function initialize_sd
**  Initializes the microSD card if microSD logging is enabled. Writes the header file to datalog.csv:
**  Time,SolidLoadcell,LiquidLoadcell,Internal_Temp,Internal_RH,External_Temp,External_RH,Ambient_Temp,Ambient_RH,DS18B20_Temp
*/
void initialize_sd()
{
    if (microSDEnabled)
    {
        Particle.publish("Initializing SD card...");
        if (!SD.begin(SD_CS_PIN))
        {
            Particle.publish("SD card initialization failed!");
            return;
        }
        Particle.publish("SD card initialization completed.");

        // Write header to SD
        myFile = SD.open("datalog.csv", FILE_WRITE);
        // if the file opened okay, write to it:
        if (myFile)
        {
            myFile.println("Time,SolidLoadcell,LiquidLoadcell,Internal_Temp,Internal_RH,External_Temp,External_RH,Ambient_Temp,Ambient_RH,DS18B20_Temp");
            // close the file:
            myFile.close();
        }
    }
}
/*
**  Function write_data_sd
**
**  Writes data to microSD card. Attempts to open the card, stores data as a csv in the format:
**  Time, loadCell1, loadCell2, TRH1_temperature, TRH1_humidity, TRH2_temperature, TRH2_humidity,
**  TRH3_temperature, TRH3_humidity, DS18B20_temperature
*/
void write_data_sd()
{
    if (microSDEnabled)
    {
        myFile = SD.open("datalog.csv", FILE_WRITE);

        // if the file opens correctly, write to it
        if (myFile)
        {
            myFile.print(Time.now());
            myFile.print(",");
            myFile.print(solidLoadCell, 4);
            myFile.print(",");
            myFile.print(liquidLoadCell, 4);
            myFile.print(",");
            myFile.print(internalTemperature);
            myFile.print(",");
            myFile.print(internalHumidity);
            myFile.print(",");
            myFile.print(externalTemperature);
            myFile.print(",");
            myFile.print(externalHumidity);
            myFile.print(",");
            myFile.print(ambientTemperature);
            myFile.print(",");
            myFile.print(ambientHumidity);
            myFile.print(",");
            myFile.print(liquidTemperature);
            myFile.println("");

            // close the file
            myFile.close();

            // if debugging is enabled, extra particle publish
            if (debugEnabled)
            {
                Particle.publish("Data written to microSD succesfully.");
            }
        }
    }
}

/*
**  Function initialize_TRH
**  Function to  initialize TRH sensors
**  For Panama pilot, only Internal and Ambient are used.
*/
void initialize_TRH()
{

    // Port for SD0/SC0 on MUX. Connected to INTERNAL_TRH screw terminal.
    // Sensor: AM2315C (AHT)
    if (internalTRHEnabled)
    {
        tcaselect(0);
        if (!aht1.begin())
        {
            Particle.publish("Could not find AHT1 - Check wiring");
        }
    }

    // Port for SD1/SC1 on MUX. Connected to EXTERNAL_TRH screw terminal.
    // Sensor: Not connected to any sensor in Panama Pilot, do not use.
    if (externalTRHEnabled)
    {
        tcaselect(1);
        if (!aht2.begin())
        {
            Particle.publish("Could not find AHT2 - Check wiring");
        }
    }

    // Port for SD2/SC2 on mux. Connected to AMBIENT_TRH screw terminal.
    // Sensor: SHT-31
    if (ambientTRHEnabled)
    {
        tcaselect(2);
        if (!sht31.begin(0x44))
        { // Set to 0x45 for alternate i2c addr
            Particle.publish("Couldn't find SHT31");
        }
    }
}

/*
**  Function read_TRH
**  Function to read Temperature and Relative Humidity data from TRH sensors
*/
void read_TRH()
{
    sensors_event_t humidity, temp;
    String tempstring = "";

    if (internalTRHEnabled)
    {
        tcaselect(0);
        aht1.getEvent(&humidity, &temp); // populate temp and humidity objects with fresh data    tcaselect(1);
        internalTemperature = temp.temperature;
        internalHumidity = humidity.relative_humidity;

        // if debugging is enabled, extra particle publishes to troubleshoot TRH sensors
        if (debugEnabled)
        {
            tempstring = "IntTemp: " + (String)internalTemperature;
            Particle.publish(tempstring);
            tempstring = "IntHum: " + (String)internalHumidity;
            Particle.publish(tempstring);
            delay(1000);
        }
    }

    if (externalTRHEnabled)
    {
        tcaselect(1);
        aht2.getEvent(&humidity, &temp); // populate temp and humidity objects with fresh data    tcaselect(1);
        externalTemperature = temp.temperature;
        externalHumidity = humidity.relative_humidity;

        // if debugging is enabled, extra particle publishes to troubleshoot TRH sensors
        if (debugEnabled)
        {
            tempstring = "ExtTemp: " + (String)externalTemperature;
            Particle.publish(tempstring);
            tempstring = "ExtHum: " + (String)externalHumidity;
            Particle.publish(tempstring);
            delay(1000);
        }
    }

    if (ambientTRHEnabled)
    {
        tcaselect(2);
        ambientTemperature = sht31.readTemperature();
        ;
        ambientHumidity = sht31.readHumidity();

        // if debugging is enabled, extra particle publishes to troubleshoot TRH sensors
        if (debugEnabled)
        {
            tempstring = "AmbTemp: " + (String)ambientTemperature;
            Particle.publish(tempstring);
            tempstring = "AmbHum: " + (String)ambientHumidity;
            Particle.publish(tempstring);
            delay(1000);
        }
    }
}

Hi Colleen,

I’m sorry that paste didn’t go well. Here is the code we’re using to post to Thingspeak. I hope this is helpful.

void post_data_thingspeak()
{
    int attempts = 0;
    int err1 = 0;
    do
    {
        // set fields one at a time for channel 1 - contains performance data
        ThingSpeak.setField(1, solidLoadCell);
        ThingSpeak.setField(2, liquidLoadCell);
        ThingSpeak.setField(3, internalTemperature);
        ThingSpeak.setField(4, internalHumidity);
        ThingSpeak.setField(5, ambientTemperature);
        ThingSpeak.setField(6, ambientHumidity);
        ThingSpeak.setField(7, liquidTemperature);
        ThingSpeak.setField(8, batterySoC);

        // Write the fields that you've set all at once.
        err1 = ThingSpeak.writeFields(myChannelNumber1, myWriteAPIKey1.c_str());

        if (debugEnabled)
        {
            String tempstring = "Data posted to ThingSpeak Ch1: " + (String)err1;
            Particle.publish(tempstring);
        }

    } while (err1 != 200 && attempts++ < 5);

    attempts = 0;
    int err2 = 0;
    do
    {
        // set fields one at a time for channel 2 - contains usage state data
        ThingSpeak.setField(1, fanSpeed);
        ThingSpeak.setField(2, heaterRelayOn);
        ThingSpeak.setField(3, inlineFanRelayOn);
        ThingSpeak.setField(4, heaterFloatSwitchTriggered);
        ThingSpeak.setField(5, overflowFloatSwitchTriggered);
        ThingSpeak.setField(6, warningLEDOn);

        // Write the fields that you've set all at once.
        err2 = ThingSpeak.writeFields(myChannelNumber2, myWriteAPIKey2.c_str());
        if (debugEnabled)
        {
            String tempstring = "Data posted to ThingSpeak Ch2: " + (String)err2;
            Particle.publish(tempstring);
        }
    } while (err2 != 200 && attempts++ < 5);

    lastLog = currentTime;
}
1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.