I hate the internet. I hate it not only because it shows us the decay of society in real-time, but also because I do not really understand it. And who can blame me? Technologically it is one giant bowl of spaghetti, and as an idiosyncratic wannabe iconoclast it is even more difficult for me to comprehend on a social level. So naturally when COVID19 hit Europe like a tonne of bricks and the internet immediately imploded I channeled this hatred hard. Now hold your horses, I am not dishing out this pseudo philosophical claptrap in a failed attempt to be topical. This has a point. Just let me get to it…
A friends birthday was coming up, and I came up with a concept for a gift that attempts to satirise not only the way people use the internet to dish out their unqualified opinion, but also the shallow way in which people deliver that opinion.
The concept was to have a device create a WiFi access point called “CORONA VIRUS CURE INFORMATION”, and once a user connects to the access point a captive portal would automatically serve a web page that only displays a GIF telling the user to “go home”. Something a little like this, featuring yours truly.
Obviously this kind of concept could be refined to be a little more usable to the general population who are not as bitter as myself. Maybe a “CAT OF THE DAY” web portal that displays pictures of the household cats? Yes. That sounds much more palatable. Or how about including a configuration page where the user could name the access point whatever they like, and an upload page so custom images could be displayed by the captive portal? I can see it now, looking for my local public WiFi Hotspot and being inundated with “5G KILLS BABIES”, “BILL GATES KILLS BABIES”, and “LOCKDOWN KILLS BABIES”. Yes. This is it. This is what I wanted.
And so the concept for the ESPCaptiveImagePortal was born.
After some musing I came up with the following requirements for ESPCaptiveImagePortal:
- Implement an WiFi access point with a web server.
- Implement a captive portal that redirects most traffic to a web page that displays a simple image. This page should be able to display different images each time it is loaded if more than one image is available. It should also be able to display a wide range of image formats, including animated images.
- Implement a configuration page allowing the user to upload images, delete images, and change the access point SSID. This page should have a hard coded username and password for basic authentication.
- Implement using the ESP8266.
The ESPCaptiveImagePortal Project
The ESPCaptiveImagePortal project can be found on GitHub here. In addition to the ESP8266 arduino core it requires a few Arduino libraries to compile. This includes ESPAsyncTCP, ESPAsyncWebServer, DNSServer, ESPStringTemplate, and ESPFlash. Most of these libraries will be able to be installed using the Arduino IDE through Library Manager, but if you are having trouble, they can also be installed by downloading the code off github directly and installing them manually.
A Working Example
Here is an example of how the ESPCaptiveImagePortal works using the CAT OF THE DAY example I mentioned a little earlier.
Obviously we don’t want just anyone who has access to the access point to be able to upload images, so ESPCaptiveImagePortal relies on three forms of security:
- The connected user knows the ESP8266 IP address.
- The connected user knows the configuration page URI (/supersecretpage by default)
- The connected user knows the hardcoded username and password.
It’s important to note the username and password is implemented using basic HTTP authentication which is incredibly weak, and allows anyone sniffing the network to grab the credentials in plain text. Obviously from a security point of view this is not ideal, but I considered it sufficient for such a project.
To access the configuration page, you have to know the IP address of the ESP8266, which is hardcoded to 192.168.4.1 by default. The URI for the configuration page is also hardcoded to “/supersecretpage” by default. So if those defaults are used, it can be accessed by using any browser with “192.168.4.1/supersecretpage” in the address bar.
The authentication that allows access ends up looking a bit like this. Default values are hardcoded in the project that can be changed very easily.
The below image shows the configuration page. It displays the total number of WiFi connections that have been made to the device as well as the following configuration options:
- Ability to delete uploaded images
- Ability to upload new images
- Ability to change WiFi SSID
The below animation shows a sped up example from start to finish of the ESPCaptiveImagePortal configuration, including getting to the configuration page, uploading an image, changing the SSID, and observing the result all through a browser on a smartphone.
A Note On Image Upload Size and Speed
One last final note is that image upload speed is slow due to the use of internal flash memory (SPIFFS) on the ESP8266. The available space on the filesystem in which images are stored is also very constrained, although this will differ depending on the ESP8266 module that is used. It is highly recommended that the image size does not exceed 500Kb in size. If the image is a non-animated image, an image size of ~100Kb is recommended, which results in a negligible upload and download time while still rendering useful results.
It’s hoped that someone will get a kick out of this project. I had a lot of fun developing it, and learnt a lot about the ESP8266 on the way. I will follow up this post with a technical post that will discuss how I achieved all of the specified features, some thoughts on the ESP8266, and what I would do differently in the future, so watch this space!
Hi, cool project! got it up and running!
However i am only gettings the filename and extension on the captive portal.
So i get a black screen with in the top left corner /images/image.jpg
Should i upload it in a specific format?
The image i am using is 400×300 pixels and 90kb.
Many thnx in advance!
I haven’t maintained this project for a while now, so it is possibly changes in some of the dependencies may have caused this issue. If you manage to find a fix, please share it via GitHub!