DEV Community


How to control addressable RGB lights with a ESP8266. Part 2.5 of 3. Rotary knob addendum.

technicholy profile image Clayton Pierce ・3 min read

Please see my previous part 1, part 2 here to catch up.

Before I set up the web server, I want local control of the LEDs, so I'm setting up a rotary knob to control the lights in addition to the web server. I'm using this library to control the rotary knob.

Any time you need to add a module to your ESP8266, you need to load it via compiling new firmware using the vagrant machine for part 1 and adding the new file to the /ports/esp8266/modules/ subdirectory before compiling new firmware. The file I show below is far too large to copy paste in one shot to the REPL. The best thing is to copy the file into the modules directory and burn new firmware. This seems tedious, but the files run much faster and I don't think micropython gets a file system on esp8266 to copy files onto. I have ordered some RP2040 boards, but those will take some time to arrive.

The rotary knob uses two pins which are out of phase with one another to determine which direction the know is going. Since this is handled by the library, we just need to detect the change and apply it to the string of lights. Later, the knob will be able to be moved to its own controller and the lights will work from the remote knob.

from machine import Pin, I2C, unique_id, reset, Timer
from micropython import const
import gc
import math
from ssd1306 import SSD1306_I2C
from neopixel import NeoPixel
from network import WLAN, STA_IF
from rotary_irq_esp import RotaryIRQ

rotary = RotaryIRQ(pin_num_clk=12, 
station = WLAN(STA_IF)
ssid = 'your ssid'
psk = 'your password'
light_len = const(144)
pixel = NeoPixel(Pin(2), light_len)

def rotary_knob(val=0):
  if val == 0:
  elif val == 1:
  elif val == 2:
  elif val == 3:
  elif val == 4:
  elif val == 5:
  elif val == 6:
  elif val == 7:

def white_low():
  for i in range(light_len):
    pixel[i] = (10, 10, 10)
def white_med():
  for i in range(light_len):
    pixel[i] = (100, 100, 100)
def white_high():
  for i in range(light_len):
    pixel[i] = (200, 200, 200)
def all_off():
  for i in range(light_len):
    pixel[i] = (0, 0, 0)
def red_low():
  for i in range(light_len):
    pixel[i] = (10, 0, 0)
def red_med():
  for i in range(light_len):
    pixel[i] = (100, 0, 0)
def red_high():
  for i in range(light_len):
    pixel[i] = (200, 0, 0)
def hsv2rgb(h, s, v):
    h = float(h)
    s = float(s)
    v = float(v)
    h60 = h / 60.0
    h60f = math.floor(h60)
    hi = int(h60f) % 6
    f = h60 - h60f
    p = v * (1 - s)
    q = v * (1 - f * s)
    t = v * (1 - (1 - f) * s)
    r, g, b = 0, 0, 0
    if hi == 0: r, g, b = v, t, p
    elif hi == 1: r, g, b = q, v, p
    elif hi == 2: r, g, b = p, v, t
    elif hi == 3: r, g, b = p, q, v
    elif hi == 4: r, g, b = t, p, v
    elif hi == 5: r, g, b = v, p, q
    r, g, b = int(r * 255), int(g * 255), int(b * 255)
    return r, g, b

if not station.isconnected():
  station.connect(ssid, psk)
  while not station.isconnected():
def rainbow_map(v=.1):
  map = {}
  for i in range(360):
    map[i] = hsv2rgb(i, 1, v)
  return map

def rainbow_one():
  color = rainbow_map()
  for i in range(360):
    for j in range(144):
      pixel[j] = color[i]

val_old = rotary.value()
while True:
  val_new = rotary.value()
  if not val_old == val_new:
    val_old = val_new

Enter fullscreen mode Exit fullscreen mode

For the "high" setting, I use a value of 200. The maximum the LED can go is 255, but I found that just results in excessive current draw for not very much light. 80% of the maximum is 204, so 200 was a good spot for the max value.

The final part of this blog will cover setting up some basic routes and controlling these same functions from a web page. I will be using a web server library for ESP8266.

Discussion (0)

Editor guide