You are on page 1of 39

175 × 235  SPINE: 11.

4  FLAPS: 0

FOR ELECTRONIC ENGINEERS

PYTHON 3 - PROGRAMMING
FOR ELECTRONICS ENGINEERS

PYTHON 3
PROGRAMMING AND GUIS
PYTHON 3
Andrew Pratt PROGRAMMING AND GUIS

This is the second edition of a book aimed at engineers,


scientists and hobbyists who want to interface PCs with
hardware projects using graphical user interfaces. Desktop
and web based applications are covered.
The programming language used is Python 3 which is
one of the most popular languages around: speed of
programming being a key feature. The book has been
revised and updated with emphasis on getting the user to
produce practical designs with ease - a text editor is all

AND
Andrew Pratt served for
that is required to produce Python programs.
25 years in the Royal
Air Force as an Aircraft Hardware interfacing is achieved using an Arduino Uno as

GUIS • Andrew Pratt


Technician. a remote slave. A full description and source code of the
communication interface is given in the book. The slave
He holds a Higher
provides digital and analogue input and outputs. Multiple
National Certificate in
Unos can be included in one project with all control code
electrical and electronic
written in Python and running on a PC
engineering and a
Degree from the Open One project involves a PIC microcontroller with code
University. provided that can be loaded into the PIC using the Uno.
The web applications and server are all implemented in
He continued his career
Python allowing you to access your electronic hardware
working in industrial
over the Internet. The Raspberry Pi computer can be used
controls. Currently
as your web server.
he is an instructor
teaching industrial An introductory chapter is provided to get you started with
control systems. using Linux. The book is written for use with Debian or
variations including Mint or Ubuntu. All of the programs in
the book are freely available, ready to use and experiment
with by way of a download from Elektor.
ISBN 978-1-907920-61-5

LEARN

Elektor International Media BV


www.elektor.com
Andrew Pratt
DESIGN

LEARN DESIGN SHARE

LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIG
SHARE

N • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHA
SIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LE
• LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN
RN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SH
Table of Contents

Table of Contents

Preface to the Second Edition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

Chapter 1    Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.2   Getting the Operating System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.3   Finding Your Way Round . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.4   File and Directory Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1.5   Wild Cards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

1.6   Redirection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1.7   Working with the Python Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1.8   File Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1.9   Bash Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

1.10   The X-Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

Chapter 2    Getting Started with Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.2   Installing Python 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.3   Start Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.4   IDLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.5   Interactive Sessions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.6   Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.6.1   Integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.6.2   Floats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.6.3   Strings and Writing To and Reading from Files . . . . . . . . . . . . . . . . . . . . . . 26

2.6.4   Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

2.6.5   Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

2.6.6   Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

2.7   Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

2.8   Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

2.9   Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

2.10   Bit and Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

2.11   Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

●5
Python 3: Programming and GUIs for Electronic Engineers
2.12   Hexadecimal Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

2.13   Persistence of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

2.14   Compiled Python Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

2.15   Unicode Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

2.16   Bytes and Bytearrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

2.17   Encoding and Decoding Bytes and Unicode . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

2.18   Variable names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

Chapter 3    Graphic User Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

3.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

3.2   Tkinter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

3.2.1   Click to Start Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

3.3   Adding Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

3.4   Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

3.5   Grid Manager Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

3.5.1   Simple Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

3.5.2   Nested Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

3.6   Inputting and Outputting Data with Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

3.6.1   Scale Widget and Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

3.6.2   Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

3.6.3   Control Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

3.6.4   Check Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

3.6.5   Radio Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

3.6.6   The Canvas Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

Chapter 4    Object Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4.2   Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4.3   Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

4.4   Summary of Object Orientation (OO) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Chapter 5    The Arduino Uno as a Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.2   The Master Slave Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.2.1   USB Serial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

●6
Table of Contents
5.2.2   Uploading the Arduino Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.2.3   Configuring the Arduino with its Address and Project ID . . . . . . . . . . . . . . . 82

5.3   The Uno Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

5.3.1   Creating Instances of Slaves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

5.3.2   Writing to Digital Output Pins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

5.3.3   Reading from Digital Input Pins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

5.3.4   Writing to Analogue Output Pins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

5.3.5   Reading from Analogue Input Pins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

5.3.6   Summary of the IO Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

5.4   Practical Examples Using Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

5.4.1   Write to Digital Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

5.4.2   Write to Analogue Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

5.4.3   Read from Digital Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

5.4.4   Read from Analogue Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

5.5   The Slave State Diagram and the Communications Protocol . . . . . . . . . . . . . . . . 95

5.5.1   The Slave State Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

5.5.2   Control of Traffic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

5.5.3   The Telegram Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

5.6   The Python End of the Communications Protocol . . . . . . . . . . . . . . . . . . . . . . . . 99

Chapter 6    Further Examples of GUIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

6.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

6.2   A Graph Plotting Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

6.2.1   Passing Arguments to a Function without Specifying How Many (*args) . . . 102

6.2.2   Passing Arguments to a Function with Keyword Arguments . . . . . . . . . . . . 102

6.2.3   Binding Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

6.2.4   The Module __name__ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

6.2.5   Following the Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

6.3   CR Charge Discharge Experiments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

6.4   Plotting Transistor Characteristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

6.4.1   Threading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

Chapter 7    Bit Map Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

7.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

●7
Python 3: Programming and GUIs for Electronic Engineers
7.2   The Bit Map File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

7.3   Reading and Writing to Binary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

7.4   The Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

7.5   The Modified Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

7.6   The Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

7.6.1   The Struct Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

7.7   Junk Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

7.8   Class BmpDraw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

Chapter 8    A Project to Monitor Your Electricity Consumption . . . . . . . . . . . . . . . . . 131

8.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

8.2   The Probe and Remote Sensing Head . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

8.3   The PIC Microcontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

8.3.1   The Arduino Slave as a PIC Programmer . . . . . . . . . . . . . . . . . . . . . . . . . 134

8.4   The Radio Link and the Arduino Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

8.5   Commissioning the System and the Desktop Program. . . . . . . . . . . . . . . . . . . . 135

8.5.1   The Desktop Calibration Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

Chapter 9    Web Browser Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

9.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

9.2   HTML 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

9.3   CherryPy a Python Web Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

9.3.1   User Input using Web Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

9.4   The Ammeter and Current Trend Web Applications . . . . . . . . . . . . . . . . . . . . . 150

9.4.1   The Uno Slave Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

9.4.2   The CherryPy Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

9.5   The Raspberry Pi as a Web Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

9.5.1   Configuring Wi-Fi from the Command Line on the Pi . . . . . . . . . . . . . . . . 158

9.5.2   Running the Python Programs Automatically After Boot. . . . . . . . . . . . . . . 159

9.6   Access from the Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

9.7   Adapting this Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

Chapter 10    Curses Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

10.1   Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

10.2   Getting Started with Curses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

●8
Table of Contents
10.2.1   The Wrapper Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

10.2.2   Windows on the stdscr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

10.2.3   Colour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

10.3   Custom Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

10.3.1   An Indicator Lamp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

10.3.2   An Analogue Gauge Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

10.3.3   Combining Attributes with the Bitwise OR Operator . . . . . . . . . . . . . . . . 173

10.3.4   Mouse Events for User Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

10.3.5   A Thumbwheel Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

10.3.6   A Button Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

10.3.7   A Label Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179

10.4   The Module with all the Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

Appendix A   Arduino Uno Slave Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

Appendix B   The Python Uno Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

B.1   Pydoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

Appendix C   The Arduino Slave Programming Tool . . . . . . . . . . . . . . . . . . . . . . . . . 201

Appendix D   The Arduino Slave ID Setting Tool Source Code . . . . . . . . . . . . . . . . . . 203

Appendix E   The PIC Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

Appendix F   The PIC Programming Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

F.1   12F1622_PROGRAMMER_V1.0.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

Appendix G   The Curses Widgets Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

G.1   Curses_widgets.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

●9
Preface to the Second Edition

Preface to the Second Edition

This book is intended to be a practical guide to interfacing simple hardware projects


with a PC. There are many topics covered in the book. They are not a random selection
and have been included as each is required to achieve the aim of communicating with a
particular interface device which has been selected for its availability and low cost.
The device is the readily available Arduino Uno. As this book is about Python, an Arduino
Sketch is provided that allows the reader to use Unos as slaves. The Python programs run
on a Linux PC to control external electronic circuits through the Unos’ inputs and outputs.
More than one of these slaves can be included in each project as each is given a unique
address.
By the end of the book you will be able to control and monitor hardware from your own
desktop graphic user interface (GUI) or web browser over the Internet. To do this, the
book will explain how to program in Python, write web pages, and use Python as a web
server. Some electronic circuits will be presented to integrate with the software projects.
One of the projects will be to monitor the current consumption of a building or house.
Another project will plot the characteristics of a transistor.
Also an introduction to Linux is given. The chosen distribution is Debian but any of its
derivatives such as Ubuntu, Mint or Raspbian if you want to use the Raspberry Pi will
do. The first edition of this book made use of a customised live Linux CD with all the
programs and necessary software on it. However in the time the first edition was in print,
this distribution became out of date so it is felt that you should always use a current
distribution. The exercise programs are available as a download from the Elektor website.
Debian has been chosen because of its ease of installing applications, stability and
popularity.
It should be appreciated that none of the topics are covered in depth. However enough
information is provided to achieve the aim and give the reader a start in each of these.
Each chapter that deals with a new topic will not try to cover everything in that chapter,
but subsequent chapters will add to those topics as required. There is a huge amount of
documentation available on the Internet. The problem is knowing in which direction to go
to get started as practical projects involve a range of topics. This book should give you a
starting level that you can build on.
It assumes the reader is familiar with using a computer but no knowledge of
programming is expected. A basic knowledge of electricity and discrete electronic
components such as resistors, capacitors, switches, and LEDs is required. An ability
to solder will be useful but the projects can be tried out using solderless breadboards.
Breadboards can be cheaper overall because components and wire can be reused. Also
construction is much quicker.
This is the second edition of the book and there are four major changes: Python 3 is used
throughout instead of Python 2, the Arduino Uno board is the target hardware interface
instead of the FTDI FT245 development board, a standard Debian type distribution is
used, and instead of using the Apache Web Server, a Python web framework is used for
serving web pages.
I hope you find this book interesting and fun.

● 11
Chapter 1 • Linux

Chapter 1 •  Linux

1.1 • Introduction

Linux has been chosen as the OS (operating system) because as you will see as you read
the book you have so much freedom to change things and experiment. If you are already
an experienced Linux user and are used to using the command line you will be familiar
with the contents of this chapter. You might use Linux but never venture away from the
graphic interfaces provided or perhaps you are completely new to Linux. The examples
shown in this book were developed using Debian 8 Jessie, the current stable release.
There are several Debian based distributions available. Two popular examples are Mint
and Ubuntu and if you want to use a Raspberry Pi there is Raspbian.

1.2 • Getting the Operating System

Here I am assuming that you either have or want to install a Debian based OS. If this is
not the case you could try using a virtual machine such as VirtualBox that will allow you
to keep your existing OS, however this might run slower than is desired. At the time of
writing, Debian can be obtained by download from "https://www.debian.org/distrib/netinst".
It is not difficult to install.

1.3 • Finding Your Way Round

If you are new to Linux things are going to seem strange at first, particularly the file
directories. Throughout the book we are going to be using the command line to access
files and start applications etc. This might seem like a backward step, but the Linux
command line is full of quick short cuts and time saving tricks. Also while writing
programs the same command line statements will sometimes need to be put into the
code.
Find on your Desktop or Applications Menu for your OS the icon for a "Terminal Emulator"

 Figure 1-1  Terminal Emulator


Figure 1-1 shows that we are in our home directory, the ~ means home directory. This is
the home directory of the user named "user".
As an introduction to the command line, type "cd /" without the quotation marks. Press
return, then type "ls" and press return. The result is shown below; directories show up
in blue. There are many commands available for different tasks and you quickly learn
the common ones. "cd" means change directory and "ls" means list the contents of a
directory.

● 13
Chapter 2 • Getting Started with Python

Chapter 2 •  Getting Started with Python

2.1 • Introduction

Microprocessors handle numbers. These numbers are represented physically by using


the binary system implemented as voltages. When a computer handles text it is still
handling numbers. For example the character "A" is 65 in the American Standard Code
for Information Interchange (ASCII). One of the changes between Python 2 and 3 is
the way text is encoded. ASCII used to be the way text was encoded under Python 2 by
default. Python 3 uses Unicode; the difference will be dealt with at the end of the chapter.
Unicode is a very important topic that needs to be understood.
At a most basic level, a microprocessor could have its code written by a human in
machine code, which are the numbers that represent the instructions and data. An
improvement is to use an assembler, which is a program that accepts human friendly
abbreviations for the machine code and writes a file that is the machine code. On the left,
Program 2-1a is a short program written for the assembler FASM.
Program 2-1  Example of assembler and 'C' coding

;prog_02_01.asm //prog_02_01.c

format ELF executable #include<stdio.h>


jmp main
message db "It’s a lot easier in Python!",10 int main(){
len equ $-message
printf("It's a lot easier in python\n");
main:
mov edx, len return 0;
mov ecx, message
mov eax, 4 }
int 0x80

mov eax, 1
int 0x80;
Prog 2-1a (prog_0201.asm) Prog 2-1b (prog_02_01.c)

The source code prog_02_01.asm has been assembled to an executable file


assembler_demo and is on the zip file. If you want to, you can run it at the command
line as follows (make sure you are in the same directory as the file and then type ./
assembler_demo, actually ./a tab should then auto-complete for you):

user@debian:~/programs/chap02_progs$ ./assembler_demo
It’s a lot easier in python!
user@debian:~/programs/chap02_progs$

Assembler is still used where the utmost speed is important or in applications


such as small micro-controllers with limited memory. It requires knowledge of the
microprocessor’s architecture and other hardware details by the programmer and the
code is not portable to other platforms.
Program 2-1b does the same as the assembler program using C. C uses a program called
a compiler that allows you to write in a form that is more readable and deals with the
details of the hardware. The compiler takes the C source code written by a human and
compiles it into executable files that can be run by the processor through your

● 21
Python 3: Programming and GUIs for Electronic Engineers

operating system.
So if that's what a C compiler does, why are we going to need Python? Basically Python
is a whole lot easier to use than C. Python is an interpreted language. The Python
interpreter has to be installed on the computer for the operating system you are using.
Python is a cross platform language. Python takes your script and compiles it into
something called byte code that runs on a virtual machine on your operating system;
this compilation occurs when you start a program. This is slower than a compiled C
program but what is too slow depends on what you’re doing. Python is fast enough for
the applications in this book.
In Python the above programs would be:

print (“It’s a lot easier in Python!”)

To any readers who are new to Python 3 but have some experience of Python2 you will
notice some things have changed, for example the "print 'Hello World'" statement is now
a function and is written as "print('Hello World')". There are other differences.

2.2 • Installing Python 3

This book deals with Python 3. Although Python 2 is still widely used, if you are new to
Python you should start with Python 3. First check to see if Python 3 is installed by typing
"python3" at the command line.

user@debian:~$ python3
Python 3.4.2 (default, Oct 8 2014, 13:14:40)
[GCC 4.9.1] on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>>

This puts you into an interactive session with Python which we will deal with later, so to
escape from this use "Ctrl d", that is to press the Control key and d simultaneously.
Make sure you have Python 3. If not it can be easily installed. While connected to the
Internet, type this at the command line:

user@debian:~$ sudo apt-get install python3

One of the really good features of a Debian based Linux OS is the package management
that makes installation and removal of software very easy. Not all Linux distributions are
this easy, notably Slackware. Although my favourite, it can be a lot more work as you
have to manually find and install any other software that the software you are installing is
dependent on. These dependencies can go to several layers.

2.3 • Start Programming

Open Mousepad by pressing Alt + F2 and entering "mousepad". Alternatively use any
text editor you prefer. Type in the following program (Note how lines two and three are
indented - this is part of the code logic. Although the code is provided typing some of the
programs will help to familiarise you with the language):

● 22
Chapter 3 • Graphic User Interfaces

Chapter 3 •  Graphic User Interfaces

3.1 • Introduction

As far as functionality is concerned, adequate programs can be written with just the
command line as an interface. However a graphical interface is much more attractive,
offering the usual widgets that most computer users are used to using: buttons, check
buttons, text entry boxes, etc. Python offers a simple way of creating these interfaces for
your programs. Two of the projects later in the book will plot graphs of values derived
from analog quantities being measured. The last chapter will show you another way of
producing GUIs for platforms that have lower resources and do not need the X-server. As
mentioned before, there is no intention of trying to treat any of the topics in the utmost
depth but rather to give the reader a set of useful introductory tools to build projects that
work and give pointers to further learning. Presented here are some simple examples.
The best way to understand them is to run and experiment with them.

3.2 • Tkinter

Tkinter is the standard library that provides python bindings to Tk which is a graphical
programming library. Tkinter offers a great deal of variety. I have presented a few
example programs that do not by any means cover all of what is available. I would
recommend running the example programs and altering them to suit you. The widgets
that make up the interface have attributes with particular names, only some are in the
example programs.
Firstly you should test to see if you have tkinter installed. Start a Python 3 interactive
session and try "import tkinter". If it is not installed you will get the result below:

user@debian:~$ python3
Python 3.4.2 (default, Oct 8 2014, 13:14:40)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
Traceback (most recent call last):
File "/usr/lib/python3.4/tkinter/__init__.py", line 39, in <module>
import _tkinter
ImportError: No module named ‘_tkinter’

During handling of the above exception, another exception occurred:

Traceback (most recent call last):


File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/tkinter/__init__.py", line 41, in <module>
raise ImportError(str(msg) + ‘, please install the python3-tk package’)
ImportError: No module named ‘_tkinter’, please install the python3-tk package
>>>

To install tkinter, do the following at the command line while connected to the Internet.

user@debian:~$ sudo apt-get install python3-tk

● 59
Python 3: Programming and GUIs for Electronic Engineers

We will start by creating the simplest graphical program that creates an empty window
and then does nothing other than resize, minimize, maximize and close. These three
lines of code actually do a lot of work.
Program 3-1  Empty window

#prog_03_01

import tkinter

root = tkinter.Tk() # Tk() is the top level class.


root.mainloop() # Mainloop is the loop that responds to events like button clicks.

Although there are only three lines in this program, there are three new things to point
out. First we import "tkinter", the package we need to create the GUIs.
Second the line "root = tkinter.Tk()" is an example of creating an instance of a class,
something we will go into in more detail in the chapter on Object Oriented Programming
(OOP). Here root is the name that is given, in this case to an instance of the class Tk,
the name is your choice. As a real world analogy you are an instance of the class of
humans and have a name. Third the line "root.mainloop()" means that having created the
instance root, we call the "mainloop()" function or method that runs the event driven loop
that controls our interface. Pressing a button would be an event and cause something to
be done by calling some function in your program.
We will now build some very short example GUIs to see how to add widgets, call functions
to react to events, and control the layout and appearance. Different widgets will be
introduced as we progress.

3.2.1 • Click to Start Programs

Up until now our programs have been started using the command line instruction
"python3 prog_xxx.py". We can make the script executable by using the command line
instruction "chmod 755 prog_xxx.py". This will change the file permissions (see Chapter
1.8 on page 18). In order for the script to run, the first line is added "#!/usr/bin/
env python3". Although this looks like a comment, it starts with "!" then the path to
the Python interpreter. When put on the first line, Linux knows to call "python3" to run
the script. We can start the program either from the command line with "./prog_03_02.
py" the "./" (means look for the file in the current directory) or you can double click on
the file in the File manager. Another way is to copy the executable script to the Desktop
from where it can run from by double clicking on it. I would recommend starting from the
command line when debugging programs.

● 60
Python 3: Programming and GUIs for Electronic Engineers

3.6.1 • Scale Widget and Label

The scale widget can be used as in input and output interface. It is particularly useful for
control applications because it mimics a traditional analogue control device. This next
program, Program 3-7 also introduces the Label widget, which presents read only text
to the user. In the program, a Scale called ‘scale_in’ is created with options to set it as
horizontal, 500 pixels long, a resolution of 0.1 and to call the ‘drive_output()’ function
when it is moved. Not apparent by inspecting the code, the scale passes a value of
its position to the function being called, so we have the argument ‘scale_value’ in the
function. It can be any legal name. This variable is a string holding the floating value of
the position. The value of the scale position is converted to a floating point assigned to
the local variable r. The text for the label has been formatted to give five decimal places
in the circumference output and a minimum width including the decimal point of nine
characters. The radius output has one decimal place and a width of five characters. Both
have been padded with leading zeros. This gives a smoother digital display without the
position jumping. The "\t" inserts a tab space in the string. To get the value of pi, the
math library has been imported.
Program 3-7  Label widget

#!/usr/bin/env python3
#prog_03_07.py

import tkinter
import math

def drive_output(scale_value):
r = float(scale_value)
c = 2 * math.pi * r
lbl_out.configure(text = ‘Radius {0:05.1f} \t-\t Circumference {1:09.5f}’.format(r, c))

root = tkinter.Tk()

root.title(‘Scale Input’)
scale_in = tkinter.Scale(orient = ‘horizontal’, length = 500, resolution = 0.1, command = drive_output)
lbl_out = tkinter.Label()
lbl_out.grid(row = 0, column = 0, pady = 10)
scale_in.grid(row = 1,column = 0, pady = 10, padx = 10)

root.mainloop()

Program  3-8 on page 67 uses another Scale to display the output value. Here the
scale’s set() method is used to determine the position of the slider. Also added are
"tickinterval" markers and an option called label that is part of the Scale object.
A "commented out" line is the alternative method of obtaining the scale position directly
as a float. To try this move the comment prefix # to the other line. The definition of the
‘scale_out’ does not include a call back as it is being used as an output widget not an
input.
The lines that create the instances of Scale, scale_in and scale_out are long lines of code
and it is recommended to limit printed lines in the editor to 80 characters. You can fold
back code over more lines if that part is enclosed in parenthesis which this part is.

● 66
Chapter 3 • Graphic User Interfaces

Program 3-8  Scale to display

##!/usr/bin/env python3
#prog_03_08.py

import tkinter
import math

def drive_output(scale_value):
r = float(scale_value)
#r = scale_in.get() # Can also be used
c = 2 * math.pi * r
scale_out.set(c)

root = tkinter.Tk()
root.title(‘Scale Input’)

scale_in = tkinter.Scale(orient = ‘horizontal’, length = 500, resolution = 0.1,


command = drive_output, label = ‘Radius’, tickinterval = 10)

scale_out = tkinter.Scale(orient = ‘horizontal’, length = 500, resolution = 0.1,


label = ‘Circumference’, tickinterval = 100, to = 700)

scale_out.grid(row = 0,column = 0, pady = 10, padx = 10)


scale_in.grid(row = 1,column = 0, pady = 10, padx = 10)

root.mainloop()

3.6.2 • Entry

If you want to type in data directly, the Entry widget can be used to accept a single line of
text.
Program 3-9 below takes a text input of a numerical value. When the button is clicked,
the function Calculate() converts the string in the Entry to a float and squares it putting
the answer in the label. There is no protection here for non numerical data being entered.
You can have your code put a string in the entry box by using the method insert(index,
s) where s is the string to insert in the entry box and it gets inserted before the position
index. 
Program 3-9  Text input

#!/usr/bin/env python3
#prog_03_09

import tkinter

def calculate():
x_string = ent_input.get()
x = float(x_string)
y = x*x
y_string = str(y)
lab_output.configure(text = y_string)

root = tkinter.Tk()
root.title(‘Entry’)
ent_input = tkinter.Entry(root)
ent_input.insert(0,’0.0’)

lab_output = tkinter.Label(root,text = ‘0.0’)

● 67
Chapter 4 • Object Oriented Programming

Chapter 4 •  Object Oriented Programming

4.1 • Introduction

So far our programs have been what are called procedural programs. Object orientation
is a different way of writing programs. It is about creating software models of real world
items as separate objects; these objects contain the data and the functions that are
associated with objects. Please be aware that the treatment of this topic is just enough
to achieve the aim of producing working interfaces. We will introduce new concepts, the
class, and inheritance. The objects we are talking about here are individual instances
of a class. You are an instance of the class human. You have a name which can be used
to distinguish you from other instances of the class human. The class of human has the
attribute height if your name is jsmith. Your height might be “jsmith.height = 1.6”.

4.2 • Class

The block of code that is the class is like a factory that produces instances of that class.
These instances encapsulate data and methods, methods being the term used for
functions in classes. This is a convenient way of programming as programs get more
complicated.
Let us consider for an initial example the electronic circuit of the voltage comparator.
If the input voltage is above a certain level, we will call the setpoint, then the output is
on, otherwise it is off.
In python we could create a class to represent voltage comparators like these, as in
Program 4-1. This program has a class named “Comparator”. The class is used to create
two instances of voltage comparators that have different setpoints.
To create a class, we start with the word “class” then give it a name, in this case
Comparator. It is the convention to start class names with a capital letter.
Indented below this first line is the rest of the class. Our class here has two methods.
Moving down to the line “comp1=....”, after the end of the class code, this line creates an
instance of a voltage comparator I have called comp1.
When creating an instance of a class, the method __init__ () of that class is called
automatically, if it exists. The word init has two underscores on both sides. Now look
at this method: there are two arguments, the first is “self” meaning that the function
belongs to this instance.
Program 4-1  Voltage comparators

#!/usr/bin/env python3
# prog_04_01a.py

class Comparator:
def __init__(self, setpoint): # Method runs whenever a new instance is created
self.switch_level = setpoint
self.output = False
def switching(self, voltage):
if voltage > self.switch_level:
self.output = True
else:
self.output = False # End of class code

● 73
Python 3: Programming and GUIs for Electronic Engineers

comp1 = Comparator(5) # Creates instance comp1, calls method __init__


comp2 = Comparator(6) # Creates instance comp2, calls method __init__

print(‘comp1 output is {}’.format(comp1.output))

print(‘comp2 output is {}’.format(comp2.output))

The second argument which I have named setpoint is the argument passed to the __
init__() method whenever a new instance is created. Here the value is 5. The next line
sets the variable switch_level to 5 which will be the setpoint for the comparator comp1.
Again the self means that this variable belongs to the instance being created. The last line
of __init__() sets the variable output to off or False.
Moving on to the line “comp2=.......”, this line creates another instance of Comparator
but this time when __init__() runs, the setpoint is set to the value 6.
Figure 4-1 is a pictorial overview of this instance creation.
Looking at the last two line of the program, these lines print out the states of the outputs.
The function switching(self, voltage) has not been called yet.

 Figure 4-1  Pictorial overview of instance creation


Running Program 4-1 at the command line gives the following.
user@debian:~$ ./prog_04_01a.py
comp1 output is False
comp2 output is False
user@debian:~$

Now let’s apply an input voltage of 5.5 to our two instances of the Comparator class.
This is the purpose of the switching(self, voltage) method.
To call the switching() method of comp1 with an input value of 5.5 you use “comp1.
switching(5.5)” and for comp2, “comp2.switching(5.5).
Program  4-2 on page 75 shows these program lines added and two lines to print out
the new output states.

● 74
Chapter 5 • The Arduino Uno as a Slave

Chapter 5 •  The Arduino Uno as a Slave

5.1 • Introduction

The first edition of this book used the Future Technologies Development International
(FTDI) UM245 USB interface to read and write single bytes from and to the project
hardware. The approach of this book is to use the Arduino Uno as a slave. No code writing
is required for the Uno as an Arduino Uno universal sketch is provided. This makes the
Arduino respond to programs written in Python on the PC which is the master. The sketch
is provided as a hex file that AVRDUDE can load into your Arduinos. A Python tool is
provided in the programs.
This chapter shows how to program and configure Arduinos and will give an overview of
how to use the communication functions in Python to command the slaves. At the end
of the chapter, more details on the protocol will be given, although useful information on
fault finding can be read later.

5.2 • The Master Slave Design

The programs written in Python have GUIs that the user can use to monitor and control
real electronic hardware. The Arduino Uno provides a hardware interface of digital and
analogue inputs and outputs (IO) that can be connected to electronic circuits. The
Arduino is the slave and the PC running the Python program is the master. For reliable
communications between the Python program and the IO, a serial communications
protocol is provided that has a number of functions that transmit data in frames back and
forth. Each frame has an error detecting check sum.

5.2.1 • USB Serial

Before your Python programs can talk to the slave, you will need to install the Python
serial library. This is very easy from the command line, just type the following:

user@debian:~$sudo apt-get install python3-serial

This is needed to use the USB serial interface. However you will need to add yourself
to the "dialout" group otherwise you will not have permission to open the ports "/dev/
ttyACM*".
To add yourself to the "dialout" group, type the following at the command line:

user@debian:~$sudo usermod -a -G dialout user

Note use your username where I have put "user".

5.2.2 • Uploading the Arduino Program

The Arduino program (sketch) has already been written using the Arduino C/C++
functions and has been compiled to a ".hex" file that you can upload to your Arduino Uno.
This is done using AVRDUDE, an open source project written by Brian S Dean. AVRDUDE
is a command line utility that requires several command line arguments. A Python GUI
tool is presented here to make it easy. Figure  5-1 on page 82 shows the user interface.
Installing AVRDUDE is easily done by typing this at the command line:

● 81
Python 3: Programming and GUIs for Electronic Engineers

user@debian:~$ sudo apt-get install avrdude

When this has completed you can then use the Python GUI tool.

 Figure 5-1  Slave programming tool


To use the programming tool, proceed as follows.
• Run the program "arduino_slave_programming_tool_V1.0.py" in the programs
for this chapter in the zip file. Start the program without your Arduino USB
lead unplugged. Ensure that you run the program from this directory, see the
explanation below.
• Click the "Scan" button and note any ports displayed in the window.
• Plug in the Arduino to be programmed and click on the "Scan" button again.
The port used by the Arduino should appear.
• Select this port and then click on the "Program" button. The output window
should display as shown above.
The programming tool has to access the hex file that it knows by the name of slave.hex.
It is a copy of the hex file for the current sketch, Arduino_Slave_17_03_26a.ino.standard.
hex. If you move the programming tool to a different directory you must move the file
slave.hex as well.

5.2.3 • Configuring the Arduino with its Address and Project ID

You might have more than one project in existence, so to prevent accidentally running the
wrong software with a hardware project the Arduino is given a project identity number.
The master program on the PC will only command Arduinos with their project ID. Also
you might have more than one Arduino in your project so the slaves are given an address
within this project.
These two numbers are written to the Electrically Erasable Programmable Read-Only
Memory (EEPROM) in the Arduino with another tool provided in the zip file. The address
and the project numbers are retained in the EEPROM when the Arduino is powered off so
they only have to be entered once for each project.

● 82
Chapter 5 • The Arduino Uno as a Slave

 Figure 5-9  Arrangement to write to digital outputs


Program 5-1  Use check buttons to select state of output

#!/usr/bin/env python3
#prog_05_01.py

import tkinter
import uno_slave

class GuiDigOuts():
def __init__(self, master):
self.uno1 = uno_slave.Uno(address = 1,project = 1, config_digital = [2,3,4,5,6,7,8,9])
master.title(‘Write Digital Outputs’)
self.chkvar_2= tkinter.IntVar() # Control variables
self.chkvar_3= tkinter.IntVar()
self.chkvar_4= tkinter.IntVar()
self.chkvar_5= tkinter.IntVar()
self.chkvar_6= tkinter.IntVar()
self.chkvar_7= tkinter.IntVar()
self.chkvar_8= tkinter.IntVar()
self.chkvar_9= tkinter.IntVar()
self.chkbtn_2 = tkinter.Checkbutton(master,text = ‘Pin 2’, variable = self.chkvar_2)
self.chkbtn_3 = tkinter.Checkbutton(master,text = ‘Pin 3’, variable = self.chkvar_3)
self.chkbtn_4 = tkinter.Checkbutton(master,text = ‘Pin 4’, variable = self.chkvar_4)
self.chkbtn_5 = tkinter.Checkbutton(master,text = ‘Pin 5’, variable = self.chkvar_5)
self.chkbtn_6 = tkinter.Checkbutton(master,text = ‘Pin 6’, variable = self.chkvar_6)
self.chkbtn_7 = tkinter.Checkbutton(master,text = ‘Pin 7’, variable = self.chkvar_7)
self.chkbtn_8 = tkinter.Checkbutton(master,text = ‘Pin 8’, variable = self.chkvar_8)
self.chkbtn_9 = tkinter.Checkbutton(master,text = ‘Pin 9’, variable = self.chkvar_9)
self.btn_write = tkinter.Button(master,text = ‘Write’, command = self.dig_write)

self.chkbtn_2.grid(row = 0, column = 0, pady = 5, padx = 5)


self.chkbtn_3.grid(row = 0, column = 1, pady = 5, padx = 5)
self.chkbtn_4.grid(row = 0, column = 2, pady = 5, padx = 5)
self.chkbtn_5.grid(row = 0, column = 3, pady = 5, padx = 5)
self.chkbtn_6.grid(row = 0, column = 4, pady = 5, padx = 5)
self.chkbtn_7.grid(row = 0, column = 5, pady = 5, padx = 5)
self.chkbtn_8.grid(row = 0, column = 6, pady = 5, padx = 5)
self.chkbtn_9.grid(row = 0, column = 7, pady = 5, padx = 5)
self.btn_write.grid(row = 1, column = 0, columnspan = 8)

● 89
Python 3: Programming and GUIs for Electronic Engineers

def dig_write(self):
self.uno1.write_digital_dict[2] = self.chkvar_2.get()
self.uno1.write_digital_dict[3] = self.chkvar_3.get()
self.uno1.write_digital_dict[4] = self.chkvar_4.get()
self.uno1.write_digital_dict[5] = self.chkvar_5.get()
self.uno1.write_digital_dict[6] = self.chkvar_6.get()
self.uno1.write_digital_dict[7] = self.chkvar_7.get()
self.uno1.write_digital_dict[8] = self.chkvar_8.get()
self.uno1.write_digital_dict[9] = self.chkvar_9.get()
self.uno1.write_digital()

tk = tkinter.Tk()
front_end = GuiDigOuts(tk)
tk.mainloop()

Program 5-2 is for the same circuit. It drives one LED on at a time so that the position
of the lit LED moves backwards and forwards. The speed of the change of position is
controlled by a scale. This program introduces a useful technique for calling a method at
intervals. Top level windows, in this case our master has a function called self.master.
after() that calls a function after a time interval. Here we are using it at the end of the
method drive() to call drive() again. The time interval is determined by the position
of the scale. Unlike using time.sleep(), the method after() does not block or in other
words stall the flow of the program. A point to remember is that sleep() has the time
interval expressed in seconds using a float, and the after() method has the time interval
expressed in milliseconds using an integer.
Program 5-2  Call a method at intervals 

#!/usr/bin/env python3
#prog_05_02.py

import tkinter
import uno_slave
import time

class GuiDigOuts():
def __init__(self, master):
self.master = master
self.uno1 = uno_slave.Uno(address = 1, project = 1, config_digital = [2,3,4,5,6,7,8,9])
self.master.title(‘Write Digital Outputs - Timed Sequence’)
self.rate_scale = tkinter.Scale(master, orient = ‘horizontal’, length = 500, from_ = 1,
to = 100, tickinterval = 10,label = ‘Step Interval (ms)’)

self.uno1.write_digital_dict = {2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,}


self.step = 2
self.direction = 1
self.rate_scale.grid(row = 0, column = 0, padx = 10,pady = 10)
self.drive()

def drive(self):
self.uno1.write_digital_dict[self.step] = 0
if self.step == 9:
self.direction = -1
if self.step == 2:
self.direction = 1

self.step = self.step + self.direction


self.uno1.write_digital_dict[self.step] = 1
self.uno1.write_digital()
delay = self.rate_scale.get()
delay = int(delay)

● 90
Chapter 6 • Further Examples of GUIs

Chapter 6 •  Further Examples of GUIs

6.1 • Introduction

This chapter moves on to more advanced GUIs and introduces further aspect of Python
and Tkinter. The GUIs will be all about interfacing with the Arduino slave. You must read
Chapter 5 on page 81 before trying the projects in this chapter in order to understand
how the Arduino is used here. The programs presented will be object oriented. The
programs will be getting longer and more complicated. This is where object oriented
programming starts to make things more manageable. If you have trouble understanding
parts of the code, try experimenting by changing one part at a time; this can be great
help towards understanding. Also some more Python features will be introduced.

6.2 • A Graph Plotting Class

As shown in Chapter 3 on page 61, there are a lot of standard widgets available but
you have to write code to make them do what you want. Often something similar crops
up in more than one program that would result in duplicating code and wasting time.
One such example is to plot a graph of the analogue inputs against time. The following
program is a class that can be used to create instances of an object that will do this and
require very little code to include it in other projects. The class that is called Graph and it
will be in a module or separate file.
Figure 6-1 shows a GUI that will be Program  6-2 on page 110, the custom widget with
the canvas and two buttons Reset and Flyback can be seen with its raised border, is an
instance of the class Graph. This widget can be placed in any GUI you write, simply by
importing the module plotter and creating an instance of Graph and calling its methods.
Program 6-1 below is plotter.py. The class plots up to six analogue inputs simultaneously
against time. Measurements on the graph can be taken by using the mouse to point to
a position on the graph and left clicking. The Flyback button causes the graph to restart
plotting from the left end without deleting anything. The Reset button also restarts from
the left end but also clears the canvas. As well as the time saving, this approach gives the
benefit of dependability that the code can be relied upon and only needs to be imported
and used.

 Figure 6-1  GUI created by Program 6-2

● 101
Python 3: Programming and GUIs for Electronic Engineers

6.2.1 • Passing Arguments to a Function without Specifying How Many (*args)

Up until now we have been specifying the arguments that are being passed to a function,
see paragraph 2.7 on page 42. Suppose that we want to pass different numbers of
arguments depending on the application. In Program  6-1 on page 103, notice the
function definition "def plot (self, *args)". Here we can pass up to 6 analogue input values
to be plotted. In the function, args is a tuple that contains all the arguments passed from
the calling function. The word args is not mandatory, it is just the convention. What is
important is that it is prefixed with the single *.
Here is an example you can try in an interactive session.

>>> def fun(*args):


... print(args)
...
>>> fun('first_argument', 100.05, 99, 'last_argument')
('first_argument', 100.05, 99, 'last_argument')
>>>

The function fun() is called with four arguments: the first a string, the second a float,
the third an integer and finally another string. In the function definition *args is used.
The function prints args; you can see that this is a tuple. If we use the built in method
enumerate() we can obtain index numbers and values for the arguments that have been
passed regardless of how many there are. The function enumerate() yields two values:
one being an enumeration of the position of the argument and the other being its value.

>>> def fun(*args):


... print(args)
... for i, v in enumerate(args):
... print('argument {0:d} = {1:s}'.format(i,str(v)))
...
>>> fun('first_argument', 100.05, 99, 'last_argument')
('first_argument', 100.05, 99, 'last_argument')
argument 0 = first_argument
argument 1 = 100.05
argument 2 = 99
argument 3 = last_argument
>>>

In the method plot() (Program 6-1), the arguments for the analogue inputs are
enumerated to be the variable channel and y the value. The variable palette is a list of
different colours for each analogue input.

6.2.2 • Passing Arguments to a Function with Keyword Arguments

If you look at the __init__() method for the class two of the arguments are keyword
arguments scale_x and scale_y. They are after the two positional arguments height and
width. Keyword arguments have default values that they take if they are not passed by
the calling method these are the values after the equal signs. If values are passed by the

● 102
Chapter 7 • Bit Map Graphics

Chapter 7 •  Bit Map Graphics

7.1 • Introduction

This chapter is mainly about the anatomy of bit map images and how to operate on
them. In the last chapter the canvas widget was used to draw on when producing GUIs
in Tkinter. What if you want to plot a graph and save it as an image file? Python does
provide a method for saving canvases as postscript files, but what we will do in this
chapter is create and modify bitmap images that can be saved and read by any image
viewer. Bit map images are very easy to manipulate as they are an array of pixels like
points on a piece of graph paper.

7.2 • The Bit Map File

The bit map images we will be dealing with will have each pixel colour defined by three
bytes, one for each primary colour. As an illustration Figure 7-1 represents an image 8
by 6 pixels. There is a square for each pixel and a byte for each of the three colours. The
image is white except for a red line across the top and the three pixels starting from the
bottom left hand corner are red, green and blue.

 Figure 7-1  Image of 8 pixels by 6 pixels


Not shown on Figure 7-1 the bit map file starts with a string of 54 bytes which is the
header. This contains information about the image - we needn't worry about the content
of the header for now. Following the header is the actual image content, starting from
the bottom left hand corner of the image, the next three bytes are the blue, green, and
then red values of the first pixel. This continues for each pixel in the bottom row. After
the bottom row is the left most pixel of the next row up and then so on for the rest of
the image. In order to view and modify images I recommend KolourPaint. This can be
installed easily on Debian by typing the following at the command line:

user@debian:~$ sudo apt-get install kolourpaint4

● 119
Python 3: Programming and GUIs for Electronic Engineers

The image depicted by Figure  7-1 on page 119 is in the zip file, its name is fig1image.
bmp. To view it you will need maximum zoom. Figure 7-2 shows how the bytes that
define the image are sequenced in the file. The first four pixels and the last two from
Figure 7-1. Note that the order of the bytes for each pixel is blue, green and then red.

 Figure 7-2  Byte sequence in the file


The object of the exercise is to write an image file with our own program. This will be
referred to as the output file. Although we don't need to worry about the content of the
header, we do need a header for any file we create. Fortunately the header does not
depend on the image content but only on the geometry of the image and colour depth.
The easiest way to write the header for your file is to copy the header from another
image of the same size and colour depth. We will look at the makeup of the header later
in the chapter.
We will take an existing bit map file, our template image, and read it. The header will be
re-used as the header for the output file. The template file can give the program a head
start by having a background such the grid lines for a graph or the face of an instrument
to draw on top of.
Looking again at Figure  7-1 on page 119, each square is a pixel and needs three bytes
to set its colour. We can create a list with three members each being an integer from
0 to 255. This would mean the third pixel from the left hand corner would be [255, 0,
0]. If we have a separate list for each pixel we need some way of identifying these lists
in terms of where they are on the image. One python object that is ideal for this is the
dictionary. Dictionaries were covered in paragraph 2.6.5 on page 40; the members of
a dictionary are indexed by keys. See below on how any pixel from Figure 7-1 could be
held in a dictionary. The keys that we are going to use to index the lists that define the
pixel colours are tuples with two integer members. These integers are the horizontal and
vertical offsets from the bottom left hand corner of the image.

image_content_dictionary = {(7, 3): [255, 255, 255], (1, 3): [255, 255, 255], (3, 0):
[255, 255, 255],................}

● 120
Chapter 8 • A Project to Monitor Your Electricity Consumption

Chapter 8 •  A Project to Monitor Your Electricity Consumption

8.1 • Introduction

This chapter is about a larger project that will monitor the current in a mains electricity
supply. The first thing to point out that there is no direct connection to the mains wiring
required. A non-invasive technique is used involving a coil of wire placed near to the
supply cables. The probe will measure the current flowing and transmit the value to the
receiver that will be connected to the Arduino slave. A graph of current against time will
be plotted. The next chapter gives details of how to use a web browser as a GUI that can
be viewed on a mobile phone or other computer. This will allow you to view the output
when away from home. The reason for the radio link is that very often the mains incomer
to a building is not at a convenient place for a computer.
The remote sensing head driven by the coil comprises a filter, amplifier, and precision
half wave rectifier, a PIC microcontroller and a low power radio transmitter. The
PIC microcontroller is a 12F1822 and it can be programmed using a tool written in
Python that uses the Arduino slave. The code for the PIC is provided. The transmitter
and receiver are readily available from Farnell Components who have international
distribution.

 Figure 8-1  Block diagram of mains supply monitor


This chapter will also introduce some new topics by making use of the desktop application
used for this project.

8.2 • The Probe and Remote Sensing Head

The probe that was used in the prototype was a coil of insulated wire, air cored with 5
turns and a diameter of approximately 60mm, as shown in Figure  8-2 on page 132. The
pickup coil is connected to the sensing head by a length of coaxial cable. A twisted pair
could be used. This is not the usual way of measuring current in a supply cable. Normally
a current transformer with a magnetic core that one of the supply cables runs through
is used. The core has a winding on it connected to a low impedance circuit. This has the
disadvantage that either the current transformer must be fitted to the cable before it is
connected or a split core transformer must be used. Either option is not suitable for a
home construction project as even if you use a split core you probably won't have room
to fit it on a domestic installation. The method described here is completely non-invasive.
The way that this sensing coil works is that some of the magnetic field from the two
supply cables links with the coil. As one of the cables is closer to the coil than the other,
there will be a resultant field that induces a voltage in the coil. Now this is where this
method is flawed. The instantaneous magnetic flux from the supply current is proportional
to the instantaneous current in the supply cable but the voltage induced in the coil is
proportional to the rate of change of the magnetic flux. If we are only considering one

● 131
Python 3: Programming and GUIs for Electronic Engineers

frequency (50Hz in the UK), the maximum rate of change of flux is proportional to the
maximum instantaneous current, only phase shifted by 90 degrees. However there are
harmonics present in the supply current, if you compare the maximum rate of change
of a 150Hz sine wave with the maximum rate of change of a 50Hz sine wave of equal
amplitude it is three times greater, five times greater for the fifth harmonic. To overcome
this problem a low pass filter is included in the sensing head to reduce the effect of any
harmonic content in the supply. It must be pointed out that this will not give results
accurate enough for metering purposes. Please note, on the photograph the supply cables
are the two running above the coil. In the UK these are referred to as the meter tails.

 Figure 8-2  Prototype probe


Figure 8-3 shows the circuit diagram for part of the sensing head. There are three LF411
operational amplifiers used. The first one 'U1' is used as a two pole Sallen and Key low
pass Butterworth filter with a corner frequency around 50Hz. If your local supply is 60Hz
this won't matter. The second stage 'U2' is a non-inverting preamplifier with a gain of
101. Another low pass filter is added using 'R3' and 'C3'. The last stage 'U3' is a precision
half wave rectifier. The gain of the last stage is set by selecting a value for 'R7'. The gain
is the ratio of 'R7' to 'R6'. In my prototype, a value of 80kΩ was used giving a gain of
80. You might find it more convenient to use a variable resistor here. Its value will be
determined on test. Note carefully that the first two opamps U1 and U2 are connected as
non inverting amplifiers and the third U3 is connected as an inverting amplifier; in other
words get pins 2 and 3 the right way round. Capacitor C4 should be a non-polarized type
such as metalised polyester.

 Figure 8-3  Circuit diagram for the sensing head

● 132
Python 3: Programming and GUIs for Electronic Engineers

self.calibration_dict = {‘raw_offset’:0, ‘raw_to_current’:1, ‘fullscale_current’:100}

self.circ_buffer = collections.deque([], maxlen=50)


#add menus
menubar = tk.Menu(self.master)
master.config(menu=menubar)
commissioning_menu = tk.Menu(menubar, tearoff = 0)
menubar.add_cascade(label = ‘Commissioning’, menu = commissioning_menu)
commissioning_menu.add_command(label = ‘Calibration’, command = self.calibration)
commissioning_menu.add_command(label = ‘Future Use’)
commissioning_menu.add_command(label = ‘Future Use’)
commissioning_menu.add_separator()
commissioning_menu.add_command(label = ‘Future Use’)
screen_capture_menu = tk.Menu(menubar, tearoff = 0)
menubar.add_cascade(label = ‘Screen Capture’, menu = screen_capture_menu)
screen_capture_menu.add_command(label = ‘Capture’, command = self.capture)

self.num_samples = self.X
self.graph1 = plotter.Graph(master,self.X, self.Y,
scale_x = self.num_samples, scale_y = self.calibration_dict[‘fullscale_current’])
self.graph1.frm.grid(row = 0, column = 0, padx = 10, pady =10,columnspan = 3)
self.reading()

def reading(self):
self.uno1.read_analog(1)
raw = self.uno1.read_analog_dict[0]
i = (raw-self.calibration_dict[‘raw_offset’]) * self.calibration_dict[‘raw_to_current’]
y = int(i*self.Y/self.calibration_dict[‘fullscale_current’])
self.circ_buffer.append([raw,i,y])
if self.x%self.X == 0:
self.graph1.flyback()

self.graph1.plot(y)
self.x = self.x + 1
self.master.after(10000, self.reading)

def calibration(self):
self.cal_window = tk.Toplevel()
self.cal_window.title(‘Calibration’)
self.cal_output = tk.Text(self.cal_window, width = 30, height = 20, relief = ‘ridge’)
self.btn_save_cal = tk.Button(self.cal_window, text = ‘Save Calibration’, command = self.save_calibration)
self.lbl_raw = tk.Label(self.cal_window, text = ‘Raw/Current/Screen Position’)
self.lbl_offset = tk.Label(self.cal_window, text = ‘raw_offset’)
self.strvar_offset = tk.StringVar()
self.strvar_offset.set(self.calibration_dict[‘raw_offset’])
self.ent_offset = tk.Entry(self.cal_window, textvariable = self.strvar_offset, width = 10)
self.lbl_raw_to_current = tk.Label(self.cal_window, text = ‘raw_to_current’)
self.strvar_raw_to_current = tk.StringVar()
self.strvar_raw_to_current.set(self.calibration_dict[‘raw_to_current’])
self.ent_raw_to_current = tk.Entry(self.cal_window, textvariable = self.strvar_raw_to_current, width = 10)
self.lbl_fullscale_current = tk.Label(self.cal_window, text = ‘fullscale_current’)
self.strvar_fullscale_current = tk.StringVar()
self.strvar_fullscale_current.set(self.calibration_dict[‘fullscale_current’])
self.ent_fullscale_current = tk.Entry(self.cal_window, textvariable = self.strvar_fullscale_current,
width = 10)
self.cal_window.grid()
self.lbl_raw.grid(row = 0, column = 0)
self.cal_output.grid(row = 1, column = 0, rowspan = 7)
self.lbl_offset.grid(row = 1, column = 1, sticky = ‘S’)
self.ent_offset.grid(row = 2, column = 1, sticky = ‘N’)
self.lbl_raw_to_current.grid(row = 3, column = 1, sticky = tk.S)
self.ent_raw_to_current.grid(row = 4, column = 1, sticky = tk.N)
self.lbl_fullscale_current.grid(row = 5, column = 1, sticky = tk.S)

● 138
Chapter 8 • A Project to Monitor Your Electricity Consumption

self.ent_fullscale_current.grid(row = 6, column = 1, sticky = tk.N)


self.btn_save_cal.grid(row = 7, column = 1, padx = 5, pady = 5, sticky = tk.S)
self.calibration_update()

def calibration_update(self):
try:
self.cal_output.delete(1.0, tk.END)
for data in self.circ_buffer:
self.cal_output.insert(tk.END,’raw = {0:d} i = {1:0.2f}A y = {2:d}\n’.format(data[0], data[1],
data[2]))
self.cal_output.see(tk.END)
except:
self.master.after_cancel(self.after_handle)

self.after_handle = self.master.after(10000, self.calibration_update)

def save_calibration(self):
self.calibration_dict[‘raw_offset’] = float(self.strvar_offset.get())
self.calibration_dict[‘raw_to_current’] = float(self.strvar_raw_to_current.get())
self.calibration_dict[‘fullscale_current’]= float(self.strvar_fullscale_current.get())
try:
calibration_file = open(‘current_monitor_cal.dat’,’bw’)
pickle.dump(self.calibration_dict, calibration_file)
calibration_file.close()
except:
self.cal_output.insert(END,’\vFailed to open file to save calibration\n’)
self.cal_output.see(END)

def capture(self):
file_name = tk.filedialog.asksaveasfilename(filetypes = [(‘Bit Map’,’*.bmp’)],title = ‘Choose or Enter
File Name’)
if file_name:
segments = []
tags = self.graph1.can.find_all() # find all objects on the canvas
for tag in tags: # loop through objects
if self.graph1.can.type(tag) == ‘line’: # filter out the lines
segments.append(self.graph1.can.coords(tag)) # make a list of coordinate lists

draw1 = bmp_draw.BmpDraw(‘current_monitor_screen_cap_template.bmpt’)
if draw1.flag == True:
for x in range (0,self.X, 90):
draw1.line(x, 0, x, self.Y, [0,255,0])

for y in range (0, self.Y, 50 ):


draw1.line(0, y, self.X, y, [0,255,0])

for segment in segments:


draw1.line(segment[0], self.Y - segment[1], segment[2], self.Y - segment[3], [0,0,255])

draw1.write_file(file_name)
tk.messagebox.showinfo(‘Capture’, ‘Capture Saved’)
else:
tk.messagebox.showinfo(“Capture”, ‘Capture Cancelled’)

tkin = tk.Tk()
front_end = CurrentLogger(tkin)
tkin.mainloop()

● 139
Chapter 9 • Web Browser Interfaces

Chapter 9 •  Web Browser Interfaces

9.1 • Introduction

Desktop GUI applications are satisfactory if you only want to interface with some local
hardware. It is however often more convenient to use a mobile device such as a tablet
computer or mobile phone. This allows you to remotely access your hardware devices
even when away from home. Security and safety have to be considered when remotely
controlling real electrical and electromechanical devices. This chapter will only cover
enough to give you a practical GUI for you own projects; it is certainly not a reference for
web design. This chapter is being presented as following on from the current monitoring
project started in the last chapter. You can easily apply the information in this chapter
to other projects of your own invention that might want to monitor similar analogue or
digital inputs to the Arduino slave.

9.2 • HTML 5

To generate the graphic interface, we are going to use HTML5 to display the graph from
the current monitoring project from the last chapter. HTML stands for Hypertext Markup
Language. It defines a web page in elements and these are represented by tags. Only the
most basic coverage of this topic will be given here. We only need to generate and display
an image similar to the Python canvas widget in the desktop program. Although HTML
5 has a canvas object, we will not be using it Instead we will be using Scaleable Vector
Graphics (SVG). The code that we need to write here is remarkably simple.
Program 9-1  Index.html

<!--prog_09_01 is actually file index.html in directory ~/programs/chap09-->


<!DOCTYPE html>
<html>
<body>
<h3>Lines Using Scaleable Vector Graphics</h3>
<svg height=”500” width=”720”>
<line x1=”360” y1=”0” x2=”360” y2=”500” style=”stroke:rgb(0,255,0);stroke-width:2” /><!-- vertical line -->
<line x1=”0” y1=”250” x2=”720” y2=”250” style=”stroke:rgb(0,255,0);stroke-width:2” /><!-- horizontal line -->
<line x1=”0” y1=”0” x2=”720” y2=”500” style=”stroke:rgb(255,0,0);stroke-width:2” /><!-- diagonal -->
</svg>
</body></html>

The above HTML script can be viewed in a web browser by typing /home/ in the URL bar
and then navigating to the file that is under the programs for Chapter 9. The file name
is index.html. The first line is a comment and does nothing to the web page. Comments
are enclosed by the tags “<!--” and “-->”. The next declares to the browser what type
of document it is. The first tag is “<html>” and it has a closing tag on the last line of
“</html>”. The next pair of tags enclose the header, and then there is the SVG code
enclosed in the svg tags. The opening tag defines the size of the graphic.

The lines that are drawn are defined between the “<line” and “/>”. The lines are defined
in a way similar to that used on the Python canvas, with x and y coordinates for each
end of the line, colour defined by the red, green and blue values, and stroke-width value.
Figure 9-1 shows the resulting graphic being viewed locally by using the path to the file.
To view a web page on a different device to the one that the file is on you need a web
server. The Apache Web Server was used in the first edition of this book and common
gateway interface (CGI) scripts were used to generate interactive web pages. In this

● 145
Python 3: Programming and GUIs for Electronic Engineers

edition I am using the CherryPy Web Framework which offers a much more straight
forward way of creating our dynamic web pages.

 Figure 9-1 

9.3 • CherryPy a Python Web Framework

CherryPy is a web framework for Python that gives us a web server and a framework to
serve dynamic content allowing the user to interact with Python programs running on the
server. To install, you need to type this at the command line:

user@debian:~$ sudo apt-get install python3-cherrypy3

We will start with the content of the “index.html” shown above and serve it using
CherryPy.
Program 9-2  CherryPy

#!/usr/bin/env python3
#prog_09_02.py
import cherrypy

class SvgDemo:
@cherrypy.expose
def index(self):
return ‘’’
<!DOCTYPE html>
<html>
<body>
<h3>Lines Using Scaleable Vector Graphics</h3>
<svg height=”500” width=”720”>
<line x1=”360” y1=”0” x2=”360” y2=”500” style=”stroke:rgb(0,255,0);stroke-width:2” /><!-- vertical line -->

● 146
Chapter 10 • Curses Interfaces

Chapter 10 •  Curses Interfaces

10.1 • Introduction

The curses interface runs on a terminal. Curses is a Python package for the ncurses
library that allows you to write text based user interfaces that are independent of the
terminal being used. Although the interface is character based, many of the features
of a GUI can be produced. One example of this type is the Midnight Commander File
manager. Unlike a basic command line program, curses allows you to print anywhere
on the screen and have multiple windows in the display for entering and reading data.
Some limited graphics such as bars that change their length can be used for meter
indications and windows that change colour can be used as indicators. The reason that
you might want to use them is that they can run without the X-windows and therefore
are useful on low resource computers. Curses is already part of Python and is simpler to
use than the ncurses library that you would use if programming in C. The curses package
is not available for Python on Microsoft Windows. Figure 10-1 shows an example of a
representation of a gauge. There are no readymade widgets but it is easy to produce your
own widgets as classes that you can re-use.

 Figure 10-1  Representation of a gauge

10.2 • Getting Started with Curses

As an example to start with, Prog 10 - 1 prints a message to the screen in two different
positions. Normally with a terminal, printing takes place at the cursor position and you
can't choose an arbitrary position on the screen, but with Curses you can.
Program 10-1  Print message to screen

#!/usr/bin/env python3
#prog_10_01.py

import curses

stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.addstr(5, 20, 'Curses can write anywhere on the screen')
stdscr.addstr(7, 10, 'Curses can write anywhere on the screen')
stdscr.getch()

curses.echo()
curses.nocbreak()
curses.endwin()

Figure  10-2 on page 164 shows the output of this program. Firstly you have to import
curses and then call the function curses.initscr(). This function initialises the library and
returns window object that it is customary to call stdscr, which represents the whole
screen. On stdscr, text can be written and separate windows can be placed. Here there
are no windows, just the stdscr. The curses.noecho() function prevents characters
appearing as you type: there are special functions to do that. The curses.cbreak()
function stops the line buffering of input as happens with a normal terminal that would
require you to press the return key. To get text to print to the screen, the addstr()

● 163
Python 3: Programming and GUIs for Electronic Engineers

function is called. This is a method of the screen or window and can take the arguments
to position the text, the string to print, and also attributes for the text, but here there
are none. An important note is the order of the positional arguments. The first one is
the number of lines down the screen or window, and the second one is the number
of columns or character places along the screen from the left. Curses does not draw
individual pixels, only characters.

 Figure 10-2  Program output  


To prevent the program ending before you get a chance to see it, the function stdscr.
getch() waits for any key press. Before the program ends, you have to undo the changes
you made to the operation of the terminal, otherwise the terminal will not behave
normally after the program ends. In the program you can see the three functions called
to reverse these effects. If the program fails before these functions can be called, you
will have the terminal in an unusable state that will require it to be closed and another
opened. There is however a convenient way of overcoming this.

10.2.1 • The Wrapper Function

The wrapper function handles this problem and does away with having to manually call
these functions. You have to put your code in a function, in this case it is called main()
and it must have one argument called stdscr. The program starts by calling curses.
wrapper() and this function must be given the name of your function because it calls it.
When the wrapper function calls your function, it passes it to the stdscr object. When
your function finishes, the program returns to the wrapper function and it cleans up the
terminal. If your function fails for any reason, the wrapper function has a try/exception
routine that handles the clean up.
Program 10-2  Using the wrapper function

#!/usr/bin/env python3
#prog_10_02.py
import curses

def main(stdscr):
stdscr.addstr(5, 20, 'Curses can write anywhere on the screen')
stdscr.addstr(7, 10, 'Curses can write anywhere on the screen')
stdscr.getch()

curses.wrapper(main)

10.2.2 • Windows on the stdscr

There is more to it than just writing text anywhere on the screen. Separate windows can

● 164
Appendix A • Arduino Uno Slave Source Code

Appendix A • Arduino Uno Slave Source Code


Program A-1 below is the source code for the Arduino slave it is not Python it is the
Arduino dialect of C and C++. This source code gets compiled to a hex file that is the
executable code that gets loaded into the Arduino to make it a slave. The hex file is in the
zip file as Arduino_Slave_17_03_26a.ino.standard.hex. An explanation of this program is
not given, but if you are familiar with C please refer to Figure  5-12 on page 95 that is
the state diagram for this program.
Program A-1  Arduino Sketch

/*Arduino_Slave_17_03_26a.ino*/
#include <EEPROM.h>

#define STATE_IDLE 0
#define STATE_CHECK_TELEGRAM 1
#define STATE_CONFIGURE_IO 2
#define STATE_DIG_READ 3
#define STATE_DIG_WRITE 4
#define STATE_AN_READ 5
#define STATE_AN_WRITE 6

#define STATE_FAIL_SAFE 7
#define STATE_TX_IDS 8
#define STATE_SET_IDS 9
#define STATE_RECEIVING_BYTES 10

#define FUN_CODE_CONFIG 2
#define FUN_CODE_DIG_READ 3
#define FUN_CODE_DIG_WRITE 4
#define FUN_CODE_AN_READ 5
#define FUN_CODE_AN_WRITE 6
#define FUN_CODE_TX_IDS 8
#define FUN_CODE_SET_IDS 9

#define BROADCAST_ADDR 255

#define ERROR_CHECK_SUM 1
#define ERROR_FUN_CODE 2
#define ERROR_ADDRESS 3
#define ERROR_PROJECT_ID 4

#define SLAVE_ADDRESS_EEPROM_LOCATION 0
#define PROJECT_ID_H_EEPROM_LOCATION 1
#define PROJECT_ID_L_EEPROM_LOCATION 2

unsigned char request_telegram_ascii[64];


unsigned char request_telegram_binary[32];
unsigned char response_telegram_ascii[64];
unsigned char response_telegram_binary[32];
unsigned char telegram_index = 0;
unsigned char telegram_binary_length;
unsigned char slave_address;
unsigned char project_id_h;
unsigned char project_id_l;
unsigned char state = 0;
volatile unsigned char chrbuff;
unsigned char pullupmask_d;
unsigned char pullupmask_b;

● 185
Appendix B • The Python Uno Slave

Appendix B • The Python Uno Slave


Below is the program uno_slave.py. This is the communication program that commands
the Arduino slave.
Program B-1  uno_slave.py

#!/usr/bin/python3
import serial
import os

H = 1
L = 0
FUN_CODE_DIG_READ = 3
FUN_CODE_DIG_WRITE = 4
FUN_CODE_AN_READ = 5
FUN_CODE_AN_WRITE = 6
FUN_CODE_GET_IDS = 8 #maps to FUN_CODE_TX_IDs in the arduino code
FUN_CODE_CONFIG = 2
BROADCAST_ADDR = 255

DEBUG = False

class Uno:
'''Arduino Uno as an IO slave.

The Uno must be running the Arduino_slavexxx sketch.


Uses an ascii formatted communications telegram.

'''

def __init__(self,address = 0, project = 0, config_digital = []):


'''Initialise the Uno slave.

address -- 1 - 254.
project -- 0 - 65535
config_digital -- List of integers detailing the pins configured as outputs.

'''

self.project = project
self.address = address
self.config_digital = config_digital
self.port = None
self.rw_available__flag = False
self.ser = serial.Serial()
self.ser.timeout = 0.1
self.ser.bytesize = 8
self.ser.stopbits = 2
self.ser.baudrate = 9600
self.ser.xonxoff = False
self.write_digital_dict = {}
self.write_analog_dict = {}
self.read_digital_dict = {0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, }
self.read_analog_dict = {0:0, 1:0, 2:0, 3:0, 4:0, 5:0}

def connection(self):
'''This function checks for connection and digital configuration and calls connect() if necessary.

Is called by read_digital(), read_analog(), write_digital(), and write_analog() to check for connection to slave.
Return True or False.

'''

● 193
Index

Index bytesarray 54
Byte slicing 55
Symbols
C
__init__ () 73
Calculate() 67
__init__() 137
calibration() 141
__main__ 104
Calibration Program 136
__name__ 103
Callbacks 61
A Calling box() 168
Adapting Project 161 Canvas() 143
administrative rights 18 Canvas Widget 70
after() 90 capture() 142
Analogue gauge 172 C compiler 22
Analogue Input Pins 87 Checkbutton() 68
Analogue Inputs 93 Check buttons 68
Analogue Output Pins 87 CherryPy Web Framework 146
Analogue Outputs 91 Class 73
Apache Web Server 11 Class BmpDraw 128
append() 143 Colour 165
Arduino Sketch 185 Commands
Arduino Slave 134 cat 17
Arduino Uno 81 cd 16
ASCII 21, 51, 96 cp 17
assembler 21 df 17
AVRDUDE 81 less 17

B ls 16
lsusb 17
Bash Scripts 19
mkdir 17
Binary 50
mv 17
Binary Files 121
rm 17
binary system 47
rmdir 17
Bit and Bytes 46
communications functions 87
Bit Map 119
Communications Protocol 95
bitwise logic operators 47
Comparators 73, 77
bitwise operators 47
Comparison Operators 48
Bitwise OR Operator 173
Compiled Python 51
bkgd() 167
Configuring the router 161
BmpDraw() 144
Configuring Wi-Fi 158
Button Widget 178
Control Variables 68
bytearray() 55

● 219
Python 3: Programming and GUIs for Electronic Engineers

contvar 68 Flyback button 101


Create window 166 format() 28
Creating file names 30 Functions 42
Creating the GUI 110 G
CurrentLogger() 143
Graphic User Interfaces 59
Current monitor 137
Graph Plotting 101
curses 163
Grid Manager 61, 62
curses.cbreak() 163
GUI 101, 145
curses.initscr() 163
curses.napms() 182 H

Custom Widgets 169 Handling pixel file 123


Header 125
D
Hexadecimal 50
Data logger 28
Hexadecimal Notation 49
Data Types 24
HTML 5 145
Debian 11
Debian 8 Jessie 13 I

Decimal 50 IDLE 23, 24


Decoding Bytes 56 if else 48
Desktop Program 135 Imports 44
Dictionaries 40 index() 149
Digital Input Pins 86 Indicator lamp 170
Digital Inputs 92 Inheritance 75
Digital Output Pins 85 Instances of Slaves 85
Digital Outputs 88 Integers 24
Directory handling 14 Internet access 160
drive() 90 Internet Service Provider 160
IO Functions 87
E
IP address 161
Empty window 60
Encoding Bytes 56 J

Error message 23 Junk Bytes 128


except 33 L
F Label Widget 66, 179
File handling 14 layout behaviour 63
File Permissions 18 Linux 13, 18
find() 35 list indexing 37
find_all() 143 Lists 36
Floats 25 Logic 46

● 220
Index

Logical operators 46 Radio Buttons 69


Long lines 52 Radio Link 135
Long string 27, 167 Raspberry Pi 11, 157
loop conditional 49 Raspbian 11, 13

M Redirection 18
Remote Sensing Head 131
mainloop() 114
row.configure() 63
Master Slave Design 81
method test() 114 S
micro SD 158 save_calibration() 142
Mint 11 Scaleable Vector Graphics 145
Modified Image 124 Scale to display 67
Mouse Events 173 Scale Widget 66
Mousepad 15, 22 Schmitt trigger 75
Moving graphics 45 Slave State Diagram 95

N sleep() 151
Split function 40
Nested Layout 64
Splitting Strings 39
Newline 31
start_test() 114
"no file" error 33
stdscr.refresh() 165
Number crunching 43
Strings 26
O Struct Module 126
Object Orientation 79 struct.pack() 126
Object Oriented Programming 73 Switching() method 75
Opening file 31
T
P Telegram Formats 97
permission number 19 Terminal Emulator 13
Persistence of Objects 50 test() 114
PIC connections 134 Test results 114
pickle.dump() 142 Text input 67
PIC Microcontroller 133 textvariable 68
privileges 18 Threading 116
Probe Sensing Head 131 Thumbwheel Widget 174
Python 2 11, 21 Time() 44
Python 3 11, 21 time.sleep() 90

Q Tkinter 59, 101


Trend graph 157
Quantities 141
try 33
R
Tuples 42

● 221
Python 3: Programming and GUIs for Electronic Engineers

U
Ubuntu 11, 13
Unicode 21
Unicode Strings 51
Uno Class 84
Uno Slave 193
USB Serial 81
utf-8 53
utf-16 53

V
Variable assigned 43
Variable names 57
variables 141
VirtualBox 13
Voltage comparators 73

W
Web Forms 148
Web Server 157
Widgets 61, 65
Wild Cards 17
win.doupdate() 182
win.noutrefresh() 182
win.refresh() 182
Wrapper Function 164

X
X-Server 20

● 222
175 × 235  SPINE: 11.4  FLAPS: 0

FOR ELECTRONIC ENGINEERS

PYTHON 3 - PROGRAMMING
FOR ELECTRONICS ENGINEERS

PYTHON 3
PROGRAMMING AND GUIS
PYTHON 3
Andrew Pratt PROGRAMMING AND GUIS

This is the second edition of a book aimed at engineers,


scientists and hobbyists who want to interface PCs with
hardware projects using graphical user interfaces. Desktop
and web based applications are covered.
The programming language used is Python 3 which is
one of the most popular languages around: speed of
programming being a key feature. The book has been
revised and updated with emphasis on getting the user to
produce practical designs with ease - a text editor is all

AND
Andrew Pratt served for
that is required to produce Python programs.
25 years in the Royal
Air Force as an Aircraft Hardware interfacing is achieved using an Arduino Uno as

GUIS • Andrew Pratt


Technician. a remote slave. A full description and source code of the
communication interface is given in the book. The slave
He holds a Higher
provides digital and analogue input and outputs. Multiple
National Certificate in
Unos can be included in one project with all control code
electrical and electronic
written in Python and running on a PC
engineering and a
Degree from the Open One project involves a PIC microcontroller with code
University. provided that can be loaded into the PIC using the Uno.
The web applications and server are all implemented in
He continued his career
Python allowing you to access your electronic hardware
working in industrial
over the Internet. The Raspberry Pi computer can be used
controls. Currently
as your web server.
he is an instructor
teaching industrial An introductory chapter is provided to get you started with
control systems. using Linux. The book is written for use with Debian or
variations including Mint or Ubuntu. All of the programs in
the book are freely available, ready to use and experiment
with by way of a download from Elektor.
ISBN 978-1-907920-61-5

LEARN

Elektor International Media BV


www.elektor.com
Andrew Pratt
DESIGN

LEARN DESIGN SHARE

LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIG
SHARE

N • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHA
SIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LE
• LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN
RN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SHARE • LEARN • DESIGN • SH