Tag Archives: programming

Pushover notifier for dates

Below is my python script to push messages via pushover to my phone.

It’s being run from a cron during the day.

CODE

import csv
import datetime
import requests

# configure own creds
PUSHOVER_USER_KEY = 'keykeykeykeykeykeykeykey'
PUSHOVER_API_TOKEN = 'tokentokentokentokentokentokentoken'
CSV_FILE = '/data/notifications.csv'

def send_pushover_notification(message):
    url = "https://api.pushover.net/1/messages.json"
    payload = {
        "token": PUSHOVER_API_TOKEN,
        "user": PUSHOVER_USER_KEY,
        "message": message
    }
    response = requests.post(url, data=payload)
    if response.status_code != 200:
        print("Failed to send notification:", response.text)

def check_and_notify():
    today = datetime.date.today()
    with open(CSV_FILE, newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            try:
                day = int(row['day'])
                month = int(row['month'])
                if today.day == day and today.month == month:
                    send_pushover_notification(row['message'])
            except ValueError:
                continue

if __name__ == "__main__":
    check_and_notify()

notifications.csv file

day,month,message
1,1,Birthday of a new year
16,05,Project Deadline
16,05,Test2 (blah) 2
7,3,Glorious bastard Rik Mayall birthday
27,3,International whisky day

Nice to haves (didn’t implement because i’m a lazy bastard)

  • 3rd Saturday every may
  • Getting dates or updates from another app
  • Selecting Pushover device, level of alertness .. etc

Busy .. work and play

While working on my clients projects, I’ve been busy with other Fun stuff.

All will be posted more about soon

  • Designing 3D models for printing
  • Testing Arduino Code for RS485!
  • Creating T-shirt prints using 3D printing and bleach/paint with Vincent !
  • Transforming my Lab
  • Testing UM25C logging possibilities
  • Testing queries on overpass-turbo.eu (So much fun)
  • Playing chiptune music using Synthcart + Midi
  • Made V2 displayer on my 64×64 HUB75 led display
  • Bought a directional Wi-Fi antenna, tweaking wireshark to pinpoint rogue access points and clients.

March stuff, being busy

Working for clients, so fragmented personal stuff.
New workplace setup so even more space!

My BBQ monitor V3

As posted before, but now an esphome version, with big-ass buzzer

Code available soon, when made generic.

4Button controller using ESPHOME

Code allready posted

STL FILE https://media.henriaanstoot.nl/4buttons.stl

Flash trick for XYUSB

Flashing this to ESPHOME, use sowing pins!

CODE

substitutions:
  name: usb-relay
  friendly_name: "USB Relay"
  default_state: "RESTORE_DEFAULT_OFF"


esphome:
  name: xyusb1
  friendly_name: xyusb1

esp8266:
  board: esp01_1m

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "ndm8xxxxxxxxxxxxxxxxxjlvrggJv3a1BkY="

ota:
  - platform: esphome
    password: "12cc9xxxxxxxxxxxxxxxxfb6a01e672"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Xyusb1 Fallback Hotspot"
    password: "xxxxxxxxxxx"

captive_portal:

time:
  - platform: homeassistant

# Blue LED
status_led:
  pin:
    number: GPIO16

# Relay
switch:
  - platform: gpio
    id: switch_relay
    pin: GPIO5

  # Green LED
  - platform: gpio
    pin: GPIO14
    id: green_led
    inverted: true # start on

  # Switch template to link relay and green LED states
  # LED is on when relay is off
  - platform: template
    id: relay
    name: "${friendly_name}"
    lambda: |-
      if (id(switch_relay).state) {
        return true;
      } else {
        return false;
      }
    turn_on_action:
        - switch.turn_on:
            id: green_led
        - switch.turn_on:
            id: switch_relay
    turn_off_action:
        - switch.turn_off:
            id: green_led
        - switch.turn_off:
            id: switch_relay

# Button
binary_sensor:
  - platform: gpio
    id: hardware_button
    pin:
      number: GPIO04
      mode: INPUT_PULLUP
      inverted: True
    on_press:
      - switch.toggle: relay

# WiFi Signal Sensor
sensor:
  - platform: wifi_signal
    name: "WiFi Status"
    update_interval: 60s

# Restart button
button:
  - platform: restart
    name: "Restart"

Reflashed my USB Volume button and added a LED-Ring.

Example is green and blue.

Funny text on box

What is a termianl assortment? LOL

Wireless Temperature/Humidity sensor for ESPHome.

Wemos D1 mini with deep sleep, voltage monitoring using A0 line.
BME280 Temperature/Humidity sensor.
And a 18650 battery with TP4065 battery manager.
Now 3D print a little case.

Made a PCB for a 24 Channel Logic analyzer

See post:

Better thumb thingy for short movie clips

(Improvement of previous posted script)

Place below bash script in a subdir with media.

Animated GIFs are generated from the video files.
You can set the number of frames per length

#!/bin/bash
#set -x
mkdir -p tmp prev
: > list
: > index.html
find ../ -type f -print | egrep -i "mp4$|wmv$|avi$|mpg$|mpeg$|flv$|mov$|divx$"  > list

cat list | while read movie; do 
	rm -f tmp/*
	newname=$( echo $movie | tr -d ' /.[]{}()' ) 
	if [ ! -f prev/${newname}.gif ] ; then

		echo "Filename : $movie"

		kseconds=$( mediainfo --Inform="Video;%Duration%"  "$movie" )
		minutes=$(( $kseconds / 60000 ))
		echo "Minutes : $minutes"
		if [ $minutes -gt 10 ] ; then 
			rate=0.032
		else
			rate=0.128
		fi
echo "ffmpeg -hide_banner -loglevel error -i $movie -r $rate  -vf scale=640:-1 tmp/output_%04d.png"
		ffmpeg -hide_banner -loglevel error -i "$movie" -r $rate  -vf scale=640:-1 tmp/output_%04d.png < /dev/null
		# remove first (most of the time just black or logo)
		rm tmp/output_0001.png
		echo -n "Frames : "
		ls tmp/out* | wc -l
		convert -delay 50 -loop 0  tmp/output*.png prev/${newname}.gif
	else
		echo "$movie exists ... skipping"
	fi
	echo "<h1>${movie}</h1><br>" >> index.html
	echo "<img src=\"prev/${newname}.gif\"><br>" >> index.html
done
exit 0

run and get something like below (output is still running as I made this post)

Display work

While working on a client project, I tested multiple displays.

  • ILI9341
  • 1.3inch SPI TFT LCD Display RGB (ST7789)
  • Waveshare 4.2 Epaper with ESP32 Controller

I thought it was fun to connect the Epaper to ESPHome.

This probably ends up being a Quote displayer
Universal e-Paper Driver Board with WiFi / Bluetooth SoC ESP32 onboard, supports various Waveshare SPI e-Paper raw panels

It was not without problems. For example, the ESPHome editor gave squiggly lines under type.
This has to be changed in the libraries.
(Already notified developers)

model: 4.20in-V2 does not work .. use model: 4.20in-v2

esphome:
  name: epaperqoute
  friendly_name: epaperqoute

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "tzRSzZky3Jk+hUYtiybzT90kxxxxxxxxxxxxxxxxxxxxx="

ota:
  - platform: esphome
    password: "4f127e114a7a44fxxxxxxxxxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Epaperqoute Fallback Hotspot"
    password: "yLSoxxxxxxxxxx"

captive_portal:


external_components:
  - source: github://pr#6209
    components: [ waveshare_epaper ]

text_sensor:
  - platform: homeassistant
    entity_id: input_text.epaper_display_text
    id: epaper_display_text
    on_value:
      then:
        - component.update: epaperdisplay
    
spi:
  clk_pin: GPIO13
  mosi_pin: GPIO14

# Upload own ttf to a directory in esphome/fonts using file editor in Home Assistant
font:
  - file: "fonts/newspaper.ttf"
    id: tahoma
    size: 64

http_request:
  verify_ssl: false

# image test
online_image:
  - url: "https://www.henriaanstoot.nl/epapertest.png"
    id: example_image
    format: PNG

#it.image(0, 0, id(example_image));

display:
  - platform: waveshare_epaper
    id: epaperdisplay
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    model: 4.20in-v2
    reset_duration: 200ms
    update_interval: never
    lambda: |
           it.printf(0, 0, id(tahoma), "%s", id(epaper_display_text).state.c_str());  

Webcam plus OpenCV fun

While attending Bornhack 2024 in Danmark, I came up with the below fun ideas.

Using Python and OpenCV, I made some funny webcam hacks.

Note: My laptop webcam is very bad, a better webcam should give you a more stable result.

First, a virtual workspace flipper. Just using my head movement to flip through my virtual desktops. (Turning left and right)

Next, an image viewer.
Using your head movement up, down, left and right to control the image.
Note : this is not the same movement as above. This won’t use rotation of your head!

Working on a demo part

Started coding a demo with a friend of mine.

I made a part that uses raster interrupts and gives the illusion that the picture is up in the border.

  • Opening the borders
  • Changing the border colour midway
  • Using NOPs to get a stable rastersplit
  • Sprites in the border
  • Fixing the sprite mirroring in the bottom part
  • Learning a lot about bad raster lines, I had to make a lot of workarounds to get it working

Hopefully I’ve got some rastertime left to play music. But I learned a lot!
UPDATE: Yes also with SID music!

Not shown: Bad raster lines, split colors background and bordercolor.
Maybe I’ll add these later.

UPDATE: 20240720

Sprite multiplexing done and self modifying code.

Keyboard switch part 1

Testing the first keyboard. It is the 8085-SDK hex matrix keyboard.

It is running on a Raspberry Pi Zero 2, without X server.
So the images are displayed using the framebuffer.
Also the touch data is read using evdev and the raw devices.

Todo:

  • HID part
  • Add a rotary button for the selection of the different Keyboard Layouts
  • Improvement keyboard matrix calculation to find out which key is being pressed.
  • Code to control AT/PS2 computers directly using GPIO pins
  • Add a controller to use Raw controlling of matrix pins ( 6502 C64 hardware for example )

Bash test and configuring the OS for testing.

cat <<EOF >> /boot/config.txt
hdmi_group=2
hdmi_mode=87
hdmi_timings=400 0 100 10 140 1280 10 20 20 2 0 0 0 60 0 43000000 3
display_rotate=3
EOF

# Image testing
apt-get install fbi
sudo fbi -d /dev/fb0 -T 1 8085.png  -a --noverbose

apt-get install python3-evdev python3-uinput evtest
evtest

First simple python test

import select
from math import floor
import sys
slot = 0

keysname=[["F","E","D","C","vect-int","reset"],
          ["B","A","9","8","GO","Single-Step"],
          ["7","6","5","4","Exam-reg","Subst-mem"],
          ["3","2","1","0","Exec","Next"],
          ]
keysnames=[["F","E","D","C","vect-int","reset"],
          ["B","A","L","H","GO","Single-Step"],
          ["PCL","PCH","SPL","SPH","Exam-reg","Subst-mem"],
          ["3","2","1","0",".",","],
          ]

for path in evdev.list_devices():
    device = evdev.InputDevice(path)
    if evdev.ecodes.EV_ABS in device.capabilities():
        break
else:
    sys.stderr.write('Failed to find the touchscreen.\n')
    sys.exit(1)

while True:
    r, w, x = select.select([device.fd], [], [])

    id_ = -1
    x = y = 0

    for event in device.read():

        if event.code == event.value == 0:
           if id_ != -1:
                yy = floor(( x - 600 ) / 700)
                xx = floor(( y - 1377 ) / 226)
                if yy < 4 and yy >=0 and xx < 6 and xx >= 00:
                     if slot == 1:
                         print(keysnames[yy][xx])
                     else:
                         print(keysname[yy][xx])

        elif event.code == ABS_MT_TRACKING_ID:
            id_ = event.value
        elif event.code == ABS_MT_SLOT:
            slot = event.value
        elif event.code == ABS_MT_POSITION_X:
            x = event.value
        elif event.code == ABS_MT_POSITION_Y:
            y = event.value

I came up with a simple matrix calculation

Pressing the 4 corner keys gave me x and y.
I took averages for min and max reading.
I don’t need pixel-perfect reading, and I noticed values between 960 and 3080 vertically.
We want 960 – 3080 into 4 blocks, but the middle should start @ 960.

So 3080/3 = about 700
700 / 2 = 350
block 1 starts 350 sooner than 960 is ~ 600
Upper key y coords = 600-> + 700
Next is 1300 -> + 700
converting to whole numbers using floor gives me:
floor(( y – 600 ) / 700)
NOTE: My x and y are rotated

Example using coordinates
1600, 1600
floor(( 1600 – 600 ) / 700) = floor(1,4…) = 1st row
(from row 0,1,2,3)

64×64 Etch a Sketch

In the past I made a Etch a Sketch with my lasercutter.

Using two rotary encoders and the 64×64 matrix display I recently bought, I made a drawing thingy.
Like a Etch a Sketch.

Some Circuit Python code.
Now I have to fix an out of memory issue using below.
And make a colour selection button??? 🙂

import time
import board
import displayio
import math
import vectorio
import rgbmatrix
import framebufferio
import array
import bitmaptools

import rotaryio
import board

encoder1 = rotaryio.IncrementalEncoder(board.GP27, board.GP26)
encoder2 = rotaryio.IncrementalEncoder(board.GP18, board.GP19)

last_position1 = 0
last_position2 = 0

# Release any existing displays
displayio.release_displays()

# --- Matrix Properties ---
DISPLAY_WIDTH = 64
DISPLAY_HEIGHT = 64

# --- Matrix setup ---
BIT_DEPTH = 2
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=2, height=64,
    rgb_pins=[board.GP0, board.GP1, board.GP2, board.GP3, board.GP4, board.GP5],
    addr_pins=[board.GP6, board.GP7, board.GP8, board.GP9, board.GP22],
    clock_pin=board.GP10, latch_pin=board.GP12, output_enable_pin=board.GP13)
colrs = 13
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=True)
b1 = displayio.Bitmap(display.width, display.height, colrs )
palette = displayio.Palette(colrs )
palette[0] = 0x000000  # black
palette[1] = 0x964B00  # brown (light yellow) 
palette[2] = 0x00FFFF  # cyan
palette[3] = 0x850101  # deep red 
palette[4] = 0x7F00FF  # violet
palette[5] = 0xC46210  # orange
palette[6] = 0x3D9140  # Cobalt green  
palette[7] = 0x004225  # british racing green 
palette[8] = 0x8B008B  # dark magenta 
palette[9] = 0x1F75FE  # crayola  blue
palette[10] =0x00308F  # air force blue US air force    
palette[11] =0xBF00FF  # electric purple 
palette[12] =0x08E8DE  # turquoise
g1 = displayio.Group(scale=1)
display.root_group = g1 

bmp = displayio.Bitmap(64,64, 2)

tilegrid = displayio.TileGrid(bitmap=bmp, pixel_shader=palette)
g1.append(tilegrid)
display.auto_refresh = True

tilegrid = displayio.TileGrid(bitmap=bmp, pixel_shader=palette)
while True:
        position1 = encoder1.position
        if last_position1 is None or position1 != last_position1:

            if position1 > last_position1:
                position1 = position1 + 1
            if position1 < last_position1:
                position1 = position1 - 1
            if position1 < 0:
                position1 = 0
            last_position1 = position1
        position2 = encoder2.position
        if last_position2 is None or position2 != last_position2:
            if position2 > last_position2:
                position2 = position2 + 1
            if position2 > last_position2:
                position2 = position2 - 1
            if position2 < 0:
                position2 = 0
            last_position2 = position2

        bmp[position1,position2]=1
        tilegrid = displayio.TileGrid(bitmap=bmp, pixel_shader=palette)
        g1.append(tilegrid)
        display.auto_refresh = True