Pi with Neopixels/Simulated Neopixels

Neopixels are addressable full-colour RGB LEDs that come in a variety of different arrangements. Ranging from single LEDs, to matrix arrays and a variety of sewable components that can be used on wearable products.


Neopixels were originally made available for Arduino projects, but now there are also Python libraries for Raspberry Pi’s.

In this blog I will be looking at setting up neopixels components on Raspberry Pi’s, and then I will show some “soft” neopixel layouts using the Python Tkinter graphic library.

Getting Started

To load the Raspberry Pi neopixel libary comes from the nice people at Adafruit, and it is loaded by:

sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel

It is important to note that neopixels can draw a lot of power so consider looking at using external 5V power for projects with a lot of LEDs. The LED power consumption is based on:

  • How many neopixel LEDs are lit at one time, and
  • What the intensity of the LEDs is.

A few other import points are:

  • not all neopixel strips are the same. Different strips will vary greatly from the LED intensity, and more importantly on the RGB vs. GRB addressing.
  • NeoPixels must be connected to D10, D12, D18 or D21 to work
  • For NeoPixels to work on Raspberry Pi, you must run the code as root

The neopixels are wired with 3 pins : 5V (VCC), GND and signal in. The default signal in wires to Pi pin 18. Neopixel component can be connected in series with data in and out connectors.


Below is an example that will set all the LEDs to a light magenta and then it will cycle one LED to a brighter RED. The overall neopixel string has a 10% brightness.

# Python neopixel example to cycle an LEDs

import board
import neopixel
import time

ORDER = neopixel.RGB  # or neopixel.GRB
numpixels = 12

# Create a pixel object with 12 pixels and low intensity
pixels = neopixel.NeoPixel(board.D18,numpixels , brightness=0.10, auto_write=True, pixel_order=ORDER)
while True:
for i in range(numpixels):
   pixels.fill((10, 0, 40)) # fill all pixels in light magenta
   pixels[i] = (80,0,0) # fill one pixel in brighter red

Depending on the type and manufacturer of the neopixels the result will look a little different. Some trial and error testing will be required to determine if the strips are RGB or GRB.


Simulated Neopixels

If you don’t have neopixels or if what to simulate neopixels then the Python Tkinter graphic library can be used to create a variety of different arrangements. For my testing I create two arrangements: a strip and a matrix.

The important things that I learned was how to create a array object that could simulate the neopixel object. To do this in Python:

import tkinter as tk

root = tk.Tk()
root.title("Soft NeoPixel Strip")

numleds = 25

# Create an array that can be used later in Tkinter

ledstrip = ['' for i in range(numleds)]

for i in range(numleds):
   ledstrip[i] = tk.Label(root,relief='raised',width=3 ) # a label array
   ledstrip[i].grid(row = 0, column = i) # position the labels is a horizontal row

Simulated Strip Neopixel

Below is an example of a soft “strip” neopixel application with a demo function.


# Python Neopixel Single Strip Presentation
import tkinter as tk

numleds = 25

theled = 0

def stringdemo():
    # move a coloured LED around the string
    global theled
    ledstrip[theled].configure(background= 'white')
    theled = theled + 1
    if theled >= numleds:
        theled = 0
    ledstrip[theled].configure(background= 'sky blue')
    root.after(500, stringdemo)
root = tk.Tk()
root.title("Soft NeoPixel Strip")

# create an LED object 
ledstrip = ['' for i in range(numleds)]

# put the LED object into a horizontal strip
for i in range(numleds):
    ledstrip[i] = tk.Label(root,width=2,height=1,relief='raised',background = 'white')
    ledstrip[i].grid(row = 0, column = (i+1))

root.after(500, stringdemo) #start a demo


Simulated Matrix Neopixels

Below is an example of a soft matrix neopixel application.


# Python Neopixel Matrix Presentation
import tkinter as tk

numleds = 100
rowcnt = 10
colcnt = int (numleds/rowcnt)

theled = 0

def stringdemo():
    # move a coloured LED around the string
    global theled
    ledstrip[theled].configure(background= 'dark gray')
    theled = theled + 1
    if theled >= numleds:
        theled = 0
    ledstrip[theled].configure(background= 'red')
    root.after(500, stringdemo)
root = tk.Tk()
root.title("Soft NeoPixel Matrix")

# create LED object
ledstrip = ['' for i in range(numleds)]

# put the LED object into a grid
for i in range(rowcnt):
    for j in range(colcnt):
        ledstrip[theled] = tk.Label(root,width=4,height=2,relief='raised',background = 'dark gray')
        ledstrip[theled].grid(row = i, column = j)
        theled = theled + 1

theled = 0 #reset the led index for the demo
root.after(500, stringdemo)



Neopixels can be used on custom lighting applicatons, for example I used them on a water fountain project.

Given a choice I would recommend using Arduino hardware over the Raspberry Pi hardware for neopixel projects. I found that the Arduino neopixel library to be much more stable and considerably faster than the Pi version.

X Windows from Raspberry Pi to Android

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

X Server Apps for Android

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


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

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

Both options are free and open source.

Getting Started with X Windows

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


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

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

~$ echo $DISPLAY

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

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

export DISPLAY=

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

$ idle


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

Python Tkinter

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

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

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

root = tk.Tk()

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

def CallBack():

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

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



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

~$ export DISPLAY=
~$ python test1.py


Final Comment

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









Simulate Raspberry Pi Hardware

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

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

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

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

Seven Segment Display

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

pip install tk_tools

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

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

import tkinter as tk
import tk_tools

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

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

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

    root.after(1000, update_gauge)

root.after(500, update_gauge)



LCD Keypad 

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


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

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


import tkinter as tk

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

root = tk.Tk()
root.title("LCD Keypad Shield")

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

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

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

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

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

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

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


Gauge and Rotary Scale

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

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

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

import tkinter as tk
import tk_tools

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

my_gauge = tk_tools.Gauge(root, height = 200, width = 400,
                             label='CPU Temp',
my_gauge.grid(row=0, column=0, sticky='news')

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

    # update the gauges according to their value

    root.after(1000, update_gauge)

root.after(500, update_gauge)



Final Thoughts

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

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

Flame Monitor

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

The Flame Sensor

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


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


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



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


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

Python Code

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

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

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

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

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

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

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


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

issent = False

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

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

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

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

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

top.after(2000, get_status)

Le gocart (Python Tkinter GUI)

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

Hardware Setup

Our hardware components were:

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


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

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



Python Tkinter

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

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

import Tkinter
import explorerhat 

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


#Define the buttons

def motor(Left,Right):

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



Pi Shortcut

To create a Pi shortcut, create a file:

nano $HOME/desktop/pi.desktop

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

[Desktop Entry]
Name=Car Controls
Comment=Python Tkinter Car Control Panel
Exec=python /home/pi/mycarapp.py

VNC (Virtual Network Computing)

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

sudo raspi-config

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


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

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