#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright 2020-2025 by Murray Altheim. All rights reserved. This file is part
# of the Robot Operating System project, released under the MIT License. Please
# see the LICENSE file included as part of this package.
#
# author: Murray Altheim
# created: 2025-06-26
# modified: 2025-06-26
#
# Note that this changes the default 0x0F for 0x0B
import colorsys
import ioexpander as io
from colorama import init, Fore, Style
init()
from core.logger import Logger, Level
[docs]
class RotaryEncoder:
I2C_ADDR = 0x0F
PIN_RED = 1
PIN_GREEN = 7
PIN_BLUE = 2
POT_ENC_A = 12
POT_ENC_B = 3
POT_ENC_C = 11
def __init__(self, i2c_addr=0x0B, multiplier=1, brightness=0.5):
self._log = Logger('encoder', level=Level.INFO)
self._i2caddress = i2c_addr
self._count = 0
self._use_stepped_hue = True
self._multiplier = multiplier
self._brightness = brightness
self._period = int(255 / self._brightness)
self._log.info('ready.')
[docs]
def start(self):
self.ioe = io.IOE(i2c_addr=self._i2caddress, interrupt_pin=4)
# swap interrupt pin for rotary encoder breakout
if self._i2caddress == 0x0B:
self.ioe.enable_interrupt_out(pin_swap=True)
self.ioe.setup_rotary_encoder(1, RotaryEncoder.POT_ENC_A, RotaryEncoder.POT_ENC_B, pin_c=RotaryEncoder.POT_ENC_C)
self.ioe.set_pwm_period(self._period)
self.ioe.set_pwm_control(divider=2) # PWM as fast as possible
self.ioe.set_mode(RotaryEncoder.PIN_RED, io.PWM, invert=True)
self.ioe.set_mode(RotaryEncoder.PIN_GREEN, io.PWM, invert=True)
self.ioe.set_mode(RotaryEncoder.PIN_BLUE, io.PWM, invert=True)
self._log.info("started: RGB encoder with a period of {}, and {} brightness steps.".format(self._period, int(self._period * self._brightness)))
[docs]
def update(self):
if self.ioe.get_interrupt():
_count = self.ioe.read_rotary_encoder(1)
self._count = _count * self._multiplier
self.ioe.clear_interrupt()
hue = (self._count % 360) / 360.0
mode = round(hue * 10) / 10.0
if self._use_stepped_hue:
r, g, b = [int(c * self._period * self._brightness) for c in colorsys.hsv_to_rgb(mode, 1.0, 1.0)]
else:
r, g, b = [int(c * self._period * self._brightness) for c in colorsys.hsv_to_rgb(hue, 1.0, 1.0)]
self.ioe.output(RotaryEncoder.PIN_RED, r)
self.ioe.output(RotaryEncoder.PIN_GREEN, g)
self.ioe.output(RotaryEncoder.PIN_BLUE, b)
return mode, hue, r, g, b
[docs]
@staticmethod
def bounded_rollover(value, limit):
if value >= limit or value <= -limit:
return 0
return value
[docs]
def off(self):
self._log.info('off.')
self.ioe.output(self.PIN_RED, 0)
self.ioe.output(self.PIN_GREEN, 0)
self.ioe.output(self.PIN_BLUE, 0)
#EOF