But there were a few things about the bluetooth connection that didn’t work great:It was fast enough to send back JSON data, but noticeably slow for loading frontend data (e.
Eventually, when we began streaming volume data to the phone via websockets, this was also noticeably slow.
Connecting to bluetooth was sometimes troublesome— the Pi would have to go into pairing mode and then the phone would have to search for it.
If the connection was lost, we would need to put another interface on the Pi to make it go into pairing mode (such as a button) that connected physically to the Pi.
We decided to move away from bluetooth and to instead use a WiFi access point.
WiFi access points are frequently used in Pis if you want to set up a guest WiFi network in your house.
We followed some documentation on the Raspberry Pi site to make the onboard WiFi chip of the Pi into an access point.
This did mean that our Pi no longer had an outgoing WiFi connection.
But this was easily solved by buying a USB WiFi dongle which would act as its outgoing connection.
Phone to Pi communication via WiFi access pointIn this architecture, the Pi is serving up our website and broadcasts a WiFi connection called hearthnet which is visible on any device as a WiFi option.
List of WiFi options from a PC when multiple hearths are onlineThe WiFI access point gave us a few advantages over bluetooth:Easy and intuitive to connect toPassword protected WiFi connectionAbility to forward the Pi’s WiFi connection to the phoneThis last ability in particular also gave us another great unexpected benefit— the ability to connect the Pi to WiFi connections that typically need a splash screen to get through.
Because our hearths are deployed to public libraries, we worried that many of these might have splash screens that need to be agreed to first in order to access the internet.
There are a lot of articles online about how to get through these on a Raspberry Pi, but all of the ones we found required opening a browser on the Pi and figuring out how to click the ‘accept’ button.
With this method, instead, the splash screen is forwarded to the phone which can then accept on behalf of the Pi ????Building the AppIn the end, we had the following running on the Raspberry Pi:Flask backend running via gunicorn that starts up on boot through systemdReact frontend hosted by nginx which is sent to the phone when it connects to the PiVarious Python cron jobs for uploading and downloading audio, for updating its status to our servers, and for downloading and running updates on itselfThis architecture lent itself well not just for phone and Pi communication, but also because it is just a web app, it was easy for developers to develop on their own machines and most things would work just fine once on the Pi.
There were a few things, though, that could only be tested on the Pi/phone setup, such as:Setting GPIO pins (to control LEDs, for example)Setting WiFi (though some of this may have worked if the development machine were a Linux machine)Some details on how the front end looked on an actual phoneBackendWe developed a Flask app with REST endpoints such as:Record (start, stop, pause)Play (start, stop)Set WiFi (to connect the Pi to WiFi)Setting volumeWe also had some websocket connections:Streaming the current volumeState (recording state, playback state, name of host, etc.
)Unlike many web applications, our backend had to keep its state since it was writing out audio files.
Because of this, we could not ask gunicorn to spin up multiple instances or else the stored state would be wrong across different threads.
For the most part, this was not a problem though, since there would only be one client connected to each backend.
Even if multiple phones connected at once, they would show the same screen since we set our state through websockets.
FrontendWe originally started in Preact, a smaller alternative to React, but once we moved away from bluetooth, we were no longer constrained by bundle size so switched back to React.
The frontend gets all of its state from the backend via websockets.
It can set the backend to go into different states, such as recording, playing an audio file, or setting the Pi’s WiFi.
In this screenshot, the volume data, as well as the time elapsed, is being streamed from the Pi over to the phone via websockets so that the host is confident that their conversation is being recorded.
We also set the endpoint that starts recording to have the Pi change the color of the LED ring to orange (instead of its default green).
From this screen, a host can also play ‘highlights’ from other conversations in order to bring other voices into a conversation.
We did hit a rather large inconvenience when we wanted to be able to grab the phone’s geolocation in order to know about where a conversation took place.
While this can be done pretty easily in most browsers, recent updates to modern browsers do not allow grabbing geolocation over an insecure network.
Our Pi to phone connection is not over HTTPS and so our app was not allowed to access geolocation data.
Instead of rolling out certs to all of our Pis and maintaining them, we chose to build a native app that was just a webview with Cordova.
This allows us to access data such as geolocation.
Since it is just a webview, we don’t really have to worry about app store updates— we can just roll out a new build of our frontend to the Pi and the phone will grab this new version the next time it connects.
The phone app being a webview also avoids the case where we update the backend on the Pi but the phone app has not been updated yet, resulting in possibly incompatible interactions between frontend and backend.
Instead, the two are always in sync ????ConclusionControlling a Raspberry Pi through a phone via a web application proved to work out pretty well.
The user interface of a phone is familiar to most of our hosts and made development similar to what we were already used to doing.
Furthermore, the possibilities for what the phone can control are anything a Raspberry Pi can do, from recording and playing audio to controlling lights and motors.
That said, there is a bit of configuration to get the networking right between the WiFi access point and a WiFi dongle, as well as setting up the backend and frontend.
So we made a repo with an Ansible script that set up a basic app with this architecture for you!.Enjoy, and we hope with all of our hearths that this might help you make something awesome!.