I’m a marketing person inside an engineer’s body. This leads me down the path of projects that tie the business world together with hardware. This project is about getting real world notifications when something happens on Twitter. Specifically, this idea came about because we wanted to see in our office when someone mentioned us or followed us on Twitter.
This sounded simple enough, especially when built on top of the Losant platform. I grabbed a Adafruit Feather Huzzah and NeoPixel Ring then went to town.
There are several items needed to complete this project.
- Twitter API Access
- Losant Workflows
- Feather Huzzah & NeoPixel Circuit
- Arduino Code for Huzzah
Something as simple as searching Twitter for a mention of your user name used be simple but now is a pain in the butt. In order to search Twitter you have to use the search API, which requires authentication.
Getting Twitter Access Token
In order to get an access token from Twitter you need an application to use. You can create one at the Application Management portal. If you have already have one you can use it. This project doesn’t cover the specifics of generating a token but you can read about it in the Twitter docs. There are scripts available to easily generate a token once you have an application on Twitter. I used Node.js to get an access token. The code below can be run to get your own token (make sure to replace with your Consumer Key and Consumer Secret).
var request = require('request');
var consumer_key = 'YOUR_CONSUMER_KEY';
var consumer_secret = 'YOUR_CONSUMER_SECRET';
var enc_secret = new Buffer(consumer_key + ':' + consumer_secret).toString('base64');
var oauthOptions = {
url: 'https://api.twitter.com/oauth2/token',
headers: {'Authorization': 'Basic ' + enc_secret, 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
body: 'grant_type=client_credentials'
};
request.post(oauthOptions, function(e, r, body) {
console.log(body)
});
Above script courtesy Sulmanen.
Console output will look something like:
{"token_type":"bearer","access_token":"AAAAAAAAABAAAAAACAAAAGmgkQAAADAADE25d5m2aEfRo2X9fd%2B0fMg%2BJFE%3D7cCMTlERxEt9PwDBIS2ptTJ1jamacmaXAI3bw1lJILkPKUyd4y"}
Grab the access_token value and save it for later.
Building Twitter Mention Losant Workflow
Using Losant’s workflow capabilities you can create a simple process to check for new mentions on Twitter. If you don’t have an account, you can sign up over here.
Once you’ve signed up go ahead and create an application - you can check out the official docs for getting started if you’re not familiar.
After the application is created go ahead and create a new virtual device (checkbox to make it virtual). Just name it whatever you’d like.
Next add several attributes to the device. Go ahead and add the following attributes:
lastMentionId : String
lastMentionText : String
lastMentionUser : String
lastFollowerId : String
followerCount : Number
followingCount : Number
listedCount : Number
favoritesCount : Number
statusCount : Number
For this particular workflow only the first three attributes and only the first four will be used for this project. However, you can take a challenge and figure out how to get the rest of these attributes into the virtual device using a third workflow that isn't covered in this project.
Please double check both the names of the attributes and types. Note that the names are case sensitive.
Next up is creating a workflow to pull the latest mentions from Twitter. For this project the only mention that is important is the latest. The id of the latest mention will be used to know if another (newer) mention has come in.
Create the workflow and name it whatever you’d like.
Once created add the following nodes. Reference the below picture for correct connections.
Here are details and the settings for each node.
Debug - Output - Docs
These are sprinkled throughout to see the payload that is coming out from connected nodes.
Virtual Button - Trigger - Docs
No configuration changes needed. This will be used for debugging the workflow.
Timer - Trigger - Docs
Set the configuration to Every 1 Minute. This will cause the workflow to start every one minute to check for new mentions.
HTTP Node - Data - Docs
Set the configuration to GET the search Twitter API. To call the API an Authorization header has to be sent. This pulls the request and puts it on the payload path in the workflow so it can be referenced later. More on the Twitter Search API.
Settings
GET
Url Template: https://api.twitter.com/1.1/search/tweets.json?q=%40losant&include_entities=false (change “losant” to your own account)
Headers:
Authorization Bearer <access_token>
Make sure to put your Twitter access token in the header.
Payload Path: data.mentions
Connects to Get Value Node and a Debug Node
Get Value - Data - Docs
The configuration needs to be set to pull the last tweet id from the Losant workflow data storage. This id is used to determine if the latest mention from the Twitter API is the same one as the last time the workflow is run. This node gives us the capability to store values across workflow runs.
Settings
Value Identifier: lastTweetId
Payload Path: data.lastTweetId
Default Value: -1
Conditional - Logic - Docs
The conditional node checks to see if the latest mention from Twitter is equal to the id pulled from the workflow storage. If these are the same nothing needs to be done (right output). If they are different then the new value needs to be recorded and a command needs to be sent to Huzzah.
Settings
Expression: {{ data.lastTweetId }} === {{ data.mentions.body.statuses.0.id_str }}
Store Value - Data - Docs
This node is going to update the latest tweet id stored in the workflow storage. The value will be pulled from the Twitter mentions.
Settings
Value Identifier: lastTweetId
Payload Path: data.mentions.body.statuses.0.id_str
Virtual Device - Output - Docs
This node will save values to the Twitter Stats virtual device that was created earlier. This isn’t absolutely necessary for this project but allows for dashboard creation from the data.
Settings
Device: This should be filled in with your one virtual device that was created.
State:
lastMentionId : {{ data.mentions.body.statuses.0.id_str }}
lastMentionText : {{ data.mentions.body.statuses.0.text }}
lastMentionUser : {{ data.mentions.body.statuses.0.user.screen_name }}
Device Command - Output - Docs
This node will actually send a command message to a device in the system. The device id needs to be set the to Light Show device from earlier in the project.
Settings
Device: This should be automatically filled in with your one device.
Command Path: newMention
Now, once all these nodes are setup and the workflow deployed you should be able to look at the debug tab to see the payloads of the respective nodes.
Building Twitter Follower Workflow
The second workflow that needs to be created watches Twitter for new followers. This will use the id of the latest follower in a similar fashion as the last workflow to determine if a new follower has been added.
Create a new workflow and name it anything you’d like.
Once created add the following nodes. Reference the below picture for correct connections.
Here are the details for each of the nodes.
Debug - Output - Docs
These are sprinkled throughout to see the payload that is coming out from connected nodes.
Virtual Button - Trigger - Docs
No configuration changes needed. This will be used for debugging the workflow.
Timer - Trigger - Docs
Set the configuration to Every 1 Minute. This will cause the workflow to start every one minute to check for new mentions.
HTTP Node - Data - Docs
Set the configuration to GET the followers Twitter API. To call the API an Authorization header has to be sent. This pulls the request and puts it on the payload path in the workflow so it can be referenced later. More on the Twitter Follower API.
Settings
GET
Url Template: https://api.twitter.com/1.1/followers/ids.json?screen_name=losant&stringify_ids=true (change “losant” to your own account)
Headers:
Authorization Bearer <access_token>
Make sure to put your Twitter access token in the header.
Payload Path: data.followers
Connects to Get Value Node and a Debug Node.
Get Value - Data - Docs
The configuration needs to be set to pull the last follower id from the Losant workflow data storage. This id is used to determine if the latest follower from the Twitter API is the same one as the last time the workflow is run. This node gives us the capability to store values across workflow runs.
Settings
Value Identifier: lastFollowerId
Payload Path: data.lastFollowerId
Default Value: -1
Conditional - Logic - Docs
The conditional node checks to see if the latest follower from Twitter is equal to the id pulled from the workflow storage. If these are the same nothing needs to be done (right output). If they are different then the new value needs to be recorded and a command needs to be sent to Light Show device.
Settings
Expression: {{ data.lastFollowerId }} === {{ data.followers.body.ids.0 }}
Store Value - Data - Docs
This node is going to update the latest follower id stored in the workflow storage. The value will be pulled from the Twitter follower list.
Settings
Value Identifier: lastFollowerId
Payload Path: data.followers.body.ids.0
Virtual Device - Output - Docs
This node will save values to the Twitter Stats virtual device that was created earlier. This isn’t absolutely necessary for this project but allows for dashboard creation from the data.
Settings
Device: This should be filled in with your one virtual device that was created.
State:
lastFollowerId : {{ data.followers.body.ids.0 }}
Device Command - Output - Docs
This node will actually send a command message to a device in the system. The device id needs to be set the to Light Show device from earlier in the project.
Settings
Device: This should be automatically filled in with your one device.
Command Path: newFollower
Now, once all these nodes are setup and the workflow deployed you should be able to look at the debug tab to see the payloads of the respective nodes.
Wiring Feather Huzzah and Neopixels Circuit
Now that Losant is setup to collect information from Twitter we need to build our actual device circuit to control the light it set. The whole setup is not very complicated.
Here’s the reference image and wiring diagram.
I soldered the three wires on to the NeoPixel ring. This made handling the ring much easier and could plug it directly into the breadboard. The wires were pretty stiff which allowed for the ring to stick straight up off of the board.
This means that the Huzzah is powering the NeoPixels and sending the data to them as well. The 3V (a3 on board) and GND (a5 on board) on the Huzzah were jumped to + and - rails on the bread board. The PWR and GND wires are then jumped to the + and - rails for power. The data IN line is jumped to analog pin 13 on the Huzzah. On the breadboard this is j11. This is pretty much it. Very simple circuit.
Programming Feather HuzzahThe last piece to get this project working is putting the required code on to the Huzzah. The code will do a basic color animation when getting a command from Losant. However, once you have this running you can explore all kinds of interesting lighting changes. You can grab the entire code from Github.
I’m not going to walk through each minor step but highlight the major pieces.
Starting off there are a number of variables that need initialized. This includes creating the Losant client and creating NeoPixel driver.
#include <ESP8266WiFi.h>
#include <Losant.h>
#include <Adafruit_NeoPixel.h>
// WiFi credentials.
const char* WIFI_SSID = "your wifi ssid here";
const char* WIFI_PASS = "your wifi pass here";
// Losant credentials.
const char* DEVICE_ID = "your device id here";
const char* ACCESS_KEY = "your access key here";
const char* ACCESS_SECRET = "your access secret here";
const int STRIP_PIN = 13;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, STRIP_PIN, NEO_RGBW + NEO_KHZ800);
// Used for keeping track of animation
bool runningAnimation = false;
uint8_t animationOffset = 0;
uint32_t prevTime;
uint8_t animationLoop = 0;
// Colors
uint32_t infraRed = strip.Color(73, 255, 92, 50);
uint32_t cobaltBlue = strip.Color(79, 40, 255, 50);
uint32_t defaultColor = strip.Color(0, 0, 0, 255);
uint32_t animationColor = cobaltBlue;
// Brightness for NeoPixel
uint8_t defaultBrightness = 255;
// For an unsecure connection to Losant.
WiFiClientSecure wifiClient;
// Device for talking to Losant
LosantDevice device(DEVICE_ID);
The next area of the code will handle setting up the application and connect to the WiFi and then to Losant platform.
void connect() {
// Connect to Wifi.
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Connect to Losant.
Serial.println();
Serial.print("Connecting to Losant...");
device.connectSecure(wifiClient, ACCESS_KEY, ACCESS_SECRET);
while(!device.connected()) {
delay(500);
Serial.print(".");
}
Serial.println("Connected!");
}
void setup() {
uint8_t i;
Serial.begin(115200);
delay(100);
connect();
// Setup Neopixel Strip and default color and brightness
strip.begin();
for(i = 0; i < 12; i++) strip.setPixelColor(i, defaultColor);
strip.setBrightness(defaultBrightness);
strip.show();
}
Once we have the basic setup we need to add in listening to Losant for a command. This is also done in the setup function. You need to add this just before the connect call.
// Register the command handler to be called when a command is received
// from the Losant platform.
device.onCommand(&handleCommand);
// existing connect
connect();
The handle command function has to be above the setup function. This function also has a dependency which needs to be above the handle function. The handle command function checks the name of the command coming from Losant. If it’s a new mention then sets the animation color to our blue and if a follower to red. For each of the commands we start the animation.
void startAnimation() {
prevTime = millis();
runningAnimation = true;
animationLoop = 0;
}
// Called whenever the device receives a command from the Losant platform.
void handleCommand(LosantCommand *command) {
Serial.print("Command received: ");
Serial.println(command->name);
if(strcmp(command->name, "newMention") == 0) {
animationColor = cobaltBlue;
startAnimation();
}
if(strcmp(command->name, "newFollower") == 0) {
animationColor = infraRed;
startAnimation();
}
}
The last couple pieces of the application handle the animation and loop. In the loop the WiFi and Losant connections are checked and reconnected if needed. If an animation is running then the NeoPixels are updated appropriately.
void pulseAnimation() {
uint8_t i;
for(i = 0; i < 12; i++) {
if((animationLoop % 2 == 0 && animationOffset > i) ||
(animationLoop % 2 == 1 && animationOffset < i)) {
strip.setPixelColor(i, animationColor);
} else {
strip.setPixelColor(i, defaultColor);
}
}
strip.show();
animationOffset++;
if(animationOffset == 12) {
animationOffset = 0;
animationLoop++;
delay(7200);
}
delay(100);
}
void checkAnimation() {
uint32_t t;
uint8_t i;
// check for running animation
t = millis();
if((t - prevTime) > 9600) {
for(i = 0; i < 12; i++) strip.setPixelColor(i, defaultColor);
strip.show();
prevTime = t;
runningAnimation = false;
Serial.println("Animation Complete!");
}
if(runningAnimation) {
pulseAnimation();
}
}
void loop() {
bool toReconnect = false;
if(WiFi.status() != WL_CONNECTED) {
Serial.println("Disconnected from WiFi");
toReconnect = true;
}
if(!device.connected()) {
Serial.println("Disconnected from Losant");
Serial.println(device.mqttClient.state());
toReconnect = true;
}
if(toReconnect) {
connect();
}
device.loop();
if(runningAnimation) {
checkAnimation();
}
}
Once the Huzzah is setup and running with the code, you should be able to use the serial console in Arduino IDE to double check that everything is working correctly. Testing Losant commands can be done through the device screen in the platform. If you need any help programming the Feather Huzzah, there’s a good walkthrough on the Losant site.
If everything is working the Neopixels will now change colors with you get a Twitter mention or a new follower.
Finishing the Project OffTo add a little flair to the project I added a small globe diffuser on top of the NeoPixels. You can get it from IKEA online. I cut a small circle out of foamcore board with a notch for the USB cord. The breadboard with NeoPixel ring then sat on the foamcore and the globe section on the light just on top of that.
Hope this small project helps you with your Twitter and hardware obsession. Make sure to post any fun changes or adaptations you make.
Comments