first commit
This commit is contained in:
commit
a5a0434432
1126 changed files with 439481 additions and 0 deletions
400
Software/Scratch/GrovePiScratch.py
Executable file
400
Software/Scratch/GrovePiScratch.py
Executable file
|
|
@ -0,0 +1,400 @@
|
|||
#!/usr/bin/python
|
||||
###############################################################################################################
|
||||
# This library is for using the GrovePi with Scratch
|
||||
# http://www.dexterindustries.com/GrovePi/
|
||||
# History
|
||||
# ------------------------------------------------
|
||||
# Author Date Comments
|
||||
# Karan 29 June 15 Initial Authoring
|
||||
# John 22 Feb 16 Adding GrovePi Barometer
|
||||
# Nicole Nov 16 Added Folder support for take_picture
|
||||
# Nicole Nov 16 Added eSpeak Support
|
||||
# Nicole 18 Nov 16 Adding PivotPi support
|
||||
# SimonW 22 Mar 18 Bug fix in error handling line 383
|
||||
'''
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
|
||||
Copyright (C) 2016 Dexter Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
'''
|
||||
'''
|
||||
#
|
||||
# Based on the BrickPi Scratch Library written by Jaikrishna
|
||||
#
|
||||
# The Python program acts as the Bridge between Scratch & GrovePi and must be running for the Scratch program to run.
|
||||
##############################################################################################################
|
||||
'''
|
||||
import scratch,sys,threading,math
|
||||
import grovepi
|
||||
import time
|
||||
import os # to handle folder paths
|
||||
|
||||
try:
|
||||
sys.path.insert(0, '/home/pi/Dexter/PivotPi/Software/Scratch/')
|
||||
import PivotPiScratch
|
||||
pivotpi_available=True
|
||||
except:
|
||||
pivotpi_available=False
|
||||
|
||||
# Folders where pictures get saved
|
||||
defaultCameraFolder="/home/pi/Desktop/"
|
||||
cameraFolder = defaultCameraFolder
|
||||
|
||||
|
||||
# Pi user ID Number - used for setting permissions
|
||||
pi_user=1000
|
||||
pi_group=1000
|
||||
|
||||
# used is GrovePi is actually connected - allows for testing without a GrovePi
|
||||
en_grovepi=1
|
||||
# print debugging statements
|
||||
en_debug=1
|
||||
|
||||
try:
|
||||
s = scratch.Scratch()
|
||||
if s.connected:
|
||||
print "GrovePi Scratch: Connected to Scratch successfully"
|
||||
#else:
|
||||
#sys.exit(0)
|
||||
except scratch.ScratchError:
|
||||
print "GrovePi Scratch: Scratch is either not opened or remote sensor connections aren't enabled"
|
||||
#sys.exit(0)
|
||||
|
||||
class myThread (threading.Thread):
|
||||
def __init__(self, threadID, name, counter):
|
||||
threading.Thread.__init__(self)
|
||||
self.threadID = threadID
|
||||
self.name = name
|
||||
self.counter = counter
|
||||
def run(self):
|
||||
while running:
|
||||
time.sleep(.2) # sleep for 200 ms
|
||||
|
||||
thread1 = myThread(1, "Thread-1", 1) #Setup and start the thread
|
||||
thread1.setDaemon(True)
|
||||
|
||||
analog_sensors=['analogRead','rotary','sound','light','moisture']
|
||||
digitalInp=['button']
|
||||
digitalOp=['led','relay']
|
||||
pwm=['LEDPower','buzzer','analogWrite']
|
||||
|
||||
def match_sensors(msg,lst):
|
||||
for i,e in enumerate(lst):
|
||||
if msg[:len(e)].lower()==e.lower():
|
||||
return i
|
||||
return -1
|
||||
|
||||
try:
|
||||
s.broadcast('READY')
|
||||
except NameError:
|
||||
print "GrovePi Scratch: Unable to Broadcast"
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
m = s.receive()
|
||||
|
||||
while m==None or m[0] == 'sensor-update':
|
||||
m = s.receive()
|
||||
|
||||
originalmsg = m[1]
|
||||
|
||||
# change input to all lowercase.
|
||||
# Users can enter any which way they want
|
||||
msg = originalmsg.lower()
|
||||
if en_debug:
|
||||
print "Rx:",originalmsg
|
||||
|
||||
if msg == 'SETUP'.lower() :
|
||||
print "Setting up sensors done"
|
||||
elif msg == 'START'.lower() :
|
||||
running = True
|
||||
if thread1.is_alive() == False:
|
||||
thread1.start()
|
||||
print "Service Started"
|
||||
|
||||
# ANALOG SENSORS
|
||||
elif match_sensors(msg,analog_sensors) >=0:
|
||||
if en_grovepi:
|
||||
s_no=match_sensors(msg,analog_sensors)
|
||||
sens=analog_sensors[s_no]
|
||||
port=int(msg[len(sens):])
|
||||
a_read=grovepi.analogRead(port)
|
||||
s.sensorupdate({sens:a_read})
|
||||
|
||||
if en_debug:
|
||||
print msg
|
||||
print sens +'op:'+ str(a_read)
|
||||
|
||||
elif msg[:8].lower()=="setInput".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[8:])
|
||||
grovepi.pinMode(port,"INPUT")
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif msg[:9].lower()=="setOutput".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[9:])
|
||||
grovepi.pinMode(port,"OUTPUT")
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif msg[:11].lower()=="digitalRead".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[11:])
|
||||
grovepi.pinMode(port,"INPUT")
|
||||
d_read=grovepi.digitalRead(port)
|
||||
s.sensorupdate({'digitalRead':d_read})
|
||||
if en_debug:
|
||||
print msg
|
||||
print "Digital Reading: " + str(d_read)
|
||||
|
||||
elif match_sensors(msg,digitalInp) >=0:
|
||||
if en_grovepi:
|
||||
s_no=match_sensors(msg,digitalInp)
|
||||
sens=digitalInp[s_no]
|
||||
port=int(msg[len(sens):])
|
||||
sens += str(port)
|
||||
grovepi.pinMode(port,"INPUT")
|
||||
d_read=grovepi.digitalRead(port)
|
||||
s.sensorupdate({sens:d_read})
|
||||
if en_debug:
|
||||
print msg,
|
||||
print sens +' output:'+ str(d_read)
|
||||
|
||||
elif msg[:16].lower()=="digitalWriteHigh".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[16:])
|
||||
grovepi.pinMode(port,"OUTPUT")
|
||||
grovepi.digitalWrite(port,1)
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif msg[:15].lower()=="digitalWriteLow".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[15:])
|
||||
grovepi.pinMode(port,"OUTPUT")
|
||||
grovepi.digitalWrite(port,0)
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif match_sensors(msg,pwm) >=0:
|
||||
if en_grovepi:
|
||||
s_no=match_sensors(msg,pwm)
|
||||
sens=pwm[s_no]
|
||||
l=len(sens)
|
||||
port=int(msg[l:l+1])
|
||||
power=int(msg[l+1:])
|
||||
grovepi.pinMode(port,"OUTPUT")
|
||||
grovepi.analogWrite(port,power)
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif match_sensors(msg,digitalOp) >=0:
|
||||
if en_grovepi:
|
||||
s_no=match_sensors(msg,digitalOp)
|
||||
sens=digitalOp[s_no]
|
||||
l=len(sens)
|
||||
port=int(msg[l:l+1])
|
||||
state=msg[l+1:]
|
||||
grovepi.pinMode(port,"OUTPUT")
|
||||
if state=='on':
|
||||
grovepi.digitalWrite(port,1)
|
||||
else:
|
||||
grovepi.digitalWrite(port,0)
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
elif msg[:4].lower()=="temp".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[4:])
|
||||
[temp,humidity] = grovepi.dht(port,0)
|
||||
s.sensorupdate({'temp':temp})
|
||||
if en_debug:
|
||||
print msg
|
||||
print "temp: ",temp
|
||||
|
||||
elif msg[:8].lower()=="humidity".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[8:])
|
||||
[temp,humidity] = grovepi.dht(port,0)
|
||||
s.sensorupdate({'humidity':humidity})
|
||||
if en_debug:
|
||||
print msg
|
||||
print "humidity:",humidity
|
||||
|
||||
elif msg[:8].lower()=="distance".lower():
|
||||
if en_grovepi:
|
||||
port=int(msg[8:])
|
||||
dist=grovepi.ultrasonicRead(port)
|
||||
s.sensorupdate({'distance':dist})
|
||||
if en_debug:
|
||||
print msg
|
||||
print "distance=",dist
|
||||
|
||||
elif msg[:3].lower()=="lcd".lower():
|
||||
if en_grovepi:
|
||||
if en_debug:
|
||||
print msg[:3], msg[3:6], originalmsg[6:]
|
||||
|
||||
sys.path.insert(0, '/home/pi/Dexter/GrovePi/Software/Python/grove_rgb_lcd')
|
||||
import grove_rgb_lcd
|
||||
if msg[3:6].lower() == "col".lower(): #lower() added just for consistency. Not really needed
|
||||
rgb = []
|
||||
for i in range(0,6,2):
|
||||
rgb.append(int(msg[6:][i:i+2],16)) # convert from one hex string to three ints
|
||||
if en_debug:
|
||||
print "colours are:",rgb[0],rgb[1],rgb[2]
|
||||
grove_rgb_lcd.setRGB(rgb[0],rgb[1],rgb[2])
|
||||
elif msg[3:6].lower() == "txt".lower():
|
||||
txt = originalmsg[6:]
|
||||
grove_rgb_lcd.setText_norefresh(txt)
|
||||
else:
|
||||
pass
|
||||
if en_debug:
|
||||
print msg
|
||||
|
||||
# elif msg[:10].lower()=="setOutput".lower():
|
||||
# if en_grovepi:
|
||||
# port=int(msg[10:])
|
||||
# a_read=grovepi.analogRead(port)
|
||||
# s.sensorupdate({'analogRead':a_read})
|
||||
# if en_debug:
|
||||
# print msg
|
||||
# print "Analog Reading: " + str(a_read)
|
||||
elif msg.lower()=="READ_IR".lower() or msg.lower()=="IR".lower():
|
||||
print "READ_IR!"
|
||||
if en_ir_sensor==0:
|
||||
import lirc
|
||||
sockid = lirc.init("keyes", blocking = False)
|
||||
en_ir_sensor=1
|
||||
try:
|
||||
read_ir= lirc.nextcode() # press 1
|
||||
if len(read_ir) !=0:
|
||||
print read_ir[0]
|
||||
except:
|
||||
if en_debug:
|
||||
e = sys.exc_info()[1]
|
||||
print "Error reading IR sensor: " + str(read_ir)
|
||||
if en_debug:
|
||||
print "IR Recv Reading: " + str(read_ir)
|
||||
if en_gpg:
|
||||
if len(read_ir) !=0:
|
||||
s.sensorupdate({'read_ir':read_ir[0]})
|
||||
else:
|
||||
s.sensorupdate({'read_ir':""})
|
||||
# CREATE FOLDER TO SAVE PHOTOS IN
|
||||
|
||||
elif msg[:6].lower()=="FOLDER".lower():
|
||||
print "Camera folder"
|
||||
try:
|
||||
cameraFolder=defaultCameraFolder+str(msg[6:])
|
||||
if not os.path.exists(cameraFolder):
|
||||
os.makedirs(cameraFolder)
|
||||
os.chown(cameraFolder,pi_user,pi_group)
|
||||
s.sensorupdate({"folder":"created"})
|
||||
else:
|
||||
s.sensorupdate({"folder":"set"})
|
||||
except:
|
||||
print "error with folder name"
|
||||
|
||||
elif msg.lower()=="TAKE_PICTURE".lower():
|
||||
print "TAKE_PICTURE!"
|
||||
try:
|
||||
from subprocess import call
|
||||
import datetime
|
||||
newimage = "{}/img_{}.jpg".format(cameraFolder,str(datetime.datetime.now()).replace(" ","_",10).replace(":","_",10))
|
||||
photo_cmd="raspistill -o {} -w 640 -h 480 -t 1".format(newimage)
|
||||
print photo_cmd
|
||||
call ([photo_cmd], shell=True)
|
||||
os.chown(newimage,pi_user,pi_group)
|
||||
print "Picture Taken"
|
||||
except:
|
||||
if en_debug:
|
||||
e = sys.exc_info()[1]
|
||||
print "Error taking picture",e
|
||||
s.sensorupdate({'camera':"Error"})
|
||||
s.sensorupdate({'camera':"Picture Taken"})
|
||||
|
||||
# Barometer code, pressure
|
||||
elif msg[:9].lower()=="pressure".lower():
|
||||
if en_grovepi:
|
||||
# We import here to prevent errors thrown. If the import fails, you just get an error message instead of the communicator crashing.
|
||||
# If user is using multiple sensors and using their own image which does not have the pythonpath set correctly then
|
||||
# they'll just not get the output for 1 sensor, and the others will still keep working
|
||||
from grove_i2c_barometic_sensor_BMP180 import BMP085 # Barometric pressure sensor.
|
||||
bmp = BMP085(0x77, 1) #Initialize the pressure sensor (barometer)
|
||||
press = bmp.readPressure()/100.0
|
||||
s.sensorupdate({'pressure':press})
|
||||
if en_debug:
|
||||
print "Pressure: " + str(press)
|
||||
if en_debug: # If Debug is enabled, print the value of msg.
|
||||
print msg
|
||||
|
||||
elif (msg[:5].lower()=="SPEAK".lower() or msg[:3].lower()=="SAY".lower() ):
|
||||
try:
|
||||
if en_grovepi:
|
||||
from subprocess import call
|
||||
cmd_beg = "espeak-ng -ven+f1 "
|
||||
in_text = msg[len("SPEAK"):]
|
||||
cmd_end = " 2>/dev/null"
|
||||
|
||||
call([cmd_beg+"\""+in_text+"\""+cmd_end], shell=True)
|
||||
if en_debug:
|
||||
print(msg)
|
||||
except:
|
||||
print("Issue with espeak")
|
||||
|
||||
# PIVOTPI
|
||||
elif pivotpi_available==True and PivotPiScratch.isPivotPiMsg(msg):
|
||||
pivotsensors = PivotPiScratch.handlePivotPi(msg)
|
||||
# print "Back from PivotPi",pivotsensors
|
||||
s.sensorupdate(pivotsensors)
|
||||
|
||||
else:
|
||||
if en_debug:
|
||||
print "Ignoring: ",msg
|
||||
|
||||
|
||||
|
||||
except KeyboardInterrupt:
|
||||
running= False
|
||||
print "GrovePi Scratch: Disconnected from Scratch"
|
||||
break
|
||||
except (scratch.ScratchConnectionError,NameError) as e: #bug fix simonw 22Mar18
|
||||
while True:
|
||||
#thread1.join(0)
|
||||
print "GrovePi Scratch: Scratch connection error, Retrying"
|
||||
# print e
|
||||
time.sleep(5)
|
||||
try:
|
||||
s = scratch.Scratch()
|
||||
s.broadcast('READY')
|
||||
print "GrovePi Scratch: Connected to Scratch successfully"
|
||||
break;
|
||||
except scratch.ScratchError:
|
||||
print "GrovePi Scratch: Scratch is either not opened or remote sensor connections aren't enabled\n..............................\n"
|
||||
except:
|
||||
e = sys.exc_info()[0]
|
||||
print "GrovePi Scratch: Error %s" % e
|
||||
Loading…
Add table
Add a link
Reference in a new issue