Compare commits
7 Commits
c0e8d1833f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c620b7585 | ||
|
|
be632795a9 | ||
|
|
e7b9bef8c5 | ||
|
|
1994ad2c16 | ||
|
|
e31b2ad4f3 | ||
|
|
6038d0d405 | ||
|
|
e67df2809d |
@@ -3,6 +3,7 @@ appdaemon:
|
||||
longitude: -96.841910
|
||||
elevation: 30
|
||||
time_zone: America/Chicago
|
||||
use_dictionary_unpacking: true
|
||||
plugins:
|
||||
HASS:
|
||||
type: hass
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
hello_world:
|
||||
module: hello
|
||||
class: HelloWorld
|
||||
|
||||
ManCaveLights:
|
||||
module: tap_dial
|
||||
class: TapDial
|
||||
entity: sensor.tapdial01_action
|
||||
init_brightness: 200
|
||||
max_brightness: 254
|
||||
step_size: 25
|
||||
color: antique_white
|
||||
button1: light.stick_lamp
|
||||
button2: light.wet_bar
|
||||
button3: light.monkey_lamp
|
||||
|
||||
LivingRoomLights:
|
||||
module: tap_dial
|
||||
class: TapDial
|
||||
entity: sensor.tapdial02_action
|
||||
init_brightness: 200
|
||||
max_brightness: 254
|
||||
step_size: 25
|
||||
button1: light.living_room_lamps
|
||||
button2: light.living_room_floodlights
|
||||
button3: light.living_room_spot
|
||||
button4: switch.christmas_tree
|
||||
|
||||
button02:
|
||||
module: button_switch
|
||||
class: AqaraSwitch
|
||||
button: sensor.button02_action
|
||||
switch: switch.keyboards
|
||||
|
||||
my_timer:
|
||||
module: 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.tapdial01a_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
|
||||
|
||||
|
||||
20
apps/button_switch.py
Normal file
20
apps/button_switch.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from appdaemon.entity import Entity
|
||||
from appdaemon.plugins.hass.hassapi import Hass
|
||||
|
||||
|
||||
class AqaraSwitch(Hass):
|
||||
def initialize(self):
|
||||
self.log(f'Initializing Aqara Switch for {self.switch.friendly_name}')
|
||||
self.button.listen_state(self.handle_button_press, new=self.args.get('action', 'single'))
|
||||
|
||||
@property
|
||||
def switch(self) -> Entity:
|
||||
return self.get_entity(self.args['switch'])
|
||||
|
||||
@property
|
||||
def button(self) -> Entity:
|
||||
return self.get_entity(self.args['button'])
|
||||
|
||||
def handle_button_press(self, entity: str, attribute: str, old: str, new: str, **kwargs):
|
||||
# self.log(f'{new}')
|
||||
self.switch.toggle()
|
||||
144
apps/color_test.py
Normal file
144
apps/color_test.py
Normal file
@@ -0,0 +1,144 @@
|
||||
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'010 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'
|
||||
|
||||
@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'059 {new}')
|
||||
|
||||
# Dial actions
|
||||
if new.startswith('dial_rotate') and self.active_entity_is_on:
|
||||
self.log('063 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'069 Button {n} {typ}')
|
||||
|
||||
if eid := self.args.get(f'button{n}'):
|
||||
self.active_entity = self.get_entity(eid)
|
||||
self.log(f'073 Set active entity to: {self.active_entity.name}')
|
||||
self.log(json.dumps(self.active_entity.get_state('all'), indent=4))
|
||||
domain, entity = eid.split('.')
|
||||
self.log(f'076 domain: {domain}, entity: {entity}')
|
||||
match domain:
|
||||
case 'light':
|
||||
# Set the light to maximum brightness if the button is held.
|
||||
if typ == 'hold':
|
||||
self.log('080 Ignore button_hold command for now...')
|
||||
else:
|
||||
if self.active_entity_is_on:
|
||||
self.log(f'083 6Current 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'090 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'099 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'108 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'114 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('124 The light is off...')
|
||||
case 'switch':
|
||||
self.log('126 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"136 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"145 Invalid hex color: {hex_color}. Must contain only valid hex digits.")
|
||||
156
apps/tap_dial.py
Normal file
156
apps/tap_dial.py
Normal file
@@ -0,0 +1,156 @@
|
||||
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)
|
||||
|
||||
@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))
|
||||
|
||||
# The active_entity_is_on property fails if no button has been pushed and the dial is rotated with the error:
|
||||
# File "/conf/apps/tap_dial.py", line 59, in handle_state_change
|
||||
# if new.startswith('dial_rotate') and self.active_entity_is_on:
|
||||
# ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
# File "/conf/apps/tap_dial.py", line 29, in active_entity_is_on
|
||||
# return self.active_entity.get_state() == 'on'
|
||||
# ^^^^^^^^^^^^^^^^^^
|
||||
# AttributeError: 'TapDial' object has no attribute 'active_entity'. Did you mean: 'remove_entity'?
|
||||
|
||||
@property
|
||||
def active_entity_is_on(self) -> bool:
|
||||
return self.active_entity.get_state() == 'on'
|
||||
|
||||
@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'056 State change: {new}')
|
||||
|
||||
# Dial actions
|
||||
if new.startswith('dial_rotate') and self.active_entity_is_on:
|
||||
_, _, dir, speed = new.split('_', 4)
|
||||
self.log(f'061 Direction {dir} speed {speed}')
|
||||
match speed:
|
||||
case 'step':
|
||||
rate = self.step_size
|
||||
case 'slow':
|
||||
rate = 2 * self.step_size
|
||||
case 'fast':
|
||||
rate = 3 * self.step_size
|
||||
val = self.active_entity.attributes['brightness']
|
||||
if val != 'null':
|
||||
self.log(f'071 Brightness value = {val} Change rate = {rate}')
|
||||
if dir == 'right':
|
||||
if val < self.max_brightness:
|
||||
if (val + rate) > self.max_brightness:
|
||||
val = self.max_brightness
|
||||
else:
|
||||
val += rate
|
||||
self.active_entity.turn_on(brightness=val)
|
||||
self.log(f'079 Brightness value = {val}')
|
||||
else:
|
||||
if val > 0:
|
||||
if (val - rate) < 0:
|
||||
val = 0
|
||||
else:
|
||||
val -= rate
|
||||
self.active_entity.turn_on(brightness=val)
|
||||
self.log(f'087 Brightness value = {val}')
|
||||
else:
|
||||
self.log(f'089 WARNING: Brightness value = {val}')
|
||||
|
||||
# Button actions
|
||||
elif new.endswith('release'):
|
||||
_, n, typ, _ = new.split('_', 4)
|
||||
# type will be either press or hold
|
||||
self.log(f'104 Button {n} {typ}')
|
||||
|
||||
if eid := self.args.get(f'button{n}'):
|
||||
self.active_entity = self.get_entity(eid)
|
||||
self.log(f'108 Set active entity to: {self.active_entity.name}')
|
||||
# self.log(json.dumps(self.active_entity.get_state('all'), indent=4))
|
||||
|
||||
domain, entity = eid.split('.')
|
||||
self.log(f'112 Curent domain: {domain}, entity: {entity}')
|
||||
match domain:
|
||||
case 'light':
|
||||
# Set the light to maximum brightness if the button is held.
|
||||
if typ == 'hold':
|
||||
self.active_entity.turn_on(brightness=self.max_brightness)
|
||||
self.log(f'118 Set {self.active_entity.friendly_name} to maximum brightness {self.max_brightness}')
|
||||
else:
|
||||
if self.active_entity_is_on:
|
||||
self.active_entity.turn_off()
|
||||
self.log(f'122 Turn off {self.active_entity.friendly_name}')
|
||||
else:
|
||||
self.active_entity.turn_on(brightness=self.init_brightness)
|
||||
self.log(f'125 Turn on {self.active_entity.friendly_name} with brightness {self.init_brightness}')
|
||||
case 'switch':
|
||||
self.active_entity.toggle()
|
||||
self.log(f'128 Toggle on/off power to {self.active_entity.friendly_name}')
|
||||
|
||||
elif switch := self.args.get(f'button{n}'):
|
||||
self.active_entity = self.get_entity(switch)
|
||||
self.log(f'132 Set active entity to: {self.active_entity.friendly_name}')
|
||||
onoff = self.active_entity.get_state()
|
||||
self.log(f'134 {self.active_entity.friendly_name} is currently {onoff}')
|
||||
self.active_entity.toggle()
|
||||
self.log(f'136 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"146 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"155 Invalid hex color: {hex_color}. Must contain only valid hex digits.")
|
||||
|
||||
37
apps/timer.py
Normal file
37
apps/timer.py
Normal file
@@ -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.")
|
||||
@@ -5,17 +5,9 @@ services:
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- config:/conf
|
||||
- ./:/conf
|
||||
ports:
|
||||
- 5050:5050
|
||||
restart: unless-stopped
|
||||
tty: true
|
||||
|
||||
|
||||
volumes:
|
||||
config:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: ./
|
||||
|
||||
@@ -15,7 +15,7 @@ mancave:
|
||||
state: off
|
||||
light.color03:
|
||||
state: off
|
||||
light.white08:
|
||||
light.white08:
|
||||
color_temp: 300
|
||||
brightness: 175
|
||||
light.wled_soundreactive:
|
||||
Reference in New Issue
Block a user