Programming languages

How to compute crystal load capacitors using Python

The UliEngineering library provides a convenient way to compute which load capacitors are suitable for a given crystal oscillator circuit.

First, install UliEngineering using

sudo pip3 install UliEngineering

Now you need to find out the following parameters:

  • The load capacitance from the crystal’s datasheet. Typical values would be 7pF or 12.5pF or 20pF
  • The pin capacitance CPin from the datasheet of the IC your crystal is connected to (e.g. your Ethernet PHY or your RTC). Typical values would be between 0.5pF to 5pF
  • Estimate the stray capacitance CStray from the board (that is the capacitance of each crystal oscillator pin to the PCB ground). You typically just take an educated guess here, so here are some values to start at:
    •  Start at 3pF
    • If you have a 4+ layer board (as opposed to a two layer board), add 2pF (since the distance to the ground plane below is much smaller on 4 layer boards
    • If you have long traces >1cm (long traces to the crystal should be avoided at all costs!), add 4pF for each cm of trace beyond 1cm for 2-layer boards or add 6pF for each cm of trace beyond 1cm for 4+ layer boards

Now we’ll plug those values into UliEngineering and compute the load capacitance:

from UliEngineering.Electronics.Crystal import load_capacitors
from UliEngineering.EngineerIO import auto_print

auto_print(load_capacitors, cload="9 pF", cpin="1 pF", cstray="5 pF")

This will print 7.00 pF

If you just want to the the value and not an auto-formatted string, use load_capacitors() directly:

capacitor = load_capacitors(cload="9 pF", cpin="1 pF", cstray="5 pF")

In this example, we’ll get capacitor == 7e-12.

Note that 7pF means that you have to add a 7pF capacitor at each side of the crystal. I recommend to use only NP0/C0G capacitors here since X5R/X7R capacitors and other high-k-dielectric ceramic capacitors not only have a high temperature coefficient but also they are not as suitable for analog applications since their capacitance will change with the voltage being applied.

Note that we used a lot of guesswork in the PCB stray capacitance estimation above, so if you need high accuracy, you need to tune your crystal oscillator to work best with your specific board. See our followup post on How to tune your crystal oscillator to get the best possible frequency accuracy for further reading.

Posted by Uli Köhler in Electronics, Python

How to add pandas pd.Timestamp

You can’t directly add Pandas pd.Timestamp instances:

t1 = pd.Timestamp('now')
t2 = pd.Timestamp('now')

t1 + t2
# TypeError: unsupported operand type(s) for +: 'Timestamp' and 'Timestamp'

But you can convert them to a numpy timestamp using their asm8 attribute, convert that timestamp to an integer, add it and convert it back:

t1 = pd.Timestamp('now')
t2 = pd.Timestamp('now')

tsum = (t1.asm8.astype(np.int64) + t2.asm8.astype(np.int64))
tsum_timestamp = pd.Timestamp(tsum.astype('<M8[ns]'))

 

Posted by Uli Köhler in pandas, Python

How to get average or mean between two pandas pd.Timestamp objects?

In order to compute the mean value between two pd.Timestamp instances, subtract them to obtain a pd.Timedelta and then add said Timedelta object to the first (smaller) timestamp:

t1 = pd.Timestamp('now')
t2 = pd.Timestamp('now')

mean_timestamp = t1 + ((t2 - t1) / 2)

 

Posted by Uli Köhler in pandas, Python

How to display BytesIO containing a PNG image in Jupyter/IPython

In IPython, you can use the Image() function to show an image:

 

from IPython.display import Image
Image(filename="img1.png")

But what if you don’t have the PNG data in a file but in a BytesIO?

Use .getvalue():

from IPython.display import Image

my_bio = ... # Insert your code here
Image(my_bio.getvalue())

 

 

Posted by Uli Köhler in Python

How to export certificates from Traefik certificate store

Traefik stores certificates as base64 encoded X.509 certificates and keys inside the certificate store.

This is a python script to export certificate from Traefik certificate store .json file:

import json
import base64

# Read Traefik ACME JSON
with open("acme.json") as acme_file:
    acme = json.load(acme_file)

# Select certificates from a specific resolver
resolver_name = "my-resolver"
certificates = acme[resolver_name]["Certificates"]

# Find the specific certificate we are looking for
certificate = [certificate for certificate in certificates if "myddomain.com" in certificate["domain"].get("sans", [])][0]

# Extract X.509 certificate data
certificate_data = base64.b64decode(certificate["certificate"])
key_data = base64.b64decode(certificate["key"])

# Export certificate and key to file
with open("certificate.pem", "wb") as certfile:
    certfile.write(certificate_data)

with open("key.pem", "wb") as keyfile:
    keyfile.write(key_data)

Note that depending on what is the primary name for your certificate, you might need to use

if "myddomain.com" == certificate["domain"]["main"]

instead of

if "myddomain.com" in certificate["domain"].get("sans", [])

 

Posted by Uli Köhler in Python, Traefik

How to filter OpenStreetmap ways by tag from .osm.pbf file using Python & Osmium

In our previous post Minimal example how to read .osm.pbf file using Python & osmium we investigated how to read a .osm.pbf file and count all nodes, ways and relations.

Today, we’ll investigate how to filter for specific ways by tag using osmium working on .osm.pbf files. In this example, we’ll filter by highwaytrunk

#!/usr/bin/env python3
import osmium as osm
from collections import namedtuple
import itertools

Way = namedtuple("Way", ["id", "nodes", "tags"])

class FindHighwayTrunks(osm.SimpleHandler):
    """
    Find ways with "highway: trunk" tag
    """

    def __init__(self):
        osm.SimpleHandler.__init__(self)
        self.ways = []

    def way(self, way):
        # If this way is a highway: trunk, ...
        if way.tags.get("highway") == "trunk":
            # ... add it to self.ways
            # NOTE: We may not keep a reference to the way object,
            # so we have to create a new Way object
            nodes = [node.ref for node in way.nodes]
            self.ways.append(Way(way.id, nodes, dict(way.tags)))

# Find ways with the given tag
way_finder = FindHighwayTrunks()
way_finder.apply_file("kenya-latest.osm.pbf")

print(f"Found {len(way_finder.ways)} ways")

This example uses kenya-latest.osm.pbf downloaded from Geofabrik, but you can use any .osm.pbf file. Parsing said file takes about 10 seconds on my Desktop.

Note that we can’t just self.ways.append(way) because way is a temporary/internal Protobuf object and may not be used directly since. Hence, we create our own object that just wraps the extracted contents of way: Its id, its list of nodes (node IDs) and a dictionary containing the tags. Otherwise, you’ll see this error message:

Traceback (most recent call last):
  File "run.py", line 32, in <module>
    trunk_handler.apply_file("kenya-latest.osm.pbf")
RuntimeError: Way callback keeps reference to OSM object. This is not allowed.
Posted by Uli Köhler in Geography, Geoinformatics, OpenStreetMap, Python

How to install cartopy on Ubuntu

First, you need to install libproj (which is a dependency of cartopy) using

sudo apt -y install libproj-dev libgeos-dev

After that, install cartopy using

sudo pip3 install cartopy

 

Posted by Uli Köhler in Cartopy, Geoinformatics, Python

How fix Cartopy pip install error ‘Proj 4.9.0 must be installed.’

Problem:

When trying to install cartopy using e.g. pip3 install cartopy you see this error message:

Collecting cartopy
  Downloading Cartopy-0.19.0.post1.tar.gz (12.1 MB)
     |████████████████████████████████| 12.1 MB 13.2 MB/s 
  Installing build dependencies ... done
  Getting requirements to build wheel ... error
  ERROR: Command errored out with exit status 1:
   command: /usr/bin/python3 /tmp/tmp2q7tvpo8 get_requires_for_build_wheel /tmp/tmpfwd5htse
       cwd: /tmp/pip-install-dg2i313t/cartopy
  Complete output (1 lines):
  Proj 4.9.0 must be installed.
  ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/python3 /tmp/tmp2q7tvpo8 get_requires_for_build_wheel /tmp/tmpfwd5htse Check the logs for full command output.

Solution:

Install proj using e.g.

sudo apt -y install libproj-dev

and then install cartopy again using e.g.

sudo pip3 install cartopy

 

Posted by Uli Köhler in Cartopy, Geoinformatics, Python

How to catch ANY exception in gdb

In gdb, run

catch throw

in order to break on any exception that is being thrown.

If you want to only break on a specific exception type instead, use

catch throw [exception type]

 

Posted by Uli Köhler in C/C++

How to compile boost unit test program using CMake

Add this to your CMakeLists.txt:

#
# Compile test suite
#
find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

add_executable(test_myprogram
    tests/MyTest.cpp
)
target_include_directories(test_myprogram PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include")
target_compile_features(test_myprogram PRIVATE cxx_std_17)

target_link_libraries(test_myprogram
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )
add_test(test_myprogram test_myprogram)
# make "make test" run the test program
add_custom_target(test
     DEPENDS myprogram
     COMMAND ./test_myprogram
)

In order to build the program and the test, run

make

In order to run the tests, use

make test
Posted by Uli Köhler in Boost, C/C++, CMake

How to fix CMake error Could not find a package configuration file provided by “boost_unit_test_framework”

Problem:

When compiling your CMake-based C++

CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:117 (find_package):
  Could not find a package configuration file provided by
  "boost_unit_test_framework" (requested version 1.71.0) with any of the
  following names:

    boost_unit_test_frameworkConfig.cmake
    boost_unit_test_framework-config.cmake

  Add the installation prefix of "boost_unit_test_framework" to
  CMAKE_PREFIX_PATH or set "boost_unit_test_framework_DIR" to a directory
  containing one of the above files.  If "boost_unit_test_framework" provides
  a separate development package or SDK, be sure it has been installed.
Call Stack (most recent call first):
  /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:182 (boost_find_component)
  /usr/share/cmake-3.16/Modules/FindBoost.cmake:443 (find_package)
  OCCUtils/CMakeLists.txt:58 (find_package)


-- Configuring incomplete, errors occurred!

Solution:

The error message is trying to tell you that you don’t have the boost unit test library installed (or CMake can’t find it).

On Ubuntu, for example, install it using

sudo apt -y install libboost-test-dev

On Windows you can install it using the prebuilt boost binaries for Windows.

Posted by Uli Köhler in C/C++, CMake

How to fix CMake error Could not find a package configuration file provided by “boost_filesystem”

Problem:

When compiling your CMake-based C++

CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:117 (find_package):
  Could not find a package configuration file provided by "boost_filesystem"
  (requested version 1.71.0) with any of the following names:

    boost_filesystemConfig.cmake
    boost_filesystem-config.cmake

  Add the installation prefix of "boost_filesystem" to CMAKE_PREFIX_PATH or
  set "boost_filesystem_DIR" to a directory containing one of the above
  files.  If "boost_filesystem" provides a separate development package or
  SDK, be sure it has been installed.
Call Stack (most recent call first):
  /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:182 (boost_find_component)
  /usr/share/cmake-3.16/Modules/FindBoost.cmake:443 (find_package)
  CMakeLists.txt:58 (find_package)

Solution:

The error message is trying to tell you that you don’t have the boost filesystem library installed (or CMake can’t find it).

On Ubuntu, for example, install it using

sudo apt -y install libboost-filesystem-dev

On Windows you can install it using the prebuilt boost binaries for Windows.

Posted by Uli Köhler in C/C++, CMake

Minimal Boost C++ Unit test example

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( test1 )
{
    BOOST_CHECK( 2 == 1 );
}

 

Posted by Uli Köhler in C/C++

How to ping gateway in ESP32

You can use the ESP32Ping library in order to easily ping the current gateway IP:

if(Ping.ping(WiFi.gatewayIP(), 1)) { // 1: Just one ping
  // TODO What to do on ping succes
  // Example: Print response time 
  Serial.print(Ping.averageTime()); // Unit: ms
  Serial.println(" ms");
} else {
  // TODO What to do if ping failed?
}

Full example:

#include <Arduino.h>
#include <WiFi.h>

#include <ESP32Ping.h>

void waitForWiFiConnectOrReboot(bool printOnSerial=true) {
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      if(printOnSerial) {
        Serial.println("Wifi connecting...");
      }
      notConnectedCounter++;
      if(notConnectedCounter > 50) { // Reset board if not connected after 5s
          if(printOnSerial) {
            Serial.println("Resetting due to Wifi not connecting...");
          }
          ESP.restart();
      }
  }
  if(printOnSerial) {
    // Print wifi IP addess
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
}

#define LED_BUILTIN 2

void setup() {
  Serial.begin(115200);
  WiFi.begin("MyWifiSSID", "MyWifiPassword");
  // Wait for wifi to be connected
  waitForWiFiConnectOrReboot();
  // Initialize LED
  pinMode(LED_BUILTIN,OUTPUT);
}

void loop() {
  if(Ping.ping(WiFi.gatewayIP())) {
    digitalWrite(LED_BUILTIN,HIGH);
    Serial.print(Ping.averageTime());
    Serial.println(" ms");
  } else {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Error :(");
  }

}

Example output

6.12 ms
5.12 ms
5.11 ms
5.16 ms
4.95 ms
4.88 ms
4.84 ms
7.67 ms
5.01 ms
4.87 ms
4.81 ms
4.80 ms
4.85 ms
5.08 ms
5.76 ms
4.54 ms
5.12 ms
2.77 ms
4.88 ms
4.84 ms
6.07 ms
5.08 ms
4.91 ms
6.04 ms
4.88 ms
4.98 ms
6.43 ms
8.18 ms
4.93 ms
5.17 ms
4.97 ms
5.46 ms
5.88 ms
4.78 ms
4.88 ms
6.03 ms
4.84 ms
5.70 ms
5.94 ms
7.25 ms
5.07 ms
4.78 ms
5.51 ms
4.99 ms
5.04 ms
4.79 ms
4.94 ms
4.81 ms
5.97 ms
5.85 ms
4.83 ms
4.80 ms
4.80 ms
6.29 ms
4.99 ms
5.04 ms
9.21 ms
5.20 ms
6.05 ms
6.14 ms
5.03 ms
4.90 ms
7.22 ms
5.06 ms
4.94 ms
9.03 ms
5.13 ms
11.97 ms
6.32 ms
6.12 ms
4.92 ms
4.92 ms
6.01 ms
4.96 ms
4.98 ms
4.94 ms
6.08 ms
6.11 ms
4.93 ms
5.05 ms
5.78 ms
4.47 ms
6.28 ms
5.02 ms
5.13 ms
5.11 ms
5.19 ms
8.89 ms
5.76 ms
5.18 ms
8.08 ms
4.97 ms
4.89 ms
4.70 ms
5.40 ms
7.46 ms
5.09 ms
4.95 ms
4.96 ms
5.01 ms
5.01 ms
4.89 ms
6.22 ms
6.76 ms
6.92 ms
6.10 ms
9.61 ms
5.29 ms
6.13 ms
5.15 ms
5.02 ms
5.03 ms
5.01 ms
6.13 ms
4.78 ms
3.90 ms
6.27 ms
8.07 ms
5.94 ms
4.50 ms
6.13 ms
4.99 ms
6.07 ms
4.80 ms
4.84 ms
4.95 ms
4.95 ms
6.78 ms
4.88 ms

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, Networking

How to fix Jupyter Hub Exception: Jupyter command `jupyter-hub` not found.

Problem:

When trying to start jupyter hub, you see this error message:

uli@uli-desktop:~$ jupyter hub
Traceback (most recent call last):
  File "/usr/local/bin/jupyter", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/jupyter_core/command.py", line 285, in main
    command = _jupyter_abspath(subcommand)
  File "/usr/local/lib/python3.8/dist-packages/jupyter_core/command.py", line 124, in _jupyter_abspath
    raise Exception(
Exception: Jupyter command `jupyter-hub` not found.

Solution:

Remove the space between jupyter and hub. Instead of

jupyter hub

run

jupyterhub

Example:

uli@uli-desktop $ jupyterhub                           
[I 2021-06-19 02:37:12.766 JupyterHub app:2463] Running JupyterHub version 1.4.1
[I 2021-06-19 02:37:12.766 JupyterHub app:2493] Using Authenticator: jupyterhub.auth.PAMAuthenticator-1.4.1
[I 2021-06-19 02:37:12.766 JupyterHub app:2493] Using Spawner: jupyterhub.spawner.LocalProcessSpawner-1.4.1
[I 2021-06-19 02:37:12.766 JupyterHub app:2493] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-1.4.1
[I 2021-06-19 02:37:12.773 JupyterHub app:1534] Loading cookie_secret from /home/uli/dev/jupyterhub_cookie_secret
[I 2021-06-19 02:37:12.788 JupyterHub proxy:497] Generating new CONFIGPROXY_AUTH_TOKEN
[W 2021-06-19 02:37:12.789 JupyterHub app:1808] No admin users, admin interface will be unavailable.
[W 2021-06-19 02:37:12.789 JupyterHub app:1809] Add any administrative users to `c.Authenticator.admin_users` in config.
[I 2021-06-19 02:37:12.789 JupyterHub app:1838] Not using allowed_users. Any authenticated user will be allowed.
[I 2021-06-19 02:37:12.823 JupyterHub app:2530] Initialized 0 spawners in 0.001 seconds
[W 2021-06-19 02:37:12.825 JupyterHub proxy:699] Running JupyterHub without SSL.  I hope there is SSL termination happening somewhere else...
[I 2021-06-19 02:37:12.825 JupyterHub proxy:703] Starting proxy @ http://:8000
02:37:12.946 [ConfigProxy] info: Proxying http://*:8000 to (no default)
02:37:12.948 [ConfigProxy] info: Proxy API at http://127.0.0.1:8001/api/routes
02:37:12.981 [ConfigProxy] info: 200 GET /api/routes 
[I 2021-06-19 02:37:12.981 JupyterHub app:2778] Hub API listening on http://127.0.0.1:8081/hub/
02:37:12.982 [ConfigProxy] info: 200 GET /api/routes 
[I 2021-06-19 02:37:12.983 JupyterHub proxy:347] Checking routes
[I 2021-06-19 02:37:12.983 JupyterHub proxy:432] Adding route for Hub: / => http://127.0.0.1:8081
02:37:12.984 [ConfigProxy] info: Adding route / -> http://127.0.0.1:8081
02:37:12.985 [ConfigProxy] info: Route added / -> http://127.0.0.1:8081
02:37:12.986 [ConfigProxy] info: 201 POST /api/routes/ 
[I 2021-06-19 02:37:12.986 JupyterHub app:2853] JupyterHub is now running at http://:8000

 

Posted by Uli Köhler in Python

How to run Jupyter Hub (multi-user mode) using systemd

The following script will install Jupyter Hub in single user mode (i.e. only a single Linux user can login to Jupyter Hub using the web interface).

Prerequisites

First install Python & PIP, then NodeJS, then Jupyter Hub, then configurable-http-proxy :

curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs python3-pip
sudo pip3 install jupyterhub
sudo npm i -g configurable-http-proxy

Installing the Jupyter Hub systemd service

Run the following script using sudo!

#!/bin/bash
# This script installs and enables/starts the JupyterHub systemd service
export NAME=JupyterHub

# Create service file
cat >/etc/systemd/system/${NAME}.service <<EOF
[Unit]
Description=${NAME}

[Service]
Type=simple
ExecStart=/usr/bin/env jupyterhub --port=11569
User=root
Group=root

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
systemctl enable --now ${NAME}

This script will install a systemd service named JupyterHub autostart it on boot. It is running on port 11569 by default.

Posted by Uli Köhler in Python, systemd

How to run Jupyter Hub (single user mode) using systemd for autostart

Note: This will only allow a single (preconfigured) user to login to Jupyter lab! See How to run Jupyter Hub (multi-user mode) using systemd on how to deploy Jupyter Hub in multi-user mode using systemd, which allows any Unix user to login!

The following script will install Jupyter Hub in single user mode (i.e. only a single Linux user can login to Jupyter Hub using the web interface).

Prerequisites

First install Python & PIP, then NodeJS, then Jupyter Hub, then configurable-http-proxy :

curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs python3-pip
sudo pip3 install jupyterhub
sudo npm i -g configurable-http-proxy

Installing the Jupyter Hub systemd service

Run the following script as the user you want to be able to login! Do not run the script using sudo !

#!/bin/bash
# This script installs and enables/starts a systemd service
export NAME=JupyterHub-$USER
export GROUP=$(id -gn $USER)
# Create service file
sudo tee /etc/systemd/system/${NAME}.service <<EOF
[Unit]
Description=${NAME}

[Service]
Type=simple
ExecStart=/usr/bin/env jupyterhub

WorkingDirectory=$HOME
User=$USER
Group=$GROUP

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
systemctl enable --now ${NAME}

This script will install a systemd service named JupyterHub-$USER (where $USER is the current user, e.g. uli) and autostart it on boot.

Running multiple services

If you run multiple services, you can run the script for each user and choose a unique port for each service by adding --port=7219 to the /usr/bin/env jupyter hub command, e.g.

ExecStart=/usr/bin/env jupyterhub --port=7192

Alternatively, you can run a single systemwide Jupyter Hub in multi-user mode where multiple users can log in.

Posted by Uli Köhler in Python, systemd

How to fix Jupyter Hub No such file or directory: ‘configurable-http-proxy’

Problem:

When trying to start Jupyter Hub, you see an error message like

[E 2021-06-18 13:07:48.462 JupyterHub proxy:711] Failed to find proxy ['configurable-http-proxy']
    The proxy can be installed with `npm install -g configurable-http-proxy`.To install `npm`, install nodejs which includes `npm`.If you see an `EACCES` error or permissions error, refer to the `npm` documentation on How To Prevent Permissions Errors.
[C 2021-06-18 13:07:48.462 JupyterHub app:2739] Failed to start proxy
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/app.py", line 2737, in start
        await self.proxy.start()
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/proxy.py", line 707, in start
        self.proxy_process = Popen(
      File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
        self._execute_child(args, executable, preexec_fn, close_fds,
      File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child
        raise child_exception_type(errno_num, err_msg, err_filename)
    FileNotFoundError: [Errno 2] No such file or directory: 'configurable-http-proxy'

Solution:

As outlined in the Jupyter Hub installation docs, you need to install the configurable-http-proxy npm package in order for Jupyter to work:

sudo npm install -g configurable-http-proxy

In case you haven’t installed npm, see our article on How to install NodeJS 14.x LTS on Ubuntu in 1 minute or find the appropriate distribution for your OS on the NodeJS download page.

Posted by Uli Köhler in Python

How to run Jupyter Lab as systemd service

If you want to run your Jupyter Lab as a network service on any modern Linux distribution, you can install a systemd service that runs Jupyter. First, you need to install jupyter lab using

sudo pip3 install jupyterlab

In case you don’t have pip3, use sudo apt -y install python3-pip or the equivalent on your distribution.

Note that this script will run Jupyter without token authentication and without password and it will listen on any IP (--ip=0.0.0.0) by default. Either change the command line flags or be aware of the security implications !

#!/bin/bash
# This script installs and enables/starts a systemd service
export NAME=Jupyter

# Create service file
cat >/etc/systemd/system/${NAME}.service <<EOF
[Unit]
Description=${NAME}

[Service]
Type=simple
ExecStart=/usr/bin/env jupyter lab --ip=0.0.0.0 --port 17256 --LabApp.token=''

WorkingDirectory=/home/uli/jupyter
User=uli
Group=uli

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
systemctl enable --now ${NAME}

You need to change the following entries in the script in order to make it work for you:

WorkingDirectory=/home/uli/jupyter
User=uli
Group=uli

Set the WorkingDirectory to whatever directory you want Jupyter to run in. Note that anyone being able to access the webinterface will basically have full access to that directory!

Set User and Group to the user that should run. Note that running Jupyter as root is not allowed. In case you still want to do it, add the --allow-root flag to the command line options.

Now run the script as root to install the service:

sudo ./install-jupyter-service.sh

Now you can access Jupyter at http://[ip of the computer]:17256.

Changing the configuration

In order to change the configuration, I recommend to edit /etc/systemd/systemd/Jupyter.service (or /etc/systemd/systemd/${NAME}.service if you changed export NAME=Jupyter) directly. After that, run

sudo systemctl daemon-reload
sudo systemctl restart Jupyter

You can also change the installation script and re-run it, but you still need to run daemon-reload and restart.

Running multiple Jupyter instances

In order to run  multiple instances, just run multiple copies of the installation script with different names. For example, use

export NAME=Jupyter-DeepLearning

Debugging Jupyter Lab output

If you have problems with Juypter Lab starting up, use

sudo systemctl status Jupyter

in order to view the status and

sudo journalctl -xfu Jupyter

to view all the logs.

Status output example:

● Jupyter.service - Jupyter
     Loaded: loaded (/etc/systemd/system/Jupyter.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-06-11 03:44:28 CEST; 4s ago
   Main PID: 48753 (jupyter-lab)
      Tasks: 1 (limit: 14226)
     Memory: 51.7M
     CGroup: /system.slice/Jupyter.service
             └─48753 /usr/bin/python3 /usr/local/bin/jupyter-lab --ip=0.0.0.0 --port 17256 --LabApp.token=

Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.215 ServerApp] nbclassic | extension was successfully loaded.
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.216 LabApp] JupyterLab extension loaded from /usr/local/lib/python3.8/dist-packages/jupyterlab
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.216 LabApp] JupyterLab application directory is /usr/local/share/jupyter/lab
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.219 ServerApp] jupyterlab | extension was successfully loaded.
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.220 ServerApp] Serving notebooks from local directory: /dev/shm
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.220 ServerApp] Jupyter Server 1.8.0 is running at:
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.220 ServerApp] http://uli-desktop:17256/lab
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.220 ServerApp]     http://127.0.0.1:17256/lab
Jun 11 03:44:29 uli-desktop env[48753]: [I 2021-06-11 03:44:29.220 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
Jun 11 03:44:29 uli-desktop env[48753]: [W 2021-06-11 03:44:29.224 ServerApp] No web browser found: could not locate runnable browser.

Uninstalling the Jupyter Lab service

In order to just stop and disable autostart (but not uninstall) the jupyter lab service, use

sudo systemctl disable --now Jupyter

After that, you can just remove the service file in order to permanently uninstall the service:

sudo rm /etc/systemd/system/Jupyter.service

You can always reinstall using our installation script.

Note that if you have changed the export NAME=... line, you need to replace Jupyter by the value of Name

Posted by Uli Köhler in Python, systemd

How to disable Jupyter Token Authentication

If you want to run Jupyter in a context where the token authentication should be disabled, use the

--LabApp.token=''

command line flag. This will users allow to access the Jupyter without entering any credentials.

Note that this has security implications and everyone that can access the Jupyter server IP & port will be able to access Jupyter! I recommend to at least add another layer of authentication like HTTP basic authentication if you use Jupyter in a public network.

Posted by Uli Köhler in Python