-
Notifications
You must be signed in to change notification settings - Fork 12
ESP8266
The ESP8266 is a super cheap (think $4) WiFi chip that is slowly gaining popularity. It's been built into quite a few boards including Adafruit's Huzzah and the Cactus Micro. Unfortunately, the cheaper the board equipped with the ESP8266 is, the more difficult it usually is to program.
The ESP8266's lightweight characteristics also usually mean that boards using it can't handle HTTPS. This means that you have to use a different Initial State endpoint. This comes with a security warning, but can also be solved by turning a more powerful board (like a Pi) into a hub that handles the encryption the ESP8266 couldn't.
NOTE: Some Adafruit ESP8266 boards now support TLS. You can read their article here: https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/ Modification of the non-AT script should be simple, with the main differences being the use of "groker.initialstate.com" instead of "insecure-groker.initialstate.com" as the ISDestURL on Line 12 and using the WiFiClientSecure library instead of WiFiClient.
While the actual way you establish an internet connection with your board may be different, the way you build your HTTP request should be the same. We have two examples, the first is for a board that requires you use AT commands: arduinoESP8266wifishieldstream-AT.ino. The second is for a board that has some form of WiFi client: arduinoESP8266wifishieldstream.ino.
I will go over the similar way that we build our HTTP request in both these sketches.
////////////////////////////
// Initial State Streamer //
////////////////////////////
// Data destination
// https can't be handled by the ESP8266, thus "insecure"
#define ISDestURL "insecure-groker.initialstate.com"
// Bucket key (hidden reference to your bucket that allows appending):
#define bucketKey "arduino"
// Bucket name (name your data will be associated with in Initial State):
#define bucketName "Arduino Stream"
// Access key (the one you find in your account settings):
#define accessKey "Your_Access_Key_Here"
The Initial State API endpoint is different from the usual (https://groker.initialstate.com/api/) because we can't use HTTPS, thus "insecure-groker.initialstate.com". Your access key tells the API which account the data belongs to and the bucket key tells the API which data bucket the data should go to. The bucket name is optional, but is what you see in your bucket shelf.
// this method makes a HTTP connection to the server and creates a bucket if it does not exist:
bool postBucket() {
// close any connection before send a new request.
// This will free the socket on the WiFi shield
client.stop();
// if there's a successful connection:
if (client.connect(ISDestURL, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
// Build HTTP request.
String toSend = "POST /api/buckets HTTP/1.1\r\n";
toSend += "Host:";
toSend += ISDestURL;
toSend += "\r\n" ;
toSend += "User-Agent:Arduino\r\n";
toSend += "Accept-Version: ~0\r\n";
toSend += "X-IS-AccessKey: " accessKey "\r\n";
toSend += "Content-Type: application/json\r\n";
String payload = "{\"bucketKey\": \"" bucketKey "\",";
payload += "\"bucketName\": \"" bucketName "\"}";
payload += "\r\n";
toSend += "Content-Length: "+String(payload.length())+"\r\n";
toSend += "\r\n";
toSend += payload;
client.println(toSend);
Serial.println(toSend);
return true;
} else {
// if you couldn't make a connection:
Serial.println("connection failed");
return false;
}
}
This function is taken from the WiFi Client example, but is functionally the same as the AT command example, just with slightly different syntax. Both sketches establish a connection with the destination URL on port 80. The function constructs the HTTP command that creates a bucket. You can skip creating a bucket in your script if you choose to create your bucket inside of Initial State.
We are basically creating this format:
POST /api/buckets HTTP/1.1
Host: insecure-groker.initialstate.com
User-Agent:Arduino
Accept-Version: ~0
X-IS-AccessKey: accessKey
Content-Type: application/json
Content-Length: payloadLength
{\"bucketKey\": \"" bucketKey "\",";
"\"bucketName\": \"" bucketName "\"}
Carriage returns are essential to the HTTP POST format - these are represented by "\r\n". Content length is also important. Sometimes a POST won't go through simply because the packet is too large (on the Cactus Micro you couldn't exceed 290 characters). Always test your use case with short strings/numbers first to make sure that's not a problem.
Posting data happens exactly the same way, just directed at the events API endpoint instead:
// this method makes a HTTP connection to the server and sends the signals measured:
bool postData() {
// close any connection before send a new request.
// This will free the socket on the WiFi shield
client.stop();
// if there's a successful connection:
if (client.connect(ISDestURL, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
// Build HTTP request.
for (int i=0; i<NUM_SIGNALS; i++){
String toSend = "POST /api/events HTTP/1.1\r\n";
toSend += "Host:";
toSend += ISDestURL;
toSend += "\r\n" ;
toSend += "Content-Type: application/json\r\n";
toSend += "User-Agent: Arduino\r\n";
toSend += "Accept-Version: ~0\r\n";
toSend += "X-IS-AccessKey: " accessKey "\r\n";
toSend += "X-IS-BucketKey: " bucketKey "\r\n";
String payload = "[{\"key\": \"" + signalName[i] + "\", ";
payload +="\"value\": \"" + signalData[i] + "\"}]\r\n";
toSend += "Content-Length: "+String(payload.length())+"\r\n";
toSend += "\r\n";
toSend += payload;
Serial.println(toSend);
client.println(toSend);
}
return true;
} else {
// if you couldn't make a connection:
Serial.println("connection failed");
return false;
}
}
Each event must be enclosed in brackets. Because of the content length restrictions, the sketches are set up to send one event at a time for i number of different signals:
POST /api/events HTTP/1.1
Host: insecure-groker.initialstate.com
User-Agent:Arduino
Accept-Version: ~0
X-IS-AccessKey: accessKey
X-IS-BucketKey: bucketKey
Content-Type: application/json
Content-Length: payloadLength
[{\"key\": \"temperature\", \"value\": \"22.2\"}]
The AT command sketch contains a function, "truncateString()", that is set up to keep your payload from exceeding the length limit.
And that's how to build an HTTP POST in a sketch!
Time for the Ethernet Shield!