vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.97k stars 726 forks source link

Problem sending data to Thingspeak with NodeMCU and SIM900 module #712

Open MerlynMetal opened 1 year ago

MerlynMetal commented 1 year ago

Hi, I'm trying to communicate with my channel on Thingspeak however it looks like I'm missing something as my data doesn't appear in the feeds. Below is my code:

#define TINY_GSM_MODEM_SIM900
#include <TinyGsmClient.h>
#define SerialAT Serial
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
/* ESP12-E & Thinkspeak*/
const char apn[]  = "xxxxx";
const char user[] = "";
const char pass[] = "";
const char server[] = "api.thingspeak.com";
const int  port = 80;
const char* TS_SERVER = "api.thingspeak.com";
String TS_API_KEY ="xxxxx";
int sent = 0;
/* TIMER */
#include <SimpleTimer.h>
SimpleTimer timer;
/* OLED */
#include <ACROBOTIC_SSD1306.h> // library for OLED: SCL ==> D1; SDA ==> D2
#include <SPI.h>
#include <Wire.h>
/* DHT22*/
#include "DHT.h"
#define DHTPIN D3  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
float hum = 0;
float temp = 0;
/* Soil Moister */
#define soilMoisterPin A0
#define soilMoisterVcc D4 //not used. LM393 VCC connect to 3.3V
int soilMoister = 0;
/* DS18B20 Temperature Sensor */
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 14 // DS18B20 on NodeMCU pin D5 corresponds to GPIO 014 on Arduino
float soilTemp;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
void setup() 
{
    Serial.begin(115200);
    delay(10);
    Serial.println(".... Starting Setup");

    SerialAT.begin(115200);
    delay(3000);
  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  modem.init();

  pinMode(soilMoisterVcc, OUTPUT);
  Serial.begin(115200);
  delay(10);
  oledStart();
  dht.begin();
  DS18B20.begin();

  timer.setInterval(2000L, getDhtData);
  timer.setInterval(7000L, getSoilMoisterData);
  timer.setInterval(9000L, getSoilTempData);
  timer.setInterval(19000L, sendDataTS);
  digitalWrite (soilMoisterVcc, LOW);
}
void loop() 
{
  displayData();
  timer.run(); // Initiates SimpleTimer
}
/***************************************************
 * Start OLED
 **************************************************/
void oledStart(void)
{
  Wire.begin();  
  oled.init();                      // Initialze SSD1306 OLED display
  clearOledDisplay();
  oled.clearDisplay();              // Clear screen
  oled.setTextXY(0,0);              
  oled.putString(" ");
}
/***************************************************
 * Get DHT data
 **************************************************/
void getDhtData(void)
{
  float tempIni = temp;
  float humIni = hum;
  temp = dht.readTemperature();
  hum = dht.readHumidity();
  if (isnan(hum) || isnan(temp))   // Check if any reads failed and exit early (to try again).
  {
    Serial.println("Failed to read from DHT sensor!");
    temp = tempIni;
    hum = humIni;
    return;
  }
}
/***************************************************
 * Get Soil Moister Sensor data
 **************************************************/
void getSoilMoisterData(void)
{
  soilMoister = 0;
  digitalWrite (soilMoisterVcc, HIGH);
  delay (500);
  int N = 3;
  for(int i = 0; i < N; i++) // read sensor "N" times and get the average
  {
    soilMoister += analogRead(soilMoisterPin);   
    delay(150);
  }
  digitalWrite (soilMoisterVcc, LOW);
  soilMoister = soilMoister/N; 
  Serial.println(soilMoister);
  soilMoister = map(soilMoister, 689, 274, 0, 100); 
}
/***************************************************
 * Get SoilTemp sensor data
 **************************************************/
void getSoilTempData()
{
  DS18B20.requestTemperatures(); 
  soilTemp = DS18B20.getTempCByIndex(0);
  int newData = ((soilTemp + 0.05) * 10); //fix soilTemp value to 1 decimal place.
  soilTemp = (newData / 10.0);
}

/***************************************************
 * Display data at Serial Monitora & OLED Display
 **************************************************/
void displayData(void)
{
  Serial.print(" Temperature: ");
  Serial.print(temp);
  Serial.print("oC   Humidity: ");
  Serial.print(hum);
  Serial.println("%");
  Serial.print("SoilTemp: ");
  Serial.print(soilTemp);
  Serial.print("oC");

  oled.setTextXY(1,0);              // Set cursor position, start of line 2
  oled.putString("TEMP: " + String(temp) + " oC");
  oled.setTextXY(3,0);              // Set cursor position, start of line 2
  oled.putString("HUM : " + String(hum) + " %");
  oled.setTextXY(5,0);              // Set cursor position, start of line 2
  oled.putString("Tsoil:" + String(soilTemp) + " oC");
   oled.setTextXY(7,0);              // Set cursor position, start of line 2
  oled.putString("Hsoil: " + String(soilMoister) + " %");
}
/***************************************************
 * Clear OLED Display
 **************************************************/
void clearOledDisplay()
{
  oled.setFont(font8x8);
  oled.setTextXY(0,0); oled.putString("                ");
  oled.setTextXY(1,0); oled.putString("                ");
  oled.setTextXY(2,0); oled.putString("                ");
  oled.setTextXY(3,0); oled.putString("                ");
  oled.setTextXY(4,0); oled.putString("                ");
  oled.setTextXY(5,0); oled.putString("                ");
  oled.setTextXY(6,0); oled.putString("                ");
  oled.setTextXY(7,0); oled.putString("                ");
  oled.setTextXY(0,0); oled.putString("                ");              
}
/***************************************************
 * Sending Data to Thinkspeak Channel
 **************************************************/
void sendDataTS(void)
{
   if (client.connect(TS_SERVER, 80)) 
   { 
     String postStr = TS_API_KEY;
     postStr += "&field1=";
     postStr += String(temp);
     postStr += "&field2=";
     postStr += String(hum);
     postStr += "&field3=";
     postStr += String(soilMoister);
     postStr += "&field4=";
     postStr += String(soilTemp);
     postStr += "\r\n\r\n";

     client.print("POST /update HTTP/1.1\n");
     client.print("Host: api.thingspeak.com\n");
     client.print("Connection: close\n");
     client.print("X-THINGSPEAKAPIKEY: " + TS_API_KEY + "\n");
     client.print("Content-Type: application/x-www-form-urlencoded\n");
     client.print("Content-Length: ");
     client.print(postStr.length());
     client.print("\n\n");
     client.print(postStr);
     delay(1000); 
   }
   sent++;
   client.stop();
}

First I get this on my serial monitor:

15:24:21.509 -> AT 15:24:21.509 -> ATE0 15:24:21.518 -> AT+CMEE=0 15:24:21.552 -> AT+CLTS=1 15:24:21.552 -> AT+CBATCHK=1 15:24:21.552 -> AT+CPIN? 15:24:22.340 -> Temperature: 0.00oC Humidity: 0.00% 15:24:22.340 -> SoilTemp: 0.00oC Temperature: 0.00oC Humidity: 0.00% 15:24:22.442 -> SoilTemp: 0.00oC Temperature: 0.00oC Humidity: 0.00% 15:24:22.581 -> SoilTemp: 0.00oC Temperature: 0.00oC Humidity: 0.00%

Then Every 10 sec this:

15:26:31.972 -> SoilTemp: 20.40oC Temperature: 21.40oC Humidity: 66.40% 15:26:32.073 -> SoilTemp: 20.40oC Temperature: 21.40oC Humidity: 66.40% 15:26:32.209 -> SoilTemp: 20.40oC686 15:26:33.872 -> AT+CIPCLOSE=0,1 15:26:33.872 -> AT+CIPSTART=0,"TCP","api.thingspeak.com",80 15:26:33.906 -> AT+CIPCLOSE=0,1 15:26:33.906 -> Temperature: 21.40oC Humidity: 66.40% 15:26:33.906 -> SoilTemp: 20.40oC Temperature: 21.40oC Humidity: 66.40% 15:26:34.042 -> SoilTemp: 20.40oC Temperature: 21.40oC Humidity: 66.40% 15:26:34.178 -> SoilTemp: 20.40oC Temperature: 21.40oC Humidity: 66.40%

MerlynMetal commented 1 year ago

After several days of tweaking, trial and error I managed to get the code working. Main thing is I had to implement Software serial as the hardware serial refused to cooperate. Below is the working solution.

/**************************************************************
 *
 * Sending DHT, Soil Temp and Soil Moisture sensor data with SIM900 module to Thinspeak
 * Based on TinyGSM examples and library
 *and mjrovai ArduFarmBot series at Instructables.com
 *
 * TinyGSM Getting Started guide:
 *   http://tiny.cc/tiny-gsm-readme
 *
 **************************************************************/

#define TINY_GSM_MODEM_SIM900

// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512

#include <TinyGsmClient.h>

// Uncomment this if you want to see all AT commands
#define DUMP_AT_COMMANDS

// Uncomment this if you want to use SSL
//#define USE_SSL

// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial

// Use Hardware Serial on Mega, Leonardo, Micro
//#define SerialAT Serial

// or Software Serial on Uno, Nano
#include <SoftwareSerial.h>
SoftwareSerial SerialAT(12, 13); // RX, TX

// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[]  = "xxxxx";
const char user[] = "";
const char pass[] = "";

// Server details
const char server[] = "api.thingspeak.com";
String TS_API_KEY ="xxxxx";
int sent = 0;

#ifdef DUMP_AT_COMMANDS
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, SerialMon);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif

#ifdef USE_SSL
  TinyGsmClientSecure client(modem);
  const int  port = 443;
#else
  TinyGsmClient client(modem);
  const int  port = 80;
#endif

/* TIMER */
#include <SimpleTimer.h>
SimpleTimer timer;

/* OLED */
#include <ACROBOTIC_SSD1306.h> // library for OLED: SCL ==> D1; SDA ==> D2
#include <SPI.h>
#include <Wire.h>

/* DHT22*/
#include "DHT.h"
#define DHTPIN D3  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
float hum = 0;
float temp = 0;

/* Soil Moister */
#define soilMoisterPin A0
#define soilMoisterVcc D4 //not used. LM393 VCC connect to 3.3V
int soilMoister = 0;

/* DS18B20 Temperature Sensor */
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 14 // DS18B20 on NodeMCU pin D5 corresponds to GPIO 014 on Arduino
float soilTemp;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

void setup() 
{
  // Set console baud rate
  SerialMon.begin(9600);
  delay(10);

  // Set GSM module baud rate
  SerialAT.begin(9600);
  delay(3000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println(F("Initializing modem..."));
  modem.init();

  String modemInfo = modem.getModemInfo();
  SerialMon.print(F("Modem: "));
  SerialMon.println(modemInfo);

  // Unlock your SIM card with a PIN
  //modem.simUnlock("1234");

  Serial.begin(9600);
  delay(10);
  oledStart();
  dht.begin();
  DS18B20.begin();
  connectGPRS();
  timer.setInterval(5000L, getDhtData);
  timer.setInterval(5000L, getSoilMoisterData);
  timer.setInterval(5000L, getSoilTempData);

  timer.setInterval(10000L, sendDataTS);

}

/***************************************************
 * Start OLED
 **************************************************/
void oledStart(void)
{
  Wire.begin();  
  oled.init();                      // Initialze SSD1306 OLED display
  clearOledDisplay();
  oled.clearDisplay();              // Clear screen
  oled.setTextXY(0,0);              
  oled.putString(" ");
}

/***************************************************
 * Get DHT data
 **************************************************/
void getDhtData(void)
{
  float tempIni = temp;
  float humIni = hum;
  temp = dht.readTemperature();
  hum = dht.readHumidity();
  if (isnan(hum) || isnan(temp))   // Check if any reads failed and exit early (to try again).
  {
    Serial.println("Failed to read from DHT sensor!");
    temp = tempIni;
    hum = humIni;
    return;
  }
}

/***************************************************
 * Get Soil Moister Sensor data
 **************************************************/
void getSoilMoisterData(void)
{
  soilMoister = 0;
  digitalWrite (soilMoisterVcc, HIGH);
  delay (500);
  int N = 3;
  for(int i = 0; i < N; i++) // read sensor "N" times and get the average
  {
    soilMoister += analogRead(soilMoisterPin);   
    delay(150);
  }
  digitalWrite (soilMoisterVcc, LOW);
  soilMoister = soilMoister/N; 
  Serial.println(soilMoister);
  soilMoister = map(soilMoister, 689, 274, 0, 100); 
}

/***************************************************
 * Get SoilTemp sensor data
 **************************************************/
void getSoilTempData()
{
  DS18B20.requestTemperatures(); 
  soilTemp = DS18B20.getTempCByIndex(0);

  int newData = ((soilTemp + 0.05) * 10); //fix soilTemp value to 1 decimal place.
  soilTemp = (newData / 10.0);
}

/***************************************************
 * Display data at Serial Monitora & OLED Display
 **************************************************/
void displayData(void)
{
  //Serial.print(" Temperature: ");
  //Serial.print(temp);
  //Serial.print("oC   Humidity: ");
  //Serial.print(hum);
  //Serial.println("%");
  //Serial.print("SoilTemp: ");
  //Serial.print(soilTemp);
  //Serial.print("oC");

  oled.setTextXY(1,0);              // Set cursor position, start of line 2
  oled.putString("TEMP: " + String(temp) + " oC");
  oled.setTextXY(3,0);              // Set cursor position, start of line 2
  oled.putString("HUM : " + String(hum) + " %");
  oled.setTextXY(5,0);              // Set cursor position, start of line 2
  oled.putString("Tsoil:" + String(soilTemp) + " oC");
   oled.setTextXY(7,0);              // Set cursor position, start of line 2
  oled.putString("Hsoil: " + String(soilMoister) + " %");
}

/***************************************************
 * Clear OLED Display
 **************************************************/
void clearOledDisplay()
{
  oled.setFont(font8x8);
  oled.setTextXY(0,0); oled.putString("                ");
  oled.setTextXY(1,0); oled.putString("                ");
  oled.setTextXY(2,0); oled.putString("                ");
  oled.setTextXY(3,0); oled.putString("                ");
  oled.setTextXY(4,0); oled.putString("                ");
  oled.setTextXY(5,0); oled.putString("                ");
  oled.setTextXY(6,0); oled.putString("                ");
  oled.setTextXY(7,0); oled.putString("                ");
  oled.setTextXY(0,0); oled.putString("                ");              
}

void loop() 
  {
  displayData();
  timer.run(); // Initiates SimpleTimer
}

void connectGPRS() {

  SerialMon.print(F("Waiting for network..."));
  if (!modem.waitForNetwork()) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" OK");

  SerialMon.print(F("Connecting to "));
  SerialMon.print(apn);
  if (!modem.gprsConnect(apn, user, pass)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" OK");

  SerialMon.print(F("Connecting to "));
  SerialMon.print(server);
  if (!client.connect(server, port)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" OK");

  unsigned long timeout = millis();
  while (client.connected() && millis() - timeout < 10000L) {
    // Print available data
    while (client.available()) {
      char c = client.read();
      SerialMon.print(c);
      timeout = millis();
    }
  }
  SerialMon.println();

}

void sendDataTS(void)
{
   if (client.connect(server, 80)) 
   { 

     String postStr = TS_API_KEY;
     postStr += "&field1=";
     postStr += String(temp);
     postStr += "&field2=";
     postStr += String(hum);
     postStr += "&field3=";
     postStr += String(soilMoister);
     postStr += "&field4=";
     postStr += String(soilTemp);
     postStr += "\r\n\r\n";

     client.print("POST /update HTTP/1.1\n");
     client.print("Host: api.thingspeak.com\n");
     client.print("Connection: close\n");
     client.print("X-THINGSPEAKAPIKEY: " + TS_API_KEY + "\n");
     client.print("Content-Type: application/x-www-form-urlencoded\n");
     client.print("Content-Length: ");
     client.print(postStr.length());
     client.print("\n\n");
     client.print(postStr);
     delay(1000); 
      }
  sent++;
client.stop();
}