Designing a new, more flexible, midi controller
Analogue multiplexer for potentiometers, and MCP I2C IO extender for matrix keyboard.


I bought a teensyrom a while ago.
Tyrone and I wanted to control the settings using potmeters.
So I grabbed a Teensy 4.1 controller and some 10K potmeters, some code using
Test code for two pots, don’t forget to set your USB mode to midi!
Schematic soon, also all tweaks and note sending.
Next to do: 12 pots!
A nice case and extra buttons!
Let’s use an old box to hold the pots!
reconst int numPots = 12; // Custom mappings: const int potPins[numPots] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11}; // Analog pins const int ccNumbers[numPots] = {4, 8, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // CC numbers const int midiChannels[numPots]= {2, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}; // MIDI channels (1–16) int lastValues[numPots]; void setup() { for (int i = 0; i < numPots; i++) { pinMode(potPins[i], INPUT); lastValues[i] = -1; } } void loop() { for (int i = 0; i < 2; i++) { int analogValue = analogRead(potPins[i]); int midiValue = analogValue / 8; // Scale 0–1023 to 0–127 if (abs(midiValue - lastValues[i]) > 1) { usbMIDI.sendControlChange(ccNumbers[i], midiValue, midiChannels[i]); lastValues[i] = midiValue; } } delay(5); }
I was planning to make a RSS reader using this display, but I came across a weather display project I wanted to check out.
(So I probably end up buying another one)
There are many questions and issues around this project using the S3.
So here is my solution.
Install vscode
Goto plugins and install platformio
git clone https://github.com/Xinyuan-LilyGO/LilyGo-EPD-4-7-OWM-Weather-Display.git
Warning this is NOT the branch you want to use
git checkout web
(git pull)
open directory in code
open platformio.ini and change line 13
default_envs = T5_4_7Inc_Plus_V2
(If needed add upload_port = /dev/tty**** at the end)
Change INO file lines 144-146.
Comment serial out, else update won’t work using regular power or battery.
When saving this platformio.ini file, some downloading and installing should be popping up.
When issues occur about libraries see below.
Fill out
data>config.json
and owm_credentials.h to be sure.
(use owm_credentials information to fill config.json)
Next press the platformio icon
Fix for uploading:
Press and hold STR_IO0 button
Press REST button
Release STR_IO0 button
Libraries:
Press platformio icon, libaries and install ArduinoJson, Button2 and LilyGo-EPD47 (select your project while doing so!)
Note: Per default once per hour update, change if you want to.
Line 70 in the INO file
Build/Upload errors? .. Press clean to recompile using a clean state !
Where is it, what device could it be?
Its SSID started with ESP. So I probably am the one responsible for its existence.
I’ve got a sh*tload of ESPs/NodeMCUs/8266 turned on 24-7.
Using a Wifi analizer I could narrow it down to my livingroom.
Checked all devices, and they are all connected to my AccessPoint.
(So no fallback AP mode)
The problem with this method is that you can’t figure out a direction.
So I used this on my Laptop.
This is a directional antenna.
Using Wireshark and wavemon, I could find the direction.
There were only two devices in the direction with the strongest signal.
My photo viewer remote, and my mini turntable controller with RFID.
But these devices are working just fine! .. So lets disconnect the power.
So it IS the mini recordplayer!
Lets look at the code. (part of)
WiFi.mode(WIFI_AP_STA);
I should have used
WiFi.mode(WIFI_STA);
Now it was a client AND an Access Point!
Mystery solved!
My previous build of the clock module is as Ben designed. Wellll . Not really, I added some components to change the clock range.
Okay, Ben’s design is awesome. Not because of its technical design. No, you will learn to use the NE555 chip in three ways!
Variable freq, debounce with delay and a flip-flop like switch
I added another function to it. While making my version.
I added a 555 power-on reset pulse part.
I used a perm board (which is shorter than a regular breadboard)
And I moved some components over and added some LEDs/pin headers.
While doing so, I only used 3/4 of the board.
So I added a power-on reset part with a manual push-button. (Partly like the C64 power-on)
I also added the 1Mhz crystal.
Rest of the boards will use JST connectors for the bus-connections.
I am working on big motor controllers and 3D print modelling for clients.
Working for clients, so fragmented personal stuff.
New workplace setup so even more space!
My BBQ monitor V3
As posted before, but now an esphome version, with big-ass buzzer
Code available soon, when made generic.
4Button controller using ESPHOME
STL FILE https://media.henriaanstoot.nl/4buttons.stl
Flash trick for XYUSB
Flashing this to ESPHOME, use sowing pins!
CODE
substitutions: name: usb-relay friendly_name: "USB Relay" default_state: "RESTORE_DEFAULT_OFF" esphome: name: xyusb1 friendly_name: xyusb1 esp8266: board: esp01_1m # Enable logging logger: # Enable Home Assistant API api: encryption: key: "ndm8xxxxxxxxxxxxxxxxxjlvrggJv3a1BkY=" ota: - platform: esphome password: "12cc9xxxxxxxxxxxxxxxxfb6a01e672" wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Xyusb1 Fallback Hotspot" password: "xxxxxxxxxxx" captive_portal: time: - platform: homeassistant # Blue LED status_led: pin: number: GPIO16 # Relay switch: - platform: gpio id: switch_relay pin: GPIO5 # Green LED - platform: gpio pin: GPIO14 id: green_led inverted: true # start on # Switch template to link relay and green LED states # LED is on when relay is off - platform: template id: relay name: "${friendly_name}" lambda: |- if (id(switch_relay).state) { return true; } else { return false; } turn_on_action: - switch.turn_on: id: green_led - switch.turn_on: id: switch_relay turn_off_action: - switch.turn_off: id: green_led - switch.turn_off: id: switch_relay # Button binary_sensor: - platform: gpio id: hardware_button pin: number: GPIO04 mode: INPUT_PULLUP inverted: True on_press: - switch.toggle: relay # WiFi Signal Sensor sensor: - platform: wifi_signal name: "WiFi Status" update_interval: 60s # Restart button button: - platform: restart name: "Restart"
Reflashed my USB Volume button and added a LED-Ring.
Example is green and blue.
Funny text on box
Wireless Temperature/Humidity sensor for ESPHome.
Wemos D1 mini with deep sleep, voltage monitoring using A0 line.
BME280 Temperature/Humidity sensor.
And a 18650 battery with TP4065 battery manager.
Now 3D print a little case.
Made a PCB for a 24 Channel Logic analyzer
See post:
In the past, I’ve played with a standard lidar device.
Now it is time to check out a 360 version.
This one is very small (40mm x 40mm x 35mm)
Provided examples didn’t work. (People with same error on the Github issues tracker page had the same)
I changed the python script so it worked also with this YDLidar T-mini Plus version.
Next to-do, put this on my robot car.
Code:
import os import ydlidar import time import sys from matplotlib.patches import Arc import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np RMAX = 32.0 fig = plt.figure() lidar_polar = plt.subplot(polar=True) lidar_polar.autoscale_view(True,True,True) lidar_polar.set_rmax(RMAX) lidar_polar.grid(True) ports = ydlidar.lidarPortList(); port = "/dev/ttyUSB0"; for key, value in ports.items(): port = value; laser = ydlidar.CYdLidar(); laser.setlidaropt(ydlidar.LidarPropSerialPort, port); laser.setlidaropt(ydlidar.LidarPropSerialBaudrate, 230400); laser.setlidaropt(ydlidar.LidarPropLidarType, ydlidar.TYPE_TRIANGLE); laser.setlidaropt(ydlidar.LidarPropDeviceType, ydlidar.YDLIDAR_TYPE_SERIAL); laser.setlidaropt(ydlidar.LidarPropScanFrequency, 10.0); laser.setlidaropt(ydlidar.LidarPropSampleRate, 4); laser.setlidaropt(ydlidar.LidarPropSingleChannel, False); laser.setlidaropt(ydlidar.LidarPropMaxAngle, 180.0); laser.setlidaropt(ydlidar.LidarPropMinAngle, -180.0); laser.setlidaropt(ydlidar.LidarPropMaxRange, 16.0); laser.setlidaropt(ydlidar.LidarPropMinRange, 0.02); laser.setlidaropt(ydlidar.LidarPropIntenstiy, True); scan = ydlidar.LaserScan() def animate(num): r = laser.doProcessSimple(scan); if r: angle = [] ran = [] intensity = [] for point in scan.points: angle.append(point.angle); ran.append(point.range); intensity.append(point.intensity); lidar_polar.clear() lidar_polar.scatter(angle, ran, c=intensity, cmap='hsv', alpha=0.95, marker=".") ret = laser.initialize(); if ret: ret = laser.turnOn(); if ret: ani = animation.FuncAnimation(fig, animate, interval=50) plt.show() laser.turnOff(); laser.disconnecting(); plt.close();
3D printed a little light case for a wemos and a piece of WS2812 led strip I had lying around.
Schematic:
NOTE: The resistor is 100-500 ohm (I forgot, just try)
You can only use this trick for a few leds (I used 4), else you better can use the sacrifice a led to make a level shifter trick.
(Wemos logic is 3.3V and the led strip is 5V)
I flashed ESPHome on the wemos using the flasher in Home Assistant.
Code:
esphome: name: matternotification friendly_name: matternotification esp8266: board: d1_mini # Enable logging logger: # Enable Home Assistant API api: encryption: key: "ogFxZUXerNxxxxxxxxxxxxxxxxxWaWyJVxCM=" ota: - platform: esphome password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Matternotification" password: "rxxxxxxxxxxxxxxx" captive_portal: light: - platform: neopixelbus type: GRB variant: WS2812 pin: D4 num_leds: 4 name: "NeoPixelMattermost"
To get the status of messages and controlling the HA entity, I made a bash script.
First curl command to get a token from Mattermost using the API.
Second curl command to get messages states from Mattermost.
Bottom two curl command turn a light entity on or off in your Home Assistant server using a API
#!/bin/bash #set -x # change : mattermost username and password (and server) # change : mattermost userid and teamid # change : home assistant long time token (and HA server) # change : light entity # while true; do # Get token using login #token=$(curl -s -i -X POST -H 'Content-Type: application/json' -d '{"login_id":"username","password":"password"}' https://mattermostinstance.com/api/v4/users/login | grep ^Token | awk '{ print $2 }' | tr -d '\r' ) #using a MM auth token (see below) token=xxxxxxxxxxxxxxxxxxxx # Get messages # Gives you something like # {"team_id":"j3fd7gksxxxxxxxxxxxxxjr","channel_id":"rroxxxxxxxxxxxxxxtueer","msg_count":0,"mention_count":0,"mention_count_root":0,"urgent_mention_count":0,"msg_count_root":0} # We need to count ":0" messages=$(curl -s -i -H "Authorization: Bearer ${token}" https://mattermostinstance.com/api/v4/users/ou5nz5--USER-UUID--rbuw4xy/channels/rropejn--TEAM-ID--tueer/unread | grep channel | grep -o ":0" | wc -l) # If 5 times ":0" then no messages if [ $messages == 5 ] ; then # Turn off curl -s -X POST -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cC--HOME-ASSISTANT-LONG-TIME-TOKEN-CBusTgTUueWpPNdH5WAWOE" \ -H "Content-Type: application/json" \ -d '{"entity_id": "light.matternotification_neopixelmattermost_2"}' \ http://192.168.1.2:8123/api/services/light/turn_off > /dev/null else # Turn on curl -s -X POST -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cC--HOME-ASSISTANT-LONG-TIME-TOKEn--CBusTgTUueWpPNdH5WAWOE" \ -H "Content-Type: application/json" \ -d '{"entity_id": "light.matternotification_neopixelmattermost_2"}' \ https://192.168.1.2:8123/api/services/light/turn_on > /dev/null fi sleep 5 done
Get a Long-lived access token from HA:
Profile > Security and Create Token
Create a token in Mattermost:
While working on a client project, I tested multiple displays.
I thought it was fun to connect the Epaper to ESPHome.
It was not without problems. For example, the ESPHome editor gave squiggly lines under type.
This has to be changed in the libraries.
(Already notified developers)
model: 4.20in-V2 does not work .. use model: 4.20in-v2
esphome: name: epaperqoute friendly_name: epaperqoute esp32: board: esp32dev framework: type: arduino # Enable logging logger: # Enable Home Assistant API api: encryption: key: "tzRSzZky3Jk+hUYtiybzT90kxxxxxxxxxxxxxxxxxxxxx=" ota: - platform: esphome password: "4f127e114a7a44fxxxxxxxxxxxxxxxxxxxxx" wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Epaperqoute Fallback Hotspot" password: "yLSoxxxxxxxxxx" captive_portal: external_components: - source: github://pr#6209 components: [ waveshare_epaper ] text_sensor: - platform: homeassistant entity_id: input_text.epaper_display_text id: epaper_display_text on_value: then: - component.update: epaperdisplay spi: clk_pin: GPIO13 mosi_pin: GPIO14 # Upload own ttf to a directory in esphome/fonts using file editor in Home Assistant font: - file: "fonts/newspaper.ttf" id: tahoma size: 64 http_request: verify_ssl: false # image test online_image: - url: "https://www.henriaanstoot.nl/epapertest.png" id: example_image format: PNG #it.image(0, 0, id(example_image)); display: - platform: waveshare_epaper id: epaperdisplay cs_pin: GPIO15 dc_pin: GPIO27 busy_pin: GPIO25 reset_pin: GPIO26 model: 4.20in-v2 reset_duration: 200ms update_interval: never lambda: | it.printf(0, 0, id(tahoma), "%s", id(epaper_display_text).state.c_str());
Part of a client’s build for powerful DC motors, so no details
Controlling this with an Arduino is straightforward, except for the SV signal.
This controls the speed using a voltage level.
A Uno has analog inputs, no outputs.
The trick is using a digital potmeter.
256 steps potmeter MCP41100
#include <SPI.h> int svpin = 5; setup: pinMode(svpin, OUTPUT); loop: // SPI Digital potmeter digitalPotWrite(0x20);