lawn mower
Dev
Pi Hole
Pi Dev
Parts
Wiring
Pi Config
Linux Setup
Commandbox install
Jar Loading
Boot Service
Make it work
Make it Pretty
Computer vs microprocessor
Power
Speed
Efficiency
Protocols
Sleep Current
Storage
Complexity
Language
Plug & Play
Wifi/Bluetooth
LTE
5V
Power
Pin 18
(PWM)
GND
PI: Pin 18 -> LEDs: Data/Signal
PI: Ground -> LED:Ground
5V DC: Ground -> LED: Ground
5V DC: 5V+ -> LED: 5V+
Pulse width modulation
GPIO - General Purpose I/O
Pi Communication Protocols
Install Latest Raspbian on SD Card
create empty SSH.TXT
edit config.txt
#comment out dtparam
#Enable audio (loads snd_bcm2835)
#dtparam=audio=on
After you save those changes
eject the SD Card
Insert in the Pi and plug it in
create wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=US
network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
}
ssh pi@raspberrypi.local
pi@raspberrypi.local's password: (default is raspberry)
//install wiringpi
sudo apt-get update && sudo apt-get install wiringpi
//disable audio (conflicts with PWM)
nano /etc/modprobe.d/alsa-blacklist.conf
//add line and save
blacklist snd_bcm2835
curl -fsSl https://downloads.ortussolutions.com/debs/gpg | sudo apt-key add -
echo "deb https://downloads.ortussolutions.com/debs/noarch /" | sudo tee -a /etc/apt/sources.list.d/commandbox.list
sudo apt-get update && sudo apt-get install apt-transport-https commandbox
> nano index.cfm
NANO..... REALLY??
WE CAN DO BETTER
<CFLED>
But, when all else fails
look for a JAVA library
> cd ~/Desktop/
> mkdir statusLights
> cd statusLights
> box
Welcome to CommandBox!
CommandBox> install "jar:https://repo1.maven.org/maven2/com/diozero/diozero-ws281x-java/0.11/diozero-ws281x-java-0.11.jar"
Done.... right?
But how do we use it?
Task runners
component {
function run(){
classLoad( '/home/pi/Desktop/lightStatus/lib/diozero-ws281x-java-0.11/diozero-ws281x-java-0.11.jar' );
var freq = 800000; //Default
var DMA = 5; //Default
var pin = 18; // GPIO Pin
var numOfLights = 50;
var brightness = 200; //0-255
// RGB, GBR, BGR
var stripType = createObject("java","com.diozero.ws281xj.StripType");
var ledController = createObject("java","com.diozero.ws281xj.rpiws281x.WS281x");
ledController.init(freq,DMA,pin,brightness,numofLights,stripType.WS2811_RGB);
for(var ledID=0; ledID < 50; ledID++ ){
//( ledID * 5) just uses the (ledID x 5) as the color to make a gradient
ledController.setPixelColourHSL(ledID,(ledID * 5),.5,.5);
ledController.render(); //have to render after set
}
}
lightTest.cfc
> Welcome to CommandBox!
> CommandBox> task run lightTest
standard index.cfm
<cfscript>
for(var ledID=0; ledID < 50; ledID++ ){
//( ledID * 5) just uses the (ledID x 5) as the color to make a gradient
ledController.setPixelColourHSL(ledID,(ledID * 5),.5,.5);
ledController.render(); //have to render after set
}
</cfscript>
index.cfm
component{
this.name = "statusLights";
function onApplicationStart(){
var freq = 800000; //Default
var DMA = 5; //Default
var pin = 18; // GPIO Pin
var numOfLights = 50;
var brightness = 200; //0-255
// RGB, GBR, BGR
var stripType = createObject("java","com.diozero.ws281xj.StripType");
application.ledController = createObject("java","com.diozero.ws281xj.rpiws281x.WS281x");
application.ledController.init(freq,DMA,pin,brightness,numofLights,stripType.WS2811_RGB);
}
}
Application.cfc
{
"dependencies":{
"diozero-ws281x-java-0.11":"jar:https://repo1.maven.org/maven2/com/diozero/diozero-ws281x-java/0.11/diozero-ws281x-java-0.11.jar"
},
"installPaths":{
"diozero-ws281x-java-0.11":"lib/diozero-ws281x-java-0.11/"
}
}
box.json
{
"name": "statuslights",
"jvm": {
"heapSize": 1024,
"minHeapSize": 256
},
"app": {
"libDirs": "lib"
},
"web": {
"host": "raspberrypi.local",
"http": {
"port": "80"
},
"webroot": "/"
},
"force": true
}
Server.json
<cfscript>
function blink(pixel,hueColor = 0,numberOfBlinks = 5){
for(var i=1; i<numberOfBlinks; i++){
ledController.setPixelColourHSL(pixel,hueColor,.5,.5);
ledController.render(); //have to render after set
sleep(100);
ledController.setPixelColourHSL(0,0,0); //OFF
ledController.render(); //have to render after set
sleep(100);
}
}
function rainbow(pixel){
for(var i=1; i<360; i++){
ledController.setPixelColourHSL(pixel,i,.5,.5);
ledController.render(); //have to render after set
sleep(60); //Slow it down so you can see it
}
}
</cfscript>
Animations
component {
function run(){
//blink(pixel,hueColor = 0,numberOfBlinks = 5)
blink(1,0,5);
blink(2,0,5);
blink(3,0,5);
blink(4,0,5);
blink(5,0,5);
// rainbow(pixel)
rainbow(6);
rainbow(7);
rainbow(8);
rainbow(9);
rainbow(10);
}
}
Do we have a problem?
Too
Much
Sleep
<cfscript>
function rainbow(pixel){
for(var i=1; i<360; i++){
ledController.setPixelColourHSL(pixel,i,.5,.5);
ledController.render(); //have to render after set
sleep(60); //Slow it down so you can see it
}
}
//Create a thread
thread {
rainbow(1);
}
//Use run async
runAsync(function(){
return rainbow(1);
});
//Install Coldbox 6 BE
//use cbFutures
async = new coldbox.system.async.AsyncManager();
async.newFuture( () => rainbow(1) )
</cfscript>
component{
function run(){
fileSystemUtil.createMapping( "/coldbox", getCwd() & "coldbox" );
//load in diozero java lib
siteMonitor()
}
//Async health check
function pingServer(id,siteURL){
cfhttp(method="GET", charset="utf-8", url=siteURL, result="local.result", timeout=10);
return {
'id' : id,
'healthy': structKeyExists(local.result,'status_code') && local.result.status_code == 200
};
}
//Site Monitor (health check)
function siteMonitor(){
async = new coldbox.system.async.AsyncManager();
var sites = [
() => pingServer(4,"https://www.ortussolutions.com"),
() => pingServer(1,"http://my.agritrackingsystems.com"),
() => pingServer(2,"http://my.agrimapping.com"),
() => pingServer(3,"http://app.cropcast.com")
]
async
.all( sites )
.get()
.each( ( healthCheck ) => {
var ledID = variables.ledIndex['siteMonitor'][healthCheck.id];
setLEDHue(ledID,60,true);
setLEDHue(ledID,colorScale((healthCheck.healthy ? 1 : 0 ),'red','blue'),true);
})
}
}
Add 'coldbox@be' as a dependency in box.json
component{
async = new coldbox.system.async.AsyncManager();
taskManager = async.newScheduledExecutor( name: "myTasks", threads: 20 );
function run(){
var future = taskManager.newSchedule(updateClock)
.every( 60000 ) // Run every minute
.start();
}
function updateClock(){
var dt = now();
//update day of the week (1-7)
var curr_weekday = datePart('w',dt);
...
//update clock hours (1-24), cut in half for 12hr clock
var curr_hr = datePart('h',dt);
...
//update clock minutes (0-60) increments of 5
var curr_min = datePart('n',dt);
...
}
}
1
2
3
4
//LED Lights ID Mapping
variables.ledIndex = {
"weekdays": [31, 30, 29, 28, 27, 26, 25],
"hours": [47, 48, 16, 19, 20, 23, 34, 33, 38, 39, 42, 44],
"minutes": [46, 49, 17, 18, 21, 22, 35, 36, 37, 40, 41, 45],
"temp": [15, 14, 13],
"piStatus": [11, 10, 9, 8],
"siteMonitor": [7, 6, 5, 4],
"workMonitor": [3, 2, 1, 0],
"pomodoro": [24],
"calStat": [32],
"genblink": [12],
"wheatley": [43]
};
// Turn off LED by ID
function turnOffLED(id,forceUpdate = false){
variables.ledController.setPixelColourHSL(id,0,0,0);
if(forceUpdate) updateLights();
}
// Set LED Hue by ID
function setLEDHue(id,hue,forceUpdate = false){
variables.ledController.setPixelColourHSL(id,hue,1,.5);
if(forceUpdate) updateLights();
}
// Push light settings to the LEDs
function updateLights(){
variables.ledController.render();
}
// Blink light
function blink(ledID,hue,delay,blinkNum){
for(var i=1; i <=blinkNum; i++){
setLEDHue(ledID,i,true);
sleep(delay);
turnOffLED(ledID,true);
sleep(delay);
}
}
// Get the corresponding color from a color range based on a percentage
function colorScale(percent, lowColor, highColor){
if(percent > 1) percent = 1;
if(!isNumeric(lowColor)) lowColor = variables.colorIndex[lowColor];
if(!isNumeric(highColor)) highColor = variables.colorIndex[highColor];
var val = abs(lowColor - highColor) * percent;
return (highColor < lowColor) ? lowColor - val : lowColor + val;
}
// update clock (Day of week, hours, minutes, pomodoro timer)
function updateClock(){
//Needs to be set here, or in the admin to ensure the correct time zone
SetTimeZone(timezone='America/Los_Angeles');
var currTime = now();
var dow = datepart('w',currTime); //Day of the week 1-7
var curr_hour = datepart('h',currTime); //Hour 24hr clock
var curr_min = datepart('n',currTime); //Minutes
var hourLEDIdx = variables.ledIndex['hours']; //led Index for hours
var hourColor = (curr_hour/24*60)+200; //Hour gradient starting at 200 (lightblue)
var minuteLEDIdx = variables.ledIndex['minutes']; //led Index for minutes
var minuteColor = (curr_min/60*60)+30; //Minute gradient starting at 30 (purple)
// update pomodoro clock (0-25 min.) (25-30 min. Red, Get up and move)
var halftime = curr_min;
var pomoLED = variables.ledIndex['pomodoro'][1];
if(halftime > 30) halftime = halftime - 30;
if(halftime <= 25){
setLEDHue(pomoLED,colorScale(halftime/25,'green','purple'));
} else {
blink(pomoLED,0,100,6);
}
// Set day of the week ...
// Set hour of the day ...
// Set minute (increments of 5) ...
updateLights(); //update lights after everything is set
}
//System Stats
function SystemStats(){
var systemInfo=GetSystemMetrics(); //Get lucee System Metrics
var heap = getmemoryUsage("heap"); // Java heap usage
var nonHeap = getmemoryUsage("non_heap"); //Java Non-heap usage
var leds = variables.ledIndex['piStatus'];
setLEDHue(leds[1],colorScale(systemInfo.cpuSystem,'green','red'));
setLEDHue(leds[2],colorScale(heap.used/heap.max, 'green','red'));
setLEDHue(leds[3],colorScale(systemInfo.queueRequests, 'green','red'));
setLEDHue(leds[4],colorScale(randRange(0,1), 'green','red'));
updateLighleds
}
//Site Monitor (health check)
function siteMonitor(){
pingServer(1,"http://my.agritrackingsystems.com");
pingServer(2,"http://app.cropcast.com");
pingServer(3,"https://www.ortussolutions.com");
pingServer(4,"https://www.google.com/");
}
...
[Unit]
Description='Status Lights'
[Service]
ExecStart='/usr/local/bin/box' server start name='statuslights' directory='/home/pi/Desktop/lightStatus/' serverConfigFile='/home/pi/Desktop/lightStatus/server.json' --noSaveSettings
ExecStop='/usr/local/bin/box' server stop name='statuslights' directory='/home/pi/Desktop/lightStatus/' serverConfigFile='/home/pi/Desktop/lightStatus/server.json'
Type=forking
SuccessExitStatus=143
Restart=on-failure
RestartSec=2000ms
[Install]
WantedBy=multi-user.target
Coldbox Site, Content Box (piBox), CFML Site
[Unit]
Description='Status Lights'
[Service]
ExecStart='/usr/local/bin/box' task run '/home/pi/Desktop/lightStatus/twinkleTask.cfc'
Type=simple
SuccessExitStatus=143
Restart=on-failure
RestartSec=2000ms
[Install]
WantedBy=multi-user.target
Task "Manager"