[Python] Twitter controlled LEDs
-
Before I started messing around trying to get Hyperion working with my Raspberry Pi I had my LEDs set up to work with my Arduino. During this time I had an idea about controlling the colour from a tweet.
I remembered seeing a blog post a long time ago about someone doing something similar with tweets and thought it might be fun to try.That was a while back and I have only just started to actually do something about it.
The Process
The whole process should look something like this:
- Someone sends a tweet to my account “@JoshuaRickers #FF0000”
- My twitter bot written in Python will pick up that tweet
- Send the html colour code to my Arduino
- Arduino changes LED colours
Simple enough?
Python Regex
I don’t know if regex hates me more or if I hate regex more. After a while of playing around and searching Google I think I have come up with the correct regex for this little project.
/(#[a-f0-9]{6}|#[a-f0-9]{3})/i
Python does not have anything built in to handle the usual regular expression syntax so you have to use a slightly modified regex with the re module.
import re p = re.compile('(#[a-f0-9]{6}|#[a-f0-9]{3})', re.IGNORECASE) test_str = "@joshuarickers #FFFfff" m = re.search(p, test_str).group() print(m)
This is a basic test to see if the regex actually works and for me to figure out how to use it in Python. I had only previously used regex when trying to code that IMDB plugin for NodeBB, using JavaScript. This is slightly different.
From the above code
m == #FFFfff
which is exactly what I want. This will then be passed to my Arduino for it to works its magic. -
Arduino
Since the previous post @Almost has helped me realise that the decimal value of a hex value can be used in place of a hex value. I should have figured that out pretty easy but the documentation for FastLED and my understanding of HTML Colour codes and Hex Colour codes got me all confused. It did click after lying in bed for about 30 minutes trying to figure the situation out.
I didn’t have time yesterday to put it into practice and to see if FastLED could accept a decimal value. It can and now instead if setting the LED colours with 0x0000FF I can just use the value 255 instead.
@Almost also mentioned the
strtol()
function which will convert a string to a long. This basically solves all my issues.
The code below shows that when i send a string of"#0000FF\n"
via serial to my Arduino it will convert the"0000FF"
into a long integer,0000FF
being255
. This value is then past to the array of LEDs which in turn turns all the LEDs blue.#include "FastLED.h" #define NUM_LEDS 50 #define DATA_PIN 11 #define CLOCK_PIN 13 CRGB leds[NUM_LEDS]; String htmlColour; long number; void setup() { Serial.begin(9600); FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS); } void loop(){ if (Serial.available() > 0){ htmlColour = Serial.readStringUntil('\n'); number = strtol( &htmlColour[1], NULL, 16); Serial.println(number); } for(int i = 0; i < NUM_LEDS; i++) { leds[i] = number; leds[i].maximizeBrightness(); } FastLED.show(); }
-
I struggled to get Python to send string to the Arduino because i didnt realise the had to be encoded into bytes. Once i realised this I was able to pass on some test colours with the following code.
import serial ser = serial.Serial('COM3', 9600, timeout=2) ser.readline() ser.write(bytes('#00CED1', 'ascii')) print(ser.readline()) ser.write(bytes('#8B008B', 'ascii')) print(ser.readline()) ser.write(bytes('#FFFF00', 'ascii')) print(ser.readline())
One thing i did notice is that I had to delay some of the communication with some readline() as it would just return an empty string.
-
Here is some of the twitter code i had from the other night.
This code returns the latest tweet to my account.from twython import Twython, TwythonError import time api_key = "" api_secret = "" access_token = "" access_secret = "" tweetID = 0 twitter = Twython(api_key, api_secret, access_token, access_secret) try: search_results = twitter.search(q = 'to:joshuarickers', count = 1, since_id = tweetID) except TwythonError as e: print(e) print(search_results['statuses'][0]['text'])
-
I have got a working version of the twitter bot.
Every 60 seconds it will grab the latest tweet to me and if it contains a html colour code it will change my LEDs to that colour.Python
from twython import Twython, TwythonError import serial, time, re ser = serial.Serial('COM3', 9600, timeout=2) regex = re.compile('(#[a-f0-9]{6}|#[a-f0-9]{3})', re.IGNORECASE) api_key = "" api_secret = "" access_token = "" access_secret = "" tweetID = 0 twitter = Twython(api_key, api_secret, access_token, access_secret) while True: try: search_results = twitter.search(q = 'to:joshuarickers', count = 1, since_id = tweetID) except TwythonError as e: print(e) print('Tweet: ', search_results['statuses'][0]['text']) if re.search(regex, search_results['statuses'][0]['text']): colour = re.search(regex, search_results['statuses'][0]['text']).group() print('Colour :', colour) print(ser.readline()) ser.write(bytes(colour, 'ascii')) time.sleep(60)
Arduino
#include "FastLED.h" #define NUM_LEDS 50 #define DATA_PIN 11 #define CLOCK_PIN 13 CRGB leds[NUM_LEDS]; String htmlColour; long number; void setup() { Serial.begin(9600); FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS); } void loop(){ if (Serial.available() > 0){ htmlColour = Serial.readStringUntil('\n'); Serial.read(); number = strtol( &htmlColour[1], NULL, 16); Serial.println(number); } for(int i = 0; i < NUM_LEDS; i++) { leds[i] = number; leds[i].maximizeBrightness(); } FastLED.show(); }
-
@Scuzz That’s pretty sweet, I would love to see a video of it working.
-
@GoaNy I will try and get one soon. The camera on my phone is pretty shit when there is low light.
-
I did something similar back with Boblight a year or 2 ago. Had it working with configurable lighting effects and Facebook/Email too.
https://www.youtube.com/watch?v=RM946iXWEx8
The lighting transition was generated as well since Boblight only took byte streams and didn’t know about any effects.
Kind of related to this, I currently have my Hyperion set up with 2 different sources, Kodi and an USB video grabber but I needed a way to easily switch them. My first solution was to create a Kodi plugin that I could control using a simple HTTP request. It worked but was tedious. I recently learned about the existence of
cec-client
and it’s monitoring mode, so I whipped up a bash script that monitors the CEC traffic and changes Hyperion sources based on my AV receiver’s source. All configurable too. The only other thing I want now is to be able to change the HDMI OUT mode of my receiver but apparently that’s impossible using CEC. There’s an undocumented command you can send over telnet to do it though but I don’t want to get another ethernet cable there.