Trying to read voltage and send to thingspeak

Hi people.

I’m new to Arduino (and programming for that matter), and I need some guidance on this project.

What I’m trying to do is to monitor the voltage produced by a fuel cell, and send it to Thingspeak at regular intervals. The voltage produced will be between 0 and 1 V, so I want to use the internal 1,1V reference.

At the moment, I only get 0V, so it seems I’m not actually reading the voltage, just sending a 0 every time. Testing with a multimeter shows the actual voltage to be around 0,5 at the moment.

As my coding knowledge is rudimentary at best, I have botched this together from various tutorials, and have probably missed something obvious.

// Include the libraries

#include <RtcDS3231.h>
#include <SoftwareSerial.h>
#include "SSD1306AsciiWire.h"
#include "WiFiEsp.h"
#include <Wire.h>



// Declare and initialise global arrays for WiFi settings
char ssid[] = "Name";
char pass[] = "Password";

// Declare and initialise global variables/arrays for Thingspeak connection
const char server[] = "thingspeak.com";
const char thingspeakAPIKey[] = "Key";
long postingInterval = 30000;

// Create new display object
SSD1306AsciiWire oled;


// Create new RTC module object
RtcDS3231<TwoWire> rtcModule(Wire);

// Create new client object
WiFiEspClient client;


// Create WiFi module object on GPIO pin 6 (RX) and 7 (TX)
SoftwareSerial Serial1(6, 7);

// Declare and initialise variable for radio status 
int status = WL_IDLE_STATUS;

// Declare global variables for time and voltage
int hours;
int minutes;
int seconds;
int sensorValue = analogRead(A0);
float voltage = sensorValue * (1.1 / 1023.0);

// Declare global variables/arrays for timing
int oldMinute;
char lastSent[20];

void setup() {
  
  // Enable I2C communication
  Wire.begin();         

  // Start display on adress 0x3C
  oled.begin(&Adafruit128x64, 0x3C);
  oled.setFont(utf8font10x16);
  oled.clear();
  oled.print("Starting");
  
  // Initialise serial for debugging
  Serial.begin(115200);

  
  // Start RTC module
  rtcModule.Begin();

  

  //Set internal voltage reference of 1.1V
  analogReference(INTERNAL);
 

  // Add dot to start up animation
  oled.print(".");

  // Initialise serial for ESP module
  Serial1.begin(9600);
  
  // Initialise ESP module
  WiFi.init(&Serial1);

  // Add dot to start up animation
  oled.print(".");

  // Check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // Don't continue
    while(true);
  }
  
  // Attempt to connect to WiFi network
  while(status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);

    // Add dot to start up animation
    oled.print(".");
  }
  printWifiStatus();
  printOled();
  updateVoltage();
}

void loop(){
  updateTime();
 
  
  // Update channel on Thingspeak (every postingInterval)
  if(seconds%postingInterval == 0){
    updateVoltage();
    sendThingspeak(voltage);
  } 

  client.flush();
  client.stop();
  delay(500);
}

void sendThingspeak(float value) {
  if (client.connectSSL(server, 443)) {
    Serial.println("Connected to server.");
    client.println("GET /update?api_key=" + String(thingspeakAPIKey) + 
    "&field1=" + String(value) + " HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    client.println("Connection: close");
    client.println();
    Serial.println("Sent to server.");
    
    // Save sent time as char-array
    sprintf(lastSent, "Sent: %02d:%02d:%02d", hours, minutes, seconds);
    
    // Update time on display
    printOled();
    delay(1000);
  }
}

void updateTime() {
  oldMinute = minutes;
  RtcDateTime now = rtcModule.GetDateTime();

  // Save time in variables
  hours = now.Hour();
  minutes = now.Minute();
  seconds = now.Second();

  // Update screen on minute update
  if(minutes != oldMinute) {
    printOled();
  } 

 
}


void printOled() {
  
  // Format and print time on display
  oled.clear();
  oled.setFont(lcdnums14x24);
  oled.setCol(20);
  char timeString[6];
  sprintf(timeString, "%02d:%02d", hours,minutes);
  oled.println(timeString);

  // Format and print voltage on display
  oled.setFont(utf8font10x16);
  oled.setRow(6);
  oled.setCol(100);
  oled.print(int(voltage));
  oled.write(176);


  // Format and print last sent time on display
  oled.setCol(0);
  oled.print(lastSent);
}



void updateVoltage(){
  

  
  
  
}

void printWifiStatus() {
  
  // Print the SSID of the network
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print the IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}

Start with a simple sketch which read the voltage and send it to a serial port (Serial.print())

I have done that, and verified that I can read the voltage correctly.

I can also send the temperature from my RTC module to thingspeak, so both things work separately.

When you are using the clock time to determine when to get the voltage and update thingsqueak, what is the point of delay() in loop()? Why are there ANY delay()s in your code?

Why are you flushing and stopping the client in loop()? ALL interactions with the client should happen in sendThingspeak().

void updateVoltage(){
 

 
 
 
}

Looks to me like you forgot to write some code. You only read the voltage once, BEFORE the hardware is ready. Of course you are then going to send garbage to thingsqueak.

PaulS:
When you are using the clock time to determine when to get the voltage and update thingsqueak, what is the point of delay() in loop()? Why are there ANY delay()s in your code?

Those were leftovers from the code I used as a starting point, and had no purpose here.

PaulS:
Why are you flushing and stopping the client in loop()? ALL interactions with the client should happen in sendThingspeak().

If I move flush and stop under sendThingspeak, nothing gets sent for some reason. I got it to work now, but had to leave flus and stop in the loop.

This is the working code.

// Include the libraries

#include <RtcDS3231.h>
#include <SoftwareSerial.h>
#include "SSD1306AsciiWire.h"
#include "WiFiEsp.h"
#include <Wire.h>



// Declare and initialise global arrays for WiFi settings
char ssid[] = "Network name";
char pass[] = "Network password";

// Declare and initialise global variables/arrays for Thingspeak connection
const char server[] = "thingspeak.com";
const char thingspeakAPIKey[] = "Key";
long postingInterval = 30000;

// Create new display object
SSD1306AsciiWire oled;


// Create new RTC module object
RtcDS3231<TwoWire> rtcModule(Wire);

// Create new client object
WiFiEspClient client;


// Create WiFi module object on GPIO pin 6 (RX) and 7 (TX)
SoftwareSerial Serial1(6, 7);

// Declare and initialise variable for radio status 
int status = WL_IDLE_STATUS;

// Declare global variables for time and voltage
int hours;
int minutes;
int seconds;
int sensorValue = analogRead(A0);
float voltage = sensorValue * (1.1 / 1023.0);

// Declare global variables/arrays for timing
int oldMinute;
char lastSent[20];

void setup() {
  
  // Enable I2C communication
  Wire.begin();         

  // Start display on adress 0x3C
  oled.begin(&Adafruit128x64, 0x3C);
  oled.setFont(utf8font10x16);
  oled.clear();
  oled.print("Starting");
  
  // Initialise serial for debugging
  Serial.begin(115200);

  
  // Start RTC module
  rtcModule.Begin();

  

  //Set internal voltage reference of 1.1V
  analogReference(INTERNAL);
 

  // Add dot to start up animation
  oled.print(".");

  // Initialise serial for ESP module
  Serial1.begin(9600);
  
  // Initialise ESP module
  WiFi.init(&Serial1);

  // Add dot to start up animation
  oled.print(".");

  // Check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // Don't continue
    while(true);
  }
  
  // Attempt to connect to WiFi network
  while(status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);

    // Add dot to start up animation
    oled.print(".");
  }
  printWifiStatus();
  updateVoltage();
  printOled();
}

void loop(){
  updateTime();
 
  
  // Update channel on Thingspeak (every postingInterval)
  if(seconds%postingInterval == 0){
    updateVoltage();
    sendThingspeak(voltage);
  } 

  client.flush();
  client.stop();

}

void sendThingspeak(float value) {
  if (client.connectSSL(server, 443)) {
    Serial.println("Connected to server.");
    client.println("GET /update?api_key=" + String(thingspeakAPIKey) + 
    "&field1=" + String(value) + " HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    client.println("Connection: close");
    client.println();
    Serial.println("Sent to server.");
    Serial.println(voltage);
    
    // Save sent time as char-array
    sprintf(lastSent, "Sent: %02d:%02d:%02d", hours, minutes, seconds);
    
    // Update time on display
    printOled();
  }
  
}

void updateTime() {
  oldMinute = minutes;
  RtcDateTime now = rtcModule.GetDateTime();

  // Save time in variables
  hours = now.Hour();
  minutes = now.Minute();
  seconds = now.Second();

  // Update screen on minute update
  if(minutes != oldMinute) {
    printOled();
  } 

 
}


void printOled() {
  
  // Format and print time on display
  oled.clear();
  oled.setFont(lcdnums14x24);
  oled.setCol(20);
  char timeString[6];
  sprintf(timeString, "%02d:%02d", hours,minutes);
  oled.println(timeString);

  // Format and print voltage on display
  oled.setFont(utf8font10x16);
  oled.setRow(6);
  oled.setCol(100);
  oled.print(int(voltage));
  oled.write(176);


  // Format and print last sent time on display
  oled.setCol(0);
  oled.print(lastSent);
}



void updateVoltage(){
  
// read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 1.1V):
voltage = sensorValue * (1.1 / 1023.0);
  
  
  
}

void printWifiStatus() {
  
  // Print the SSID of the network
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print the IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}
int hours;
int minutes;
int seconds;

For those REALLY long days with 30000 hours?

Using the most appropriate type is a good habit to develop.

PaulS:
For those REALLY long days with 30000 hours?

Using the most appropriate type is a good habit to develop.

I'm afraid I don't get this one.
Are you referring to the 30 second posting interval?

Asche:
I’m afraid I don’t get this one.
Are you referring to the 30 second posting interval?

An int can hold a value in the range -32768 to 32767. Do you REALLY need that range? Aren’t there 24 hours per day on your planet?

PaulS:
An int can hold a value in the range -32768 to 32767. Do you REALLY need that range? Aren't there 24 hours per day on your planet?

Condescending posts like that aren't very helpful.

As I wrote in my first post, I'm new to arduino and programming.

Feel free to explain what you think I'm doing wrong. I am very happy to hear useful suggestions on improvement.

Condescending posts like that aren't very helpful.

Grow a thicker skin, or don't come here.

You REALLY need to understand data types, and the amount of memory they use, and the amount (very freaking little) an Arduino has, and you need to learn to use the proper type/size.

PaulS:
Grow a thicker skin, or don't come here.

Plenty of skin, thank you. I just felt the post wasn't very informative.

PaulS:
You REALLY need to understand data types, and the amount of memory they use, and the amount (very freaking little) an Arduino has, and you need to learn to use the proper type/size.

Working on it. I just can't see that I have defined 30000 hours anywhere.

I defined a posting interval of 30000 milliseconds with:

long postingInterval = 30000;

I see that I can do the same with:

const int postingInterval = 30;

Working on it. I just can't see that I have defined 30000 hours anywhere.

I didn't say that you did. Your variable type unnecessarily allows for that, though.

PaulS:
I didn't say that you did. Your variable type unnecessarily allows for that, though.

Ahh, yes of course.

That is something I can refine.

What I'm really curious about now is how to increase the number of decimals sent to thingspeak. At the moment I'm only getting 2 decimal places, but I would like to have 4.

What I'm really curious about now is how to increase the number of decimals sent to thingspeak. At the moment I'm only getting 2 decimal places, but I would like to have 4.

You are sending a float (not a string representation of a float value) to thingsqueak. If you want thingsqueak to show (present a string representation of a float value) more decimal places, take it up with thingsqueak.

I realised I'm not actually sending float values to ThingSpeak, but a string representation.

 client.println("GET /update?api_key=" + String(thingspeakAPIKey) + 
    "&field1=" + String(value,4) + " HTTP/1.1");

That made it easy enough to define the number of decimals sent. In this case 4.

Asche:
That made it easy enough to define the number of decimals sent. In this case 4.

Do you really think you are measuring voltage to 4 decimal places?

The resolution of the ADC on the Arduino is 1 part in 1024. So, with a VERY accurate device actually connected to the ADC pin, you'll get a voltage reading that changes in the third decimal place AT BEST.

PaulS:
The resolution of the ADC on the Arduino is 1 part in 1024. So, with a VERY accurate device actually connected to the ADC pin, you'll get a voltage reading that changes in the third decimal place AT BEST.

I know.
This is a learning experience for me, not high precision science. I have propper instruments for the job, but I want to see what I can actually do with a cheap arduino based system.