timer and led status integrated in gui_light class

This commit is contained in:
Dirk Alders 2023-01-08 20:35:36 +01:00
parent 9907924e54
commit 94f089dd93
8 changed files with 107 additions and 81 deletions

View File

@ -504,10 +504,19 @@ class gui_light(tradfri_light):
AUTOSEND = False
#
KEY_ENABLE = "enable"
KEY_TIMER = "timer"
KEY_LED_X = "led%d"
def __init__(self, mqtt_client, topic, enable_state=True, enable_brightness=False, enable_color_temp=False):
super().__init__(mqtt_client, topic, enable_state, enable_brightness, enable_color_temp)
self.add_callback(self.KEY_ENABLE, self.print_formatted, None)
self.add_callback(self.KEY_TIMER, self.print_formatted, None)
for i in range(0, 10):
self.add_callback(self.KEY_LED_X % i, self.print_formatted, None)
self.led_names = {}
#
self.maxvalue = None
self.last_printed = None
def __init_data__(self, enable_state, enable_brightness, enable_color_temp):
data = {}
@ -518,6 +527,9 @@ class gui_light(tradfri_light):
data[self.KEY_BRIGHTNESS] = 50
if enable_color_temp:
data[self.KEY_COLOR_TEMP] = 5
data[self.KEY_TIMER] = '-'
for i in range(0, 10):
data[self.KEY_LED_X % i] = False
self.store_data(**data)
def __rx__(self, client, userdata, message):
@ -559,14 +571,18 @@ class gui_light(tradfri_light):
else:
print("Unknown command!")
def add_led_name(self, key, name):
self.led_names[key] = name
def print_formatted(self, device, key, value):
if value is not None:
color = COLOR_GUI_ACTIVE
device = " - ".join(self.topic.split('/')[1:])
if key == self.KEY_STATE:
if value == True:
print(color + 10 * ' ' + u'\u25a0' + 9 * ' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
print(color + 10 * ' ' + u'\u25a0' + 9 * ' ' + device + colored.attr("reset"))
else:
print(color + 10 * ' ' + u'\u25a1' + 9*' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
print(color + 10 * ' ' + u'\u25a1' + 9 * ' ' + device + colored.attr("reset"))
elif key == self.KEY_ENABLE:
self.print_formatted(device, self.KEY_BRIGHTNESS, self.data.get(self.KEY_BRIGHTNESS))
self.print_formatted(device, self.KEY_COLOR_TEMP, self.data.get(self.KEY_COLOR_TEMP))
@ -577,8 +593,26 @@ class gui_light(tradfri_light):
sys.stdout.write(color)
sys.stdout.write('B' if key == self.KEY_BRIGHTNESS else 'C')
sys.stdout.write(percent_bar(value))
sys.stdout.write("%3d%%" % value + 5 * " ")
print(" - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
print("%3d%%" % value + 5 * " " + device + colored.attr("reset"))
elif key == self.KEY_TIMER:
if isinstance(value, (int, float, complex)) and not isinstance(value, bool):
if self.maxvalue is None:
self.maxvalue = value
disp_value = value
perc = disp_value / self.maxvalue * 100
else:
disp_value = 0
perc = 0
self.maxvalue = None
self.last_printed = None
if self.last_printed is None or abs(self.last_printed - perc) >= 4.95:
print(color + 't' + percent_bar(perc) + '%3d%%' % perc + 5 * ' ' + device + ' (%.1f)' % disp_value + colored.attr('reset'))
self.last_printed = perc
elif key.startswith(self.KEY_LED_X[:-2]):
led = green_led() if value else grey_led()
ledname = '(%s)' % self.led_names.get(key, key)
devicename = ' - '.join(self.topic.split('/')[1:])
print(10 * ' ' + led + 9 * ' ' + COLOR_GUI_ACTIVE + devicename + ' ' + ledname + colored.attr("reset"))
class tradfri_button(base):
@ -676,34 +710,6 @@ class remote(base):
print(COLOR_REMOTE + 10 * ' ' + icon + 6 * ' ' + devicename + colored.attr("reset"))
class gui_timer(base):
AUTOSEND = False
def __init__(self, mqtt_client, topic):
super().__init__(mqtt_client, topic)
self.maxvalue = None
self.last_printed = None
def __rx__(self, client, userdata, message):
payload = payload_filter(message.payload)
if message.topic.startswith(self.topic) and message.topic.endswith('/feedback/set'):
if isinstance(payload, (int, float, complex)) and not isinstance(payload, bool):
if self.maxvalue is None:
self.maxvalue = payload
perc = payload / self.maxvalue * 100
if self.last_printed is None or abs(self.last_printed - perc) >= 4.8:
sys.stdout.write(COLOR_GUI_ACTIVE + 't' + percent_bar(perc))
print('%3d%%' % perc + 2 * ' ' + ' - '.join(self.topic.split('/')[1:]) + ' (%.1f)' % payload + colored.attr('reset'))
self.last_printed = perc
else:
self.maxvalue = None
self.last_printed = None
sys.stdout.write(COLOR_GUI_ACTIVE + 't' + percent_bar(0))
print('%3d%%' % 0 + 2 * ' ' + ' - '.join(self.topic.split('/')[1:]) + colored.attr('reset'))
else:
print("Unknown Message")
class brennenstuhl_radiator_valve(base):
TEMP_RANGE = [10, 30]
#

View File

@ -1,6 +1,6 @@
import config
from __simulation__.devices import shelly, silvercrest_powerplug, tradfri_light, tradfri_button, silvercrest_motion_sensor, my_powerplug, remote, brennenstuhl_radiator_valve
from __simulation__.devices import gui_light, gui_led_array, gui_timer, gui_radiator_valve
from __simulation__.devices import gui_light, gui_led_array, gui_radiator_valve
import inspect
@ -136,7 +136,6 @@ class ffe_kitchen(base):
self.circulation_pump = shelly(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY,
input_0_func=shelly.INPUT_FUNC_OUT1_TRIGGER, output_0_auto_off=10*60)
self.circulation_pump.add_channel_name(shelly.KEY_OUTPUT_0, "Circulation Pump")
self.gui_timer_circulation_pump = gui_timer(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_GUI_TIMER)
class ffe_diningroom(base):
@ -206,6 +205,8 @@ class ffe(base):
class stairway(base):
def __init__(self, mqtt_client):
self.gui_main_light = gui_light(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_GUI, True, False, False)
self.gui_main_light.add_led_name(self.gui_main_light.KEY_LED_X % 0, "Motion Ground Floor")
self.gui_main_light.add_led_name(self.gui_main_light.KEY_LED_X % 1, "Motion First Floor")
self.main_light = shelly(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_SHELLY, input_0_func=shelly.INPUT_FUNC_OUT1_TRIGGER)
self.main_light.add_channel_name(shelly.KEY_OUTPUT_0, "Main Light")
self.motion_sensor_gf = silvercrest_motion_sensor(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF)

View File

@ -186,6 +186,41 @@ class base(dict):
return self.__previous__.get(key)
class nodered_gui_leds(base):
KEY_LED_0 = "led0"
KEY_LED_1 = "led1"
KEY_LED_2 = "led2"
KEY_LED_3 = "led3"
KEY_LED_4 = "led4"
KEY_LED_5 = "led5"
KEY_LED_6 = "led6"
KEY_LED_7 = "led7"
KEY_LED_8 = "led8"
KEY_LED_9 = "led9"
KEY_LED_LIST = [KEY_LED_0, KEY_LED_1, KEY_LED_2, KEY_LED_3, KEY_LED_4, KEY_LED_5, KEY_LED_6, KEY_LED_7, KEY_LED_8, KEY_LED_9]
#
TX_TYPE = base.TX_VALUE
def set_led(self, key, data):
"""data: [True, False]"""
self.logger.debug("Sending %s with content %s", key, str(data))
self.pack(key, data)
class nodered_gui_timer(base):
KEY_TIMER = "timer"
#
TX_TYPE = base.TX_VALUE
def set_timer(self, data):
"""data: numeric"""
self.pack(self.KEY_TIMER, data)
def set_timer_mcb(self, device, key, data):
self.logger.debug("Sending %s with content %s", key, str(data))
self.set_timer(data)
class shelly(base):
KEY_OUTPUT_0 = "relay/0"
KEY_OUTPUT_1 = "relay/1"
@ -700,7 +735,7 @@ class nodered_gui_switch(nodered_gui_button):
self.set_state(data)
class nodered_gui_light(nodered_gui_switch):
class nodered_gui_light(nodered_gui_switch, nodered_gui_leds, nodered_gui_timer):
KEY_ENABLE = "enable"
KEY_BRIGHTNESS = "brightness"
KEY_COLOR_TEMP = "color_temp"
@ -755,28 +790,6 @@ class nodered_gui_light(nodered_gui_switch):
self.set_color_temp(data)
class nodered_gui_leds(base):
KEY_LED_0 = "led0"
KEY_LED_1 = "led1"
KEY_LED_2 = "led2"
KEY_LED_3 = "led3"
KEY_LED_4 = "led4"
KEY_LED_5 = "led5"
KEY_LED_6 = "led6"
KEY_LED_7 = "led7"
KEY_LED_8 = "led8"
KEY_LED_9 = "led9"
#
TX_TYPE = base.TX_VALUE
#
RX_KEYS = [KEY_LED_0, KEY_LED_1, KEY_LED_2, KEY_LED_3, KEY_LED_4, KEY_LED_5, KEY_LED_6, KEY_LED_7, KEY_LED_8, KEY_LED_9]
def set_led(self, key, data):
"""data: [True, False]"""
self.logger.debug("Sending %s with content %s", key, str(data))
self.pack(key, data)
class brennenstuhl_heatingvalve(base):
KEY_LINKQUALITY = "linkquality"
KEY_BATTERY = "battery"

View File

@ -16,10 +16,8 @@ except ImportError:
ROOT_LOGGER_NAME = 'root'
logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
# TODO: implement devices.nodered_gui_timer (for circulation pump)
# TODO: implement devices.nodered_gui_heatvalve incl. setpoint, boost, ... + replace led with timer
# TODO: improve heating function
# TODO: implement timer and motion leds for stairwasy
# TODO: improve heating function (away mode (reduced setpoint), return to default button, default values in config)
# TODO: improve devices.brennenstuhl_heatvalve
# TODO: implement garland (incl. day events like sunset, sunrise, ...)
# TODO: implement warning message

View File

@ -23,8 +23,7 @@ class common_circulation_pump(room_shelly):
#
self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.circ_pump_actions, True)
#
self.gui_timer_view = devices.nodered_gui_heatvalve(mqtt_client, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_GUI_TIMER)
self.gui_timer_view.set_feedback('-')
self.gui_main_light.set_timer('-')
#
self.ct = task.periodic(6, self.cyclic_task)
self.pump_timer = None
@ -34,18 +33,18 @@ class common_circulation_pump(room_shelly):
def circ_pump_actions(self, device, key, data):
if data is True:
self.pump_timer = 10
self.gui_timer_view.set_feedback(self.pump_timer)
self.gui_main_light.set_timer(self.pump_timer)
else:
self.pump_timer = None
self.gui_timer_view.set_feedback('-')
self.gui_main_light.set_timer('-')
def cyclic_task(self, rt):
if self.pump_timer is not None:
if self.pump_timer <= 0:
self.pump_timer = None
self.gui_timer_view.set_feedback('-')
self.gui_main_light.set_timer('-')
else:
self.gui_timer_view.set_feedback(self.pump_timer)
self.gui_main_light.set_timer(self.pump_timer)
self.pump_timer -= self.ct.cycle_time / 60

View File

@ -43,7 +43,7 @@ class brightness_choose_n_action(object):
callback_device: A device for installing callback which are executed, when the device is switched on or off. It needs the following method:
* .add_callback(key, data or None, callback, on_changes_only)
"""
if len(self.brightness_device_list) >= len(devices.nodered_gui_leds.RX_KEYS):
if len(self.brightness_device_list) >= len(devices.nodered_gui_leds.KEY_LED_LIST):
raise ValueError("Number of devices is limited by number of leds in devices.nodered_gui_leds.")
self.brightness_device_list.append(brightness_device)
self.callback_device_list.append((callback_device, callback_key))
@ -61,7 +61,7 @@ class brightness_choose_n_action(object):
def update_active_device_led(self):
for i in range(0, len(self.brightness_device_list)):
self.gui_led_active_device.set_led(devices.nodered_gui_leds.RX_KEYS[i], self.active_device_state == i)
self.gui_led_active_device.set_led(devices.nodered_gui_leds.KEY_LED_LIST[i], self.active_device_state == i)
def choose_prev_device(self, device=None, key=None, data=None):
if self.active_device_state is not None:

View File

@ -59,9 +59,11 @@ class room_shelly(room):
class room_shelly_motion_sensor(room_shelly):
def __init__(self, mqtt_client, topic_shelly, topic_gui, topic_motion_sensor_1, topic_motion_sensor_2=None, timer_value=config.DEFAULT_ON_TIME_LIGHT):
def __init__(self, mqtt_client, topic_shelly, topic_gui, topic_motion_sensor_1, topic_motion_sensor_2=None, timer_value=30):
super().__init__(mqtt_client, topic_shelly, topic_gui)
self.timer_value = timer_value
self.motion_detected_1 = False
self.motion_detected_2 = False
#
self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, True, self.reload_timer, True)
self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, False, self.reset_timer, True)
@ -79,11 +81,13 @@ class room_shelly_motion_sensor(room_shelly):
cyclic_task.run()
def set_motion_detected(self, device, key, data):
if now() < sunrise_time(60) or now() > sunset_time(-60) or data is False:
if device == self.motion_sensor_silvercrest_1:
self.motion_detected_1 = data
elif device == self.motion_sensor_silvercrest_2:
self.motion_detected_2 = data
self.gui_main_light.set_led(devices.nodered_gui_light.KEY_LED_0, self.motion_detected_1)
self.gui_main_light.set_led(devices.nodered_gui_light.KEY_LED_1, self.motion_detected_2)
if now() < sunrise_time(60) or now() > sunset_time(-60):
if data is True:
logger.info("%s: Motion detected - Switching on main light %s", device.topic, self.main_light_shelly.topic)
self.main_light_shelly.set_output_0(True)
@ -99,12 +103,17 @@ class room_shelly_motion_sensor(room_shelly):
def cyclic_task(self, cyclic_task):
if self.main_light_timer is not None:
if self.main_light_timer <= 0:
if not self.motion_detected_1 and not self.motion_detected_2:
logger.info("No motion and time ran out - Switching off main light %s", self.main_light_shelly.topic)
self.main_light_shelly.set_output_0(False)
self.main_light_timer = None
else:
self.gui_main_light.set_timer(self.main_light_timer)
if (self.motion_detected_1 or self.motion_detected_2) and self.main_light_timer <= self.timer_value / 10:
self.main_light_timer = self.timer_value / 10
else:
self.main_light_timer -= cyclic_task.cycle_time
else:
self.gui_main_light.set_timer('-')
class room_shelly_tradfri_light(room_shelly):

View File

@ -17,5 +17,5 @@ class stairway(room_shelly_motion_sensor):
def __init__(self, mqtt_client):
# http://shelly1-3494546A9364
super().__init__(mqtt_client, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_SHELLY, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_GUI,
config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF,
config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_FF, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MIN_ON_TIME)
config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_FF,
timer_value=config.USER_ON_TIME_STAIRWAYS)