I made this to allow me to connect my WearWare LED screen t-shirt (Made with rpi-rgb-led-matrix) to my Android phone’s mobile hotspot, and launch it’s web UI simply by clicking a shortcut / widget on my home screen.
Posting it here, in case anyone else finds it useful.
This is very much a WIP. This is 100% vibe coded - I did not write a single line of the Kotlin code, I don’t even know Kotlin.
So to be clear, it is your android phone that acts as the hotspot and your Pi connects to it?
If so, doesn’t your Pi get a half random IP that you have to find and type in your web browser?
My (old) solution uses an ESP32 as AP and it does the web interface too (my phone connects to the ESP32 and the ESP32 sends commands to the Pi).
I have the details down the page here (scroll to bottom):
This was written before I started using a Pi to run the screens, hence the dual CPU solution today which is not entirely needed.
I did code my interface in C++ but it’s super basic (html3, no fancy UI callbacks) and I used GitHub - distrakt/OmEspHelpers: An Arduino ESP32/ESP8266 library for extremely rapid IoT web page UI creation · GitHub which basically builds the webUI from the code, so I don’t have any html page separate from the code.
Your solution is probably much nicer given that mine dates to 2019 now ![]()
Yes, it does, that’s why I need an app like this. It doesn’t matter if the Pi has a hostname (eg wearware.local ) - Android cannot resolve .local names for devices connected to it’s hotspot.
The pi is connecting the the phone’s hotspot. I used to do it the other way around, which was conventient because I could just point the browser on my phone to http://wearware.local:5000 and it would reliably connect (Because the Pi was handling the DNS resolution), but that meant that my phone lost all internet connection while connected to the pi (Was trying to route data via the pi).
Here’s how it works:
I created /etc/avahi/services/wearware-dns-sd.service with the following contents:
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>WearWare UI</name>
<service>
<type>_http._tcp</type>
<port>5000</port>
</service>
</service-group>
This creates a DNS-SD (DNS Service Discovery) entry for the Pi
Now, if any device on the subnet sends an mDNS request (These are sent to the broadcast address of the subnet, so all devices will see it), the pi will respond saying "I have an HTTP service available on port 5000, it’s called WearWare UI.
So this app I wrote will send out that mDNS broadcast, and then display a list of everything that responds.
You then pick something from a list, and it makes a shortcut or widget that stores the name (in my case WearWare UI).
When you tap the shortcut, it sends the mDNS request again to get the current IP, and launches a browser to that IP and port.
In this way, even if the IP changes between the time you create the shortcut and the time you tap the icon on your home screen, it still works.
So as long as your ESP32 can be configured to respond to DNS-SD packets, then you could use the same method.
Haha, that’s pretty cool. Lots of tech to get around the fact that android sadly doesn’t support setting static DHCP leases.
Added new features:
- Now supports all protocols. 7 built in, but you can add your own
eg you can use it to launch an SSH client as well - Added support for
sl-usernameTXT parameter
eg add<txt-record>sl-username=root</txt-record>to your service definition on the pi to set the username to log in as - Added custom app icon
- Added “Appify” mode for http / https shortcuts
In appify mode it does not launch it in the default browser, but in a “webview” (Which is still your default browser, just embedded in an “app”).
This has the following benefits:- Gives the web page it’s own entry in the task list, separate from your browser.
- In non-app mode, if your shortcut points to
/, and you currently have a browser open to/somepage, then clicking the shortcut would open another browser tab
In appified mode, it just re-opens the existing appified instance, and does not change which page it is on