X Windows from Raspberry Pi to Android

So you’ve done a cool graphic app on your Raspberry Pi wouldn’t it be nice to see it on your Android phone ? Well luckily there are a couple of X Server apps that you can run on your Android phone that allows you to see your Pi graphic apps.

X Server Apps for Android

When you do a search for “x servers” on Android Play Store, you will get a few results.

apps_xservers

X Server XSDL from pelya, has good reviews and I found it to be fairly robust. My only comment was I wasn’t sure how to clear the background help statements, and it made the screen look a little messy.

X server from Darkside is a beta release. I preferred the background and SSH integration over XSDL, however this app did not always close the window when the code requested it.

Both options are free and open source.

Getting Started with X Windows

There are two main ways for X Windows to be run on a remote system. The first method is that the Window is sent from the Pi (or any Linux/X Windows system) to the Android phone. The second method is what you typically do on a Windows PC using an SSH terminal program like  Putty; you SSH (Secure Shell) in to the Rasp Pi and then when you run an app it open on your remote node.

xwindow_overview

Calling windows from a PC is pretty easy but calling windows from an Android phone is challenging and slow because of the keyboard. The two X Servers apps do not have SSH components built-in but there are some Android SSH client apps that can be run independently or integrated with the Darkside X app.

Sending an X Window from a Raspberry Pi or Linux node is rather straightforward. The sending location of an X window is defined by the DISPLAY session variable. To check its value enter:

~$ echo $DISPLAY
localhost:10.0

A typical results will be something like: localhost:10.0 .

To change the DISPLAY variable enter the ipaddress:window_number.  In my case the phone’s IP is 192.168.0.102, and the window number is 0, so in a terminal on the PI the command is:

export DISPLAY=192.168.0.102:0

This will now direct all X Windows in my terminal session to my phone. To test things we can send the Python IDE to the phone by:

$ idle

x_idle

Unfortunately the Android X Server app does not support moving or resizing of X Windows, so the app is pinned to the top left. Luckily if we are writing Python apps we can set the sizing and positioning when the app starts up.

Python Tkinter

The tkinter graphic library allows you to create a simple graphic front end to your Python projects.

The following code will update a label with the time every second. The geometry setting is used to move the window (300 left, and 100 down).

# test1.py - Show the time every second
#
import tkinter as tk
from datetime import datetime

root = tk.Tk()
root.geometry("+300+100")

def Updatetime():
label['text'] = datetime.now().strftime("%H:%M:%S")
root.after(1000,Updatetime)

def CallBack():
root.destroy()

label = tk.Label( root, text='', font = "Aria 72 bold" )
label.pack()

B = tk.Button(root, text ="Quit", font = "Aria 72 bold", command = CallBack)

B.pack()

root.after(1000,Updatetime)
root.mainloop()

To set the X window to my phone and run this Python application enter:

~$ export DISPLAY=192.168.0.102:0
~$ python test1.py

test1

Final Comment

I found that Python 3 was much more solid than Python 2. For example a Pi real time bars example worked perfectly on Python3, but on Python2 the bar wouldn’t update at all.

x_bars

 

 

 

 

 

 

 

Simulate Raspberry Pi Hardware

The Raspberry Pi has some great add-on hardware, such as Pi Tops that fit directly on top of the Pi module and wired components.

A good number of the wired Arduino designed parts now can also be used with Rasp PI’s. Some examples of this includes the HT16K33 and TM1637 seven segment displays.

Nothing beats using real hardware to show Pi values and status, but if you’re missing the hardware or you’d like to duplicate a displayed value remotely, then a soft version of the hardware can be very useful.

In this blog we’ll look at a three Python soft display examples, a seven-segment display, a LCD Keypad Top and a gauge.

Seven Segment Display

The tk_tools module is based on the Python tkinter module and it is has some cool components such as LEDs, Charts, Gauges and Seven Segment displays. The module is installed by:

pip install tk_tools

The tk_tools Seven Segment component can function like an Arduino TM1637 or HT16K33 display component. The tk_tools seven-segment display supports a height, digit_color and a background color.

Below is a some example code that shows the Pi’s CPU temperature in the soft seven segment display. 

import tkinter as tk
import tk_tools

root = tk.Tk()
root.title("CPU Temp")

ss = tk_tools.SevenSegmentDigits(root, digits=5, background='black',   
  digit_color='yellow', height=100)
ss.grid(row=0, column=1, sticky='news')

# Update the Pi CPU Temperature every 1 second
def update_gauge():
    # Get the Raspberry CPU Temp
    tFile = open('/sys/class/thermal/thermal_zone0/temp')
    # Scale the temp from milliC to C
    thetemp = int(float(tFile.read())/1000)

    ss.set_value(str(thetemp))
    root.after(1000, update_gauge)

root.after(500, update_gauge)

root.mainloop()

 

LCD Keypad 

The LCD Keypad I’ve used on a lot of my Pi Projects, (below is a PI FM radio example). Its supports 2 lines of text and it has 5 (or 6) buttons that can be used in your Python app. 

LCD_radio

The standard Python Tkinter library can be used to create a custom LCD keypad display. For my example I tried to replicate the look-and-feel of the Pi Top that I had, but you could enhance or change it to meet your requirements.

Below is an example that writes the button pushed to the 2 line label.

lcd_keypad_up

import tkinter as tk

def myfunc(action):
   print ("Requested action: ",action)
   Line1.config(text = "Requested action: \n" + action)

root = tk.Tk()
root.title("LCD Keypad Shield")
root.configure(background='black')

Line1 = tk.Label(root, 
		 text="ADC key testing     \nRight Key OK        ",
		 fg = "white",
		 bg = "blue",
		 font = "Courier 45",
                 borderwidth=4, relief="raised")
Line1.grid(row = 0,column = 0, columnspan =15, rowspan = 2)

selectB = tk.Button(root, width=10,text= "SELECT",bg='silver' ,
  command = lambda: myfunc("SELECT"),relief="raised")
selectB.grid(row = 3,column = 0)

leftB = tk.Button(root, width=10,text= "LEFT", bg='silver' ,
  command = lambda: myfunc("LEFT"),relief="raised")
leftB.grid(row = 3,column = 1)

rootB = tk.Button(root, width=10,text= "UP", bg='silver' ,
  command = lambda: myfunc("UP"),relief="raised")
rootB.grid(row = 2,column = 2)

rightB = tk.Button(root, width=10,text= "DOWN", bg='silver' , 
  command = lambda: myfunc("DOWN"),relief="raised")
rightB.grid(row = 3,column = 3)

bottomB = tk.Button(root, width=10,text= "RIGHT", bg='silver',
 command = lambda: myfunc("RIGHT"),relief="raised")
bottomB.grid(row = 4,column = 2)

rstB = tk.Button(root, width=10,text= "RST", bg='silver' ,
  command = lambda: myfunc("RESET"),relief="raised")
rstB.grid(row = 3,column = 4)

root.mainloop()

Gauge and Rotary Scale

There aren’t any mainstream low cost gauges that are available for the Rasp Pi, but I wanted to show how to setup a soft gauge.

The tk_tools gauge component is very similar to a speedometer. The rotary scale is more like a 180° circular meter. Both components support digital values, units and  color scales.gaugedoc

Below is a gauge example that reads the Pi CPU temperature every second.

import tkinter as tk
import tk_tools

root = tk.Tk()
root.title("CPU Temp")

my_gauge = tk_tools.Gauge(root, height = 200, width = 400,
                             max_value=70,
                             label='CPU Temp',
                             unit='°C',
                             bg='grey')
my_gauge.grid(row=0, column=0, sticky='news')

def update_gauge():
    # Get the Raspberry CPU Temp
    tFile = open('/sys/class/thermal/thermal_zone0/temp')
    # Scale the temp from milliC to C
    thetemp = int(float(tFile.read())/1000)
    my_gauge.set_value(thetemp)

    # update the gauges according to their value

    root.after(1000, update_gauge)


root.after(500, update_gauge)

root.mainloop()

gauge_temp

Final Thoughts

There are a lot of soft hardware components that could be created.

I found myself getting tripped up thinking : “What would be a good tkinter component and what should be  a Web component”. This is especially true when looking at charting examples, or when I was looking a remote connections.

Flame Monitor

Our goal was to create a fireplace flame monitoring system that would let us know if our gas fireplace was left on.

The Flame Sensor

For this project we used a low cost ($3) flame sensor, that measures infrared light generated by a flame. These flame sensors are great for indoor projects. Natural sunlight will generate infrared light so some shielding will be required if you want to use these sensors on outdoor projects.

flame_module

The flame sensor has 2 outputs, an analog value (AO) , and a digital value (DO). The analog value is from 0 to 5 VDC, where a 0 VDC signal represents no infrared light is detected and 5 VDC is full scale infrared light is detected. The digital output is 0 if  no infrared light is detected and  1 if threshold  amount of infrared light is detected. The flame sensor has a potentiometer that can adjust infrared light sensitivity limit.

Construction

The flame sensor documentation recommends that the sensor be mounted 1.5 to 3 feet away from flame. We used Meccano to create a stable base with two supporting upright arms.

OLYMPUS DIGITAL CAMERA

Hardware

For this project we used a Raspberry Pi, but an Arduino module could also be used. One disadvantage in using the Raspberry Pi is that it doesn’t have Analog inputs in the base unit. We used an Pimoroni ExplorerHat to support the Analog input.

flame_pi

If you only have the base Raspbander to your desired setting.

Python Code

It will take a little bit of trial and error to determine your “Flame is ON” value, and this will change based your fireplace and sensor positioning. We found that:

  • 5 = no noticeable flame
  • < 3 = fire is on low, flame is detected
  • < 1 = fire is super hot

Using an analog connection on the Explorerhat analog input 2, the basic Python syntax would be:

>>> import explorerhat
Explorer HAT Pro detected...
>>> explorerhat.analog.two.read()
5.052

After the basic code is working it is possible to upgrade the application by:

  • adding a Web or Tkinter interface
  • adding logic for valid times (i.e. is the fire on after 1am ?)
  • send text messages or email alerts

Below is some code that will add a Tkinter visual interface and send a message to IFTTT  (we used this for SMS texting).

flame_tkinter

# Flame Monitor, with a link to IFTTT
#
from tkinter import *
import explorerhat
import requests

issent = False

def get_status():
        global issent
        print ('Getting a new value....')
        lb_status['text'] = explorerhat.analog.two.read()
        if explorerhat.analog.two.read():
                lb_1['text'] = 'flame on'
                lb_1['bg'] = 'red'
                if issent == False:
                        theurl = 'https://maker.ifttt.com/trigger/nodered/with/key/_yourkeycodeishere'

                        r = requests.post(theurl, data = {'value1':'flame!!!','value2':explorerhat.analog.two.read()})
                        issent = True
                        print('sent message to ifttt')

        else:
                issent = False
                lb_1['text'] = 'flame off'
                lb_1['bg'] = 'green'
        top.update()
        top.after(2000, get_status)

top = Tk()
top.title("Fire Place Flame Scanner Monitor")

lb_1 = Label(top, text ="Flame Scanner", bg = "green", fg = "white", width= 30, font = ('DejaVu Sans Mono',20,'bold') )
lb_1.pack(side = BOTTOM)
lb_status = Label(top, text ="OFF", fg = "red", width= 30, font = ('DejaVu Sans Mono',20,'bold') )
lb_status.pack(side = BOTTOM)

top.after(2000, get_status)
top.mainloop()

Le gocart (Python Tkinter GUI)

For this project we wanted to control a Lego vehicle with a Python Tkinter app. Next we added a short cut to the Pi desktop and then we used VNC to see the Pi desktop and our app on a tablet.

Hardware Setup

Our hardware components were:

  • Raspberry Pi 3
  • Pimoroni ExplorerHat Pro – supports bi-directional DC motors
  • Dexter Connectors – allow 2 wire connections to Lego Mindstorms parts
  • 2 Lego Mindstorms motors
  • Portable USB charger
  • lots of Lego parts
  • 4 jumpers

le_gocart_parts

The Lego Mindstorms parts are little pricey but they allow you to make some pretty funky contraptions. The other thing that we like about the Mindstorms motors is that they have a lot of torque for a 5V DC motor.

There are a few options for the cabling (like cutting the cable and exposing the individual wires) we used the Dexter connectors that are breadboard friendly. ANA and GND connections on the Dexter side go to Motor + and Motor – on the ExplorerHat Pro board.

le_gocart_wiring

 

Python Tkinter

The Tkinter library allows you to create a simple graphic user interface (GUI) with components like: buttons, sliders, lists, text, labels etc.

For our interface we created a grid of 3 rows and 2 columns with 5 buttons. We made a simple motor function where we passed the speed and direction of the wheels. A negative speed is backwards, zero is stop, and a positive speed is forward.

import Tkinter
import explorerhat 

top = Tkinter.Tk()
top.title("Car Control")

explorerhat.motor.one.speed(0)
explorerhat.motor.one.speed(0)

#Define the buttons

def motor(Left,Right):
 explorerhat.motor.one.speed(Right)
 explorerhat.motor.two.speed(Left)

B_Left = Tkinter.Button(top, text ="Left", bg = "green", fg = "white", width= 15, height= 5, command = lambda: motor (50,0)).grid(row=1,column=1)
B_Right = Tkinter.Button(top, text ="Right", bg = "green", fg = "white", width= 15, height= 5, command = lambda: motor (0,50)).grid(row=1,column=2)
B_Forward= Tkinter.Button(top, text ="Forward", bg = "green", fg = "white", width= 15, height= 5, command = lambda: motor (50,50)).grid(row=2,column=1)
B_Backward = Tkinter.Button(top, text ="Backward", bg = "green", fg = "white", width= 15, height= 5, command = lambda: motor (-50,-50)).grid(row=2,column=2)
B_Stop = Tkinter.Button(top, text ="Stop", bg = "red", fg = "white", width= 33, height= 3, command = lambda: motor (0,0)).grid(row=3,column=1,columnspan=2)

top.mainloop()

VNC1

Pi Shortcut

To create a Pi shortcut, create a file:

nano $HOME/desktop/pi.desktop

Inside this file define the name, path, and icon info for your new application:

[Desktop Entry]
Name=Car Controls
Comment=Python Tkinter Car Control Panel
Icon=/home/pi/car1.png
Exec=python /home/pi/mycarapp.py
Type=Application
Terminal=false
Categories=None;

VNC (Virtual Network Computing)

VNC is install on the Raspbian image. To enable VNC run:

sudo raspi-config

Then select the interfacing option, and then select VNC and enable.

raspi-config-vnc

Finally you will need to define a VNC password and load some VNC software on your Tablet. There are a lot of packages to choose from. We have an Android table and we used RemoteToGo without any problems.

Note, when your Pi boots without a HDMI monitor connected the desktop resolution will be at a low setting (probably 800×600) this can be adjusted. For us we simply resized the desktop to fit our tablet screen.