Remote Garage Door Sensor/Opener
So, I live on the top floor of a three-storey building. My garage has an electric door and is vertically below my aparment on the 'basement' level. The following post details my efforts to be able to know if the door is open, and to possibly control it remotely. In the past, I've accidently left the door open and I want to be able to prevent this! I also want to be able to access the garage when the keys aren't nearby.
I've already tried a crappy 433mhz universal remote from eBay, which did train to the garage remote. I then went to test it and 1-in-50 key-presses worked. The purchase ended up being a quick and cheap way to work out that the Vicway V-380G has rolling codes!
Fortunately, this model garage-door-opener also has terminal blocks with a screw-terminal named DOOR. I asked the manufacturer if I could just short that terminal with the one next to it named GND and they confirmed that doing so will operate the door! What should I use to do this? Arduino? Raspi? Any of the above? Sure... but how do I communicate with any of them from three concrete storeys above?
- WIRELESS: Does not work... the signal doesn't reach. My mobile phone gets no wifi signal when in the garage. It does work out in the carpark though.
- ETHERNET: Ok sure... run a cable down the side of the building? Is there an inner cable cavity between solid concrete floors? No, but, ethernet-over-power does work! Do I want my LAN exposed to the entire building's power grid? I dunno.
- LORA: Will this be able to communicate through three layers of solid concrete? Wifi couldn't. I'm still going to give it a bash. Will the signal be encrypted? Can any hacker just muck around with my garage door if they wanted to?
POC #1: Ethernet
I have two pairs of ethernet-over-power devices, and I tested a Netcomm set first. Plugging it in saw the home link light mainly solid, but it was probably blinking more than it usually should. I assume the connection through the building's power grid is noisy-AF and, well, I didn't really think I expected anything less. Regardless... I wasn't here to stream 4K60, I just wanted a crappy website hosted on the Arduino with a button and a bit of status information.
An Arduino Ethernet Shield was purchased from Jaycar, along with a tiny relay board. I have a few boards with 4 or 8 relays... but I didn't want to waste them. The example webserver sketch was uploaded to a UNO with the Ethernet shield attached and the unit was moved to the garage with the ethernet-over-power in place.
And ... nothing. Link, but no data. I don't know what I was expecting... ethernet-over-power was not going to work.
POC #2: LoRa with MQTT
There are a lot of great blogs on the internet... and whenever I think of a cool idea for a project... I know someone has already done it... somewhere... somehow. What I wasn't expecting was to find someone in NZ that was considering the exact same setup of components from jaycar. Jon, thank you for the work you put in to documenting the caveats of these older-style components. I went ahead and purchased both the LoRa Sheild (I already had enough spare Arduinos at home) and LoRa Gateway.
The LoRa Gateway is an all-in-one LoRa radio + Arduino + Linux SOC. The SOC talks to the Arduino via SPI and uses Yun's Bridge Protocols. If you search for any of this, then you'll quickly find that all of this tech is OLD. LoRaWAN is the new standard and this is all LoRa-only.
I had plans to host a webpage on the gateway and send data directly to the LoRa node, but I quickly realised that extending the gateway to do my bidding was going to be difficult. It uses flash disk with most files read-only and the website is hosted from ROM! Instead, I'd have to have the gateway actually be a gateway and transmit data to some other server on my LAN.
The setup would therefore be configured as follows...
Garage | Gateway | NAS | ||||||
---|---|---|---|---|---|---|---|---|
Arduino (Read Sensors) | –> | LORA Gateway (Arduino) | –> | LORA Gateway (Linux SOC) | –> | MQTT Broker | <-> | Website |
Arduino (Operate Relay) | <– | LORA Gateway (Arduino) | <– | LORA Gateway (Linux SOC) | <– | –> | SQL Database |
I chose a local MQTT Broker, as I didn't really want to sign up to another external webservice (they seem to use Thingspeak), to only then have to bring the data back down to the local network once again. The local broker wouldn't persist data, so I would also have to work out a mechanism to store in a DB somewhere. Fortunately (hah, or so I thought) I already has MS SQL running in docker on the NAS.
Setting up the Arduino IDE
Following the actual Dragino documentation with a newer version of Arduino will end in misery. I installed the latest 2.3+ version and got no end of errors of missing libraries. So, what to do? Spin up Win7 on my NAS and set up Arduino 1.8.6.
Once installed, add the following url to the Additional Boards Manager URLs: http://www.dragino.com/downloads/downloads/YunShield/package_dragino_yun_test_index.json
Now go to Board Manager and install the Dragino Yun set of boards:
Next, download the RadioHead Library and extract it into Documents\Arduino\libraries.
Finally, select the board, the port and load up the LoRa_Simple_Server_Yun sketch from the Dragino examples.
If it compiles... try an upload! You'll need to enter your LG01's password...
... and then ...
Seamless! Amazing actually. The code has passed through a Linux SOC and then been transmitted over SPI into the Atmel co-CPU? If this didn't work, then write a comment below and tell me what happened. Next up, set up your first node. I used a spare Leonardo with a LoRa Shield.
Download this sketch (or Jon's version), modify the node_id from 12345 to something relevant (leaving the less-than and greater-than symbols in-place) and check the serial monitor on both sides...
It... works! RSSI of -21 is very good... since the nodes are on the workbench, right next to eachother. Let's see what happens when I shift the node to the garage.
Integrate the Garage
The garage door motor has a terminal block wth DOOR and GND. These need to be bridged to activate (open or close) the door... so I bought a relay module and wired it across. Next up, I wanted to know if the door was open or closed, so I bought two magnetic reed switches and installed them at either end of the door chain traversal. I also threw on a temperature and humidity sensor.
With this all wired up, the Arduino was ready to transmit statistics and react to commands.
Provide basic feedback from the Gateway
I was initially going to use an Arduino Buzzer from Jaycar and the Buzzer Library (who doesn't want bits of the Super Mario tune playing!?), so I could get audio feedback to know what the garage door is doing. Unfortunately, including and operating the buzzer interfered with the Yun Bridge Library communication when writing/reading files from the Linux SOC.
It seems that Timer or PWM operation trashes the Process call and no amount of asynchronous or shell-command tinkering worked. Even the FileSystem write command spewed out empty files. I didn't even bother begging for help on the forums as the library is already deprecated. One note though... The official dragino repo has Arduino 1.6.9 for download and I wonder if this is the final 'supported' version with this gateway. Using 1.8.6 might cause these bugs?
Instead, I purchased a self-contained piezo buzzer and wired it up via my transistor power method. I wasn't sure if the digital pins could deal with the current and therefore used the transistor as a switch. I also grabbed a large flashing LED for consistent 'door is open' statii notification.
Attaching all this to the Gateway was easy enough as they provide a really nice screw-terminal block. The pinout is as follows:
1 | 2 | 3 | 4 | 5 | 6 | 7 | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+ | - | + | - | + | - | + | - | + | - | + | - | a | b |
+5v | GND | A0 | A1 | GND | A3 | A4 | A5 | A6 | A7 | N/A | GND | D3 | D4 |
I chose to integrate with the Digital pins 3 and 4 for my buzzer and LED respectively.
MQTT Broker Installation
This MQTT Server and Node Tutorial helped a lot, but I still didn't want to use Thingspeak. Instead, I overloaded my NAS further with the Eclipse Mosquitto Docker Image.
I created a base folder on the NAS for the home of Mosquitto. In here, I downloaded the default configuration file and created a data and log directory. The default configuration only allows local connections, so we'll need to edit it to allow external nodes to report to it. There's a great guide here, but the basic idea is to add the following line to the configuration file:
# listener port-number [ip address/host name/unix socket path] listener 1883 0.0.0.0 listener 9001 0.0.0.0 protocol websockets
Search for #listener and replace that chunk with the bit above. Now we need to create the server so that we can shell in and create a password file. Port 9001 will be used for WebSocket connections and port 1883 will be for standard TCP connections. I've called it mosqii here, but you can call it whatever you like. Just remember to use the new name in each subsequent command.
#docker create --name mosqii -it -p 1883:1883 -p 9001:9001 -v /volume2/SSD/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf -v /volume2/SSD/mosquitto/data:/mosquitto/data -v /volume2/SSD/mosquitto/log:/mosquitto/log eclipse-mosquitto
Once created, start it with:
$ docker start mosqii
With it up and running, use the following command to connect via sh and create a password file with a username and password of your choice:
$ docker exec -it mosqii sh / # cd mosquitto/config /mosquitto/config # mosquitto_passwd -c garage_door_auth garage_door Password: Reenter password: /mosquitto/config #
Type exit and get out of docker. Stop the docker container with:
$ docker stop mosqii
Edit mosquitto.conf once again, adding the newly-created password file to our listener configuration. We couldn't do this at the start as the server would crash if the file wasn't found.
# listener port-number [ip address/host name/unix socket path] listener 1883 0.0.0.0 listener 9001 0.0.0.0 protocol websockets password_file /mosquitto/config/garage_door_auth
Download MQTT Explorer and connect to the server to test your settings...
Data!
Configure the Gateway for MQTT
With the Gateway connected to my local LAN, I browsed to my router and checked the DHCP listing. duinotech-xxxxx was listed at IP 192.168.1.156 and a quick browse via chrome brought up the internal website. If you've bought one from Jaycar, then the initial password is duinotech.
The unit was quickly upgraded with firmware v4.3.7 and the root password then changed to dragino.
Let it reboot and do its thing... then browse to the Servers and select MQTT with debugging enabled.
Next head to the MQTT Settings page and fill out the private server details. Add a row to the channels table so that we have something to match on when the LoRa node sends data.
With it all configured, return to the system logging and see what's going on. Thankfully the logging is pretty self-explanatory!
Note that initially I had no data flowing to the newly created server. I actually had to SSH into the Gateway to work out what was going on, but even getting in wasn't easy...
$ ssh -l root 192.168.1.156 Unable to negotiate with 192.168.1.156 port 22: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,kexguess2@matt.ucc.asn.au
Turns out it's using old cipher methods and you need to overload your ssh client to force it to connect...
$ ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-rsa -l root 192.168.1.156 root@192.168.1.156's password: BusyBox v1.23.2 (2019-01-10 15:05:04 CST) built-in shell (ash) ____ ____ _ ____ ___ _ _ ___ | _ \| _ \ / \ / ___|_ _| \ | |/ _ \ | | | | |_) | / _ \| | _ | || \| | | | | | |_| | _ < / ___ \ |_| || || |\ | |_| | |____/|_| \_\/_/ \_\____|___|_| \_|\___/ W i F i, L i n u x, M C U, E m b e d d e d OpenWRT Chaos Calmer 15.05 Version: Dragino-v2 IoT-4.3.7 Build Wed Sep 11 22:30:26 CST 2019 www.dragino.com ---------------------------------------------------- root@dragino-17b9d2:~#
All scripts are in /etc/iot/scripts/. I was going to inspect mqtt_process.sh, but decided to just follow Jon's instructions and replace the existing file.
root@dragino-17b9d2:~# cd /etc/iot/scripts/ root@dragino-17b9d2:/etc/iot/scripts# ls lg01_pkt_fwd mqtt_process.sh mqtt_process_old.sh mqtt_sub.sh polish_mqtt_config tcp_client tcp_client.lua xively_routine.lua root@dragino-17b9d2:/etc/iot/scripts#
The replacement script is here, but that also caused issues for me. I could see in the web logs that it was complaining that "12345/" didn't match any known configuration keys. It turns out that a trailing slash was causing the issue. This can be fixed on line 66 of Jon's mqt_process.sh by removing the trailing slash so that it reads:
CID=`ls /var/iot/channels/`
With this fix done, the data was flowing to the MQTT Broker and visible in MQTT Explorer!
Web remote
A quick website was spun up in a folder on my Windows machine. It uses MQTT.js and reports the data from the garage.
<html> <head> <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script> <script> const url = 'mqtt://someserver.somewhere.org:9001' const options = { // Clean session clean: true, connectTimeout: 4000, // Authentication clientId: 'garage_door_ctrl', username: 'garage_door', password: 'some_password_here', } const client = mqtt.connect(url, options) client.on('connect', function () { console.log('Connected') // Subscribe to a topic client.subscribe('channels/garage_door/publish/this_is_a_key', function (err) { console.log('ERROR: ' + err); }) }) client.on("message", (topic, message) => { // message is Buffer //console.log(topic.toString() + ": " + message.toString()); var splitted = message.toString().split('&'); $("#temp").text(splitted[0].split("=")[1]); $("#humidity").text(splitted[1].split("=")[1]); if (splitted.length > 3) { op = splitted[2].split("=")[1]; cl = splitted[3].split("=")[1] $("#open_d").text(op); $("#closed_d").text(cl); if (op == "0") { $("#open_close_btn").text("Close Door"); $("#open_close_btn").prop("disabled", ""); } else if (cl == "0") { $("#open_close_btn").text("Open Door"); $("#open_close_btn").prop("disabled", ""); } else { $("#open_close_btn").text("...moving..."); $("#open_close_btn").prop("disabled", "disabled"); } } }); function open_close() { client.publish('channels/garage_commands', 'open_door'); $("#open_close_btn").prop("disabled", "disabled"); } </script> </head> <body> <center> <button onclick="open_close();" id="open_close_btn" disabled="disabled" style="width:90%;height:200px;font-family:tahoma; font-size:32pt;">...determining position...</button> <table style="font-family:tahoma; font-size:32pt;"> <tr> <td>T:<span id=temp>?</span></td> <td>/</td> <td>H:<span id=humidity>?</span></td> <td>/</td> <td>O:<span id=open_d>?</span></td> <td>/</td> <td>C:<span id=closed_d>?</span></td> </tr> <tr> <td colspan=4> <center id=message></center> </td> </tr> </table> </center> </body> </html>
It also sends an "open_door" message to the MQTT server on channels/garage_commands when you hit the button. Note that you need to have enabled websockets on 9001 to be able to use the MQTT.js library!
Sending data back to the Garage
One-day data is great, but how do we get the data flowing in the other direction? Turns out we actually need to subscribe to the MQTT Broker on the LG01 and act when data changes. Unfortunately, the LG01-S doesn't support configuring MQTT subscription settings in the Web UI? The documentation here indicates there should be an MQTT Subscribe configuration area, but we don't have it. Fortunately it does tell us the shell commands!
mosquitto_sub -h 192.168.199.148 -p 1883 -i dragino-1b7060 -t command
So, we can use mosquitto_sub to get commands from the MQTT broker... but how do we then get them into the MCU to send over LoRa? Turns out there's a 'talkback' server demo in the github which makes use of the Yun Process Library once again.
The goal would be to store the commands received from MQTT in a file somewhere on the Linux SOC, without bashing the flash too much and causing it to wear out, and then read the file back into the MCU. The Linux SOC offers a /tmp folder which is actually hosted in RAM, so this'll work for us. We can then read the file via the Yun Process Library on the MCU, and, if the content of the file matches a command that we want to react to, we can then send a command via the LoRa network to the node in the garage and clear the local file. Actually, we should clear the local file regardless, as there are no other consumers and we want to know if/when another MQTT message comes in.
So, on the Gateway MCU side I created an mqtt_sub.sh script in the /etc/iot/scripts/ folder:
#!/bin/sh touch /var/last_command while true do echo "waiting..." mosquitto_sub -C 1 -u garage_door -P l0r@l0r@ -h 192.168.1.61 -p 1883 -t channels/garage_commands > /var/last_command_tmp mv /var/last_command_tmp /var/last_command cat /var/last_command done
Since we now have a file to read, I added the following chunk to the gateway node so that it could send out a message over LoRa:
void checkForCommands() { String lastCommand = ""; Process pDown; pDown.begin("cat"); pDown.addParameter("/tmp/last_command"); pDown.run(); // Run the process and wait for its termination while (pDown.available() > 0) { char c = pDown.read(); if (c != '\n' && c != '\r') lastCommand += c; } if (lastCommand != "") { if (lastCommand == "open_door") { Console.println("Opening door!..."); uint8_t data[] = "OPEN_DOOR"; rf95.send(data, sizeof(data)); rf95.waitPacketSent(); } else { Console.print("Unknown command: "); Console.println(lastCommand); } File last_cmd = FileSystem.open("/tmp/last_command", FILE_WRITE); last_cmd.println(""); last_cmd.close(); } }
And it worked! The message was sent to the LoRa node and the arduino code was updated accordingly to watch for messages and act!
The only note above is that the /var folder is actually a symlink to /tmp, so they can be used interchangeably. Also note that the step to write from the temporary file to the real command file is essential. If you try to pipe out from mosquitto_sub directly then the file will be empty until a message comes in.
I then scheduled this in /etc/rc.local so that it started on boot of the gateway. Make sure you keep the ampersand at the end!
# Put your custom commands here that should be executed once # the system init finished. By default this file does nothing. /etc/iot/scripts/mqtt_sub.sh & exit 0
With this, the unit was listening consistently to the MQTT broker for commands.
Storing the data long-term!
For data persistence... any sane person would use MySql. Unfortunately, I have MS SQL running in docker... because I could... as I use it for other application development. Instead of runnign yet another DB on the NAS, it'd be nice to store this data in there also! Of course, it's never that easy! There's a great example here using python, I need ODBC from Microsoft... and I'm running this raw on the NAS... so no package manager!
So, yeah, this going to have to be ANOTHER docker container? Do I have to? Can this NAS even handle all of this? Can't I run a plugin on the MS SQL docker container? Let's see what's running on the shell inside the SQL container and if I can just run an extra process.
$ docker exec -u 0 -it sql1 /bin/bash root@sql1:/# python3 Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> exit() root@sql1:/# pip bash: pip: command not found root@sql1:/# apt-get install pip Reading package lists... Done Building dependency tree... Done Reading state information... Done E: Unable to locate package pip root@sql1:/# apt-get update Get:1 https://packages.microsoft.com/ubuntu/22.04/prod jammy InRelease [3632 B] Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB] Get:3 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB] Get:4 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main arm64 Packages [40.1 kB] Get:5 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main amd64 Packages [164 kB] Get:6 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main all Packages [1035 B] Get:7 https://packages.microsoft.com/ubuntu/22.04/prod jammy/main armhf Packages [14.6 kB] Get:8 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [2771 kB] Get:9 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB] Get:10 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB] Get:11 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages [1792 kB] Get:12 http://security.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [44.7 kB] Get:13 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1129 kB] Get:14 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [2104 kB] Get:15 http://archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [266 kB] Get:16 http://archive.ubuntu.com/ubuntu jammy/restricted amd64 Packages [164 kB] Get:17 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [17.5 MB] Get:18 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [2858 kB] Get:19 http://archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [51.8 kB] Get:20 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1420 kB] Get:21 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [2378 kB] Get:22 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [81.0 kB] Get:23 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [33.7 kB] Fetched 33.4 MB in 14s (2340 kB/s) Reading package lists... Done root@sql1:/# apt-get install pip Reading package lists... Done Building dependency tree... Done Reading state information... Done Note, selecting 'python3-pip' instead of 'pip' The following additional packages will be installed: binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-11 dirmngr dpkg-dev fakeroot fontconfig-config fonts-dejavu-core g++ g++-11 gcc gcc-11 gcc-11-base gnupg gnupg-l10n gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan6 libassuan0 libbinutils libc-dev-bin libc-devtools libc6 libc6-dbg libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libdeflate0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libfontconfig1 libfreetype6 libgcc-11-dev libgd3 libgdbm-compat4 libgdbm6 libgomp1 libisl23 libitm1 libjbig0 libjpeg-turbo8 libjpeg8 libjs-jquery libjs-sphinxdoc libjs-underscore libksba8 liblocale-gettext-perl liblsan0 libmpc3 libnpth0 libnsl-dev libperl5.34 libpng16-16 libpython3-dev libpython3.10 libpython3.10-dev libpython3.10-minimal libpython3.10-stdlib libquadmath0 libstdc++-11-dev libtiff5 libtirpc-dev libtsan0 libubsan1 libwebp7 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 linux-libc-dev lto-disabled-list make manpages manpages-dev netbase patch perl perl-modules-5.34 pinentry-curses python3-dev python3-distutils python3-lib2to3 python3-pkg-resources python3-setuptools python3-wheel python3.10 python3.10-dev python3.10-minimal rpcsvc-proto xz-utils zlib1g-dev Suggested packages: binutils-doc cpp-doc gcc-11-locales dbus-user-session libpam-systemd pinentry-gnome3 tor debian-keyring g++-multilib g++-11-multilib gcc-11-doc gcc-multilib autoconf automake libtool flex bison gcc-doc gcc-11-multilib parcimonie xloadimage scdaemon apache2 | lighttpd | httpd glibc-doc git bzr libgd-tools gdbm-l10n libstdc++-11-doc make-doc man-browser ed diffutils-doc perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl libtap-harness-archive-perl pinentry-doc python-setuptools-doc python3.10-venv python3.10-doc binfmt-support Recommended packages: libnss-nis libnss-nisplus The following NEW packages will be installed: binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-11 dirmngr dpkg-dev fakeroot fontconfig-config fonts-dejavu-core g++ g++-11 gcc gcc-11 gcc-11-base gnupg gnupg-l10n gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libasan6 libassuan0 libbinutils libc-dev-bin libc-devtools libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libdeflate0 libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libfontconfig1 libfreetype6 libgcc-11-dev libgd3 libgdbm-compat4 libgdbm6 libgomp1 libisl23 libitm1 libjbig0 libjpeg-turbo8 libjpeg8 libjs-jquery libjs-sphinxdoc libjs-underscore libksba8 liblocale-gettext-perl liblsan0 libmpc3 libnpth0 libnsl-dev libperl5.34 libpng16-16 libpython3-dev libpython3.10-dev libquadmath0 libstdc++-11-dev libtiff5 libtirpc-dev libtsan0 libubsan1 libwebp7 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 linux-libc-dev lto-disabled-list make manpages manpages-dev netbase patch perl perl-modules-5.34 pinentry-curses python3-dev python3-distutils python3-lib2to3 python3-pip python3-pkg-resources python3-setuptools python3-wheel python3.10-dev rpcsvc-proto xz-utils zlib1g-dev The following packages will be upgraded: libc6 libc6-dbg libpython3.10 libpython3.10-minimal libpython3.10-stdlib python3.10 python3.10-minimal 7 upgraded, 103 newly installed, 0 to remove and 14 not upgraded. Need to get 113 MB of archives. After this operation, 318 MB of additional disk space will be used. Do you want to continue? [Y/n]
That's a positive shiteload of dependencies... but we're on the NAS.. I have ~25tb free... so let's goooooo....
Get:106 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-distutils all 3.10.8-1~22.04 [139 kB] Get:107 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-dev amd64 3.10.6-1~22.04 [26.0 kB] Get:108 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 python3-setuptools all 59.6.0-1.2ubuntu0.22.04.1 [339 kB] Get:109 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-wheel all 0.37.1-2ubuntu0.22.04.1 [32.0 kB] Get:110 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-pip all 22.0.2+dfsg-1ubuntu0.4 [1305 kB] Fetched 113 MB in 38s (3007 kB/s) debconf: delaying package configuration, since apt-utils is not installed (Reading database ... 9933 files and directories currently installed.) Preparing to unpack .../libc6-dbg_2.35-0ubuntu3.8_amd64.deb ... Unpacking libc6-dbg:amd64 (2.35-0ubuntu3.8) over (2.35-0ubuntu3.7) ... Preparing to unpack .../libc6_2.35-0ubuntu3.8_amd64.deb ... debconf: unable to initialize frontend: Dialog debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 78.) debconf: falling back to frontend: Readline debconf: unable to initialize frontend: Readline debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.34.0 /usr/local/share/perl/5.34.0 /usr/lib/x86_64-linux-gnu/perl5/5.34 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.34 /usr/share/perl/5.34 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.) debconf: falling back to frontend: Teletype /var/lib/dpkg/tmp.ci/preinst: 9: arithmetic expression: expecting primary: "5 * 10000 + 13 * 100 + " dpkg: error processing archive /var/cache/apt/archives/libc6_2.35-0ubuntu3.8_amd64.deb (--unpack): new libc6:amd64 package pre-installation script subprocess returned error exit status 2 Errors were encountered while processing: /var/cache/apt/archives/libc6_2.35-0ubuntu3.8_amd64.deb E: Sub-process /usr/bin/dpkg returned an error code (1) root@sql1:/#
Short-lived excitement. Seems it wants to run a configuration screen but it can't work out how to display a text GUI? Anyway, this is the internet... someone has had this error before. So, remove the half-installed , set up apt-utils and go:
apt install apt-utils echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
There's actually a second error above regarding arithmetic. It's trying to calculate a version number, but the NAS is reporting an x for the minor version via uname. We need to mask /bin/uname and make it provide the information we need (thanks to the help over here):
root@sql1:/bin# apt-get install nano ... root@sql1:/bin# mv /bin/uname /bin/uname_old root@sql1:/bin# nano /bin/uname
Paste in the following, replacing the version number appropriately:
#!/bin/sh case "$1" in "-r") echo 5.13.0 ;; *) /bin/uname_old $1 esac
Don't forget to chmod a+x it. You should then get:
root@sql1:/bin# uname -r 5.13.0 root@sql1:/bin# uname -a Linux sql1 5.13.x #1 SMP Wed Jun 12 00:11:51 CST 2024 x86_64 x86_64 x86_64 GNU/Linux
And then, try try try again...
root@sql1:/usr/bin# apt-get install pip Reading package lists... Done Building dependency tree... Done Reading state information... Done Note, selecting 'python3-pip' instead of 'pip' The following additional packages will be installed: binutils binutils-common binutils-x86-64-linux-gnu build-essential... Suggested packages: binutils-doc cpp-doc gcc-11-locales... Recommended packages: libnss-nis libnss-nisplus The following NEW packages will be installed: binutils binutils-common binutils-x86-64-linux-gnu build-essential... The following packages will be upgraded: libc6 libpython3.10 libpython3.10-minimal libpython3.10-stdlib python3.10 python3.10-minimal 6 upgraded, 103 newly installed, 0 to remove and 14 not upgraded. Need to get 99.4 MB of archives. After this operation, 318 MB of additional disk space will be used. Do you want to continue? [Y/n] y ... Get:69 http://archive.ubuntu.com/ubuntu jammy/main amd64 fontconfig-config all 2.13.1-4.2ubuntu5 [29.1 kB] Get:70 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gnupg-l10n all 2.2.27-3ubuntu2.1 [54.4 kB] Get:71 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gnupg-utils amd64 2.2.27-3ubuntu2.1 [308 kB] Get:72 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gpg amd64 2.2.27-3ubuntu2.1 [519 kB] Get:73 http://archive.ubuntu.com/ubuntu jammy/main amd64 pinentry-curses amd64 1.1.1-1build2 [34.4 kB] Get:74 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gpg-agent amd64 2.2.27-3ubuntu2.1 [209 kB] ... Fetched 99.4 MB in 46s (2182 kB/s) Extracting templates from packages: 100% Preconfiguring packages ... (Reading database ... 9572 files and directories currently installed.) Preparing to unpack .../libc6_2.35-0ubuntu3.8_amd64.deb ... Unpacking libc6:amd64 (2.35-0ubuntu3.8) over (2.35-0ubuntu3.7) ... ... Setting up libalgorithm-diff-xs-perl (0.04-6build3) ... Setting up libalgorithm-merge-perl (0.08-3) ... Setting up libpython3-dev:amd64 (3.10.6-1~22.04) ... Setting up python3-dev (3.10.6-1~22.04) ... Processing triggers for libc-bin (2.35-0ubuntu3.7) ... /sbin/ldconfig.real: /opt/mssql/lib/libc++.so.1 is not a symbolic link /sbin/ldconfig.real: /opt/mssql/lib/libc++abi.so.1 is not a symbolic link root@sql1:/# pip install paho-mqtt Collecting paho-mqtt Downloading paho_mqtt-2.1.0-py3-none-any.whl (67 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.2/67.2 KB 40.3 kB/s eta 0:00:00 Installing collected packages: paho-mqtt Successfully installed paho-mqtt-2.1.0 root@sql1:/#
Errors? But, yey, paho-mqtt is installed! Install pyodbc also, and then grab the scripts and follow the instructions for the MS SQL driver over here. I copied the ubuntu scripts, removed sudo as it's not installed, installed curl as it's required and then kicked it off.
if ! [[ "16.04 18.04 20.04 22.04" == *"$(lsb_release -rs)"* ]]; then echo "Ubuntu $(lsb_release -rs) is not currently supported."; exit; fi curl https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | tee /etc/apt/sources.list.d/mssql-release.list apt-get update ACCEPT_EULA=Y apt-get install -y msodbcsql17 # optional: for bcp and sqlcmd ACCEPT_EULA=Y apt-get install -y mssql-tools echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc # optional: for unixODBC development headers apt-get install -y unixodbc-dev
root@sql1:/database_tools# ./inst_ms.sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 983 100 983 0 0 231 0 0:00:04 0:00:04 --:--:-- 240 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 88 100 88 0 0 27 0 0:00:03 0:00:03 --:--:-- 27 Hit:1 https://packages.microsoft.com/ubuntu/22.04/prod jammy InRelease Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB] Hit:3 http://archive.ubuntu.com/ubuntu jammy InRelease Get:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB] Hit:5 http://archive.ubuntu.com/ubuntu jammy-backports InRelease Fetched 257 kB in 9s (29.6 kB/s) Reading package lists... Done Reading package lists... Done Building dependency tree... Done Reading state information... Done msodbcsql17 is already the newest version (17.10.6.1-1). msodbcsql17 set to manually installed. 0 upgraded, 0 newly installed, 0 to remove and 14 not upgraded. Reading package lists... Done Building dependency tree... Done Reading state information... Done mssql-tools is already the newest version (17.10.1.1-1). 0 upgraded, 0 newly installed, 0 to remove and 14 not upgraded. Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: libodbccr2 The following NEW packages will be installed: libodbccr2 unixodbc-dev 0 upgraded, 2 newly installed, 0 to remove and 14 not upgraded. Need to get 264 kB of archives. After this operation, 1895 kB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 libodbccr2 amd64 2.3.9-5ubuntu0.1 [16.7 kB] Get:2 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 unixodbc-dev amd64 2.3.9-5ubuntu0.1 [248 kB] Fetched 264 kB in 8s (33.1 kB/s) Selecting previously unselected package libodbccr2:amd64. (Reading database ... 19952 files and directories currently installed.) Preparing to unpack .../libodbccr2_2.3.9-5ubuntu0.1_amd64.deb ... Unpacking libodbccr2:amd64 (2.3.9-5ubuntu0.1) ... Selecting previously unselected package unixodbc-dev:amd64. Preparing to unpack .../unixodbc-dev_2.3.9-5ubuntu0.1_amd64.deb ... Unpacking unixodbc-dev:amd64 (2.3.9-5ubuntu0.1) ... Setting up libodbccr2:amd64 (2.3.9-5ubuntu0.1) ... Setting up unixodbc-dev:amd64 (2.3.9-5ubuntu0.1) ... Processing triggers for libc-bin (2.35-0ubuntu3.7) ... /sbin/ldconfig.real: /opt/mssql/lib/libc++.so.1 is not a symbolic link /sbin/ldconfig.real: /opt/mssql/lib/libc++abi.so.1 is not a symbolic link root@sql1:/database_tools#
Before-long, SQL drivers were installed. Now, the meat. We need a python script to watch MQTT. Using chunks from this tutorial, I came up with the following:
#!/usr/bin/python3 import paho.mqtt.client as mqtt import pyodbc from datetime import datetime #MQTT Settings brokerAddress = "localhost" userName = "garage_door" passWord = "password_here" subscribeTopic = "garage_door/publish/this_is_a_key" # Connect to Database driver = "{ODBC Driver 17 for SQL Server}" server = "localhost" database = "MQTT_DATA" username = "mqtt_user" password = "password_here" connectionString = "DRIVER=" + driver + ";SERVER=" + server + ";DATABASE=" + database + ";UID=" + username + ";PWD=" + password conn = pyodbc.connect(connectionString) cursor = conn.cursor() # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected successfully") else: print("Connect returned result code: " + str(rc)) # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): topic = msg.topic measurementValue = msg.payload.decode("utf-8") SaveToDatabase(topic, measurementValue) def SaveToDatabase(topic, measurementValue): print(topic + " " + measurementValue) #Find Date and Time now = datetime.now() datetimeformat = "%Y-%m-%d %H:%M:%S" measurementDateTime = now.strftime(datetimeformat) # Insert Data into Database query = "INSERT INTO MEASUREMENTDATA (SensorName, MeasurementValue, MeasurementDateTime) VALUES (?,?,?)" sensorName = topic parameters = sensorName, measurementValue, measurementDateTime cursor.execute(query, parameters) cursor.commit() # Create the MQTT client client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message #client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS) #this may cause issues if not set up. client.username_pw_set(userName, passWord) client.connect(brokerAddress, 1883) client.subscribe(subscribeTopic) client.loop_forever()
With all the correct drivers installed, I got the following:
root@sql1:/database_tools# ./mqtt_watcher.py Traceback (most recent call last): File "/database_tools/./mqtt_watcher.py", line 20, inconn = pyodbc.connect(connectionString) pyodbc.InterfaceError: ('28000', "[28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user 'mqtt_user'. (18456) (SQLDriverConnect)")
HAHA! Yes. It hates me.. and it should... none of those credentials are correct. I went and corrected the auth, the table and the insert schema and the data was logged!
Green Hills, Nou, Itoigawa – June, 2024
Whilst driving with friends from Osaka to Aizuwakamatsu, we needed a place to split the trip and I started Googling. Toyama was a logical mid-way point, but I didn't want us to have to slug it into a boring business hotel when we just needed a place to sleep. Instead, I wanted to enjoy the summer twilight, rail-side in a country house and I managed to find just the place!: Green Hills in Nou.
This beautiful house is perched directly next to the Nihonkai Hisui Line. This happens to be a private line; but it's also the main trunk up the northern coast of Japan and the fastest route for freight from Hokkaido when trying to get further west than Tokyo. So, whilst you won't see JR Limited express trains (thanks to the Hokuriku Shinkansen), you will see trains of the Echigo-Tokimeki Railway and a parade of freight trains hauled by EF510 locomotives.
So, above was taken from the left window that you can see in the first image above. It was the 'second bedroom' on the second floor of the house. It had a beautiful view of the railway! Despite the morning rain, I managed to get up in time for the first 'daylight' freight just after 4am. Disregard the tapping in the video as it's just a leak from the gutter above, beating on the first floor roof.
The trains thundered by like clockwork... and I really need to emphasise on the word 'thundered'. Due to there being a crossover right in front of the tunnel portal next to the house, the katan-katan of the wheelsets was loud enough to actually rattle the foundations of the house.
On the next trip to Japan, I'll probably book this place for a few days and set up a temporary live camera so everyone can enjoy the sights.
Curry Station Niagara, Yutenji, Tokyo – June, 2024
This post has been in draft state since mid-2019... as I'd promised myself to visit this restaurant back then, but had never made it. The restaurant in question is Curry Station Niagara in Yutenji, Tokyo. It's a train-themed curry cafe and it's only open from 11-5pm each day. This timing does make it hard... and somehow I'd always targeted it for dinner. Fortunately, this time I had time for lunch!
It's easy to get to, being just a short walk from Tokyo Metro's Yutenji Subway Station. Note that only local trains stop at Yutenji Station!... don't try and take an express! Exit the station via the east exit and turn left. You'll soon find a hint on a corner that you're heading in the right direction...
Follow the extension cable that powers that sign and you'll arrive at the destination.
Once inside, you'll find a bench on the right to wait, whilst a counter seat or booth becomes free. At the end of the waiting area there is a ticket machine to purchase food and beverage. Talk to the proprietor first to work out where to sit and then purchase your tickets.
I went for a counter seat (pretty cramped!) as the three booths were occupied. There's a G-Scale railway running around the perimiter of the restaurant which delivers food, where possible.
Whilst other passengers receive their lunch...
Make sure you take in the full surroundings!
Before-long, my katsu curry arrived... and it was delicious!
Absolutely worth the visit. You even get a ticket as a souvenir of your visit.
Commodore 64C Set – Refurbishment
It's been while since I last had one of these units. A member of an FB group mentioned they had a C64 + Floppy Disks up for grabs, but only offered for someone to come and collect it. It was a 40 minute drive for me, and a good price, so I went for it. I'd asked for pictures whilst negotiating, but none were provided... so I had no idea what I was in for.
Turns out I was in for a great surprise! Included was a Commodore 64c with Commodore 1802 PAL Monitor. Also included was a 1541-II Disk Drive (with a box of disks!) and a Star NX-1000C Dot Matrix printer. I gave it all a cursory once-over and then applied power... but as you can see from the shot above, the happiness was short-lived.
Commodore 1802 Monitor
This unit was only producing a flat squished pattern. The image could be made-out in the squished pattern on the screen, but there was no dial to adjust vertical height... so something had to be going wrong inside. I spooled up What broke on this Commodore 1802 monitor? from Adrian's Digital Basement and left it playing whilst I started dismantling and reviewing the monitor's guts.
Hilariously, we both pulled out the same loose capacitor at the same time... couldn't believe it.
It was an absolute mess where that capacitor was. Its juices had wrecked a few resistor legs as well.
Anyway, the problematic capacitor was replaced and the vertical picture issue was fixed!
Unfortunately, there was no colour. Every site online pointed to a dead R225 (some places incorrectly mention this as R255), and so I looked at R225 on this board...
Crusty! I had no 1w 5.1Kohm resistors in stock, so I paralleled four 22kohm 0.25w resistors.
Did it work? Not really.. I started getting weird colour bars from the composite (ERROR!, this was an assumption) output of the video cable from the C64C.
So I went on a capacitor rampage and replaced everything on the board. Note that the photo below is whilst I was half-way through... trying to clean the gunk off.
This didn't fix it, so I reviewed the data on the Commodore Monitor Information Site. Unfortunately, the Commodore 1802 (tall) was the NTSC version and there was no PDF for my PAL version. Regardless, the schematics sort-of lined up... I just had issues trusting the resistors? Let's have a closer look at that (supposed) 5.1Kohm:
That resistor above has the visible colour-bands of brown red orange gold? It's meant to be a 5.1kohm? Using Element 14's Resistor Calc, I tapped in the colours I could see and was told it's actually a 12kohm resistor? Double? What gives? I then looked at R329 as seen in the photo above-above... it's meant to be a 560ohm resistor, but the colours are showing green-poo-poo-gold? Brown? Red? No idea... but that second colour is meant to be Blue! So wait... these colours have actually cooked so much that their pigment has changed?
I went back to Jaycar and bought 1w resistors that I could actually use to do proper serial maths on... instead of the parallel maths above...
560ohm was a 1:1 install... 5.1k was 1.8k + 3.3k.
Still a crap picture from the C64. A good lesson here is that you should be absolutely sure that your video signal source works... don't just assume that 40 year-old tech can produce a proper composite signal. For this reason, I tried my Playstation 2:
Oh nup, it works... it's me. I'm stupid. Every time I've written composite above, I need to be punished.
That Momement You Realise You're Stupid
This unit was built in 1987. It's a complete set. It plugs together. Why would the unit have a DIN-8 to RCA cable with Yellow+Red+White plugs if they didn't expect you to plug them into the matching sockets on the monitor?
I had assumed all along that they were stereo sound... because... 1995 called and that was the standard. Of course, that's an incorrect assumption as this machine pre-dates any such standards. So... what happens when you plug in the correct colour plugs into the correct colour sockets and switch to the "SEP" mode (i.e. separated Chroma and Luma, as per the plug names)?
LOL. Didn't I feel a little silly? Turns out a C64 DIN-8 Video cable has Yellow=Luma, Red=Chroma and White=Mono-Audio.
Floppy Drive
I tested the voltages out of the power supply, finding that the 5v line was down near 3.2v. Plugging it in and turning on the drive just saw the disk spinning and all lights on.
I found the nearest spare power supply with the relevant 12 and 5v and wired it in. It worked perfectly!
On the original drive power cable, red was 12v, green was 5v and black was ground... but always test, test and re-test before plugging anything together!
Star NX-1000C
Supposedly this thing is colour. I powered it on and it emitted an annoying beep at first. Turns out it just wanted paper. To test, you just need to hold down the online button as you power it on...
Well I'll be... it just worked. It even printed from GEOS. Time to find some tractor-feed dot-matrix printer paper! A quick google tells me that wont be cheap!
GEOS
Rummaging around in the random box of floppy disks proved to be fruitful. There was a GEOS Applications disk, but no base boot disk. I randomly selected a blank disk with no label from the box and tried LOAD "*",8,1. Would you believe it? GEOS booted!
Unfortunately, the desktop wasn't grey... instead it was a hideous shade of smeared pink. All images I could find on the net showed that GEOS should have a light grey background, similar to a macintosh boot. I did find an eBay auction that had similar issues as mine.
I thought it may be chroma/luma, so I rigged up a composite video cable and tested it:
Seems I might need a LumaFix for this... it's on order. Of course, it might just be how it's meant to be displayed.
S-Video Conversions
I nearly fell for the same fallacy again... make sure you can trust your inputs! The 1802 monitor has S-Video style inputs, but it's using RCA plugs. This makes it hard to both connect something else to this 1802 and connect the C64 to another S-Video display. So, what to do? Build an adapter...
Hideous, right? I read here that I needed a 300ohm resistor inline in the Chroma, so that was wedged in. I then whipped out my trusty Sony PVM LCD and ... well, the C64 looked stunning.
The jailbars are there, so I'm looking forward to receivng the LumaFix... but even without it, this monitor goes very well with the C64! So, with the adapter in hand, I flipped the game and routed my Playstation2 through S-Video and into the C64 1802 Monitor.
Shite. So. What's going on here? I know I twiddled all of the potentiometers inside the monitor to oblivion... but those colours are an entire primary-colour off. Just in case you're wondering...
Right behind the 'external' contrast potentiometer is the "sub-brightness" control. "Tint" is R507, next to the grey-box mid-picture. Anyway, something was off, and I had a hunch! I loaded up Sim-City to check how green the grass was and it proved to be grey! The entire green channel was missing? After an hour of multi-metering... I accidently knocked Q555 on the board that plugs into the back of the picture tube and green came back!
Yup, that's Q555, sitting proud at the top of the PCB. I must've bumped it during capacitation and broken the solder joints. A quick re-solder and ....
It's glorious!
PC-98 – Window Accelerators
Thanks to the complexity of Kanji characters, early Japanese 'DOS' machines needed high-resolution text displays. This requirement resulted in the PC-98's 640x400 standard console mode. The video cards to run this were purposely-built and were never really meant to run Windows.
Due to these limitations, companies started coming out with "Window Accelerators" which provided a secondary video device, of which could produce much higher resolutions at higher colour depths. I happened to get my hands on an IO-DATA GA-1280A-2, capable of 1280x1024 @ 256 colours.
Being a secondary video device, these cards require a passthrough cable from the primary machine video output to their 'input' port. When the machine is displaying standard PC-98 graphics, accelerators will route this output straight to the monitor. Once the card is initialised, you'll hear the internal relays 'click' and video will be displayed from the card's internal ram buffer, which specific software is now sending the graphical data to.
Unfortuantely, my specimen came as-is with no cable... so a trip was made to Jaycar for a male and female set of ribbon-crimp IDC 15-pin plugs.
The card was mounted in the machine and the wiring was hooked up...
With no drivers, the card will just pass the standard video through. This is what happened until I installed the drivers for DOS and Windows 3.1. And then? Reboot... a beautiful "CLICK" from the relay on the card and...
Windows 3.1 at a ridiculous resolution.
Does it play Doom?
By default, a PC-9801 can't play doom with it's in-built EGC video card. The settings only give you the following options:
And yeah, GA-1280* is there and it works perfectly.. not even needing other drivers! Well. It runs terribly on the PC-9801VX, even with the 486 Upgrade. The shots above were taken with the card installed in my newly-acquired FC-9801K with 486-Overdrive processor and Doom runs nicely!
PlayStation 2 – Linux And VGA
Back in University, our fourth year project was a Billiards game on the PlayStation 2. I still don't know how we wrangled making games as an educational experience, but it was fun nonetheless. We used PS2 Dev Kits that came with a linux distro, mouse and keyboard. There was also a VGA adapter which only worked with sync-on-green monitors and I specifically remember having to make a lot of desk space for the 21" Sony Trinitron. Since I'd been mucking around with the 'fake' HDD adapters for the old PS2s recently, it came to me that I should try install Linux and get VGA-out going... turns out it's not as easy as one might think!
Third-Party HDD Adapters Won't Work
If you've got a SATA adapter by PPH, or something similar, and the ethernet port is covered, or totally missing, then you're out of luck. The Linux distributions I've tried require the Original Sony HDD Adapters (or one of the original clones that HAD ethernet) and will just freeze up and stuggle if you try anything else.
Fortunately, I'd secured one for AU5$ from a Hard-Off somewhere in the bowels of Japan. Currently they're going for AU50$ on eBay AU, or ~AU20$ on Yahoo Auctions Japan.
Free MCBoot As A Bootloader
You'll need Free MCBoot installed on a memory card, unless your PS2 is already physically modded. Some versions of the PS2 work with a simple "DVD" method to install Free MCBoot and you can follow these instructions if your that happens to be the case.
I disregarded the warnings and tried to use the ISO that lined up with my 5000x version, as per the version info:
It threw the expected error...
The alternative method is to make the HDD bootable to, in turn, make the Memory Card bootable. It's all a little chicken-and-egg, but it worked in the end. I downloaded the FHDB installer 1.966 and used the HDD Raw Copy Tool to flash the IMG from the archive over the HDD I indended to use in the PS2.
This disk was connected to my PC via a USB adapter to do so. Note that I was using a blank HDD here... don't use a drive with precious data! Slap the freshly formatted HDD in your PS2 and boot it up. At the same time, copy the guts of this zip file to a folder on a USB key, as we want to run the installer to get the software installed onto a Memory Card. On the PS2, scroll down to uLE/wLE and navigate to MASS and then the folder you used above. Select the installer and hit the circle button.
After it's done, shut the unit down and unplug the HDD. Reboot with just the memory card in to make sure that it works. From here plug the HDD back into your PC and format it with WinHIIP so that it wont try to boot from the HDD again!
Linux Live DVD
You'll find a miriad of Linux Live DVDs here. We'll go with Version 3. You'll then find a huge list of ISOs to choose from. We'll take the PAL Large No Modchip. Download and burn it to a DVD. Whilst that's happening, grab Kernel Loader 3.0 and copy it to a USB drive. We'll need to copy this to the Memory Card...
Disregard the jump to the kloader folder. In fact, disregard that that folder even exists. Just use the R1 shoulder button and paste the kloader file in the root of MC0. Once it's done... insert the DVD and run the loader!
I was joking... don't insert it yet. As you can see above, they've added a DVD video folder with a static image to tell you that the DVD ain't bootable... thanks for the warning! So, boot into Free MC Boot, scroll down to the Loader, open it and, whilst it's opening, put the DVD back in. You can then select the kernel loader from the memory card and go for gold.
We're up, and we can ping! The experience is as slow as molasses from the DVD and sound doesn't work... but let's get installed first.
Installing to the HDD
There's a great tutorial here that I followed to get this done. Download INITRD.GZ, VMLINUX.GZ, ps2fdisk and fstab and send them to a USB Key. Boot into the Linux Live DVD and open xterm.
As above, insert the USB key into the PS2 and mount SDA1 in Linux. Copy ps2fdisk from the SDA1 to a usable folder and partition the disk. Note that you cannot use the already-included ps2fdisk from the Live DVD.. it just wrecks your HDD setup. Meanwhile, since we're using a memory card to bootstrap the HDD, we can wipe the entire HDD and use the lot for our Linux partitions. Just make sure to not try and fill the entire disk with the second partition as you'll get out-of-space errors. Next, mount it and copy everything over. Finally, copy FSTAB from the USB key to the hdd's /etc/ folder. Once all that's done... reboot. It's now time to configure kloader!
Finally, reboot and copy INITRD and VMLINUX to your Memory card.
As above, reset the configuration and then set the Ramdisk, kernel and root partition. Save the configuration the Memory card and boot. Excuse the shitty video quality as my internal HDMI capture card stopped working and I had to switch to a crappy USB HDMI capture device. Also notice how much quicker that boot was when compared to the DVD boot above. And yeah, still no sound. Let's fix that...
Getting Sound Going...
Seems the 'drivers' are IRX files and we can borrow them from game discs. Unfortuantely, the newest versions don't work, so use these files: LIBSD.IRX and SDRDRV.IRX. Copy them to your USB Thumb drive and insert it.
Follow the above steps to copy them to a folder called kloader on MC0.
Next open up kloader and configure the modules. Choose the configuration rows with upper-case file-names, just because. Sound! Network! We're up! But the video quality is awful...
VGA Output
So, officially, the PS2 outputs R+Sync-On-G+B. This means that your monitor needs to understand that the green channel is a combination of video synchronisation and green data. If it doesn't then you won't get a picture. Fortunately, and since this whole topic is already 20 years old, there's numerous people online who have already solved the problem for us: use an LM1881N sync-splitter.
LM1881(M or N) ======== VGA PIN 13 -----------|1 8|----- +5v PS2 PIN 10 | | VGA PIN 2 --\ 0.1uF | | PS2 PIN 12 --+----||---|2 7| | | ____ 680 kOhm Resistor | | /----|____|----\ VGA PIN 14 ------------|3 6|----| |-----\ | | \------||------/ | PS2 PIN 8 --+----------|4 5| 0.1uF | VGA PIN 6 --| ======== | VGA PIN 7 --| | VGA PIN 8 --+-------------------------------------------/ (GROUND) PS2 PIN 11 ------------- VGA PIN 1 (RED) PS2 PIN 9 ------------- VGA PIN 3 (BLUE) PS2 PIN 4 -- AUDIO RIGHT PS2 PIN 7 -- SVIDEO CHROMA PS2 PIN 3 -- AUDIO RIGHT GROUND PS2 PIN 5 -- SVIDEO LUMA PS2 PIN 2 -- AUDIO LEFT PS2 PIN 8 -- SVIDEO GROUND PS2 PIN 1 -- AUDIO LEFT GROUND (Share PIN 8 with GROUND in above circuit) PS2 PIN 6 -- COMPOSITE VIDEO OUTPUT
So, it's all pretty self-explanatory above. The PS2 AV port provides +5v, so I've used that... regardless of everyone saying to use an external source? I've also used a 680kohm resistor as the original 585k was nowhere to be found. Finally, tie all the video grounds together, leaving the audio grounds separate. Also note that PS2 Pin 1 is left-most as you're looking at the PS2.
I built up a crappy prototype and tested it out... haphazardly...
And it worked beautifully! So I mounted it a little more safely in a crappy ziffy box from Jaycar...
And gave it a spin on a real monitor...
And yes, your success may vary. You'll need to configure two variables in the boot loader and if you only configure X and not the console, you'll get the distortion as above.
Oh yeah, to configure VGA output, just press R2 when you're at the kernel boot loader and it'll cycle through the video modes. Then you just need to edit your kernel parameters to include the following: crtmode=vesa0,60 xmode=VESA,1024x768x24. Note that you may have to manually create an xmode config file in /etc/ with the contents VESA,1024x768x24 if X doesn't listen to the command line argument.
Success! I've started productionising the adapter, so tell me if anyone wants one!
Still waiting for a few parts.
What's next?
Of course, after doing all this, I find there's a newer version of Gentoo for the PS2? Learn how to build a bootable USB here. Unfortunately, the newer version doesn't support sound?.
I wonder if I can build OTTD, like I did on the PowerCenter 180.
Sony HitBit HB-F1 II – Power Supply Modifications
Whilst picking this up from a Hard-Off in DenDen Town, Osaka, I was told by the cashier that there was no power supply and that finding one would be a challenge. I wasn't too worried about this as using a 110v power supply in AU is just painful. Secondly, there seemed to be enough information on the internet to rig something together once I'd found time to do so back home.
So yeah, the power supply is a three-pin jack with AC 18v, DC 9v and Ground. This is confirmed on my unit by the voltage ratings inscribed on the base of the unit.
Finding an external supply with these two voltages would be an expensive task, so the better answer was to review the two links above to see what they did to convert. After a quick scan, it seemed that the AC voltage was used to create a -12v rail for the cartridge port and a +12v, which also was only for the cartridge port?. It seems that the MSX itself only needed the 9v DC, which it then also converted to 5v DC to run the entire system. Let's open'er'up! There are six screws under in the base that need removing. The lid will then lift off. The keyboard can then be removed, being gentle with the mylar ribbon cable.
You're then presented with the RF shielding. They've used a plastic-coated foil and it's quite soft! It's held down by screws around the bottom half, so find them all and remove them.
From here, it's the usual Sony-esque work of art. The PCB is so clean and tidy and the layout is precise. All the power paraphenalia is top-left and most of it will be redundant once we're finished with it. We're removing the power socket, so I went ahead and removed the motherboard from the case. There's 3 screws holding this down.
They went out of their way with the PCB graphic layer. They've actually drawn the connecting circuit lines on the underside of the board. There's no need to constantly flip it over if you're trying to trace a connection! There's also amazing information on pins of important ICs... and, for that note... DC sockets?
Seeing this written on the underside of the power plug threw me! Can I just supply the above voltages and get away with it? I won't need a complex supply for AC voltage if this is the case? I wired in the 12v line and, well, nothing came out! Hah. This seems to be a mis-print on the PCB? Those are NOT the voltages required.
So, I could go on about how I tested voltages in random locations and got some things going, whilst others stopped... and vice versa... but I wont, I'll just present the answer for this unit. You'll need a power supply that has +5v, +12v and -12v. Officially, you don't need the latter two if you're just using boring game cartridges. The unit only makes +12v and -12v to send to the cartridge port, and these are only used for "special" carts.. such as RS-232, etc.
Because I'm a perfectionist, I wanted to not 'downgrade' this machine... so I chose a Pico-ATX supply, as it had all the required supply voltages and an easy-to-use DC socket.
I de-soldered the ATX plug as it was just going to consume vital space inside the MSX.
On the MSX board, there's a large horizontal cable marked +/-12v. Desolder this from the left end and solder the appropriate wires to the associated supply voltages on the PicoATX.
Finally, there are two 7805 regulators that need to be removed. There's one that's bolted to the heatsink on the left and I de-soldered the wires from the mainboard. There's another nearby with a tiny heatsink on it that also needs to be removed.
With them both out, just flip the board and solder a wire into each of the OUT pins.
These need to be fed with 5v. I love how, even though the top regulator doesn't have the OUT pin described, that you can follow the traces easily from the IN of the lower regulator. The jumper wire, on the other side of the board, in the top-left of the image is drawn on this side of the board!
Once you've de-soldered the power socket, print out my personally-designed DC socket mount and use it to mount the DC socket to the board.
Finally, de-solder the power switch cable from both ends. Using one side of the power switch (it's DPST), connect one pin to ground and the other to PS_ON on the PicoATX.
Jam the lot back into the case.
When re-assembling, make sure to not screw the latches on the printer port. Try not to slice your fingers as you pinch them together and feed the board into the case.
Don't forget the two screws on the back of the case which hold the RCA socket and DC socket in place. These poor connectors get a lot of punishment. Before totally closing up this machine, I threw all the parts I removed into a zip-lock bag and stuck it under the lid. You never know, someone in the future might want to restore it to original condition?
And then it was done! Test? Of course...
Unfortunately, this unit doesn't have cursor keys! It's only got the gamepad directional arrows, and so I can't even play my favourite game.
Atari 7800 Controller Button Replacement
This Atari 7800 Gamepad came to me with one of the plastic buttons missing. They're held into the shell via two 2x2mm lugs and they must have perished after decades of abuse.
Without waiting around, I popped open the case and measured up the surviving button.
The button has a slight gradient on top, which I'm sure my 3D printer will struggle with...
And underneath there's a small tab to press on the rubber membrane inside the controller. Anyway, straight into Tinkercad I went to design a replacement.
I didn't even bother with the tab on the base... it's all just flat. The rubber membrane in the controller has a flat top anyway.
It printed OK! Could do with a sand, but I didn't have any wet-dry.
Not the prettiest... but it works perfectly! Here's the STL.
Python: Close Files If You’re Going To Open Them
I've been trying to archive some videos off Youtube lately, using yt-dlp. It's an amazing tool, but my target files have been episodes in parts. Usually four parts and Plex really hates jogging through... so what to do? Combine the files together with ffmpeg. The code was meant to be pretty simple (and 98% of it was written by ChatGPT... whoops)...
def concat_episodes(episode_name, concat_files): plfile = "file_list.txt" f = open(plfile, "w", encoding="utf-8") for filename in concat_files: f.write("file '" + filename + "'\r\n") concat_command = f"ffmpeg -stats -safe 0 -f concat -i {plfile} -c copy '{episode_name}'" print(concat_command) subprocess.run(concat_command, shell=True)
But no amount of wrangling would get ffmpeg to work. The concat filter kept throwing: Invalid data found when processing input. No amount of "-safe 0", relative paths or absolute paths worked! No permissions... no cwds or shell arguments. If I let the python script drop to the shell, then the same line pasted (since I printed it out) worked perfectly fine! What the?
OH RIGHT. I missed the memo that I should be closing a file so that it lands on disk... prior to trying to open it in another process!:
def concat_episodes(episode_name, concat_files): plfile = "file_list.txt" f = open(plfile, "w", encoding="utf-8") for filename in concat_files: f.write("file '" + filename + "'\r\n") f.close() concat_command = f"ffmpeg -stats -safe 0 -f concat -i {plfile} -c copy '{episode_name}'" print(concat_command) subprocess.run(concat_command, shell=True)
The file was still open and not flushed to disk... so ffmpeg would always open an empty file! This has been a public service announcement.
Random HDMI Capture Cards
I can't believe I'm calling these cards retro, but they are! They're all early 00s and the drivers are only for Windows XP and Vista? How random... I had no idea there were cheap PCI-E HDMI Capture cards back then. I would not have had any reason for them back then, and hardly do today, but I'd picked them up in a Hard Off somewhere across Japan for 1$ each and thought I should finally test them out.
DRECAP DC-HC1
First up is a DRECAP DC-HC1. It's tiny and came with a low-profile case bracket. I unscrewed the bracket and loosely placed it in my machine, making sure to NOT move the HDMI cable once connected.
Whilst looking for drivers... actually, prior to that, whilst trying to ID the card (there are no valid serial numbers or other identifying marks), I found other cards that also seemed to be identical. I then stumbled across this blog post which indicated that the base card was a Timeleak HD72A and that the drivers could be found here.
With the correct drivers installed, everything worked nicely!
KEIAN DM626 H3
The second card was identified via Yodobashi Camera product listing! How cool. Out of stock! Knowing the product name, I then went googling for drivers. It turns out the original site is long gone and, since their support page had ugly javascript, webarchive can't help to find drivers.
I stumbled across this blog post with great info on installation. It turns out you can use the Monster X3A drivers here for this card. The X3A only has one port, so it seems we'll only use the closest port to the motherboard? ... it actually turned out that any port on the card worked! Unfortunately, sound didn't.
Mucking around with Composite Signals
As that I couldn't get audio from the second card, I went with using the bracket of it on the first card! I wasn't ready to have a loose card hanging around inside my PC's case.
The HDMI port, by total fluke, lined up 98% and cables were securely connected. From there, I purchased this little beast for AU12$ on eBay...
And you know what? It works nicely! Here's a Sega Master System II hooked up. I've got a switch to toggle the PAL/NTSC pin, so when you see (and hear) it switch from PAL 60 to PAL you'll know why!
Nice... No more mucking around with other TVs... I can now use this to continue the long chain of Atari and Sega mods/repairs.