First project, IFTTT temperature alarm SMS(publish vs variable)

Making my first Project and a functional one to warn me if its getting too hot in the car for my dog… Using Control Everything’s I2c shield and MCP9808 sensor. they gave me this nice piece of code to start working with. But I see IFTTT wants a variable not a published number. The variable is defined early in the firmware at line 33 and 35, but the program publishes the temp at the end. does that mean IFTTT will have access to the variable Ctemp once I run the program? I don’t have my temp sensor till tomorrow so I cant test it very effectively yet.

Code: sry it posted wonky like

// 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.

// MCP9808

// This code is designed to work with the MCP9808_I2CS I2C Mini Module available from ControlEverything.com.

// https://www.controleverything.com/content/Temperature?sku=MCP9808_I2CS#tabs-0-product_tabset-2



#include <application.h>

#include <spark_wiring_i2c.h>



// MCP9808 I2C address is 0x18(24)

#define Addr 0x18



double cTemp = 0.0, fTemp = 0.0;

void setup()

{

    // Set variable

    Particle.variable("i2cdevice", "MCP9808");

    Particle.variable("cTemp", cTemp);

    

    // 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 mode, Power-up default

    Wire.write(0x00);

    Wire.write(0x00);

    // Stop I2C Transmission

    Wire.endTransmission();

    

    // Start I2C Transmission

    Wire.beginTransmission(Addr);

    // Select resolution rgister

    Wire.write(0x08);

    // Resolution = +0.0625 / C

    Wire.write(0x03);

    // Stop I2C Transmission

    Wire.endTransmission();

    delay(300);

}



void loop()

{

    unsigned int data[2];

    

    // Starts I2C communication

    Wire.beginTransmission(Addr);

    // Select data register

    Wire.write(0x05);

    // Stop I2C transmission

    Wire.endTransmission();

    

    // 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();

    }

    delay(300);

    

    // Convert the data to 13-bits

    int temp = ((data[0] & 0x1F) * 256 + data[1]);

    if(temp > 4095)

    {

        temp -= 8192;

    }

    cTemp = temp * 0.0625;

    fTemp = cTemp * 1.8 + 32;

    

    // Output data to dashboard

    Particle.publish("Temperature in Celsius : ", String(cTemp));

    Particle.publish("Temperature in Fahrenheit : ", String(fTemp));

    delay(500);

}

You can try changing the publish subject to cTemp or something else instead of Temperature in Celsius : so that in IFTTT, you can “listen” to that published event.

Particle.variable() “exposes” your global variable to the cloud so the current value of that variable can be retrieved by the cloud whenever needed.
This registration is a one time action and will keep the var exposed as long the device is connected.

BTW, 500ms is too little for even one Particle.publish() per iteration. You need to limit that to one publish per second (1000ms).

I will probably slow the loop WAY down to only one run per 15-30 seconds. even though car temps can rise quickly 30 seconds seems to be an acceptable notification time. I’m not sure how fast this thing will go through data either yet. but the Particle.Publish command obviously sends the characters when the code line executed… How does a globally exposed variable work with the data stream?

Does IFTTT ask for the variable at a regular interval or does the variable get sent to IFTTT every time the code loops?

As already said, Particle.variable()s are retrieved (requested) by the cloud and not sent by the device, so no stream for those.

Hence IFTTT must be requesting an update on a regular basis to get an update on the value.

Rather than publishing once every 30 seconds, you could use considerably less data if you only publish when there is a significant change in the temperature.

We have to get @Elfmaze back on the air. There are a couple improvements that could be made.

The only concern with only publishing when there is a significant change is you do not know if the Electron has fallen off the network. Because this is something to monitor a potentially overheating car interior, there is a cause for safety here.

Is there a way for IFTTT to tell when the Electron (or Photon) is off the air? If there is, then @Ric 's idea would be great.

IFTTT can do a notification when the device is offline. BUT, that includes when the device is turned off. I suppose it would be easy enough to turn the IFTTT applet off when i turn the Electron off.

I was able to finally get the thing to reflash by putting it into safe mode then flashing OTA. Is it possible the loop was cycling too fast and the electron could not keep up before, leading to my connectivity issues?

Also I was using Microsoft EDGE browser the seems like it was crashing console on the computer side. Chrome appears to be running things smoother.

IFTTT’s poling rate for variables is 15mins I hear… which I really prefer was 5min but its still better than nothing. and I can still pull up console on my cell phone to check the temp real time.

As far as optimization goes. I got rid of the second push to send both Centigrade and Farenheit. so now just F come through. would shortening the event name help as well(less characters)? If I reduce the polling rate to once every min that would be 1440 events a day and with IFTTT set at 26c that would give me updates every 15mins of the RV’s temperature once it gets above about 79*f , seems acceptable for now. much better than nothing.

How much data would the 1440 publishes take per day, needs to be answered. and is that an acceptable cost for the days im on the road is a guestion for me. I feel like we are getting there though

Good to hear you can update it again. I still like @Ric 's idea. I’d suggest using two software timers. One timer to publish the latest reading to IFTTT. One to take the reading - once every 30 sec?

The delay in the loop pauses the program which may have unintended effects.

The publish timer can be set for 15 minutes or whatever. If it takes longer than 30 sec, then the other timer will trigger although the 15 minute timer is running.

Inside the sensor timer you can also check for temperature swings and cause it to publish a special reading.

You would need two variables. One for the current reading and the last reading to detect differences. The last reading could store the last published value.

Three functions:

  1. Sensor timer
  2. Publish timer
  3. Publish sensor value

You would call function 3 when you would normally publish a value or the special condition in 1. You could send an initial reading upon restart/reboot of the device.

Added a 4th function to allow calling the sensor update function from outside the timer too.

Here is a skeleton.

// 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.

// MCP9808
// This code is designed to work with the MCP9808_I2CS I2C Mini Module
// available from ControlEverything.com.

// https://www.controleverything.com/content/Temperature?sku=MCP9808_I2CS#tabs-0-product_tabset-2

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

// MCP9808 I2C address is 0x18(24)
#define Addr 0x18

double cTemp = 0.0, fTemp = 0.0;
double lastPublishedFTemp = 0.0;

// Setup timers
Timer tempSensorTimer(30000, updateTempSensorReading);
Timer publishTempToIFTTT((1000 * (60 * 15)), publishTempSensorReading);

// Actually do the publishing here
// We use this function from multiple locations
void doPublishTempSensorReading() {
    // IFTTT publishing code
    // send fTemp
    
    // Output data to dashboard

    //Particle.publish("Temperature in Celsius : ", String(cTemp));
    Particle.publish("Temperature in Fahrenheit : ", String(fTemp));
    
    // Save the last published fTemp
    lastPublishedFTemp = fTemp;
}

// Do the actual sensor update here
// We use it from multiple locations
void takeTempSensorReading() {
    unsigned int data[2];

    // Starts I2C communication
    Wire.beginTransmission(Addr);

    // Select data register
    Wire.write(0x05);

    // Stop I2C transmission
    Wire.endTransmission();

    // 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();
    }

    // This may not be needed here
    delay(300);

    // Convert the data to 13-bits
    int temp = ((data[0] & 0x1F) * 256 + data[1]);

    if(temp > 4095)
    {
        temp -= 8192;
    }

    cTemp = temp * 0.0625;
    fTemp = cTemp * 1.8 + 32;
    
}

// Actually get a new temperature reading
void updateTempSensorReading() {
    takeTempSensorReading();
    
    // At the point we only care if there is a significant rise
    // since our last published reading.   Adjust the threashold
    // to whatever.
    if (fTemp - lastPublishedFTemp > 5.0) {
        doPublishTempSensorReading();
        // If you want to reset the publish timer since this
        // was a special event, we can call this special
        // function since we are within a timer.
        // publishTempToIFTTT.resetFromISR();
    }
}

// Timer call for publishing reading to IFTTT
void publishTempSensorReading() {
    doPublishTempSensorReading();
}

void setup()
{

    // Set variable
    Particle.variable("i2cdevice", "MCP9808");
    Particle.variable("cTemp", cTemp);
    
    // 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 mode, Power-up default
    Wire.write(0x00);
    Wire.write(0x00);

    // Stop I2C Transmission
    Wire.endTransmission();


    // Start I2C Transmission
    Wire.beginTransmission(Addr);
    
    // Select resolution rgister
    Wire.write(0x08);

    // Resolution = +0.0625 / C
    Wire.write(0x03);

    // Stop I2C Transmission
    Wire.endTransmission();

    // Delay to allow configuration to settle
    delay(300);
    
    // Initilaize storage variables with initial readings
    takeTempSensorReading();
    lastPublishedFTemp = fTemp;
    // Or comment the line just before and publish to IFTTT now
    // doPublishTempSensorReading();
    
    // Start the timers
    tempSensorTimer.start();
    publishTempToIFTTT.start();
}


void loop()
{

}

Awesome! i’ll take a look at the code in a bit here. ran the program as is for an hour at 10 sec intervals. took .12 megs for 360 pings. So estimating half a MB a day with my old code.

I have found a problem with the sensor as well. IF the USB power drops out, the I2c sensor looses power as well. the power LED goes out on the MCP9808 and the returned values go crazy. The I2c shield I bought is just a simple bread board. they had one with a 5v boost transformer, but I didn’t think this sensor needed it as the spec sheet for the MCP9808 has the operating voltage as 2.7 to 5.5volts. I was under the impression this meant it would still run under battery power in a emergency loss of 5v primary power. more experimenting needed.

Just for a Data Usage reference, I have a few Analog Pressure sensors w/ Electrons.
They Publish ##.# psi every 10 minutes along with the API key and Particle overhead. This generally uses 1 MB per month for each Electron for readings every 10 minutes. I’m using a webhook and graph to ThingSpeak. I added a function to change to Publish Delay “on-the-fly” if the Electron Billing looks like it may go over 1 MB towards the end of the billing cycle.

But I also have an alarm set-point that will trigger an Alarm Publish if the pressure falls too low.
I have an IFTTT applet that watches for this Alarm Publish and will send a notification immediately( & another applet for SMS text). So the ALARM condition is treated independently of the routine publishing for graphing purposes. The IFTTT applet for “NEW EVENT PUBLISHED” responds very quickly in my experience.
This has worked well for me and should work for your Temperature project, especially since you don’t need 24/7 throughout the entire month.

As a failsafe, you could figure out an external script that used the ThingSpeak API’s data age (reported in seconds) to make sure your Electron was actually publishing the temp readings, and to notify you if the last temperature update was longer than your target (10 minutes, etc).
https://api.thingspeak.com/channels/12397/fields/4/last_data_age.txt

Because you wont know that you missed an ALARM publish if anything is preventing the Electron from updating the data, unless you notice (or notified) that the routine data updates have stopped. That’s on my wish-list, but I’m a newbie and moving pretty slow.

Ok. So, that is the sensor specs. The I2C specs for the Control Everything devices work on a signal voltage of 5.0V. The I2C signal for the Electron is 3.3V or 3V3 but 5.0V tolerant (and generally not recommended). It will work with the USB input as it is delivering ~5.0V. Once you disconnect that, then you are on the LiPo which is under 5.0V. While the I2C on the Electron still works, the sub 5.0V mangles the signal for the Control Everything I2C – hence the crazy readings.

Ok… I think I found the Control Everything booster you mentioned. This will siphon power from the LiPo battery to create the 5.0V needed to keep the I2C on the Control Everything side happy.

The boost circuit is controlled by A3. if you want to turn off the boost circuit just set this pin Low and it is advised to turn off the I2C port power while it's not in use. If you draw continuous power from the boost circuit it can get really hot.

If you have a small LiPo battery, because of the power draw, it may not last very long as is. If you poll the sensor less frequently, you save power.

Theoretically…

setup() {
  // Ensure CE booster/I2C/sensor is off
  pinMode(A3, OUTPUT);
  digitalWrite(A3, LOW);
}

// in the TakeSensorReading
void takeTempSensorReading() {
  // at the top 
  // Wake up the CE I2C
  digitalWrite(A3, HIGH);

  // take a reading code as usual

  // Turn the CE I2C off
  digitalWrite(A3, LOW);
}

Don’t be confused by this board. This provides the level shifter between the Electron and the Control Everything I2C but assumes a 5.0V supply is available to the Control Everything side. This is the other shifter that also assumes a 5.0V supply on the CE side.

The other option is to use a different board with sensor that can operate on 3V3.
Here is a different board with compatible signal levels for I2C – then everything should run off the LiPo without the extra song and dance.

blast, so I should have went with the adafruit sensor after all. at least the adafruit sensor is cheap once I have an order to share the shipping cost with. originally i went with the CE stuff because I didn’t want to use my full sized bread board for this and didn’t realize the Electron came with its own little half board. would have made a project box a bit more standard too. Eh… version 1.0.
this is the board I got https://shop.controleverything.com/products/i2c-breakout-for-particle-electron-or-particle-photon?variant=25687311371

Finished putting her together!

https://scontent.fagc1-2.fna.fbcdn.net/v/t31.0-8/19095759_10101172682816428_6922324325595095690_o.jpg?oh=b9967ac649ebaf82ee577bff1e561030&oe=59E2D44C

3 Likes

Is there any way to slow down IFTTT’s variable polling? I am still using the first build but I slowed the final delay down to a delay(60000) so only running the publish loop once every min. the one min publish rate is working great for logging on to the events publishing console tab. BUT when I turn on my IFTTT applet that is reading the variable ctemp It is rapid firing off warnings to me. like 15 notifications a min.

can I slow down that polling rate? I am planning on optimization of this code using the examples above… but I ran out of time before I departed on the road trip.

Why not consider listening to published events to control how often IFTTT triggers?

Adding a delay(60000) is also not a recommended practice as :cloud: connection might drop.