Skip to content

Instantly share code, notes, and snippets.

@mjvo
Last active December 3, 2018 16:10
Show Gist options
  • Save mjvo/e960cc12b70ca33ebd4923e6d5c34df9 to your computer and use it in GitHub Desktop.
Save mjvo/e960cc12b70ca33ebd4923e6d5c34df9 to your computer and use it in GitHub Desktop.
// Arduino library dependencies
#include <SPI.h>
#include <WiFi101.h>
#include <timer.h>
#include <ArduinoJson.h>
// ************
// Enter your wifi access credentials and base64 encoded Twitter API
// key and secret in the tab: arduino_secrets.h
// ************
#include "arduino_secrets.h"
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
char token[] = TWITTER_TOKEN;
int wifi_status = WL_IDLE_STATUS; // the WiFi radio's status
String access_token; // var for Bearer token generated by getBearerToken() function
String twitter_user = "DukeU"; // screen name of Twitter user to query
// vars to keep track of results of last Twitter API call
long last_tweet_id = 0;
int last_retweet_count = 0;
int last_favorite_count = 0;
long last_followers_count = 0;
// instantiate a secure WiFi client
// (most APIs require https connections)
WiFiSSLClient client;
// create a timer with default settings
auto doQuery = timer_create_default();
void setup() {
//Initialize serial:
Serial.begin(9600);
// Feather M0-specific WiFi pins
WiFi.setPins(8, 7, 4, 2);
// do initial WiFi connect
wifiConnect();
// Query Twitter API for Bearer token
getBearerToken();
// Initial query of user's latest Tweet
queryTwitter(false);
// Instantiate timer for regular API calls
// (There are limits on how many requests per hour can
// be made against the API for a particular client app)
setQueryIntervals();
}
void setQueryIntervals() {
// syntax: doQuery.every(milliseconds, callbackFunction);
//doQuery.every(100, someFunc); // call the someFunc() function every 100 ms
doQuery.every(30000, queryTwitter); // queries Twitter every 30 secs
}
// *******************************
// This is the main function for querying and parsing Twitter's API
// *******************************
bool queryTwitter(void *) {
client.setTimeout(10000);
client.connect("api.twitter.com", 443);
// Send HTTP request
client.print("GET /1.1/statuses/user_timeline.json?count=1&screen_name=");
client.print(twitter_user);
client.println(" HTTP/1.1");
client.println(F("Host: api.twitter.com"));
client.print("Authorization: Bearer ");
client.println(access_token);
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
return true;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return true;
}
// Skip response headers
char endOfHeaders[] = "\r\n\r\n";
client.find(endOfHeaders);
// Allocate JsonBuffer based on ArduinoJSON assistant
// https://arduinojson.org/v5/assistant/
const size_t bufferSize = 4 * JSON_ARRAY_SIZE(0) +
4 * JSON_ARRAY_SIZE(1) +
8 * JSON_ARRAY_SIZE(2) +
JSON_ARRAY_SIZE(5) +
3 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(2) +
8 * JSON_OBJECT_SIZE(3) +
3 * JSON_OBJECT_SIZE(4) +
6 * JSON_OBJECT_SIZE(5) +
2 * JSON_OBJECT_SIZE(10) +
JSON_OBJECT_SIZE(25) +
JSON_OBJECT_SIZE(41) + 10000;
StaticJsonBuffer<bufferSize>jsonBuffer;
// Parse response
JsonArray& root = jsonBuffer.parseArray(client);
// *******************************
// BEGIN JSON PARSE
// *******************************
// Latest Tweet info from JSON
JsonObject& latest_tweet = root[0];
long latest_tweet_id = latest_tweet["id"];
const char* latest_tweet_content = latest_tweet["text"];
int latest_retweet_count = latest_tweet["retweet_count"];
int latest_favorite_count = latest_tweet["favorite_count"];
// User info from JSON
JsonObject& user = latest_tweet["user"];
const char* full_name = user["name"];
const char* screen_name = user["screen_name"];
long followers_count = user["followers_count"];
// Do things with JSON data
// This code just prints to Serial but you can
// leverage to trigger actuators or send OSC or
// MQTT messages, etc
Serial.print("Latest Tweet from ");
Serial.print(screen_name);
Serial.print(" / ");
Serial.print(full_name);
Serial.print(", who has ");
Serial.print(followers_count);
Serial.println(" followers.");
if (followers_count > last_followers_count) {
Serial.print("New followers since last check: ");
Serial.println(followers_count - last_followers_count);
}
Serial.print("Tweet ID: ");
Serial.println(latest_tweet_id);
Serial.println(latest_tweet_content);
Serial.print("Favorited: ");
Serial.println(latest_favorite_count);
Serial.print("Retweets: ");
Serial.println(latest_retweet_count);
if (latest_tweet_id == last_tweet_id) {
if (latest_favorite_count > last_favorite_count) {
Serial.print("New favorites since last check: ");
Serial.println(latest_favorite_count - last_favorite_count);
}
if (latest_retweet_count > last_retweet_count) {
Serial.print("New retweets since last check: ");
Serial.println(latest_retweet_count > last_retweet_count);
}
} else {
last_favorite_count = 0;
last_retweet_count = 0;
}
// store data to compare against future Twitter API queries
last_tweet_id = latest_tweet_id;
last_retweet_count = latest_retweet_count;
last_favorite_count = latest_favorite_count;
last_followers_count = followers_count;
// *******************************
// END JSON PARSE
// *******************************
// Disconnect from Twitter API
client.println(F("Connection: close"));
client.stop();
return true; // repeat
}
void loop() {
// check if wifi lost and if yes, reconnect.
// non-blocking version
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi connection lost. Reconnecting...");
wifi_status = WL_IDLE_STATUS;
wifiConnect();
}
// for timer
doQuery.tick();
}
// connect to WiFi (or reconnect if WiFi lost)
void wifiConnect() {
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi chip not present or accessible");
// don't continue:
while (true);
}
// attempt to connect to WiFi network:
while ( wifi_status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WiFi:
if (sizeof(pass) <= 1) {
wifi_status = WiFi.begin(ssid);
}
else {
wifi_status = WiFi.begin(ssid, pass);
}
// wait 2 seconds for connection:
delay(2000);
}
// you're connected now, so print out a success message:
Serial.println("You're connected to the network");
// print your Feather's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("Device IP Address: ");
Serial.println(ip);
}
// function to request Twitter API Bearer token
// runs once in setup() and assigns it to `access_token`
void getBearerToken() {
client.setTimeout(10000);
client.connect("api.twitter.com", 443);
// Send HTTP request
client.println(F("POST /oauth2/token HTTP/1.1"));
client.println(F("Host: api.twitter.com"));
client.println(F("User-Agent: My Twitter App v1.0.23"));
client.print("Authorization: Basic ");
client.println(token);
client.println(F("Content-Type: application/x-www-form-urlencoded;charset=UTF-8"));
client.println(F("Content-Length: 29"));
client.println("");
client.println(F("grant_type=client_credentials"));
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
return; //false;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return; //false;
}
// Skip response headers
char endOfHeaders[] = "\r\n\r\n";
client.find(endOfHeaders);
// Allocate JsonBuffer
const size_t capacity = JSON_ARRAY_SIZE(3)
+ 8 * JSON_OBJECT_SIZE(1)
+ 4 * JSON_OBJECT_SIZE(4)
+ 300;
StaticJsonBuffer<capacity>jsonBuffer;
// Parse response
JsonObject& root = jsonBuffer.parseObject(client);
// Extract the array "query.results.channel"
JsonArray& results = root["access_token"];
// Extract values
//Serial.println("Bearer Token: ");
//Serial.println(root["access_token"].as<String>());
access_token = (root["access_token"].as<String>());
// Disconnect
client.println(F("Connection: close"));
client.stop();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment