#!/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