Table of Contents
The plan:
The plan was simple. I had nanoleaves lying around from a previous project (Wishing Tree) and wanted to do something with them. Before starting my software development apprenticeship, I used to enjoy watching football. I would put on several games regardless of the day they were played on. Now, due to myself working during the week and creating personal projects on the weekend, my time is limited, and thus I rarely ever get to watch the games.
I thought, instead of taking the simple approach of keeping open a live tracker/listening to the radio, I would take a creative approach of lighting up the nanoleaves based on the team that scores. I wanted to produce an output quick. I didnt care about how the code war written nor how long it took for the leaves to light up. My goal was to have my nanoleaves light up when a team scores no matter what.
Design Process:
Immediately upon undertaking this project, I knew I needed the football team colours. I was fortunate enough that a website (teamcolorcodes) already had all the teams in the premier league with their team colours RGB. This saved me a-lot of time. At this point I had to have a way of storing all the colours for the application to use. I went with a json file which contained the team name, along with the three colours that represent the team
After creating the JSON file with the team colours, I decided to draw a simple design sketch on figma showing the 3 frames/stages of the colours that the nanoleaves will look like upon a team scoring. (These colours will change dependent on team colours)
The Problem With The Nanoleaf API:
The way that nanoleaves work is via sending requests to the API. The nanoleaf documentation is severely lacking and quite underwhelming in what the leaves are able to do. That being said, the main way to light up nanoleaves from code is to send a PUT request to the leaves with RGB data. This request follows a format along the lines of the following:
Leaf 1 -> PUT Request = (’{“write”: {“animdata”: “ 1 1 237 233 57”}')
The request above follows a certain format as stated in the nanoleaf documentation. That is, to create a write command and send the following attributes. The first “ 1” is the frame. I would want to send one colour so 1 frame would be needed. The second “ 1” is the ID of the leaf. This is used to target the specific leaf to send the request too. Finally, the last 3 numbers are the RGB value to send to the leaf. This works if you want to light up the leaves however its incredibly inefficient, due to the amount of requests that are needed to light up all the leaves in a sequence. In addition, it’s prone to many issues, including overloading pythons request library.
Development:
Starting development, I had a clear idea in mind of what I was meant to do, as-well as the challenges that would arise. Due to this project being a quick side project, I did not care about following best practices and followed the approach of “As long as the code works”.
Packet Builder Algorithm
To combat the issue of having to send three requests to each leaf every second to change their colours, I came up with a solution, that I called the packet builder. The solution is to have 1 request that is sent to the leaves. Inside this request will be the total frames, each leaf ID and all the RGB values the leaves will light up with.
To the human reading the packet that is sent, it will seem like a large ball of mess containing mass amounts of integers, however to the API this request is massively more efficient than sending each request individually to each leaf 3 times per second.
There are 3 main methods/functions that encompass this packet builder algorithm. Those are getting the layout of the nanoleaves and all the panels that are on the network. The second is getting the ID of each leaf from the panels recognised on the network. The final is the packet builder itself.
GetLayout()
1 |
|
The GetLayout() method is very simple in nature. A GET request is sent to the Nanoleaf API. The JSON string that is returned is passed into a variable called outputFormat. This string will be used later on when getting the ID of each leaf.
GetId()
The GetId() method is the next part of the packet builder process. This method simply iterates through the layout JSON string, which contains all the leaves on the network that were detected, and searches for the string panelId. If this string is found in the layout request, the text will be formatted and split. From here, that stripped string (Leaf specific ID) will be added to an array named leafId. Once the whole string has been iterated over, the leafId array is returned. This is vital for the PacketBuilder script.
1 |
|
PacketBuilder()
The PacketBuilder() method, the final part of the packet builder process, is shown below. This method is responsible for actually building the request that will be sent to the nanoleaf API.
1 |
|
The script does a-lot of things. The first of which is iterating over the leafId array. For each iteration, a new string is built. The string contains the leafId, the time of the animation and the total frames. This string is then appended to an array.
Once all leaf Ids have finished being processed, the array of strings has a for-loop iterate over its elements. This is where the request and format of the request is formed. A new string is created. It contains the previously made string as-well as the RBG colours from the texts.json made earlier in the design stage.
1 |
|
This method above is the function responsible for checking the currents teams the user has chosen to watch and stores their team colours in a dictionary called “ currentTeamColours”. This dictionary has an array of the colours stored in it. The dictionary is returned once the function is finished running.
1 |
|
The lines of code above are the last of the PacketBuilder(). They are responsible for creating a custom animData request to send to the nanoleaf API. The leafColour variable is sent to the nanoleaf API via a PUT request. The above code doesn’t show the actual request that is sent. The actual request is shown below:
The above image is showing the request that is received by the nanoleaves. This is extremely more efficient and is a great solution to the issue described earlier. With this packet builder complete and working, the final part is using the beautiful soup library to scrape live football data and change the leaves colours based on the team that scored.
Getting The Live Football Scores
For this part of the application I wanted to take the quickest route possible. To me, that meant listening for a change of goal on a live scoring webpage and changing the light colours based on the information from the webpage.
Once I decided upon a website (sportinglife), I implemented the final aspects of the code.
1 |
|
Above is showing the input part of the code. This is where I will enter the URL to the football game. This is then passed to the BeautifulSoup library. From there I am finding the two classes, in the HTML source code, responsible for displaying the score and the team names. I store both of these elements into variables.
1 |
|
The code above is the final aspect of the application. It simply checks the function every 1 second waiting for the score for either team to increase. If a team scores than the GetLayout() method is called and the application runs, builds the packet/request and the leaves light up. If no team has scored, the method runs itself every second until a team does score. This function will run for the length of the game