Various enhancements
This commit is contained in:
parent
80186534dc
commit
a4310ec1c7
1 changed files with 118 additions and 82 deletions
200
c4ctrl.py
200
c4ctrl.py
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Author: Shy
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A command line client for Autoc4, the home automation system of the C4.
|
A command line client for Autoc4, the home automation system of the C4.
|
||||||
|
@ -10,9 +12,6 @@ Dependencies:
|
||||||
(available from https://github.com/eclipse/paho.mqtt.python)
|
(available from https://github.com/eclipse/paho.mqtt.python)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__date__ = "07 April 2017"
|
|
||||||
__author__ = "Shy"
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,39 +24,41 @@ class C4Interface():
|
||||||
retain = True
|
retain = True
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
def __init__(self, topic=None):
|
|
||||||
# Set a default topic
|
|
||||||
if topic: self.topic = topic
|
|
||||||
|
|
||||||
def push(self, message, topic=None, retain=None):
|
def push(self, message, topic=None, retain=None):
|
||||||
""" Send a message to the MQTT broker.
|
""" Send a message to the MQTT broker.
|
||||||
|
|
||||||
message may a byte encoded payload or a list of byte encoded
|
message may be a byte encoded payload or a list of either dict()s
|
||||||
payloads. """
|
or tuples()s. If message is a byte encoded payload, topic= must be
|
||||||
|
given. dict()s and tuple()s should lool like this:
|
||||||
|
dict("topic": str(topic), "payload": bytes(payload))
|
||||||
|
tuple(str(topic), bytes(payload)) """
|
||||||
|
|
||||||
from paho.mqtt import publish
|
from paho.mqtt import publish
|
||||||
|
|
||||||
# Overwrite defaults
|
# Skip empty messages
|
||||||
if topic: self.topic = topic
|
if message == [] or message == "": return
|
||||||
if retain != None: self.retain = retain
|
|
||||||
|
# Set defaults
|
||||||
|
if retain == None: retain = self.retain
|
||||||
|
|
||||||
if type(message) == list:
|
if type(message) == list:
|
||||||
# Add <qos> and <retain> to every message
|
# Add <qos> and <retain> to every message
|
||||||
for item in message.copy():
|
for item in message.copy():
|
||||||
if type(item) == dict:
|
if type(item) == dict:
|
||||||
item["qos"] = self.qos
|
item["qos"] = self.qos
|
||||||
item["retain"] = self.retain
|
item["retain"] = retain
|
||||||
elif type(item) == tuple:
|
elif type(item) == tuple:
|
||||||
new_item = (
|
new_item = (
|
||||||
item[0] or self.topic, # topic
|
item[0] or topic, # topic
|
||||||
item[1], # payload
|
item[1], # payload
|
||||||
self.qos, # qos
|
self.qos, # qos
|
||||||
self.retain # retain
|
retain # retain
|
||||||
)
|
)
|
||||||
message.remove(item)
|
message.remove(item)
|
||||||
message.append(new_item)
|
message.append(new_item)
|
||||||
|
|
||||||
if self.debug: return print("[DEBUG] inhibited messages:", message)
|
if self.debug: return print("[DEBUG] inhibited messages:",
|
||||||
|
message, file=sys.stderr)
|
||||||
|
|
||||||
publish.multiple(message,
|
publish.multiple(message,
|
||||||
hostname=self.broker,
|
hostname=self.broker,
|
||||||
|
@ -66,29 +67,32 @@ class C4Interface():
|
||||||
else: # Message is not a list
|
else: # Message is not a list
|
||||||
if self.debug:
|
if self.debug:
|
||||||
return print("[DEBUG] inhibited message to '{}': '{}'".format(
|
return print("[DEBUG] inhibited message to '{}': '{}'".format(
|
||||||
self.topic, message))
|
topic, message), file=sys.stderr)
|
||||||
|
|
||||||
publish.single(self.topic,
|
publish.single(topic,
|
||||||
payload=message,
|
payload=message,
|
||||||
qos=self.qos,
|
qos=self.qos,
|
||||||
retain=self.retain,
|
retain=retain,
|
||||||
hostname=self.broker,
|
hostname=self.broker,
|
||||||
port=self.port)
|
port=self.port)
|
||||||
|
|
||||||
def pull(self, topic=[]):
|
def pull(self, topic=[]):
|
||||||
""" Return the state of a topic.
|
""" Return the state of a topic.
|
||||||
|
|
||||||
topic may be a list of topics or a single topic given as string. """
|
topic may be a list of topics or a single topic given as string.
|
||||||
|
Returns a paho message object or list of message objects. """
|
||||||
|
|
||||||
from paho.mqtt import subscribe
|
from paho.mqtt import subscribe
|
||||||
|
|
||||||
topic = topic or self.topic
|
# topic must be a list
|
||||||
# <topic> must be a list
|
|
||||||
if type(topic) == str:
|
if type(topic) == str:
|
||||||
topic = [topic]
|
topic = [topic]
|
||||||
|
|
||||||
|
# Skip empty queries
|
||||||
|
if topic == []: return
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("[DEBUG] inhibited query for:", topic)
|
print("[DEBUG] inhibited query for:", topic, file=sys.stderr)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return subscribe.simple(topic,
|
return subscribe.simple(topic,
|
||||||
|
@ -100,15 +104,16 @@ class C4Interface():
|
||||||
def status(self):
|
def status(self):
|
||||||
""" Returns current status (string "open" or "closed") of the club. """
|
""" Returns current status (string "open" or "closed") of the club. """
|
||||||
|
|
||||||
st = self.pull("club/status")
|
club_status = self.pull("club/status")
|
||||||
|
|
||||||
# Produce fake result to prevent errors if in debug mode
|
# Create a fake result to prevent errors if in debug mode
|
||||||
if C4Interface.debug:
|
if C4Interface.debug:
|
||||||
print("[DEBUG] Warning: handing over fake data to allow further execution!")
|
print("[DEBUG] Warning: handing over fake data to allow for further execution!",
|
||||||
class st: pass
|
file=sys.stderr)
|
||||||
st.payload = b'\x00'
|
class club_status: pass
|
||||||
|
club_status.payload = b'\x00'
|
||||||
|
|
||||||
if st.payload == b'\x01':
|
if club_status.payload == b'\x01':
|
||||||
return "open"
|
return "open"
|
||||||
else:
|
else:
|
||||||
return "closed"
|
return "closed"
|
||||||
|
@ -131,6 +136,7 @@ class C4Interface():
|
||||||
class Dmx:
|
class Dmx:
|
||||||
""" Abstraction of the 3 channel LED cans in the club. """
|
""" Abstraction of the 3 channel LED cans in the club. """
|
||||||
|
|
||||||
|
# 3 bytes for color, one each for red, green and blue
|
||||||
template = "000000"
|
template = "000000"
|
||||||
|
|
||||||
def __init__(self, topic, color=None):
|
def __init__(self, topic, color=None):
|
||||||
|
@ -139,20 +145,20 @@ class Dmx:
|
||||||
self.is_master = topic.rfind("/master") == len(topic)-7 # 7 = len("/master")
|
self.is_master = topic.rfind("/master") == len(topic)-7 # 7 = len("/master")
|
||||||
|
|
||||||
def _pad_color(self, color):
|
def _pad_color(self, color):
|
||||||
""" Merge hex color value into hex template.
|
""" Merge hex color values or payloads into the template.
|
||||||
|
|
||||||
|
Expand 4 bit hex code notation (eg. #f0f) and pad with template
|
||||||
|
to get a fitting payload for this kind of light. """
|
||||||
|
|
||||||
Expand 4 bit hex code notation (eg. #f0f) and pad with template. """
|
|
||||||
if len(color) > len(self.template):
|
if len(color) > len(self.template):
|
||||||
# Silently truncate
|
# Silently truncate bytes exceeding template length
|
||||||
return color[:len(self.template)]
|
return color[:len(self.template)]
|
||||||
|
|
||||||
# Expand 3 char codes and codes of half the required length.
|
# Expand 3 char codes and codes of half the required length.
|
||||||
# Yet, lets presume that a 6-char code should never be expanded.
|
# Yet, let's presume that a 6-char code is alway meant to be
|
||||||
|
# interpreted as a color and should never be expanded.
|
||||||
if len(color) != 6 and len(color) == 3 or len(color) == (len(self.template) / 2):
|
if len(color) != 6 and len(color) == 3 or len(color) == (len(self.template) / 2):
|
||||||
expanded = ""
|
color = "".join(char*2 for char in color)
|
||||||
for c in color:
|
|
||||||
expanded += c*2
|
|
||||||
color = expanded
|
|
||||||
|
|
||||||
if len(color) == len(self.template): # Nothing more to do
|
if len(color) == len(self.template): # Nothing more to do
|
||||||
return color
|
return color
|
||||||
|
@ -165,6 +171,7 @@ class Dmx:
|
||||||
""" Set color (hex) for this instance.
|
""" Set color (hex) for this instance.
|
||||||
|
|
||||||
The color is then available via its color variable. """
|
The color is then available via its color variable. """
|
||||||
|
|
||||||
color = self._pad_color(color)
|
color = self._pad_color(color)
|
||||||
|
|
||||||
self.color = color
|
self.color = color
|
||||||
|
@ -174,12 +181,15 @@ class Dmx:
|
||||||
class Dmx4(Dmx):
|
class Dmx4(Dmx):
|
||||||
""" Abstraction of the 4 channel LED cans in the club. """
|
""" Abstraction of the 4 channel LED cans in the club. """
|
||||||
|
|
||||||
|
# 3 bytes for color plus 1 byte for brightness
|
||||||
template = "000000ff"
|
template = "000000ff"
|
||||||
|
|
||||||
|
|
||||||
class Dmx7(Dmx):
|
class Dmx7(Dmx):
|
||||||
""" Abstraction of the 7 channel LED cans in the club. """
|
""" Abstraction of the 7 channel LED cans in the club. """
|
||||||
|
|
||||||
|
# 3 bytes for color, another 3 bytes for special functions and 1 byte
|
||||||
|
# for brightness
|
||||||
template = "000000000000ff"
|
template = "000000000000ff"
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +201,10 @@ class C4Room:
|
||||||
self.switch_state = "" # State of switches in the like of str("0010")
|
self.switch_state = "" # State of switches in the like of str("0010")
|
||||||
|
|
||||||
def _interactive_light_switch(self):
|
def _interactive_light_switch(self):
|
||||||
""" Interactively ask for input. Returns str(userinput). """
|
""" Interactively ask for input.
|
||||||
|
|
||||||
|
Returns str(userinput). Will not write to stdout if sys.stdin is
|
||||||
|
no tty. """
|
||||||
|
|
||||||
if sys.stdin.isatty():
|
if sys.stdin.isatty():
|
||||||
print("[{}]".format(self.name))
|
print("[{}]".format(self.name))
|
||||||
|
@ -211,18 +224,24 @@ class C4Room:
|
||||||
return userinput
|
return userinput
|
||||||
|
|
||||||
def _get_state(self):
|
def _get_state(self):
|
||||||
""" Returns current state of switches as a str() of 1s and 0s. """
|
""" Returns current state of switches as a string of 1s and 0s. """
|
||||||
|
|
||||||
state = ""
|
state = ""
|
||||||
req = []
|
req = []
|
||||||
for topic in self.switches:
|
for topic in self.switches:
|
||||||
req.append(topic[1])
|
req.append(topic[1])
|
||||||
responce = self.c4.pull(req)
|
responce = self.c4.pull(req)
|
||||||
|
|
||||||
for sw in self.switches:
|
for sw in self.switches:
|
||||||
for r in responce:
|
for r in responce:
|
||||||
if r.topic == sw[1]:
|
if r.topic == sw[1]:
|
||||||
state += str(int.from_bytes(r.payload, byteorder="little"))
|
state += str(int.from_bytes(r.payload, byteorder="little"))
|
||||||
|
|
||||||
|
if C4Interface.debug:
|
||||||
|
print("[DEBUG] Warning: handing over fake data to allow for further execution!",
|
||||||
|
file=sys.stderr)
|
||||||
|
state = '0' * len(self.switches)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def light_switch(self, userinput=""):
|
def light_switch(self, userinput=""):
|
||||||
|
@ -278,9 +297,13 @@ class C4Room:
|
||||||
|
|
||||||
command=[]
|
command=[]
|
||||||
for i in range(len(self.switches)):
|
for i in range(len(self.switches)):
|
||||||
|
# If we know their state, skip switches which are unchanged
|
||||||
|
if self.switch_state:
|
||||||
|
if self.switch_state[i] == userinput[i]: continue
|
||||||
|
|
||||||
command.append({
|
command.append({
|
||||||
"topic" : self.switches[i][1],
|
"topic" : self.switches[i][1],
|
||||||
"payload" : bytearray([int(userinput[i])])
|
"payload" : bytes([int(userinput[i])])
|
||||||
})
|
})
|
||||||
|
|
||||||
return self.c4.push(command)
|
return self.c4.push(command)
|
||||||
|
@ -288,7 +311,7 @@ class C4Room:
|
||||||
def set_colorscheme(self, colorscheme, magic):
|
def set_colorscheme(self, colorscheme, magic):
|
||||||
""" Apply colorscheme to the LED Cans in this room. """
|
""" Apply colorscheme to the LED Cans in this room. """
|
||||||
|
|
||||||
cmd = []
|
command = []
|
||||||
for light in self.lights:
|
for light in self.lights:
|
||||||
if colorscheme.color_for(light.topic):
|
if colorscheme.color_for(light.topic):
|
||||||
|
|
||||||
|
@ -301,23 +324,24 @@ class C4Room:
|
||||||
# Generate the ghost topic for topic
|
# Generate the ghost topic for topic
|
||||||
ghost = "ghosts" + light.topic[light.topic.find('/'):]
|
ghost = "ghosts" + light.topic[light.topic.find('/'):]
|
||||||
|
|
||||||
cmd.append({
|
command.append({
|
||||||
"topic" : ghost,
|
"topic" : ghost,
|
||||||
"payload" : light.payload
|
"payload" : light.payload
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
# Send data to the real lanterns, not fluffyd.
|
# Send data to the real lanterns, not fluffyd.
|
||||||
cmd.append({
|
command.append({
|
||||||
"topic" : light.topic,
|
"topic" : light.topic,
|
||||||
"payload" : light.payload
|
"payload" : light.payload
|
||||||
})
|
})
|
||||||
|
|
||||||
if cmd == []: return
|
# Nothing to do. May happen if a preset defines no color for a room.
|
||||||
|
if command == []: return
|
||||||
|
|
||||||
if magic: # Do not retain "magic" messages
|
if magic: # Do not retain "magic" messages
|
||||||
return self.c4.push(cmd, retain=False)
|
return self.c4.push(command, retain=False)
|
||||||
else:
|
else:
|
||||||
return self.c4.push(cmd)
|
return self.c4.push(command)
|
||||||
|
|
||||||
|
|
||||||
class Wohnzimmer(C4Room):
|
class Wohnzimmer(C4Room):
|
||||||
|
@ -400,22 +424,9 @@ class Keller(C4Room):
|
||||||
|
|
||||||
|
|
||||||
class Kitchenlight:
|
class Kitchenlight:
|
||||||
""" The Kitchenlight. """
|
""" Interface to the Kitchenlight and its functions. """
|
||||||
|
|
||||||
_END = "little" # Endianess
|
_END = "little" # Kitchenlight endianess
|
||||||
_available_modes = """
|
|
||||||
off turn off
|
|
||||||
checker[,DELAY[,COLOR_1[,COLOR_2]]]
|
|
||||||
Checker
|
|
||||||
matrix[,LINES] Matrix
|
|
||||||
mood[,MODE] (1=Colorwheel, 2=Random)
|
|
||||||
Moodlight
|
|
||||||
oc[,DELAY] Open Chaos
|
|
||||||
pacman Pacman
|
|
||||||
sine Sine
|
|
||||||
text[,TEXT[,DELAY]] Text
|
|
||||||
flood Flood
|
|
||||||
clock Clock"""
|
|
||||||
|
|
||||||
def __init__(self, topic="kitchenlight/change_screen",
|
def __init__(self, topic="kitchenlight/change_screen",
|
||||||
powertopic="power/wohnzimmer/kitchenlight",
|
powertopic="power/wohnzimmer/kitchenlight",
|
||||||
|
@ -428,26 +439,42 @@ class Kitchenlight:
|
||||||
""" Send commands via a C4Interface to the MQTT broker. """
|
""" Send commands via a C4Interface to the MQTT broker. """
|
||||||
|
|
||||||
if self.autopower or poweron or poweroff:
|
if self.autopower or poweron or poweroff:
|
||||||
c4 = C4Interface(self.topic)
|
c4 = C4Interface()
|
||||||
cmd = []
|
command = []
|
||||||
cmd.append({
|
command.append({
|
||||||
"topic" : self.topic,
|
"topic" : self.topic,
|
||||||
"payload" : data })
|
"payload" : data })
|
||||||
if poweroff:
|
if poweroff:
|
||||||
cmd.append({
|
command.append({
|
||||||
"topic" : self.powertopic,
|
"topic" : self.powertopic,
|
||||||
"payload" : b'\x00'})
|
"payload" : b'\x00'})
|
||||||
elif self.autopower or poweron:
|
elif self.autopower or poweron:
|
||||||
cmd.append({
|
command.append({
|
||||||
"topic" : self.powertopic,
|
"topic" : self.powertopic,
|
||||||
"payload" : b'\x01'})
|
"payload" : b'\x01'})
|
||||||
c4.push(cmd)
|
c4.push(command)
|
||||||
else:
|
else:
|
||||||
c4 = C4Interface(self.topic)
|
c4 = C4Interface()
|
||||||
c4.push(data)
|
c4.push(data, topic=self.topic)
|
||||||
|
|
||||||
|
def list_available(self):
|
||||||
|
""" Print a list of available Kitchenlight modes. """
|
||||||
|
|
||||||
|
print("Available Kitchenlight modes (options are optional):")
|
||||||
|
print("""
|
||||||
|
off turn off Kitchenlight
|
||||||
|
checker[,DELAY[,COLOR_1[,COLOR_2]]] Checker
|
||||||
|
matrix[,LINES] Matrix
|
||||||
|
mood[,1|2] (1=Colorwheel, 2=Random) Moodlight
|
||||||
|
oc[,DELAY] Open Chaos
|
||||||
|
pacman Pacman
|
||||||
|
sine Sine
|
||||||
|
text[,TEXT[,DELAY]] Text
|
||||||
|
flood Flood
|
||||||
|
clock Clock""")
|
||||||
|
|
||||||
def set_mode(self, mode, opts=[]):
|
def set_mode(self, mode, opts=[]):
|
||||||
"""Switch to given mode."""
|
""" Switch to given mode. """
|
||||||
|
|
||||||
mode = mode.lower()
|
mode = mode.lower()
|
||||||
if mode == "off":
|
if mode == "off":
|
||||||
|
@ -458,7 +485,7 @@ class Kitchenlight:
|
||||||
return self.matrix(*opts)
|
return self.matrix(*opts)
|
||||||
if mode == "mood":
|
if mode == "mood":
|
||||||
return self.moodlight(*opts)
|
return self.moodlight(*opts)
|
||||||
if mode == "oc" or mode == "openchaos":
|
if mode == "oc":
|
||||||
return self.openchaos(*opts)
|
return self.openchaos(*opts)
|
||||||
if mode == "pacman":
|
if mode == "pacman":
|
||||||
return self.pacman()
|
return self.pacman()
|
||||||
|
@ -836,7 +863,8 @@ class ColorScheme:
|
||||||
|
|
||||||
# First of all, refuse to override virtual presets
|
# First of all, refuse to override virtual presets
|
||||||
if name in self._virtual_presets:
|
if name in self._virtual_presets:
|
||||||
print("I'm sorry Dave. I'm afraid I can't do that. The name \"{}\" is reserved. Please choose a different one.".format(name))
|
print("I'm sorry Dave. I'm afraid I can't do that. The name \"{}\" \
|
||||||
|
is reserved. Please choose a different one.".format(name))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if name == '-':
|
if name == '-':
|
||||||
|
@ -1047,7 +1075,8 @@ class RemotePresets:
|
||||||
available = self.query_available(rooms.copy())
|
available = self.query_available(rooms.copy())
|
||||||
# Produce some fake data to prevent KeyErrors if in debug mode
|
# Produce some fake data to prevent KeyErrors if in debug mode
|
||||||
if C4Interface.debug:
|
if C4Interface.debug:
|
||||||
print("[DEBUG] Warning: handing over fake data to allow further execution!")
|
print("[DEBUG] Warning: handing over fake data to allow for further execution!",
|
||||||
|
file=sys.stderr)
|
||||||
available = {
|
available = {
|
||||||
"global" : [preset],
|
"global" : [preset],
|
||||||
"wohnzimmer" : [preset],
|
"wohnzimmer" : [preset],
|
||||||
|
@ -1079,7 +1108,8 @@ if __name__ == "__main__":
|
||||||
description="Command line client for AutoC4.")
|
description="Command line client for AutoC4.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-d", "--debug", action="store_true",
|
"-d", "--debug", action="store_true",
|
||||||
help="display what would be send to the MQTT broker, but do not actually connect")
|
help="display what would be send to the MQTT broker, but do not \
|
||||||
|
actually connect")
|
||||||
|
|
||||||
# Various club functions
|
# Various club functions
|
||||||
group_fn = parser.add_argument_group(title="various functions")
|
group_fn = parser.add_argument_group(title="various functions")
|
||||||
|
@ -1104,7 +1134,9 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Ambient control
|
# Ambient control
|
||||||
group_cl = parser.add_argument_group(title="ambient color control",
|
group_cl = parser.add_argument_group(title="ambient color control",
|
||||||
description="PRESET may be either a preset name (which may be abbreviated), '#' followed by a color value in hex notation (eg. \"#ff0066\") or '-' to read from stdin.")
|
description="PRESET may be either a preset name (which may be \
|
||||||
|
abbreviated), '#' followed by a color value in hex notation (eg. \
|
||||||
|
\"#ff0066\") or '-' to read from stdin.")
|
||||||
group_cl.add_argument(
|
group_cl.add_argument(
|
||||||
"-w", "--wohnzimmer", type=str, dest="w_color", metavar="PRESET",
|
"-w", "--wohnzimmer", type=str, dest="w_color", metavar="PRESET",
|
||||||
help="apply local colorscheme PRESET to Wohnzimmer")
|
help="apply local colorscheme PRESET to Wohnzimmer")
|
||||||
|
@ -1116,7 +1148,7 @@ if __name__ == "__main__":
|
||||||
help="apply local colorscheme PRESET to Fnordcenter")
|
help="apply local colorscheme PRESET to Fnordcenter")
|
||||||
group_cl.add_argument(
|
group_cl.add_argument(
|
||||||
"-m", "--magic", action="store_true",
|
"-m", "--magic", action="store_true",
|
||||||
help="use fluffyd to change colors")
|
help="EXPERIMENTAL: use fluffyd to change colors")
|
||||||
group_cl.add_argument(
|
group_cl.add_argument(
|
||||||
"-l", "--list-presets", action="store_true",
|
"-l", "--list-presets", action="store_true",
|
||||||
help="list locally available presets")
|
help="list locally available presets")
|
||||||
|
@ -1126,7 +1158,9 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Switch control
|
# Switch control
|
||||||
group_sw = parser.add_argument_group(title="light switch control",
|
group_sw = parser.add_argument_group(title="light switch control",
|
||||||
description="BINARY_CODE is a string of 0s or 1s for every light in the room. Accepts integers also. Will show some information and ask for input if omitted.")
|
description="BINARY_CODE is a string of 0s or 1s for every light in the \
|
||||||
|
room. Accepts decimals also. May be prepended by '&' or '^' as AND or \
|
||||||
|
OR operators. Will show some information and ask for input if omitted.")
|
||||||
group_sw.add_argument(
|
group_sw.add_argument(
|
||||||
"-W", nargs='?', dest="w_switch", const="", metavar="BINARY_CODE",
|
"-W", nargs='?', dest="w_switch", const="", metavar="BINARY_CODE",
|
||||||
help="switch lights in Wohnzimmer on/off")
|
help="switch lights in Wohnzimmer on/off")
|
||||||
|
@ -1142,13 +1176,16 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Remote presets
|
# Remote presets
|
||||||
group_rp = parser.add_argument_group(title="remote preset functions",
|
group_rp = parser.add_argument_group(title="remote preset functions",
|
||||||
description="Available room names are \"wohnzimmer\", \"plenar\", \"fnord\" and \"keller\". Preset and room names may be abbreviated.")
|
description="Available room names are \"wohnzimmer\", \"plenar\", \
|
||||||
|
\"fnord\" and \"keller\". Preset and room names may be abbreviated.")
|
||||||
group_rp.add_argument(
|
group_rp.add_argument(
|
||||||
"-r", "--remote-preset", type=str, metavar="PRESET[:ROOM[,ROOM,...]]",
|
"-r", "--remote-preset", type=str, metavar="PRESET[:ROOM[,ROOM,...]]",
|
||||||
help="activate remote PRESET for ROOM(s).")
|
help="activate remote PRESET for ROOM(s). Activates preset globally \
|
||||||
|
if ROOM is omitted.")
|
||||||
group_rp.add_argument(
|
group_rp.add_argument(
|
||||||
"-R", "--list-remote", nargs='?', const="global", metavar="ROOM",
|
"-R", "--list-remote", nargs='?', const="global", metavar="ROOM",
|
||||||
help="list remote presets for ROOM")
|
help="list remote presets for ROOM. Will list global presets if ROOM \
|
||||||
|
is omitted.")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Debug, gate, status and shutdown
|
# Debug, gate, status and shutdown
|
||||||
|
@ -1167,8 +1204,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Kitchenlight
|
# Kitchenlight
|
||||||
if args.list_kl_modes:
|
if args.list_kl_modes:
|
||||||
print("Available Kitchenlight modes (options are optional):")
|
Kitchenlight().list_available()
|
||||||
print(Kitchenlight._available_modes)
|
|
||||||
if args.kl_mode:
|
if args.kl_mode:
|
||||||
kl = Kitchenlight()
|
kl = Kitchenlight()
|
||||||
mode = args.kl_mode.split(',')
|
mode = args.kl_mode.split(',')
|
||||||
|
|
Loading…
Reference in a new issue