Sunday, 12 April 2015

Python, MPD and Volumio

I'm building a Raspberry Pi powered vintage radio, by stripping out all the gubbings and add a raspberry pi, IQAudio DAC & Amp.


I'm going to use Volumio to provide the music player and UI, but in order to get the existing buttons on the radio working I need to interact with MPD (Music Player Daemon) which is the server software which makes it all work.

There is a python library called python-mpd2 [code] which provides an api for communicating with MPD, its pretty easy to use and it allows you to do things such as change the volume, play, pause, stop, skip tracks, change playlists, search for music, etc.

Install python-mpd2

I found that I need to install python's "setup tools" when using the volumio image:
wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python
Once setup tools is installed you can download python-mpd2 and install it:
git clone git://github.com/Mic92/python-mpd2.git
cd python-mpd2
sudo python setup.py install
Usage

The python-mpd2 module is pretty easy to use, its effectively a python client for the MPD server. The first steps are to import it, create the MPDClient and connect to the server.
from mpd import MPDClient
client = MPDClient()
#to connect to MPD you need to know the IP address and port
client.connect("localhost", 6600)
Once you are connected you can use the client to issue commands to the MPD server, such as pulling back the current status and the current version.
print(client.status())
print(client.mpd_version)
Some useful other mpd-python2 functions are:
#set the volume between 0 and 100
client.setvol(100)

#play song at certain position
client.play(1)

#pause and resume playback
client.pause(0)
client.pause(1)

#skip to the next or previous track
client.next()
client.previous()

#clear current playlist and load a new one
client.playlistclear()
client.load("nameofyourplaylist")
Here is a complete list of mpd-python2 commands.

Thursday, 2 April 2015

Autcraft - Autism Awareness Day

2nd April is Autism Awareness Day and on this day Start Duncan tries to get as many people talking about Autism and Bullying. You can read his call to arms on his blog.


Stuart (or AutismFather) runs a really special Minecraft server called Autcraft which is for children with Autism and their families.

He started Autcraft because there were so many Autistic children who where bullied or were excluded on other Minecraft servers, which I really struggle with, so I wanted to create a Minecraft program and a video to support Stuart, Autcraft and Autism Awareness Day.



The animation is all written in Python and a lot of the code is borrowed from some of my other Minecraft projects.

The code to create the diamond block text was taken from my Minecraft twitter client and the leg and boot is created in the same way I create and move around the ships in the Minecraft Starwars animation.

The rest of it is just Monty Python inspire silliness with a very important message "don't stand for bullying".

If you want to take a look at the code or run it yourself - github.com/martinohanlon/minecraft-autismawarenessday

Monday, 2 March 2015

Minecraft - Star Wars

Myself and David Whale (my co-author on Adventures in Minecraft) were asked if we would do a talk on "Hacking Minecraft" at the Raspberry Pi 3rd Birthday Party. I wanted to do something fun to show you how you can do amazing things in Minecraft using the Pi API.


After coding the Solar System in Minecraft I had the idea of creating the Death Star which would be able to 'fire' at the planets and destroy them.  I ended up coding an animation of the Death Star destroying Alderaan right up to Luke flying down the trench and successfully bombing the exhaust port with a block of TNT.


If you want to try it out yourself, all the code in at https://github.com/martinohanlon/minecraft-starwars. To download the code and run it on your raspberry pi, follow these instructions.

Run Minecraft: Pi Edition and open a world.

Open LX Terminal, and run the following commands to download the program and run the program

cd ~
git clone https://github.com/martinohanlon/minecraft-starwars
cd minecraft-starwars
python minecraft-starwars.py

The code relies heavily on the minecraftstuff module which is included in the mcpi directory of the repository, so if you copy the program anywhere else be sure to copy the mcpi directory too.

Saturday, 21 February 2015

Minecraft - Code a Solar System

Update - I took this further and created a DeathStar to blow up planets too, in a Minecraft Star Wars animation.

Every wondered how big the Sun is? Well check out the picture below.


If the Earth was the size of 1 block in Minecraft the Sun would have a diameter of 109 blocks and if the distance was to scale 11728 blocks away!


What about the size and distance of the other planets in blocks?

PlanetDiameterDistance
Mercury0.384539.04
Venus0.958482.28
Earth1.011727.81
Mars0.5317866.1
Jupiter11.2161037.94
Saturn9.45112378.49
Uranus4.01225188.15
Neptune3.88352391.03
Pluto0.19460175.6

I didn't build this Solar System I coded it. I took information about the diameter and distance of the planets from Nasa's Planetary Fact Sheet and created a fairly simple program which created spheres of the right size based on a factor of Kilometers to Blocks.

The code is on github at github.com/martinohanlon/minecraft-solarsystem or you can download the Minecraft world.

You can change the ratio of the sun and planets by changing the constant KMTOBLOCK, which is the number of kilometers per block - be careful though, the sun will be VERY big if the value is too low. You might have to increase the height of your Minecraft world too.

#Minecraft - Code a solar system
#Martin O'Hanlon
#www.stuffaboutcode.com

#import minecraft api library
import mcpi.minecraft as minecraft
import mcpi.block as block

# draw hollow sphere
def drawHollowSphere(mc, x1, y1, z1, radius, blockType, blockData=0):
    # create sphere
    for x in range(radius*-1,radius):
        for y in range(radius*-1, radius):
            for z in range(radius*-1,radius):
                if (x**2 + y**2 + z**2 < radius**2) and (x**2 + y**2 + z**2 > (radius**2 - (radius * 2))):
                    mc.setBlock(x1 + x, y1 + y, z1 +z, blockType, blockData)

# draw sphere
def drawSphere(mc, x1, y1, z1, radius, blockType, blockData=0):
    # create sphere
    for x in range(radius*-1,radius):
        for y in range(radius*-1, radius):
            for z in range(radius*-1,radius):
                if (x**2 + y**2 + z**2 < radius**2):
                    mc.setBlock(x1 + x, y1 + y, z1 +z, blockType, blockData)

#setup constants (all values in kilometers)
SUN = 1391684
#name, diameter, distance, blockId, blockData
PLANETS = (("mercury", 4879, 57900000, block.WOOL.id, 7),
           ("venus", 12104, 108200000, block.WOOL.id, 0),
           ("earth", 12756, 149600000, block.WOOL.id, 11),
           ("mars", 6792, 227900000, block.WOOL.id, 14),
           ("jupiter", 142984, 778600000, block.WOOL.id, 4),
           ("saturn", 120536, 1433500000, block.WOOL.id, 8),
           ("uranus", 51118, 2872500000, block.WOOL.id, 3),
           ("neptune", 49528, 4495100000, block.WOOL.id, 10),
           ("pluto", 2390, 5870000000, block.WOOL.id, 6))

#how many km's to a block
# change this value to have different sizes in the solar system
KMTOBLOCK = 12756.0

#middle of the minecraft sky, where the centre of the planets will be
MCMIDDLE = 75

#program
print("Minecraft Planets")
print("1 block = {} kilometers".format(KMTOBLOCK))

#connect to minecraft
mc = minecraft.Minecraft.create()

#set the middle of the solar system
pos = minecraft.Vec3(0,MCMIDDLE,0)

#create the sun
sunDiameter = round(SUN / KMTOBLOCK, 2)
sunRadius = int(round(sunDiameter / 2))
print("Sun - Diameter = {} blocks".format(sunDiameter))
drawHollowSphere(mc, pos.x, pos.y, pos.z, sunRadius, block.WOOL.id, 1)
gapToLeave = (sunDiameter / 2) + 20
pos.z = pos.z + gapToLeave

#loop through the planets
for planet in PLANETS:
    name = planet[0]
    diameter = round(planet[1] / KMTOBLOCK, 2)
    radius = int(round(diameter / 2))
    distance = round(planet[2] / KMTOBLOCK, 2)
    print("{} - Diameter = {} blocks - Distance = {} blocks".format(name, diameter, distance))
    #if the diameter is less than 1.5 draw a single block
    if diameter < 1.5:
        mc.setBlock(pos.x, pos.y, pos.z, planet[3], planet[4])
        pass
    else:
        drawSphere(mc, pos.x, pos.y, pos.z, radius, planet[3], planet[4])
        pass
    
    gapToLeave = (diameter / 2) + 20
    pos.z = pos.z + gapToLeave

#move the player to the sun
mc.player.setPos(0,0,0)

Have fun.

Wednesday, 4 February 2015

Raspberry Pi 2 - Minecraft Server

The new Raspberry Pi 2 has got twice the RAM and a load more processing power, so will it make a better Minecraft server?  The old Pi made an adequate Minecraft server providing you only had a few players and you kept the view distance low.


I tried both the vanilla server and a spigot server, both similar results, both performed reasonably well, but Spigot seemed a little more stable (but this is only based on feeling).  I was only able to test with up to 3 players but it worked well under those conditions.


Setting up your own server is pretty simple.

You will need to download either the vanilla server from Mojang or build your own spigot server jar file.

Note - The instructions below, will take you through how to create a vanilla server, if you have built spigot the only difference will be the name of the 'jar file' you put into the start.sh file

1. Make a directory for your Minecraft server

mkdir ~/MinecraftServer
cd ~/MinecraftServer

2. Download the 1.8.1 vanilla Minecraft server jar file

wget https://s3.amazonaws.com/Minecraft.Download/versions/1.8.1/minecraft_server.1.8.1.jar

3. Create a script to run the server jar file

nano start.sh

Enter the following command which will run the server

java -Xmx1024M -Xms512M -jar minecraft_server.1.8.1.jar nogui

Ctrl X to exit & save

4. Make the script executable:

chmod +x start.sh

5. Run the server

./start.sh

You should receive a message asking you to accept the EULA.



6. Accept the EULA (end user license agreement), open eula.txt

nano eula.txt

Change:

eula=false

To:

eula=true

Ctrl X to save and exit

7. Run the server

./start.sh

The first time the server runs it will take a while to start as it creates a new world.

Once you see the word "Done", the server is up and running and you should be able to connect to the server using Minecraft choosing Multiplayer, Direct Connect and entering the IP address of the Pi.


You can shutdown the server by typing the command "stop" in the command window .

If you find the server is slow, particularly when generating chunks (i.e. creating new bits of the world when you get to the edge), you could try reducing the view distance.  I reduced it from 10 to 7 and this seemed to make the server more responsive.

8. Edit view-distance in server.properties

nano server.properties

Change:

view-distance=10

To:

view-distance=7

Ctrl X to save and exit

Restart the server for the change to take effect.

Tuesday, 13 January 2015

Minecraft API - Player's Direction

One of the questions I get asked a lot about the Minecraft: Pi edition APi is "how can I get the direction the player is facing?" and I have always had to say "sorry you can't do that".

While I can't change the API for Minecraft: Pi edition I can change RaspberryJuice - so I decided to add functions to allow you to find out where the player is looking.  You can download the RaspberryJuice plugin Canarymod and Bukkit.

I have also created a new Adventures in Minecraft starterkit which includes the new version of RapsberryJuice and everything you need to use the new api functions.



The 3 new functions in the api are:
  • player.getRotation() - return the angle of rotation between 0 and 360
  • player.getPitch() - returns the angle of pitch between -90 and 90
  • player.getDirection() - returns a unit-vector of x,y,z pointing in the direction the player is facing
The functions also work with the entities as well so you can use entity.getRotation(), entity.getPitch() and entity.getDirection()

Here are the couple of code examples I demo in the video.

Get the players rotation and pitch angles:
#import the minecraft module
import mcpi.minecraft as minecraft

#create a connection to minecraft
mc = minecraft.Minecraft.create()

while True:
    #get the players rotational angle
    angle = mc.player.getRotation()
    #get the player up and down angle
    pitch = mc.player.getPitch()
    mc.postToChat(str(angle) + " : " + str(pitch))

Create a block in front of the player using getDirection():
import mcpi.minecraft as minecraft
import mcpi.block as block
import time

#how far in front of the player the block will be
BLOCKDISTANCE = 5

mc = minecraft.Minecraft.create()

while True:
    #get the position
    pos = mc.player.getPos()
    #get the direction
    direction = mc.player.getDirection()
    #calc the position of the block in front of the player
    x = round(pos.x + (direction.x * BLOCKDISTANCE))
    y = round(pos.y + (direction.y * BLOCKDISTANCE) + 1)
    z = round(pos.z + (direction.z * BLOCKDISTANCE))
    mc.setBlock(x,y,z,block.DIAMOND_BLOCK)
    time.sleep(0.1)
    mc.setBlock(x,y,z,block.AIR)

I hope you find the new api functions useful.

Tuesday, 30 December 2014

BBC iPlayer RSS Feeds - 4 million / day

When the BBC decided to turn off its iPlayer RSS feeds with no up front warning, I was annoyed, really annoyed, which isn't like me.

Why was I annoyed? I think it was the total arrogance of the "Yeah sorry you used to use them, we don't do that anymore, try this new thing", "but the new things not ready yet?", "Yeah sorry about that".

In short a fairly sizable group of people used these RSS feeds either directly or indirectly via 3rd party tools to access iPlayer content and it was the only reliable and open data method for getting information about iPlayer content.

I was interested, other than me, who else used these RSS feeds, so I made a freedom of information (FOI) request to the BBC and asked them.  It turns out for the 30 days prior to them being shutdown they were accessed 4,000,000 (yes 4 MILLION) times a day!  

The response from the BBC goes on to state that they suspect that a fair number of the downloads where from bots, yep probably, but those bots where doing so to deliver services to people and it could be that 1 bot download serviced many people.

The moral of the story is that you can't expect services to be provided forever regardless of who is providing them and how many people use them or assume that there will be a replacement.

Below is my request and subsequent response from the BBC.

Subject: FOI Request - BBC iPlayer RSS Feeds Usage
From: "Martin O'Hanlon" 
To: foi@bbc.co.uk

Dear Sir,

I am requesting information under the Freedom of Information act about the
usage of BBC iPlayer RSS feeds.

On (or around) the 29th October, access to the BBC iPlayer RSS Feeds was
removed (http://iplayerhelp.external.bbc.co.uk/tv/feeds).

Could you provide information relating to the use of the RSS Feeds prior to
them being removed.

By month, for the 12 months previous could you state the number of access
requests for the RSS feeds supplied under http://feeds.bbc.co.uk/iplayer/.

If you are unable to provide 12 months of data by month, could you provide
the information for the last 30 days.

Kind regards

Martin O'Hanlon

-------------------------------

From: FOI Enquiries <FOIEnquiries@bbc.co.uk>
To: "'Martin O'Hanlon'" 
Subject: Response to your request for information - RFI20141782
Date: Fri, 28 Nov 2014 14:49:53 +0000

Dear Mr O'Hanlon

Please find attached the response to your request for information, referenc=
e RFI20141782.

Kind regards

BBC Information Policy and Compliance
BC2 B6, 201 Wood Lane, London W12 7TP

You can download the attached from here, or view the contents below:

Martin O'Hanlon
Via email: martin@ohanlonweb.com

28th November 2014

Dear Martin,

Freedom of Information Act 2000 – RFI20141782

Thank you for your request under the Freedom of Information Act (‘the Act’) of 30th
October 2014, seeking:

“I am requesting information under the Freedom of Information act about the usage of BBC iPlayer
RSS feeds.

On (or around) the 29th October, access to the BBC iPlayer RSS Feeds was removed
(http://iplayerhelp.external.bbc.co.uk/tv/feeds).

Could you provide information relating to the use of the RSS Feeds prior to them being removed.
By month, for the 12 months previous could you state the number of access requests for the RSS
feeds supplied under http://feeds.bbc.co.uk/iplayer/.

If you are unable to provide 12 months of data by month, could you provide the information for the
last 30 days.”

I estimate that to deal with your request for 12 months’ worth of data, given the amount of
data this involves, would take more than two and a half days; under section 12 of the Act, we
are allowed to refuse to handle the request if it would exceed the appropriate limit. The
appropriate limit has been set by the Regulations (SI 2004/3244) as being £450 (equivalent to
two and a half days work, at an hourly rate of £25).

With regard to the 30 days’ worth information, the following is the total number of requests
for urls under http://feeds.bbc.co.uk/iplayer which relates to iPlayer RSS feeds (date followed
by the total):

28/09/2014 - 4139102
29/09/2014 - 3969429
30/09/2014 - 3688324
01/10/2014 - 3884073
02/10/2014 - 3883081
03/10/2014 - 3925662
04/10/2014 - 4159130
05/10/2014 - 4222500
06/10/2014 - 4131642
07/10/2014 - 3985815
08/10/2014 - 4012385
09/10/2014 - 3915717
10/10/2014 - 3882014
11/10/2014 - 4048638
12/10/2014 - 4208782
13/10/2014 - 4116161
14/10/2014 - 3970894
15/10/2014 - 4140721
16/10/2014 - 3840215
17/10/2014 - 3929542
18/10/2014 - 4183741
19/10/2014 - 4298197
20/10/2014 - 4059930
21/10/2014 - 4046123
22/10/2014 - 3941945
23/10/2014 - 3922209
24/10/2014 - 3962244
25/10/2014 - 4070949
26/10/2014 - 4307425
27/10/2014 - 4074942
28/10/2014 - 4050387

Please note that the data above does not give any indication of what was making the request
i.e. whether human or bot (a software application which runs automated tasks over the
internet). The rather flat level probably indicates that there was a very large amount of
automated processing going on, so this should not be confused with actual users doing
something with the information in the feeds.

You may request an internal review of our decision that your request exceeds the
appropriate limit. Please contact us at the address above, explaining what you would like us to
review and including your reference number. If you are not satisfied with the internal review,
you can appeal to the Information Commissioner. The contact details are: Information
Commissioner's Office, Wycliffe House, Water Lane, Wilmslow, Cheshire, SK9 5AF, Tel:
0303 123 1113 (local rate) or 01625 545 745 (national rate) or see http://www.ico.gov.uk/

Yours sincerely,

Kate Leece
Head of Legal and Business Affairs
BBC Future Media