How to fix APT error NO_PUBKEY B53DC80D13EDEF05


When you run apt update, you see the following error message:

Err:12 gcsfuse-bionic InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B53DC80D13EDEF05


Install the Google Cloud key using

curl -fsSL| gpg -o /usr/share/keyrings/kubernetes-archive-keyring.gpg --dearmor

After that, you can try running

sudo apt update


Posted by Uli Köhler in Linux

What voltage does the KNX TP1 equalization pulse have?

According to the KNX standard, the allowable voltage during the equalization part of a logical 0 transmitted on the bus is between 0V and 13V above the DC voltage or reference voltage, which is typically 30V.

Source: KNX standard: Communication media: Twisted Pair 1, v01.02.02, section 1.1.2, Figure 7, download at

Posted by Uli Köhler in Electronics

List of switching power MOSFETs from LCSC

This is a list of a few standard switching MOSFETs from LCSC that I use regularly.

The lists are sorted by ascending size. Power MOSFET is defined as >= 1A continous drain current.


  • HL20N04 SOT-89 40V 20A 38W 14mOhm 0,1135€/pc @ 100pcs
  • SL10N10A SOT-223 100V 10A 3.2W 120mOhm 0,123€/pc @ 100pcs
  • STN2610D D2PAK 60V 50A 63W 0,1775€/pc @ 100pcs



Posted by Uli Köhler in Components, Electronics

Are there SMD variants of the JST VH 3.96mm connector series?

As far as I can tell from the JST website, JST does not sell any SMD variants of the JST XH series.

However, LCSC lists some 3rd party SMD connectors as VH 3.96mm, such as:

So far I have not tested those and I don’t know yet if they are compatible with the standard JST housings.

Posted by Uli Köhler in Components, Electronics

Where to find cheap RJ45 connectors

Generally, I always recommend going with metal-shielded RJ45 ports since those tend not to break as often.

If you want to buy more than, say, 10pcs, you can check out LCSC’s Ethernet Connectors / Modular Connectors lineup. The very good prices compensate for the shipping fee even when buying only medium quantities.

Note that it’s easy to mix up models with and without magnetics at the moment as there is no suitable filter. It’s easiest to just look at the length of the connector – RJ45 connectors without magnetics are almost cubic in size (i.e. length in the direction where you insert the connector is equal to the width) whereas connectors with magnetics are much longer. Nevertheless, always check the datasheet.

Some examples:

With magnetics:

No magnetics:

  • RCH RC01133, No LEDs, no magnetics, right angle, THT, 0.11€/pc @100pcs
  • HC-WK88-H16-DB, Two LEDs, no magnetics, right angle, THT, 0.14€/pc @ 100pcs
  • RJ45-B-1*1, Two LEDs, no magnetics, shield with case contacts, 0.22€/pc @ 100pcs
Posted by Uli Köhler in Components, Electronics, Networking

How to compute non-inverting OpAmp amplifier gain using UliEngineering in Python

In this example, we’ll use the UliEngineering library to compute the gain of a non-inverting OpAmp amplifier, given the two feedback resistor values R1 and R2

In order to install UliEngineering (a Python 3 library) run:

sudo pip3 install -U UliEngineering

We can now use noninverting_amplifier_gain() from the UliEngineering.Electronics.OpAmp package to convert between the units of temperature:

Tip: You can pass both numbers (like 100e3) or strings (such as 100 kΩ) to most UliEngineering functions. SI prefixes like k and m are automatically decoded.


from UliEngineering.Electronics.OpAmp import noninverting_amplifier_gain

# Gain of a non-inverting amplifier with 100k & 10k feedback resistor
gain = noninverting_amplifier_gain(100e3, 10e3)
# gain = 11.0

# ... or you can use strings
gain = noninverting_amplifier_gain("100k", "10k")
# ... or strings with units
gain = noninverting_amplifier_gain("100kΩ", "10kΩ")

# You can also automatically format the result
from UliEngineering.EngineerIO import auto_format
print(auto_format(noninverting_amplifier_gain, "100k", "10k"))
# prints 11.0 V/V
Posted by Uli Köhler in Electronics, Python

Where to find cheap 5.5×2.1mm PCB-mount barrel jack connectors?

As with most commodity PCB components, LCSC is a good place to find cheap connectors if you want to buy more than 10 pcs or so (due to the shipping fees).

These are listed in AC/DC power connectors. In order to find them quickly, select the Package=Plugin filter and select In Stock and then sort by price (ascending).

Using this method, you can easily find parts such as:

Keep in mind that these are not 100% the same regarding their geometry, so always check in the datasheet if they fit your footprint.

Posted by Uli Köhler in Components, Electronics

How to access RouterOS API in Python using the ‘routeros’ library (minimal example)

This example uses the routeros library from PyPI (GitHub) to access the MikroTik API and extract the system identity.

#!/usr/bin/env python3
from routeros import login

routeros = login('admin', 'abc123abc', '')

output = routeros('/system/identity/print')
# Extract the one identity string from the list of dictionaries


Posted by Uli Köhler in MikroTik, Python

Netmiko MikroTik RouterOS SSH key login example

In our previous example Netmiko MikroTik RouterOS minimal example we showed how to login to a RouterOS device using netmikoand password-based login.

#!/usr/bin/env python3  
from netmiko import ConnectHandler
import os.path
mikrotik = {
    'device_type': 'mikrotik_routeros',
    'host':   '',
    'username': 'admin',
    'key_file': os.path.expanduser("~/.ssh/id_mikrotik"),
with ConnectHandler(**mikrotik) as mikrotik_connection:
    print(mikrotik_connection.send_command(f'/system/identity/print', cmd_verify=False))


Example output:

name: MySwitch01


Posted by Uli Köhler in MikroTik, Networking, Python

How to parse Ethernet packet header (src & dst MAC addresses) using lwIP

You can use this code, for example, in a custom packet handler function.

#include <lwip/prot/ethernet.h>

eth_hdr* hdr = reinterpret_cast<eth_hdr*>(buffer);
auto srcMAC = hdr->src.addr;
auto dstMAC = hdr->dest.addr;

Serial.printf("Received packet: Packet of length %d\n", len);
Serial.printf("    Src MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", srcMAC[0], srcMAC[1], srcMAC[2], srcMAC[3], srcMAC[4], srcMAC[5]);
Serial.printf("    Dst MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", dstMAC[0], dstMAC[1], dstMAC[2], dstMAC[3], dstMAC[4], dstMAC[5]);
Serial.printf("    Our MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", ourEthernetMAC[0], ourEthernetMAC[1], ourEthernetMAC[2], ourEthernetMAC[3], ourEthernetMAC[4], ourEthernetMAC[5]);


Posted by Uli Köhler in Embedded, Networking

Where does lwIP parse the Ethernet packet header?

The Ethernet packet header is parsed in ethernet_input() in lwip/src/netif/ethernet.c:


Posted by Uli Köhler in Embedded, Networking

What is the default esp_eth_update_input_path() handler function?

By default, esp-idf or the Arduino framework handles incoming Ethernet packets using the

static esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv);

function in components/esp_eth/src/esp_eth_netif_glue.c which (besides calling just calls the exported functionesp_netif_receive():

static esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv)
    return esp_netif_receive((esp_netif_t *)priv, buffer, length, NULL);

The function esp_netif_receive() is declared in esp_netif.h and implemented in esp_netif_lwip.c.

This function will call esp_netif->lwip_input_fn(...) on the packet, which will in turn call the interface-type specific .input_fn(...), which is one of

or for wrapped interfaces:

  • esp_netif_lwip_slip_input
  • esp_netif_lwip_ppp_input
Posted by Uli Köhler in ESP8266/ESP32, Networking

How to pass string to executable stdin using in Python

In our previous example How to capture stdout to string using in Python we showcased how to use, out_stream=...) to capture stdout to a StringIO which can then be converted to a string.

Similarly, we can pass a string to the sub-process stdin by first converting it into a StringIO and then using, in_stream=...).

stdin_str = "abc123" # what we want to pass to stdint

stdin_io = StringIO(stdin_str)
result ="myexecutable", in_stream=stdin_in)
# ...
Posted by Uli Köhler in Python

How to capture stdout to string using in Python

This example showcases how to capture stdout to a string instead of printing it to system stdout:

The basic trick is to initialize a StringIO (a file-like object where pyinvoke can write the stdout from the sub-process to) and pass it to the out_stream argument of

import invoke
from io import StringIO

outStream = StringIO()
result ="wg genkey", out_stream=outStream)
stdout_str = outStream.getvalue()
print("Result: ", stdout_str)


Posted by Uli Köhler in Python

How to add git repository to PlatformIO dependencies (lib_deps)

Typically, you would add a PlatformIO library dependency by adding the following to platformio.ini:

lib_deps =

but you can also add a git repository (the following example uses the main branch such as master or main):

lib_deps =

or you can use a specific branch or tag

lib_deps =


Posted by Uli Köhler in PlatformIO

How to fix Arduino / PlatformIO undefined reference to `loop()’


While trying to compile your Arduino or PlatformIO project, you see an error message such as
/home/uli/.platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/libFrameworkArduino.a(main.cpp.o):(.literal._Z8loopTaskPv+0x8): undefined reference to `loop()'


You have not declared a loop() function in your source code. Open main.cpp or your .ino source code file and start with the following (empty) loop() function which does nothing:
void loop() {
    // Nothing to do here since HTTPServer
    // is running in a separate thread
After you’ve added any void loop() { /* ... */} function to your sourcecode try to build/upload again and the error message should have disappeared.
If you want, you can also add code such as to print a message to the serial port every time the loop is run:
void loop() {
    // Nothing to do here since HTTPServer
    // is running in a separate thread
    Serial.println("Hello world!");


Posted by Uli Köhler in Arduino, C/C++, PlatformIO

How to add “platformio” / “pio” shortcut on Linux command line

Typically, when you want to use the pio executable from PlatformIO, you need to first activate the virtual environment using

source ~/.platformio/penv/bin/activate

However, you can easily create a shortcut using a shell alias using:

For bash:

echo -e '\nalias platformio="source ~/.platformio/penv/bin/activate"\n' >> ~/.bashrc

For zsh:

echo -e '\nalias platformio="source ~/.platformio/penv/bin/activate"\n' >> ~/.zshrc

Note that in order for the change to take effect, you need to restart your shell (or open a new shell).

Now you can use run


and you’ll immediately have access to pio and other PlatformIO tools.

Posted by Uli Köhler in PlatformIO

How to create new PlatformIO project on the command line

You can create a new PlatformIO project on the command line by running e.g.

pio project init --board esp32dev --ide vscode --sample-code

Note that all options (--board and --ide) are optional. Without --sample-code, PlatformIO will not automatically generate src/main.cpp

This will initialize a new PlatformIO project in the current directory.

Posted by Uli Köhler in PlatformIO
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy