Use [feedback]="false"
to hide the strength meter:
<p-password [feedback]="false" [(ngModel)]="value"></p-password>
Use [feedback]="false"
to hide the strength meter:
<p-password [feedback]="false" [(ngModel)]="value"></p-password>
#include <esp_adc/adc_oneshot.h> #include <esp_adc/adc_cali.h> #include <esp_adc/adc_cali_scheme.h> adc_oneshot_unit_handle_t adc1_handle = nullptr; adc_cali_handle_t adc_cali_channel_handle = nullptr; void InitADC() { //-------------ADC1 Init---------------// adc_oneshot_unit_init_cfg_t init_config1 = { .unit_id = ADC_UNIT_1, }; ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); //-------------ADC1 Config---------------// adc_oneshot_chan_cfg_t config = { .atten = ADC_ATTEN_DB_11, .bitwidth = ADC_BITWIDTH_DEFAULT, // default width is max supported width }; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_6, &config)); // Initialize adc_cali_curve_fitting_config_t cali_config = { .unit_id = ADC_UNIT_1, .chan = ADC_CHANNEL_6, .atten = ADC_ATTEN_DB_11, .bitwidth = ADC_BITWIDTH_DEFAULT, }; ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_channel_handle)); } void ADCRead() { // Read raw value int raw = 0; ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC_CHANNEL_6, &raw)); // Apply calibration to value int voltage = 0; ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_channel_handle, raw, &voltage)); printf("ADC Channel[%d] Cali Voltage: %d mV\n", ADC_CHANNEL_6, voltage); }
Usage example:
InitADC(); while(true) { ADCRead(); // Wait for some delay before reading again vTaskDelay(50 / portTICK_PERIOD_MS); }
This prints, for example:
ADC Channel[6] Cali Voltage: 163 mV
You are trying to yaml.safe_dump()
an object which is (or contains) a namedtuple
instance such as:
import yaml import collections MyTuple = collections.namedtuple("MyTuple", ["a", "b", "c"]) mytuple = MyTuple(1,2,3) yaml.safe_dump(mytuple)
which results in the following exception:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/uli/.local/lib/python3.10/site-packages/yaml/__init__.py", line 269, in safe_dump return dump_all([data], stream, Dumper=SafeDumper, **kwds) File "/home/uli/.local/lib/python3.10/site-packages/yaml/__init__.py", line 241, in dump_all dumper.represent(data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 27, in represent node = self.represent_data(data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 58, in represent_data node = self.yaml_representers[None](self, data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 231, in represent_undefined raise RepresenterError("cannot represent an object", data) yaml.representer.RepresenterError: ('cannot represent an object', MyTuple(a=1, b=2, c=3))
You need to add a custom representer to implicitly convert your namedtuple
to a dict.
Before running yaml.safe_dump()
, add the following lines:
import collections def represent_namedtuple(dumper, data): return dumper.represent_dict(data._asdict()) yaml.SafeDumper.add_representer(MyTuple, represent_namedtuple)
You need to add_representer()
for every namedtuple you use!
Now, the yaml.safe_dump()
call should work perfectly:
yaml.safe_dump(mytuple) # Returns 'a: 1\nb: 2\nc: 3\n'
You are trying to yaml.safe_dump()
an object which is (or contains) a defaultdict, e.g.:
import yaml import collections yaml.safe_dump(collections.defaultdict(list))
which results in the following exception:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/uli/.local/lib/python3.10/site-packages/yaml/__init__.py", line 269, in safe_dump return dump_all([data], stream, Dumper=SafeDumper, **kwds) File "/home/uli/.local/lib/python3.10/site-packages/yaml/__init__.py", line 241, in dump_all dumper.represent(data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 27, in represent node = self.represent_data(data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 58, in represent_data node = self.yaml_representers[None](self, data) File "/home/uli/.local/lib/python3.10/site-packages/yaml/representer.py", line 231, in represent_undefined raise RepresenterError("cannot represent an object", data) yaml.representer.RepresenterError: ('cannot represent an object', defaultdict(<class 'list'>, {}))
You need to add a custom representer to implicitly convert the defaultdict
to a dict.
Before running yaml.safe_dump()
, add the following lines:
import collections from yaml.representer import Representer yaml.SafeDumper.add_representer(collections.defaultdict, Representer.represent_dict)
Now, the yaml.safe_dump()
call should work perfectly:
yaml.safe_dump(collections.defaultdict(list)) # Returns'{}\n'
This simple Python script will list all files sorted by filesize in the given directory recursively. You must give an -e/--extension
argument to only consider specific filename extensions. Filename extensions are compared in a case-insensitive manner.
#!/usr/bin/env python3 import os import argparse def convert_size(size_bytes): """ Convert byte size to a human-readable format. """ for unit in ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']: if size_bytes < 1024: return f"{size_bytes:.2f}{unit}" size_bytes /= 1024 return f"{size_bytes:.2f}YB" def get_files_with_extensions(root_dir, extensions): """ Recursively find files with the given extensions in the directory. """ for root, dirs, files in os.walk(root_dir): for file in files: if any(file.lower().endswith(ext.lower()) for ext in extensions): full_path = os.path.join(root, file) size = os.path.getsize(full_path) yield full_path, size def main(): parser = argparse.ArgumentParser(description="List files with specific extensions sorted by size.") parser.add_argument("directory", type=str, help="Directory to search") parser.add_argument("-e", "--extension", type=str, action='append', help="File extension to filter by", required=True) args = parser.parse_args() files = list(get_files_with_extensions(args.directory, args.extension)) files.sort(key=lambda x: x[1]) for file, size in files: print(f"{convert_size(size)} - {file}") if __name__ == "__main__": main()
Usage example: Find largest Python files:
python ListLargestFiles.py -e py .
Usage example: Find (some types of) movies:
python ListLargestFiles.py -e mov -e avi -e mkv -e mp4 ~/Nextcloud
Example output:
[...] 108.81MB - /home/uli/Nextcloud/Google Fotos/20220925_151542.mp4 117.92MB - /home/uli/Nextcloud/Google Fotos/20220925_151958.mp4 237.51MB - /home/uli/Nextcloud/Google Fotos/20220911_115209.mp4 265.02MB - /home/uli/Nextcloud/Google Fotos/20220905_151716.mp4 317.36MB - /home/uli/Nextcloud/Google Fotos/20220912_124906.mp4 431.06MB - /home/uli/Nextcloud/Google Fotos/20220921_153051.mp4
You can install a specific branch of repository using the pip install git+https://...@branch
syntax.
This works with branches and tags:
pip install git+https://github.com/myuser/myrepo.git@mybranch
or, to select a specific revision, just use the revision ID (a shorter revision ID also works):
pip install git+https://github.com/myuser/myrepo.git@aa1edc18e0fb8dc12f550d3b0588eb2c53915097
You intend to publish your package on PyPI using poetry using a command such as
poetry publish
However, you see the following error message:
Publishing mypackage (0.1.0) to PyPI - Uploading mypackage-0.1.0-py3-none-any.whl FAILED HTTP Error 403: Invalid or non-existent authentication information. See https://pypi.org/help/#invalid-auth for more information. | b'<html>\n <head>\n <title>403 Invalid or non-existent authentication information. See https://pypi.org/help/#invalid-auth for more information.\n \n <body>\n <h1>403 Invalid or non-existent authentication information. See https://pypi.org/help/#invalid-auth for more information.\n Access was denied to this resource.<br/><br/>\nInvalid or non-existent authentication information. See https://pypi.org/help/#invalid-auth for more information.\n\n\n \n'
First, you need to create a PyPI API token if you don’t have one already. The username/password authentication is deprecated.
Now run the following command to configure poetry:
poetry config http-basic.pypi __token__ APITOKEN
where APITOKEN
is the API token you want to use on this computer. Leave __token__
as-is since it’s a special username that tells PyPI to use an API token instead of the old & deprecated username/password authentication
It should look like this:
poetry config http-basic.pypi __token__ pypi-AgEIc[...]
Now retry publishing:
poetry publish
Example output:
Publishing mypackage (0.1.0) to PyPI - Uploading mypackage-0.1.0-py3-none-any.whl 100% - Uploading mypackage-0.1.0.tar.gz 100%
I recommend Poetry for initializing, managing & publishing python projects.
Important note: This code is deprecated as it has been superseded by the UliSerial library on GitHub. UIiSerial implements the serial port filtering in a platform-independent manner using pyserial built-in features.
Typically, when one intends to select a serial port in Python, you use a sequence such as
glob.glob('/dev/ttyACM*')[0]
or just go to straight hard-coding the port such as /dev/ttyACM0
.
It should be quite obvious why this isn’t robust:
/dev/ttyACM1
)The following code uses only the linux integrated tool udevadm
to query information and built-in libraries. Currently it does not work on anything but Linux.
import glob import subprocess import re def get_serial_ports(): # Get a list of /dev/ttyACM* and /dev/ttyUSB* devices ports = glob.glob('/dev/ttyACM*') + glob.glob('/dev/ttyUSB*') return ports def get_udev_info(port): # Run the udevadm command and get the output result = subprocess.run(['udevadm', 'info', '-q', 'all', '-r', '-n', port], capture_output=True, text=True) return result.stdout def find_serial_ports(vendor=None, model=None, usb_vendor=None, usb_model=None, usb_model_id=None, vendor_id=None): # Mapping of human-readable names to udevadm keys attribute_mapping = { "vendor": "ID_VENDOR_FROM_DATABASE", "model": "ID_MODEL_FROM_DATABASE", "usb_vendor": "ID_USB_VENDOR", "usb_model": "ID_USB_MODEL_ENC", "usb_model_id": "ID_USB_MODEL_ID", "vendor_id": "ID_VENDOR_ID", "usb_path": "ID_PATH", "serial": "ID_SERIAL_SHORT" } # Filters based on provided arguments filters = {} for key, value in locals().items(): if value and key in attribute_mapping: filters[attribute_mapping[key]] = value # Find and filter ports ports = get_serial_ports() filtered_ports = [] for port in ports: udev_info = get_udev_info(port) match = True for key, value in filters.items(): if not re.search(f"{key}={re.escape(value)}", udev_info): match = False break if match: filtered_ports.append(port) return filtered_ports def get_serial_port_info(port): # Mapping of udevadm keys to human-readable names attribute_mapping = { "ID_VENDOR_FROM_DATABASE": "vendor", "ID_MODEL_FROM_DATABASE": "model", "ID_USB_VENDOR": "usb_vendor", "ID_USB_MODEL_ENC": "usb_model", "ID_USB_MODEL_ID": "usb_model_id", "ID_VENDOR_ID": "vendor_id", "ID_SERIAL_SHORT": "serial", } # Run the udevadm command and get the output udev_info = get_udev_info(port) port_info = {} for line in udev_info.splitlines(): if line.startswith('E: '): key, value = line[3:].split('=', 1) if key in attribute_mapping: # Decode escape sequences like \x20 to a space. # NOTE: Since only \x20 is common, we currently only replace that one port_info[attribute_mapping[key]] = value.replace('\\x20', ' ') return port_info def find_serial_port(**kwargs): """ Find a single serial port matching the provided filters. """ ports = find_serial_ports(**kwargs) if len(ports) > 1: raise ValueError("Multiple matching ports found for filters: " + str(kwargs)) elif len(ports) == 0: raise ValueError("No matching ports found for filters: " + str(kwargs)) else: return ports[0]
# Example usage: Find a serial port matching_ports = find_serial_ports(vendor="OpenMoko, Inc.") print(matching_ports) # Prints e.g. ['/dev/ttyACM0']
This is typically used so you know what filters to add for find_serial_ports()
.
# Example usage: Print info about a serial port serial_port_info = get_serial_port_info('/dev/ttyACM0') print(serial_port_info)
This prints, for example:
{ 'serial': '01010A23535223934CF29A1EF5000007', 'vendor_id': '1d50', 'usb_model': 'Marlin USB Device', 'usb_model_id': '6029', 'usb_vendor': 'marlinfw.org', 'vendor': 'OpenMoko, Inc.', 'model': 'Marlin 2.0 (Serial)' }
On my Desktop, Angular commands such as
ng build
or
ng new
worked successfully, but they didnt stop / terminate after running the command. Instead, they just waited indefinitely without any output.
This is related to analytics being enabled, see this GitHub post.
In order to fix it, run
ng analytics disable --global
It will print
Global setting: disabled Local setting: enabled Effective status: disabled
and it won’t terminate the first time you do this. Just press Ctrl+C
to force stop it.
After that, any command will exit after finishing its task
I suspect this has something to do with IPv6 configuration since my Desktop’s IPv6 network setup is somewhat broken at the moment. However, I did not do any further research into this.
Run these shell commands on your Ubuntu computer to install NodeJS 20.x:
sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo mkdir -p /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg NODE_MAJOR=20 echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list sudo apt-get update sudo apt-get install nodejs -y
Instead of 20
you can also choose other versions like 18
. However, using this method, you can’t install multiple versions of NodeJS in parallel.
This example parses a HTTP POST request body using ArduinoJson. I recommend using my HumanESPHTTP library as simple server library based on the ESP-IDF HTTP server.
constexpr size_t JsonParseBufferSize = 2048; typedef ArduinoJson::StaticJsonDocumentJsonParseBuffer; /** * This buffer is used to parse /api/configure events */ static JsonParseBuffer document; static const httpd_uri_t configureHandler = { .uri = "/api/configure", .method = HTTP_POST, .handler = [](httpd_req_t *req) { // Receive POST body data into a new buffer char* jsonBody = (char*)malloc(req->content_len + 1); jsonBody[req->content_len] = '\0'; // NUL terminate [just in case] if(jsonBody == nullptr) { return SendStatusError(req, "Failed to allocate memory for JSON body"); } int err = httpd_req_recv(req, jsonBody, req->content_len); if(err != req->content_len) { free(jsonBody); return SendStatusError(req, "Failed to read request body"); } // Parse the body as JSON deserializeJson(document, jsonBody, req->content_len); // TODO: Do something with [document] // Cleanup free(jsonBody); return SendStatusOK(req); } };
which uses the following utility functions:
esp_err_t SendStatusError(httpd_req_t *request, const char* description) { httpd_resp_set_type(request, "application/json"); httpd_resp_send_chunk(request, "{\"status\":\"error\", \"error\": \"", HTTPD_RESP_USE_STRLEN); // NOTE: We silently assume that description does not have any special characters httpd_resp_send_chunk(request, description, HTTPD_RESP_USE_STRLEN); httpd_resp_send_chunk(request, "\"}", HTTPD_RESP_USE_STRLEN); httpd_resp_send_chunk(request, nullptr, 0); // Finished return ESP_OK; } esp_err_t SendStatusOK(httpd_req_t *request) { httpd_resp_set_type(request, "application/json"); httpd_resp_sendstr(request, "{\"status\":\"ok\"}"); return ESP_OK; }
When opening your Angular app with a standalone component, you see the following error message:
Can't bind to 'routerLink' since it isn't a known property of 'a'
In the component where the error occurs, add
import { RouterModule } from '@angular/router';
and add
RouterModule,
to the imports
of the component. Example:
@Component({ selector: 'app-top-bar', standalone: true, imports: [ CommonModule, RouterModule ], templateUrl: './top-bar.component.html', styleUrl: './top-bar.component.sass' }) export class TopBarComponent { }
If you encounter
rmt: rmt_transmit(466): loop count is not supported
on the ESP32, this is because you have used a rmt_transmit_config_t
with explicitly set loop_count
.
rmt_transmit_config_t cfg = { .loop_count = 1, .flags = { .eot_level = 0, } }; ESP_ERROR_CHECK(rmt_transmit(/* ... */, &cfg));
but your IC (e.g. ESP32-D0WD-V3) does not support hardware loop mode.
Fixing this is easy: Just comment out the .loop_count
line:
rmt_transmit_config_t cfg = { //.loop_count = 1, // DISABLED as chip does not support it .flags = { .eot_level = 0, } }; ESP_ERROR_CHECK(rmt_transmit(/* ... */, &cfg));
Note that if you leave .loop_count
at its default, it will always act as if .loop_count = 1
.
This extended version of Jupyter Widget notebook with interactive IntSlider making a HTTP POST request features two sliders instead of one.
import ipywidgets as widgets import httpx from IPython.display import display # Define the slider widget delaySlider = widgets.IntSlider( value=450, # Initial value min=0, # Minimum value max=2000, # Maximum value step=1, # Step size description='Delay:' ) lengthSlider = widgets.IntSlider( value=20*10, # Initial value min=0, # Minimum value max=40*10, # Maximum value step=1, # Step size description='Length:' ) # Define a function to handle slider changes def on_slider_change(change): # Define the API URL with the slider value httpx.post("http://10.1.2.3/api/configure", json={"channels":[{ "channel": 0, "delay": delaySlider.value, "length": lengthSlider.value, }]}) # Attach the slider change handler to the slider widget delaySlider.observe(on_slider_change, names='value') lengthSlider.observe(on_slider_change, names='value') # Display the slider widget in the notebook display(widgets.Box(children=[delaySlider, lengthSlider]))
This Jupyter notebook displays an IntSlider
and makes a HTTP POST request with JSON body on every change using the httpx
library.
import ipywidgets as widgets import httpx from IPython.display import display # Define the slider widget slider = widgets.IntSlider( value=450, # Initial value min=0, # Minimum value max=2000, # Maximum value step=1, # Step size description='Value:' ) # Define a function to handle slider changes def on_slider_change(change): slider_value = change['new'] # Define the API URL with the slider value httpx.post("http://10.1.2.3/api/configure", json={"delay": slider_value}) # Attach the slider change handler to the slider widget slider.observe(on_slider_change, names='value') # Display the slider widget in the notebook display(slider)
This basic example showcases how to use PlatformIO with ESP-IDF only (no Arduino) to connect to Wifi in station mode and print Hello world in a loop. It is based on the basic Hello World example from PlatformIO ESP32 with ESP-IDF minimal C++ example:
#include <cstdio> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <esp_wifi.h> #include <esp_log.h> #include <nvs_flash.h> #include <esp_netif.h> #include <esp_event.h> extern "C" { void app_main(void); } static void NetworkEventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { esp_wifi_connect(); ESP_LOGI("wifi", "Retrying to connect to Wifi..."); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI("wifi", "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); } } void InitNVS() { // Initialize NVS esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); } void InitWifi() { // Initialize TCP/IP network interface (required for Wi-Fi) ESP_ERROR_CHECK(esp_netif_init()); // Initialize the event loop ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); // Initialize Wi-Fi wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // Set Wi-Fi to station mode ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); // Configure the Wi-Fi connection wifi_config_t wifi_config = { .sta = { .ssid = "MyWifi", .password = "mypassword" } }; // Register event handler ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &NetworkEventHandler, NULL, NULL)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &NetworkEventHandler, NULL, NULL)); // Set Wi-Fi configuration and start Wi-Fi ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); } void app_main() { InitNVS(); InitWifi(); while(true) { printf("Hello PlatformIO!\n"); // Wait for one second vTaskDelay(1000 / portTICK_PERIOD_MS); } }
[env:esp32dev] platform = espressif32 board = esp32dev framework = espidf monitor_speed = 115200
All sdkconfig
settings have been left at their respective defaults.
While trying to compile your ESP-IDF app using code such as
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
you see an error message such as
src/main.cpp:76:41: error: cannot convert 'esp_interface_t' to 'wifi_interface_t' 76 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); | ^~~~~~~~~~~~~~~ | | | esp_interface_t
Instead of ESP_IF_WIFI_STA
, use WIFI_IF_STA
(which has the correct type):
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
By default, when you initialize a PlatformIO ESP-IDF project, it will generate main.c
– not a C++ but a pure C file
This minimal example instead uses main.cpp
(you can just rename your main.c
– see How to use C++ main.cpp with PlatformIO on ESP32 / esp-idf for a detailed list of steps to do).
#include <cstdio> #include <freertos/FreeRTOS.h> #include <freertos/task.h> extern "C" { void app_main(void); } void app_main() { while(true) { printf("Hello PlatformIO!\n"); // Wait for one second vTaskDelay(1000 / portTICK_PERIOD_MS); } }
When you are using PlatformIO to compile your firmware, it is easily possible to use a C++ main.cpp
instead of the pure C main.c
by just renaming main.c
to main.cpp
However, you also need to properly declary app_main()
. After the #include
section of your main.cpp
(or at the top of the file if you don’t have an #include
section yet), add this code:
extern "C" { void app_main(void); }
This will tell the compiler that app_main()
is a C
function, not a C++
function.
main.cpp
example#include <cstdio> #include <freertos/FreeRTOS.h> #include <freertos/task.h> extern "C" { void app_main(void); } void app_main() { while(true) { printf("Hello PlatformIO!\n"); // Wait for one second vTaskDelay(1000 / portTICK_PERIOD_MS); } }