61S8BgGEuUL._SL1021_

LED light control

For a while now I’ve been wanting to fit some LED lights around the back of my sofa at home to brighten up that end of the room, and I spoke at the Preston Raspberry Jam a couple of months ago about my ideas. The plan was being to be able to use a Raspberry Pi to control the lights in the same way I use it control my Sonos system. I wanted them to come on when I got home and go off when I leave etc. After a lot of research i went for the Tingkam waterproof 5m RGB 50/50 LED Light strip from Amazon for £16.99.

61S8BgGEuUL._SL1021_

This kit comes with a remote control to change the light colours etc. There are a few ways I could have gone with connecting the Pi to the LED strip. It’s not just as simple as hooking the strip up to the GPIO ports though, the LED strip needs a faster signal than the GPIO can provide so you have to use SPI. I went for the simple option to begin with, I’m going to try it with the SPI connection at some point but for now I had an easier idea. At BETT I remembered seeing that Energenie did a IR version of their Pi-Mote board.

ENER314IR_01

The board has an IR transmitter but also, and very importantly an IR receiver. IT comes bundled with LIRC (Linux infrared Remote Control) software which is a breeze to install and configure and has the ability to learn the commands from your remote control.

Having taught LIRC the commands for the LED strip remote I could then control LED strip with a Pi. I wanted to be able to control the LEDS without going looking for my remote or having to get up so I quickly knocked together a webpage on the Pi with a few buttons to control the important features.

Photo 16-02-2015 18 39 36

 

I installed webpy on the Pi to act as a really simple web server and wrote a few lines of code to control the button pushes in the POST action for the web page. I’ve posted the code below.

the Python script that runs when the web server starts is here:

import web
from web import form
from soco import SoCo
import os


# Define the pages (index) for the site
urls = ('/', 'index','/sonos','sonos')
render = web.template.render('templates/')

app = web.application(urls, globals())




# define what happens when the index page is called
class index:
    # GET us used when the page is first requested
    def GET(self):
        
        return render.index("LED Remote control")

    # POST is called when a web form is submitted
    def POST(self):
        # get the data submitted from the web form
        userData = web.input()
        
        # Estblish which button has been pressed
        if userData.btn=="sonos":
            raise web.seeother('/sonos')

        #send the command to the pi-mote software, print statement for debuggin 
        else:
            print ("irsend SEND_ONCE LED" + " " +userData.btn)
            os.system("irsend SEND_ONCE LED" +" " + userData.btn)
         
            
        raise web.seeother('/') 

irsend is the command that sends the IR signal from the Py-mote, SEND_ONCE makes sure the it doesn’t continually transmit, LED is the command set to send using and userData.btn is inserts the value attribute from the button on the HTML page, each value coreseponds to a command remote control command.

$def with (title)
<!doctype html>
<html>
    <head>
        <meta name="apple-mobile-web-app-capable" content="yes">
        <title>$title</title>
        <link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/pure-min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
        
        <link rel="apple-touch-icon" href="static/apple-touch-icon.png">
        <link rel="apple-touch-startup-image" href="static/startup.png">
        
        
        
        <style scoped>
            
            .button-large,
	    .button-mlarge,
            .button-xlarge,
            .button-red,
            .button-green,
            .button-blue,
            .button-white{
                border-radius: 8px;
                
            }
	.button-large{
            font-size:200%;
        }
        .button-mlarge{
            font-size:250%;
        }
            
            
        .button-xlarge{
            font-size: 300%;
        }
        .button-red{
            background:red;
            
        }
        .button-green{
            background:green;
        }
        .button-blue{
            background:blue;
        }
        .button-white{
            background:white;
        }
            
            
        </style>

    </head> 
    <body>
        <form class="form" method="post"> 
        <div class="  button-large pure-menu pure-menu-open pure-menu-horizontal">
        <ul>
            <li><button name="btn" value="LED" class="pure-button">LED</button></li>
            <li><button name="btn" value="sonos" class="pure-button">Sonos</button></li>
            </ul>
        </div>
            
        
                
                   <table class="pure-table">
                        <tr>
                            <td><button name="btn" value="KEY_BRIGHTNESS_UP" class="button-xlarge pure-button">B up</button></td>
                            <td><button name="btn" value="KEY_BRIGHTNESS_DOWN" class="button-xlarge pure-button">B down</button></td>
                            <td><button name="btn" value="KEY_NEXT" class="button-xlarge pure-button">Next</button></td>
                            <td><button name="btn" value="KEY_POWER" class="button-xlarge pure-button">Power</button></td>
    
                        </tr>
                        <tr>
                            <td><button name="btn" value="KEY_RED" class="button-red button-xlarge pure-button">Red</button></td>
                            <td><button name="btn" value="KEY_GREEN" class="button-green button-xlarge pure-button">Green</button></td>
                            <td><button name="btn" value="KEY_BLUE" class="button-blue button-xlarge pure-button">Blue</button></td>
                            <td><button name="btn" value="KEY_WHITE" class="button-white button-xlarge pure-button">White</button></td>
    
                        </tr>
                            <tr>

                            <td><button name="btn" value="KEY_INC_RED" class= "button-red button-xlarge pure-button"><i class="fa fa-arrow-up"></i></button></td>
                            <td><button name="btn" value="KEY_INC_GREEN" class="button-green button-xlarge pure-button"><i class="fa fa-arrow-up"></i></button></td>
                            <td><button name="btn" value="KEY_INC_BLUE" class="button-blue button-xlarge pure-button"><i class="fa fa-arrow-up"></i></button></td>
                            <td><button name="btn" value="KEY_QUICK" class="button-xlarge pure-button">Quick</button></td>
    
                        </tr>
                        
                        <tr>

                            <td><button name="btn" value="KEY_DEC_RED" class= "button-red button-xlarge pure-button"><i class="fa fa-arrow-down"></i> </button></td>
                            <td><button name="btn" value="KEY_DEC_GREEN" class="button-green button-xlarge pure-button"><i class="fa fa-arrow-down"></i> </button></td>
                            <td><button name="btn" value="KEY_DEC_BLUE" class="button-blue button-xlarge pure-button"><i class="fa fa-arrow-down"></i> </button></td>
                            <td><button name="btn" value="KEY_SLOW" class="button-xlarge pure-button">Slow</button></td>
    
                        </tr>
			<tr>
                            <td><button name="btn" value="KEY_FADE_3" class="button-mlarge pure-button">Fade3</button></td>
                            <td><button name="btn" value="KEY_FADE_7" class="button-mlarge pure-button">Fade7</button></td>
                            <td><button name="btn" value="KEY_FLASH_3" class="button-mlarge pure-button">Flash3</button></td>
                            <td><button name="btn" value="KEY_FLASH_7" class="button-mlarge pure-button">Flash7</button></td>
    
                        </tr>
                        
                    </table>
                </form>
        
    </body>  
</html>

I made an icon and added the relevant code to the html header so i can run the webpage as a webapp on the iPhone and not have the Safari address bar at the top of the screen.

I mounted the board on a model A with a wifi adapter and hid it down the side of the sofa, the whole thing works a treat. The Pi-mote board is easy to configure ( although LIRC wouldn’t work on a Pi B2 due to some issues with the Kernel). I’ll definitely be getting another and finding something else to control.

The LEDs are stuck to the back edge of the sofa, the strip comes with a self adhesive back. U used a corner adapter to get a good join around the corner in the sofa, you can cut the strip every 10ish centimetres which is useful for getting the sizes correct.

Photo 16-02-2015 19 08 30 Photo 16-02-2015 19 08 20

The model A with the Pi-mote and then unceremoniously dumped down the side of the sofa.

Photo 16-02-2015 19 07 43Photo 16-02-2015 19 07 07

and a couple of pics with the LEDs on

 Photo 12-02-2015 18 53 25 Photo 12-02-2015 18 53 53

Car Pi

I picked up my very nearly new Golf Mk7 this week, and one of the most exciting things it has is an 8″ touch screen built into the dash. I’ve ordered an RCA adapter for the aux port for the display today so hopefully within the week I will have a Raspberry Pi fitted in the car.

Once that’s done I need to find a use for it, obviously the car disables the video input when your driving for ‘safety’, and it gives you lots of data about your driving already. I am thinking of using the 12v supply in the boot to power a wifi hotspot using a data simcard so i have 4G wifi in car and can browse the web in the car. I also want to play with the Deezer api and perhaps do something for the car with that.

Thats all for now

Weather Forecast finally working

Finally got around to doing some work on the weather forecaster, I made a quick video to show it in action:

I made the vid on my mac as its easier to show it working on the mac than the pi, works just as well on the pi though

I’m going to keep working on it and see where it goes.

Oh and go and buy, beg, borrow or steal a copy of this :

Adventures in Minecraft by Martin O’Hanlon and David Whale

I’ve had my copy a day now and it’s really, really good. I wouldn’t have got that video above made without it as I’ve never managed to get Bukkit woking before. Its a fantastic resource.

Code for the forecaster is below

from mcpi import minecraft
from mcpi import block
import re

# reads the weather from the text file and returns the weather and temperature
def readFile():
    try:
        with open("weather.txt") as file:

            fo=open("weather.txt", "r")
            weatherToday=fo.readline()
            tempToday=fo.readline()
            print(weatherToday)
            print(tempToday)
            return {'weather':weatherToday, 'temp':tempToday}
    except IOError as e:
            print "unable to open"
#finds whole words in strings using reggae
def findWord(word):
    return re.compile(r'\b({0})\b'.format(word), flags=re.IGNORECASE).search


# checks the weather forecast against known weather types 
def checkWeather():
    weatherType=["Cloudy","Sunny", "Rain", "Fog"]
    weatherFile=readFile()
    weatherString=weatherFile['weather']

    for condition in weatherType:
        check=findWord(condition)(weatherString)
        if check != None: weather = condition
    return {'weather':weather, 'temp':weatherFile['temp']}

#saves the location the weather was previously drawn in so it can be deleted the next day
def savePlace(place,fileName):
    strx=str(place.x)
    stry=str(place.y)
    strz=str(place.z)
    fo =open(fileName, "w")
    fo.write(strx + "\n" + stry + "\n" + strz)

def readPlace(fileName):

    fo=open(fileName,"r")
    place=minecraft.Vec3(int(fo.readline()),int(fo.readline()),int(fo.readline()))
    return place

# numbers and weather a drawn as ASCII characters
def digits(number):
    digit_dots = {
       '0':[
    ' 000',
    '0   0',
    '0   0',
    '0   0',
    '0   0',
    '0   0',
    '0   0',
    ' 000',
    ],
       '1':[
    '  0',
    ' 00',
    '  0',
    '  0',
    '  0',
    '  0',
    '  0',
    ' 000',
    ],
       '2':[
    ' 000',
    '0   0',
    '   0',
    '  0',
    ' 0',
    '0',
    '0',
    '00000',
    ],
       '3':[
    ' 000',
    '0   0',
    '    0',
    '  00',
    '    0',
    '    0',
    '0   0',
    ' 000',
    ],
       '4':[
    '   0',
    '  00',
    ' 0 0',
    '0  0',
    '00000',
    '   0',
    '   0',
    '   0',
    ],
       '5':[
    '00000',
    '0',
    '0',
    '0000',
    '    0',
    '    0',
    '0   0',
    ' 000',
    ],
       '6':[
    ' 000',
    '0   0',
    '0',
    '0000',
    '0   0',
    '0   0',
    '0   0',
    ' 000',
    ],
       '7':[
    '00000',
    '    0',
    '   0',
    '  0',
    ' 0',
    '0',
    '0',
    '0',
    ],
       '8':[
    ' 000',
    '0   0',
    '0   0',
    ' 000',
    '0   0',
    '0   0',
    '0   0',
    ' 000',
    ],
       '9':[
    ' 000',
    '0   0',
    '0   0',
    ' 0000',
    '    0',
    '    0',
    '0   0',
    ' 000',
    ],
       ':':[
    '',
    '',
    '  00',
    '  00',
    '',
    '  00',
    '  00',
    '',
    ],
    }
    return digit_dots[number]

def patterns(weather):
    weatherPatterns={
    'Cloudy':[

    '      0       ',
    '     000      ',
    '    00000     ',
    '   0000000    ',
    '  000000000   ',
    ' 00000000000  ',
        ],
     'Rain':[

    '      0       ',
    '     000      ',
    '    00000     ',
    '   0000000    ',
    '  000000000   ',
    ' 00000000000  ',
    '    1    1    ',
    '   1    1     ',
    '  1    1      ',
        ],
    'Sunny':[
    '              ',
    '       0      ',
    '    0  0  0   ',
    '     0 0 0    ',
    '    0 000 0   ',
    '     00000    ',
    ' 0000000000000',
    '     00000    ',
    '    0 000 0   ',
    '     0 0 0    ',
    '    0  0  0   ',
    '       0      ',
    ]
    }

    return weatherPatterns[weather]

def drawWeather(mc,place,weather,blockType):
    place.y += 11
    place.z -= 10
    savePlace(place,"place.txt")
    shape=patterns(weather)
    lineOffset=0
    for line in shape:
        dotOffset=0
        for dot in line:
            if dot == '0':

                mc.setBlock(place.x+dotOffset,place.y-lineOffset,place.z,blockType)
            elif dot =='1':
                mc.setBlock(place.x+dotOffset,place.y-lineOffset,place.z,block.WOOL.id,3)

            else:
                mc.setBlock(place.x+dotOffset,place.y-lineOffset,place.z,block.AIR)
            dotOffset += 1
        lineOffset += 1

def drawTemp(mc,place,numbers,offset):
    savePlace(place, "tempplace.txt")
    xOffset = offset * 6
    lineOffset = 0

    for line in numbers:
        dotOffset  = 0
        for dot in line:
            if dot == '0':
                mc.setBlock(place.x+dotOffset+xOffset, place.y - lineOffset, place.z, block.ICE)
            else:
                mc.setBlock(place.x+dotOffset+xOffset, place.y - lineOffset, place.z, block.AIR)
            dotOffset +=1

        for blank in range(dotOffset, 5):
                mc.setBlock(place.x+blank+xOffset, place.y - lineOffset, place.z, block.AIR)
        lineOffset +=1

def resetWeather(mc,place):
    for row in range (0,20):
        for col in range(0,12):
            mc.setBlock(place.x + row,place.y-col,place.z,block.AIR)

def main():
    mc=minecraft.Minecraft.create() 

    fileName="place.txt"
    lastWeather= readPlace(fileName)
    resetWeather(mc,lastWeather)
    fileName="tempplace.txt"
    lastTemp= readPlace(fileName)
    resetWeather(mc,lastTemp)

    currentPlace = mc.player.getPos()
    currentPlace.x=int(currentPlace.x)
    currentPlace.y=int(currentPlace.y)
    currentPlace.z=int(currentPlace.z)

    weatherFile=checkWeather()
    weather=weatherFile['weather']
    if weather == "Cloudy":blockType=block.STONE
    if weather == "Sunny":blockType=block.WOOL.id,4
    if weather == "Rain":blockType=block.STONE
    drawWeather(mc,currentPlace,weather,blockType)

    temp = weatherFile['temp']
    digitOffset=0
    currentPlace.x -=11
    for character in temp:
        mapy = digits(character)
        drawTemp(mc,currentPlace,mapy,digitOffset)
        digitOffset+=1

main()

WEATHER FORECAST UPDATE

Not had much time to work on the weather project, but an interesting idea came out of the Preston Raspberry Jam yesterday, I’m hopefully going to be able to have the students at school link the forecaster to a weather station and have Minecraft display the symbols for the weather outside. Exciting!!

sonosrpi

SWITCH OFF SONOS

A few weeks ago my lovely wife said it was OK to start building a Sonos system at home, which is awesome, I’ve loved the simplicity of the Sonos hardware since I first worked with it several years ago. It gets used every day, but i quite often forget to switch it off when I leave the house. Patrick Lenz developed a neat little solution using IFTTT and a geofence for the Mac, but only for one user. I wanted to have two users and use a Raspberry Pi to control the lot. Sonos don’t have an API, but a bit of digging finds you SoCo a Python class that can control a Sonos system using UPNP.

That was the Sonos side of things sorted. All I needed to achieve now was some way of telling the Pi that neither mine or my wife’s phones are in the house, so the Sonos system should be turned off.

Using IFTTT I set up a recipe to put a text file in my Dropbox if I left the Geofence, and the same for my wife. The text file contains 2 characters mine says ‘jo’ (James out), my wife’s says ‘ho’, you get the idea.

ifttt

Now using Andrea Frabrizi’s Dropbox Uploader i wrote a bit of code to loop the Dropbox uploader to check the text file, download the textfile and delete it from the Dropbox.

Then it’s just a quick If statement and the job’s done.

from soco import SoCo
import os
import time 



# run the dropbox-uploader shell script to download then delete the file from dropbox,
# otherwise dropbox creates multiple files, return the contents of the text file
def checkTrigger(user):
    print("checking " +user)
    os.system("/home/pi/Dropbox-Uploader/dropbox_uploader.sh download /IFTTT/" + user + ".txt")
    os.system("/home/pi/Dropbox-Uploader/dropbox_uploader.sh delete /IFTTT/" + user +".txt")
    try:
        with open(user + ".txt") as file:
            fo=open("/home/pi/automation/" + user + ".txt")
            return fo.read()
    except IOError as e:
        print "unable to open"
        
    

def main():
    while True:
        #check each of the text files                 
        jlocation=checkTrigger("jtrigger")
        
        
        hlocation=checkTrigger("htrigger")
        
        ## if both phones outside of the Geofence, turn off Sonos        
        if jlocation =="jo" and hlocation == "ho":
            sonos = SoCo("<IPADDRESSOFSONOSSPEAKER>")
            sonos.pause()
            print("Sonos paused")
            print("sleeping")
            time.sleep(60)
            
if __name__ =="__main__":
    main()
    
        


It works really well. Next job is to sort out the opposite, having Sonos come one when I arrive at home..

Weather forecast

There’s loads of ways of picking up the weather forecast, i thought the world needed one more. What if I could display the day’s weather and top temperature in the Minecraft world and have it update dynamically each day. I did a bit of digging and found that over on http://www.suppertime.co.uk/blogmywiki/2013/05/raspi-wx/ they had done a similar thing with pi and a printer to print the weather forecast.

The easiest way to get the weather into a format I could use on the pi was set up a recipe on IFTTT to drop the weather condition and temp into my Dropbox. Then use Andrea Fabrizi’s Dropbox Upload shell script to download the text file to the Pi each day.

IFTTT sends a very simple summary of the weather, “Cloudy”, “Mostly Dry” etc, now all I had to do is translate that into one simple key word for each day’s forecast. Using a regular expression to search for the keywords I could narrow down the general forecast to one simple word.

# Check for the presense of the weather text file and read the contents
def readFile():
    try:
        with open("weather.txt") as file:

            fo=open("weather.txt", "r")
            weatherToday=fo.read()
            return weatherToday
    except IOError as e:
            print "unable to open"

# Regular expression checks for whole words, returns 'None' if no match found
def findWord(word):
    return re.compile(r'\b({0})\b'.format(word), flags=re.IGNORECASE).search

def checkWeather():
    weatherType=["Cloudy","Sunny", "Wet", "Fog"]# list of possinle weather types output by IFTTT
    weatherString=readFile() # Calls the readfile function

    #checks the contents of the text file against the keywords, needs more work for days when miltiple
    #keywords exist
    for condition in weatherType:
        check=findWord(condition)(weatherString)
        if check != None: weather = condition
    return weather

Now all I had to do was draw the weather symbols in Minecraft. I took my inspiration and a handful of code from SleepOz’s digital clock. To draw the weather symbols, I need to work on the cloud but the sun looks pretty good! It’s still a work in progress so only has sun and cloud. I’m going to do rain next and try and animate blocks to look like rain falling.

def patterns(weather):
    weatherPatterns={
    'Cloudy':[

    '    0         ',
    '   000        ',
    '  00000       ',
    '  00000       ',
    ' 0000000      ',
    ' 0000000      ',
    ' 0000000      ',
    '000000000     ',
    '  00000       ',
    '000000000     ',
        ],
    'Sunny':[
    '              ',
    '       0      ',
    '    0  0  0   ',
    '     0 0 0    ',
    '    0 000 0   ',
    '     00000    ',
    ' 0000000000000',
    '     00000    ',
    '    0 000 0   ',
    '     0 0 0    ',
    '    0  0  0   ',
    '       0      ',
    ]
    }

    return weatherPatterns[weather]

It then uses a couple of nested loops to display the blocks, if it reads a zero it draws the block, otherwise it draws an air block

def drawWeather(mc,place,weather,blockType):

    shape=patterns(weather) # calls the function to return the correct weather pattern
    lineOffset=0 #starts drawing from the top of the shape
    for line in shape: #For each line of the weather shape
        dotOffset=0 #Starts from the left most block
        for dot in line: #For each column in the current line
            if dot == '0':

                mc.setBlock(place.x+dotOffset,place.y-lineOffset,place.z,blockType)
            else:
                mc.setBlock(place.x+dotOffset,place.y-lineOffset,place.z,block.AIR)
            dotOffset += 1 #Move to the next column
        lineOffset += 1 #Move to the next line

It’s still a work in progress but I think it’s off to a decent start. The next job is to draw more weather symbols ( kids at school can help with that), and make it remember where it drew yesterdays forecast and go an erase it.