diff --git a/apps/apps.yaml b/apps/apps.yaml index 9c211e5..ea7b2af 100644 --- a/apps/apps.yaml +++ b/apps/apps.yaml @@ -12,8 +12,6 @@ ManCaveLights: button1: light.stick_lamp button2: light.wet_bar button3: light.monkey_lamp - # button4: light.kitchen_candlelabra - # device: tapdial01 LivingRoomLights: module: tap_dial @@ -38,3 +36,31 @@ my_timer: class: TimerClass on_time: '18:00:00' light: light.wet_bar + brightness: 225 + color: ff99ff + effect: candle + +LightColorTest: + module: color_test + class: TapDial + entity: sensor.tapdial03_action + init_brightness: 200 + max_brightness: 254 + step_size: 25 + color1: FF0018 + color2: ff99ff + color3: 008018 + color4: 0000F9 + brightness1: 100 + brightness2: 150 + brightness3: 200 + brightness4: 254 + effect1: candle + effect2: finish_effect + effect3: okay + effect4: channel_change + button1: light.wet_bar + button2: light.wet_bar + button3: light.wet_bar + button4: light.wet_bar + diff --git a/apps/color_test.py b/apps/color_test.py new file mode 100644 index 0000000..39f5617 --- /dev/null +++ b/apps/color_test.py @@ -0,0 +1,145 @@ +from appdaemon.entity import Entity +from appdaemon.plugins.hass.hassapi import Hass +import json + +class TapDial(Hass): + active_entity: Entity + + def initialize(self): + self.tap_dial.listen_state(self.handle_state_change) + self.log(f'0.0 Tap Dial entity: {self.tap_dial.entity_id}') + + @property + def tap_dial(self) -> Entity: + return self.get_entity(self.args['entity']) + + @property + def step_size(self) -> int: + return int(self.args.get('step_size', 25)) + + @property + def init_brightness(self) -> int: + return int(self.args.get('init_brightness', 200)) + + @property + def max_brightness(self) -> int: + return int(self.args.get('max_brightness', 254)) + + @property + def active_entity_is_on(self) -> bool: + return self.active_entity.get_state() == 'on' + + # Experiment to read and write various properties to a light.... + + @property + def light_brightness(self) -> int: + return self.active_entity.attributes['brightness'] + + @light_brightness.setter + def light_brightness(self, val: int): + return self.active_entity.turn_on(brightness=val) + + @property + def light_color(self) -> list[int]: + return self.active_entity.get_state('rgb_color') + + @light_color.setter + def light_color(self, val: list[int]): + return self.active_entity.turn_on(rgb_color=val) + + @property + def light_effect(self) -> str: + return self.active_entity.get_state('effect') + + @light_effect.setter + def light_effect(self, val: str): + return self.active_entity.turn_on(effect=val) + + def handle_state_change(self, entity: str, attribute: str, old: str, new: str, **kwargs): + self.log(f'0.1 {new}') + + # Dial actions + if new.startswith('dial_rotate') and self.active_entity_is_on: + self.log('Ignore dial_rotate commands for now...') + + # Button actions + elif new.endswith('release'): + _, n, typ, _ = new.split('_', 4) + # type will be either press or hold + self.log(f'2.1 Button {n} {typ}') + + if eid := self.args.get(f'button{n}'): + self.active_entity = self.get_entity(eid) + self.log(f'2.1.1 Set active entity to: {self.active_entity.name}') + + domain, entity = eid.split('.') + match domain: + case 'light': + # Set the light to maximum brightness if the button is held. + if typ == 'hold': + self.log('Ignore button_hold command for now...') + else: + if self.active_entity_is_on: + self.log(f'Current values for Brightness: {self.light_brightness}, RGB Color: {self.light_color}, Effect: {self.light_effect}') + # self.log(f'New values for Color: {self.args.get(f"color{n}")} and Effect: {self.args.get(f"effect{n}")}') + hex = self.args.get(f"color{n}") + # self.log(f'Translate {self.args.get(f"color{n}")} to RGB {self.hex_to_rgb(hex)} ') + br_val = self.args.get(f'brightness{n}') + match n: + case '1': # do nothing + self.log(f'Made it to case{n}') + # self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex),transition=10) + self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex)) + # self.active_entity.turn_on(rgb_color=self.hex_to_rgb('FFFFFF')) + # self.active_entity.turn_on(effect='candle') + # self.light_color = self.hex_to_rgb(hex) + # self.light_effect = self.args.get(f'effect{n}') + # self.log(json.dumps(self.active_entity.get_state('all'), indent=4)) + case '2': # attempt to change brightness, color + self.log(f'Made it to case{n}') + # self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex),transition=10) + self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex)) + # self.active_entity.turn_on(rgb_color=self.hex_to_rgb('FFFFFF')) + # self.active_entity.turn_on(effect='candle') + # self.light_color = self.hex_to_rgb(hex) + # self.light_effect = self.args.get(f'effect{n}') + # self.log(json.dumps(self.active_entity.get_state('all'), indent=4)) + case '3': # attempt to apply 'candle' effect + self.log(f'Made it to case{n}') + self.active_entity.turn_on(effect='stop_hue_effect') + # self.active_entity.turn_on(effect='candle') + self.active_entity.set_state(effect='fireplace') + # self.log(json.dumps(self.active_entity.get_state('all'), indent=4)) + case '4': # json.dump + self.log(f'Made it to case{n}') + # self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex),transition=10) + # self.active_entity.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex)) + # self.active_entity.turn_on(rgb_color=self.hex_to_rgb('FFFFFF')) + # self.active_entity.turn_on(effect='candle') + # self.light_color = self.hex_to_rgb(hex) + # self.light_effect = self.args.get(f'effect{n}') + self.log(json.dumps(self.active_entity.get_state('all'), indent=4)) + + else: + self.log('The light is off...') + case 'switch': + self.log('Ignore non-light entities for now...') + + # This function was written by chatgpt... + def hex_to_rgb(self, hex_color: str) -> list: + + # Remove the "#" if it's included + hex_color = hex_color.lstrip('#') + + # Check if the string has a valid length + if len(hex_color) != 6: + raise ValueError(f"Invalid hex color: {hex_color}. Must be 6 characters long.") + + try: + # Split the hex color into its RGB components and convert to integers + r = int(hex_color[0:2], 16) + g = int(hex_color[2:4], 16) + b = int(hex_color[4:6], 16) + return [r, g, b] + except ValueError: + raise ValueError(f"Invalid hex color: {hex_color}. Must contain only valid hex digits.") diff --git a/apps/tap_dial.py b/apps/tap_dial.py index 25c4bb8..d44df17 100644 --- a/apps/tap_dial.py +++ b/apps/tap_dial.py @@ -92,3 +92,23 @@ class TapDial(Hass): self.log(f'2.2 {self.active_entity.friendly_name} is currently {onoff}') self.active_entity.toggle() self.log(f'2.2 Toggle on/off power to {self.active_entity.friendly_name}') + + # This function was written by chatgpt! + def hex_to_rgb(self, hex_color: str) -> list: + + # Remove the "#" if it's included + hex_color = hex_color.lstrip('#') + + # Check if the string has a valid length + if len(hex_color) != 6: + raise ValueError(f"Invalid hex color: {hex_color}. Must be 6 characters long.") + + try: + # Split the hex color into its RGB components and convert to integers + r = int(hex_color[0:2], 16) + g = int(hex_color[2:4], 16) + b = int(hex_color[4:6], 16) + return [r, g, b] + except ValueError: + raise ValueError(f"Invalid hex color: {hex_color}. Must contain only valid hex digits.") + diff --git a/apps/timer.py b/apps/timer.py new file mode 100644 index 0000000..092a1cf --- /dev/null +++ b/apps/timer.py @@ -0,0 +1,37 @@ +from appdaemon.entity import Entity +from appdaemon.plugins.hass.hassapi import Hass + + +class TimerClass(Hass): + def initialize(self): + on_time = self.args['on_time'] + self.run_daily(self.activate, start=on_time) + self.log(f'Initialized timer for {self.light.friendly_name} at {on_time}') + + @property + def light(self) -> Entity: + return self.get_entity(self.args['light']) + + def activate(self, **kwargs: dict): + hex = self.args.get('color') + br_val = self.args.get('brightness') + self.light.turn_on(brightness=br_val,rgb_color=self.hex_to_rgb(hex)) + + # This function was written by chatgpt... + def hex_to_rgb(self, hex_color: str) -> list: + + # Remove the "#" if it's included + hex_color = hex_color.lstrip('#') + + # Check if the string has a valid length + if len(hex_color) != 6: + raise ValueError(f"Invalid hex color: {hex_color}. Must be 6 characters long.") + + try: + # Split the hex color into its RGB components and convert to integers + r = int(hex_color[0:2], 16) + g = int(hex_color[2:4], 16) + b = int(hex_color[4:6], 16) + return [r, g, b] + except ValueError: + raise ValueError(f"Invalid hex color: {hex_color}. Must contain only valid hex digits.")