Whisky Festival 2025

Going with my friend Vincent to the Whisky Festival, with some of his friends.
Missing the train, buying whisky coins every half hours, some beers afterwards. Fun times.
Bought some cigars accompanying the whiskies.
Seen Wullie Macmorland walking around.
I’ve played pipes in his restaurant several times in the 90’s
Last time I’ve seen him is 10+ years ago, with a great story.

When I walked into his restaurant, he remembered me. And my love for whisky.
Before I could sit down, he called me to his bar.
“I have a whisky you have to try!” He said.
Sneaky with the bottle below the counter, he poured me a “whisky”.
It was disgusting !
I said, “THAT’s not whisky!”
“Yes it is!” he smiled. Safari whisky!
He was laughing at my disgusted face.
“Someone gave it to me, it’s everything but whisky.”
It’s even bad for lamp oil! LOL

Jup, I am a fan of smoky whiskies.

UPDATE:
20250312 – Liquid BBQ smoke whisky delivered ..

Some 3D printing

Made a cap for a mushroom button, with editable text.

It’s on makersworld:
https://makerworld.com/en/models/1093945

Also made some chair thingies. We have wooden floors and her new chair has pointy feet.

Made using Openscad

difference(){
union(){
cylinder(h=5,d=30);

translate([0,0,1.5]){
difference(){
rotate([20,0,0])
cylinder(h=30,d=25);

rotate([20,0,0])
cylinder(h=30,d=17);
}
}
}
translate([0,0,-5])
cylinder(h=5,d=30);
}

Some tests with SDR (Software Defined Radio)

I’ve got a little SDR stick a while ago with some antenna’s.

I’ve got some extra antenna’s

So I was playing around with P2000 and Airplane Radio (tracking overhead planes)

Airplane info in terminal
P2000 info
Local webserver on my laptop tracking overhead planes.

For debugging I used SigDigger

dump1090-mutability --aggressive --interactive --net --net-http-port 8080 --net-sbs-port 30003 

git clone https://github.com/Zanoroy/multimon-ng.git
 cd multimon-ng/
 mkdir build
 cd build
 cmake ..
 make
rtl_fm -f 169.65M -M fm -s 22050 -p 83 -g 30 | ./multimon-ng -a FLEX -t raw /dev/stdin

dump1090-fa --interactive

Home Assistant with Openhasp and cheap display using LGVL.

I bought a cheap esp32 display (4 inch 480×480) from China.

It also has three relays to control lights.

Below is a gallery with default screens.

Flashing OpenHasp was a breeze.
Configure the thing for HA was not so easy.

Install OpenHasp via Hacs on HA.

There is a webinterface on the display, here you have to configure wifi, mqtt and the pages.

Config files used for this first test:

{"page":1,"id":34,"obj":"img","src":"L:/pcb480x480.png","auto_size":0,"w":480}
{"page":1,"id":1,"obj":"btn","x":0,"y":0,"w":480,"h":50,"text":"IOTDesigns","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
{"page":1,"id":2,"obj":"btn","x":10,"y":60,"w":105,"h":90,"toggle":true,"text":"\uE335","text_font":32,"mode":"break","align":1}
{"page":1,"id":3,"obj":"dropdown","x":10,"y":160,"w":170,"h":60,"options":"Option 1\nOption 2\nOption 3\nOption 4"}
{"page":0,"id":1,"obj":"label","x":375,"y":45,"h":40,"w":100,"text":"00.0°C","align":2,"bg_color":"#2C3E50","text_color":"#FFFFFF"}
{"page":1,"id":6,"obj":"slider","x":20,"y":300,"w":440,"h":40,"min":15,"max":85}

Designer at : https://haspdesigner.qrisonline.nl/

4inchdisplay2:
    objects:
      - obj: "p0b1"  # temperature label on all pages
        properties:
          "text": '{{ states("sensor.livingtemperature") }}°C'
      - obj: "p1b2"  # light-switch toggle button
        properties:
          "val": '{{ 1 if states("switch.livingshelly") == "on" else 0 }}'
          "text": '{{ "\uE6E8" if is_state("switch.livingshelly", "on") else "\uE335" | e }}'
        event:
          "up":
            - service: homeassistant.toggle
              entity_id: "switch.livingshelly"
      - obj: "p1b3"  # dropdown
        event:
          "changed":
            - service: persistent_notification.create
              data:
                message: I like {{ text }}
      - obj: "p1b6" # Light brightness
        properties:
          "val": "{{ state_attr('number.dinnertable_brightness_0', 'brightness') if state_attr('number.dinnertable_brightness_0', 'brightness') != None else 0 }}"
        event:
          "changed":
            - service: light.turn_on
              data:
                entity_id: number.dinnertable_brightness_0
                brightness:  "{{ val }}"
          "up":
            - service: light.turn_on
              data:
                entity_id: number.dinnertable_brightness_0
                brightness:  "{{ val }}"

NOTE: Dimmer is not working via HA (yet), but mqtt messages are working.

objTypeDescriptionExtra Parts
btnBinaryButton
switchToggleSwitchindicator, knob
checkboxToggleCheckboxindicator
labelVisualLabel
ledVisualLED
spinnerVisualSpinnerindicator
objVisualBase Object
lineVisualLine
imgVisualImage
cpickerSelectorColor pickerknob
rollerSelectorRollerselected
dropdownSelectorDropdown Listselected, items, scrollbar
btnmatrixSelectorButton Matrixitems
msgboxSelectorMessageboxitems, items_bg
tabviewSelectorTabviewitems, items_bg, indicator, selected
tabSelectorTab
barRangeProgress Barindicator
sliderRangeSliderindicator, knob
arcRangeArcindicator, knob
linemeterRangeLine Meter
gaugeRangeGaugeindicator, ticks
qrcodeVisualQrcode

AI Warning

We’ve gone too far.

IA is generating news articles and complete YT video’s.
Also, forums and news articles are made using AI.

Reviews are being generated by vote farms.

Unchecked and being re-ingested by other IA scrapers.
It’s being fed again into other new AI generators.

Content generators are not interested in if the generated content is true.
Just generate traffic and income.

I hate watching a long YT video, voice being generated, story content from ChatGPT and not fact checked.
No new information, just generic information stretched into more time you have to watch.

If there is a disaster, people generate false footage to generate traffic.

I’ll resume this rant in time .. i’m not done

Flipper Zero

I’ve got a flipper zero at last.
https://flipperzero.one/

I know, it’s more an useful toy than a serious tool.
It’s too limited. But useful for me.

Learning about tools and sub gigahertz monitoring.

I hoped to get a BFFB for it, that will be a big plus.
https://www.justcallmekokollc.com/product/flipper-zero-bffb/31


One of the first things was reflashing the device with Momentum firmware.
I’ve ordered a Wi-Fi Dev Board, so I can use Marauder.

Here are some qFlipper screenshots.

Will add pictures and info about the Wifi dev board.

Some information:

The Flipper Zero is a versatile multi-tool for geeks, hackers, and hardware enthusiasts. It is designed as a portable, open-source device with numerous capabilities for interacting with digital systems and hardware. Here’s an overview of what the Flipper Zero can do:

1. RFID and NFC Communication

  • Read and Emulate: Supports RFID cards (low-frequency 125 kHz) and NFC cards (high-frequency 13.56 MHz). It can read, emulate, and clone certain types of RFID/NFC tags, such as access cards and contactless payment cards (within legal limits).
  • Protocols Supported: Includes MIFARE, HID Prox, and others used in access control systems.

2. Sub-GHz Radio Transmission

  • Works with a wide range of sub-GHz frequencies (300-900 MHz) used in garage door openers, key fobs, IoT devices, and wireless sensors.
  • Transmit and Analyze: It can capture, analyze, and even replay radio signals for research and testing purposes.

3. Infrared (IR) Control

  • Universal Remote: The Flipper Zero has an IR transmitter/receiver that allows it to control TVs, air conditioners, and other IR-enabled devices.
  • It can learn IR commands and replay them for universal control.

4. GPIO Pins for Custom Projects

  • Hardware Hacking: Provides GPIO (General Purpose Input/Output) pins for connecting to external hardware.
  • You can use the GPIO pins to interact with sensors, control relays, or debug devices like routers or microcontrollers.

5. Bluetooth and Wi-Fi (with Modules)

  • Bluetooth LE: Built-in Bluetooth Low Energy support allows communication with BLE-enabled devices.
  • Wi-Fi: Optional Wi-Fi dev board attachment (like the ESP8266 or ESP32) expands its capabilities for network penetration testing or IoT device research.

6. BadUSB and HID Attacks

  • Emulate USB Devices: Can act as a USB keyboard or mouse for automating tasks or security testing.
  • Useful for penetration testing with scripts (similar to tools like Rubber Ducky).

7. Universal Debugging

  • The Flipper can debug and interact with devices via UART, SPI, and I2C protocols, making it a powerful tool for developers and hackers.

8. Tamagotchi Mode

  • Includes a fun “pet” feature where you care for and interact with a digital creature that grows and evolves based on how you use the device.

9. Extensible and Open Source

  • The Flipper Zero’s firmware is open-source, allowing developers to modify and expand its capabilities.
  • It supports custom plugins, applications, and firmware modifications.

10. Signal Analysis and Replay

  • Capture, analyze, and replay signals (e.g., remote controls) for testing and research.
  • Legal Disclaimer: Using these features responsibly and within the bounds of the law is crucial.

Common Uses

  • Security auditing and penetration testing.
  • Reverse engineering and debugging hardware.
  • Researching IoT devices and wireless communications.
  • Fun DIY projects and learning electronics.

The Flipper Zero is a powerful tool, but its legality depends on how it is used. Be sure to respect laws and ethical guidelines when exploring its capabilities.

Reverse engineering Epaper Arduino for own image pusher

To display quotes, changing once per hour.

There is not much to be found for Waveshare 4.2 Epaper.
Except for an Arduino web example.
( see https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board )

I reversed engineered the workings, and created a python upload script to push images.

Original workings are a mess.
Per 4 bit of color, high-low switched in a byte.
Black and red separated.
Using a till p encoding over curl commands.

My implementation uses a python script called as:

python3 epaper-pusher.py ~/Downloads/Untitled.png
http://10.1.0.99/EPDI_
30 times something like 
http://10.1.0.99/ppppppppppppppppppppppppppppppppppppppppppppppppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppiodaLOAD_
http://10.1.0.99/NEXT_
30 times something like
http://10.1.0.99/pbcdefghijjjjjjffffffoooooooaaabbbbbbeeeedddppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppiodaLOAD_
http://10.1.0.99/SHOW_
NOTES:
a = 0000
-
-
-
p = 1111 = 15

30 lines with 1000 bytes ( ending with iodaLOAD_ )

black pixels
first block 1
second block 0

red pixels
first block 0
second block 1

white pixels
first block 1
second block 1

PIXEL Example
RBRB
BWBW

First block 
1010 - letter K
0101 - Letter F - second nibble = white

Second block
0101 - Letter F
1111 - Letter P - second nibble white

Code

from PIL import Image
import numpy
import requests

url="http://10.1.0.99/" 

black_pixels = numpy.zeros((400,300))
red_pixels = numpy.zeros((400,300))



def classify_pixel_color(pixel):
    """
    Classify a pixel as black, white, or red.
    """
    r, g, b = pixel[:3]  # Ignore alpha if present

    # Define thresholds for classification
    if r < 128 and g < 128 and b < 128:
        return 'black'
    elif r > 200 and g > 200 and b > 200:
        return 'white'
    elif r > 128 and g < 100 and b < 100:
        return 'red'
    else:
        return None

def process_image(image_path):
    """
    Process the image and classify its pixels into black, white, or red.
    """
    image = Image.open(image_path)
    image = image.convert("RGB")  # Ensure the image is in RGB mode

    width, height = image.size
    pixel_data = image.load()

    color_counts = {'black': 0, 'white': 0, 'red': 0}

    for y in range (0, 299):
        for x in range (0, 399):
            black_pixels[x][y] = 0
            red_pixels[x][y] = 0

    for y in range(299):
        for x in range(399):
            color = classify_pixel_color(pixel_data[x, y])
            if color:
                color_counts[color] += 1
                if color == 'black':
                    black_pixels[x][y] = 1;
                if color == 'red':
                    red_pixels[x][y] = 1;
                if color == 'white':
                    black_pixels[x][y] = 1;
                    red_pixels[x][y] = 1;

    return color_counts, black_pixels, red_pixels

def number_to_letter(num):
    """
    Translates a number from 0 to 15 into a corresponding letter (a-p).

    Args:
        num (int): The number to translate.

    Returns:
        str: The corresponding letter (a-p).
    """
    if 0 <= num <= 15:
        return chr(ord('a') + num)
    else:
        raise ValueError("Number must be between 0 and 15, inclusive.")

def print_array_in_chunks(array, chunk_size=1001):
    current_chunk = ""
    for item in array:
        # Convert item to string and add to the current chunk
        item_str = str(item)
        if len(current_chunk) + len(item_str) + 1 > chunk_size:
            # Print the current chunk and reset it
            current_chunk += "iodaLOAD_"
            try:
                requests.get(url + current_chunk, verify=False)
                if not response.content:  # Equivalent to expecting an empty reply
                    pass
            except requests.exceptions.RequestException as e:
                # Catch any request-related errors
                pass
            current_chunk = item_str
        else:
            # Append the item to the current chunk
            current_chunk += (item_str)
    current_chunk += "iodaLOAD_"
    # Print any remaining items in the chunk
    if current_chunk:
        try:
            requests.get(url + current_chunk, verify=False)
            if not response.content:  # Equivalent to expecting an empty reply
                pass
        except requests.exceptions.RequestException as e:
            # Catch any request-related errors
            pass
        

def switch_in_pairs(arr):
    # Loop through the array with a step of 2
    for i in range(0, len(arr) - 1, 2):
        # Swap values at index i and i+1
        arr[i], arr[i + 1] = arr[i + 1], arr[i]
    return arr

if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Usage: python3 script.py <image_path>")
        sys.exit(1)

    image_path = sys.argv[1]
    try:
        color_counts, black_pixels, red_pixels = process_image(image_path)
        try:
            requests.get(url + "EPDI_" , verify=False)
            if not response.content:  # Equivalent to expecting an empty reply
                pass
        except requests.exceptions.RequestException as e:
            # Catch any request-related errors
            pass

        
        lines=[]
        for y in range(300):
            for x in range(0,399,4):
                first = red_pixels[x][y]
                second = red_pixels[x+1][y]
                thirth = red_pixels[x+2][y]
                fourth = red_pixels[x+3][y]
                nibble = 0
                if (first ==  1):
                        nibble = nibble + 8
                if (second ==  1):
                        nibble = nibble + 4
                if (thirth ==  1):
                        nibble = nibble + 2
                if (fourth ==  1):
                        nibble = nibble + 1
                lines.append(number_to_letter(nibble))
        switched_array = switch_in_pairs(lines)
        print_array_in_chunks(switched_array)
        try:
            requests.get(url + "NEXT_" , verify=False)
            if not response.content:  # Equivalent to expecting an empty reply
                pass
        except requests.exceptions.RequestException as e:
            # Catch any request-related errors
            pass
        lines=[]
        for y in range(300):
            for x in range(0,399,4):
                first = black_pixels[x][y]
                second = black_pixels[x+1][y]
                thirth = black_pixels[x+2][y]
                fourth = black_pixels[x+3][y]
                nibble = 0
                if (first ==  1):
                        nibble = nibble + 8
                if (second ==  1):
                        nibble = nibble + 4
                if (thirth ==  1):
                        nibble = nibble + 2
                if (fourth ==  1):
                        nibble = nibble + 1
                lines.append(number_to_letter(nibble))
        switched_array = switch_in_pairs(lines)
        print_array_in_chunks(switched_array)

        try:
            requests.get(url + "SHOW_" , verify=False)
            if not response.content:  # Equivalent to expecting an empty reply
                pass
        except requests.exceptions.RequestException as e:
            # Catch any request-related errors
            pass

    except Exception as e:
        pass

Home Assistant and Dehumidifier

A while ago, I bought a small Dehumidifier for my wine cellar.
I liked it a lot, so I bought another for our bedroom.

I saw some posts about people asking which Dehumidifier is supported by Home Assistant.
This one is. The “Eeese Otto Dehumidifier”

This works with the LocalTuya integration.

There are many examples how to integrate LocalTuya in HA which can be found easily using a search on the net. So, I’m not going to explain that.

I could not find a configuration example, that’s why I’ll post that part here.

Pre config:

  • Install App on phone to connect Tuya device to cloud (one time only)
    You need this to extract the localkey
  • Add a developer account to https://eu.platform.tuya.com/
    (Enable devices and change from Read to Control)
    (Get localkey from API Explorer, here is also a hint to be found about the entities)
    See below pictures
  • Install LocalTuya to HA
End result after config

Gallery of config steps

Developer website information, where to find your credentials.
(And a list of entities)

Home Assistant Voice and OpenMqttGateway

Yesterday I got my Home Assistant Voice!

This is a Non-Cloud solution like Alexa and Google devices.
I only could play with it for a few minutes because I was working on Arduino code with an ILI9341 Display and a BME280 (Temperature/Humidity/Air pressure).

Today I got some new goodies in, one of these is a LilyGO LoRa display which works on 433 Mhz.

I flashed OpenMQTTGateway on this device.

In the past, I posted about the RFCOM Gateway using Domoticz.
This runs on a Raspberry Pi.
While looking for alternatives, I found a rtl-sdr solution.

https://github.com/merbanan/rtl_433

Using this:

But I liked the ESP32 solution more.
Now I can dismantle Domoticz, which served me well for many years.

How cool to see realtime updates!

Note: This is a receiver device only!
But I only use read-only sensors like : Door/window, doorbell, temperature/humidity and Firesensors.

These are automatically detected in Home Assistant.

No more RFXCOM with a Raspberry.

"If something is worth doing, it's worth overdoing."