Just learned about My traceroute, which combines the functions of the traceroute and ping programs in one tool. Really handy!
sudo apt install mtr
mtr wikipedia.org
Just learned about My traceroute, which combines the functions of the traceroute and ping programs in one tool. Really handy!
sudo apt install mtr
mtr wikipedia.org
While searching on how to validate a given JSON string, I found two options. The first simply returns a Boolean value, the second also returns information about what could be wrong.
DATA(lv_json) = '{'
&& '"employee": {'
&& |"name" : "Max", |
&& |"age" : 43, |
&& '}'
&& '}'.
" option 1:
DATA(is_valid) = /ui5/cl_json_util=>is_wellformed( lv_json ).
" option 2:
DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ).
TRY.
lo_reader->next_node( ).
lo_reader->skip_node( ).
CATCH cx_sxml_parse_error INTO DATA(lx_parse_error).
WRITE lx_parse_error->get_text( ).
ENDTRY.
There are many blogs describing how to create a QR-Code in the context of SAPscript or Smartforms (e.g. here, here, here and here). But I was looking for a way to generate a QR-Code and only receive the graphical data stream from it, without the need for any manual steps such a creation via SE73. During my search, I found these two notes, which contained all the information I needed:
Following my little test report:
PARAMETERS p_text TYPE string DEFAULT 'My QR-Code Content'.
DATA: lv_action TYPE i.
DATA: lv_filename TYPE string.
DATA: lv_fullpath TYPE string.
DATA: lv_path TYPE string.
TRY.
cl_rstx_barcode_renderer=>qr_code( EXPORTING i_module_size = 25 " Size of smallest module (in pixel, max: 32000)
i_barcode_text = p_text " Barcode text
* i_mode = 'A' " Mode ('N', 'A', 'L', 'B', 'K', 'U', '1', '2'; note 2030263)
* i_error_correction = 'H' " Error correction ('L', 'M', 'Q', 'H')
* i_rotation = 0 " Rotation (0, 90, 180 or 270)
IMPORTING e_bitmap = DATA(e_bitmap) ). " Bitmap in BMP format
DATA(lt_raw_data) = cl_bcs_convert=>xstring_to_solix( e_bitmap ).
" Save-Dialog
cl_gui_frontend_services=>file_save_dialog( EXPORTING default_file_name = 'QR-Code'
default_extension = 'bmp'
file_filter = |{ cl_gui_frontend_services=>filetype_all }|
CHANGING filename = lv_filename
path = lv_path
fullpath = lv_fullpath
user_action = lv_action ).
IF lv_action EQ cl_gui_frontend_services=>action_ok.
" Download file to disk
cl_gui_frontend_services=>gui_download( EXPORTING filename = lv_fullpath
filetype = 'BIN'
bin_filesize = xstrlen( e_bitmap )
CHANGING data_tab = lt_raw_data ).
ENDIF.
CATCH cx_rstx_barcode_renderer INTO DATA(lo_exp).
MESSAGE lo_exp->get_text( ) TYPE 'I'.
ENDTRY.
I had some videos in the format “My Episode #01.mkv” which I wanted to rename to “S01E01 My Episode #01.mkv“. This little script did the job for me:
# Specify the directory containing the files. For current directory use: $(dirname "$0")
directory="/path/to/your/directory"
# Loop through all .mkv files in the directory
for file in "$directory"/*.{webm,mkv}; do
# Check if the file exists to avoid errors when no files match
[ -e "$file" ] || continue
# Extract the base filename (without the directory path)
filename=$(basename "$file")
# Use regex to find the episode number (e.g., #01, #02)
if [[ $filename =~ \#([0-9]+) ]]; then
episode_number=${BASH_REMATCH[1]}
# Pad the episode number with a leading zero if it's a single digit
if [ ${#episode_number} -eq 1 ]; then
episode_number="0$episode_number"
fi
# Construct the new filename
new_filename="S01E${episode_number} $filename"
# Rename the file
mv "$file" "$directory/$new_filename"
echo "Renamed: $filename -> $new_filename"
fi
done
“This utility is a compilation of Windows tasks I perform on each Windows system I use. It is meant to streamline installs, debloat with tweaks, troubleshoot with config, and fix Windows updates.”
This is discussed for many years and unfortunately will not be implemented in the UI5 framework itself (see here). There are already different blogs describing how to build a wrapper for oData requests (for example here and here).
But with ES2024 it now got super simple to do this:
async function readData(model, entitySet) {
const [promise, resolve, reject] = Promise.withResolver( )
model.read(entitySet, {
success: data => resolve(data),
error: error => reject(error)
})
return promise
}
const user = await readData(oDataModel, "/user")
With ES2023 there are some new Array methods that always return a copy of the original array: toReversed, toSorted, toSpliced, with
const people = [
{ name: "Max", age: 19 },
{ name: "Tom", age: 65 },
{ name: "Liz", age: 43 },
]
// Copying counterpart of the reverse() method
const reversedPeople = people.toReversed()
// [{age: 43, name: "Liz"}, {age: 65, name: "Tom"}, {age: 19, name: "Max"}]
// Copying version of the sort()
const sortedPeople = people.toSorted((a,b) => a.age - b.age)
// [{age: 19, name: "Max"}, {age: 43, name: "Liz"}, {age: 65, name: "Tom"}]
// Copying version of the splice() method
const splicedPeople = people.toSpliced(1,1)
// [{age: 19, name: "Max"}, {age: 43, name: "Liz"}]
// Copying version of using the bracket notation to change the value of a given index
const updatedPeople = people.with(0, { name: "Pat", age: 12})
// [{age: 12, name: "Pat"}, {age: 65, name: "Tom"}, {age: 43, name: "Liz"}]
Activate the last_seen
attribute via the Zigbee2MQTT interface. Go to Settings → Advanced → Last seen → Choose ISO_8601
Per default, the last seen
sensor is disabled for all Home Assistant entities. To enable the last_seen
attribute for all devices, add the following lines via VS Code in homeassistant → zigbee2mqtt → configuration.yaml
device_options:
legacy: false
homeassistant:
last_seen:
enabled_by_default: true
Now you must either restart Home Assistant or activate the entity manually: Go to Settings → Devices & services → Entities and adjust your Filter like this:
Then search for last seen
, click on select all
(right next to the filter button) and choose Enable selected
in the context menu when clicking on the three dots in the top right corner.
Now the last_seen
entity values should be visible, and you can use this new entity to detect an offline device. For example, by using this blueprint or by creating a template sensor like it is described here (related YT video).
{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | rejectattr('attributes.device_class', 'undefined') | selectattr('attributes.device_class', '==', 'timestamp') %}
{% if 'last_seen' in state.entity_id and (states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((24 | int) * 60 * 60))) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find=' last seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
{% endif %}
{% endfor %}
{{ result.sensors | join('\n') | truncate(254, True) }}
The template sensor can be put somewhere on your dashboard or used in an automation. Following the automation I’m using:
alias: Notify when zigbee device goes offline using last_seen
description: ""
trigger:
- platform: state
entity_id:
- sensor.offline_zigbee_devices
from: null
to: null
for:
hours: 0
minutes: 10
seconds: 0
condition: []
action:
- service: notify.mobile_app_mi_8
metadata: {}
data:
title: |-
{% if not states('sensor.offline_zigbee_devices') %}
All Zigbee Devices Online!
{% else %}
The following Zigbee Devices are offline:
{% endif %}
message: >-
{% for entity in expand('sensor.offline_zigbee_devices') | map(attribute='entity_id') | list %}
{{ states(entity) }}
{% endfor %}
mode: single
I also recommend excluding the last_seen
sensors from the Logbook, because else the Logbook is flooded with changes. To do this, simply add the following lines in your configuration.yaml file:
logbook:
exclude:
entity_globs:
- sensor.*_last_seen
In an automation, you can retrieve the friendly_name of the triggering device using:
{{ trigger.to_state.attributes.friendly_name }}
Helpful if an automation can be triggered by different devices (e.g. garage door 1 or garage door 2) and you want to send a notification that explicitly names the triggering device:
- service: notify.ALL_DEVICES
data:
title: Garage open!
message: >-
{{ trigger.to_state.attributes.friendly_name }} is open
Since ES2024 there is a new way to create promises by using the withResolver
function:
// ES 6 Via Constructor
const promise = new Promise((resolve, reject) => { }
// ES2024 Via factory function
const [promise, resolve, reject] = Promise.withResolver( )
Since ES2018 there is an additional handler called finally
:
const promise = fetch("/myAPI")
promise
.then(response => console.log(response))
.catch(error => console.error(error))
.finally(() => console.log("Called in any case"))
And handling multiple Promises has been made easier by the new methods allSettled
, any
, race
which were introduced in ES2020 and ES2015:
// Promise that resolves when all promises are resolved
const promise = Promise.all([promiseA, promiseB])
promise.then(([valueA, valueB]) => console.log(valueA, valueB))
// ES2020 Promise that resolves when all promises are settled (either resolved or rejected)
const promise = Promise.allSettled([promiseA, promiseB])
// ES2020 Promise that resolves when either promiseA or promiseB is resolved
const promise = Promise.any([promiseA, promiseB])
// ES2015 Promise that resolves/rejects when any promise is resolved or rejected
const promise = Promise.race([promiseA, promiseB])