Thursday, 26 June 2025

Raspberry Pi Desktop Digital Signage (RaspbianOS + Wayland) - Part 2 - Mouse Automation

 In my last post I detailed how I turned one of my desktop Raspberry Pis into a digital sign that could automatically switch between multiple kiosk-mode web pages. The method that I presented works, but leaves the mouse cursor visible on the screen.

In this post I will continue that topic and show how I used ydotool to hide the mouse cursor when this solution is running.

Why ydotool?

I am by no means a Wayland expert, but my understanding is that Wayland based compositors are lean, mean and designed for security.  The security model of Wayland prevents mouse input events from being generated by an end-user, and requires daemon level authorisation. This is a problem for anyone who actually wants to automate mouse movements from a user-space tool.

ydotool  is an application that can enable user-space based automation on Wayland systems by creating a socket-based bridge that can transmit user requested events to an authorised daemon. I couldn't find detailed documentation of how to implement it, so what follows is my understanding:

There are three main components to this solution:

  • A user space tool (ydotool), which enables command line requests for  mouse and keyboard events
  • A system level daemon  (ydotoold) which processes automation requests and transmits them to Wayland
  • A file-system socket, which act as a bridge between the two components
In essence, it seems to work like this,
    The ydotoold daemon starts with system privileges, and creates a socket to listen to
    The ydotool application transmits automation requests to this socket
    The user-space requests from ydotool are turned into system level input events by ydotoold
    The mouse moves!

Of course, this will only work if the user has sufficient rights to write to the socket!

Implementing ydotool


Here is a summary I added ydotool to my digital signage solution

  • Download, build and install ydotool
  • Create a startup script for the ydotoold daemon
  • Create a systemd service for the ydotoold daemon
  • Add a ydotool command to the digital sign launch script 

I'll provide more detail for these steps below


Download, build and install ydotool


Here are the steps I used to build and install ydotool

(note - this step may be unnecessary. Apt packages for ydotool and ydotoold are available for Raspbian,  BUT I wasn't able to get the solution to work with the packaged versions. Your mileage may vary).

Install cmake 
> sudo apt install cmake

clone the ydotool repository 
> git clone https://github.com/ReimuNotMoe/ydotool.git

change into the ydotool repository directory 
>cd ydotool

run the ydotool build steps:

mkdir build
cd build
cmake ..
make -j `nproc`


install the solution (make install)

(see the ydotool github repository for more information)

If all goes well then you will have fresh copy of ydtool and ydotoold installed to /usr/local/bin

Create a startup script for the ydtoold daemon


The next step is to create a launch script for the ydotoold daemon.  I called mine /usr/local/bin/run_ydotoold.sh

Edit this file and add the following:

#!/bin/sh
export YDOTOOL_SOCKET=/tmp/.ydotool_socket

/usr/local/bin/ydotoold &

sleep 1
chmod 777 /tmp/.ydotool_socket

while true; do
    echo "ydotoold is running at $(date)" >> /var/log/ydotoold.log
    sleep 300
done

This script starts the daemon, ensures that the ydotoold socket is user writeable and then sleeps to prevent the daemon from being terminated.

Make sure to make this script executable.
> sudo chmod u+x /usr/local/bin/run_ydotoold.sh

Enable ydotoold as a systemd service


To ensure that ydotoold is run as a system level service, we need to create a systemd service script.

Edit a new service script as the superuser:
> sudo nano /etc/systemd/service/ydotoold

Add and save the following contents:

[Unit]
Description=Run ydotoold
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/run_ydotoold.sh &
User=root

[Install]
WantedBy=multi-user.target

After creating the file, enable and start the service using systemctl:

>sudo systemctl enable /etc/systemd/service/ydotoold.service
>sudo systemctl start ydotool.service
>sudo systemctl status ydotoold.service

If all goes well you should see that the service is now active and running:



Test ydotool


It should now be possible to use ydtool to move the mouse.

Open a terminal in the GUI desktop (not SSH)

set the YDOTOOL_SOCKET environment variable (don't skip this step!)

> export YDOTOOL_SOCKET=/tmp/.ydotool_socket

run a test command

> /usr/local/bin/ydotool mousemove --absolute 100 100

If everything has worked,  you should see the mouse cursor jump to coordinates 100,100 on the screen


Add ydotool to the digital sign launch script


The final step is to add the ydotool command to our digital signage launch script.  

Edit pysign/pysign_launch.sh and change it to the following:

#!/bin/bash

#Move mouse
export YDOTOOL_SOCKET=/tmp/.ydotool_socket
/usr/local/bin/ydotool mousemove --absolute 1000 1000

#run chromium using playwright
cd /home/pi/dev/pysign
source ./pysign_env/bin/activate
python3 ./pysign.py

This inserts a command to move the mouse off screen before launching the browser.


Conclusion


..and with that we are done.  Hiding the mouse cursor turned out to be just as complex as automating the browser window, but the end result is worth the effort!

Obviously, huge thanks are due to the people who maintain the ydotool repository.  Once you understand how to make it work, it is a very useful tool for automating a Wayland desktop.



Friday, 20 June 2025

Raspberry Pi Desktop Digital Signage (RaspbianOS + Wayland)

 

In my last post I mentioned turning a Raspberry Pi + Official Touch Screen into a nifty desk clock.  Well, it turns out that I actually have two desktop Raspberry Pis  and as I also wanted something to do with the second one I decided to turn it into digital signage that could swap between multiple full screen web pages in a kiosk mode browser.

Because I am probably a masochist, I wanted to do this with a typical Raspbian 64-bit OS install running Wayland. Many of the 'traditional' solutions to this problem are X-Windows based and these don't work with a Wayland descended compositor.

I'll detail the steps in the next couple of posts, but the summary of the recipe is

  •    Use python playwright and create a python script and shells script to drive the browser
  •    Use the /etc/xdg/labwc/autostart script to autostart this python script 
  •    Use ydotool to hide the mouse cursor 
  •    Create a shell scripts and a systemd service script to enable ydotool 

If you are still with me, you will have noticed that it takes much more effort to hide the mouse cursor than it does to create the page flipping kiosk browser solution. Thanks Wayland!

I'll cover the steps to get the browser automation working in this post, and cover the mouse automation in a future post.  Here is a detailed description of the first couple of steps above


Assumptions

For this recipe I am assuming that you have a Raspberry Pi 4 or better running the current (2025) 64-bit version of Raspbian OS based on Debian Bookworm.  I am also going to assume that you have configured Raspbian to automatically login to the GUI.


Install and configure SSH

Make sure that you have SSH installed and working on the device, so that you can control the device once the kiosk browser is running, otherwise you will be locked out!


Create a project folder

Create a folder to hold all of the scripts etc for this recipe. Mine is called /home/pi/dev/pysign


Create (and activate) a virtual python environment

We are going to be using python for this recipe, and for Raspbian OS this requires us to create and activate a virtual environment.  I recommend that you create this in the project folder to keep everything together.

>cd /home/pi/dev/pysign

> python3 -m venv /home/pi/dev/pysign/pysign_env

> source /home/pi/dev/pysign/pysign_env/bin/activate

(important, from this point forwards make sure that you activate the virtual environment in each ssh/terminal window that you use to do python related tasks)


Install Playwright Python

Playwright (https://playwright.dev/) is a modern web testing suite that supports multiple browsers and has multiple SDKs.  Unlike older suites like Puppeteer, it works well Wayland and the version of Chromium installed by Raspbian OS.

To install playwright, use a terminal with the python virtual environment activated and run the the following commands:

> pip install pytest-playwright asyncio

This will install playwright and the python playwright SDK. It will also install asyncio, which we will use for making asynchronous python methods.


Create the browser automation script

Next we will create the python script that uses playwright to drive the browser.  Here is a basic script, which swaps between a couple of hard coded URLs.  I called mine pysign.py


from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        app_data_path="/tmp"
        browser = await p.chromium.launch_persistent_context(
                app_data_path,
                executable_path="/usr/lib/chromium/chromium",
                args=[ "--kiosk",
                        "--start-maximized",
#                        "--disable-infobars",
                        "--ozone-platform=wayland",
                        "--no-restore-on-startup",
                        "--noerrdialogs"],
                ignore_default_args=["--enable-automation"],
                headless=False,
                no_viewport=True
)
        page = await browser.new_page()
        while True:
                await page.goto("https://playwright.dev") #Display Web Page 1
                time.sleep(30)				  #Wait 30 seconds
                await page.goto("https://old.reddit.com") #Display Web Page 2
                time.sleep(30)
        await browser.close()

asyncio.run(main())

This script uses playwright to configure chromium to launch in full screen kiosk mode, then flips between two different URLs. The script pauses for 30 seconds after showing each page.
You can easily edit this to modify the web page URLs, change the timing or add additional pages.  A better version (for a future post) would also accept command line arguments and an array of URLs to flip between, but this version is good enough to prove the concept. 


Create a python launch script

Next we will create a shell script that will launch the python program above. Creating this script will simplify the automation process later.
create a new shell script in the project folder. I called mine pysign_launch.sh 

#!/bin/bash

#run chromium using playwright
cd /home/pi/dev/pysign
source ./pysign_env/bin/activate
python3 ./pysign.py


Use chmod to make this script executable

> chmod 777 ./pysign_launch.sh


Test the python launch script

At this point it is probably worth testing the python launch script. If all goes well then chromium should launch and start flipping between a couple of windows.

(open a GUI terminal)

> source /home/dev/pysign/pysign_launch.sh

( To terminate the script, you will need to use ps and kill from an SSH session.)


Autostart the python launch script

The next step is to make sure that our launch script is automatically launched when the user logs into the desktop.  This uses the same approach as in the previous post. We just need to add our script to /etc/xdg/labwc/autostart
> sudo nano /etc/xdg/labwc/autostart
 append the following line (modify as appropriate for the folders/filenames you have chosen for your implementation)
 /home/pi/dev/pysign/pysign_launch.sh &
For the record, my complete autostart file looks like this:
/usr/bin/lwrespawn /usr/bin/pcmanfm --desktop --profile LXDE-pi &
/usr/bin/lwrespawn /usr/bin/wf-panel-pi &
/usr/bin/kanshi &
/usr/bin/lxsession-xdg-autostart
/home/pi/dev/pysign/pysign_launch.sh &


Reboot and test

The final step is to reboot the device. If everything has gone well then a few seconds after the desktop appears, the browser should launch into kiosk mode and start flipping between the URLs in the python script.


Recommended site

The default sites in the script are fairly lame. One site I recommend trying is this great implementation of the 'digital rain' effect from The Matrix.

https://rezmason.github.io/matrix/



 It looks great on the Pi screen!


Conclusion

You'll probably notice that although the solution works, the mouse cursor is often annoyingly visible on the screen. In the next post I'll cover how to use ydotool to hide this.


Saturday, 7 June 2025

Raspberry Pi Desk Clock

I have a raspberry pi 5 in one of the original touch screen v1 official 7 inch display case.  It is always on my desk but is normally powered down.    

As part of a bigger project I am working on, I wanted to turn into a web-based digital signage device - something that would show a single web page in kiosk mode and re-display the page after a reboot. To test the idea, I wanted to turn the device into a simple desk clock.  Simple enough? Well actually....

The first issue I had was getting the device to reliably and automatically show a single web page.  When I started the device was running the Raspberry Pi port of Ubuntu 24, but with Gnome running the display and XFCE and XRDP also installed to enable a different remote desktop.  Getting a kiosk mode browser running with this setup proved to be challenging enough that I decided on a do over and reinstalled the device. 

Initially I tried to get Ubuntu Core running. Ubuntu Core is specifically designed for IOT devices like digital signs and has a Raspberry Pi port.  It should be the right choice for this sort of setup, but unfortunately I could not get the display screen to work.  For some reason the DSI screen device wasn't being activated, no matter how much I fiddled with the boot config.

In the end I abandoned that approach and fell back to reinstalling the current 64-bit version of the Raspberry Pi Desktop os (which is based on Debian Bookworm).  Getting the kiosk mode to work with the display screen with this setup was much easier. 

Raspbian OS (Bookworm) Kiosk Mode Browser

The key details how to set this up are in this forum post: https://forums.raspberrypi.com/viewtopic.php?t=379321

The summary is:  

  • Enable ssh and login
  • edit this file: 

/etc/xdg/labwc/autostart

  • add something like this line:

/usr/bin/lwrespawn chromium-browser --app=https://<YOUR URL> --kiosk --noerrdialogs ---disable-infobars --no-first-run --ozone-platform=wayland --start-maximized --no-restore-on-startup 

  •  save and reboot

This configures the desktop environment to autostart chromium in kiosk mode and display the configured web page

Online Clock Digital Signage 

With the kiosk mode working, the next step was to find a decent clock web page and call it a day, but this proved to be challenging.  Despite searching pages of results, I wasn't able to find a clock app that met these criteria:

  • minimalist, 
  • ad-free
  • customizable fonts and colors
  • persistent settings

In the end I got so frustrated with the lack of suitable options  that I decided to build and deploy my own.  

Vibe Coding With Claude Console

I didn't want to spend days building a clock app, so I decided to use Claude Console and vibe code it.  In my opinion this is a perfect use case for AI assistant coding - it is a single layer, simple app that is UX centric and has no likelihood of scalability, security or data integrity issues.  I like Claude Console for a couple of reasons

1) It is a pre-pay model.  You pay as you go instead of having to maintain a subscription

2) The agent is bound to the console and leaves your IDE alone.  You can take it or leave it any stage.

After an hour or so of iterating with Claude (and around 5 bucks in tokens) I had a an app that met all of my requirements.  I was even able to add a bit of sci-fi flair by including glow effects and my favourite sci-fi fonts (Orbitron and Michroma) 

Deployment 

I typically use CloudFlare Pages for simple static web hosting, because it gives you a one stop shop for registering a host name and deploying a CI build from GitHub.  This part of the project also went smoothly, and I was able to quickly get the site registered and deployed.

Due partially to my frustration with finding an alternative, and partially to Guinness Draught, the finished product is deployed at this host name:

https://suckmyclock.xyz/

After a little configuration, I am pretty happy with the look on the raspberry pi desktop:


Summary

I am happy with the above outcome. This is the retro-future look that I wanted when I started the project., and it adds nicely to my cleaned-up desk.  

In the end it took me far longer to work out how to host a kiosk mode web page then it did to build and deploy my own custom clock application.  I guess that shows the benefit of AI assistant coding tools, but as mentioned above this is almost the perfect use case for them as there is minimal possibility of hidden technical debt creeping into the solution. 

Using AI agents as smart scaffolding tools seems like a reasonable use for them -especially for simple projects, and in this case I think Claude console did the job much faster then I could have coded something myself.


Moving Blog Platforms

 After struggling for weeks with Google Search Console and Blogger settings, I've come to the conclusion that I need to move to a differ...