-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcontrol_load.py
115 lines (93 loc) · 3.79 KB
/
control_load.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Print a list of loads and allow the user to control them with the keyboard."""
import argparse
import asyncio
import logging
import sys
import termios
import tty
from collections.abc import Iterator
from contextlib import contextmanager, suppress
from aiovantage import Vantage
from aiovantage.objects import Load
# Grab connection info from command line arguments
parser = argparse.ArgumentParser(description="aiovantage example")
parser.add_argument("host", help="hostname of Vantage controller")
parser.add_argument("--username", help="username for Vantage controller")
parser.add_argument("--password", help="password for Vantage controller")
parser.add_argument("--debug", help="enable debug logging", action="store_true")
args = parser.parse_args()
async def parse_keypress() -> str | None:
"""Rudimentary keypress parser (async version)."""
loop = asyncio.get_running_loop()
char: str = await loop.run_in_executor(None, sys.stdin.read, 1)
if char == "\x1b":
seq = await loop.run_in_executor(None, sys.stdin.read, 2)
if seq == "[A":
return "KEY_UP"
if seq == "[B":
return "KEY_DOWN"
return None
return char
@contextmanager
def cbreak_mode(descriptor: int) -> Iterator[None]:
"""Context manager to read terminal input character by character."""
old_attrs = termios.tcgetattr(descriptor)
try:
tty.setcbreak(descriptor)
yield
finally:
termios.tcsetattr(descriptor, termios.TCSADRAIN, old_attrs)
def clamp(value: int, min_value: int, max_value: int) -> int:
"""Clamp a value between a minimum and maximum value."""
return max(min_value, min(max_value, value))
async def main() -> None:
"""Run code example."""
if args.debug:
logging.basicConfig(level=logging.DEBUG)
async with Vantage(args.host, args.username, args.password) as vantage:
# Print out the available loads
print("Load ID Name")
print("------- ----")
async for load in vantage.loads:
print(f"{load.id: ^7} {load.name}")
print()
# Ask which load to control
while True:
try:
print("Enter a load ID to control:")
print("> ", end="", flush=True)
load_id = int(input())
load = vantage.loads[load_id]
break
except (ValueError, KeyError):
print("Invalid load id")
continue
# Print control instructions
print(f"\nControlling load '{load.name}'")
print(" Use the arrow keys to increase or decrease the load's brightness.")
print(" Press the spacebar to toggle the load.")
print(" Press 'q' to quit.\n")
# Listen for control keypresses
with cbreak_mode(sys.stdin.fileno()):
while True:
key = await parse_keypress()
if key == "KEY_UP" or key == "KEY_DOWN":
# Increase or decrease load brightness
level = int(load.level or 0)
new_level = clamp(level + (10 if key == "KEY_UP" else -10), 0, 100)
if new_level == level:
continue
await load.ramp(Load.RampType.Fixed, 1, new_level)
print(f"Set '{load.name}' brightness to {new_level}%")
elif key == " ":
# Toggle load
if load.is_on:
await load.turn_off()
print(f"Turned '{load.name}' load off")
else:
await load.turn_on()
print(f"Turned '{load.name}' load on")
elif key == "q":
break
with suppress(KeyboardInterrupt):
asyncio.run(main())