Twitter icon
Facebook icon
LinkedIn icon
Google icon
Reddit icon
StumbleUpon icon icon

Home Automation with PYNQ and Zigbee

Added to IoTplaybook or last updated on: 10/18/2022
Home Automation with PYNQ and Zigbee


We often forget the FPGA can be used in consumer applications and not just industrial, automotive, defense / aerospace etc. This is especially true for devices in the cist optimised range such as the Artix, Spartan and Zynq 7000 series devices.

Programmable logic and SoC provides a range of benefits which at first might not be obvious including

  • System Integration - combine several discrete processing elements into a single package.
  • Time to Market - Reduced time compared to ASIC Solutions
  • In Field Update - ability to upgrade not only the SW but also the "fixed" logic design as standards and product road maps evolve
  • Architectural Flexibility - The ability to provide a wide range of interfacing and acceleration of functions to the programmable logic.
  • De Risking - The ability to start development early.

One common application of FPGA in the consumer market is home automation. In home automation systems there is often a central secure gateay which manages connection of devices and the wider system.

For this project we are going to demonstrate the central gateway which connects to series of ZigBee controlled lights.

The road map for the project is to interface it at a later stage with a Smart AI based digital lock which will communicate with the gateway and establish the home settings for the person unlocking.

Things used in this project

Hardware components

Arty Z7-20
Digilent Arty Z7-20
× 1


ConBee II USB Gateway
Dresden Elektronik ConBee II USB Gateway
× 1 Dresden-Elektronik
Philips hue
Philips hue
× 1 Philips

Software apps and online services

PYNQ Framework
AMD-Xilinx PYNQ Framework

Home Automation, PYNQ and ZigBee

It's entirely possible to control and automate ZigBee devices right from the PYNQ's Juptyer notebook. This has some great benefit such as customising User Interfaces which is pretty unique itself when compared to the other Home Assistant and Automation software. Not only that, we can even leverage the fact that this is a PYNQ board and we can utilize the PL to further customise our application. It's perfect for the home assistant community and surprisingly its relatively simple. Let's show you how we did it.

Featured Images

Color Picker
1 of 4 - Color Picker

HSV sliders
2 of 4 - HSV Slides

Phosco App
3 - 4 - Phosco App

Arty Z7, Conbee II and Philips Hue Lamp
4 - 4 - Arty Z7, Conbee II and Philips Hue Lamp

Method Summary

This section is to summaries the methods used in this project.

The PYNQ framework runs and underlying OS. The underlying OS for the PYNQ frame is Ubuntu. We are going to leverage this later on to install docker which in turns install the deCONZ software.

What and Why docker ?

Simply put docker is a great way of distributing software and reduces the overhead of multiple virtual machines. Docker has the ability to run software in what's called a "Container", a container is a fully package software, which includes the image, libraries and configuration files. Since the container will run the software we don't have to worry about compatibility issues and will run as expected straight out of the box with minimal intervention.

What and Why deCONZ software

The Conbee II uses the deCONZ software which is provided by the manufacture Dresden Elektronik to connect and control devices. The deCONZ software allows us to connect and control device through the Web App. What makes this all work is the fact that the deCONZ web app has a built-in REST API, which we can interface from within the Juypter Notebook enivronment!

Prerequisites - Hardware

For this Demonstration will be using for the Hardware:

  • Arty Z7 Xilinx ZYNQ 7000
  • Smart Light - Philips Hue GO Portable light

The Arty Z7 is capable of running the PYNQ framework and has a USB slot. The USB slot is a requirement as we will be using the ConBee II USB Gateway directly off the Arty Z7 itself.

The Conbee II is a great little USB stick that can connect smart devices such as lights, switches, outlets and sensors. This little stick is capable on all platforms from Windows to Ubuntu and we will be installing it on PYNQ.

The smart light in this project, is a generic Bluetooth smart light that you can pick up online. You don't have to purchase the same one, but make sure to check that its compatible with the Conbee II. The full list of compatible devices can be found here:

Setting up PYNQ

To get started the first thing we need is to download the PYNQ image from at the time of writing Version 2.7 is the latest release. Here we are going to download the PYNQ-Z1 image since its compatible with our Arty Z7 board.

Download Pynq image
Download Pynq image

Once downloaded we need to flash the image onto a SD card. We are going to use the software WinDisk32 to flash the image. Note Flashing the SD card willeraseeverything. Make sure you don't have anything on the SD card.

After the flashing process has completed. Remove the SD card and insert the card into the Arty Z7, make sure that the Boot Jumper is set to SD. Plug in Arty and wait for the Pynq image to Boot.

Once PYNQ has finished loading, we need to find our IP Address enter the command below.

ifconfig -a

Find our IP Address, it should be under the eth0 interface. Here our IP Address is Take a note of this we will need it later.

Find IP Address
Find IP Address

Setting up Docker and Docker-Compose

As mentioned in the Method Summary section we will be installing Docker. To begin we need to add the current user to the dialout group

sudo usermod -a G dialout $USER

Next we need to download the docker package using the command below:

sudo apt-get install

Wait for the install is done. Once completed we need to install docker compose. Docker compose is a use tool, and will help us create and modify our software.

sudo apt-get install docker-compose

Setting up DeConz using docker compose

With the docker-compose installed we next need to setup the deCONZ container/Application, this is the software that interacts and finds our zigbee devices.

Navigate to /opt folder:

cd /opt

Next we are going to create a new docker-compose.yaml file.

What the heck is a.yaml file ???

This is the file that we add and configure our container. In future as well if we wanted to add more containers. This is the file.

So, going back to creating the yaml file.

sudo nano docker-compose.yaml

3. Copy and paste the container into the yaml file. Make sure to keep the indentation correct !

version: "3.2"
  image: deconzcommunity/deconz:latest
  privileged: true
  container_name: deCONZ
  network_mode: host
  restart: always
   - type: bind
   source: /opt/deconz
   target: /opt/deCONZ
  - /dev/ttyACM0
   - TZ=Europe/London
   - DEBUG_APS=0
   - DEBUG_ZCL=0
   - DEBUG_ZDP=0

This will configure the container so that it will download the latest version of the deCONZ software and set our web portal on port 8090. This is key, because the PYNQ utilise the Web portal for Jupyter’s notebook, which by default uses Port 80 for webpages and has opened an extra port of 9090. This is why we have set the port for the deCONZ application to use 8090. As this does not interfere with the Pynq Jupyter’s notebook web sockets.

yaml file
yaml file

Save (CTR-S) and close (CTR-X) the configuration.

Next we can start the deCONZ application using the docker-compose. Enter the command below:

sudo docker-compose up -d

This will download the deCONZ application and automatically start the container when done.

When we get the "Done" response, let's do a sanity check to see if the container is actually running.

sudo docker container ls

Container is running
Container is running

The container is running. Awesome!

Conbee II and deCONZ setup

Now with the deCONZ application running in the container. We can open the deCONZ web app by using the instructions below.

Open a web browser and enter in the IP along with the port number 8090. In our instance, our IP address is and with the Port number:

Phoscon Web Address
Phoscon Web Address

This will open the Phoscon web app. From the figure below we can see our gateway click on the icon to begin the setup.

On the next page we need to create our login credentials (See next image). Click next when done.

ConBee GateWay
1 - 2 ConBee GateWay

Credential Setup
1 - 2 Credential Setup

The Phoscon App will now ask you to connect any lights. You can connect your lights now or later. We are going to connect our Philips Hue GO Portable Light. Make sure our Lamp is plugged in. Click the search Button.

Connecting Lights
Connecting Lights

As we can see from the figure above, we can see our Lamp. If you click on the Lamp, you can rename it to make identifying the lamps easier. Once all the Lamps have been detected. Click the proceed without lights. Don’t worry the Lamps that already have been detect will be remembered.

On the next page we can create a new group to add the lamp to. Below is an example.

Create a new group, edit, manage lights.

Create a new group
1 - 3 Create a new group

Edits lights
2 - 3 Edits lights

Select Manage lights
3 - 3 Select Manage lights

 Add our lights to the group. We only have 1 light to add. Click on the Green Plus Icon

1 - 2

2 - 2

Click Save and press the arrow icon to return to the group page.

With the lights added to our custom group, we can control it. Note the can be some latency below the webapp and the light. Be patient. If there are still issues consider refreshing the page, moving the device closer or restarting the container using the command below:

sudo docker container restart deCONZ

A Quick Test (Let's play around)

Click on the lights tab to adjust the brightness, colour, and saturation. The colour temperature can also be changed using the icon in the figure below.

Testing the light responds
Testing the light response

Setting Up the REST API

Now with the light setup we can create our own interface using Jupyter’s Notebook. This is relatively easy. Since the deCONZ application has a built in API we can leverage this by using some simple python scripts.

Open a new web browser and navigate to Jupyter’s notebook page. In our case This will open the familiar jupyter’ notebook.

We are going to create a new folder to keep everything tidy. We have named the folder ConBee II and inside this folder create a new python3 application

Create new folder
1 - 2 Create new folder

Create new python3 file
2 - 2 Create new python3 file

The REST API works by making requests. For more information on how to access the API on the official website:

We need to import some libraries to make the requests.

import requests
import json

Next we need to create a request to obtain an API key. In a new cell enter:

URL = ""

device = {'devicetype': 'application'}

p =, json=device)

pretty_json = json.loads(p.text)
print (json.dumps(pretty_json, indent=2))

Running the code above, we will receive the following error:

Request Response Error
Request Response Error

The error is Link button not pressed. This is referring to the authentication check. We need to authorise third party apps. Head back into the Phoscon App and click on the gateway option.

Phoscon App settings
1 - 2 Photoscan App settings

2 - 2

Under the advance settings, click Authenticate app. You will have 60 seconds to rerun the code on the previous step. If done within the time the results are successful with an API key. You have now successful authenticated your app and can start configuring and controlling device with Jupyter.

Command was successful and responded with API key
Command was successful and responded with API key

Controlling our device in Juypter

To make requests now we need to provide our API key. For example, we would like to see our lights.

The # represent the API key from the last step

r = requests.get(URL+"/D########9/lights")
pretty_json = json.loads(r.text)
print (json.dumps(pretty_json, indent=2))

The figure above shows us both the Philip Hue Lamp and the ConBee II device

Please see the full list using the commands. Using the link provided:

The parameter that can be modified are the parameters listed under the “state” category:

These parameter require a request PUT command. For example we could turn on of off our device.

Turn on our Lamp in juypter
Turn on our Lamp in juypter

Creating custom Interface with Jupyter Notebook

Now that we know how to control our devices, next is to integrate them into Jupyter’s build in GUI creation tool. We will use the ipywidgets library.

import ipywidgets

Let’s first get some basic controls for our Light. We need an ‘On switch’ and an ‘Off switch’. There aren’t any switches, but we can use buttons instead. The code below create a button which changes the “on” value to True.

Button Pressed
1 - 2 Button Pressed

UI button turning on Lamp
2 - 2 UI button turning on lamp

btn = widgets.Button(description='On')

def btn_eventhandler(obj):
    data = {"on": True}
    r = requests.put(URL+"/D78828C329/lights/1/state", json = data)
    print("Lamp is On!")


Next let's turn off the Lamp. This time we’ll set the ‘on’ value to False!

1 - 2

UI button turn off lamp
2 - 2

btn = widgets.Button(description='OFF')

def btn_eventhandler(obj):
    data = {"on": False}
    r = requests.put(URL+"/D78828C329/lights/1/state", json = data)
    print("Lamp is OFF!")

We can even add a colour picker widget. The colour picker widget returns to RGB values of the selected colour. However, this presents a little problem. The deCONZ rest api expects the values in HSV. The hue parameter in the HSV colour model is between 0°–360° and is mapped to 0–65535 to get 16-bit resolution.

First lets add the Color picker

colorpicker = widgets.ColorPicker(
        description='Pick a color',
        disabled=False )
colorpicker ## Click the little blue square

Colour Picker
Color Picker

Next is taking the information in the color picker and converting the value to a useable format that the deCONZ software can understand. After countless hours of debugging and head scratching. Copy the code below:

import math 
def RGBtoHSV(colorpicker):
    R = int(colorpicker.value[1:3],16)
    G = int(colorpicker.value[3:5],16)
    B = int(colorpicker.value[5:7],16)

    R1 = R/255
    G1 = G/255
    B1 = B/255


    Cmax = max(R1,G1,B1)


    Cmin = min(R1,G1,B1)

    delta = Cmax - Cmin

    if delta != 0:
        if Cmax == R1:
            Hue = round(60*(((G1-B1)/delta)%6))
        elif Cmax == G1:
            Hue = round(60*(((B1-R1)/delta)+2))
            Hue = round(60*(((R1-G1)/delta)+4))
        if Cmax == R1:
            Hue = R1
        if Cmax == G1:
            Hue = G1
        if Cmax == B1:
            Hue = B1

    if Cmax != 0:
        Sat = 255*(delta/Cmax)
        #print("\nSaturation: {0}% of 255 is {1}".format(round((delta/Cmax)*100), round(Sat)))
        Sat = 0
        #print("Saturation: 0%")
    Vis = 255 * Cmax

    Hue = round(Hue * ((2**16)/360)) ## Mapped to 360 degrees

    #print("Visablity: {0}% of 255 is {1}".format(round((Cmax*100)), Vis))

    #print("\nRed {0} Green {1} Blue {2}".format(R,G,B))
    #print("Hue {0} Sat {1} Vis {2}".format(Hue,round(Sat),round(Vis)))
    #print (json.dumps(pretty_json, indent=2))
    return Hue, Sat, Vis

This correctly returns the Hue, Saturation and Visibility from the color picker. Call this function with:

Hue,Sat,Vis = RGBtoHSV(colorpicker)

Next is to simply send the PUT request and the Lamp will change color as desired.

data = {"on": True, 
        "bri" : Vis,
        "hue" : Hue,
        "sat" : Sat

r = requests.put(URL+"/D78828C329/lights/1/state", json = data)

pretty_json = json.loads(r.text)
#print (json.dumps(pretty_json, indent=2))

Send the HSV to the device
1 - 3 Send the HSV to the device

Selected color
2 - 3 Selected color

Color displayed on device
3 - 3 Color displayed on device

For our final example we are going to control the Hue, Saturation and Brightness using sliders!

HSV sliders
HSV sliders

With this we can change how we want our light to look.

Now that we have all our GUI elements that we want. We need to add them together to create a GUI. We can do this by using Juypter/Labs create our own custom interface with no extra modification!

Save and close the Python3 notebook. We want to navigate to Jupyter Labs, simple type in the search bar <ip>:9090/lab. In our case This will open the Lab environment. Here we want to navigate and open our python3 file.

From here you can click and drag in the cells with the UIs and begin to create a unique UI

Here is our very basic UI. This can be opened in a new tab as shown below.

Customising UI
Customising UI

The Full code can be found on our GitHub Page:


So you see it's possible! We hoped that you have found this project useful. Be on the look out for future posts. Why not check out some of Adam's other Awesome projects.

Code  Home Automation PYNQ Juypter Notebook

Instructions are provided

AdiuvoEngineering / Home-Automation-PYNQ

Repository for the Hackster project: Home Automation with PYNQ and Zigbee. This repository is for the code use in the project. It contains the Jupyter Notebook that was use in creating the Hackster project. LINK HERE (LINK NOT PUBLIC) — Read More

Latest commit to the master branch on 8-11-2022

Download as zip


Adam Taylor

Adam Taylor

101 projects • 1590 followers

Adam Taylor is an expert in design and development of embedded systems and FPGA’s for several end applications (Space, Defense, Automotive)

Jeff Nguyen

Jeff Nguyen

Embedded Systems Engineer at Adiuvo Engineering.

This content is provided by our content partner, an Avnet developer community for learning, programming, and building hardware. Visit them online for more great content like this.

This article was originally published at It was added to IoTplaybook or last modified on 10/18/2022.