Store data and upload when online

Hi,

I know this has been posted in the past I can’t find a clean example on how to do this. Would anyone be willing to share their code on how to store variable data with timestamp when offline and public then publish the data to the Particle cloud when online.

We are always willing to help but this community rather wants to enable you to solve any given problem instead of providing off-the-shelf solutions.

What have you tried?
What did you not understand in any of the codes you looked at before?

4 Likes

@ScruffR

Ok here is what I have so far but please take it easy on me I’m trying to waste anyone’s time. The code verifies OK but does not save or return the data correctly. Any guidance really appreciated!

// This #include statement was automatically added by the Particle IDE.
#include <Ubidots.h>

// Distributed with a free-will license.
// Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
// TMP112
// This code is designed to work with the TMP112_I2CS I2C Mini Module available from ControlEverything.com.
// https://www.controleverything.com/content/Temperature?sku=TMP112_I2CS#tabs-0-product_tabset-2

#include <application.h>
#include <spark_wiring_i2c.h>

// TMP112 I2C address is 0x48(72)
#define Addr 0x48

SYSTEM_THREAD(ENABLED);

double cTemp = 0.0, fTemp = 0.0;


const char* WEBHOOK_NAME = "Ubidots";

Ubidots ubidots("webhook", UBI_PARTICLE);


int address = 0;      //EEPROM address counter


void printTemp();
void clearEEPROM();

unsigned long timestamp_seconds = Time.now();

struct MyObject {
  char name[13];
  double field1;
  char field2[4];
  unsigned long field3;
};

void setup() 
{
    
    Serial.begin();
	pinMode(PWR, INPUT);
	pinMode(CHG, INPUT);
    
    
    // Set variable
    Particle.variable("i2cdevice", "TMP112");
    Particle.variable("cTemp", cTemp);
    Particle.variable("fTemp", fTemp);

   
    // Initialise I2C communication as MASTER 
    Wire.begin();
    // Initialise Serial communication, set baud rate = 9600
    Serial.begin(9600);
    
    // Start I2C Transmission
    Wire.beginTransmission(Addr);
    // Select configuration register
    Wire.write(0x01);
    // Continuous conversion, comparator mode, 12-bit resolution
    Wire.write(0x60);
    Wire.write(0xA0);
    // Stop I2C Transmission
    Wire.endTransmission();
    delay(300);  
    
    
    
}


void loop()
{
    
    delay(15000);
    unsigned int data[2];
    // Start I2C Transmission
    Wire.beginTransmission(Addr);
    // Select temperature data register
    Wire.write(0x00);
    // Stop I2C Transmission
    Wire.endTransmission();
    delay(300);
    
    // Request 2 bytes of data
    Wire.requestFrom(Addr, 2);
    
    // Read 2 bytes of data
    // temp msb, temp lsb
    if(Wire.available() == 2)
    {
        data[0] = Wire.read();
        data[1] = Wire.read();
    }
    
    // Convert the data to 12-bits
    int temp = ((data[0] * 256) + (data[1])) / 16;
    if(temp > 2048)
    {
        temp -= 4096;
    }
    cTemp = temp * 0.0625;
    fTemp = cTemp * 1.8 + 32;
    
    if(Particle.connected()==true) {


            // Output data to dashboard
        
            ubidots.add("Temperature", fTemp, NULL, timestamp_seconds); // Change for your variable name
            bool bufferSent = false;
            bufferSent = ubidots.send(WEBHOOK_NAME, PUBLIC);
            
    
        	printTemp();
        	clearEEPROM();
        	
	
    }
    
    
   if(Particle.connected()==false)  {
       
       
            MyObject myObj = {"Temperature", fTemp, NULL, timestamp_seconds };
            EEPROM.put(address, myObj);         //write value to current address counter address
                 
            address++;                      //increment address counter
              if(address == EEPROM.length())  //check if address counter has reached the end of EEPROM
                {
                    address = 0;              //if yes: reset address counter
                }
            
         }
    
    
}   
    
 
    
void clearEEPROM()
    {
      for (int i = 0 ; i < EEPROM.length() ; i++) {
        if(EEPROM.read(i) != 0)                     //skip already "empty" addresses
        {
          EEPROM.write(i, 0);                      //write 0 to address i
          Particle.publish("DataCleared");
        }
      }
    
      address = 0;                                  //reset address counter
      
    }
    
    
void printTemp()
    {
      for (int i = 0 ; i < EEPROM.length() ; i++) {
          uint8_t value = EEPROM.read(i); 
       
        if(value != 0) //skip "empty" addresses
        {           
           
            MyObject myObj;
            EEPROM.get(i, myObj);                //read EEPROM data at address i
            ubidots.add(myObj.name, myObj.field1, myObj.field2, myObj.field3 );
         
         	bool bufferSent = false;
	        bufferSent = ubidots.send(WEBHOOK_NAME, PUBLIC);
	        Particle.publish("DataRetrieved");
        }
      }
    }

You might also want to take a quick look at :

3 Likes

What is your specific question or what does your code not do the way you expect it?

But I found a few things you may want to (re)consider.

  • You are using timestamp_seconds but only set it once, hence all your data objects will get the same time stamp. You need to refresh the value each time you collect/store new data.
  • You are only incrementing address by 1, but your data structure is longer than one byte, hence each new EEPROM.put() will corrupt the previously stored object(s).
  • Since your project seems to run permanently, you could use a normal array of MyObject fields - or if you want your data to survive a reset even opt for a retained array instead of EEPROM based instances of “volatile” data.

BTW, since you are always storing the same name with the actual data you are wasting almost half the memory on non-information. The name is only needed for publishing to ubidots and you have that hardcoded in all cases when creating a new set of data so the worth of that field is zero but uses a big portion of your data.

The other point is that it shouldn’t be necessary to always call ubidots.send() after each ubidots.add() call. AFAIK the add() function queues multiple entries and one final send() call should push them all out.

Also, why do you have to send PUBLIC?

4 Likes

Thanks @ScruffR @Rftop

I ended up implementing the PublishQueueAsync but I still appreciate the feedback on the code.