So I had mentioned that I would make a program that allows you to run things separately from Scratch. As an example, you can get the system time with this.
The Python code:
#! /usr/env/python
# Block Extensions
# By: Magnie
# GPLv3
instruct = """
Instructions:
1. Start up Scratch and enable Remote Sensor Connections
2. Run be.py (with Python)
3. In Scratch, create a variable named 'be' then set it to 'time'
then run it.
4. Drag out a sensor value block from the sensing section. Click the
drop-down menu and select 'be-result'. Click the block once, and
it should display the time (Hour:Minute:Second).
You can do 3 with the broadcast 'be: time' and get the same results
for number 4.
"""
from array import array
import socket
import time
class ControlBase(object):
"""
Deals with all the new messages.
"""
def __init__(self, host="127.0.0.1", port=42001):
self.ext = Extensions()
self.link = Link(host, port, ext=self)
self.link.run()
def new_message(self, data):
for msg in data['sensor-update']:
self.execute(msg, data['sensor-update'][msg])
for msg in data['broadcast']:
if 'be:' in msg:
self.execute('be', msg[4:])
def execute(self, name, value):
if name != 'be':
return
message = value
message = message.split(' ')
block = message[0]
if len(message) > 0:
args = message[1:]
else:
args = None
result = self.ext.run_block(block, args)
self.link.send(result)
class Extensions(object):
"""
The "holder" for the blocks and their functions.
To create a block, you must do the following:
a) Code a function. 'time' in this example:
def time(self, format_='%H:%M:%S'):
return time.strftime(format_)
b) Create an if statement in the run_block function that runs
your function and returns the result.
elif block == 'time':
args = (args or ['%H:%M:%S'])
return self.time(args[0])
c) Add the block "command" to the list of blocks in self.blocks
('time' in this example)
"""
def __init__(self):
pass
def run_block(self, block, args):
if block == 'echo':
return 'echo'
elif block == 'time':
args = (args or ['%H:%M:%S'])
return self.time(args[0])
elif block == 'help':
return self.instruct()
return '!No such block?'
def time(self, format_='%H:%M:%S'):
return time.strftime(format_)
def instruct(self):
return instruct
class Link(object):
"""
The connection between Scratch and the extension.
"""
def __init__(self, host="127.0.0.1", port=42001, buffer_=1024, ext=''):
location = (host, port)
self.buffer_ = buffer_
self.ext = ext
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect(location)
self.running = 0
def run(self):
self.running = 1
while self.running:
try:
data = self.sock.recv(self.buffer_)
data = self.parse_message(data)
self.ext.new_message(data)
except Exception, e:
print str(e)
self.running = 0
continue
def parse_message(self, message):
# This pareses the message to make it easier to handle.
if not message:
return None
sensors = {}
broadcasts = []
commands = []
i = 0
while True:
# Figure out the length and each separate message.
# Kind of messy and unreadable..
length = message[i:i + 4]
length = array("I", length)[0]
command = message[i + 4:i + length + 4]
commands.append(command)
if (i + length + 4) < len(message):
i = (i+4) + length
else:
del command
break
for command in commands:
# See if the command is a broadcast or sensor-update.
if command[0] == 'b':
command = command.split('"')
command.pop(0)
command = '"'.join(command[0:])
broadcasts.append(command[:-1])
elif command[0] == 's':
command = command[15:]
command = command.split('" "', 1)
name = command[0][0:]
value = '" "'.join(command[1:])[:-2]
sensors[name] = value
# Return in programmer-friendly format.
return dict([('sensor-update', sensors),
('broadcast', broadcasts)])
def give_length(self, cmd):
# This defines the length of the message.
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
return (a.tostring() + cmd)
def send(self, message):
message = 'sensor-update "be-result" "{0}"'.format(message)
message = self.give_length(message)
self.sock.send(message)
if __name__ == '__main__':
# Wouldn't want to ruin someone's program, now would we?
base = ControlBase()The instructions are at the top of the code (I don't think you could really miss it). This can be used to run functions that would normally be too complicated for Scratch.
Any suggestions, thoughts?
Offline
This is really cool!
EDIT: I remember making a project involving the Scratch OSC Bridge and it allowed me to control the project with my iOS device. The only reason I bring that up is because actions in this are being done remotely also.
Last edited by chanmanpartyman (2012-06-13 14:35:27)
Offline