hwclock --set --date '2021-01-04 13:04:00'
hwclock --set --date '2021-01-04 13:04:00'
The following systemd service will automatically. See this guide for more information on the setup and ensure sudo i2cdetect -y 1
detects the RTC with address 0x68
.
This is an automatic service installation & enable script based on A simple systemd service autoinstall script . This script will automatically enable the service on boot:
#!/bin/bash # This script installs and enables/starts a systemd service # It also installs the service file export NAME=ConfigureRTC cat >/etc/systemd/system/${NAME}.service <<EOF [Unit] Description=${NAME} [Service] ExecStart=/bin/bash -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device && hwclock -s' Restart=always [Install] WantedBy=multi-user.target EOF # Enable and start service systemctl enable --now ${NAME}.service
This is just the systemd service:
[Unit] Description=ConfigureRTC [Service] ExecStart=/bin/bash -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device && hwclock -s' Restart=always [Install] WantedBy=multi-user.target
sudo systemctl disable --now systemd-timesyncd
sudo systemctl enable --now systemd-timesyncd
You can verify if NTP is active or not by running
timedatectl
Then look for these lines:
System clock synchronized: yes NTP service: active
System clock synchronized
will tell you if the NTP service has successfully synchronized the system time to a NTP time server: yes
if synchronized, no
if not synchronized.
NTP service
will tell you if the NTP service is running, i.e. if it is trying to synchronize the system time to a NTP time server: active
if running, inactive
when not running
Local time: Tue 2023-03-14 16:49:28 CET Universal time: Tue 2023-03-14 15:49:28 UTC RTC time: Tue 2023-03-14 15:49:28 Time zone: Europe/Berlin (CET, +0100) System clock synchronized: yes NTP service: active RTC in local TZ: no
Local time: Tue 2023-03-14 16:48:01 CET Universal time: Tue 2023-03-14 15:48:01 UTC RTC time: Tue 2023-03-14 15:48:01 Time zone: Europe/Berlin (CET, +0100) System clock synchronized: no NTP service: inactive RTC in local TZ: no
sudo raspi-config nonint do_i2c 0
Now load the relevant modules:
sudo modprobe "i2c-bcm2835" sudo modprobe "i2c-dev" sudo modprobe "rtc-ds1307"
and now check if the I2C device file exists using stat /dev/i2c-1
:
$ stat /dev/i2c-1 File: /dev/i2c-1 Size: 0 Blocks: 0 IO Block: 4096 character special file Device: 5h/5d Inode: 169 Links: 1 Device type: 59,1 Access: (0660/crw-rw----) Uid: ( 0/ root) Gid: ( 998/ i2c) Access: 2023-03-14 16:23:06.643999999 +0100 Modify: 2023-03-14 16:23:06.643999999 +0100 Change: 2023-03-14 16:23:06.643999999 +0100 Birth: -
If you instead see
ls: cannot access '/dev/i2c-1': No such file or directory
either the driver is not loaded properly or I2C is disabled. Try rebooting the system and repeating the commands above and possibly checking dmesg
for any error messages.
#!/bin/bash check_module() { local module="$1" if grep -Fxq "$module" /etc/modules then echo "$module already exists in /etc/modules" else echo "$module not found in /etc/modules. Adding it now..." echo "$module" | sudo tee -a /etc/modules fi } check_module "i2c-dev"
This script will at the module if it doesn’t exist in /etc/modules yet.
Note that it will only detect if exactly the same line as the argument to check_module
is already present in /etc/modules
. For example if i2c-dev option1=value1
is in /etc/modules
, the script will only detect this line correctly if you call it like
check_module "i2c-dev option1=value1"
but not if you call it like
check_module "i2c-dev"
When trying to detect I2C devices on the Raspberry Pi (Raspbian) using i2cdetect
, you see the following error:
$ i2cdetect bash: i2cdetect: command not found
Install i2c-tools
using
sudo apt -y install i2c-tools
After installing i2c-tools
, you can use i2cdetect
and other related tools such as i2cget
.
While trying to rename a file using fs.move()
in NodeJS, you see an error message such as
Error: EXDEV: cross-device link not permitted, rename '/tmp/upload_8a8c71784abf9942b40c1359935b1997' -> 'myfile.pdf'
This error occurs because you are moving a file from one drive (/tmp
in our example above) to another drive (the current directory in our example above). On most platforms, this can’t be done using a simple rename operation.
Instead, fs.copyFile()
the file.
For example, instead of
await fs.move('/tmp/upload_8a8c71784abf9942b40c1359935b1997', 'myfile.pdf')
first, copy the file:
await fs.copyFile('/tmp/upload_8a8c71784abf9942b40c1359935b1997', 'myfile.pdf')
and then – if desired – remove the source file to mirror the behaviour of os.move()
as closely as possible.
await fs.remove('/tmp/upload_8a8c71784abf9942b40c1359935b1997', 'myfile.pdf') await fs.unlink('/tmp/upload_8a8c71784abf9942b40c1359935b1997')
First, import stat
from the NodeJS standard library:
import { stat } from "node:fs/promises";
// Async-await style: const statResult = await stat("myfile.pdf"); const fileSizeInBytes = statResult.size;
stat("myfile.pdf").then(statResult => { const fileSizeInBytes = statResult.size; // TODO your code goes here });
In our previous post Matplotlib custom SI-prefix unit tick formatter we showed how to format a matplotlib Y axis with a custom unit with SI prefixes.
Similarly, we can use UliEngineering.Math.Decibel
in order to format plots (most notably plots with a logarithmic Y axis) as decibels:
from UliEngineering.Math.Decibel import * import matplotlib.ticker as mtick def decibel_formatter(v0=1.0, unit='dB'): def format_value(value, pos=None): dB = value_to_dB(value, v0=v0) return f'{dB:.0f} {unit}' return format_value # Usage example: plt.gca().set_yscale("log") # Optional plt.gca().yaxis.set_major_formatter(mtick.FuncFormatter(decibel_formatter()))
See our previous post How to get list of all footprints using KiCAD pcbnew plugin Python API and How to get all selected footprints using KiCAD pcbnew plugin Python API for more info on how to obtain a footprint object.
Once you have a pcbnew.FOOTPRINT
object, you can get its graphical elements (which are basically the lines, rectangles, circles etc in the footprint – but not any silkscreen labels) using
footprint.GraphicalElements()
Example:
for graphical_element in footprint.GraphicalItems(): print(graphical_element)
Output:
<pcbnew.FP_TEXT; proxy of <Swig Object of type 'FP_TEXT *' at 0x7fc47f2c41e0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f0f10b0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c69d0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c6d30> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f0f10e0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c6cd0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c6ca0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f0f38d0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c68b0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c41e0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f0f10b0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c69d0> > <pcbnew.FP_SHAPE; proxy of <Swig Object of type 'FP_SHAPE *' at 0x7fc47f2c6d30> >
You can filter them using
fp_texts: list[pcbnew.FP_TEXT] = [ item for footprint in selected_footprint.GraphicalItems() if type(item).__name__ == 'FP_TEXT' ] fp_shapes: list[pcbnew.FP_SHAPE] = [ item for footprint in selected_footprint.GraphicalItems() if type(item).__name__ == 'FP_SHAPE' ]
In our previous post, we showed how to get all selected objects using the KiCAD python API using
pcbnew.GetCurrentSelection()
You can simply filter these entries to obtain just a list of selected footprints using either a for loop with inline filtering:
for selected_object in pcbnew.GetCurrentSelection(): if type(selected_object).__name__ == 'FOOTPRINT': print(selected_object.GetReference())
or using a list comprehension:
selected_footprints: list[pcbnew.FOOTPRINT] = [ footprint for footprint in pcbnew.GetCurrentSelection() if type(footprint).__name__ == 'FOOTPRINT' ]
#!/usr/bin/env python import pcbnew import os class SimplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Plugin Name as shown in Pcbnew: Tools->External Plugins" self.category = "A descriptive category name" self.description = "A description of the plugin and what it does" self.show_toolbar_button = False # Optional, defaults to False self.icon_file_name = os.path.join(os.path.dirname(__file__), 'simple_plugin.png') # Optional, defaults to "" def Run(self): board: pcbnew.BOARD = pcbnew.GetBoard() footprints: list[pcbnew.FOOTPRINT] = board.GetFootprints() # TODO Do something useful with [board] for selected_object in pcbnew.GetCurrentSelection(): print(selected_object) SimplePlugin().register() # Instantiate and register to Pcbnew
D39 D32 D23 D37 D18 D34 D11 D15
When you have a FOOTPRINT
object or a list of footprints in KiCAD’s Python API such as from board.GetFootprints()
, you can get their reference designators such as C11
or R4
using
pcbnew.GetCurrentSelection():
Not that not only footprints might be selected but also other objects such as shapes, vias, pads etc.
#!/usr/bin/env python import pcbnew import os class SimplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Plugin Name as shown in Pcbnew: Tools->External Plugins" self.category = "A descriptive category name" self.description = "A description of the plugin and what it does" self.show_toolbar_button = False # Optional, defaults to False self.icon_file_name = os.path.join(os.path.dirname(__file__), 'simple_plugin.png') # Optional, defaults to "" def Run(self): board: pcbnew.BOARD = pcbnew.GetBoard() footprints: list[pcbnew.FOOTPRINT] = board.GetFootprints() for selected_object in pcbnew.GetCurrentSelection(): # TODO Do something useful with selected_object print(selected_object) SimplePlugin().register() # Instantiate and register to Pcbnew
<pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8b70> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8de0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8c30> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8b40> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8db0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8c00> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8ba0> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8e10> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8bd0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8b70> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8de0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8c30> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8b40> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8db0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8c00> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8ba0> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8e10> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8bd0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8b70> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8de0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8c30> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8b40> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8db0> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8c00> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8ba0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8e10> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8bd0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8b70> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8de0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8c30> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8b40> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8db0> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8c00> > <pcbnew.PCB_TRACK; proxy of <Swig Object of type 'PCB_TRACK *' at 0x7fc49d2a8ba0> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8e10> > <pcbnew.FOOTPRINT; proxy of <Swig Object of type 'std::deque< FOOTPRINT * >::value_type' at 0x7fc49d2a8bd0> > <pcbnew.PCB_VIA; proxy of <Swig Object of type 'PCB_VIA *' at 0x7fc49d2a8b70> >
When you have a FOOTPRINT
object or a list of footprints in KiCAD’s Python API such as from board.GetFootprints()
, you can get their reference designators such as C11
or R4
using
footprint.GetReference()
#!/usr/bin/env python import pcbnew import os class SimplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Plugin Name as shown in Pcbnew: Tools->External Plugins" self.category = "A descriptive category name" self.description = "A description of the plugin and what it does" self.show_toolbar_button = False # Optional, defaults to False self.icon_file_name = os.path.join(os.path.dirname(__file__), 'simple_plugin.png') # Optional, defaults to "" def Run(self): board: pcbnew.BOARD = pcbnew.GetBoard() footprints: list[pcbnew.FOOTPRINT] = board.GetFootprints() # TODO Do something useful with [board] for footprint in footprints: print(footprint.GetReference()) SimplePlugin().register() # Instantiate and register to Pcbnew
When using KiCAD’s Python API for pcbnew
, you can obtain a list of FOOTPRINT
objects using
board: pcbnew.BOARD = pcbnew.GetBoard() footprints: list[pcbnew.FOOTPRINT] = board.GetFootprints()
The : pcbnew.BOARD
and : list[pcbnew.FOOTPRINT]
are optional but will tell your editor (such as visual studio code) which object to expect for better autocompletion.
#!/usr/bin/env python import pcbnew import os class SimplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Plugin Name as shown in Pcbnew: Tools->External Plugins" self.category = "A descriptive category name" self.description = "A description of the plugin and what it does" self.show_toolbar_button = False # Optional, defaults to False self.icon_file_name = os.path.join(os.path.dirname(__file__), 'simple_plugin.png') # Optional, defaults to "" def Run(self): board: pcbnew.BOARD = pcbnew.GetBoard() footprints: list[pcbnew.FOOTPRINT] = board.GetFootprints() # TODO Do something useful with [board] for footprint in footprints: print(footprint) SimplePlugin().register() # Instantiate and register to Pcbnew
When using KiCAD’s Python API for pcbnew
, you can simply get a board object using pcbnew.GetBoard()
:
board: pcbnew.BOARD = pcbnew.GetBoard()
The : pcbnew.BOARD
is optional but will tell your editor (such as visual studio code) which object to expect for better autocompletion.
#!/usr/bin/env python import pcbnew import os class SimplePlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "Plugin Name as shown in Pcbnew: Tools->External Plugins" self.category = "A descriptive category name" self.description = "A description of the plugin and what it does" self.show_toolbar_button = False # Optional, defaults to False self.icon_file_name = os.path.join(os.path.dirname(__file__), 'simple_plugin.png') # Optional, defaults to "" def Run(self): board: pcbnew.BOARD = pcbnew.GetBoard() # TODO Do something useful with [board] print(board) SimplePlugin().register() # Instantiate and register to Pcbnew
static const httpd_uri_t valueHandler = { .uri = "/api/value", .method = HTTP_GET, .handler = [](httpd_req_t *req) { httpd_resp_set_type(req, "application/json"); // create json docuemnt DynamicJsonDocument json(1024); json["value"] = 1.0; // Serialize JSON to string std::string buf; serializeJson(json, buf); // Send response httpd_resp_send(req, buf.c_str(), buf.length()); return ESP_OK; } };
In order to add the ArduinoJson
to PlatformIO, add the following lib_deps
to platformio.ini
:
lib_deps = [email protected]
The default password for MEBx is
admin
You can list all connected cameras using
v4l2-ctl --list-devices
Example output:
bcm2835-codec-decode (platform:bcm2835-codec): /dev/video10 /dev/video11 /dev/video12 /dev/video18 /dev/video31 /dev/media0 bcm2835-isp (platform:bcm2835-isp): /dev/video13 /dev/video14 /dev/video15 /dev/video16 /dev/video20 /dev/video21 /dev/video22 /dev/video23 /dev/media2 /dev/media3 rpivid (platform:rpivid): /dev/video19 /dev/media1 HD USB Camera: HD USB Camera (usb-0000:01:00.0-1.2): /dev/video0 /dev/video1 /dev/media4
When trying to run the VirtualHere USB client on Linux, you see the following error message:
$ ./vhuit64 Please run with sudo modprobe: ERROR: could not insert 'vhci_hcd': Operation not permitted
Simply run vhuit64
using sudo
:
sudo ./vhuit64
When trying to import your erpc
project generated Python code using e.g.
from erpc_myproject import *
You see the following error message:
Traceback (most recent call last) Cell In [1], line 1 ----> 1 from erpc_myproject import * File ./erpc_myproject/__init__.py:13 11 version = "unknown" 12 if version != "1.9.1": ---> 13 raise ValueError("The generated shim code version (1.9.1) is different to the rest of eRPC code (%s). \ 14 Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) 16 from . import common 17 from . import client ValueError: The generated shim code version (1.9.1) is different to the rest of eRPC code ('unknown'). Install newer version by running "python setup.py install" in folder erpc/erpc_python/.
Either you have not installed the erpc
Python library (if the error message lists ... different to the rest of eRPC code ('unknown')
) or you have installed the wrong version (e.g. ... (1.9.1) is different to the rest of eRPC code ('1.10.0')
).
If you have not installed erpc
at all, simply use
pip install erpc
and retry running your script.
If you have installed the wrong version, you have two options:
Just use the original command (some erpcgen
call) you’ve used to re-generate the code using the currently installed version.
For this, you need to determine what the correct version is. Let’s consider the following error message:
ValueError: The generated shim code version (1.9.1) is different to the rest of eRPC code ('1.10.0'). Install newer version by running "python setup.py install" in folder erpc/erpc_python/.
From this message, we can read that the shim code version is 1.9.1
whereas you have 1.10.0
installed. Therefore, in order to make it work, we need to install erpc
version 1.9.1
.
Install it using
pip install -U erpc==1.9.1
and then retry your command. If you are using jupyter notebooks or similar, you need to restart your kernel to load the new library!