I have a smart thermostat that allows me to control my heating and cooling system remotely from a smart phone app. This is one of the most commonly used IoT devices. I also have created web interfaces to some of the Raspberry Pi controlled devices in my home - alarm system, lights, sprinklers, hot tub, weather station, security cameras.
I programmed these web interfaces myself, but there are much easier ways that are actually more secure, and these use the services that support the Internet of Things. One of the easiest to use is ThingSpeak.com. Here are the steps to use this service.
Go to the ThingSpeak web site and click on "Get Started." Click on "Sign Up" to create an account and then log in. Now you can create a new "Channel" which includes 1 to 8 fields of data. Once created, the channel is assigned an API_Key which is required to update the channel. You can see this value by clicking on the "API Keys" tab.
I have created a channel named "Example" with a single data field. Data can be uploaded to this field by using the following URL:
https://api.thingspeak.com/update?api_key=JPISWIDBF2CERG24&field1=123
(Yes, that is the actual API key. Feel free to post your own values, but try to keep them between 1-1000 so the chart is usable.)
You can view the public view here: https://thingspeak.com/channels/67033
Note that you can only update once per minute using this method.
Examples in a couple dozen languages, including C and Python are available here:
https://thingspeak.com/docs/examples
Here is an example of real data - temperature and fermentation rate from my home-brewing system.
I decided to create my own API since I had all the necessary code already. This API requires the CURL library to handle the web access. To install this:
sudo apt-get update
sudo apt-get install libcurl4-openssl-dev
Here is the API that I created for updating two fields.
/*********************************************************************** Filename: thingspeak.c send data to ThingSpeak IoT server Uses libcurl to send the data via HTTP 13-Nov-2015 Ted Hale created ************************************************************************/ /* system includes */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <string.h> #include <curl/curl.h> // Note: this function can be replaced with printf if you like. void Log(char *format, ... ); #define TRUE 1 // the URL structure to update ThingSpeak // https://api.thingspeak.com/update?api_key=YOUR_CHANNEL_API_KEY&field1=7 char *URLtemplate = "https://api.thingspeak.com/update?api_key=%s&%s=%s&%s=%s"; // structure used by the libcurl write callback function struct url_data { size_t size; char* data; }; //===================================================================== // write callback function needed by libCurl size_t write_data(void *ptr, size_t size, size_t nmemb, struct url_data *data) { size_t index = data->size; size_t n = (size * nmemb); char* tmp; data->size += (size * nmemb); tmp = realloc(data->data, data->size + 1); /* +1 for '\0' */ if(tmp) { data->data = tmp; } else { if(data->data) { free(data->data); } Log("wuthread> write_data Failed to allocate memory.\n"); return 0; } memcpy((data->data + index), ptr, n); data->data[data->size] = '\0'; return size * nmemb; } //===================================================================== // upload data to ThingSpeak int UpdateThingSpeak(char *api_key, char *f1, char *v1, char *f2, char *v2) { int error = 1; time_t now; struct tm *dt; char url[256]; CURL *curl; CURLcode res; struct url_data response; time(&now); dt = gmtime(&now); // build the URL string snprintf(url, sizeof(url)-1, URLtemplate, api_key, f1, v1, f2, v2); // guarantee null termination of string url[sizeof(url)-1] = 0; Log("UpdateThingSpeak> send: [%s]",url); curl = curl_easy_init(); if (curl) { response.size = 0; response.data = malloc(4096); /* reasonable size initial buffer */ response.data[0] = '\0'; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); res = curl_easy_perform(curl); if(res != CURLE_OK) { Log("UpdateThingSpeak> curl_easy_perform() failed: %s\n",curl_easy_strerror(res)); Log("URL is: [%s]",url); error = 1; } else { // ThingSpeak returns "0" for error, else returns sample number error = (strcmp(response.data,"0") == 0); } curl_easy_cleanup(curl); free (response.data); } else { Log("UpdateThingSpeak> curl_easy_init failed\n"); error = 1; } return error; }
Hi, how can I use your API? Can I see some examples? Thank you very much!
ReplyDeleteThe code listed in the post above will update a thingspeak feed with two variables. It needs to be modified for other configs
DeleteHere is how to call it (you need your own key)
sprintf(temp,"%d",someVariable);
sprintf(temp2,"%f",someOtherVariable);
UpdateThingSpeak("DFLGGKEFTRKREHKY", "field1", temp, "field2", temp2);
Ok, got it. I have customized your function UpdateThingSpeak for my needs, tested and everything work properly. Thanks so much! Cheers!
ReplyDeletei am trying to implement the same . Can you please share your implementation of this API ?
DeleteThank You in advance
Hey, I am sorry but I am no longer working on this project and I have lost most of the stuff but at the end I remember I had understood that it was better to move from C to Python...if you are interested I can share Python code...
DeleteAlessandro
Sure ! I would like to refer python code for the same.
Deleteplease do share .
Thank you.
import string
Deleteimport time
import smtplib
import math
import httplib, urllib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
updateThingspeak = 15 # how many seconds to sleep between posts
key = '************' # Thingspeak channel to update
def updateTHINGSPEAK():
while True:
params = urllib.urlencode({'field1': 0.1, 'field2': 0.2, 'field3': 0.3,
'field4': 0.4,'key':key })
headers = {"Content-typZZe":
"application/x-www-form-urlencoded","Accept": "text/plain"}
conn = httplib.HTTPConnection("api.thingspeak.com:80")
try:
conn.request("POST", "/update", params, headers)
response = conn.getresponse()
conn.close()
except:
print 'connection failed'
break
while 1:
updateTHINGSPEAK()
time.sleep(5)
Please fix indentation since it has been wrongly formatted automatically by the browser/page
DeleteI am trying to implement the above program and getting following error
ReplyDelete/tmp/ccBKEEhS.o: In function `write_data':
a.c:(.text+0x344): undefined reference to `Log'
/tmp/ccBKEEhS.o: In function `UpdateThingSpeak':
a.c:(.text+0x3e8): undefined reference to `Log'
a.c:(.text+0x4c0): undefined reference to `Log'
a.c:(.text+0x4d0): undefined reference to `Log'
a.c:(.text+0x524): undefined reference to `Log'
without making any changes to the program as it is
And if I replace Log with printf, following error is encountered
ReplyDeletea.c:10:6: error: conflicting types for ‘printf’
void printf(char *format, ... );
^~~~~~
In file included from a.c:2:0:
/usr/include/stdio.h:364:12: note: previous declaration of ‘printf’ was here
extern int printf (const char *__restrict __format, ...);
^~~~~~
pi@raspberrypi:~/speak $
Pls do let me know the issues here.
Just starting with Raspberry
Thanks in advance
Was able to overcome the issues.
ReplyDeleteWorking fine.
Great.
Hi, nice job...
ReplyDeleteCan you provide similar code to read data from Thingspeak?