This started out as a kit from The Pi Hut, when building it I swapped some of the LEDS from Red 3mm LEDS to Green 3mm LEDS. I Then continued building as normal, instructions at: https://thepihut.com/blogs/raspberry-pi-tutorials/3d-xmas-tree-for-raspberry-pi-assembly-instructions.
Simple SoftwareTo test the LEDs and make simple patterns I used the Pi Hut's code. This uses the GPIOZero library so make sure this is installed.
from gpiozero import LEDBoard
from gpiozero.tools import random_values
from signal import pause
tree = LEDBoard(*range(2,28),pwm=True)
for led in tree:
led.source_delay = 0.1
led.source = random_values()
pause()
OnlineNow I wanted this to be controllable online instead of using a database I used the 100% free Google Sheets. Firstly I setup a sheet with a row for each LED as shown below.
Setting up the SheetI decided instead of sending each number to the Pi I would use this as a binary number and send one base 10 number to be decoded. So I added the following.
Now I will add one more column with a formula,
=A1*B1
Now the spreadsheet has the columns.
Next I added a function to be the sum on column C.
=SUM(C1:C27)
This is the number I will be sending. Originally I attempted to use a python library to directly read the sheet however this was too slow and unreliable. I then came up with a different idea. To use a web app hosted by Google Apps Script.
Google Apps Script SiteNow I needed to setup a site to control it and a site to read it. I created a webapp in Google Apps Script and used the code below for my doGet()
function doGet(e) {
page = e.parameters.a[0]
if (page==1) {
return HtmlService.createHtmlOutputFromFile("interface");
}
else if (page==2) {
val = SpreadsheetApp.openById(SHEETID).getSheets()[0].getRange("C28").getValue();
return HtmlService.createHtmlOutput("<p>"+"StartVal"+val+"EndVal"+"</p>");
}
}
This code will take a parameter into the site to decide which page to serve.
If it sees the url URL
?a=1
Then it will feed the page "interface.html" and if it sees URL
?a=2
then it will server a simple HTML paragraph with StartValNumFromSheetEndVal
Now we can use this simple site to feed the values to python. At the top of the page on Google Apps Script press publish, deploy as webapp set the version to new and set the permissions to anyone even anonymous so that python doesnt have to be signed in. Set the app to execute as yourself so you can access the sheet.
Now to create the html page for controls. My Code is below.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Control Christmas Tree</h1>
<div id="allbuttons">
<div id="numbers">
<button onclick="writejs(1)"><img src="https://drive.google.com/uc?export=view&id=1wMZW-wr0-_9B7JKU4IhCzV3aQsan9Bor" width="100px"/></button><br><br>
<!--<button onclick="writejs(2)">1</button>-->
<button onclick="writejs(3)">1</button>
<button onclick="writejs(4)">2</button>
<button onclick="writejs(5)">3</button>
<button onclick="writejs(6)">4</button><br><br>
<button onclick="writejs(7)">5</button>
<button onclick="writejs(8)">6</button>
<button onclick="writejs(9)">7</button>
<button onclick="writejs(10)">8</button>
<button onclick="writejs(11)">9</button><br><br>
<button onclick="writejs(12)">10</button>
<button onclick="writejs(13)">11</button>
<button onclick="writejs(14)">12</button>
<button onclick="writejs(15)">13</button>
<button onclick="writejs(16)">14</button><br><br>
<button onclick="writejs(17)">15</button>
<button onclick="writejs(18)">16</button>
<button onclick="writejs(19)">17</button>
<button onclick="writejs(20)">18</button>
<button onclick="writejs(21)">19</button><br><br>
<button onclick="writejs(22)">20</button>
<button onclick="writejs(23)">21</button>
<button onclick="writejs(24)">22</button>
<button onclick="writejs(25)">23</button>
<button onclick="writejs(26)">24</button><br><br>
</div>
<br><br><br><br>
<div id="MasterButtons">
<button onclick="writejs(100)">All Off</button>
<button onclick="writejs(101)">All On</button>
</div>
</div>
<script>
function writejs(num) {
google.script.run
.withSuccessHandler(function(response) {
console.log(response);
})
.withFailureHandler(function(err){
console.log(err);
})
.write(num);
}
</script>
</body>
</html>
It is important to have the buttons with an onclick value to trigger a javascript function. Make sure that the site contains the function:
<script>
function writejs(num) {
google.script.run
.withSuccessHandler(function(response) {
console.log(response);
})
.withFailureHandler(function(err){
console.log(err);
})
.write(num);
}
</script>
This gets called when the buttons are pushed. It then takes the value and runs a Google Apps Script Function. I have also added a few buttons with other functions that pass different numbers. Now we will write the Google Apps script function.
Mine is below
function write(num) {
sheet = SpreadsheetApp.openById(SHEETID).getSheets()[0];
if (num==100) {
sheet.getRange("A1:A26").setValue(0);
return "Off"
} else if (num==101) {
sheet.getRange("A1:A26").setValue(1);
return "Off"
} else {
val = sheet.getRange("A"+num).getValue();
newval = val+1;
if (newval > 1) {newval = 0;}
sheet.getRange("A"+num).setValue(newval);
return newval;
}
}
Remember to replace SHEETID with the sheet id of your spreadsheet you will find this in the URL. The function first opens the sheet. Then it checks if the value is either 100 or 101 for the All On and All Off buttons. If it is neither of these then the code is run to toggle one of the values in the sheet.
This should be the Web App done, now we should be able to move on to the Python code for the Raspberry Pi.
Python Codeimport urllib.request
from re import findall
from gpiozero import LEDBoard
def get():
page = str(urllib.request.urlopen("WEBAPPURLFROMEARLIER").read())
result = str(bin(int(str(findall("StartVal(.*?)EndVal",page)[0]))))[2:]
resultlist = list(result)
resultlist.reverse()
return ''.join(resultlist)
tree = LEDBoard(*range(2,28),pwm=False)
while True:
try:
vals = get()
x = 0
for led in tree:
x = x+1
except:
print("Error")
Replace WEBAPPURLFROMEARLIER
with the URL from publishing the site earlier.
This code should now work.
Comments