Adding rotary extender to Trinket Mo for pixel goggles

Need help coding the trinket mo using arduino to add the rotary extender.
the goggles currently work perfect but son wants to add the rotary extender to cycle different functions and dimming. Any chance someone can help me with the coding for it? thanks in advance.
Heres the current code also

#include <Adafruit_NeoPixel.h>

#define PIN 0   // whichever you use for your OUTPUT (DATA)
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(32, PIN);
// Adafruit_NeoPixel pixels( 32, PIN, NEO_GRB + NEO_KHZ800);  // alternative

byte pixPos;

void setup()
{
  pixels.begin();
}

void loop()
{
  // turning them all RED
  for(pixPos = 0; pixPos < 32; pixPos++)  // run through pixel positions
  {
    pixels.setPixelColor(pixPos, pixels.Color(200, 0, 0)); // RED
  }
  pixels.show();
pixels.begin();
  pixels.setBrightness(50);  // 0 = off, 255 = full brightness

}

Heres the python code i tried to use in arduino

# SPDX-FileCopyrightText: 2019 Phillip Burgess for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# pylint: disable=import-error

"""
NeoPixel goggles code for CircuitPython

With a rotary encoder attached (pins are declred in the "Initialize
hardware" section of the code), you can select animation modes and
configurable attributes (color, brightness, etc.). TAP the encoder
button to switch between modes/settings, HOLD the encoder button to
toggle between PLAY and CONFIGURE states.

With no rotary encoder attached, you can select an animation mode
and configure attributes in the "Configurable defaults" section
(including an option to auto-cycle through the animation modes).

Things to Know:
- FancyLED library is NOT used here because it's a bit too much for the
  Trinket M0 to handle (animation was very slow).
- Animation modes are all monochromatic (single color, varying only in
  brightness). More a design decision than a technical one...of course
  NeoPixels can be individual colors, but folks like customizing and the
  monochromatic approach makes it easier to select a color. Also keeps the
  code a bit simpler, since Trinket space & performance is limited.
- Animation is monotonic time driven; there are no sleep() calls. This
  ensures that animation is constant-time regardless of the hardware or
  CircuitPython performance over time, or other goings on (e.g. garbage
  collection), only the frame rate (smoothness) varies; overall timing
  remains consistent.
"""

from math import modf, pi, sin
from random import getrandbits
from time import monotonic
from digitalio import DigitalInOut, Direction
from richbutton import RichButton
from rotaryio import IncrementalEncoder
import adafruit_dotstar
import board
import neopixel

# Configurable defaults

PIXEL_HUE = 0.0         # Red at start
PIXEL_BRIGHTNESS = 0.4  # 40% brightness at start
PIXEL_GAMMA = 2.6       # Controls brightness linearity
RING_1_OFFSET = 10      # Alignment of top pixel on 1st NeoPixel ring
RING_2_OFFSET = 10      # Alignment of top pixel on 2nd NeoPixel ring
RING_2_FLIP = True      # If True, reverse order of pixels on 2nd ring
CYCLE_INTERVAL = 0      # If >0 auto-cycle through play modes @ this interval
SPEED = 1.0             # Initial animation speed for modes that use it
XRAY_BITS = 0x0821      # Initial bit pattern for "X-ray" mode

# Things you probably don't want to change, unless adding new modes

PLAY_MODE_SPIN = 0               # Revolving pulse
PLAY_MODE_XRAY = 1               # Watchmen-inspired "X-ray goggles"
PLAY_MODE_SCAN = 2               # Scanline effect
PLAY_MODE_SPARKLE = 3            # Random dots
PLAY_MODES = 4                   # Number of PLAY modes
PLAY_MODE = PLAY_MODE_SPIN       # Initial PLAY mode

CONFIG_MODE_COLOR = 0            # Setting color (hue)
CONFIG_MODE_BRIGHTNESS = 1       # Setting brightness
CONFIG_MODE_ALIGN = 2            # Top pixel indicator
CONFIG_MODES = 3                 # Number of CONFIG modes
CONFIG_MODE = CONFIG_MODE_COLOR  # Initial CONFIG mode
CONFIGURING = False              # NOT configuring at start
# CONFIG_MODE_ALIGN is only used to test the values of RING_1_OFFSET and
# RING_2_OFFSET. The single lit pixel should appear at the top of each ring.
# If it does not, adjust each of those two values (integer from 0 to 15)
# until the pixel appears at the top (or physically reposition the rings).
# Some of the animation modes rely on the two rings being aligned a certain
# way. Once adjusted, you can reduce the value of CONFIG_MODES and this
# mode will be skipped in config state.

# Initialize hardware - PIN DEFINITIONS APPEAR HERE

# Turn off onboard DotStar LED
DOTSTAR = adafruit_dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1)
DOTSTAR.brightness = 0

# Turn off onboard discrete LED
LED = DigitalInOut(board.D13)
LED.direction = Direction.OUTPUT
LED.value = 0

# Declare NeoPixels on pin D0, 32 pixels long. Set to max brightness because
# on-the-fly brightness slows down NeoPixel lib, so we'll do our own here.
PIXELS = neopixel.NeoPixel(board.D0, 32, brightness=1.0, auto_write=False)

# Declare rotary encoder on pins D4 and D3, and click button on pin D2.
# If encoder behaves backwards from what you want, swap pins here.
ENCODER = IncrementalEncoder(board.D4, board.D3)
ENCODER_BUTTON = RichButton(board.D2)


def set_pixel(pixel_num, brightness):
    """Set one pixel in both 16-pixel rings. Pass in pixel index (0 to 15)
       and relative brightness (0.0 to 1.0). Actual resulting brightness
       will be a function of global brightness and gamma correction."""
    # Clamp passed brightness to 0.0-1.0 range,
    # apply global brightness and gamma correction
    brightness = max(min(brightness, 1.0), 0.0) * PIXEL_BRIGHTNESS
    brightness = pow(brightness, PIXEL_GAMMA) * 255.0
    # local_color is adjusted brightness applied to global PIXEL_COLOR
    local_color = (
        int(PIXEL_COLOR[0] * brightness + 0.5),
        int(PIXEL_COLOR[1] * brightness + 0.5),
        int(PIXEL_COLOR[2] * brightness + 0.5))
    # Roll over pixel_num as needed to 0-15 range, then store color
    pixel_num_wrapped = (pixel_num + RING_1_OFFSET) & 15
    PIXELS[pixel_num_wrapped] = local_color
    # Determine corresponding pixel for second ring. Mirror direction if
    # configured for such, correct for any rotational difference, then
    # perform similar roll-over as above before storing color.
    if RING_2_FLIP:
        pixel_num = 15 - pixel_num
    pixel_num_wrapped = 16 + ((pixel_num + RING_2_OFFSET) & 15)
    PIXELS[pixel_num_wrapped] = local_color


def triangle_wave(pos, peak=0.5):
    """Return a brightness level (0.0 to 1.0) corresponding to a position
       (0.0 to 1.0) within a triangle wave (spanning 0.0 to 1.0) with wave's
       peak brightness at a given position (0.0 to 1.0) within its span.
       Positions outside the wave's span return 0.0."""
    if 0.0 <= pos < 1.0:
        if pos <= peak:
            return pos / peak
        return (1.0 - pos) / (1.0 - peak)
    return 0.0


def hue_to_rgb(hue):
    """Given a hue value as a float, where the fractional portion
       (0.0 to 1.0) indicates the actual hue (starting from red at 0,
       to green at 1/3, to blue at 2/3, and back to red at 1.0),
       return an RGB color as a 3-tuple with values from 0.0 to 1.0."""
    hue = modf(hue)[0]
    sixth = (hue * 6.0) % 6.0
    ramp = modf(sixth)[0]
    if sixth < 1.0:
        return (1.0, ramp, 0.0)
    if sixth < 2.0:
        return (1.0 - ramp, 1.0, 0.0)
    if sixth < 3.0:
        return (0.0, 1.0, ramp)
    if sixth < 4.0:
        return (0.0, 1.0 - ramp, 1.0)
    if sixth < 5.0:
        return (ramp, 0.0, 1.0)
    return (1.0, 0.0, 1.0 - ramp)


def random_bits():
    """Generate random bit pattern, avoiding adjacent set bits (w/wrap)"""
    pattern = getrandbits(16)
    pattern |= (pattern & 1) << 16   # Replicate bit 0 at bit 16
    return pattern & ~(pattern >> 1) # Mask out adjacent set bits


# Some last-minute state initialization

POS = 0                              # Initial swirl animation position
PIXEL_COLOR = hue_to_rgb(PIXEL_HUE)  # Initial color
ENCODER_PRIOR = ENCODER.position     # Initial encoder position
TIME_PRIOR = monotonic()             # Initial time
LAST_CYCLE_TIME = TIME_PRIOR         # For mode auto-cycling
SPARKLE_BITS_PREV = 0                # First bits for sparkle animation
SPARKLE_BITS_NEXT = 0                # Next bits for sparkle animation
PREV_WEIGHT = 2                      # Force initial sparkle refresh


# Main loop

while True:
    ACTION = ENCODER_BUTTON.action()
    if ACTION is RichButton.TAP:
        # Encoder button tapped, cycle through play or config modes:
        if CONFIGURING:
            CONFIG_MODE = (CONFIG_MODE + 1) % CONFIG_MODES
        else:
            PLAY_MODE = (PLAY_MODE + 1) % PLAY_MODES
    elif ACTION is RichButton.DOUBLE_TAP:
        # DOUBLE_TAP not currently used, but this is where it would go.
        pass
    elif ACTION is RichButton.HOLD:
        # Encoder button held, toggle between PLAY and CONFIG modes:
        CONFIGURING = not CONFIGURING
    elif ACTION is RichButton.RELEASE:
        # RELEASE not currently used (play/config state changes when HOLD
        # is detected), but this is where it would go.
        pass

    # Process encoder input. Code always uses the ENCODER_CHANGE value
    # for relative adjustments.
    ENCODER_POSITION = ENCODER.position
    ENCODER_CHANGE = ENCODER_POSITION - ENCODER_PRIOR
    ENCODER_PRIOR = ENCODER_POSITION

    # Same idea, but for elapsed time (so time-based animation continues
    # at the next position, it doesn't jump around as when multiplying
    # monotonic() by SPEED.
    TIME_NOW = monotonic()
    TIME_CHANGE = TIME_NOW - TIME_PRIOR
    TIME_PRIOR = TIME_NOW

    if CONFIGURING:
        # In config mode, different pixel patterns indicate which
        # adjustment is being made (e.g. alternating pixels = hue mode).
        if CONFIG_MODE is CONFIG_MODE_COLOR:
            PIXEL_HUE = modf(PIXEL_HUE + ENCODER_CHANGE * 0.01)[0]
            PIXEL_COLOR = hue_to_rgb(PIXEL_HUE)
            for i in range(0, 16):
                set_pixel(i, i & 1)  # Turn on alternating pixels
        elif CONFIG_MODE is CONFIG_MODE_BRIGHTNESS:
            PIXEL_BRIGHTNESS += ENCODER_CHANGE * 0.025
            PIXEL_BRIGHTNESS = max(min(PIXEL_BRIGHTNESS, 1.0), 0.0)
            for i in range(0, 16):
                set_pixel(i, (i & 2) >> 1)  # Turn on pixel pairs
        elif CONFIG_MODE is CONFIG_MODE_ALIGN:
            C = 1      # First pixel on
            for i in range(0, 16):
                set_pixel(i, C)
                C = 0  # All other pixels off
    else:
        # In play mode. Auto-cycle animations if CYCLE_INTERVAL is set.
        if CYCLE_INTERVAL > 0:
            if TIME_NOW - LAST_CYCLE_TIME > CYCLE_INTERVAL:
                PLAY_MODE = (PLAY_MODE + 1) % PLAY_MODES
                LAST_CYCLE_TIME = TIME_NOW

        if PLAY_MODE is PLAY_MODE_XRAY:
            # In XRAY mode, encoder selects random bit patterns
            if abs(ENCODER_CHANGE) > 1:
                XRAY_BITS = random_bits()
            # Unset bits pulsate ever-so-slightly
            DIM = 0.42 + sin(monotonic() * 2) * 0.08
            for i in range(16):
                if XRAY_BITS & (1 << i):
                    set_pixel(i, 1.0)
                else:
                    set_pixel(i, DIM)
        else:
            # In all other modes, encoder adjusts speed/direction
            SPEED += ENCODER_CHANGE * 0.05
            SPEED = max(min(SPEED, 4.0), -4.0)
            POS += TIME_CHANGE * SPEED
            if PLAY_MODE is PLAY_MODE_SPIN:
                for i in range(16):
                    frac = modf(POS + i / 15.0)[0]  # 0.0-1.0 around ring
                    if frac < 0:
                        frac = 1.0 + frac
                    set_pixel(i, triangle_wave(frac, 0.5 - SPEED * 0.125))
            elif PLAY_MODE is PLAY_MODE_SCAN:
                if POS >= 0:
                    S = 2.0 - modf(POS)[0] * 4.0
                else:
                    S = 2.0 - (1.0 + modf(POS)[0]) * 4.0
                for i in range(16):
                    Y = sin((i / 7.5 + 0.5) * pi)  # Pixel Y coord
                    D = 0.5 - abs(Y - S) * 0.6     # Distance to scanline
                    set_pixel(i, triangle_wave(D))
            elif PLAY_MODE is PLAY_MODE_SPARKLE:
                NEXT_WEIGHT = modf(abs(POS * 2.0))[0]
                if SPEED < 0:
                    NEXT_WEIGHT = 1.0 - NEXT_WEIGHT
                if NEXT_WEIGHT < PREV_WEIGHT:
                    SPARKLE_BITS_PREV = SPARKLE_BITS_NEXT
                    while True:
                        SPARKLE_BITS_NEXT = random_bits()
                        if not SPARKLE_BITS_NEXT & SPARKLE_BITS_PREV:
                            break  # No bits in common, good!
                PREV_WEIGHT = 1.0 - NEXT_WEIGHT
                for i in range(16):
                    bit = 1 << i
                    if SPARKLE_BITS_PREV & bit:
                        result = PREV_WEIGHT
                    elif SPARKLE_BITS_NEXT & bit:
                        result = NEXT_WEIGHT
                    else:
                        result = 0
                    set_pixel(i, result)
                PREV_WEIGHT = NEXT_WEIGHT
    PIXELS.show()

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.