Discuss Scratch

joncassidy
Scratcher
1 post

Mesh server for raspberry pi - control Pi GPIO remotely

I run a raspberry pi without a display or keyboard, and access it from a laptop. Mostly I'm playing with it to see what it will do, so this seems fine.

I like Scratch, but I want to interact with the real world more. I can run X remotely, but here's another approach, using the scratch mesh function to send commands to a (small) python listener on the raspberry pi, and switching LEDs on and off from scratch. I think it's a good way to show children about controlling the real world.

This needs:
  1. Scratch 1.4, set up to use the mesh function. Very quick to do for any scratch - instructions at
    http://wiki.scratch.mit.edu/wiki/Mesh#Mesh_by_Modification_of_Scratch. Unfortunately not available for Scratch 2.0
  2. A raspberry pi, and something connected to the GPIO pins. I used a berryclip, because they are cheap and simple, but you do have to solder them yourself.
  3. The wiringPi library
  4. A little bit of python script running on the pi. I started with the one at http://archive.scratch.mit.edu/forums/viewtopic.php?id=95283, and extended it to control the GPIO pins, as below. I would have liked to just add this to that posting, as it;s a great piece of work, but the forums are closed.
You can then:
  1. Run the python as superuser (“sudo python meshServer.py”)
  2. Connect to it by joining the mesh session from another computer running scratch (as at the mesh link above, by Shift-clicking on the Share menu)
  3. Broadcast commands like ‘pin 7 on’ to switch pin 7 on. Currently set up for the berryclip as above. Next I'll make it more generic, but don't be afraid of changing the python - I don't know python either!
It's a bit rough at the moment, but enough to do traffic lights with my kids.

Code: (Save as meshServer.py on the pi):
#!/usr/bin/env python
import select
import socket
import sys
import threading
import RPi.GPIO as GPIO
import pdb
import struct

class Server:
def __init__(self):
self.host = ''
self.port = 42001
self.backlog = 5
self.size = 1024
self.server = None
self.threads = []
GPIO.setmode(GPIO.BOARD)

def open_socket(self):
try:
self.server = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
self.server.bind((self.host,self.port))
self.server.listen(5)
except socket.error, (value,message):
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)

def run(self):
self.open_socket()
input = [self.server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == self.server:
# handle the server socket
c = Client(self.server.accept())
c.start()
self.threads.append(c)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
print("Just set running to 0")

# close all threads
self.server.close()
for c in self.threads:
c.join()

class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
def processMessage(self, message):
if (message == 'broadcast kill'): running = 0
# broadcasts = pinX output. X=number, output = on or off
message=message.replace('\"','')
if message[0:9] == 'broadcast':
messageParts = message[11:].split()
pinNumber = int(messageParts[1])
#pdb.set_trace()
if (messageParts[2] == "on") | (messageParts[2] == "1"):
pinSetting = GPIO.HIGH
else:
pinSetting = GPIO.LOW
print("Pin:" + str(pinNumber) + "to:" + str(pinSetting))
GPIO.output(pinNumber, pinSetting)

def run(self):
running = 1
GPIO.setup(7, GPIO.OUT) # Red 1
GPIO.setup(11, GPIO.OUT) # Yellow 1
GPIO.setup(15, GPIO.OUT) # Green 1
GPIO.setup(19, GPIO.OUT) # Red 2
GPIO.setup(21, GPIO.OUT) # Yellow 2
GPIO.setup(23, GPIO.OUT) # Green 2
GPIO.setup(26, GPIO.IN) # Push Button
while running:
try:
data = self.client.recv(self.size)
except KeyboardInterrupt:
running = 0
except Exception, e:
self.log(str(e))
data = ''
if data:
for user in s.threads:
try:
pointer = 0
while pointer < len(data):
messageLength = struct.unpack(">l",data[pointer:pointer+4])[0]
thisMessage = data[pointer+4:pointer+4+messageLength]
pointer += messageLength + 4
self.processMessage(thisMessage)
except KeyboardInterrupt:
running = 0
except Exception, e:
self.log(str(e))
GPIO.cleanup()
self.client.close()
running = 0

def log(self, string):
try:
log_file = open("mesh.log", 'a')
log_file.write('\n' + string)
log_file.close()
except IOError, e:
log_file = open("mesh.log", 'w')
log_file.write(string)
log_file.close()

if __name__ == "__main__":
s = Server()
s.daemon = True
s.run()

Last edited by joncassidy (Oct. 24, 2013 20:56:35)

Magnie
Scratcher
100+ posts

Mesh server for raspberry pi - control Pi GPIO remotely

That's brilliant! You should probably ask for this to be moved to Advanced Topics, it'll be more at home there. You should also put the code inside [code] tags so it's easier to read on the site.

Powered by DjangoBB