Unfortunately ControlMyPi will be shutting down on September 1st due to Google removing support for XMPP :(
Since I first wrote ControlMyPi many well supported IoT platforms have come about. Most of these use MQTT for the messaging where ControlMyPi was using XMPP.
I would suggest you take a look at the IoT systems provided by Adafruit and AWS. Here’s a tutorial I wrote for Adafruit:
Monitor PiCam and temperature on a PiTFT via adafruit.io
There are many many more on the Adafruit learning system.
Head of Development, Software Architect and Developer by day. Data Science and Raspberry Pi dabbler by night.
2017-05-06
2015-06-14
Motion Google Drive Uploader for OAuth 2.0
Three years ago I wrote the original script to upload video to Google Drive as a trigger from Motion. Unfortunately Google recently removed support for the old security model and you now have to use OAuth 2.0. Also the gdata libraries have been superseded by the Google API Python Client. A few people have written alternatives to my original script quicker than I did, but here's my new version.
Note: I'm not using any third party libraries like PyDrive for example, this script goes straight to the Google APIs. (PyDrive has not been touched for a long time by its author and is missing features).
Motion Google Drive Uploader on Github
Note: I'm not using any third party libraries like PyDrive for example, this script goes straight to the Google APIs. (PyDrive has not been touched for a long time by its author and is missing features).
Motion Google Drive Uploader on Github
Installation
Google setup:
- Go to https://code.google.com/apis/console - make sure you're logged in as the correct user for the Drive you want to use.
- Use the drop-down at the top of the page to create a project called 'Uploader'.
- Click on "Enable an API" then "Drive API" and then click the "Enable API" button
- Next go to "APIs & auth -> Credentials" menu and click "Create new Client ID".
- Set Application type to "Installed application" and click "Configure Consent Screen"
- Set the Product Name to "Uploader"
- You'll be returned back to the dialog. Make sure "Installed application" and "other" are selected and then click "Create Client ID".
- Download the JSON file.
- Rename it to client_secrets.json and put it somewhere like /home/pi/.
Script setup:
- Go to /home/pi/ and get the uploader.py from github: git clone https://github.com/jerbly/motion-uploader.git
- Update/install Google Python API: sudo pip install --upgrade google-api-python-client
- Make uploader.py executable: chmod a+x uploader.py
Configuration:
- If you used the git clone command you'll find the example uploader.cfg file in the motion-uploader directory. This now has a couple more options which need setting up.
- oauth/folder - set this to the directory where you have put the client_secrets.json file and where the script can write a credentials. e.g. /home/pi/
- docs/snapshot-folder - set this to a public folder name in your drive if you wish to use this feature (explained below).
Initial authentication:
- From the command line run the script by hand with your config file and a test avi file e.g. ./uploader.py /home/pi/uploader.cfg /home/pi/test.avi
- Copy the URL to your clipboard and paste it into a browser where you are already logged in to Google as the correct user.
- Accept and copy the authentication code to the clipboard.
- Paste it back in to the command line and hit enter.
- This will authenticate you and create a credentials file which will be used for future logins.
Now, finally, you can run up Motion and it should work like it used to.
New feature: Public Snapshot
Motion comes with a feature to periodically take a snapshot regardless of whether motion has been detected. This is a nice feature if you want to have a web site with the latest view from your webcam. You can use Google Drive to host this image rather than installing a web server on your Pi and opening firewalls etc.
- Create a public folder in your Google Drive:
- Create a new folder called 'public'
- Double click on it
- Go to the sharing menu (person icon with + sign)
- Click "Advanced" and then "Change..."
- Set it to "On - Public on the Web"
- Configure your uploader.cfg so docs/snapshot-folder is set to this folder 'public'.
- Configure motion.conf to take a snapshot every n seconds named lastsnap.jpg and upload it:
- snapshot_interval 300
- snapshot_filename lastsnap
- on_picture_save /home/pi/motion-uploader/uploader.py /home/pi/uploader.cfg %f snap
To find the public URL that you can bookmark and embed in other pages run the command line with the 'snapurl' option: ./uploader.py /home/pi/uploader.cfg /home/pi/lastsnap.jpg snapurl
It will print something like this: https://googledrive.com/host/{your-folder-id-here}/lastsnap.jpg
Labels:
google drive,
motion,
python,
raspberry pi
2014-09-01
Raspberry Pi Pygame UI basics
Stage 1 setup
- Follow Adafruit instructions for PiTFT
- Get the tutorial code: git clone https://github.com/jerbly/tutorials.git
Test the setup
pi@raspberrypi ~ $ sudo python Python 2.7.3 (default, Mar 18 2014, 05:13:23) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import pygame >>> import os >>> os.putenv('SDL_FBDEV', '/dev/fb1') >>> pygame.init() (6, 0) >>> lcd = pygame.display.set_mode((320, 240)) >>> lcd.fill((255,0,0)) <rect(0, 0, 320, 240)> >>> pygame.display.update() >>> pygame.mouse.set_visible(False) 1 >>> lcd.fill((0,0,0)) <rect(0, 0, 320, 240)> >>> pygame.display.update()You can also run this test (with a one second sleep) from the pygamelcd project: sudo python test1.py
From GPIO to screen
So, we can paint colours on the screen - let's do this from GPIs!
We'll use the four tactile buttons along the bottom of the screen to draw the GPIO number and a coloured background. From left to right the buttons correspond to GPIO #23, #22, #27, and #18.
(Note: If you have a revision 1 board then #27 is #21 - you'll just have to change the code a little)
We'll use the four tactile buttons along the bottom of the screen to draw the GPIO number and a coloured background. From left to right the buttons correspond to GPIO #23, #22, #27, and #18.
(Note: If you have a revision 1 board then #27 is #21 - you'll just have to change the code a little)
import pygame import os from time import sleep import RPi.GPIO as GPIO #Note #21 changed to #27 for rev2 Pi button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 18:(0,0,0)} #Setup the GPIOs as inputs with Pull Ups since the buttons are connected to GND GPIO.setmode(GPIO.BCM) for k in button_map.keys(): GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Colours WHITE = (255,255,255) os.putenv('SDL_FBDEV', '/dev/fb1') pygame.init() pygame.mouse.set_visible(False) lcd = pygame.display.set_mode((320, 240)) lcd.fill((0,0,0)) pygame.display.update() font_big = pygame.font.Font(None, 100) while True: # Scan the buttons for (k,v) in button_map.items(): if GPIO.input(k) == False: lcd.fill(v) text_surface = font_big.render('%d'%k, True, WHITE) rect = text_surface.get_rect(center=(160,120)) lcd.blit(text_surface, rect) pygame.display.update() sleep(0.1)
You can also run this from the pygamelcd project: sudo python test2.py
From screen to GPIO
With the PiTFT installed and the 4 tactile buttons there aren't many GPIs left on the model B Raspberry Pi. So wire up #17 and #4. The software renders 4 labels on the screen and then looks for mouse events in the four quarters:
import pygame from pygame.locals import * import os from time import sleep import RPi.GPIO as GPIO #Setup the GPIOs as outputs - only 4 and 17 are available GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.setup(17, GPIO.OUT) #Colours WHITE = (255,255,255) os.putenv('SDL_FBDEV', '/dev/fb1') os.putenv('SDL_MOUSEDRV', 'TSLIB') os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') pygame.init() pygame.mouse.set_visible(False) lcd = pygame.display.set_mode((320, 240)) lcd.fill((0,0,0)) pygame.display.update() font_big = pygame.font.Font(None, 50) touch_buttons = {'17 on':(80,60), '4 on':(240,60), '17 off':(80,180), '4 off':(240,180)} for k,v in touch_buttons.items(): text_surface = font_big.render('%s'%k, True, WHITE) rect = text_surface.get_rect(center=v) lcd.blit(text_surface, rect) pygame.display.update() while True: # Scan touchscreen events for event in pygame.event.get(): if(event.type is MOUSEBUTTONDOWN): pos = pygame.mouse.get_pos() print pos elif(event.type is MOUSEBUTTONUP): pos = pygame.mouse.get_pos() print pos #Find which quarter of the screen we're in x,y = pos if y < 120: if x < 160: GPIO.output(17, False) else: GPIO.output(4, False) else: if x < 160: GPIO.output(17, True) else: GPIO.output(4, True) sleep(0.1)
Stage 2 setup
We're now going to improve the UI by introducing a widget framework PygameUI.
1. Update your version of distribute: sudo easy_install -U distribute
2. Install PygameUI: sudo pip install pygameui
PygameUI GPIOs

The widget rendering and touchscreen events are handled by PygameUI. The PiTft class defines the buttons to draw on screen and the click event to be fired when a button is pressed.
import pygame import os import pygameui as ui import logging import RPi.GPIO as GPIO #Setup the GPIOs as outputs - only 4 and 17 are available GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.setup(17, GPIO.OUT) log_format = '%(asctime)-6s: %(name)s - %(levelname)s - %(message)s' console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter(log_format)) logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(console_handler) os.putenv('SDL_FBDEV', '/dev/fb1') os.putenv('SDL_MOUSEDRV', 'TSLIB') os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') MARGIN = 20 class PiTft(ui.Scene): def __init__(self): ui.Scene.__init__(self) self.on17_button = ui.Button(ui.Rect(MARGIN, MARGIN, 130, 90), '17 on') self.on17_button.on_clicked.connect(self.gpi_button) self.add_child(self.on17_button) self.on4_button = ui.Button(ui.Rect(170, MARGIN, 130, 90), '4 on') self.on4_button.on_clicked.connect(self.gpi_button) self.add_child(self.on4_button) self.off17_button = ui.Button(ui.Rect(MARGIN, 130, 130, 90), '17 off') self.off17_button.on_clicked.connect(self.gpi_button) self.add_child(self.off17_button) self.off4_button = ui.Button(ui.Rect(170, 130, 130, 90), '4 off') self.off4_button.on_clicked.connect(self.gpi_button) self.add_child(self.off4_button) def gpi_button(self, btn, mbtn): logger.info(btn.text) if btn.text == '17 on': GPIO.output(17, False) elif btn.text == '4 on': GPIO.output(4, False) elif btn.text == '17 off': GPIO.output(17, True) elif btn.text == '4 off': GPIO.output(4, True) ui.init('Raspberry Pi UI', (320, 240)) pygame.mouse.set_visible(False) ui.scene.push(PiTft()) ui.run()
Analog input

Get the Adafruit Python library: git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git
If you need to enable i2c follow this guide: Configuring I2C
A few important notes about this code.
A few important notes about this code.
- A thread is used to constantly read the potentiometer. If you take the reading in-line in the scene update method then you'll slow down the screen refresh rate.
- The PotReader class is given a reference to the PiTft class in order to pass data
- The ui.Scene class (PiTft) is instantiated after the call to ui.init - if you do this the other way around it will fail.
- A signal handler is used to trap ctrl+c and terminate the PotReader thread before calling sys.exit - otherwise the program will not close.
import sys sys.path.append('/home/pi/Adafruit-Raspberry-Pi-Python-Code/Adafruit_ADS1x15') import pygame import os import pygameui as ui import logging import RPi.GPIO as GPIO import signal from Adafruit_ADS1x15 import ADS1x15 import threading import time ADS1015 = 0x00 # 12-bit ADC ADS1115 = 0x01 # 16-bit ADC # Select the gain # gain = 6144 # +/- 6.144V gain = 4096 # +/- 4.096V # gain = 2048 # +/- 2.048V # gain = 1024 # +/- 1.024V # gain = 512 # +/- 0.512V # gain = 256 # +/- 0.256V # Select the sample rate sps = 8 # 8 samples per second # sps = 16 # 16 samples per second # sps = 32 # 32 samples per second # sps = 64 # 64 samples per second # sps = 128 # 128 samples per second # sps = 250 # 250 samples per second # sps = 475 # 475 samples per second # sps = 860 # 860 samples per second # Initialise the ADC using the default mode (use default I2C address) # Set this to ADS1015 or ADS1115 depending on the ADC you are using! adc = ADS1x15(ic=ADS1115) #Setup the GPIOs as outputs - only 4 and 17 are available GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.setup(17, GPIO.OUT) log_format = '%(asctime)-6s: %(name)s - %(levelname)s - %(message)s' console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter(log_format)) logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(console_handler) os.putenv('SDL_FBDEV', '/dev/fb1') os.putenv('SDL_MOUSEDRV', 'TSLIB') os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') MARGIN = 20 class PotReader(): def __init__(self, pitft): self.pitft = pitft self.terminated = False def terminate(self): self.terminated = True def __call__(self): while not self.terminated: # Read channel 0 in single-ended mode using the settings above volts = adc.readADCSingleEnded(0, gain, sps) / 1000 self.pitft.set_volts_label(volts) self.pitft.set_progress(volts / 3.3) class PiTft(ui.Scene): def __init__(self): ui.Scene.__init__(self) self.on17_button = ui.Button(ui.Rect(MARGIN, MARGIN, 130, 60), '17 on') self.on17_button.on_clicked.connect(self.gpi_button) self.add_child(self.on17_button) self.on4_button = ui.Button(ui.Rect(170, MARGIN, 130, 60), '4 on') self.on4_button.on_clicked.connect(self.gpi_button) self.add_child(self.on4_button) self.off17_button = ui.Button(ui.Rect(MARGIN, 100, 130, 60), '17 off') self.off17_button.on_clicked.connect(self.gpi_button) self.add_child(self.off17_button) self.off4_button = ui.Button(ui.Rect(170, 100, 130, 60), '4 off') self.off4_button.on_clicked.connect(self.gpi_button) self.add_child(self.off4_button) self.progress_view = ui.ProgressView(ui.Rect(MARGIN, 200, 280, 40)) self.add_child(self.progress_view) self.volts_value = ui.Label(ui.Rect(135, 170, 50, 30), '') self.add_child(self.volts_value) def gpi_button(self, btn, mbtn): logger.info(btn.text) if btn.text == '17 on': GPIO.output(17, False) elif btn.text == '4 on': GPIO.output(4, False) elif btn.text == '17 off': GPIO.output(17, True) elif btn.text == '4 off': GPIO.output(4, True) def set_progress(self, percent): self.progress_view.progress = percent def set_volts_label(self, volts): self.volts_value.text = '%.2f' % volts def update(self, dt): ui.Scene.update(self, dt) ui.init('Raspberry Pi UI', (320, 240)) pygame.mouse.set_visible(False) pitft = PiTft() # Start the thread running the callable potreader = PotReader(pitft) threading.Thread(target=potreader).start() def signal_handler(signal, frame): print 'You pressed Ctrl+C!' potreader.terminate() sys.exit(0) signal.signal(signal.SIGINT, signal_handler) ui.scene.push(pitft) ui.run()
Labels:
i2c,
pygame,
python,
raspberry pi,
touchscreen
Subscribe to:
Posts (Atom)