🎁📬❄️📦 Holiday Shipping Deadlines are approaching! International customers and domestic ground - get your orders in 12/9/2020 📦❄️📬🎁
0

help with HTTP API
Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Please be positive and constructive with your questions and comments.

help with HTTP API

by mgenova79 on Thu Dec 19, 2019 5:32 pm

Hello everyone, this is my first post and i'm looking for some help using the HTTP API. I am new to HTTP requests and struggling trying to get sensor data from a DS18B20 to adafruit.io. I am using an arduino nano 33 IoT. I previously had the project working with thingspeak, but wanted to give adafruit.io a try because of the neat dashboards. I found several examples using an ESP8266 but could not find much documentation for a SAMD board. I do not wish to use the MQTT api because i only plan on logging data every 10 minutes or so, hence why i chose to use HTTP. the code hangs at client.post in the log_data_to_cloud() function and my status code returns a -1. I am sure the problem is with my syntax but have ran out of ideas. Any help is greatly appreciated.

P.S. I am an electrical engineering student, coding is not my best ability but i can manage. Its a bit messy so go easy on me :) code is attached. thanks in advance.

Code: Select all | TOGGLE FULL SIZE
#include <ArduinoJson.h>
#include <SPI.h>
#include <ArduinoHttpClient.h>
#include <Wire.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include "ThingSpeak.h"
#include "secrets.h"                                       
//Wifinina is for SAMD boards such as nano 33 IoT
#include <WiFiNINA.h>
//uncomment this for esp32
//#include <WiFi.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
#define ONE_WIRE_BUS 12   
#define compressor_relay_pin 11
#define case_lights_relay_pin 10
//eventually i want to cycle the fan on 5 min off 5 min for energy saving
//#define fan_relay_pin 3
#define button_pin 2

RTC_DS3231 rtc;

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress sensor_1_address = { 0x28, 0xCD, 0x50, 0x45, 0x92, 0x6, 0x2, 0x4E };
//DeviceAddress sensor_2_address = { 0x28, 0x97, 0xCB, 0x79, 0x97, 0x0, 0x3, 0xF3 };  BAD SENSOR
LiquidCrystal_I2C lcd(0x27,20,4);

int port = 443;
char ssid[] = SECRET_SSID;                                 
char pass[] = SECRET_PASS;
int keyIndex = 0;
const char url[] = "io.adafruit.com/api/v2/mgenova79/feeds/autonomous-beer-fridge-temp";

String response;
int statusCode = 0;

char adafruit_username[] = IO_USERNAME;
char adafruit_key[] = IO_KEY;
int status = WL_IDLE_STATUS;
WiFiSSLClient wifi;
HttpClient client = HttpClient(wifi, url, port);


//***********************VARIABLES******************************************

unsigned long myChannelNumber = SECRET_CH_ID;
const char * myWriteAPIKey = SECRET_WRITE_APIKEY;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
unsigned long current_millis;                               
unsigned long previous_compressor_millis = 0;
unsigned long previous_email_millis = 0;
unsigned long previous_datalog_millis = 0;
unsigned long previous_alarm_millis = 0;
unsigned long rtc_interval = 30000;
unsigned long log_interval = 30000;
unsigned long compressor_interval = 30000;
unsigned long alarm_interval = 30000;
unsigned long email_interval = 1800000;
unsigned int alarm_counter = 0;
//thingspeak will take a float or integer, not a double.  double will not compile
float discharge_air_temp = 0;                                         
float return_air_temp = 0;                                     
const int high_alarm_setpoint = 65;                               
const int low_alarm_setpoint = 20;
const int cut_in_temp = 45;
const int cut_out_temp = 25;
bool alarm_state = 0;
unsigned long previous_millis_rtc = 0;

int button_state;
int last_button_state = LOW;
unsigned long last_debounce_time = 0;
unsigned long debounce_delay = 50;

const unsigned int on_hour = 17;
const unsigned int on_min = 0;
const unsigned int off_hour = 23;
const unsigned int off_min = 0;

byte curr_hour;
byte curr_min;

bool manual_lights = false;
bool auto_lights = false;

//**************************************************************************

void init_wifi()  {
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
 

}


void reconnect() {
  if(WiFi.status() != WL_CONNECTED){
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(SECRET_SSID);
    while(WiFi.status() != WL_CONNECTED){
      WiFi.begin(ssid, pass);                              // Connect to WPA/WPA2 network. Change this line if using open or WEP network
      Serial.print(".");
      delay(2000);     
    }
    Serial.println("\nConnected.");
    Serial.println(WiFi.localIP());
  }
}


void print_wifi_status() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  lcd.setCursor(0,1);
  lcd.print(WiFi.localIP());
  delay(3000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("AutonomousBeerFridge");    // if you see this, net connection is ok
}


void get_rtc_time()  {
  if ( ( millis() - previous_millis_rtc) >= rtc_interval)  {
    DateTime now = rtc.now();
    curr_hour = now.hour();
    curr_min = now.minute();
    Serial.println();
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(curr_hour, DEC);
    Serial.print(':');
    Serial.print(curr_min, DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
    previous_millis_rtc = millis();

    if ( on_hour <= off_hour)  {
      if ( ( curr_hour >= on_hour ) && ( curr_min >= on_min )) {
        auto_lights = 1;
      } 
      if ( ( curr_hour >= off_hour ) && ( curr_min >= off_min )) {
      auto_lights = 0;
      }
    }     
    if ( on_hour > off_hour)  { 
      if ( ( curr_hour >= off_hour ) && ( curr_min >= off_min )) {
        auto_lights = 0;
      } 
      if ( ( curr_hour >= on_hour ) && ( curr_min >= on_min )) {
      auto_lights = 1;
      }
    }
  Serial.print( "manual light ststus: ");
  Serial.print(manual_lights);
  Serial.print( "   auto light ststus: ");
  Serial.print(auto_lights);
  Serial.println(); 
   if ( ( manual_lights == 1 ) || ( auto_lights == 1 ) )  {
    digitalWrite(case_lights_relay_pin, HIGH);
  }
  else  {
    digitalWrite(case_lights_relay_pin, LOW );
  }
  }
}


void check_button_status() {
  int reading = digitalRead(button_pin);
  if (reading != last_button_state) {
    last_debounce_time = millis();
  }
  if ( (millis() - last_debounce_time) > debounce_delay) {
    if (reading != button_state) {
      button_state = reading;
      if (button_state == LOW) {
        manual_lights = !manual_lights;
        if (manual_lights == 1)  {
          Serial.print("manual lights on = ");
          Serial.println(manual_lights);
        }
        else  {
          Serial.print("manual lights off = ");
          Serial.println(manual_lights);
        }
      }
    }
  }
 
  last_button_state = reading;
}


void log_temp_data_to_cloud()   {
  if ( current_millis - previous_datalog_millis >= log_interval) {
    sensors.requestTemperatures();
    discharge_air_temp = sensors.getTempF(sensor_1_address);
    //return_air_temp = sensors.getTempF(sensor_2_address);
    Serial.println(discharge_air_temp);
    //Serial.println(return_air_temp);
   
   
    // AIO http code
    String values = "temp=" + String(discharge_air_temp);
    client.beginRequest();
    client.post("/api/v2/mgenova79/feeds/autonomous-beer-fridge-temp" + values);
    client.sendHeader("X-AIO-Key", adafruit_key);
    client.sendHeader("Content-Type", "application/json");
    client.endRequest();
    int statusCode = client.responseStatusCode();
    String response = client.responseBody();
    if (statusCode == 200 )  {
      Serial.println("data uploaded successfully!");
    }
    else {
      Serial.print("sorry, an error occured with status code: ");
      Serial.println(statusCode);
      Serial.print("response: ");
      Serial.println(response);
    }

    // https://io.adafruit.com/api/v2/mgenova79/feeds/autonomous-beer-fridge-temp
    // https://io.adafruit.com/mgenova79/feeds/autonomous-beer-fridge-temp

  previous_datalog_millis = current_millis;
  }
}


void cycle_compressor_relay()  {
  if (current_millis - previous_compressor_millis >= compressor_interval)   { 
    if (discharge_air_temp > cut_in_temp){
        digitalWrite(compressor_relay_pin, HIGH);                   //relay command on
        lcd.setCursor(0,2);
        lcd.print("             ");
        lcd.setCursor(0,2);
        lcd.print("Mode: Cooling");
        Serial.println("Mode: Cooling");
      }
 
      if (discharge_air_temp < cut_out_temp){
        digitalWrite(compressor_relay_pin, LOW);                   //relay command off
        lcd.setCursor(0,2);
        lcd.print("             ");
        lcd.setCursor(0,2);
        lcd.print("Mode: idle");
        Serial.println("Mode: Idle");
      }
    previous_compressor_millis = current_millis;
  }
}


void check_alarm_status()  {
  if (current_millis - previous_alarm_millis >= alarm_interval)  {
    if (discharge_air_temp >= high_alarm_setpoint || discharge_air_temp <= low_alarm_setpoint)  {
      alarm_state = 1;
      Serial.print("in alarm state for ");
      Serial.print( ( current_millis - alarm_counter )/1000);
      Serial.println(" seconds");
      lcd.setCursor(0,3);
      lcd.print("ALARM !!");
    }
    else  {
      alarm_state = 0;
      alarm_counter = current_millis;
      lcd.setCursor(0,3);
      lcd.print("        ");
    }
  previous_alarm_millis = current_millis;
  }
  if (current_millis - previous_email_millis >= email_interval && alarm_state == 1)  {
    //send email here, create a new function
    Serial.println("Email Sent!");
    previous_email_millis = current_millis;
  }
}


void setup() {
  delay(3000); // wait for console opening
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  lcd.init();
  lcd.backlight();
  lcd.clear();
  sensors.begin();
  init_wifi();
  print_wifi_status();
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  pinMode(compressor_relay_pin, OUTPUT); 
  pinMode(case_lights_relay_pin, OUTPUT);
  digitalWrite(compressor_relay_pin, LOW);
  digitalWrite(case_lights_relay_pin, LOW);
  pinMode(button_pin, INPUT_PULLUP);
  digitalWrite(button_pin, HIGH);
  ThingSpeak.begin(wifi);
}


void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    print_wifi_status();
    return;
  }
  current_millis = millis();
  get_rtc_time();
  check_button_status();
  log_temp_data_to_cloud();
  cycle_compressor_relay();
  check_alarm_status();
}




mgenova79
 
Posts: 5
Joined: Thu Dec 19, 2019 5:20 pm

Re: help with HTTP API

by mgenova79 on Thu Dec 19, 2019 6:15 pm

spent a little more time reading and found that i had too much information in the url so i changed

Code: Select all | TOGGLE FULL SIZE
const char url[] = "io.adafruit.com/api/v2/mgenova79/feeds/autonomous-beer-fridge-temp";


Code: Select all | TOGGLE FULL SIZE
const char url[] = "io.adafruit.com";


am i right that the path to the feed is implemented like this?
Code: Select all | TOGGLE FULL SIZE
client.post("/api/v2/mgenova79/feeds/autonomous-beer-fridge-temp" + values);


i am now getting error code 404 with a response of:
not found - that is an invalid URL, please check the API documentation at https://io.adafruit.com/api/docs to make sure your URL is correct

I think i am getting close, just not sure what the formatting is supposed to look like

mgenova79
 
Posts: 5
Joined: Thu Dec 19, 2019 5:20 pm

Re: help with HTTP API

by mgenova79 on Mon Dec 23, 2019 2:25 am

well I spent the better part of the weekend reading the documentation at arduinojson.org and finally figured out how to serialize the data properly and i got the code working. Here is the minimal-ish code that I made for a test to push data to adafruit.io. I hope this helps someone else.

Code: Select all | TOGGLE FULL SIZE
#include <ArduinoJson.h>
#include <SPI.h>
#include <ArduinoHttpClient.h>
#include <WiFiNINA.h>
#include "secrets.h"

char ssid[] = SECRET_SSID;                                 
char pass[] = SECRET_PASS;
int keyIndex = 0;
int status = WL_IDLE_STATUS;
char adafruit_username[] = IO_USERNAME;
char adafruit_key[] = IO_KEY;
String response;
int statusCode = 0;
const char url[] = "io.adafruit.com";
int port = 443;

WiFiSSLClient wifi;
HttpClient client = HttpClient(wifi, url, port);


void init_wifi()  {
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
}


void print_wifi_status() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}


void send_data_to_adafruitIO()  {

  // Allocate JsonDocument
  const int capacity = JSON_ARRAY_SIZE(2) + 4 * JSON_OBJECT_SIZE(2);
  StaticJsonDocument<capacity> doc;

  // Add the "feeds" array
  JsonArray feeds = doc.createNestedArray("feeds");
  JsonObject feed1 = feeds.createNestedObject();
  feed1["key"] = "DischargeAirTemp";
  feed1["value"] = 24.78;
  JsonObject feed2 = feeds.createNestedObject();
  feed2["key"] = "ReturnAirTemp";
  feed2["value"] = 39.93;

  // Add the "location" object
  JsonObject location = doc.createNestedObject("location");
  location["lat"] = 35.363892;
  location["lon"] = -119.116088;
 
  //uncomment next two lines to view the minified JSON Document, this is the ideal format for sending over TCP
  //Serial.println();
  //serializeJson(doc, Serial);
 
  //uncomment next two lines to view the Prettified JSON document, preferred method for viewing.  do not send this over TCP because it used more memory.
  //Serial.println();
  //serializeJsonPretty(doc, Serial);

  client.beginRequest();
  client.post("/api/v2/mgenova79/groups/autonomousbeerfridge/data");
  client.sendHeader("X-AIO-Key", adafruit_key);
  client.sendHeader("Content-Type", "application/json");
  client.sendHeader("Content-Length", measureJson(doc));
  client.beginBody();
  serializeJson(doc, client);
  client.endRequest();
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();
 
  if (statusCode == 200 )  {
  Serial.println("data uploaded successfully!");
  }
  else {
  Serial.print("sorry, an error occured with status code: ");
  Serial.println(statusCode);
  Serial.print("response: ");
  Serial.println(response);
  }   
}


void setup() {

  delay(2000); // wait for console opening
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connnect.
  }
 
  init_wifi();
  print_wifi_status();
  send_data_to_adafruitIO();
}

void loop() {
  // put your hands up in the air here, repeatedly:
  // Seriously, do nothing
}

mgenova79
 
Posts: 5
Joined: Thu Dec 19, 2019 5:20 pm

Re: help with HTTP API

by TI545 on Wed Nov 11, 2020 1:21 pm

Hello mgenova79. Thank you for posting your solution. I also recently bought a nano33iot board. I've played around with its sensors, but have not posted data to the cloud. Your code will help me when I look at the adafruit.io documentation.

TI545
 
Posts: 11
Joined: Tue Feb 27, 2018 5:25 pm

Re: help with HTTP API

by TI545 on Wed Dec 02, 2020 3:42 pm

OK, I have your example working, thank you very much.

It didn't work, many times, and I played with the syntax. In the end, I re-read some learn.adafruit.com. This Nano33iot board uses the WifiNina chip. And I realized I could update the io.adafruit.com SSL certificates using the arduino IDE tool for WifiNina. After I did that, the Arduino sketch worked, my feed is updated.

TI545
 
Posts: 11
Joined: Tue Feb 27, 2018 5:25 pm

Re: help with HTTP API

by mgenova79 on Wed Dec 02, 2020 4:00 pm

I'm glad the code worked for you! Thanks for reporting back.

mgenova79
 
Posts: 5
Joined: Thu Dec 19, 2019 5:20 pm

Please be positive and constructive with your questions and comments.