Using The SSD1306 OLED on a Wemos S2 Pico ESP32-S2 board

Wemos S2 pico board with ESP32-S2

Just received the Wemos S2 pico board from AliExpress, and thought I'd write a simple tutorial on how to use it with Arduino, as Wemos' Getting started guide was a bit outdated on Arduino config and did not have an OLED example.

Quick Background

I've been planning to make a DIY hardware Bitcoin wallet just for fun. To make it even remotely secure — once you assume attackers have your internet connected devices pwned it pretty much varying degrees of tinfoil — it's essential that you have an external display and a button to print out your secret key or which address you're signing your coins to go.

My ESP8266 supply was running low (have been using ), and not sure if it has enough memory, I looked what Wemos might have nowadays, since I've used their nice D1 Mini in several projects, such as the ATX power control. I was very happy to discover they had this Wemos S2 Pico available at a reasonable 8 € price point from LoLin AliExpress store , having an SSD-1306 compatible OLED display and even a button. Perfect!

Note: there are clones for Wemos products for cheaper, but I like to show my support even if it costs a dollar or two more!

Setting up Arduino for ESP32-S2 Support

Following Wemos' Getting Started tutorial, I realized the Boards list did not include any ESP32-S2 modules. I checked that I had the "latest" 1.0.6 version installed. After some googling lead me to this Adafruit page, I realised that I needed 2.0.x version that is served from a different location (latest ESP32 branch now lives in Github).

After following the installation instructions — essentially replacing the old Espressif "Additional Boards Manager URL" in Arduino Preferences with the new one — I updated the ESP32 package to 2.0.1 and voilà: There is now the "ESP32S2 Dev Module" available in the ESP32 Boards section. Since Wemos' instructions, the USB CDC setting had changed a bit, this is how I set it up (changes made highlighted):

Arduino Board Configuration for Wemos S2 Pico ESP32-S2

Note that the S2 Pico requires you to hold Button 0 down, press Reset button and release the Button 0 to enter flashing mode. This will change the COM port! Thankfully, it seems to stay in that mode so you should not be in a rush to flash.

Using The OLED on Wemos S2 Pico

Read post

Combine Go (golang) and SvelteKit for GUI

This post outlines the basics of creating a project that combines Go (or "golang" as googling for "go" is a pain — why didn't the guys at Google think of this?) native backend serving a web UI / GUI running on SvelteKit.

In a nutshell, this involves creating a new go project, creating a simple web server program that supports serving files from a static folder, and finally creating a SvelteKit project and configuring it to produce static content into that folder. But let's do a short detour on why this might be useful!

Combining native executable with Web UI

Native graphical user interfaces are not easy on any platform, and after looking at Qt, WxWidgets, Electron etc. I decided all had either major shortcomings, huge learning curves or resulted in way too large packages.

Doing a native web server, on the other hand, is quite easy using Go. I also investigated C and C++, but at least on Windows you very quickly run into MinGW vs. Visual Studio issues, runtimes, build systems and all that chaos, whereas Go pretty much produces executables with minimum fuss.

Once you have a web server, you can just serve a web UI and the user can run the executable and open the UI in their browser.

Simple web server with Go

Once you are comfortable creating a "Hello world" level app in Go, making a simple app for web server is not too hard:

$ mkdir project
$ cd project
project$ go mod init example/project

Here's a simple web server you can paste into main.go

package main

import (
    "encoding/json"
    "log"
    "mime"
    "net/http"
)

func databases(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*") // for CORS
    w.WriteHeader(http.StatusOK)
    test := []string{}
    test = append(test, "Hello")
    test = append(test, "World")
    json.NewEncoder(w).Encode(test)
}

func main() {
    // Windows may be missing this
    mime.AddExtensionType(".js", "application/javascript")

    http.Handle("/test", http.HandlerFunc(databases))
    http.Handle("/", http.FileServer(http.Dir("static")))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Read post

Fixing MIME type errors when using Golang net/http FileServer

Today as I was finishing my Go+SvelteKit article, I ran into frustrating Chrome error message:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.

Don't you just love Chrome? It knows what it needs to do (load a JavaScript module), but utterly refuses to do that because of a wrong MIME type. This happened with a client-side SvelteKit application, when it tried to open some part of the .js code.

At the time of writing, it seemed I could not find the answer easily to this one, but there actually seems to be a StackOverflow solution discussing this. But to help others hitting the same issue:

The problem on my Windows install was likely that Windows 10 registry did not contain a MIME type definition for .js files. Informing user how to tweak registry to get your program working is not ideal, but thankfully you can augment the mime types:

import "mime"

func main() {
	// Windows may be missing this
	mime.AddExtensionType(".js", "application/javascript")

    // And then you create the FileServer like you normally would
	http.Handle("/", http.FileServer(http.Dir("static")))
}

After adding the mime fix, remember to force reload Chrome page (hold Control key down while you press refresh), otherwise the problem persists as Chrome does not really bother reloading the offending files.

Read post

$6 DIY bluetooth sheet music page turn pedal with ESP32

I've had an iPad Pro 12.9" for some time, and been happily using it for sheet music when playing the piano. However, having to interrupt your playing to swipe to the next page does get annoying. You can get a $100 commercial AirTurn pedal, but since one can get a microcontroller from Ebay/Aliexpress for $4 and a simple foot pedal switch for $2, I thought it would be a fun one evening hacking project. It turned out quite nice:

Getting started: ESP32 devkit

The sheet music applications on iPad (and Android) usually have bluetooth keyboard support, turning the page when user presses an arrow key or spacebar. So the minimum viable product is just a bluetooth-enabled microcontroller that can pair with the iPad and send a single key upon request.

The ESP32 chip has both WiFi and Bluetooth, and I chose it for this project, as it is readily available in a compact form factor, and it's easy to program with Arduino. Searching [AliExpress](https://www.aliexpress.com for ESP32 should give you plenty of options.

I had a ESP32 board labelled with "ESP32 DEVKITV1" in my parts box, and it was quite easy to set up with this ESP32 tutorial:

  1. Install the driver for USB-UART bridge
  2. Add source URLs for ESP32 to Arduino and install ESP32 support
  3. Select "DOIT ESP32 DEVKIT" from the board menu
  4. Hold down "Boot" button on the board while selecting "Upload", release when the console says "Connecting..."

Before you proceed with the tutorial, check that you can get the lights blinking or flash some other example code successfully for the board. There are plenty of resources around if you hit into any issues! I had to google the step 4 myself, although it would have sufficed to read the linked tutorial carefully...

Read post

Automatic Eleventy (11ty) Site Updates with Github Hooks

A while ago I updated my site to Eleventy.js. This improved my blogging process considerably, as Markdown is quick to write, and especially code samples are easy to copy-paste without any escaping.

I put all my posts into one Github repository. Using Visual Studio Code, I get nice realtime preview, and once I'm done, I just git commit, git push on my computer, and git pull on the server, and regenerate the site with Eleventy.

Now only issue is that one usually finds 5-10 things to change after every post, and while VS Code has great git support built in, even the simple update process gets a bit tedious with commands being run on SSH side. So I started wondering if I could use the Github webhooks to automate the regeneration. Turns out: YES.

Simple Script to Pull Markdown from Github and Regenerate

First component is of course a small shell script to automate the git pull and regeneration. One could do a more elaborate one, but this worked for me server-side:

#!/bin/sh

cd ~/myblog_post # here are the .md files
git pull
cd ~/myblog_eleventy # here's the 11ty site generator
npx @11ty/eleventy --input=. --output=../apps/myblog_static # hosting dir

Node.js Mini-Server for Github Webhooks

Next, I needed to set up a web server that would get the HTTP POST from Github whenever I push changes. Here your configuration will depend on hosting you have, but Opalstack for example has simple installation of a Node.js application. I usually disable the automatic restarting (crontab -e etc.), use ./stop script and run my server manually for a while to see everything works, before restoring the crontab.

If you choose to forego Github webhook security mechanisms, the code is really simple, but in that case, anyone knowing the addess of your server can flood you with fake push requests. So let's take the high road and use this gist to verify Github hooks! I chose to use Polka so I needed to modify the headers part of the code just a bit:

const { exec } = require("child_process");
const polka = require('polka');
const { json } = require('body-parser');
const crypto = require('crypto')

const port = 12345;
const secret = 'ohreally :)';
const sigHeaderName = 'x-hub-signature-256';
const sigHashAlg = 'sha256';

// Middleware to verify Github "signed" POST request
function verifyPostData(req, res, next) {
  console.log('Verifying signature', req.headers[sigHeaderName]);

  if (!req.rawBody) {
    console.log('Request body empty');
    return next('Request body empty');
  }
  
  const sig = Buffer.from(req.headers[sigHeaderName] || '', 'utf8');
  const hmac = crypto.createHmac(sigHashAlg, secret);
  const digest = Buffer.from(sigHashAlg + '=' +
    hmac.update(req.rawBody).digest('hex'), 'utf8');

  if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) {
    console.log('Got request with invalid body digest');
    return next(`Request body digest (${digest}) did not match
      ${sigHeaderName} (${sig})`);
  }
  
  console.log('Verification done.');
  return next()
}

polka()
  .use(json({ verify: (req, res, buf, encoding) => {
    // Store raw body data in req rawBody variable
    if(buf && buf.length) req.rawBody = buf.toString(encoding || 'utf8');
  }
  }))
  .get('/', (req, res) => { res.end('Hello, polka!'); }) // just for testing
  .post('/myblog', verifyPostData, (req, res) => {
    console.log('Article repo updated, generating site...');
    exec('~/blog_eleventy/gen.sh', (error, stdout, stderr) => {
      if(error) console.log(`error: ${error.message}`);
      if(stderr) console.log(`stderr: ${stderr}`);
      console.log(`stdout: ${stdout}`);
    });
    res.end(`Hello, Github!`);
  })
  .listen(port, () => {
    console.log(`> Running on localhost:${port}`);
  });

Read post

Project Euler Problem 2 and 3 with Clojure, Python, Javascript and C++

Continuing from my Project Euler Problem 1, here are the next two Euler problems and some reflection!

Project Euler Problem 2

The second problem asks to find the sum of even Fibonacci numbers numbers below four million. For procedural languages, this is quite walk in the park, but for me a concise method to produce the series in Clojure proved a bit of a brain nugget!

Python 3

For Python, I decided to make a simple generator that yields the Fibonacci numbers below a given treshold N. Rest is just list comprehension:

def fib(N):
    i, j = 0, 1
    while j < N:
        yield(j)
        i, j = j, i+j

print(sum(i for i in fib(4e6) if i%2==0))

C++

In C++ it's natural to just loop with a conditional addition. This time I decided to drop using namespace std; to save a few characters. Without i, j = j, i+j syntax, the temporary variable ij is a bit ugly.

#include <iostream>

int main() {
    int i=0, j=1, s=0;

    while(j<4000000) {
        if(j%2==0) s += j;
        int ij = i + j; i = j; j = ij;
    }
    std::cout << s << std::endl;
}
}

Javascript

Here I could go either way, towards the Python list comprehension or C++ loop. Since generators are part of JS, I chose to try them out!

function *fib(N) {
    let i=0, j=1;
    while(j < N) {
        yield j;
        [i, j] = [j, i+j];
    }
}

console.log([...fib(4e6)].reduce((a,b) => a + b*(1-b%2), 0));

I combined the sum and conditional using reduce. Note that b*(1-b%2) evaluates to zero for off values of b!

Clojure

In Clojure, I wanted really to avoid just looping with while to get a feel of the different ways to generate the Fibonacci numbers. There are many ways to do it, including recursion (which gets really slow unoptimized) and lazy-cat solution that really eluded comprehension, until I realized that with lazy sequences, you can do (map + s (rest s)) and items are pulled from the linked list just in time to construct the next item.

Read post