Deep Sleep Temperature Sample

Deep Sleep Temperature Sensor

I have a temperature sensor that I want to last for a very long time running from battery so I want to use best practices with deep sleep and collecting readings while disconnected. I also want to use best practices where the agent persists settings for the device. There will also be a mobile app that can be used to set two values: Threshold temperature (degrees F) and time to take readings before logging (in minutes)

Here is what I am trying to accomplish:

  1. When the code first runs, it will immediately enter deep sleep mode
  2. When pin 1 goes high, the device will wake up and read settings from agent
  3. The device will then disconnect while it is taking temperature readings and only connect after a certain amount of time to send temperature log to the agent for saving.
  4. Once the log is written, the device will go back to deep sleep waiting for pin 1 to wake.
  5. The device will take a temperature reading every 15 seconds and use it to calculate an average temperature every minute. This minute average will be saved in an array to later send to the agent.
  6. While reading temperatures, ignore pin 1. It is only used to wake up the device from deep sleep.
  7. When a temperature reading first exceeds the temperature threshold, log that time.
  8. Time logging doesn’t need high precision.
  9. Battery life is of high importance.
  10. The device could wake up from between 0 and 10 times a day to take readings.
  11. Temperature readings can be gathered from 1 to 60 minutes before logging.
  12. I am using a thermistor on pin 5 to take temperature readings.

In summary, there will be the following states:

  1. Deep sleep
  2. Wake and read settings (WiFi connected)
  3. Collect readings (WiFi off)
  4. Send log to server (WiFi connected)
  5. Deep sleep (repeat)

I have the code below but it is not working as expected.

Agent Code

`
thresholdTemp <- 99.0;
logTime <- 2;

// default settings
settings <- {};
settings.thresholdTemp <- thresholdTemp;
settings.logTime <- logTime;

// get saved settings if present
local savedSettings = server.load();
if (savedSettings.len() != 0) settings = savedSettings;

local error = server.save(settings); // if error == 0 then save successful

device.on(“get.settings”, function (noData)
{
server.log(“sending settings to device”);
device.send(“set.settings”, settings);
});

device.on(“log”, function (log)
{
//persist log in some 3rd party store

server.log("Data logged:");
server.log("Start time: " + log.startTime);
server.log("End time: " + log.endTime);

if (log.thresholdTime > 0)
{
    server.log("Threshold time: " + log.thresholdTime);
}

server.log("Temp reading count: " + log.temps.len());

});

// set settings from http request`

Device Code

`const MAXSLEEP = 86396; // max amount of time to sleep (1 day)
const TEMP_INTERVAL = 15; // Interval in seconds to read temperature from sensor

// these constants are particular to the thermistor we’re using
// check your datasheet for what values you should be using
const B_THERM = 4038.0;
const T0_THERM = 298.15;

// the resistor in the circuit (10KO)
const R2 = 10000.0;

// default settings
thresholdTemp <- -1;
logTime <- -1;

server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 30.0);
wake <- hardware.pin1;
therm <- hardware.pin5;
therm.configure(ANALOG_IN);

currentTemp <- 0;
averageTemp <- 0;
tempTotal <- 0;
tempCounter <- 1;
thresholdLogged <- false;

logData <- {};
logData.startTime <- 0;
logData.thresholdTime <- 0;
logData.endTime <- 0;
logData.temps <- [];

agent.on(“set.settings”, function (data)
{
thresholdTemp = data.thresholdTemp;
logTime = data.logTime;
});

function goToDeepSleep() {
wake.configure(DIGITAL_IN_WAKEUP);
imp.onidle(function() {server.sleepfor(MAXSLEEP)});
}

function disconnect() {
server.log(“Disconnecting”);
server.flush(30);
server.disconnect();
}

function logConnectionHandler(reason)
{
if (reason == SERVER_CONNECTED)
{
agent.send(“log”, logData);
goToDeepSleep();
}
}

function awakeConnectionHandler(reason)
{
if (reason == SERVER_CONNECTED)
{
server.log(“device awake from pin1”);
server.log(“requesting settings from agent.”)
agent.send(“get.settings”, null);
logStartTime();
disconnect();
readTemperature();
}
}

function logStartTime()
{
logData.startTime <- time();
server.log("Log start time; " + logData.startTime);
}

function getTempInF() {
local Vin = hardware.voltage();

local Vout = Vin * therm.read() / 65535.0;
local R_Therm = (R2 * Vin / Vout) - R2;

local ln_therm = math.log(10000.0 / R_Therm);
local temp_K = (T0_THERM * B_THERM) / (B_THERM - T0_THERM * ln_therm);

local temp_C = temp_K - 273.15;
local temp_F = temp_C * 9.0 / 5.0 + 32.0;

return temp_F;
}

function readTemperature() {
local currentTime = time();
currentTemp = getTempInF();

if (!thresholdLogged && currentTemp > thresholdTemp)
{
    logData.thresholdTime <- currentTime;
    thresholdLogged = true;
}

tempTotal += currentTemp;
averageTemp = tempTotal / tempCounter;

if (tempCounter > (60 / TEMP_INTERVAL))
{
    //write to log
    logData.temps.append(averageTemp);
    
    currentTemp = 0;
    averageTemp = 0;
    tempTotal = 0;
    tempCounter = 0;
}

if (currentTime - logData.startTime > logTime * 60)
{
    logData.endTime <- currentTime;
    server.connect(logConnectionHandler, 60.0);
    return;
}

tempCounter += 1;		
imp.wakeup(TEMP_INTERVAL, readTemperature);

}

if (hardware.wakereason() == WAKEREASON_PIN1)
{
server.connect(awakeConnectionHandler, 60.0);
}
else
{
goToDeepSleep();
}`

Logs:

2014-10-09 13:13:34 UTC-7 [Agent] sending settings to device 2014-10-09 13:13:34 UTC-7 [Status] Device Booting; 6.83% program storage used 2014-10-09 13:13:34 UTC-7 [Device] device awake from pin1 2014-10-09 13:13:34 UTC-7 [Device] requesting settings from agent. 2014-10-09 13:13:34 UTC-7 [Device] Log start time; 1412885612 2014-10-09 13:13:34 UTC-7 [Device] Disconnecting 2014-10-09 13:13:36 UTC-7 [Agent] Data logged: 2014-10-09 13:13:36 UTC-7 [Agent] Start time: 1412885612 2014-10-09 13:13:36 UTC-7 [Agent] End time: 1412885613 2014-10-09 13:13:36 UTC-7 [Agent] Threshold time: 1412885613 2014-10-09 13:13:36 UTC-7 [Agent] Temperature reading count: 0 2014-10-09 13:13:36 UTC-7 [Status] Device disconnected 2014-10-09 13:13:36 UTC-7 [Status] Device Booting; 6.83% program storage used 2014-10-09 13:13:36 UTC-7 [Device] sleeping until 1412972012000 2014-10-09 13:14:31 UTC-7 [Agent] sending settings to device 2014-10-09 13:14:31 UTC-7 [Status] Device disconnected 2014-10-09 13:14:31 UTC-7 [Status] Device Booting; 6.83% program storage used 2014-10-09 13:14:31 UTC-7 [Device] device awake from pin1 2014-10-09 13:14:31 UTC-7 [Device] requesting settings from agent. 2014-10-09 13:14:31 UTC-7 [Device] Log start time; 1412885671 2014-10-09 13:14:31 UTC-7 [Device] Disconnecting 2014-10-09 13:14:33 UTC-7 [Agent] Data logged: 2014-10-09 13:14:33 UTC-7 [Agent] Start time: 1412885671 2014-10-09 13:14:33 UTC-7 [Agent] End time: 1412885671 2014-10-09 13:14:33 UTC-7 [Agent] Threshold time: 1412885671 2014-10-09 13:14:33 UTC-7 [Agent] Temperature reading count: 0 2014-10-09 13:14:33 UTC-7 [Status] Device Booting; 6.83% program storage used 2014-10-09 13:14:33 UTC-7 [Device] sleeping until 1412972069000

The main point of the sample was to discuss saving battery life by using deep sleep and turning off the WiFi connection while gathering sensor readings.

If you look at the log, then you can see the following:

  1. No temperature readings are being taken – temperature reading count: 0
  2. End time and threshold time are always the same

Also, the part where data is logged is happening when pin1 wakes and not at other times.

I need someone to take a look at the code or provide a complete best practices sample of using deep sleep and turning off WiFi in the same sample.

You shouldn’t be calling disconnect except from an onidle handler as otherwise you will never receive any notifications from the server (including code updates).

If you want to receive settings from the agent, you’ll need to wait long enough for them to be received too, which is likely at least a second; whilst your code is running, inbound messages from the server are not processed because squirrel takes priority.

eg

`function awakeConnectionHandler(reason)
{
if (reason == SERVER_CONNECTED)
{
server.log(“device awake from pin1”);
server.log(“requesting settings from agent.”)
agent.send(“get.settings”, null);
logStartTime();
// time to get settings from agent before disconnecting
imp.wakeup(1, function() { disconnect(); });

   // read the temperature in parallel
    readTemperature();
}

}`

…but then you also need to deal with the fact that you may still be connected when the temperature readings are collected. Generally, given the cost of a connection, you should just connect once per cycle and both transmit readings from the last cycle and also receive new settings from the host.

Here is a summary of what I am trying to do:

  • Device is always deep sleeping until pin1 wakes it up
  • Once awake, read settings once from the server & the device stores start time in an “object”
  • Turn off WiFi to save power while taking temperature readings
  • Take a temperature reading every 15 seconds but every minute store the minute average temperature in an object
  • The first temperature reading to cross threshold (value from settings) then store threshold time in an object
  • After x minutes (value from settings) of taking readings, end time will be stored in an object
  • Connection will then be made to the agent so that data object (contains: start time, threshold time, end time, average min readings) can be sent to agent
  • Device will deep sleep until pin1 awake

The data being sent from the device to the agent only happens once per wake up and will be stored in the following data structure:

logData <- {}; //Sample data: logData.startTime <- time(); // 1412880000 logData.thresholdTime <- time(); // 1412880045 logData.endTime <- time(); // 1412880600 logData.temps <- []; // [85.5, 99.1, 99.5, 100.8, 101.2, 99.8, 99.0, 99.5, 93.7, 92.2]

It can be many hours or days between time that device wakes up to take readings. It can be between 1 to 60 minutes that device will be taking temperature readings and not need to be connected to WiFi.

My comments above still stand. You need to wait after connection if you want to receive data from the agent.

If you look at the example on the deepsleep page:

http://electricimp.com/docs/api/imp/deepsleepfor/

…you can see an example of how to absolutely minimize power in this type of application, staying in deep sleep when not online and only sending periodically. To do this you need to make use of the nv table to save readings and state between wakes, though.