Node.JS Lab

G3N3R4T1NG.C0D3.4.FUN!


Quick reference of useful Linux commands and much more. The kind of thing you need handy when emergencies arise.

NATO Phonetic Alphabet

NATO_Phonetic_Alphabet

Linux permissions

Linux_permissions

Greek Alphabet

Greek_Alphabet

Russian Alphabet

Russian_Alphabet

Resistor Color Code

Resistor_Color_Code

List contents of .tgz file

tar tf /home/user/my_file.tgz

Compress folder into a .tgz file

tar cvzf /home/user/my_folder.tgz my_folder

Compress folder into a .tgz file with date

tar cvzf /home/user/my_folder_$(date +%d-%m-%Y_%H-%M-%S).tgz my_folder

Uncompress .tgz file into a folder

tar xzvf my_folder.tgz -C /home/user/my_folder

SSH Copy file (local > remote) (Upload)

scp my_file.tgz user@host:/home/user/my_file.tgz

SSH Copy file (remote > local) (Download)

scp user@host:/home/user/my_file.tgz my_file.tgz

SSH Copy directory (local > remote) (Upload)

scp -r /home/source user@host:/home/user/destination

SSH Copy directory (remote > local) (Download)

scp -r user@host:/home/user/source /home/destination

Check Linux distro and version

lsb_release -a

or

cat /etc/issue

or

cat /etc/os-release

or

hostnamectl

Follow journal and grep something

journalctl -f | grep something

Follow journal and grep several things

journalctl -f | grep -e orange -e peach -e raspberry

Follow journal and grep regex

journalctl -f | egrep '(orange|peach|raspberry)'

Clear console, restart a service, follow journal, and grep regex

clear && clear && systemctl restart my_service && journalctl -f | egrep '(something)'

Unzip into a specific folder

unzip my_file.zip -d my_folder

Find string in files

grep -r "string to find" /home/dir/*.ext

Find a file

find /home/user/ -name file_name.ext

MongoDB - Connection string for replica set

mongodb://db1.server.com:port,db2.server.com:port,arbiter.server.com:port/MyDataBaseName?replicaSet=MyReplicaSetName

MongoDB - updateOne() example

db.collection_name.updateOne(
    {
        _id: ObjectId("UUIDOFTHEOBJECT")
    } , {
        $set: {
            field1: {
                field2: "new value",
                field3: 3,
                field4: {
                    field5: false
                }
            }
        }
    }
);

Node.JS - Replace all ocurrences of a string (Method 1)

"hello.user.test".split(".").join(" ");

Node.JS - Replace all ocurrences of a string (Method 2)

"hello_user_test".replace(/_/g, " ");

Node.JS - Get date as ISO string

(new Date(Date.now())).toISOString();

Node.JS - Clone / Copy JSON object

let oldObject = { "website":"www.nodejslab.com" };
let newObject = {};
newObject = Object.assign(newObject, oldObject);

Node.JS - Clone / Copy Object

let newObject = Object.create(oldObject);

Certbot - Generate SSL/TLS certificates for NGINX

certbot --nginx -d example.com -d example.net

Certbot - Renew SSL/TLS certificates for NGINX

(TO DO: info here: https://certbot.eff.org/docs/using.html)
certbot renew
certbot --force-renew

Node.JS - List object keys

console.log(Object.keys(myJsonObj));

See file sizes inside a given folder

du /home/* -sh

See size of current folder

du -sch

See size of file system

df -h

Docker - Install docker

apt install docker.io

Docker - Uninstall docker

apt-get remove docker docker-engine docker.io

Docker - Export container to TAR file

docker export containerNameOrID > /home/user/my_file_name_$(date +%d-%m-%Y_%H-%M-%S).tar

Docker - Import container from TAR file

docker import /home/user/my_file_name.tar
docker import /home/user/my_file_name.tar RepoName:TagName

Docker - pull image from https://hub.docker.com

docker pull imageName
docker pull imageName:latest
docker pull imageName:1.2.3

Docker - Follow container logs

docker logs -f --since 1m containerNameOrID

Docker - Go inside the container

docker exec -it containerNameOrID /bin/bash

Docker - See images in local PC

docker images

Docker - List runnning containers

docker ps

Docker - List all containers

docker container ls --all

Docker - Start a container

docker start containerNameOrID

Docker - Stop a container

docker stop containerNameOrID

Docker - Remove container

docker container rm containerNameOrID

Docker - Build an image

docker build . -t myImageName

Docker - Delete an image by force

docker image rm --force myImageNameOrID

Docker - Inspect the layers of an image

docker history --human --format "{{.CreatedBy}}: {{.Size}}" myImageNameOrID

Docker - Run an image in a container in detached mode

docker run -p LocalPort:InternalPort -d myImageNameOrID

Docker - Run an image in a container in detached mode in the host network

docker run -p LocalPort:InternalPort -d myImageNameOrID --network host

Docker - Run an image in a named container and accessing the instance from the host without the container's IP

docker run -d --name newContainerName -e url=http://localhost:externalAppPort -p externalAppPort:internalAppPort imageName
Example:
docker run -d --name some-ghost -e url=http://localhost:3001 -p 3001:2368 ghost

Docker - containers location

/var/lib/docker/containers

Modify user password

passwd userName

Add user

adduser newUserName

Add user to SUDO group

usermod -aG sudo userName

CURL to display total time

curl --request GET 'https://www.somewhere.com' --write-out '\nTOTAL TIME: %{time_total} seconds'

CURL to POST body from JSON file

curl --request POST 'https://www.example.com' -d @MyJSONFile.json --header "Content-Type: application/json"

Node.JS - shortest and simplest string encryption / decryption with AES-256

// Libraries
const crypto = require('crypto');

// Constants
const OUTPUT_FORMAT = "hex";
const ALGORITHM = "aes256";
const KEY = "012345ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const IV = "ABCDEF0123456789";

// Implementations
function encrypt(message) {
    let cipher = crypto.createCipheriv(
        ALGORITHM, 
        Buffer.from(KEY), 
        Buffer.from(IV)
    );
    return (Buffer.concat([
        cipher.update(message), 
        cipher.final()
    ])).toString(OUTPUT_FORMAT);
}

function decrypt(message) {
    let decipher = crypto.createDecipheriv(
        ALGORITHM, 
        Buffer.from(KEY), 
        Buffer.from(IV)
    );
    return (Buffer.concat([
        decipher.update(Buffer.from(message, OUTPUT_FORMAT)),
        decipher.final()
    ])).toString('utf8');
}

// Program
console.log(encrypt("Hello"));
console.log(decrypt(encrypt("Hello")));

Node.JS - copy-paste-run-ready string encryption / decryption with AES-256

/* --- Code ready to copy -> paste -> run --- */
// Libraries
const crypto = require('crypto');
const ENCODING = "hex"; // hex or base64

// Implementations
function encryptAES256(clearMsg, key) {
    let iv = crypto.randomBytes(16); // Generating 16 byte random IV
    let cipher = crypto.createCipheriv(
        "aes256",
        crypto.createHash("sha256").update(key, "utf8").digest(), // 32 bytes always for the key
        iv);
    return (Buffer.concat([
        iv, // Adding the IV at the beginning of the encrypted message (https://nodejs.org/dist/latest-v16.x/docs/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options)
        cipher.update(clearMsg),
        cipher.final()
    ])).toString(ENCODING);
}

function decryptAES256(encMsg, key) {
    let decipher = crypto.createDecipheriv(
        "aes256",
        crypto.createHash("sha256").update(key, "utf8").digest(), // 32 bytes always for the key
        Buffer.from(encMsg, ENCODING).slice(0, 16) // Extracting the IV from the encrypted string (16 bytes)
    );
    return (Buffer.concat([
        decipher.update(Buffer.from(encMsg, ENCODING).slice(16)), // Extracting the encrypted message from the encrypted string
        decipher.final()
    ])).toString('utf8');
}

// Exporting the functions to use it as a module
// module.exports.encryptAES256 = encryptAES256;
// module.exports.decryptAES256 = decryptAES256;

// Demo / Test
let e = encryptAES256("Hello World!", "test");
console.log("> Encrpyted: " + e);

let d = decryptAES256(e, "test");
console.log("> Decrpyted: " + d);

Grep .gz log files

zgrep 'StringIASearchingFor' logFileName.gz

Docker - execute command inside container (check Node.JS version inside container)

docker exec myContainerID node --version

Node.JS - generate UUID-like strings with crypto

const crypto = require('crypto');
let uuidStyleStr = crypto.randomBytes(4).toString('hex') + "-" +
    crypto.randomBytes(2).toString('hex') + "-" +
    crypto.randomBytes(2).toString('hex') + "-" +
    crypto.randomBytes(2).toString('hex') + "-" +
    crypto.randomBytes(6).toString('hex');
console.log(uuidStyleStr);

Check OS version

lsb_release -a

Node.JS - scramble strings N times

let myStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz\\\"";

function scramble(str, times) {

    str = Buffer.from(str, 'utf8');

    console.log(str + " >>>----> " + str.length + " chars");

    for (let i = 1; i <= times; i++) {

        let orig = Math.floor(Math.random() * str.length);
        let dest = Math.floor(Math.random() * str.length);

        let temp = str[orig];
        str[orig] = str[dest];
        str[dest] = temp;

    }

    console.log(str + " >>>----> " + str.length + " chars");
}

scramble(myStr, 223);

/* 
    Expected output (mileage may vary):
    ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz\" >>>----> 64 chars
    4RjeE6DzBtYGAFTrbymnxIZXNq9c0kV"sUWhPiLKg\avJfSHl72p385uCwOdQM1o >>>----> 64 chars
*/

NPM - Pack project into tarball (run at package.json level)

npm pack

NPM - Install project from tarball globally

npm install -g projectName-1.0.0.tgz

NPM - Uninstall project globally

npm uninstall -g projectName

PuTTY - Where is the configuration in Windows?

HKEY_CURRENT_USER\Software\SimonTatham\PuTTY

Copy ownership from one file to another

chown --reference=SourceFile DestinationFile

Copy permissions from one file to another

chmod --reference=SourceFile DestinationFile

Create a file

touch MyFileName

Write to a file from command line

echo "Hello World!" > MyFileName
echo '{ "myArray": [ { "something": { "somethingElse": [ 1, 2, 3 ] } } ] }' > MyJsonFileName

HTML ASCII Encoding Reference

Character From Windows-1252 From UTF-8
space %20 %20
! %21 %21
" %22 %22
# %23 %23
$ %24 %24
% %25 %25
& %26 %26
' %27 %27
( %28 %28
) %29 %29
* %2A %2A
+ %2B %2B
, %2C %2C
- %2D %2D
. %2E %2E
/ %2F %2F
0 %30 %30
1 %31 %31
2 %32 %32
3 %33 %33
4 %34 %34
5 %35 %35
6 %36 %36
7 %37 %37
8 %38 %38
9 %39 %39
: %3A %3A
; %3B %3B
< %3C %3C
= %3D %3D
> %3E %3E
? %3F %3F
@ %40 %40
A %41 %41
B %42 %42
C %43 %43
D %44 %44
E %45 %45
F %46 %46
G %47 %47
H %48 %48
I %49 %49
J %4A %4A
K %4B %4B
L %4C %4C
M %4D %4D
N %4E %4E
O %4F %4F
P %50 %50
Q %51 %51
R %52 %52
S %53 %53
T %54 %54
U %55 %55
V %56 %56
W %57 %57
X %58 %58
Y %59 %59
Z %5A %5A
[ %5B %5B
\ %5C %5C
] %5D %5D
^ %5E %5E
_ %5F %5F
` %60 %60
a %61 %61
b %62 %62
c %63 %63
d %64 %64
e %65 %65
f %66 %66
g %67 %67
h %68 %68
i %69 %69
j %6A %6A
k %6B %6B
l %6C %6C
m %6D %6D
n %6E %6E
o %6F %6F
p %70 %70
q %71 %71
r %72 %72
s %73 %73
t %74 %74
u %75 %75
v %76 %76
w %77 %77
x %78 %78
y %79 %79
z %7A %7A
{ %7B %7B
| %7C %7C
} %7D %7D
~ %7E %7E
%7F %7F
` %80 %E2%82%AC
 %81 %81
%82 %E2%80%9A
ƒ %83 %C6%92
%84 %E2%80%9E
%85 %E2%80%A6
%86 %E2%80%A0
%87 %E2%80%A1
ˆ %88 %CB%86
%89 %E2%80%B0
Š %8A %C5%A0
%8B %E2%80%B9
Π%8C %C5%92
 %8D %C5%8D
Ž %8E %C5%BD
 %8F %8F
 %90 %C2%90
%91 %E2%80%98
%92 %E2%80%99
%93 %E2%80%9C
%94 %E2%80%9D
%95 %E2%80%A2
%96 %E2%80%93
%97 %E2%80%94
˜ %98 %CB%9C
%99 %E2%84
š %9A %C5%A1
%9B %E2%80
œ %9C %C5%93
 %9D %9D
ž %9E %C5%BE
Ÿ %9F %C5%B8
%A0 %C2%A0
¡ %A1 %C2%A1
¢ %A2 %C2%A2
£ %A3 %C2%A3
¤ %A4 %C2%A4
¥ %A5 %C2%A5
¦ %A6 %C2%A6
§ %A7 %C2%A7
¨ %A8 %C2%A8
© %A9 %C2%A9
ª %AA %C2%AA
« %AB %C2%AB
¬ %AC %C2%AC
­ %AD %C2%AD
® %AE %C2%AE
¯ %AF %C2%AF
° %B0 %C2%B0
± %B1 %C2%B1
² %B2 %C2%B2
³ %B3 %C2%B3
´ %B4 %C2%B4
µ %B5 %C2%B5
%B6 %C2%B6
· %B7 %C2%B7
¸ %B8 %C2%B8
¹ %B9 %C2%B9
º %BA %C2%BA
» %BB %C2%BB
¼ %BC %C2%BC
½ %BD %C2%BD
¾ %BE %C2%BE
¿ %BF %C2%BF
À %C0 %C3%80
Á %C1 %C3%81
 %C2 %C3%82
à %C3 %C3%83
Ä %C4 %C3%84
Å %C5 %C3%85
Æ %C6 %C3%86
Ç %C7 %C3%87
È %C8 %C3%88
É %C9 %C3%89
Ê %CA %C3%8A
Ë %CB %C3%8B
Ì %CC %C3%8C
Í %CD %C3%8D
Î %CE %C3%8E
Ï %CF %C3%8F
Ð %D0 %C3%90
Ñ %D1 %C3%91
Ò %D2 %C3%92
Ó %D3 %C3%93
Ô %D4 %C3%94
Õ %D5 %C3%95
Ö %D6 %C3%96
× %D7 %C3%97
Ø %D8 %C3%98
Ù %D9 %C3%99
Ú %DA %C3%9A
Û %DB %C3%9B
Ü %DC %C3%9C
Ý %DD %C3%9D
Þ %DE %C3%9E
ß %DF %C3%9F
à %E0 %C3%A0
á %E1 %C3%A1
â %E2 %C3%A2
ã %E3 %C3%A3
ä %E4 %C3%A4
å %E5 %C3%A5
æ %E6 %C3%A6
ç %E7 %C3%A7
è %E8 %C3%A8
é %E9 %C3%A9
ê %EA %C3%AA
ë %EB %C3%AB
ì %EC %C3%AC
í %ED %C3%AD
î %EE %C3%AE
ï %EF %C3%AF
ð %F0 %C3%B0
ñ %F1 %C3%B1
ò %F2 %C3%B2
ó %F3 %C3%B3
ô %F4 %C3%B4
õ %F5 %C3%B5
ö %F6 %C3%B6
÷ %F7 %C3%B7
ø %F8 %C3%B8
ù %F9 %C3%B9
ú %FA %C3%BA
û %FB %C3%BB
ü %FC %C3%BC
ý %FD %C3%BD
þ %FE %C3%BE
ÿ %FF %C3%BF

HTML URL Encoding Reference

ASCII Character Description URL-encoding
NUL null character %00
SOH start of header %01
STX start of text %02
ETX end of text %03
EOT end of transmission %04
ENQ enquiry %05
ACK acknowledge %06
BEL bell (ring) %07
BS backspace %08
HT horizontal tab %09
LF line feed %0A
VT vertical tab %0B
FF form feed %0C
CR carriage return %0D
SO shift out %0E
SI shift in %0F
DLE data link escape %10
DC1 device control 1 %11
DC2 device control 2 %12
DC3 device control 3 %13
DC4 device control 4 %14
NAK negative acknowledge %15
SYN synchronize %16
ETB end transmission block %17
CAN cancel %18
EM end of medium %19
SUB substitute %1A
ESC escape %1B
FS file separator %1C
GS group separator %1D
RS record separator %1E
US unit separator %1F

Check IP address

ip a

Install and enable SSH server

apt update
apt install openssh-server
systemctl status ssh
ufw allow ssh

Stop and disable SSH server

sudo systemctl stop ssh
sudo systemctl disable ssh

Install NVM (https://github.com/nvm-sh/nvm)

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc

Install CURL

sudo apt update && sudo apt upgrade
sudo apt install curl
curl --version

Hash file (https://www.gnu.org/software/coreutils/manual/html_node/Summarizing-files.html)

b2sum MyFileName.Ext
md5sum MyFileName.Ext
sha1sum MyFileName.Ext
sha224sum MyFileName.Ext
sha256sum MyFileName.Ext
sha384sum MyFileName.Ext
sha512sum MyFileName.Ext

Markdown reference

Cheat Sheet
Basic Syntax

PDF user manuals

Fujifilm X-E4
Fujifilm X-T3
Fujifilm X-H1
Sony Alpha A6000
Nikon D750
Nikon D500
NETGEAR N450/CG3000Dv2
TP-Link 300Mbps Wireless N Router TL-WR841N

Adobe

Camera Raw plugin dowload

NVM - Install Node.JS version

nvm install 1.2.3

NVM - Set Node.JS default version

nvm alias default 1.2.3

Nest.JS - Add reource with CRUD operations

nest g reource MyResourceName

NPM - Update NPM version

npm install -g npm@8.1.4

Include jQuery from a CDN (Content Delivery Network)

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head> 

Nginx - Management commands

systemctl start nginx
systemctl stop nginx
systemctl restart nginx

Nginx - Check configuration syntax and test it

nginx -t

MongoDB - find() example

use MyDataBaseName
db.getCollection('MyCollectionName').find({}).toArray()

Generate SSH RSA Key pair

ssh-keygen -t rsa -b 4096

Scan available WiFi networks

nmcli dev wifi

List USB devices

lsusb

Uncompress bzip2 files

bzip2 -d fileName.bz2

Uncompress .tar file into a folder

tar xvf my_folder.tar -C /home/user/my_folder

Install flex

sudo apt-get update
sudo apt-get install flex

Install bison

sudo apt-get update
sudo apt-get install bison

Search and Replace strings in NANO

Press Ctrl + \
Enter search string [press Enter]
Enter replacement string [press Enter]
Press A to replace all instances

Unmask service

systemctl unmask ServiceName
systemctl enable ServiceName
systemctl start ServiceName

Install Kong OSS DB-less mode in Ubuntu Mate Impish 21.10 in Raspberry PI 4

sudo docker pull arm64v8/kong

sudo docker run -d --name kong \
    -e "KONG_DATABASE=off" \
    -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
    -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
    -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
    -p 8000:8000 \ 
    -p 8443:8443 \
    -p 8001:8001 \
    -p 8444:8444 \
    arm64v8/kong
    
# Ports:
# 8000 = HTTP Proxy
# 8001 = HTTP Admin API
# 8443 = HTTPS Proxy
# 8444 = HTTPS Admin API
# 
# References:
# https://hub.docker.com/r/arm64v8/kong/
# https://docs.konghq.com/gateway/2.7.x/install-and-run/docker/

Connect to WiFi network (didn't work for me)

sudo ifconfig wlan0 up
sudo iwlist wlan0 scan | grep ESSID
sudo iwconfig wlan0 essid MyWiFiNetwork key s:MyKey
sudo dhclient wlan0
sudo ifconfig wlan0 down

Install Kong OSS with PostgreSQL in Ubuntu Mate Impish 21.10 in Raspberry PI 4

# Download docker images

sudo docker pull arm64v8/kong
sudo docker pull arm64v8/postgres

# Start a PostgreSQL container 

sudo docker run -d --name kong-database \
    -p 5432:5432 \
    -e "POSTGRES_USER=kong" \
    -e "POSTGRES_DB=kong" \
    -e "POSTGRES_PASSWORD=kong" \
    arm64v8/postgres:9.6

# Run the database migrations with an ephemeral Kong container

sudo docker run --rm \
    --link kong-database:kong-database \
    -e "KONG_DATABASE=postgres" \
    -e "KONG_PG_HOST=kong-database" \
    -e "KONG_PG_USER=kong" \
    -e "KONG_PG_PASSWORD=kong" \
    -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
    arm64v8/kong kong migrations bootstrap

# Start Kong

sudo docker run -d --name kong \
    --link kong-database:kong-database \
    -e "KONG_DATABASE=postgres" \
    -e "KONG_PG_HOST=kong-database" \
    -e "KONG_PG_PASSWORD=kong" \
    -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
    -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
    -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
    -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
    -p 8000:8000 \
    -p 8443:8443 \
    -p 8001:8001 \
    -p 8444:8444 \
    arm64v8/kong

# After reboot use the following commands to start the containers:

sudo docker container start kong-database
sudo docker container start kong

# Ports:
# 8000 = HTTP Proxy
# 8001 = HTTP Admin API
# 8443 = HTTPS Proxy
# 8444 = HTTPS Admin API
#
# References:
# https://hub.docker.com/r/arm64v8/kong/
# https://hub.docker.com/r/arm64v8/postgres/

PM2 - Start all applications in ecosystem.json

pm2 start ecosystem.json

NMAP - Scan IP address for open ports

# Basic scan:
nmap -sT 1.2.3.4

# RPC service scan:
nmap -sR 1.2.3.4

NMAP - Scan network hosts up

nmap -sP 192.168.0.0/24

NMAP - List network's hostnames

nmap -sL 192.168.0.0/24

Ghost - Hide "Log in" & "Subscribe" menus

# main-header.hbs

{{else}}
    <!--
    <ul>
    <li>
        <a href="{{@site.url}}/signin">Log in</a>
    </li>
    <li>
        <a href="{{@site.url}}/signup">Subscribe</a>
    </li>
    </ul>
    -->
{{/if}}

PIMORONI Inky Impression 7 color display example commands

python3 clear.py

Python - PIMORONI Inky Impression 7 Color Display - Clear and show image

#!/usr/bin/env python3

# File Name: show.py
#
# Usage 1: Show a selected image
#
#     python3 show.py foto1.jpg
#     python3 show.py /home/pi/foto1.jpg
#
# Usage 2: Show a random image
#
#     ls /home/pi/*.jpg | sort -R | tail -1 | while read file; do    python3 show.py $file; done

import time
import sys

from inky.inky_uc8159 import Inky, CLEAN

from PIL import Image
from inky.inky_uc8159 import Inky

inky = Inky()

saturation = 0.6

# Clear display
for _ in range(2):
    for y in range(inky.height - 1):
        for x in range(inky.width - 1):
            inky.set_pixel(x, y, CLEAN)

    inky.show()
    time.sleep(1.0)

# Load image
if len(sys.argv) == 1:
    print("""
Usage: {file} image-file
""".format(file=sys.argv[0]))
    sys.exit(1)

image = Image.open(sys.argv[1])

if len(sys.argv) > 2:
    saturation = float(sys.argv[2])

inky.set_image(image, saturation=saturation)
inky.show()

Install Node.JS 17.4.0 in a separate folder

mkdir /usr/local/lib/nodejs
wget https://nodejs.org/download/release/v17.4.0/node-v17.4.0-linux-x64.tar.gz
tar -xzvf node-v17.4.0-linux-x64.tar.gz
rm -f node-v17.4.0-linux-x64.tar.gz
ln -s /usr/local/lib/nodejs/node-v17.4.0-linux-x64/ node-17.4.0
rm /usr/local/lib/nodejs/node-1.2.3

List all known coded character sets

iconv -l

Change character set encoding of a file

iconv -f US-ASCII -t UTF-8 MyUS-ASCIIFile.txt -o MyUTF8File.txt

Rename all .jpg and .JPG files with a specific name and number

ls *.{jpg,JPG} | cat -n | while read n f; do mv "$f" "photo$n.jpg"; done

Select a random .jpg or .JPG file from a folder

ls *.{jpg,JPG} | sort -R | tail -1 | while read file; do 
    # Do something $file
done

Select several random files from a folder

ls | sort -R | tail -$N | while read file; do 
    # Do something $file
done

Create a service with a timer

The goal here is to run a script that will select a random image and show it in the PIMORONI Inky Impression 7 Color ePaper every determined period of time. I assume python3 is already installed in the machine. The Pimorony Inky Impression libraries and examples can be downloaded from this website. I am using a Raspberry PI Zero WH with Raspbian GNU/Linux 11 (bullseye).

  1. Install Pimoroni's Inky libraries (you may say YES to all).
    curl https://get.pimoroni.com/inky | bash
    
  2. Go inside the directory where services are.
    cd /etc/systemd/system/
    
  3. Create a the timer file.
    nano inky7.timer
    
    Add the following content to it:
    [Unit]
    Description=PIMORONI Inky Impression 7 color e-paper random image select and display TIMER.
    
    [Timer]
    OnUnitActiveSec=180s
    OnBootSec=180s
    
    [Install]
    WantedBy=timers.target
    
    Save and exit.
  4. Create a the service file.
    nano inky7.service
    
    Add the following content to it:
    [Unit]
    Description=Description=PIMORONI Inky Impression 7 color e-paper random image select and display JOB.
    
    [Service]
    Type=oneshot
    SyslogIdentifier=inky7_service
    ExecStart=bash /usr/local/bin/inky7.sh
    
    Save and exit.
  5. Create the script file.
    nano /usr/local/bin/inky7.sh
    
    Add the following content to it:
    ls /home/pi/Pictures/Inky/*.jpg | sort -R | tail -1 | while read file; do    python3 /usr/local/bin/show.py $file; done
    
    Save and exit.
  6. Create the Python file.
    nano /usr/local/bin/show.py
    
    Add the following content to it (careful with the indentation):
    #!/usr/bin/env python3
    
    # File Name: show.py
    #
    # Usage 1: Show a selected image
    #
    #     python3 show.py foto1.jpg
    #     python3 show.py /home/pi/foto1.jpg
    #
    # Usage 2: Show a random image
    #
    #     ls /home/pi/*.jpg | sort -R | tail -1 | while read file; do    python3 show.py $file; done
    
    import time
    import sys
    
    from inky.inky_uc8159 import Inky, CLEAN
    
    from PIL import Image
    from inky.inky_uc8159 import Inky
    
    inky = Inky()
    
    saturation = 0.6
    
    # Clear display
    for _ in range(2):
        for y in range(inky.height - 1):
            for x in range(inky.width - 1):
                inky.set_pixel(x, y, CLEAN)
    
        inky.show()
        time.sleep(1.0)
    
    # Load image
    if len(sys.argv) == 1:
        print("""
    Usage: {file} image-file
    """.format(file=sys.argv[0]))
        sys.exit(1)
    
    image = Image.open(sys.argv[1])
    
    if len(sys.argv) > 2:
        saturation = float(sys.argv[2])
    
    inky.set_image(image, saturation=saturation)
    inky.show()
    
  7. Reload the daemon to take the changes into account.
    systemctl daemon-reload
    
  8. Start the timer, this will start the service automatically.
    systemctl start inky7.timer
    
  9. Enable the timer so that it runs at startup, this is optional.
    systemctl enable inky7.timer
    

Example logs (journalctl):

Jan 23 20:38:49 raspberrypi systemd[1]: Starting Description=PIMORONI Inky Impression 7 color e-paper random image select and display JOB....
Jan 23 20:39:49 raspberrypi systemd[1]: inky7.service: Succeeded.
Jan 23 20:39:49 raspberrypi systemd[1]: Finished Description=PIMORONI Inky Impression 7 color e-paper random image select and display JOB..
Jan 23 20:39:49 raspberrypi systemd[1]: inky7.service: Consumed 22.214s CPU time.

Jan 23 20:42:49 raspberrypi systemd[1]: Starting Description=PIMORONI Inky Impression 7 color e-paper random image select and display JOB....
Jan 23 20:43:49 raspberrypi systemd[1]: inky7.service: Succeeded.
Jan 23 20:43:49 raspberrypi systemd[1]: Finished Description=PIMORONI Inky Impression 7 color e-paper random image select and display JOB..
Jan 23 20:43:49 raspberrypi systemd[1]: inky7.service: Consumed 22.266s CPU time.

Notes:
To stop the timer and the service respectively run:

systemctl stop inky7.timer
systemctl stop inky7.service

To stop running at startup run:

systemctl disable inky7.timer

Configure Raspberri PI

sudo raspi-config

Encode string to base64

echo -n 'MyStringToBeEncoded' | base64