All posts by fash

Fluxengine disk reader

I’ve build a drawbridge disk reader in the past:
https://www.henriaanstoot.nl/2022/04/26/started-to-build-a-drawbridge/
I found an even more interesting project.

I was looking for a solution to my XT laser problem.
https://www.henriaanstoot.nl/2022/11/25/disk-troubles-or-missing-old-skool-hardware/

And found this! The fluxengine
https://github.com/davidgiven/fluxengine

An open source project using a small controller board.
“Flashing” some software on the board and soldering a pinheader was easy.
When connecting a flat cable and a floppy drive, you end up with a device which can read many formats. Including dos 1.44/720 and amiga.

Nice package it came in

Using the power from a sata/ide harddisk adaptor

Reading and writing a MSDOS disk, no problem.
Imaging an amiga disk .. easy!

You need to compile some software, but it was well documented

Shelly alarm button

For a while i’ve been using the wireless shelly button for all kinds of notifications.
Most of the time i like to use it as a kind of alarm/need-help-now button.

The f*ckin’ awesome button i’m talking about (pictured above) is a small (45x45mm 16mm height) button, which can connect to your wifi and send MQTT messages.
It even has a strap thingy to attach it to your keychain,

Four types of messages:

  • short press
  • 2x short presses
  • 3x short presses
  • and long press

When using pushover, you can push alarm and messages to your android (even overriding mute/silent if you configure it that way!)

Configuring the button:
https://www.shelly.cloud/documents/user_guide/shelly_button_1.pdf

Configuring pushover:
https://www.npmjs.com/package/node-red-node-pushover

My node red config:

Switch node

[
    {
        "id": "abb6a4fea5021683",
        "type": "mqtt in",
        "z": "458ff8a6.218fa8",
        "name": "",
        "topic": "shellies/shellybutton1-11CDAC2C21D3/input_event/0",
        "qos": "2",
        "datatype": "auto",
        "broker": "8c74c5f6.9a7a48",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 320,
        "y": 760,
        "wires": [
            [
                "bebce75c2be0b54d"
            ]
        ]
    },
    {
        "id": "8eac36b9c194977b",
        "type": "comment",
        "z": "458ff8a6.218fa8",
        "name": "Shelly Button",
        "info": "",
        "x": 200,
        "y": 720,
        "wires": []
    },
    {
        "id": "699c63fede80052b",
        "type": "debug",
        "z": "458ff8a6.218fa8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 700,
        "wires": []
    },
    {
        "id": "604ae0babdcf3929",
        "type": "switch",
        "z": "458ff8a6.218fa8",
        "name": "",
        "property": "payload.event",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "S",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "SS",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "SSS",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "L",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 4,
        "x": 690,
        "y": 700,
        "wires": [
            [
                "699c63fede80052b",
                "5f289f050b9eea26"
            ],
            [
                "e895ce98af0a9c35"
            ],
            [
                "50c9c06fc3dbdcdd"
            ],
            [
                "06efa30e61695599"
            ]
        ]
    },
    {
        "id": "e895ce98af0a9c35",
        "type": "debug",
        "z": "458ff8a6.218fa8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 760,
        "wires": []
    },
    {
        "id": "50c9c06fc3dbdcdd",
        "type": "debug",
        "z": "458ff8a6.218fa8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 820,
        "wires": []
    },
    {
        "id": "06efa30e61695599",
        "type": "debug",
        "z": "458ff8a6.218fa8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 880,
        "wires": []
    },
    {
        "id": "bebce75c2be0b54d",
        "type": "json",
        "z": "458ff8a6.218fa8",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 600,
        "y": 780,
        "wires": [
            [
                "604ae0babdcf3929",
                "699c63fede80052b"
            ]
        ]
    },
    {
        "id": "5f289f050b9eea26",
        "type": "pushover",
        "z": "458ff8a6.218fa8",
        "name": "",
        "device": "",
        "title": "Alarm",
        "priority": "2",
        "sound": "persistent",
        "url": "",
        "url_title": "",
        "html": false,
        "x": 1150,
        "y": 640,
        "wires": []
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "MQTTBROKER",
        "broker": "MQTTBROKER",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]

Security cam ftp search major changes in images.

Weird title i know.

I have several ip cameras which monitor movement in and around our home.

I’m using Zoneminder and other home automation systems but i want to scan through a bunch of files uploaded by the security cameras to my secondary fileserver.

So what is interesting?

  • Major movement compared to a base image
  • Movement compared to a previous uploaded image
  • Setting a threshold when to output information (note the 65% mark)
| 76 % | 1438 | SDAlarm_20221129-213515.jpg | 3145 | .......-.......................X.....................................................................
| 76 % | 1439 | SDAlarm_20221129-213517.jpg | 3661 | ..............-.....................X................................................................
| 76 % | 1440 | SDAlarm_20221129-213519.jpg | 3739 | ...........-.........................X...............................................................
| 77 % | 1441 | SDAlarm_20221129-213521.jpg | 3704 | .....-...............................X...............................................................

Looking at the output we see:
At 76% of the captured images (image 1438) the threshold was above 3000 and the minus gives us the information of the difference between this image and the previous, the X marks the difference between current image and the baseline.
| percent | image number | filename | difference | graphbar

Bash script:

#!/bin/bash
threshold=3000
baseline=$( ls  SDAlarm*jpg | head -1)
previous=$( ls  SDAlarm*jpg | head -1)
total=$( ls *.jpg |wc -l)
echo "Number of files : $total"
nr=1
ls *jpg | while read; do
graph="....................................................................................................."
diff=$(compare -verbose -metric MAE $baseline $REPLY /dev/null  2>&1 | grep all | awk '{ print $2 }' | cut -f1 -d. )
prevdiff=$(compare -verbose -metric MAE $previous $REPLY /dev/null  2>&1 | grep all | awk '{ print $2 }' | cut -f1 -d. )
line=$( echo "100 / $total * $nr" | bc -l | cut -f1 -d.)
line=$(( $line + 1))
#echo -n "$line | $nr | $REPLY | "
#echo $diff
draw1=$(( $diff / 100 + 1))
draw2=$(( $prevdiff / 100 + 1))
graph=$(echo $graph | sed "s/./X/$draw1")
graph=$(echo $graph | sed "s/./-/$draw2")
if [ $diff -gt $threshold ] ; then
printf "| %4s %% | %3s | %30s | %5s | %102s \n" $line  $nr $REPLY $diff $graph
fi
nr=$(( $nr +1 ))
previous=$REPLY
done

Want to see only difference with previous image?

change:

if [ $diff -gt $threshold ] ; then
into
if [ $prevdiff -gt $threshold ] ; then

Automatic photo sorting with Gps location lookup

We take a lot of pictures, with our Nikon camera and our mobile phones.

(Apparently in 2019 5544 pictures)

Some stats

757 20190803 - on a single day (Holiday)

Average pictures per month
locate "/2019/" | egrep -i "photoalbum|gsm" | egrep -i "mp4$|jpg$" | grep -Eo '2[[:digit:]]{3}[[:digit:]]{2}[[:digit:]]{2}' | cut -c-6 |sort | uniq -c | sort -n | awk '{ sum += $1; n++ } END { if (n > 0) print sum / n; }'
461

Besides android pictures being automatically uploaded to our nextcloud, I’m using some apps and scripts to get pictures and movies stored on my fileserver. (bash scripts/andftp)

For sorting those media files, i made a sorting script.
(Today I added a location sorting addition using GPS information stored in the exif information.

  • jpg and jpeg (add your own extentions)
  • mp4 and mov (for mobile and nikon)
  • Sorts by camera model/year/date/location
  • tries to extract date from filename when not found in exifinfo
  • Sorts whatsapp media
  • Sorts Raw

INSTALLING

pip3 install reverse_geocoder
You need python3, exiftool, exiftime and mediainfo

copy below python script in ~/bin/reverse2.py

( need more info? change last print entry admin1/admin2)
[{‘lat’: ‘-39.45556’, ‘lon’: ‘173.85833’, ‘name’: ‘Opunake’, ‘admin1’: ‘Taranaki’, ‘admin2’: ‘South Taranaki District’, ‘cc’: ‘NZ’}]

import reverse_geocoder as rg
import sys

lat=sys.argv[1]
lon=sys.argv[2]

coordinates = (lat,lon)

results = rg.search(coordinates) # default mode = 2


#print (results)

for entry in results:
    print(entry['name'] + "(" +  entry['cc'] + ")")

And a bash script /usr/local/bin/exifsort.sh

#!/bin/bash
#set -x

reversepath=/home/henri/projects/reversegeo/reverse2.py

#RAW
rawcnt=`ls | grep -i  nef$ | wc -l`
if [ "$rawcnt" = "0" ] ; then
echo "no raw"
else
mkdir raw 2>/dev/null
ls | grep -i nef$ | while read ; do mv $REPLY raw ; done
fi


ls | egrep -i "jpg$|jpeg" | while read ; do 
 	location=""	
	getmodel=$(exiftool "$REPLY" |grep "Make " | awk '{ print $3 }')
	if [ "$getmodel" != "" ] ; then 
		getmodel=$getmodel/
	fi
	echo "$REPLY" | grep WA0 >/dev/null && getmodel=whatsapp/

	gpsinfo=$(exiftool -c "%+.6f" "$REPLY" |grep "GPS Position" | cut -d":" -f2 | tr -d ' ' | sed s/,/\ /g)
	if [ "$gpsinfo" != "" ] ; then 
		location=$(python3 $reversepath $gpsinfo | grep -vi load | sed s/\(NL\)//g)
	fi
	dater=$(exiftime "$REPLY" 2>/dev/null | egrep "Created|Digitized" | sed s/Digitized/Created/g | tail -1  | cut -c 16-19,21,22,24,25)
	if [ "$dater" = "" ] ; then 
#		echo "Trying from filename"
		dater=$(echo $REPLY | grep -Eo '2[[:digit:]]{3}-[[:digit:]]{2}-[[:digit:]]{2}')

		if [ "$dater" = "" ] ; then 
#			echo "Trying from filename - maybe without dashes"
			dater=$(echo $REPLY | grep -Eo '2[[:digit:]]{3}[[:digit:]]{2}[[:digit:]]{2}')

		fi
	fi
	if [ "$dater" != "" ] ; then 
		year=$(echo $dater | cut -c-4)
		mkdir -p "${getmodel}$year/${dater}/$location"
		mv "$REPLY" "${getmodel}${year}/${dater}/$location"
	else
		mkdir -p "${getmodel}unknowndate/$location"
		mv "$REPLY" "${getmodel}unknowndate/$location"
      	fi
done

ls | egrep -i "mov$|mp4$" | while read ; do 
	
 	location=""	
	getmodel=$(exiftool "$REPLY" |grep "Make " | awk '{ print $3 }')
	if [ "$getmodel" != "" ] ; then 
		getmodel=$getmodel/
	fi

	echo "$REPLY" | grep WA0 >/dev/null && getmodel=whatsapp/
	gpsinfo=$(exiftool -c "%+.6f" "$REPLY" |grep "GPS Position" | cut -d":" -f2 | tr -d ' ' | sed s/,/\ /g)
	if [ "$gpsinfo" != "" ] ; then 
		location=$(python3 $reversepath $gpsinfo | grep -vi load | sed s/\(NL\)//g)
	fi
	dater=$(mediainfo "$REPLY" | grep Encode | tail -1 | cut -f2- -d:  | cut -f3 -d" " | sed s/-//g)
	if [ "$dater" = "" ] ; then 
#		echo "Trying from filename"
		dater=$(echo $REPLY | grep -Eo '2[[:digit:]]{3}-[[:digit:]]{2}-[[:digit:]]{2}')

		if [ "$dater" = "" ] ; then 
#			echo "Trying from filename - maybe without dashes"
			dater=$(echo $REPLY | grep -Eo '2[[:digit:]]{3}[[:digit:]]{2}[[:digit:]]{2}')

		fi
	fi
	if [ "$dater" != "" ] ; then 
		year=$(echo $dater | cut -c-4)
		mkdir -p "${getmodel}$year/${dater}/$location"
		mv "$REPLY" "${getmodel}${year}/${dater}/$location"
	else
		mkdir -p "${getmodel}unknowndate/$location"
		mv "$REPLY" "${getmodel}unknowndate/$location"
      	fi
done

Example running in a directory with mixed media

# Raw images get moved into a RAW directory
no raw

# Samsung phone detected with date and GPS location
mkdir -p samsung/20220717/Hilversum
mv 20220717_133453.jpg samsung/20220717/Hilversum

# OnePlus phone
mkdir -p OnePlus/20021208/Voorburg
mv IMG_20190109_091825.jpg OnePlus/20021208/Voorburg

# Realme (Added country when not NL)
mkdir -p realme/20220607/Isle of Islay(GB)
mv IMG20220607213630.jpg realme/20220607/Isle of Islay(GB)

# Whatsapp has no date embedded so it get it from filename
Trying from filename
Trying from filename - maybe without dashes
mkdir -p whatsapp/20221021/
mv IMG-20221021-WA0000.jpg whatsapp/20221021/

# Nikon without GPS
mkdir -p NIKON/20220613/
mv DSC_1423.MOV NIKON/20220613/

# Whatsapp video without exif
mkdir -p whatsapp/20170528/
mv VID-20170528-WA0006.mp4 whatsapp/20170528/

# No camera name detected in exif from mobile movie
mkdir -p 20190114/Maarssen
mv VID_20190114_142455.mp4 20190114/Maarssen

# Location in mp4
mkdir -p 20220607/Lamlash(GB)
mv VID20220607155044.mp4 20220607/Lamlash(GB)

Result

./NIKON/2022/20220613/DSC_1423.MOV
./NIKON/2022/20220610/750_1101.JPG
./realme/2022/20220818/Hilversum/IMG20220818203825.jpg
./realme/2022/20220607/Isle of Islay(GB)/IMG20220607213630.jpg
./2019/20190114/Maarssen/VID_20190114_142455.mp4
./whatsapp/2017/20170528/VID-20170528-WA0006.mp4
./whatsapp/2022/20221021/IMG-20221021-WA0000.jpg
./2022/20220607/Lamlash(GB)/VID20220607155044.mp4
./2022/20220516/Hilversum/VID20220516125913.mp4
./OnePlus/2002/20021208/Voorburg/IMG_20190109_091825.jpg
./samsung/2022/20220717/Hilversum/20220717_133453.jpg

You could automate this using incrond
apt-get install incron
add your user to /etc/incron.allow
incrontab -e
add

/fileserver/mediain/ IN_CREATE /usr/local/bin/sortmymedia.sh
Coping a file in the directory, auto sort and move to correct location

sortmymedia.sh

#!/bin/bash
cd /home/user/media
/usr/local/bin/exifsort.sh

Disk troubles or missing old skool hardware?

I bought a XT Laser/3 a while ago.
And i wanted to get my old programs running on it again.

One of the disk i found was a 5.25 inch boot disk which should contain a boot demo i’ve made in the past with Edk.
But it is the secondary drive in this system. Those old machines lack a bios you can change.
And change A: for B: for example.
Some machines had a program which could alter boot settings. (not this one)
So i was playing with jumpers and dipswitches on the motherboard.
( Drive select / Termination / drive before or after the twist in the flatcable. )

Dipswitches on the motherboard

Wellll leave the boot order for now, i needed to get software on the machine using floppy’s.
I could not find empty HD disks (1.44MB which i wanted to use)
So i took a DD disk and a drill ..

I bought an external usb floppy drive.

Now i have everything to get my programs on the msdos machine.

EXCEPT ….

Diskette didn’t work in the drives.
So i bought new old stock diskettes online.

Now i have everything

WRONG again

Formatted 1.44 disk in USBfloppy drive .. OK
Read in 3.5 drive on the MSDOS machine .. NOT OK
Check drive in MSDOS machine .. is 1.44MB .. OK
… check floppy controller in MSDOS machine .. NOT OKAY
(720kb is 300kbits per second and 1.44 HD 500kbits per second)
So i’m limited to 720kb due to the controller ..


Can the USB Floppy drive read/write 720kb disks .. NO!
( A cheap series made with drives only supporting HD disks )

Alternatives? .. Serial maybe, there is Norton Commander on the MSDOS machine so i could use “link”

Do i still have a USB-RS232 sub-d cable ? YES!
Nullmodem cable? NO
Make a null modem cable .. i’ve made those before .. BUT no sub-d connectors.

I’ve been throwing away too much in the past.

Now i have to buy those things again:

VGA – 8bit ISA – have 2 now
Floppy drive – have one for 1.44
8bit soundblaster compatible – TODO
Nullmodem – well i’ve bought connectors for those

Tunebook generator

I’m using below scripts to generate tunebooks.
These books I can print OR view on a tablet using my DIY bluetooth page turner. ( see other post )

I often work on tunes, add notes, text or write other versions.
So i needed a fast and simple way to re-generate a tunebook. ( hence the date on the title page and in the name, so i know whats the most recent version )
Now i have a separate tunebook for each instrument, with the same looks

What does this script?

  • Generates a title page using Latex
  • Generates a tune index, with page numbers ( works with multipage tunes )
  • Adds bookmarks to the tunes, so you can use the bookmark link in your reader.
  • Merges all pdf’s into one.

Todo: embed page numbers on every page?

BASH script:

#!/bin/bash

nrpdf=$(ls *\.pdf | grep ^[A-Z]  | wc -l)
echo "Tune PDFs in directory : $nrpdf"
pages=$(( $nrpdf / 126 ))
pages=$(( $pages + 1 ))
echo "Needed index pages : $pages"

# Extra pages : Number 002-099
extrapages=$( ls 0*pdf | egrep -v "001|000" | wc -l)
echo "Extra pages : $extrapages"

nr=$(( 1 +  $extrapages + $pages ))
echo "Total pages for tunes : $nr"
echo "create column page as text"
nr=$(( $nr +1 ))
ls *\.pdf | grep ^[A-Z] | sort | while read ; do
echo "$nr $REPLY"
next=$(exiftool "$REPLY" | awk -F": " '/Page Count/{print $2}')
nr=$(( $nr + $next ))
done | cut -f1,3- -d" " | cut -f1 -d. | sed s/\ a$//g | sed s/\ b$//g | pr -2 -t > /tmp/col
echo "Create Index pdf"
vim /tmp/col -c "set printfont=courier:h12"  -c":let &printheader = \" \""   -c "hardcopy > 001aIndex.ps | q"; ps2pdf 001aIndex.ps

echo "Create title page pdf"
pdflatex "000 title.tex" 1>/dev/null

tempPDF=`mktemp`

echo -n "Add bookmarks : "
ls *\.pdf | grep ^[A-Z] | sort | while read i ; do
    bookmarkTitle=$( echo $i | cut -f2- -d" " | rev | cut -f2- -d. | rev)
    bookmarkInfo="BookmarkBegin\nBookmarkTitle: $bookmarkTitle\nBookmarkLevel: 1\nBookmarkPageNumber: 1"
    pdftk "$i" update_info_utf8 <(echo -en $bookmarkInfo) output $tempPDF >/dev/null
    mv $tempPDF "$i"
    echo -n "."
done
echo ""
set +x
#ls *\.pdf | grep ^[A-Z] | sort > /tmp/pdflist
pdftk *pdf cat output ../tunebook_$(date +%Y%m%d).pdf

Needed tex file (named “000 title.tex”)

\documentclass[11pt]{report}
\usepackage[T1]{fontenc}
\usepackage{anyfontsize}
\usepackage[a4paper, total={6in, 8in}]{geometry}

\usepackage[T1]{fontenc}
\usepackage{tgbonum}

\newlength{\drop}

\begin{document}
  \begin{titlepage}
    \drop=0.1\textheight
    \centering
    \vspace*{\baselineskip}
    \rule{\textwidth}{1.6pt}\vspace*{-\baselineskip}\vspace*{2pt}
    \rule{\textwidth}{0.4pt}\\[\baselineskip]
    {\fontsize{50}{60}\selectfont Irish Tunes Test Tunebook}
    \rule{\textwidth}{0.4pt}\vspace*{-\baselineskip}\vspace{3.2pt}
    \rule{\textwidth}{1.6pt}\\[\baselineskip]
    \scshape
	{\large Tunebook}\par
    \vspace*{2\baselineskip}
    {\itshape Henri - Exampletunes\par}
    \vfill
    {\scshape generated:} \\
    \today
  \end{titlepage}
\end{document}

File naming:

000 title
001 index
002 – 099 xyz (extra pages, not in index)
AAA – ZZZ Tunes (i take te first letters from the tune name)
example “BOR I was born for sports.pdf” is sorted under BOR from born

000 title.pdf
001aIndex.pdf
002 tuneinfo.pdf
BAT The Battle of Aughrim.pdf
BOR I was born for sports.pdf
CER Cerlew Jig.pdf
CHA Chanters Song.pdf
GAN Gander at the Pratie Hole.pdf
HON honeymoon.pdf
KIT Kitty Goes a-Milking.pdf
TER Terribus.pdf

51st highlanders I will name "AAA51 51st highlanders.pdf"

Output from the script

 ./generatebook
Tune PDFs in directory : 8
Needed index pages : 1
Extra pages : 1
Total pages for tunes : 3
create column page as text
Create Index pdf
Create title page pdf
Add bookmarks : ........

Needed software:

pdftk, pdflatex, vim, exiftool, texlive-fonts-recommended

Domoticz + NodeRed + HomeAssistant MQTT

I’ve got my RFXCOM connected to my Domoticz, and not connected to my HA.

RFXCOM 433 Mhz

To have the changes of my IOT devices being known to HomeAssistant I wanted to use mqtt.

Domoticz writes the mqtt topic (payload) like this
(topic: domoticz/out)

{
	"Battery" : 100,
	"LastUpdate" : "2022-11-17 18:21:59",
	"RSSI" : 6,
	"description" : "",
	"dtype" : "Temp + Humidity",
	"hwid" : "4",
	"id" : "230E",
	"idx" : 8461,
	"name" : "Living Temp/Hum",
	"nvalue" : 0,
	"stype" : "Cresta, TFA TS34C",
	"svalue1" : "20.0",
	"svalue2" : "60",
	"svalue3" : "1",
	"unit" : 1
}

So you can’t see which device it is by the topic name, the idx is in the json (8461)

To get this device ( a temperature sensor) into HA using mqtt i rewrote the mqtt topic using NodeRed

Temperature Humidity Sensor

NodeRed flow

[
    {
        "id": "836cc419ddb2ca2b",
        "type": "mqtt in",
        "z": "cfb00976f06591d6",
        "name": "",
        "topic": "domoticz/out/#",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "8c74c5f6.9a7a48",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 200,
        "y": 140,
        "wires": [
            [
                "dbe628e18027a287"
            ]
        ]
    },
    {
        "id": "a6cb517fd1cc9987",
        "type": "mqtt out",
        "z": "cfb00976f06591d6",
        "name": "",
        "topic": "",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 870,
        "y": 140,
        "wires": []
    },
    {
        "id": "dbe628e18027a287",
        "type": "function",
        "z": "cfb00976f06591d6",
        "name": "MQTT REWRITE",
        "func": "var varidx = msg.payload.idx;\nmsg.topic = \"home/\"+varidx+\"/payload\";\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 570,
        "y": 140,
        "wires": [
            [
                "a6cb517fd1cc9987"
            ]
        ]
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "MQTTSERVERIP",
        "broker": "MQTTSERVERIP",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]

The function node code ( rewrites the mqtt topic)

var varidx = msg.payload.idx;
msg.topic = "home/"+varidx+"/payload";
return msg;

Now we have a idx separated payload “home/IDX/payload”
(The other entries svalue/nvalue are from testing.

Adding the MQTT entries to HomeAssistant configuration.conf

mqtt:
 sensor:
  - name: "LivingTemperature"
    state_topic: "home/8461/payload"
    unit_of_measurement: "°C"
    value_template: "{{ value_json.svalue1 }}"
  - name: "LivingHumidity"
    state_topic: "home/8461/payload"
    unit_of_measurement: "%"
    value_template: "{{ value_json.svalue2 }}"

Now i can add the card to the dashboard.

This should now be a generic mqtt translator

A quick update:

Adding a motion sensor:

Home Assistant
  - name: "LivingMotion"
    state_topic: "home/45/payload"
    value_template: "{{ value_json.nvalue }}"

Add sensors to be reset to the switch node

[
    {
        "id": "836cc419ddb2ca2b",
        "type": "mqtt in",
        "z": "cfb00976f06591d6",
        "name": "",
        "topic": "domoticz/out/#",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "8c74c5f6.9a7a48",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 200,
        "y": 140,
        "wires": [
            [
                "dbe628e18027a287",
                "768bb6e4b6731436"
            ]
        ]
    },
    {
        "id": "a6cb517fd1cc9987",
        "type": "mqtt out",
        "z": "cfb00976f06591d6",
        "name": "",
        "topic": "",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 870,
        "y": 140,
        "wires": []
    },
    {
        "id": "dbe628e18027a287",
        "type": "function",
        "z": "cfb00976f06591d6",
        "name": "MQTT REWRITE",
        "func": "var varidx = msg.payload.idx;\nmsg.topic = \"home/\"+varidx+\"/payload\";\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 570,
        "y": 140,
        "wires": [
            [
                "a6cb517fd1cc9987"
            ]
        ]
    },
    {
        "id": "768bb6e4b6731436",
        "type": "switch",
        "z": "cfb00976f06591d6",
        "name": "",
        "property": "payload.idx",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "45",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 330,
        "y": 260,
        "wires": [
            [
                "e46fed76a596a719"
            ]
        ]
    },
    {
        "id": "e46fed76a596a719",
        "type": "delay",
        "z": "cfb00976f06591d6",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 500,
        "y": 260,
        "wires": [
            [
                "3f7eeffc8d066de3"
            ]
        ]
    },
    {
        "id": "3f7eeffc8d066de3",
        "type": "function",
        "z": "cfb00976f06591d6",
        "name": "nvalue 0",
        "func": "msg.payload.nvalue = 0;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 700,
        "y": 260,
        "wires": [
            [
                "dbe628e18027a287"
            ]
        ]
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "MQTTIP",
        "broker": "MQTTIP",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]

Assembly in Dosbox, and draw a line

Below my setup in Dosbox.
(As used 30 years ago)

First install dosbox (Linux/Windows)

download the package with used files and compilers from here:
https://media.henriaanstoot.nl/assembly.tgz

extract with tar xzvf /tmp/assembly.tgz to a directory

start dosbox and mount the directory as C

mount c /path/assembly

Run “a line”, this a batchfile which starts the editor (qedit)
When closing the file (esc – q menu)
It will compile the assembly and write out a executable

This is the batchfile

@echo off
q %1.asm
cls
masm %1.asm;
link %1.obj;
exe2bin %1.exe %1.com
echo READY!

line assembly code

    NAME lijnentrekroutine

.286

Code SEGMENT
    ASSUME CS:Code,DS:Code
org 100h
Start:
    mov ax,13h            ;set video mode
    int 10h

    mov bx,100
    mov cx,100
hiero:
    mov dx,0a000h
    mov es,dx
    mov ax,320
    mul cx
    add ax,bx
    mov di,ax
    mov al,2
    stosb
    inc bx
    inc bx
    inc cx
    cmp bx,150
    jnz hiero


    mov ah,8
    int 21h
    mov ax,3
    int 10h

    MOV AX,4C00h
    INT 21h

code ends
end start

Hercules to VGA

While playing with MuseScore….
(Typesetting some scores for Pipes and Flute)

This came in: WOOOT

Trident 8900C (1024 x768 max 512Kb)

This is a Trident VGA card. While having a 16bit ISA connector, it can work in a 8bits ISA slot.

A while ago i bought a Laser XT/3, that’s the one my parents had.
This is where i did a lot of assembly programming on.
It’s a 8086 cpu, 640K and has a Hercules/CGA graphics card.

I found loads of assembly files and i want to see if i can get it running again.
While some code was written for hercules, ( That’s the monochrome image you see in the example above ) and a few for EGA (4 colors).

Most of it was written for VGA. Probably on a later machine like a 80386?

But i know there are vga cards for 8 bit msdos computers, and i found one. ( This one is even autodetect, so no jumpers to figure out)

So i’ve put this card in the machine, turned it on, and it works!
I’ve got only 2 examples living on the harddisk of the machine, both black and white … 🙂
I have to search for interesting code in hundreds of files.

Some friends of mine, picture was taken from an amiga genlock digitizer
The intro pages of a “amiga emulator” WHERE is the rest??? (end is a cga starfield demo)

Hercules Card

There is not much info available about this card:

  • Max resolution (Hercules) : 720×348
  • 15 pin analog monitor port (CN1)
  • BIOS enabled JP1 Pins 1 & 2 closed
  • BIOS disabled JP1 Pins 2 & 3 closed
  • CGA selected SW1 On
  • MDA (Hercules) selected SW1 Off

Floppy drive boot

My friend EDK and I made some demo’s like

And a boot demo, which was able to start from a bootsector, went into a graphic mode and ran a demo with sound. Edk wrote a sector loader for this.
I have some 5.25 inch floppy disks, labelled boot demo. So i wanted to try this today …
I needed to change the boot order, so i went online to search for jumper settings.

I see a led when it tries to boot, but my disks are probably formatted 720Kb instead of 360Kb, which this drive is.

So …. TODO!

Find a 720Kb floppy drive (5.25 inch), and sort through my code!
There is a 8bit soundblaster compatible soundcard that i bidding on online, hopefully i’ll get it

Assembly and modes

I wasn’t sure how to sort the assembly code into Hercules and VGA compatible, but i used this table (There are also extended modes for higher resolutions)

mode 0x00text 40×25 gray
mode 0x01text 40×25 16 colors
mode 0x02text 80×25
mode 0x03text 80×25 16 color
mode 0x04graphics mode (CGA) 320×200
mode 0x05graphics mode (CGA) 320×200
mode 0x06graphics mode (CGA) 640×200 (B/W)
mode 0x07text 80×25 Hercules
mode 0x0Fgraphics mode 640×350? gray
mode 0x10graphics mode 640×350?
mode 0x11graphics vga 2 colors
mode 0x12graphics vga 16 colors
mode 0x13graphics 320×200 256 colors
# Set VGA mode
    mov ax,13h
    int 10h         ;screen 320x200 256 colours

# Exit VGA mode
    mov ax,3
    int 10h         ;screen  80x25 text
    mov ax,4c00h
    int 21h         ;back to DOS