PySide6 Snippets

These snippets may apply to PySide2 also but are untested there.

Plain Text to Rich Text Conversion

Handling special characters in Qt Rich Text Widget.

If you are using a rich text widget, then any special characters, like say the less than sign <, if written to the text object will cause your output to be broken. Qt provides a function for these cases: convertFromPlainText

from PySide6.QtGui import Qt
...
    def my_method(plain_text)
        myQmlModel.rich_text_property = Qt.convertFromPlainText(plain_text)

Carriage Returns and Line Feeds in Rich Text do not work with WordWrap

In addition to the convertFromPlainText method, you can not have line feeds in your text, so you need to find and convert those to <br/>. If you do not, WordWrap option will not work correctly and your lines will extend past your widget width. At least in PySide 6.2.3.

Reference: QtGui — Qt for Python


Qt ® is a registered trademark of The Qt Company Ltd. and its subsidiaries.

Python ® is a registered trademark of the Python Software Foundation.

Qt5 to Qt6 Qml/Pyside 2 to 6 Porting Adventures

Here are a few things noticed during a port of a Pyside2 project and associated Qml to Pyside6 (6.2.1).

Injection of parameters into signal handlers is deprecated.

If you hit the following warning, it is formatting quirk now being enforced by Qt 6.

Injection of parameters into signal handlers is deprecated. Use JavaScript functions with form al parameters instead.

In our case it came about in this snippet of Qt5/Qml code on the Main Window’s onClosing handling to avoid closing on a certain condition. As the documentations quotes, you are allowed to set closing.accepted to true or false: Window QML Type | Qt Quick 6.2.1

ApplicationWindow {
    id: application
    onClosing: {
        ...
        if (condition) {
            close.accepted = false
            userDialog.open()
        } else {
            close.accepted = true
        }
    }

The fix is fortunately simple through the addition of the function(close). Refer for more details: Signal and Handler Event System | Qt QML 6.3.0

ApplicationWindow {
    id: application
    onClosing: function(close) {
        ...
        if (condition) {
            close.accepted = false
            userDialog.open()
        } else {
            close.accepted = true
        }
    }

Qml ComboBox indicator is null

Leaving the indicator element as the “default” one by not providing it in Qml in Qt5 (5.12 at least) “worked” in that a sub component could reference its with indicator.width. However porting the Qml to PySide6 resulted in a null dereference.

The contentItem’s rightPadding below references control.indicator.width, which threw the null dereference in PySide6 but not PySide2.

import QtQuick.Controls 2.12
ComboBox {
    id: control
    ...
    contentItem: Text {
        leftPadding: 0
        rightPadding: control.indicator.width + control.spacing
        ...
    }
    delegate: ItemDelegate {
        width: control.width
        ...
    }
    background: Rectangle {
        border.width: 1
        ...
    }
}

Simply adding a dummy Canvas worked around this problem, but naturally that is a bad work around.

import QtQuick.Controls 2.12
ComboBox {
    id: control
    ...
    all the above content
    ...
    indicator: Canvas {
    }
}

It seems that this issue was specific to the 2.12 import, changing the import to leave out the version selection or using 2.5, which was the installed version for PySide6, resolved the null de-refence.

import QtQuick.Controls 2.5

QtQuick.Dialogs 1.2 not installed

The modal dialog import in the main window resulted in an error

module “QtQuick.Dialogs” version 1.2 is not installed

Removing the 1.2 version removes the error, but introduces a new Dialog which results in the next error with the dialog being opened in the Top Left of the parent.

import QtQuick.Dialogs

Qml Dialog is centered Top Left of window

QtQuick.Dialogs 1.2 seemed to center the Modal Dialog to your window. In moving to 2.x version, it inherits from Popup which has x,y coordinates, which default to top left. Alternatively you can use anchors to center the dialog.

anchors.centerIn: Overlay.overlay

Refer popup documentation for use of anchoring or x,y positioning: Popup QML Type | Qt Quick Controls 6.3.0

Qt 6 Qml seems not to have a TreeView

A small set back for our project was what seems to be a lack of the TreeView from QtQuick.Controls 1.4, which was dropped at least initially in version 6. It seems it can be obtained from the Qt Marketplace, but the license is GPLv3 or proprietary, which makes one concerned to use it, if your own project is one of the permissive free software licenses, which many QML projects seem to be.

In our particular case an alternate implementation using ListView was adopted to avoid licensing complications.


Qt ® is a registered trademark of The Qt Company Ltd. and its subsidiaries.

Python ® is a registered trademark of the Python Software Foundation.

Python Gems

This post holds some Python® snippets of common and useful coding scenarios.

Iterate through Python List in Reverse

# Traverse Python list in reverse
for item in reversed(list_of_items):
    print(item)

Print List without brackets

mylist = [1,2,3,4]
print(mylist)
[1, 2, 3, 4]
print(','.join(map(str, mylist)))
1,2,3,4

Adding to lists

Subtly different to many other languages, you can use append, insert to add a single object (of any type) or extend, to add a list to another to form one contiguous list. If you use append to add a list, the whole list will be placed as a single object.

list1 = ['one', 'two']
list2 = ['three', 'four']
# Then extend the first with the second list
list1.extend(list2)
# to get
['one','two','three','four']
# If you instead had
list1.append(list2)
# it would become
['one', 'two', ['three','four']]

List manipulations

# Sort your list
list_sort = sorted(['z', 'a', 'f', 'b'])

Iterate through Dictionary

for key,value in mydictionary.items()
    print(key, value)

for key in mydictionary.keys()
    print(key, mydictionary[key])

for value in mydictionary.values()
    print(value)

Array of Formatted Strings

items = [1,2,3,4]
fstring_items = [f"the number: {i}" for i in items]
print(fstring_items)
['the number: 1', 'the number: 2', 'the number: 3', 'the number: 4']

List of Files in a Directory

directory = "/path/to/dir"
files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]

Directory and File Detection

# Get the absolute path to this python file
current_path = os.path.dirname(os.path.abspath(__file__))

List Module Location

If you need to know where your current environment is getting a module from, then run python cli as below. Make sure you are in the correct environment. i.e if you are using a virtual environment, first activate it.

$ python3
>>> import module_name
>>> print(module_name.__file__)

Install from Repository

python3 -m pip install git+https://bitbucket.org/project-directory/repository.git@tag-or-branch-name

If you want to install globally use sudo.

If you get error error: invalid command 'bdist_wheel' then you need to install python -m pip wheel. This can likely happen in a virtual environment. You could add wheel as a dependency in your setup.py file.

Building your python package

For a long time to build a package the setup.py was called directly.

This is deprecated.

SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.

This docs page has a nice if detailed explanation.

In short replace your previous

python setup.py sdist bdist_wheel

with

python -m build

in the package directory containing the setup.py file.

Threading

What thread is that?

When dealing with thread’s inevitably you need to figure out what is what thread, which the name of the thread can help you with in debugging.

import threading
print(threading.current_thread().name, "your message")

Especially if you are using a User Interface you may need to detect if you are the main thread, to avoid UI access issues.

main = threading.current_thread() is threading.main_thread()

Python ® is a registered trademark of the Python Software Foundation.

Python Date and Time

If there is something that can go wrong in programming, it is date and time. If you are using time, think, and do it right first time. It is amazing how many projects end up in an uncomfortable situation because time-zones or daylight saving or ambiguous time causes hard to reverse issues because copious amounts of data has the wrong time.

At Direkt EmbeddedTM we recommend a few simple rules with date and time.

Always save time in UTC

Always send time in UTC, or an ISO format including the Time Zone

Always print time in UTC, or an ISO format including the Time Zone

If you must use local time only do so on a UI, and always include a timezone somewhere, just to be clear!



Here are some recommended Python® snippets for date and time using the base installation (no libraries).

Date Time in ISO UTC

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

# Always use timezone.utc to ensure isoformat returns +00:00.
print(now.isoformat())

2021-08-13T04:53:23.588839+00:00

Getting your timezone

zone = datetime.now(timezone.utc).astimezone().tzinfo
print(zone)
AEST

Date Formatted File Names

For logging, you want a reverse date, similar to ISO format, but without colons. The following format is pretty common. Add the Z at the end to indicate UTC time. Z if for zulu, aka UTC. It is not very common, but common enough and short and clear.

utc_str = now.strftime("%Y%m%dT%H%M%SZ")
app = "my-app"
file_name = f"{utc_str}-{app}.log"
print(file_name)

20210813T051726Z-my-app.log

Note: f formatted strings are dependent on python 3.6


Python ® is a registered trademark of the Python Software Foundation.

QML Listview With Custom Classes

When it comes to user interfaces Qt® software is good at it, and we love QtQuick and the QML language.

If you have developed UIs after the mobile boom (post 2005), you will have developed List Views. Every platform has them.

There are a fair view examples for Qt software List Views, both for PySide2/PyQt and C++, which point to using QAbstractListModel.

Many of them though point you at list views which show multiple string values. For example a list view of Users with first name and last name. The examples show how to extracts each of these strings in the QAbstractListModel using the Roles in the model.

Instead it would be nice to use a ‘variant’ to obtain a reference to your own class, which will have properties and methods which you can reference directly from your QML Qt software.

In Python this is reasonable straight forward because everything is a variant and the integration works ‘naturally’ as it were. So returning your class via the data() method of the QAbstractListModel works ‘out of the box’.

For C++ classes it is not as intuitive, primarily because to expose your class members and properties to QML, you need a QObject, as detailed in the guidelines provided in the Qt software documentation on integrating C++ with QML language. Take special note of the Q_OBJECT, Q_PROPERTY and Q_INVOKABLE macros.

Unfortunately, to return a custom class as a QVariant in the QAbstractListModel, we need it registered using meta data, which states:

Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered.

from Detailed Description in qMetaType documentation.

Which a QObject does not fulfil as it does not have a copy constructor. So, we are between a rock and a hard place.

QAbstractListView is not the only container class we can use in a list view, but it is arguably the correct one. You could use say QList<Object *>, but then adding and removing items will not be correctly reflected.

The solution in C++ is to ensure that we return a pointer via the QVariant.

Lets look at an example. Firstly, we create our class, and we provide two strings store internally as mText and mCommand, and a submit method. mText is exposed via a property we will call name, and we expose the submit method using a Q_INVOKABLE macro. To provide an example of multiple ways to expose your members and methods, we also provide a public slot alternate_submit, as they can be referenced from QML language directly. Which you will use will be a subjective choice.

#define YOURCLASS_H

#include <QObject>
#include <QMetaType>

class YourClass: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ Text WRITE setText)
public:
    YourClass();
    YourClass(const QString& txt, const QString& command);
    QString Text(void) const;
    QString Command(void) const;
    Q_INVOKABLE void submit(void);
signals:

public slots:
    void alternate_submit(void);
private:
    QString mText;
    QString mCommand;
};

#endif // YOURCLASS_H

Next, we create our abstract list. Although we do not need to, we will create two roles, one called text, the other item, which will return the pointer to our whole class, rather than just a string. The key here is the static_cast on returning our item.

QVariant YourListModel::data(const QModelIndex &index, int role) const
{
   if (!index.isValid())
       return QVariant();
   if ( role == ETEXT)
   {
       return QVariant::fromValue(mDatas[index.row()]->Text());
   }
   else if (role == EITEM)
   {
       return QVariant::fromValue(static_cast<QObject *> mDatas[index.row()]));
   }
   return QVariant();
}

With that in place, your QML language can now reference your mText, in two ways, via model.text as provided by the the abstract list ETEXT role, or model.item.name as provided by the property of the EITEM role. Useful, practically no, but as a demonstration, yes. The other duplicate we added was the submit() and alternate_submit() methods. These can both be used to call a function from your QML language. Lets exemplify with a QML language snippet.

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    width:parent.width
    height: 40
    clip: true
    Button {
        anchors.fill: parent
        onClicked: model.item.alternate_submit()  // or model.item.submit() or item.submit()
        text: model.item.name  // or model.text or item.name
    }
}

A number of alternatives are given for obtaining the properties. This is because model can be implicit to the QML file, so you can drop it. Adding it is arguably an easier read.

Errors you may hit

Undefined Reference in qmetatype.h

If you hit an undefined reference in the qmetatype.h, QMetaTypeFunctionHelper, as follows

...include\QtCore\qmetatype.h:766: error: undefined reference to `YourClass::YourClass()'

Then you have forgotten your default constructor. Referring to the documentation (which of course we read very carefully).

Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered.

from Detailed Description in qmetatype documentation.

In YourClass.ccp simply add

YourClass::YourClass()
{}

TypeError: Property ‘submit’ of object QVariant(YourClass) is not a function

To be able to execute a function in a C++ class from the QML language you need to inherit your class from QObject, assign it the QOBJECT macro. Also the ‘function’ needs to be assigned the Q_INVOKABLE macro if it is a normal C++ method, or be a public slot.

In the YourClass example above, submit() and alternate_submit() can both be used within the QML language.

error: use of deleted function ‘QObject::QObject(const QObject&)’

error: use of deleted function ‘QObject::QObject(const QObject&)’

This will occur if you are trying to return a QVariant of a class inheriting a QObject. This can not be done as QObjects do not have a copy constructor. Instead cast and return the pointer to your object.

return QVariant::fromValue(static_cast<QObject *> mDatas[index.row()]));

depends on non-NOTIFYable properties

QQmlExpression: Expression qrc:/ui/YourClass.qml:10:15 depends on non-NOTIFYable properties:

This simply means you have not added a NOTIFY method for the QML language binding system to use. Refer The Property System | Qt Core 5.15.5, and in their example it is the priorityChanged method.


Qt is a registered trademark of The Qt Company Ltd. and its subsidiaries.

“Python” is a registered trademark of the Python Software Foundation.

MySQL Monitoring

MySQL is one of the most popular database engines.

Here are some handy sql statements to use to help with your development.

View Processes Connected

To pin point who is connected, list all processes.

SHOW PROCESSLIST;
#idUserHostdbCommandTimeStateInfo
1114testlocalhostDB_ASleep1546
2125testlocalhostQuery0initshow processlist
3126testlocalhostDB_BSleep16
Example list of connected client processes

To filter on fields use the information_schema.

select * from information_schema.processlist where db = 'DB_A'

Monitor Connections During Test

While testing your client software, monitor the connections and see if you are leaking them.

SHOW GLOBAL STATUS WHERE Variable_name RLIKE '^(.connect.)$'

The following variables will give you a quick overview of what is going on.

ConnectionsThe number of connection attempts (successful or not) to the MySQL server.

Max_used_connections
The maximum number of connections that have been in use simultaneously since the server started.
Threads_connectedThe number of currently open connections.

Connections will keep growing as it is all connection that have been made, and will not decrease.

Threads_connected you need to ensure goes back to a low number like one or two (for the connection you are monitoring on). If this stays high once your application ends, you are not closing connections.

Max_used_connections is interesting to see at any one time how many connections are active. This way you can increase the max_connections variable.

Acknowledgements

The following knowledge and help sites provided much of this content.

https://dev.mysql.com/doc/refman/8.0/en/show-status.html

Serving Flask Apps with NGinx and Uwsgi

Even an embedded system is going to need a web application, be it on the embedded device, or a part of a test system.

We recommend flask applications, and serving them via Nginx and uWSGI.

There are a lot of examples online. The following one outlines most of the possibilities you can choose from: deploy-flask-uwsgi-nginx

We recommend using the apps-available and apps-enabled as the method for starting your uwsgi server flask application. This is less intrusive and requires less custom parts like an additional system specific service.

For additional security you could install your applications somewhere other than /var/www if that is being served as your root for nginx (for example use /srv/uwsgi-apps instead).

To ensure independent application environments, us a python virtual environment for each of your applications. If you do choose to use the system libraries, we touch on some issues you may run into.

For the nginx configuration, the default uwsgi socket location for your application can be used. On Ubuntu at least it has been:

uwsgi_pass unix:/run/uwsgi/app/<your-application>/socket;

Trouble Shooting

To help you trouble shoot during setup, once you have defined <yourapplication>.ini file under /etc/uwsgi/apps-available and symlinked to apps-enable, restart uwsgi and then tail the uwsgi log for your application.

sudo systemctl restart uwsgi
sudo tail -f /var/log/uwsgi/app/<yourapplication>.log

If something goes wrong inside your application on (re)starting uwsgi, that log will show it.

For example

- mapped 654912 bytes (639 KB) for 8 cores
- *** Operational MODE: preforking ***
Traceback (most recent call last):
  File "./wsgi.py", line 1, in <module>
    from app import app as application
  File "./app.py", line 1, in <module>
    from flask import Flask, jsonify, request
ModuleNotFoundError: No module named 'flask'
- unable to load app 0 (mountpoint='') (callable not found or import error)

Module Not Found Error: No module name

In the example above either the system (or your virtual environment) does not have flask installed or you are using the wrong python plugin.

If your python –version is 3.6.x the python plugin in your uwsgi .ini file should be

plugin = python36

When you run uwsgi through its apps-enabled/<yourapp>.ini method, the application will not be run as your user, so even if you have installed flask and other libraries using pip(3), they are attached to your user’s local, rather than the system library.

If you install using pip a library you will see the output.

Requirement already satisfied: flask in /home/user/.local/lib/python3.6/site-packages

Note the /home/user/.local.

If you are not using a virtual environment, you need to ensure libraries are system libraries, either install them using their corresponding distribution package (e.g. in Ubuntu, sudo apt install python3-flask, or using sudo -H pip …)

No Python Application Found

If you see the error

--- no python application found, check your startup logs for errors ---

Then look earlier in the application log (/var/log/uwsgi/app/<yourapplication>.log) to see if your application was started or if their was an exception.

Unable to load app

unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***

To decipher this, look into <yourapplication>.ini file for the module and chdir lines

chdir = /srv/uswgi-apps/yourapplication
module = wsgi:myapp

The wsgi of wsgi:myapp must correspond to the file name wsgi.py in your /srv/uwsgi-apps/yourapplication folder and the myapp must correspond to the import line in your wsgi.py file which imports your flask app as ‘myapp‘. In the example here, the flask app file was called app.py (as many tutorials tend to name their app files).

from app import app as myapp

if __name__ == '__main__':
    myapp.run()

Gracefully Reloading Applications

The uWSGI documentations detail how to manage your applications once deployed.

We recommend using at least the touch reload option and for finer grain control the Master FIFO method.

Touch Reload

The touch reload means that any time you change your ini file, that application will be reloaded.

touch-reload = /etc/uwsgi/apps-available/<yourapplication>.ini

DANGER! If using touch reload, verify your .ini changes on a staging server before deploying to a production server, because your application will be down if there is an error loading it.

Master FIFO

You can have one or more master-fifo lines.

master-fifo = /tmp/<yourapplication>-master-fifo

From the uwsgi docs: Only the uid running the master has write access to the fifo.

This means that most likely you need to echo commands to the master fifo as the www-data user (unless you specify a different user using uid in .ini file).

$ sudo -u www-data sh
[sudo] password for user: 
$ echo r > /tmp/<yourapplication>-master-fifo

HUP System Signal

If you already deployed your application and you are not in a position to add touch reload or master fifo, you can use the -HUP signal to reload your application.

sudo kill -HUP $(cat /var/run/uwsgi/app/<yourapplication>/pid)

KICAD Schematics Tutorial

If you are a startup needing schematic and PCB design capabilities, or you are learning electronics, Kicad is an open source tool with everything you would need to get started. You can install it following the download instructions on the Kicad web site.

This tutorial will walk you through creating schematic design and PCB layout in Kicad to create some flashing LEDs, using an Astable Multivibrator design.

Select File->New->Project and name your project say LEDFlashAstable.

Start a new schematic project.

To start the schematic design double click on the LEDFlashAstable.sch file.

Double click to open schematic page.

This will start the first schematic page, into which we will place and connect all components. The following is the final schematic we are aiming for.

Final Schematic

To place a component click on the Opamp icon, on the right tool bar.

This will select the component tool. To actually place the component, move the mouse to where on the schematic page you want to place the component and click.

Click on the schematic page to open the component library page. You will see a window and status bar while component libraries are loaded.

If you have a lot of libraries this can take a few minutes.

The first component we will place is the BJT transistor. Choosing a component is one of the subtle skills of an electronics engineer. There as so many to choose from and the wrong choice could be costly later. In this tutorial we will use Kicad to help us choose our component.

Typing in the filter box, will filter the components to suitable ones. BUT, take care as if you have a very large library set (as below with 16427 items loaded), typing a single character will take a long time to filter.

Choose Symbol Window

Instead, copy the text bjt from here and paste it into the filter box.

Then add dual to further narrow down our search.

As you can see in the search window Kicad conveniently gives you the voltage and current rating. A quick scan shows that almost all the voltages are high enough. Additional for the dual devices it seems the lowest current is 100mA, so we could chose any one at which point price may become the deciding factor. Additionally because most are SOT-363 (a 2x2mm package) the choice in Kicad is somewhat irrelevant as most will be pin for pin compatible.

The MBT3904DW would suit this circuit wo we will choose it.

To select the component into Kicad select Unit A of MBT3904DW and click ok.

Place the component by clicking on the page. To place the second half of the package/chip, click on the page again, which will open the library selection to the same location you just were. Click on Unit B, and then click OK.

While the image is ‘see through’, click Y (for mirror) so that the component faces the opposite direction (as per our example circuit).

In a similar way place a resistor.

Now what we want to do is choose the package that we want, which will define our foot print.

Hover the cursor over the resistor, and press ‘e’ for edit.

Click on the Footprints text box and then click the ‘book’ in the right corner. This will open the footprint library.

On the left scroll down to Resistor_SMD (surface mount resistor), and then on the right column scroll to and double click on R_0603_1608Metric.

We chose the 0603 SMD package as its big enough to work with manually using a soldering iron.

Then click ok to close the components edit window.

Now we want to repeat/copy this resistor, to place four resistors. This ensures each resistor will have the same footprint.

Hover your cursor over the same resistor and press ‘c’ for copy. This will ‘copy’ the component and allow you to place it. Repeat another two times to get the 4 resistors.

Place multiple identical resistors

To move the first resistor placed (as it is out of line), hover over it and press ‘m’ for move. Then move it and click once positioned.

Now we need to place two capacitors.

We still have the component symbol selected (right of screen), so click anywhere on the grid/screen (not on a symbol).

In the component library, type c for capacitor or if you have a lot of symbols/libraries, copy and past capacitor to the filter box.

Select C for Unpolarized capacitor (though you could use a polarized capacitor), and click Ok.

Select Unpolarized Capacitor

Whilst the component is ‘see through’ move and place it by clicking the mouse key.

Hover over the capacitor symbol and press ‘e’ for edit, as done earlier for the resistor.

Click on the Footprint text box and then click the ‘books’ to open the foot print library.

This time scroll on the left to Capacitor_SMD and then scroll to and double click C_0603_1608Metric on the right list.

Select 0603 Foot Print for Capacitor

Then click on the Value text box and type 10u or 10uF.

Enter Capacitor Value

Then Click Ok to save the edit.

Hover over the capacitor symbol and press ‘c’ to copy and then place a second by moving the copy and clicking to position it.

As noticed the capacitors are a little too close to the resistors. Click and hold the mouse button, starting top left of middle resistors and move to bottom right to select two resistors.

Then drag the components by moving the mouse to the new position and click the mouse button to place.

Major Components Placed

Now we add two LEDs in series with our outer most resistors.

Click on the screen/grid. Then type LED (or copy paste if you have a large number of symbols) and select LED and click Ok.

Select LED

Press ‘r’ for rotate a few times to orient the LED as shown.

Place LED

Click to place the LED.

Press ‘e’ to edit the component and click on Footprint text box and then the books on the right to open the footprint library.

Scroll on the left column to LED_SMD and in right column double click on LED_1206_3216Metric.

Select LED Footprint

Then click Ok to close the symbol editor.

1206 is a fairly common SMD led size and should be a decent size for our purposes.

Now duplicate this LED by hovering over it and pressing ‘c’ for copy and placing it on the opposite side by moving it and clicking once positioned.

LEDs Placed

Now we need to draw the wires to create the circuit.

Either select the wire tool on the right

or hover over the top left LED pin (circle on component pins) and press ‘w’ for wire.

Then move the mouse to the pin to connect the wire to, the opposing LED…

Join LEDs with wire.

… and click on the pin. Note the automatic creation of the connection points (big green circle) on each pin. This means all those components are connected to the same “NET” or circuit wire.

LED NET or wire circuit

Do the same with the rest of the connections, to create the following circuit.

Join all NETs

Take care with the four cross over wires which should NOT have a junction circle (green dots). If you find a junction is created automatically it will be because your wire crosses a ‘pin’, so move components as needed to avoid this.

Now we have a fairly complete circuit, but we still need power and ground.

This can be done by selecting the ‘power tool’.

Then click on the screen to open the selector. Scroll down, select GND and press Ok.

Place GND near the bottom.

Repeat this except place VDD at the top.

Place VDD and GND

To ensure we have an easy way to connect power and ground, we also add a connector for power and ground.

Select the component symbol and click on the grid/screen.

Type ‘conn’ and scroll down to Connector_Generic and select Conn_01x02 and press Ok.

Select Connector

Place the component by clicking on the screen somewhere. The location is not important as we will keep it ‘separate’.

To set a footprint, hover over the connector component and click ‘e’ for edit. Then click on the Footprints text box and then click on the ‘books’ icon to open the footprint library.

Select Connector_Wire, SolderWirePad_1x02_P3.81mm_Drill0.8mm. This footprint may be too large, but before creating the PCB we are not sure, so select it as a starting point.

Now we will connect ground to pin 1 and Vdd to pin 2 of the connector.

Hover over the GND component at the bottom of the schematic and press ‘c’ for copy. Then move it to near pin 1 of the connector.

Then Hover over VDD component at the top of the schematic and press ‘c’ for copy. Then move it to near pin 2 of the connector.

Keeping VDD at the top and GND below which is a convention in electronic circuits.

To make the wire layout clean, hover over the connector, press ‘m’ for move and then press ‘r’ twice to rotate the component ‘upside down’. Then move it to the left and click to place it.

Placing Power Connector to VDD and GND NET

Now move cursor to the pins and click ‘w’ for wire and connect the wires.

That completes our circuit layout. Note how it looks like we have two circuits. This is because VDD and GND are ‘invisibly’ connected.

If you click the ‘Highlight net tool’ on the right (pink and grey lines) and then click on the top green wire, which is the ‘VDD NET’, you will see the ‘invisible connection’ in the pink lines on the circuit.

Highlight NET Tool

It is a convenient way to visually verify your circuit connections. The safest way though is to use the Electrical Rules Checker.

Electrical Rules Checker

Now we need to check our circuit. The Rule checker helps us by finding issues with our schematic before we go to design the PCB.

Click on the lady bird (bug) icon at top right of tool bar, then click Ok.

The ‘Messages box’ has a message Item not annotated. This is because we have not given each of our components unique identifiers, which is necessary.

Press Close to close the window.

We can manually annotate if we want, but we can automate this, especially useful with larger circuits.

Click on the Annotate button

You can control what is annotated, but for our purposes default settings are fine, so press Annotate button to give each component an identifier.

Press Close to close the annotate window.

Now you will see all the components have an ID and the ? marks are gone.

Press the lady bird button at the top right again, and Press Run in the popup window.

As you can see there are three messages, and three green arrows on the schematic to show where the error is.

The first error is telling us that the connector pin for GND is not connected. If you zoom in, it certainly looks connected and no different to the VDD connector.

To work around this (which may be an issue with the component itself), we can try add a junction.

Click the junction tool on the right.

Then move the cursor to the join, and click to add the junction. Press Run on the Rule Checker window again to check. (Note, you can move the window to the right so it is always there while you fix the circuit, for convenience).

Leave the Rule Checker Window in place while correcting mistakes.

That has corrected the warning, though technically this one should not have been necessary.

The last two errors are related to Kicad noticing the circuit does not have any ‘driving’ components. This is because we have a passive circuit that will be connected to a battery or other power source, which is not defined in the schematic.

To hide these warnings we can add what Kicad calls a ‘power flag’.

Click on the power tool on the right hand tool bar, and type PWR in the popup window.

Select Power Flag

Select PWR_FLAG and press OK.

Place this component near the connector’s VDD. Then hover over it and press ‘c’ to copy it and move it near the GND.

Finally go to the pin and press ‘w’ for wire and create a wire from the PWR_FLAG to the GND and VDD NETs.

Clean Rules

Another Run of the Electrical Rules Checker now will show no warnings or errors.

Finally lets chose the resistors to use. For the maths behind choosing resistor and capacitor values, refer to Astable Multivibrator.

We have two load resistors in series with the LEDs (on the same ‘line’). These we can make 100ohms and are responsible to ensure the current through the LEDs is not too high.

Hover over the resistor and press ‘e’ to edit. Change the Value to 100.

The remaining two resistors R2&R3 we will set to 33kOhms.

The result of this circuit is a flashing rate of just under a second.

Final Circuit

Congratulations, one flashing LED circuit.

Exercises

  1. Test your skills and add a second LED in parallel to each existing LED. i.e. one led to right of D2 and another LED to left of D1.
  2. This circuit has no input protection, so if someone were to supply a high voltage, components would be damaged. Add a current limiting resistor and Zener diode to provide some simple protection to your circuit.

For theory refer to Designing a Simple Over-Voltage Protection Circuit using Zener, which is effectively a Voltage Regulator.

Open source Divergence

Is divergence the open source weakness?

No one could deny open source has greatly impacted the tech industry in the last 20+ years. There is probably not a single web site you visit that does not run on open source in some way.

When it comes to code reuse, you can not beat it.

Yet its proliferation and ease of changing (forking a project) has also meant that for every solution/project there are many divergences.

Is this the open source weakness. Will consistent proprietary source win out in the end?

The Open Source Dilemma

Technology businesses today are faced with the dilemma of open source. They can’t live with it, nor without it.

Traditionally a business needs to own its Intellectual Property to be commercially viable.

Open source contradicts this as ownership is open and shared, making the choice of using it a catch-22.

Once upon a time the businesses owned the high tech and hence in a way controlled the technology. Today, open source drives many technology sectors and is changing its landscape.

Today spending money on entirely proprietary source means you will be competing against companies who are faster to market simply because they leverage and reuse existing open source components.

Yet, even if you do not need to buy open source, it is not “free” and maintaining it for your own needs comes with its own challenges.

How your business handles this dilemma can make the difference between success and failure.

At Direkt Embedded we challenge you to embrace open source and invite you to take us with you on your journey.

Helping you create robust embedded systems and software