Picture of TempBug: internet-connected thermometer
Screen Shot 2015-01-30 at 8.23.02 AM.png

Last January, we had some trouble with the heat in my office. Specifically, the kind of trouble wherein the heat is not on, you turn it up, and it still not on. This went on for more than a few days, and finally ended a day or two after we got an email announcing that the heat was broken and speculating that it had probably been down for a few days. My teammates and I laughed a bit at this - we knew exactly when the heat had stopped working. We had a continuous record of the temperature in the office going back months, with 10-minute resolution.

You can do this too, and it's quick, cheap, and easy! This little gadget is built around an electric imp, and you can push the data from the imp out to anywhere you want. In my case, I found it handy to push the data to Sparkfun's Data Stream service, which stores the data for free. Even better, I can use imp.guru's Sparkfun Data Stream frontend to get nice graphs of the data I've collected.

This project takes about an hour to two hours, if you've never done a project with an electric imp before, and when you're done you'll have a thermometer that you can toss anywhere with WiFi and collect data for months to years on a single battery, depending on how often you check the temperature.

1-40 of 99Next »
Ploopy26 days ago


BryanS241 month ago

This device looks to fit my needs exactly, but does anyone know what the accuracy is at temperatures of -20 degrees Celsius +/- 15 degrees C.?

The accuracy would be dependent on the thermistotr you select. The IMP and database provide .01 degree resolution using the agent and device code.

BryanS241 month ago

This device looks to fit my needs exactly, but does anyone know what the accuracy is at temperatures of -20 degrees Celsius +/- 15 degrees C.?

EngrDanny made it!1 month ago
Awesome tutorial, how do you graph the data?

Also, the time stamp on the Sparkfun Stream is 3 hours ahead of the device. Any thoughts?
NeilB92 months ago

Hi there. It's fantastic. So straightforward, worked first time and tells me exactly how (and if) my solar PV panels are heating my hot water through an ImmerSUN device. I didn't thin k it wasm but this Tempbug proves it is doing exactly as it should. I have it monitoring the hot-water pipe leading out of the tank. I would really like to also be able to monitor the 9v battery voltage too, so I know when to change the battery. I have tried to follow Lathyrus's code, but I get completely lost. and very cold feet! Are there any simple lines of code I can insert into Tombrew's code that will give me this, without breaking what already works? If it ain't broke ...! Thank you all. I am alos using Luke Beno's excellent Analog.io to see the data logged in Sparkfun, as imp.guru is no longer available. Brilliant!

MariusV12 months ago

Hi there and thanks for the tutorial. I built the TempBug on a breadboard and when it runs I get nothing in the datastream. I the code, I only changed the b_therm value (4600 for my thermistor) and obviously, the keys from sparkfun.

The log shows something like:

expecting: batteryvoltage, temp

2015-06-16 20:45:03 UTC+3[Status]Device connected

2015-06-16 20:45:03 UTC+3[Status]Device disconnected

2015-06-16 20:45:03 UTC+3[Device]sleeping until 1434477601000

2015-06-16 20:45:03 UTC+3[Agent]PUSH: 400 - 0 batteryvoltage missing from sent data.

Any ideas on where I could start troubleshooting?

Thanks in advance,


MariusV1 MariusV12 months ago

Well ... this is just random. Now I soldered the parts on the breakout board and I get single digit values :|

MariusV1 MariusV12 months ago

UPDATE: The cod will work only if I remove the "batteryvoltage" tag from sparkfun. But now I'm getting huge values for my temp in celsius ... 150 degrees

dalekb3 months ago

This is the first time I've ever made anything like this. I found the instructions to be very detailed and helpful. But I'm not sure why I can't get my Tempbug to work. Here is an example of the idea log I am getting:

2015-05-30 23:16:14 UTC-7[Status]Device connected
2015-05-30 23:16:15 UTC-7[Device]ERROR: the index 'device' does not exist
2015-05-30 23:16:15 UTC-7[Device]ERROR: at main:63
2015-05-30 23:16:20 UTC-7[Status]Device disconnected
2015-05-30 23:16:20 UTC-7[Status]Device connected
2015-05-30 23:16:20 UTC-7[Device]ERROR: the index 'device' does not exist
2015-05-30 23:16:20 UTC-7[Device]ERROR: at main:63
2015-05-30 23:16:25 UTC-7[Status]Device disconnected

Can you help me understand what I may have done wrong and how I might be able to fix it?

alpha01014 months ago

Could you use a 9v wallwart or a USB wall charger instead of a battery(you could use a small solar panel and run indefinetly) ? And, could you print the data to an excel sheet? Could you manage several of these and have them all printed in one excel?

This Seems more practical for me at least. Im no expert but these conversions dont seem very difficult.

lathyrus1 year ago
Wow! Despite not having soldered anything for about 30 years, I was able to build this thermometer without any real difficulty in a couple of hours, and I understand how it works! Thanks Tombrew for the excellent instructions. The only problem I had was that the guy in Maplins gave me the wrong size fixed resistor, so the first time I built it the reading in my livingroom was a chilly -159 degrees C... but with the correct 100k Ohm resistor everything is fine. I also couldn't get blinkup to work with my Sony Android phone so I had to borrow my wiffe's iPhone to do the setup. And getting Xively (Cosm) to draw graphs was tricky until I figured out that I needed a MASTER API key, available under the Settings tab.

Follow-up: The tempbug has been running smoothly in my attic for 9 months now. My first 9 volt battery lasted only a month, checking the temperature every 15 mins. So I changed the interval to 2 hours and my second battery lasted 6 months. I also noticed that the first temperature reading in each cycle is a bit higher than the others (by about 0.5 degree, I don't know why) so I modified the code to ignore the first reading and average the next 10:

2014-07-14 06:00:08 UTC+1[Device]ignore: voltage: 3.315 temp: 19.4 C2014-07-14 06:00:08 UTC+1[Device]loop: 0 voltage: 3.313 temp: 18.9 C2014-07-14 06:00:08 UTC+1[Device]loop: 1 voltage: 3.311 temp: 18.4 C2014-07-14 06:00:08 UTC+1[Device]loop: 2 voltage: 3.311 temp: 18.2 C2014-07-14 06:00:08 UTC+1[Device]loop: 3 voltage: 3.311 temp: 18.1 C2014-07-14 06:00:08 UTC+1[Device]loop: 4 voltage: 3.313 temp: 18.2 C2014-07-14 06:00:08 UTC+1[Device]loop: 5 voltage: 3.309 temp: 18.3 C2014-07-14 06:00:08 UTC+1[Device]loop: 6 voltage: 3.311 temp: 18.2 C2014-07-14 06:00:08 UTC+1[Device]loop: 7 voltage: 3.313 temp: 18.2 C2014-07-14 06:00:08 UTC+1[Device]loop: 8 voltage: 3.311 temp: 18.6 C2014-07-14 06:00:08 UTC+1[Device]loop: 9 voltage: 3.311 temp: 18.1 C

Building and programming the Imp was so much fun that I bought 2 more and made a phone-controlled electric gate opener, and a gizmo for forcibly rebooting my Wowwee Rovio...

Thanks again Tombrew for the great intro and instructions!

how did you change to a 2 hour interval? was it in the code inserted into electric imp? if so where?

Here's the complete Device and Agent code that I'm using. It logs the temperature on odd-numbered hours (1 a.m., 3. a.m. etc). It uploads to Xively the temperature (Celsius), WiFi signal strength, battery voltage, and lag (how long it took to do the measurement cycle).

//KW tempbug device code v2 20nov2013
// April with a 100k resistor from 3V3 to pin9 and 100k NTC Thermistor from pin9 to pin8
// pin8 TEMP_READ_EN_L - drive low to enable temp reading (great for batteries!)
// pin9 ANALOG NTC value
// benchmarking runtime: first tick with hardware.micros
local tick = hardware.micros();
// turn on WiFi powersave to reduce power consumption when awake
// WiFi is not used until line 44 (no communication with agent until end of program)
// Configure Pins
// pin 8 is driven high to turn off temp monitor (saves power) or low to read
// pin 9 is the middle of the voltage divider formed by the NTC - read the analog voltage to determine temperature
// all calculations are done in Kelvin
// these are constants for this particular thermistor; if using a different one,
// check your datasheet
const b_therm = 4450;
const t0_therm = 298.15;
// turn on the thermistor network
// gather several pin9 ADC and battery voltage readings and average them
// (just takes out some noise)
local val = 0;
local v_high = 0;
//skip first measurement (always low)
local val_now=hardware.pin9.read();
local v_high_now=hardware.voltage();
local v_therm = v_high_now * val_now / 65535.0;
local r_therm = 100000.0 / ( (v_high_now / v_therm) - 1);
local ln_therm = math.log(100000.0 / r_therm);
local t_therm = (t0_therm * b_therm) / (b_therm - t0_therm * ln_therm) - 273.15;
local t_str = format("%.01f", t_therm);
local batt_str = format("%.03f",v_high_now);
server.log("ignore: voltage: " +batt_str +" temp: " +t_str+" C");
//then measure 10 times
for (local i = 0; i < 10; i++) {
val_now = hardware.pin9.read();
v_high_now = hardware.voltage();
v_therm = v_high_now * val_now / 65535.0;
r_therm = 100000.0 / ( (v_high_now / v_therm) - 1);
ln_therm = math.log(100000.0 / r_therm);
t_therm = (t0_therm * b_therm) / (b_therm - t0_therm * ln_therm) - 273.15;
t_str = format("%.01f", t_therm);
batt_str = format("%.03f",v_high_now);
server.log("loop: " +i +" voltage: " +batt_str +" temp: " +t_str+" C");
val += val_now;
v_high += v_high_now;
val = val/10;
v_high = v_high / 10.0;
// turn the thermistor network back off
// scale the ADC reading to a voltage by dividing by the full-scale value and multiplying by the supply voltage
local v_therm = v_high * val / 65535.0;
// calculate the resistance of the thermistor at the current temperature
local r_therm = 100000.0 / ( (v_high / v_therm) - 1);
local ln_therm = math.log(100000.0 / r_therm);
local t_therm = (t0_therm * b_therm) / (b_therm - t0_therm * ln_therm) - 273.15;
// format into a string for the string output port
local t_str = format("%.01f", t_therm);
server.log("Current temp is "+t_str+" C");
// update the current battery voltage with a nicely-formatted string of the most recently-calculated value
local batt_str = format("%.03f",v_high);
server.log("Battery Voltage is "+batt_str);
// benchmarking runtime
local tock = hardware.micros();
server.log(format("Read cycle took %d us", (tock-tick)));
local lag = ((tock-tick)/1000000.0);
local lag_str = format ("%.06f",lag);
//log WiFi signal strength
function ReportRSSI() {
local rssi = imp.rssi();
if (rssi < -87) {
server.log("WiFi signal is: " + rssi + " dBm (0 bars)");
else if (rssi < -82) {
server.log("WiFi signal is: " + rssi + " dBm (1 bar)");
else if (rssi < -77) {
server.log("WiFi signal is: " + rssi + " dBm (2 bars)");
else if (rssi < -72) {
server.log("WiFi signal is: " + rssi + " dBm (3 bars)");
else if (rssi < -67) {
server.log("WiFi signal is: " + rssi + " dBm (4 bars)");
else {
server.log("WiFi signal is: " + rssi + " dBm (5 bars)");
return rssi;
local rssi = ReportRSSI();
//attempt to send it to Xively...
agent.send("Xively-temp", t_str); // send data to Xively
agent.send("Xively-lag", lag_str); // send data to Xively
agent.send("Xively-battery", batt_str); // send data to Xively
agent.send("Xively-rssi", rssi); // send data to Xively
// wake up every 2 hours on odd-numbered hours (prevents drifting on slow DHCP)
imp.onidle( function() {
local secsToEvenHour = (1+ 120*60 - (time()%(120*60)) );
local secsToOddHour = secsToEvenHour - (60*60);
if (secsToOddHour < 0) {secsToOddHour += (120*60);}
local snoozelength = secsToOddHour;
server.log("snoozing for " + (snoozelength / 60) + " minutes and " + (snoozelength % 60) + " seconds" );
// full firmware is reloaded and run from the top on each wake cycle, so no need to construct a loop
##################### CUT HERE ######################
//KW tempbug agent code v2 20nov2013
//********************BEGIN XIVELY********************
//Code written by @beardedinventor modified for use by Joel Wehr
API_Key <- "pdyL6p9fp9zVtakiNqFGTaKGXPwqnMuxCdfM7258b1D8D6LI"; //Type your Xively API Key
Feed_ID <- "1282406454" //Type your Feed ID
/// Channel_ID <- "thermistor"; //Type your Channel ID -- modified by KW - see bottom of program
Xively <- {}; // this makes a 'namespace'
class Xively.Client {
ApiKey = null;
triggers = [];
constructor(apiKey) {
this.ApiKey = apiKey;
* method: PUT
* IN:
* feed: a XivelyFeed we are pushing to
* ApiKey: Your Xively API Key
* OUT:
* HttpResponse object from Xively
* 200 and no body is success
function Put(feed){
local url = "https://api.xively.com/v2/feeds/" + feed.FeedID + ".json";
local headers = { "X-ApiKey" : ApiKey, "Content-Type":"application/json", "User-Agent" : "Xively-Imp-Lib/1.0" };
local request = http.put(url, headers, feed.ToJson());
return request.sendsync();
* method: GET
* IN:
* feed: a XivelyFeed we fulling from
* ApiKey: Your Xively API Key
* OUT:
* An updated XivelyFeed object on success
* null on failure
function Get(feed){
local url = "https://api.xively.com/v2/feeds/" + feed.FeedID + ".json";
local headers = { "X-ApiKey" : ApiKey, "User-Agent" : "xively-Imp-Lib/1.0" };
local request = http.get(url, headers);
local response = request.sendsync();
if(response.statuscode != 200) {
server.log("error sending message: " + response.body);
return null;
local channel = http.jsondecode(response.body);
for (local i = 0; i < channel.datastreams.len(); i++)
for (local j = 0; j < feed.Channels.len(); j++)
if (channel.datastreams[i].id == feed.Channels[j].id)
feed.Channels[j].current_value = channel.datastreams[i].current_value;
return feed;
class Xively.Feed{
FeedID = null;
Channels = null;
constructor(feedID, channels)
this.FeedID = feedID;
this.Channels = channels;
function GetFeedID() { return FeedID; }
function ToJson()
local json = "{ \"datastreams\": [";
for (local i = 0; i < this.Channels.len(); i++)
json += this.Channels[i].ToJson();
if (i < this.Channels.len() - 1) json += ",";
json += "] }";
return json;
class Xively.Channel {
id = null;
current_value = null;
this.id = _id;
function Set(value) {
this.current_value = value;
function Get() {
return this.current_value;
function ToJson() {
local json = http.jsonencode({id = this.id, current_value = this.current_value });
return json;
client <- Xively.Client(API_Key);
//********************END XIVELY********************
device.on("Xively-temp", function(v) {
channel1 <- Xively.Channel("temperature");
feed1 <- Xively.Feed(Feed_ID, [channel1]);
device.on("Xively-lag", function(v) {
channel1 <- Xively.Channel("lag");
feed1 <- Xively.Feed(Feed_ID, [channel1]);
device.on("Xively-rssi", function(v) {
channel1 <- Xively.Channel("WiFi");
feed1 <- Xively.Feed(Feed_ID, [channel1]);
device.on("Xively-battery", function(v) {
channel1 <- Xively.Channel("battery");
feed1 <- Xively.Feed(Feed_ID, [channel1]);

Great. Thanks! How would I have it run every 6 hours starting at 8:00 am? I can see where to do it every 6 hours - just 60 *6. But how would I make it start the 6 hour cycle at 8:00 am, 2:00 pm, 8:00 pm, or 2:00 am?

lathyrus lathyrus11 months ago

Here are the graphs on Xively for 3 months

lathyrus lathyrus11 months ago

And here's what my code writes to the Electric Imp IDE log window every 2 hours.


Is there a way to send the remaining battery life data as well as the temperature reading?

StuartH26 months ago

This is really great and the simple to follow instructions got me up and running very easily. I'm trying to take this to the next level now and I've created an amazon cloud instance with Phant.io running. I'm not a great coder, certainly not for squirrel, and I was wondering what I need to change in the IMP agent code to redirect to my own cloud instance running Phant.io rather than sparkfun. Any help much appreciated.

Ryan12197810 months ago

Thanks for making this easy to build! but I'm having a problem Xively isn't allowing any new accounts now. so i have this but have no where to sent the info. i tried to use another site thingspeak.com but the code wont work with the way its wired. i was wondering if you have any ides what i can do. thanks for any help you can give!

tombrew (author)  Ryan12197810 months ago
Wondered if that would happen.

imp.guru has a nice graphing front end for devices like this. They built their front end on top of Sparkfun's data store. It looks pretty good - I should get around to switching my examples all over to it. Try it out here: http://imp.guru/

Hi, I just found a blog entry about temperature logging using the Electric Imp and using a graph from ThingSpeak here:


I'm a novice at programming, but do you think it would be possible to reuse the code from Slickstreamer in the Tempbug project?

ThingSpeak graph.png
tombrew (author)  kenny.carlsson7 months ago

Absolutely, though I haven't dug into slickstreamer at all. If you can send HTTP requests to post data, then the imp can do it!

tombrew (author)  Ryan1219787 months ago

Just updated this instructable to use Sparkfun and imp.guru, so no more Xively troubles!

BenC411 months ago

What kind of wireless range does the imp have?

tombrew (author)  BenC47 months ago

It's very good! Better than your phone or computer; it has the same WiFi chip in it your phone probably has, but the antenna isn't surrounded by a battery and a metal frame.

lathyrus BenC411 months ago

Similar to a laptop's wifi card. My Imp in the attic and the router is in the hallway 2 floors below it on the opposite side of the house. When the Imp's battery begins to run out, the WiFi signal it detects drops, and when if falls below about -93 dBm it can't connect anymore.

Pizzadragon 7 months ago

hah, finally read through all the comments and my Qs are answered. Thanks again for the writeup. This will be perfect for my situation!

Pizzadragon 7 months ago

wow! awesome instructions! I was planning on hacking sth together with an arduino I've got hibernating in a drawer since last xmas, but you won me over with this tutorial.

going to set this up in a utility room at home. I already set up a raspi webcam for visual access, now for temp readings. I've got water pipes that are at risk of freezing in severe weather and this puppy will help me set up alarm notifications for my computer and phone when the temp gets too low.

After that I plan on adding a wifi connected water sensor with notification to monitor for leaks.

If I have an outlet nearby I assume that I can simply use a usb power supply for the board instead of the battery, right?

I assume squirrel enables the option for sending temp readings to anywhere I like, right? I'm building a simple website with a dashboard of info from a bunch of devices, like a couple home security webcams i made with raspis and probably two or three of these tempbugs. Got any advice on whether SQLite would be a good choice or another database? Or perhaps I can tap into the Xively API to feed my webpage dashboard...

Thanks for a great project idea!

achary8 months ago

hello sir i need to build a wake up signal with int pin with other exisiting pins through pushbutton, like pin1 can be wake by pin2 and pin5 via pushbutton pressed..

raydlettca11 months ago

I had the thermometer up on Xively yesterday, but was having trouble with measuring temperature. Then I tried to modify the code, made a mess, and then decided to start from scratch and got rid of everything on electric imp. I started by attempting to relink via BlinkUp and can't get it to link up. Any thoughts on how to get BlinkUp to work again?

tombrew (author)  raydlettca11 months ago

You actually don't need to BlinkUp again; you can just edit the code in the model you've already created. When you hit "build and run" in the IDE, the code you have in the IDE is built and sent to the imp, wiping out the previous code.

BlinkUp is only needed when initially configuring or changing the WiFi credentials on the imp. As long as you're in the same Electric Imp account and on the same WiFi network you were on before, there's no need to do it again.

If you've lost your WiFi configuration and are now having trouble using BlinkUp to get it back, you can take a look at the documentation and tips on BlinkUp here: https://electricimp.com/docs/gettingstarted/1-blinkup/

KRS Test1 year ago

Thanks for a great list of instructions. You really have done an outstanding job making this manageable for a for someone with limited tech skills!

I have been able to setup the code and the integration to Xively but am having trouble with the readings. The readings remain steady at say 50 for quite a while then spike up to 120 or plunge to -119. Sometimes they stay at say -10 for an extended period of time. Attached is a picture of the Xively graph.

Have tested the readings by placing the E-Imp next to hot and cold items but there is little fluctuation in the readings.

No doubt I have made a simple error somewhere but am struggling to find it.

For the moment the power supply is by USB from a laptop. Am planning on soldering on the battery once the readings work properly.

Any feedback or suggestions would be appreciated.

Thanks again!

Electric Imp output.jpg
tombrew (author)  KRS Test11 months ago

Sounds like a flaky connection somewhere in your thermistor circuit. Go back over your solder joints and make sure they're all holding together properly. It might be a good idea to look up a tutorial on soldering if you're unfamiliar; I've covered the basics here but a more in-depth of cold solder joints and how to avoid them might save you some time.

raydlettca11 months ago

Thanks for the instructions, there were one thing that was not mentioned in putting this together, the 2 pin jumper. I temporarily made one from wire. One problem that I am having is I am not getting temperature reads. The request log is running properly - there are request and responses - but nothing shows up in the graph to the left. Any thoughts?

Try to write the temperature as a server.log() statement in the Imp IDE first, to make sure the thermistor is working correctly, before you try to draw graphs in Xively. Uploading data to Xively is tricky - I eventually got something to work, but I don't really understand how it works!

lenny20201 year ago

I tried to build it--great, thorough, easily understandable instructions, but I am not getting any info posted to Xively. I copied the info for lines 7 and 8, and although the project seems to cycle as expected, the log states:

Posted to Xively: 120.21, got return code: 56, msg: <html>

<head><title>400 Bad Request</title></head>

body bg color="white">

<center><hi>400 Bad Request</hi></center>




I am getting no data posted, and the Request log sits empty with the "waiting for requests area" just cycling. Where have I screwed up? I could send you any additional information you request, if needed

tombrew (author)  lenny20201 year ago

Hi Lenny,

Sorry, that sounds frustrating! Let's look over your code on a direct message.

I have also just built this and get this message when it tries to send data to Xively. Perhaps I have the same issue as Lenny.

2014-07-21 14:45:04 UTC-4
Posted to Xively: 71.60, got return code: 56, msg: <html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>

1-40 of 99Next »