Same Code for Python GUI and Web Apps

The Python PySimpleGUI project has two main goals:

  • A simpler method for creating graphical interfaces, and
  • Common code for Tkinter, QT, xW and Web graphics

I feel comfortable doing my own Tkinter and Web interfaces, but common code for both is very cool and it could be very useful for Rasp Pi applications. However things didn’t work “out of the box”, so this blog will look at some workarounds and issues.

A Simple Example

If you are used to coding in QT or xW PySimple is absolutely easier to use.

PySimpleGUI has some defined graphic objects (like Text or Button) and the screen placement is defined by how they are grouped with [ ] brackets. For example two objects in a [ ] bracket puts the two objects on the same line. 

If you’re a Tkinter user PySimpleGUI may seem a little more cumbersome in it’s layout design. (I find Tkinter’s grid methods to be a superior layout approach).

For my first example I used the published example and I added an option for the graphic method (tkinter, Qt, Wx and Web):

 import sys, random, time  
   
 mode = "tkinter"  
 # Check for command line arguments   
 if len(sys.argv) > 1: # if there is use the Web Interface  
   if sys.argv[1] == 'web':  
     import PySimpleGUIWeb as sg  
     mode = "Web"  
   elif sys.argv[1] == 'wx':  
     import PySimpleGUIWx as sg  
     mode = "Wx"  
   elif sys.argv[1] == 'qt':  
     import PySimpleGUIQt as sg  
     mode = "Qt"  
   else:  
     import PySimpleGUI as sg  
   
 else: # if no arguments use the standard GUI  
   import PySimpleGUI as sg  
   
 # Basic example from PySimpleGUI
   
 sg.change_look_and_feel('DarkAmber')  # Add a touch of color  
 # All the stuff inside your window.  
 layout = [ [sg.Text('Some text on Row 1')],  
       [sg.Text('Enter something on Row 2'), sg.InputText()],  
       [sg.Button('Ok'), sg.Button('Cancel')] ]  
   
 # Create the Window  
 window = sg.Window('PySimpleGUI ' + mode , layout)  
 # Event Loop to process "events" and get the "values" of the inputs  
 while True:  
   event, values = window.read()  
   if event in (None, 'Cancel'):  # if user closes window or clicks cancel  
     break  
   print('You entered ', values[0])  
   
 window.close()  
 print('Program terminating normally')  
   

The output for the different graphic methods looks incredibly similar for this example:

GUI_wxGUI_webGUI_tkGUI_qt

It’s important to note that PySimpleGUI is still under development so many of the features will be in transition. If you stick to basic functions like: buttons, images and text you should be good.

I found that the default Tkinter version to be very solid, and the other versions would complain on some of the added features such as: frames, sliders, and progressbars.

A Realtime Update Example

For my next example I wanted to do a Rasp Pi type example with some simulated values from a temperature sensor.

To write back to a graphic object:

  • define a key name when the object is defined (key = “myojbname”)
  • use:  window[‘myojbname’]( new_value) to update the object
 import sys, random, time  
   
 mode = "tkinter"  
 # Check for command line arguments   
 if len(sys.argv) > 1: # if there is use the Web Interface  
   if sys.argv[1] == 'web':  
     import PySimpleGUIWeb as sg  
     mode = "Web"  
   elif sys.argv[1] == 'wx':  
     import PySimpleGUIWx as sg  
     mode = "Wx"  
   elif sys.argv[1] == 'qt':  
     import PySimpleGUIQt as sg  
     mode = "Qt"  
   else:  
     import PySimpleGUI as sg  
   
 else: # if no arguments use the standard GUI  
   import PySimpleGUI as sg  
   
 # Basic example of PSGWeb  
   
 def main():  
   sg.change_look_and_feel('LightGrey')  
   dataframe = [  
     [sg.Text('Temperature (C):',size=(12,2)),  
     sg.Text(' ', font='Courier 48', text_color='red', key='degC')],  
     [sg.Text('Humidity (%)  :',size=(12,2)),  
     sg.Text(' ', font='Courier 48', text_color='red', key='humid')],  
       
   ]  
   layout = [  
     [sg.Image(filename = "dht11.png"),sg.Frame("DHT11 Sensor", dataframe,font='Any 12', title_color='blue')]  
     ]  
     
   if mode == "web":  # Note: customization on the Web interface
     window = sg.Window('Pi Weather Data ' + mode, layout,web_ip='192.168.0.107', web_port = 8888, web_start_browser=False, disable_close=True)  
   else:  
     window = sg.Window('Pi Weather Data ' + mode, layout)  
     
   while True:  
     event, values = window.read(timeout=10)  
     temp_degC = random.randint(20,30)  
     humidity = random.randint(0,100)  
     window['degC']( temp_degC)  
     window['humid'](humidity)  
     time.sleep(1)  
       
   window.close()  
   
 main()  
 print('Program terminating normally')  
   

The Wx code would not run, and the development team has commented on compatibility issues that they are having with Wx so future support may be dropped.

The Tkinter and Qt, but for this example the Web presentation dropped the frame outline.

GUI2_qtGUI2_tkGUI2_web

PySimpleGUIWeb

The PySimpleGUIWeb project is based on the Remi Project which defines graphics objects in an HTML/Web environment.

One big difference that I found between the Remi project and PySimpleGUIWeb is that Remi supports callbacks. I found that callbacks are extremely useful if you are trying to mix reads and writes in the same application. PySimpleGUI uses a read to get user input but this gets confusing if you are using a timer for writing new data to the GUI.

The PySimpleGUIWeb library by default was missing some key documentation. I found that “out of the box” it wasn’t usable for my applications . However everything that I needed was in the Window class it just wasn’t clearly documented.

The following web features can be controlled:

  • web_ip=’xx.xx.xx.xx’ , default is localhost (127.0.0.1), not good for remote connections.
  • web_port= xxxx , default is a random port id. Again not useful for remote connections.
  • web_start_browser=False, default a web browser is launched (not useful for SSH).
  • disable_close=True , default closes the app when the web browser closes.

An example to open a Web connection (not local) that doesn’t auto-open a browser and stays open would be:

window = sg.Window('Pi Weather Data ',  layout,web_ip='192.168.0.107', web_port = 8888, web_start_browser=False, disable_close=True)

Final Thoughts

I like the concept of the same code being used on both a Tkinter and a Web  app. I believe that this has a lot of potential. However at this point only the simplest features are available in the Web, so I’d rather use a Python Web framework like Bottle.

I really like some of the concepts of PySimpleGUI but I think that understanding and using the standard Tkinter allows you more flexibility and it lets you include add-in modules like Tk_tools.

 

Streaming Video Server

There are some reasonably priced video surveillance products available on the market. If however you have a USB Web Cam and a Raspberry Pi (or equivalent or an old PC) you can make your own.

If you are working in the Unix world I would recommend motion , it’s super easy to setup and it’s got lots of added features if you want to turn them on. To install:

sudo apt-get install motion

Once you have motion installed you’ll need to tweek some of it’s parameters by:

sudo nano /etc/motion/motion.conf

The /etc/motion/motion.conf file contains a lot of cool parameters to tweek, some of the more important ones are:

# Image width (pixels). Valid range: Camera dependent, default: 352
width 800

# Image height (pixels). Valid range: Camera dependent, default: 288
height 600

# Maximum number of frames to be captured per second.
framerate 1

# Maximum framerate for stream streams (default: 1)
stream_maxrate 1

# Restrict stream connections to localhost only (default: on)
stream_localhost off

The speed of your hardware and network will determine how many frames per second you can use.

To run the video server enter:

sudo motion

The motion package has a built in web server that is accessed by: http://your_ip:8081

livevideo

Hardware Setup

There are lots of options for the mounting of your video server. I like to use Lego Pi cases about ($8) and then use some Lego to secure the rest of the components. Below is an example where I used a PIR (Pyroelectric Infrared) module ($3) to manually turn the motion software on/off, and I added a USB card reader to enable/disable the system.

OLYMPUS DIGITAL CAMERA
Homemade Security System

Performance and Tuning

Ideally it would be nice to run at 24 frames per second (or better) to get smooth video action. Unfortunately I found that the Raspberry Pi 3 would often freeze up at this refresh rate with a USB camera. The linux command line tool vmstat can be useful to show your CPU and I/O status. Below is some sample vmstat output:

$ vmstat # Pi 3 video server at 24 fps
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 1 0 0 593552 17808 269856 0 0 41 57 803 180 7 1 74 18 0

The id is the idle time (74%), which isn’t bad. The problem however id wa, waiting for I/O.

You will have to do some trial and error to get a refresh rate that works best for you.

Port Forwarding

With the basic setup you will be able to access the video server from your local LAN/WAN. If however you want to access your video server from the Internet then you will need to allow a connection through your router to your video server, this is called port forwarding.

Unfortunately the configuration of port forwarding will vary from manufacturer to manufacture, so please see the documentation for your specific devices.

 

Python talking to littleBits Cloud API

LittleBits is a set of components that allow kids to build their own electrical circuits. The Cloudbit will send and receive values from the Internet.

For this project we wanted to build some Python programs that could interact with the littleBits Cloud API.

littleBits Hardware Setup

cloudbit_setup

The Cloudbit enables an input to be sent to the Internet, and it will receive a value (output) from the Internet. For a test setup we used a dimmer bit to adjust the input value with a number bit to show the value. On the output side we used a bargraph bit. Other combinations of bits are possible. The key is to be able to test and see your input and output values.

Cloudbits Setup

For the Cloudbit setup you will need to create a sign-in on the littleBits web site. For details on how to setup your Cloudbit use the following link.

Python Basic Setup

The Cloud API is a RESTful interface, that uses http requests with some header definitions. Before you get started you’ll need your specific littleBits device ID and authorization token. In your specific Cloudbit definition go to the Settings icon, and get your Device ID and AccessToken.

littlebit_id

 

The Cloud API presently does not support a single point read (this might change), instead the input data point value is streamed about once a second.

The basic syntax in Python to get values from the  Cloud API will be:

import requests

requests.packages.urllib3.disable_warnings()

# Change with your Authorization code and deviceID
authToken = "4f3830b44e15fa0d"
deviceId = "00e04c"

headers = {"Authorization": "Bearer " + authToken,"Content-type": "application/json"}

# For a read 
littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/input"
r = requests.get(littleBitsUrl, headers=headers, stream=True)

#  For a write, note: a data body needs to be defined
# littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/output"
# body = {"percent": thevalue , "duration_ms": thetime} 
# thebody = json.dumps(body)
# r = requests.post(littleBitsUrl, data=thebody, headers=headers)

To do a read of the Cloud API an get request is done, to do a write a post request is used.

Python Read Value Example

The cloud API will stream the input value about every second in a format something like:

data: {"type":"input","timestamp":1521587206463,"percent":61,"absolute":629,"name":"amplitude","payload":{"percent":61,"absolute":629},"from":{"device":{"id":"00e04c0379bb","mac":"00e04c0379bb"}}}
{"type":"input","timestamp":1521587206463,"percent":61,"absolute":629,"name":"amplitude","payload":{"percent":61,"absolute":629},"from":{"device":{"id":"00e04c0379bb","mac":"00e04c0379bb"}}}

This data stream will need to be massaged with the following steps:

  • decode the stream (UTF-8)
  • remove the leading data: , (the remain message will be JSON formatted).
  • load the remain string into a JSON object

Below is some example code, for an app with a slider.

lb_tk_input

#
# lb_input.py - read input from a Cloudbit device
#
import json
import requests

requests.packages.urllib3.disable_warnings()

# Change with your Authorization code and deviceID
authToken = "4f3830b44e1d4b27xxxxxx"
deviceId = "00e04c03xxxx"

littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/input"

headers = {"Authorization": "Bearer " + authToken,"Content-type": "application/json"}
r = requests.get(littleBitsUrl, headers=headers, stream=True)

for line in r.iter_lines():
   strmsg = line.decode("utf-8").strip()
 
   print("Str: ",strmsg)
   if len(strmsg) > 0:
      lb_data = strmsg.split('data:')[1]
      print(lb_data)
      result = json.loads(lb_data)
      thevalue = result['percent']
      lb_bar.set(thevalue)
      thetime = str(datetime.datetime.fromtimestamp(result['timestamp']/1000))
      lb_time['text'] = "Time : " + thetime[:-7]
      root.update()

The Cloud API passed the time stamp as a numeric value with microseconds. The time can be cleaned with:

thetime = str(datetime.datetime.fromtimestamp(result['timestamp']/1000)) 
time_no_micro_seconds = thetime[:-7]

Python Output Value Example

The Cloud API output uses a post method and unlike the input example there is no streaming.

The new output value and a pulse time is sent in the post data parameter. The value is from 0-100, and a pulse time is -1 for sustained, otherwise a millisecond pulse time is used.

Below is some sample code for a Tkinter app:

lb_tk_output

from Tkinter import *
import json
import requests

# update your auth Token and device ID
authToken = "4f3830b44e1d4b27xxxx"
deviceId = "00e04c03xxxxx"

littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/output"

headers = {"Authorization": "Bearer " + authToken, "Content-type": "application/json"}

def setvalue():
	thevalue = lb_value.get()
	thetime = lb_duration.get()
	body = {"percent": thevalue , "duration_ms": thetime}
	thebody = json.dumps(body)
	print body, thebody
	r = requests.post(littleBitsUrl,  data=thebody, headers=headers)
	print r
     

root = Tk()
root.title('littleBits Output')

Label(text = "Value (0-100) :",width=30).grid(row=0,column=0)
lb_value = Entry(root, width= 10)
lb_value.grid(row=0,column=1)
Label(text = "Duration (ms) (constant=-1) :",width=30).grid(row=1,column=0)
lb_duration = Entry(root, width= 10)
lb_duration.grid(row=1,column=1)


Button(root, text=' Set Output ', bg='silver', command=setvalue).grid(row=2,column=1)

root.mainloop()

Final Comments

There are a lot of simple applications and projects that can be created with Python and some littleBits. One of the limitations on the Cloudbit is that it only sends 1 value and receives 1 value. If you are dealing with digital signals it would be possible to do some multiplexing.

Pi PHP Controls

I’ve been trying to teach my kids PHP,  below are some notes on how to get a PHP page to control Pi GPIO outputs. For motor controls we use the Pimoroni ExplorerHat Pro and it is possible to address the ExplorerHat pins directly with gpio calls. However other shields or tops like PiFace Digital could also be used.

Loading PHP

On the Raspberry Pi you will need to load both a web server and PHP. There are a number of good web servers to load. We picked Apache because it is well documented and more mainstream.

There are some good installation procedure for installing Apache and PHP on the Raspberry Pi. A minimalist installation would be:

sudo apt-get install apache2 -y
sudo apt-get install php5 libapache2-mod-php5 -y

If everything is installed correctly the Apache home directory should be: /var/www/html.

To test that your installation is working open a browser on the Pi and go to: http://localhost. If the default (index.html) page comes up then you’ve install Apache correctly.

ExplorerHat Pro GPIO Pinouts

Typically we use the Python interface to talk to the ExplorerHat Pro. If you use PHP you will need to address the ExplorerHat Pro GPIO pins directly.

ExplorerHat  BCM wPi
Motor 1 Forward 19 24
Motor 1 Backward 20 28
Motor 2 Forward 21 29
Motor 2 Backward 26 25
LED 1 4 7
LED 2 17 0
LED 3 27 2
LED 4 5 21
Output 1 22 31
Output 2 26 32
Output 3 23 33
Output 4 27 36

PHP Interfacing to Pi GPIO

There are a few ways to access the GPIO pins in PHP:
1. use a PHP library
2. shell to the gpio command

Using a PHP library allows for a standard PHP interface, with an object model.

From testing I found that the PHP libraries were not as flexible as the standard gpio command. For example you could not access extended GPIO pin numbers (i.e. 200).

GPIO Command Line Utility

PHP can shell out to the gpio command line utility. I liked this approach because I could test the actions manually before putting them into a PHP web page.

A simple gpio read example would be:

<html lang="en">
<head>
</head>
<body>
<?php
$ret = shell_exec('gpio read 7');
echo "Pin 7 status = " . $ret;
?>
</body>
</html>

And a gpio write example (with reading back the result) would be:

<html>
<head>
</head>
<body>
<?php
exec("gpio write 7 1");
$ret = shell_exec('gpio read 7');
echo "Pin 7 status = " . $ret;
?>
</body>
</html>

 

PHP Forms

For many Pi projects button interfaces are all that is required. In the Web design this is not typical so it is important to determine which button is pushed. One approach to this problem is to give all the buttons the same name:


  
  
  
  


Then in the PHP code look for a value for this form variable:

<?php
// define the GPIO pins for the motor ouptput (Note: PiFace pins start at 200)
$leftpin = 24;
$rightpin = 29;

if (isset($_POST['submit'])) {
	switch ($_POST['submit']) {
		case "go":
			exec("gpio write " . $leftpin . " 1");
			exec("gpio write " . $rightpin . " 1");
			break;
		case "stop":
			exec("gpio write " . $leftpin . " 0");
			exec("gpio write " . $rightpin . " 0");
			break;
		case "left":
			exec("gpio write " . $leftpin . " 1");
			exec("gpio write " . $rightpin . " 0");
			break;
		case "right":
			exec("gpio write " . $leftpin . " 0");
			exec("gpio write " . $rightpin . " 1");
			break;
	}
}
?>

Mobile CCS Templates

There are quite a few good mobile templates to choose from. [Bootstrap](http://getbootstrap.com/) is one of the most popular frameworks, and for Pi applications it seems to be a good fit. A simple four button example would be:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>PHP/Pi Rover Controls</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">

  <h2>PI Four Button Example</h2>
  <form action="" method="post">
    <div class="form-group">

    <button type="submit" name="submit" class="btn-success btn-lg" style="width:100%" value="go">Forward</button>
    <button type="submit" name="submit" class="btn-info btn-lg" style="width:49%" value="left">Left</button>
    <button type="submit" name="submit" class="btn-info btn-lg" style="width:49%" value="right">Right</button>
    <button type="submit" name="submit" class="btn-danger btn-lg" style="width:100%" value="stop">Stop</button>
  </form>
</div>

</body>
</html>

Some of the key items are:

  • Add references in to the bootstrap ccs and js files
  • Add tags with the required class definitions:
    • the btn-lg class will make a large button, instead of standard sized btn 
    • different button colours are possible using btn-info, btn-success. btn-danger
    • Button width is defined with style=”width: xx%” . For multiple buttons the sum of the width needs to <100%

 

bootstrap4btns

Further Examples

Below are some pictures of a mobile rocket launcher project.  The Web page had two sections. The top section controlled bi-directional motors that were connected to a Explorer HAT Pro shield. The bottom section controlled the rocket launcher turret. The missile launcher was connected via a USB cable to the Pi. For the missile launcher program we created a Python app with command line options to set the action.

Screenshot

OLYMPUS DIGITAL CAMERA

Pi/Node-Red Car

The goal of the Pi/Node-Red car project was to create a small vehicle that can be controlled from a smart phone . For the project we used:

  • 1 Car chassis for Arduino ($15)
  • 1 Pimoroni Explorer HAT Pro  ($23)
  • 1 Portable microUSB charger
  • 1 USB WiFi Adapter
  • 4 short alligator clips and 4 connectors
  • Duct tape

The Arduino car chassis may require a small amount of assembly. Rather than soldering connections we like to use short alligator clips. It is not recommended to wire DC motors directly to a Raspberry Pi so the Pimoroni Explorer HAT Pro is used to connect the 2 DC motors.

The Raspberry Pi and the portable microUSB charger are secured to the top of the car chassis with duct tape. The left motor is wired to the motor 1 connectors on the Explorer Hat, and the right motor is wired to motor 2 connectors. Note you may have to do a little trial and error on the Explorer HAT “+” and “-” motor connections to get both wheels spinning in a forward direction.

The Explorer HAT Node-Red library is installed by:

 cd $HOME/.node-red
npm install node-red-dashboard 

The Web dashboard presentation is configured in the “dashboard” tab. For this example we create 2 groups: a control group to drive the vehicle, and a light group to turn on the Explorer Pro lights. Use the “+group” button to add a group, and the “edit” to change an existing group.
dash_conf

To control a motor, an “Explorer HAT” node and a dashboard button node are dropped and connected together. All the configuration is done in the button node . The button configure options are:

  • the group the button will appear in (Controls)
  • the size of the button (3×1 = 50% of width and narrow)
  • Topic, motor.one or motor.twois used for motor control
  • Payload, -100 = reverse, 0=stop, 100 = forward

Control_conf

The Explorer HAT has 4 colored LEDs. To toggle the LEDS, the topic is light.color with 1=ON, and 0=OFF . We thought that it would be fun to also add some Web dashboard button to control the colored lights.

light_conf

The Node-Red dashboard user interface is accessed by: ipaddress:1880/UI, so for example 192.168.1.102:1880/ui. Below is a picture that shows the final vehicle logic and the Web dashboard.

 

final_logic2

 

 

 

littleBits/Pi Temperature Monitor

By using littleBits Proto modules it is possible to create Raspberry Pi projects with littleBits components. On this project we created a temperature monitor with a local indication and a remote Web page using Node-Red.

The parts used were:

  • 1 Raspberry Pi 3
  • 1 Explorer Hat (used for Analog Inputs)
  • 2 littleBits Proto bits
  • 1 littleBits Temperature bit
  • 1 littleBits Number bit
  • 1 littleBits Wire bit (optional, used for easier wiring)

The Wiring

To complete the littleBits circuit the first Proto bit was wired with 5V to the VCC and the data connectors. Pi GND was wired to the module’s GND. The second Proto bit had the data pin with to the Explorer HAT analog input 1.

tempcircuit

Node-Red Logic

On the Pi, the following Node-Red nodes were used:

  • Explorer Hat Node – reads the analog input
  • Function Node – only pass on analog input 1
  • Smooth Node – removes noise and jitter
  • Function Node – converts 0-5V to 0-100 C

temp_logic

The logic for the first function node, (to pass only analog input 1), was:

 if (msg.topic == "explorerhat/analog.1"){
return msg;
} 

We added a smooth node to remove noise in the analog input signal. The configuration that we used for the smooth node was:

temp_smooth

The logic for the second function, (to convert the voltage to a temperature), was:

msg.payload= (100/5)*msg.payload;
return msg;

Finally we used a Chart Dashboard node to show the results on a Web page. Our configuration for this was:

temp_gauge

To view the Web page use the URL of : http://the-pi-address:1880/ui

temp_pic_full

Remote Controlled Rocket Launcher

We’ve made a number of different versions of the mobile rocket launcher, and all of them have been fun. The version above is using the a PI 1 with a PiFace Digital module for the motor controls and a wireless keyboard for the controls.

The version shown below is using a PI 3, with an ExploreHAT Pro for the motor controls and a Python Web Server program for the controls. By using some simplified HTML tagging we were able to use an old PSP as a remote interface console.

launcher

Rocket Launcher Sample Code

We found the rocket launcher in a sale bin, but they call be purchased at: http://dreamcheeky.com/thunder-missile-launcher. The rocket launcher comes with it’s own Windows based program.

Below is some Python code that will control the rockets launchers turret and fire a missile. Based on this sample code you should be able to make some cool projects. A couple of notes from our testing:

  • you need to manually stop the turret motion once you start it. So you need to set your own wait time
  • you need 3-4 seconds between each missile firing. It might be a coincident but we damaged our first rocket launcher trying to issue fast firing commands.
 import usb
import sys
import time

device = usb.core.find(idVendor=0x2123, idProduct=0x1010)

# On Linux we need to detach usb HID first
try:
device.detach_kernel_driver(0)
# except Exception, e:
except Exception:

pass # already unregistered

device.set_configuration()

endpoint = device[0][(0,0)][0]

down = 1 # down
up = 2 # up
left = 4 # rotate left
right = 8 # rotate right
fire = 16 # fire
stop = 32 # stop

#device.ctrl_transfer(0x21, 0x09, 0x0200, 0, [signal])

while True:

print('r = right, l = left, u = up, d = down, f = fire ')
key = raw_input ('enter key:')
if (key == 'l'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, left, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'u'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, up, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'r'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, right, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'd'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, down, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'f'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, fire, 0x00,0x00,0x00,0x00,0x00,0x00])
time.sleep(4)
time.sleep(0.1)
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, stop, 0x00,0x00,0x00,0x00,0x00,0x00])