๐ŸŽ„โ›„โ„๏ธ๐ŸŽ It's beginning to look a lot like ADABOX-mas! The next ADABOX from Adafruit ships soon! Get yours now, or give as a gift! ๐ŸŽ„โ›„โ„๏ธ๐ŸŽ
0

Read Adafruit IO Configuration FromSD Card
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.

Read Adafruit IO Configuration FromSD Card

by whmckinley on Sat Nov 02, 2019 10:42 pm

I'm trying to build a Arduino based ESP8266 Sensor that will Publish several values to the IO. I am using WifiManger for configuration of the SSID and Password and that is working well. I have been hard coding the username and key, and reliably publishing data to the AdafruitIO. My next objective is to allow the AdafruitIO credentials to be stored on a SD card and read for IO_USERNAME and IO_KEY.

I'm ok coding with inputs and outputs, reading sensors, and I've gone through the SD examples, plus used the readlines.h library. I can read the SD Files, using 2 separate files, one for IO_USERNAME and one for IO_KEY. I can read them, I can print them, but I cannot get connected to AdafruitIO with them. I'm not understanding how to get the username and key assigned to the IO_USERNAME and IO_KEY to get a successful connection.

Here is the code I am using to read the sd card. user.txt and key.txt only contain a single line with username and key respectively.

Code: Select all | TOGGLE FULL SIZE

#include <SPI.h>
#include <SD.h>
#include <ReadLines.h>

char username[RL_MAX_CHARS];
char key[RL_MAX_CHARS];

void setup() {
    Serial.begin(115200);

    while (!SD.begin(D4)) {
        Serial.println("initialization failed!");
        delay(1000);
    }
    Serial.println("");
    RL.readLines("user.txt", [](char* username) {
        Serial.println(String(username));
     
    });
    RL.readLines("key.txt", [](char* key) {
        Serial.println(String(key));
       
    });
}

void loop() {
   
}



Would appreciate any recommendations.

whmckinley
 
Posts: 10
Joined: Thu Oct 13, 2011 12:43 am

Re: Read Adafruit IO Configuration FromSD Card

by Abusement on Sun Nov 03, 2019 11:46 am

whmckinley,

This was a nightmare to figure out, and I don't honestly know if this is the best way to solve this problem. I can say that this works really well, but feels so, so wrong when you consider how the Adafruit IO library is designed. In my scenario I have an RFM69 radio that receives a signal containing sensor data from a remote unit. I then want to take that data with my wifi enabled "monitor" with an ESP32 Airlift and send it up to Adafruit for graphing and all the goodness there. This is a simple separation of concerns thing that came up from stability issues between the radio and the WiFi chip I use, but that's another frustrating topic.

Here's a link to a library I'm actively developing (working on it today too actually) that solves this issue. Unfortunately you have to deal with both reading the configuration file, in my case a JSON document, and then passing those values into the Adafruit library.

https://github.com/SirkleZero/workshop-climate-lib

Specifically I am working on the v2 branch today to tidy up some of this code to work with my new ESP32 Airlift, which so far has been MUCH less troublesome than my previous WINC1500. While doing that I've done a few updates to make things more resilient to account for failures (that happen often...).

Here's the specific code files you'll want to look at.
https://github.com/SirkleZero/workshop- ... tIOProxy.h
https://github.com/SirkleZero/workshop- ... OProxy.cpp

And all files in this Configuration namespace...
https://github.com/SirkleZero/workshop- ... figuration

When going through this you'll also see how I'm handling connect and reconnect functionality, timeouts to handle hangs, etc. There are still a few things that I'm working on feature wise here, but this should make it much easier for you to see how this can be done. For example, today I'll be working through how to create and manage a timeout when calling io->run(). I've found that if this takes too long to run my Watchdog timer will restart the device, thinking it crashed. I'm not entirely sure how I'll deal with this yet, so you'll see a TODO comment in there depending on when I address it and when you look at it.

To see how I use the library, you can look at this project, also the v2 branch. I'm pretty big into having simple Sketch documents, and moving my logic into easy to understand design patterned objects. This makes it MUCH easier to add and remove components from the system, even when there are dependencies to navigate.

https://github.com/SirkleZero/workshop-climate-monitor

If you need any help understanding any of this, lemme know and I'll do my best to answer your questions.

Abusement
 
Posts: 11
Joined: Wed Oct 17, 2018 7:26 pm

Re: Read Adafruit IO Configuration FromSD Card

by whmckinley on Thu Nov 07, 2019 12:18 am

Abusement, Thank You for your recommendations and pointer. However my use case scenario is quite different than yours. Mine is a sensor that is only active Every half hour, monitoring a pool temperature. It is being power cycled by a TPL5110 and only sends a single value to the Adafruit IO. I have found a method that works for me. I've attached an example kluged together from the Wifimanager and the publish example. It allows me to configure the network and the AdafruitIO IO_USERNAME and IO_Key

Again, Thanks

Code: Select all | TOGGLE FULL SIZE
#include <FS.h>                   //this needs to be first, or it all crashes and burns...

#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino

//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include "AdafruitIO_WiFi.h"

#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson

//define your default values here, if there are different values in config.json, they are overwritten.
char IO_USERNAME[40]; // has to match #define IO_USERNAME, place holder
char IO_KEY[34];    // has to match #define IO_KEY, place holder

// DO Not use the #defines for IO_USERNAME or IO_KEY
#define WIFI_SSID   ""  // needed for good compile
#define WIFI_PASS   "" // needed for good compile
int count = 0;

//flag for saving data
bool shouldSaveConfig = false;

//callback notifying us of the need to save config
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println();

  //clean FS, for testing
//  SPIFFS.format();

  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("\nparsed json");

          strcpy(IO_USERNAME, json["IO_USERNAME"]);
          strcpy(IO_KEY, json["IO_KEY"]);

        } else {
          Serial.println("failed to load json config");
        }
        configFile.close();
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  //end read



  // The extra parameters to be configured (can be either global or just in the setup)
  // After connecting, parameter.getValue() will get you the configured value
  // id/name placeholder/prompt default length

  WiFiManagerParameter custom_IO_USERNAME("name", "IO_USERNAME", IO_USERNAME, 40);
  WiFiManagerParameter custom_IO_KEY("key", "IO_KEY", IO_KEY, 32);

  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;

  //set config save notify callback
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  //set static ip
  //  wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0));

  //add all your parameters here
  wifiManager.addParameter(&custom_IO_USERNAME);
  wifiManager.addParameter(&custom_IO_KEY);

  //reset settings - for testing
 // wifiManager.resetSettings();

  //set minimu quality of signal so it ignores AP's under that quality
  //defaults to 8%
  //wifiManager.setMinimumSignalQuality();

  //sets timeout until configuration portal gets turned off
  //useful to make it all retry or go to sleep
  //in seconds
  //wifiManager.setTimeout(120);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect("AutoConnectAP")) {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000);
  }

  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");

  //read updated parameters, this is where the IO_USERNAME and IO_KEY get set by the Wifimanager
  strcpy(IO_USERNAME, custom_IO_USERNAME.getValue());
  strcpy(IO_KEY, custom_IO_KEY.getValue());

  //save the custom parameters to FS
  if (shouldSaveConfig) {
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["IO_USERNAME"] = IO_USERNAME;
    json["IO_KEY"] = IO_KEY;

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }

    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }

  Serial.println("local ip");
  Serial.println(WiFi.localIP());

// Test section to verify connection and publish to AdafruitIO, just using basic publish example.

 AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
  AdafruitIO_Feed *counter = io.feed("counter");
  Serial.print("Connecting to Adafruit IO");
  // connect to io.adafruit.com
  io.connect();

  // wait for a connection
  while (io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  // we are connected
  Serial.println();
  Serial.println(io.statusText());
  // put your main code here, to run repeatedly:
   Serial.print("sending -> ");
  Serial.println(count);
  counter->save(count);

 }

void loop() {

// Empty

}

whmckinley
 
Posts: 10
Joined: Thu Oct 13, 2011 12:43 am

Please be positive and constructive with your questions and comments.