HSV CircuitPython Code Using the FancyLED Library

This piece of CircuitPython code utilizes the Adafruit Character LCD, FancyLED and NeoPixel libraries, so make sure that they are loaded into your library folder on your board.

You don't have to remain confined to RGB values though. The FancyLED library in CircuitPython allows you to use HSV, or hue, saturation and value, to affect the NeoPixel strip's color.

The code is very similar to the NeoPixel library RGB code that we just looked at. The goals are still the same: have the pots control the three values that affect the NeoPixel strip's color (in this case HSV) and have these values display on the LCD in real time.

import time

import adafruit_character_lcd
import adafruit_fancyled.adafruit_fancyled as fancy
import board
import digitalio
import neopixel
from analogio import AnalogIn

lcd_rs = digitalio.DigitalInOut(board.D5)
lcd_en = digitalio.DigitalInOut(board.D6)
lcd_d7 = digitalio.DigitalInOut(board.D12)
lcd_d6 = digitalio.DigitalInOut(board.D11)
lcd_d5 = digitalio.DigitalInOut(board.D10)
lcd_d4 = digitalio.DigitalInOut(board.D9)
lcd_columns = 16
lcd_rows = 2

lcd = adafruit_character_lcd.Character_LCD(
    lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows
)

potH = AnalogIn(board.A0)  # pot for hue
potS = AnalogIn(board.A1)  # pot for saturation
potV = AnalogIn(board.A2)  # pot for value
pixpin = board.D13  # NeoPixel pin
numpix = 8

strip = neopixel.NeoPixel(pixpin, numpix, brightness=1.0)


def val(pin):
    # divides voltage (65535) to get a value between 0 and 1
    return pin.value / 65535


def round_pot_h():
    # rounds decimal value to 2 decimal places
    return round(val(potH), 2)


def round_pot_s():
    return round(val(potS), 2)


def round_pot_v():
    return round(val(potV), 2)


while True:
    # calls for HSV values
    color = fancy.CHSV(val(potH), val(potS), val(potV))
    # converts float HSV values to integer RGB values
    packed = color.pack()
    # writes converted int values to NeoPixels
    strip.fill(packed)

    lcd.set_cursor(3, 0)
    # text at the top of the screen
    lcd.message('H + S + V =')
    lcd.set_cursor(1, 1)
    # sends the rounded value and converts it to a string
    lcd.message(str(round_pot_h()))
    lcd.set_cursor(6, 1)
    lcd.message(str(round_pot_s()))
    lcd.set_cursor(11, 1)
    lcd.message(str(round_pot_v()))
    time.sleep(0.5)
    # refreshes screen to display most recent pot values
    lcd.clear()

The first change is the division of the analog voltage value by itself (pin.value / 65535) so that the minimum value read is 0 and the maximum is 1, since that is the range of HSV values.

Next, are the functions round_pot_h, round_pot_s and round_pot_v. These functions return a rounded number for the HSV values. Since HSV uses a decimal range between 0 and 1, the numbers can be very long in length, which won't fit on the LCD screen. Here, the numbers are being rounded to 2 decimal places so that all three HSV values can fit comfortably on the screen. However, you can easily change the number of decimal places to suit your needs.

In the loop, the HSV values are assigned to color, which is then converted from float HSV values to integer RGB values using pack() from the FancyLED library. These integer values are then written to the NeoPixel strip using strip.fill(packed) from the NeoPixel library.

For the LCD portion, the only big change from the NeoPixel RGB value code is that functions are being used and called to round the HSV values. This was done to avoid memory allocation issues.

Also, you'll notice that the values are not being converted to integers for the LCD. This is because although we need integers to write the colors to the NeoPixel strip, we want to see the float HSV values on the screen. Just like the RGB value code, the rounded HSV values are sent to the LCD as strings with str.

Some examples of HSV values being dialed in.

Last updated on Mar 01, 2018 Published on Mar 02, 2018