From 0b8893d43319038250642be350957f2563488dec Mon Sep 17 00:00:00 2001 From: mikahjc Date: Sat, 18 May 2024 00:13:19 -0500 Subject: [PATCH] Add class for HUSB238 board control and LED matrix control --- ControlMixerPython/boot_out.txt | 5 -- ControlMixerPython/lib/neopixel.mpy | Bin 0 -> 1318 bytes ControlMixerPython/mixer_leds.py | 109 ++++++++++++++++++++++++++++ ControlMixerPython/power.py | 88 ++++++++++++++++++++++ 4 files changed, 197 insertions(+), 5 deletions(-) delete mode 100644 ControlMixerPython/boot_out.txt create mode 100644 ControlMixerPython/lib/neopixel.mpy create mode 100644 ControlMixerPython/mixer_leds.py create mode 100644 ControlMixerPython/power.py diff --git a/ControlMixerPython/boot_out.txt b/ControlMixerPython/boot_out.txt deleted file mode 100644 index 2f1227d..0000000 --- a/ControlMixerPython/boot_out.txt +++ /dev/null @@ -1,5 +0,0 @@ -Adafruit CircuitPython 9.0.4 on 2024-04-16; Adafruit ItsyBitsy M4 Express with samd51g19 -Board ID:itsybitsy_m4_express -UID:A9C26FCF53324853202020472A3908FF -boot.py output: -Booting normal mode diff --git a/ControlMixerPython/lib/neopixel.mpy b/ControlMixerPython/lib/neopixel.mpy new file mode 100644 index 0000000000000000000000000000000000000000..e79666f32d940cbbc51a02556fc36be931333279 GIT binary patch literal 1318 zcmY*WT~ixX7=AaOOB&(iWH|&9X-XiJ010eES|PTOY|4iS1VPMbXGt~-*)e2yHk(53 zHmM)Fxwf2Ce<{qF8S>5V@1k}A!bfKf5X}}e9<*;N_*7P>g&4orxZO#Sc6G`q$A$F*S;s5-H`EpGLO!r&}0*yU4mF|Gj(u~>fl?+3x z&c|X@^ir)5rTb%7GRKy#^iC_fM0MY)8zr?OUda-rJ-}LLqciq_D;~wI&ArUFxVrIf zW_u?ifW7zs8F;)t6=zJR=?sU%>-SUq)TT6A431uW`)1Z}Ar^XCiItujav!MO3cR}1Sjxm)SN%uubRUju|@iyI*a?@xlQgM zOx}2B3LYV@5Moe&VH=S`77Y|yH-I5No+0DBg+zEOndEI`$}`W~;|!VM9b}ew622v| zpOwG*!aQAE^erSqGh9CzF!fM$BD^*loZg6xh9aSn$Zon8jGU!6zJK&m5O7~Ag*`7) zIsE1sz8kj)TRfb_nP1T$H}q42d68PowtaqV@dmuFo4cR>Dg0sLd)SJGvvKRwm%=Yy zFJz(KZ|B*+em_sIbf#3xLy)AqE}7Q!~~sCTUG4f(>9y~fNEduze0O+rh2tLHgJ?cErcnvEp%DH7CNyon literal 0 HcmV?d00001 diff --git a/ControlMixerPython/mixer_leds.py b/ControlMixerPython/mixer_leds.py new file mode 100644 index 0000000..2349a9e --- /dev/null +++ b/ControlMixerPython/mixer_leds.py @@ -0,0 +1,109 @@ +from power import HUSB238 +import board +import neopixel + +VM_GREEN = (32,255,32) +VM_RED = (255,16,16) + +LED1 = 1 << 0 # 1 +LED2 = 1 << 1 # 2 +LED3 = 1 << 2 # 4 +LED4 = 1 << 3 # 8 +LED5 = 1 << 4 # 16 +LED6 = 1 << 5 # 32 +LED7 = 1 << 6 # 64 +LED8 = 1 << 7 # 128 +LED9 = 1 << 8 # 256 +LED10 = 1 << 9 # 512 +LED11 = 1 << 10 # 1024 +LED12 = 1 << 11 # 2048 +LED13 = 1 << 12 # 4096 +LED14 = 1 << 13 # 8192 +LED15 = 1 << 14 # 16384 +LED16 = 1 << 15 # 32768 +LED17 = 1 << 16 # 65536 +LED18 = 1 << 17 # 131072 +LED19 = 1 << 18 # 262144 +LED20 = 1 << 19 # 524288 +LED21 = 1 << 20 # 1048576 +LED22 = 1 << 21 # 2097152 +LED23 = 1 << 22 # 4194304 +LED24 = 1 << 23 # 8388608 +LED25 = 1 << 24 # 16777216 +LED26 = 1 << 25 # 33554432 +LED27 = 1 << 26 # 67108864 +LED28 = 1 << 27 # 134217728 +LED29 = 1 << 28 # 268435456 +LED30 = 1 << 29 # 536870912 +LED31 = 1 << 30 # 1073741824 +LED32 = 1 << 31 # 2147483648 +LED33 = 1 << 32 # 4294967296 +LED34 = 1 << 33 # 8589934592 +LED35 = 1 << 34 # 17179869184 +LED36 = 1 << 35 # 34359738368 +LED37 = 1 << 36 # 68719476736 +LED38 = 1 << 37 # 137438953472 +LED39 = 1 << 38 # 274877906944 +LED40 = 1 << 39 # 549755813888 +LED41 = 1 << 40 # 1099511627776 +LED42 = 1 << 41 # 2199023255552 +LED43 = 1 << 42 # 4398046511104 +LED44 = 1 << 43 # 8796093022208 +LED45 = 1 << 44 # 17592186044416 + +leds = [ + LED1, LED2, LED3, LED4, LED5, + LED6, LED7, LED8, LED9, LED10, + LED11, LED12, LED13, LED14, LED15, + LED16, LED17, LED18, LED19, LED20, + LED21, LED22, LED23, LED24, LED25, + LED26, LED27, LED28, LED29, LED30, + LED31, LED32, LED33, LED34, LED35, + LED36, LED37, LED38, LED39, LED40, + LED41, LED42, LED43, LED44, LED45 +] + +def get_led_states(value): + return [(value & led) != 0 for led in leds] + + +_COLORS = [ + VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, + VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, + VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, + VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, + VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN +] + +class MixerLeds: + def __init__(self, i2c): + self._i2c = i2c + self._pd = HUSB238(i2c) + self._pixels = neopixel.NeoPixel(board.D5, 45, auto_write=False) + self._known_wattage = 0 + + def _init_pd(self): + if not self._pd.connect(): + print('Init PD failed to start connection') + return False + if self._known_wattage == self._pd.wattage: + return + available_wattage = self._pd.attempt_wattage(30) + self._known_wattage = available_wattage[1] + if not available_wattage[0]: + self._pixels.deinit() + available_brightness = available_wattage[1]/30.0 + self._pixels = neopixel.NeoPixel(board.D5, 45, brightness=available_brightness, auto_write=False) + + return True + + def set_state(self, state): + if not self._init_pd(): + return + + for idx, led_state in enumerate(get_led_states(state)): + if (led_state): + self._pixels[idx] = _COLORS[idx] + else: + self._pixels[idx] = (0,0,0) + self._pixels.show() diff --git a/ControlMixerPython/power.py b/ControlMixerPython/power.py new file mode 100644 index 0000000..fd597e8 --- /dev/null +++ b/ControlMixerPython/power.py @@ -0,0 +1,88 @@ +import adafruit_husb238 +import time + +class HUSB238: + _pd = None + + def __init__(self, i2c): + self._i2c = i2c + + def connect(self): + if (self.is_connected()): + try: + return self._pd.attached + except Exception as e: + return False + try: + self._pd = adafruit_husb238.Adafruit_HUSB238(self._i2c) + return True + except Exception as e: + self._pd = None + return False + + def is_connected(self): + if self._pd is not None: + try: + return self._pd.attached + except Exception as e: + self._pd = None + return False + else: + return False + + def attempt_wattage(self, watts): + if not self.is_connected(): + return False, 0 + if self.wattage >= watts: + return True, self.wattage + voltages = self.available_voltages + next_voltage_index = voltages.index(self.voltage) + 1 + while self.wattage < watts and next_voltage_index < len(voltages): + if not self.is_connected(): + print('Connection lost') + return False, 0 + target = voltages[next_voltage_index] + self.voltage = target + time.sleep(1) + if (self._pd.voltage != target): + print(f'Voltage did not switch to {target}v') + return False, self.wattage + next_voltage_index += 1 + resulting_wattage = self.wattage + return resulting_wattage >= watts, resulting_wattage + + @property + def wattage(self): + return self.voltage * self.current + + @property + def available_voltages(self): + return self._safe_pd_call(lambda: self._pd.available_voltages, []) + + @property + def voltage(self): + return self._safe_pd_call(lambda: self._pd.voltage, 0); + + @voltage.setter + def voltage(self, value): + self._pd.voltage = value + + @property + def current(self): + return self._safe_pd_call(lambda: self._pd.current, 0) + + def _unsafe_pd_call(self, func, default_val, attempts=20): + attempt_count = 0 + while attempt_count < attempts: + try: + return func() + except Exception as e: + print('unsafe waiting') + time.sleep(0.5) + return default_val + + def _safe_pd_call(self, func, default_val): + if self.is_connected(): + return func() + else: + return default_val \ No newline at end of file