If you’d like to use some of your Python experience on Android, then the QPython Android IDE may surprise you with what it has to offer.
Out of the box QPython includes some excellent libraries, especially if you’re interested in doing some data mining or modeling.

In this blog I’d like to look at an example of building an Android QPython GUI app that controls some lights on a Raspberry Pi.
A Button Interface
Luckily you can do all your development on a Windows/Linux/MacOS/Raspberry Pi before you need to move the application to Android.
QPython comes with a number of pre-installed libraries such as: a standalone Web Server, a low level Android interface, sockets, and the QPython supports the Pygame library.
I used a simple 4 button application, but there are lots of other graphic features that are possible in Pygame. The only real difference with a pygame QPython app is that a #qpy:pygame reference is required at the top of the file. This reference is overlooking in Window/Linux/MacOS.
#qpy:pygame
import pygame
import socket
pygame.init()
def draw_button(button, screen):
#Draw the button rect and the text surface
pygame.draw.rect(screen, button['color'], button['rect'])
screen.blit(button['text'], button['text rect'])
def create_button(x, y, w, h, bg, text, callback):
# Create a buttondictionary of the rect, text,
# text rect, color and the callback function.
FONT = pygame.font.Font(None, 50)
text_surf = FONT.render(text, True, pygame.Color('black'))
button_rect = pygame.Rect(x, y, w, h)
text_rect = text_surf.get_rect(center=button_rect.center)
button = {
'rect': button_rect,
'text': text_surf,
'text rect': text_rect,
'color': pygame.Color(bg),
'callback': callback,
}
return button
def main():
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Rasp Pi Interface: ")
clock = pygame.time.Clock()
def bt_func(input): # A callback function for the button.
pygame.display.set_caption("Rasp Pi Interface: Send - " + input)
print(input)
button1 = create_button(100, 50, 250, 80,'blue','BLUE LED',lambda: bt_func('blue'))
button2 = create_button(100, 150, 250, 80,'yellow', 'YELOW LED',lambda:bt_func('yellow'))
button3 = create_button(100, 250, 250, 80,'red', 'RED LED', lambda: bt_func('red') )
button4 = create_button(100, 350, 250, 80,'green', 'GREEN LED',lambda: bt_func('green'))
# A list that contains all buttons.
button_list = [button1, button2,button3, button4]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# This block is executed once for each MOUSEBUTTONDOWN event.
elif event.type == pygame.MOUSEBUTTONDOWN:
# 1 is the left mouse button, 2 is middle, 3 is right.
if event.button == 1:
for button in button_list:
# `event.pos` is the mouse position.
if button['rect'].collidepoint(event.pos):
# Increment the number by calling the callback
# function in the button list.
button['callback']()
screen.fill(pygame.Color('white'))
for button in button_list:
draw_button(button, screen)
pygame.display.update()
clock.tick(30)
main()
pygame.quit()
When the Pygame application is running the buttons will send toggle the display caption and write a print() message.

Socket Communications
Sockets are a simple way to have multiple devices communicate together. For this example the Raspberry Pi will be a Socket Server and a PC, Linux node or an Android phone could be socket clients.
# Simple Python Socket Server
#
import socketserver
class Handler_TCPServer(socketserver.BaseRequestHandler):
# Handler to manage incoming requests
def handle(self):
# self.request - TCP socket connected to the client
self.data = self.request.recv(1024).strip()
# self.data - is the incoming message
print("{} sent:".format(self.client_address[0]))
print(self.data)
# if required a request could be send back
#self.request.sendall("ACK from TCP Server".encode())
if __name__ == "__main__":
# Define the host and port to use
HOST, PORT = "192.168.0.133", 9999
# Init the TCP server object, bind it to the localhost on 9999 port
tcp_server = socketserver.TCPServer((HOST, PORT), Handler_TCPServer)
print("Socket Server Started on : " + HOST + " port: " + str(PORT))
# Activate the TCP server.
tcp_server.serve_forever()
A simple Python TCP socket client would be:
import socket
host_ip, server_port = "192.168.0.133", 9999
data = " Hello how are you?\n"
# Initialize a TCP client socket using SOCK_STREAM
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Establish connection to TCP server and exchange data
tcp_client.connect((host_ip, server_port))
tcp_client.sendall(data.encode())
# Read data from the TCP server and close the connection
received = tcp_client.recv(1024)
finally:
tcp_client.close()
print ("Bytes Sent: {}".format(data))
print ("Bytes Received: {}".format(received.decode()))
Put It Together
Once the socket communications and the Pygame interface is working, the full program can be completed. The first step is to define some output LED pins on the Raspberry Pi. For my project I used a Pimoroni Explorer Hat Pro. This Pi top had some built in colored LED pins.
# Pi Socket Server to toggle 4 color LEDs
import socketserver
class Handler_TCPServer(socketserver.BaseRequestHandler):
# Handler to manage incoming message requests
def handle(self):
# self.request - TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} sent:".format(self.client_address[0]))
print(self.data)
if self.data == "red":
GPIO.output(redpin, not GPIO.input(redpin))
if self.data == "yellow":
GPIO.output(yellowpin,not GPIO.input(yellowpin))
if self.data == "blue":
GPIO.output(bluepin,not GPIO.input(bluepin))
if self.data == "green":
GPIO.output(greenpin,not GPIO.input(greenpin))
# just send back ACK for data arrival confirmation
#self.request.sendall("ACK from TCP Server".encode())
if __name__ == "__main__":
# Define 4 LED pins as outputs
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
yellowpin = 17
bluepin = 4
redpin = 27
greenpin = 5
GPIO.setup(redpin,GPIO.OUT)
GPIO.setup(yellowpin,GPIO.OUT)
GPIO.setup(bluepin,GPIO.OUT)
GPIO.setup(greenpin,GPIO.OUT)
HOST, PORT = "192.168.0.133", 9999
# Init the TCP server object, bind it to the localhost on 9999 port
tcp_server = socketserver.TCPServer((HOST, PORT), Handler_TCPServer)
print("Socket Server Started on : " + HOST + " port: " + str(PORT))
# Activate the TCP server.
# To abort the TCP server, press Ctrl-C.
tcp_server.serve_forever()
Next our Pygame interface needs to include some TCP socket client code that sends the color message.
#qpy:pygame
import pygame
import socket
pygame.init()
def draw_button(button, screen):
#Draw the button rect and the text surface
pygame.draw.rect(screen, button['color'], button['rect'])
screen.blit(button['text'], button['text rect'])
def create_button(x, y, w, h, bg, text, callback):
# Create a buttondictionary of the rect, text,
# text rect, color and the callback function.
FONT = pygame.font.Font(None, 50)
text_surf = FONT.render(text, True, pygame.Color('black'))
button_rect = pygame.Rect(x, y, w, h)
text_rect = text_surf.get_rect(center=button_rect.center)
button = {
'rect': button_rect,
'text': text_surf,
'text rect': text_rect,
'color': pygame.Color(bg),
'callback': callback,
}
return button
def main():
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Rasp Pi Interface: ")
clock = pygame.time.Clock()
def bt_func(input): # A callback function for the button.
pygame.display.set_caption("Rasp Pi Interface: Send - " + input)
print(input)
host_ip, server_port = "192.168.0.133", 9999
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Establish connection to TCP server and exchange data
tcp_client.connect((host_ip, server_port))
tcp_client.sendall(input.encode())
finally:
tcp_client.close()
button1 = create_button(100, 50, 250, 80,'blue','BLUE LED',lambda: bt_func('blue'))
button2 = create_button(100, 150, 250, 80,'yellow', 'YELOW LED',lambda: bt_func('yellow'))
button3 = create_button(100, 250, 250, 80,'red', 'RED LED', lambda: bt_func('red'))
button4 = create_button(100, 350, 250, 80,'green', 'GREEN LED',lambda: bt_func('green'))
# A list that contains all buttons.
button_list = [button1, button2,button3, button4]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# This block is executed once for each MOUSEBUTTONDOWN event.
elif event.type == pygame.MOUSEBUTTONDOWN:
# 1 is the left mouse button, 2 is middle, 3 is right.
if event.button == 1:
for button in button_list:
# `event.pos` is the mouse position.
if button['rect'].collidepoint(event.pos):
# Increment the number by calling the callback
# function in the button list.
button['callback']()
screen.fill(pygame.Color('white'))
for button in button_list:
draw_button(button, screen)
pygame.display.update()
clock.tick(30)
main()
pygame.quit()
Loading the Application on Android
To load the application on my phone, I connected my phone to a PC and I move the file to the phone’s /Download directory. QPython files can be created/edited and run using the Editor button. New Python applications can be created using the PygameApp menu option.
It’s important to note that if you are using print() functions in your application then a log directory file location prompt will come up the first time that your app is run.
QPython applications can be made into a desktop short cut.
Once everything is configured, you should be able to click on the desktop QPython icon and start controlling the Raspberry Pi.
