|
@@ -22,21 +22,6 @@ def payload_filter(payload):
|
22
|
22
|
return payload.decode("utf-8")
|
23
|
23
|
|
24
|
24
|
|
25
|
|
-def percent_bar(value):
|
26
|
|
- rv = ""
|
27
|
|
- for i in range(0, 10):
|
28
|
|
- rv += u"\u25ac" if (value - 5) > 10*i else u"\u25ad"
|
29
|
|
- return rv
|
30
|
|
-
|
31
|
|
-
|
32
|
|
-def green_led():
|
33
|
|
- return colored.fg('green') + "\u2b24" + colored.attr("reset")
|
34
|
|
-
|
35
|
|
-
|
36
|
|
-def grey_led():
|
37
|
|
- return colored.fg('light_gray') + "\u2b24" + colored.attr("reset")
|
38
|
|
-
|
39
|
|
-
|
40
|
25
|
def command_int_value(value):
|
41
|
26
|
try:
|
42
|
27
|
return int(value)
|
|
@@ -51,6 +36,39 @@ def command_float_value(value):
|
51
|
36
|
print("You need to give a integer parameter not '%s'" % str(value))
|
52
|
37
|
|
53
|
38
|
|
|
39
|
+def devicename(topic):
|
|
40
|
+ return " - ".join(topic.split('/')[1:])
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+def percent_bar(value):
|
|
44
|
+ rv = ""
|
|
45
|
+ for i in range(0, 10):
|
|
46
|
+ rv += u"\u25ac" if (value - 5) > 10*i else u"\u25ad"
|
|
47
|
+ return rv
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+def print_light(color, state, topic, description, led=False):
|
|
51
|
+ if led is True:
|
|
52
|
+ if state is True:
|
|
53
|
+ icon = colored.fg('green') + "\u2b24" + color
|
|
54
|
+ else:
|
|
55
|
+ icon = colored.fg('light_gray') + "\u2b24" + color
|
|
56
|
+ else:
|
|
57
|
+ icon = u'\u2b24' if state is True else u'\u25ef'
|
|
58
|
+ print(color + 10 * ' ' + icon + 9 * ' ' + devicename(topic), description + colored.attr("reset"))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+def print_switch(color, state, topic, description):
|
|
62
|
+ icon = u'\u25a0' if state is True else u'\u25a1'
|
|
63
|
+ print(color + 10 * ' ' + icon + 9 * ' ' + devicename(topic), description + colored.attr("reset"))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+def print_percent(color, prefix, perc_value, value_str, topic, description):
|
|
67
|
+ if len(prefix) > 1 or len(value_str) > 7:
|
|
68
|
+ raise ValueError("Length of prefix (%d) > 1 or length of value_str (%d) > 7" % (len(prefix), len(value_str)))
|
|
69
|
+ print(color + prefix + percent_bar(perc_value), value_str + (8 - len(value_str)) * ' ' + devicename(topic), description + colored.attr("reset"))
|
|
70
|
+
|
|
71
|
+
|
54
|
72
|
class base(object):
|
55
|
73
|
AUTOSEND = True
|
56
|
74
|
COMMANDS = []
|
|
@@ -226,11 +244,9 @@ class shelly(base):
|
226
|
244
|
|
227
|
245
|
def print_formatted(self, device, key, value):
|
228
|
246
|
if value is not None:
|
229
|
|
- icon = u'\u2b24' if value == "on" else u'\u25ef'
|
230
|
247
|
info = (" - %ds" % self.__output_0_auto_off__) if self.__output_0_auto_off__ is not None and value == "on" else ""
|
231
|
248
|
channel = "(%s%s)" % (self.names.get(key, key), info)
|
232
|
|
- devicename = " - ".join(self.topic.split('/')[1:])
|
233
|
|
- print(COLOR_SHELLY + 10 * ' ' + icon + 9 * ' ' + devicename + ' ' + channel + colored.attr("reset"))
|
|
249
|
+ print_light(COLOR_SHELLY, value == "on", self.topic, channel)
|
234
|
250
|
|
235
|
251
|
|
236
|
252
|
class my_powerplug(base):
|
|
@@ -293,10 +309,7 @@ class my_powerplug(base):
|
293
|
309
|
|
294
|
310
|
def print_formatted(self, device, key, value):
|
295
|
311
|
if value is not None:
|
296
|
|
- icon = u'\u2b24' if value else u'\u25ef'
|
297
|
|
- channel = "(%s)" % self.names.get(key, "Channel %d" % (int(key) + 1))
|
298
|
|
- devicename = " - ".join(self.topic.split('/')[1:])
|
299
|
|
- print(COLOR_POWERPLUG + 10 * ' ' + icon + 9 * ' ' + devicename + ' ' + channel + colored.attr("reset"))
|
|
312
|
+ print_light(COLOR_POWERPLUG, value, self.topic, "(%s)" % self.names.get(key, "Channel %d" % (int(key) + 1)))
|
300
|
313
|
|
301
|
314
|
|
302
|
315
|
class silvercrest_powerplug(base):
|
|
@@ -340,10 +353,7 @@ class silvercrest_powerplug(base):
|
340
|
353
|
|
341
|
354
|
def print_formatted(self, device, key, value):
|
342
|
355
|
if value is not None:
|
343
|
|
- icon = u'\u2b24' if value == "on" else u'\u25ef'
|
344
|
|
- channel = "(%s)" % self.names.get(key, key)
|
345
|
|
- devicename = " - ".join(self.topic.split('/')[1:])
|
346
|
|
- print(COLOR_POWERPLUG + 10 * ' ' + icon + 9 * ' ' + devicename + ' ' + channel + colored.attr("reset"))
|
|
356
|
+ print_light(COLOR_POWERPLUG, value == "on", self.topic, "(%s)" % self.names.get(key, key))
|
347
|
357
|
|
348
|
358
|
|
349
|
359
|
class silvercrest_motion_sensor(base):
|
|
@@ -372,10 +382,7 @@ class silvercrest_motion_sensor(base):
|
372
|
382
|
|
373
|
383
|
def print_formatted(self, device, key, value):
|
374
|
384
|
if value is not None:
|
375
|
|
- if value:
|
376
|
|
- print(COLOR_MOTION_SENSOR + 10 * ' ' + u'\u2b24' + 9 * ' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
|
377
|
|
- else:
|
378
|
|
- print(COLOR_MOTION_SENSOR + 10 * ' ' + u'\u25ef' + 9 * ' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
|
|
385
|
+ print_light(COLOR_MOTION_SENSOR, value, self.topic, "")
|
379
|
386
|
|
380
|
387
|
|
381
|
388
|
class tradfri_light(base):
|
|
@@ -480,24 +487,19 @@ class tradfri_light(base):
|
480
|
487
|
if value is not None:
|
481
|
488
|
color = COLOR_LIGHT_ACTIVE
|
482
|
489
|
if key == self.KEY_STATE:
|
483
|
|
- if value == "on":
|
484
|
|
- print(color + 10 * ' ' + u'\u2b24' + 9 * ' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
|
485
|
|
- else:
|
486
|
|
- print(color + 10 * ' ' + u'\u25ef' + 9 * ' ' + " - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
|
|
490
|
+ print_light(COLOR_LIGHT_ACTIVE, value == "on", self.topic, "")
|
487
|
491
|
self.print_formatted(device, self.KEY_BRIGHTNESS, self.data.get(self.KEY_BRIGHTNESS))
|
488
|
492
|
self.print_formatted(device, self.KEY_COLOR_TEMP, self.data.get(self.KEY_COLOR_TEMP))
|
489
|
493
|
elif key in [self.KEY_BRIGHTNESS, self.KEY_COLOR_TEMP]:
|
490
|
|
- if self.data.get(self.KEY_STATE) != "on":
|
491
|
|
- color = COLOR_LIGHT_PASSIVE
|
492
|
|
- if key == self.KEY_BRIGHTNESS:
|
493
|
|
- value = round(value * 100 / 256, 0)
|
494
|
|
- else:
|
495
|
|
- value = round((value - 250) * 100 / 204, 0)
|
496
|
|
- sys.stdout.write(color)
|
497
|
|
- sys.stdout.write('B' if key == gui_light.KEY_BRIGHTNESS else 'C')
|
498
|
|
- sys.stdout.write(percent_bar(value))
|
499
|
|
- sys.stdout.write("%3d%%" % value + 5 * " ")
|
500
|
|
- print(" - ".join(self.topic.split('/')[1:]) + colored.attr("reset"))
|
|
494
|
+ perc_value = round(value * 100 / 256, 0) if key == self.KEY_BRIGHTNESS else round((value - 250) * 100 / 204, 0)
|
|
495
|
+ print_percent(
|
|
496
|
+ COLOR_LIGHT_PASSIVE if self.data.get(self.KEY_STATE) != "on" else COLOR_LIGHT_ACTIVE,
|
|
497
|
+ 'B' if key == gui_light.KEY_BRIGHTNESS else 'C',
|
|
498
|
+ perc_value,
|
|
499
|
+ "%3d%%" % perc_value,
|
|
500
|
+ self.topic,
|
|
501
|
+ ""
|
|
502
|
+ )
|
501
|
503
|
|
502
|
504
|
|
503
|
505
|
class gui_light(tradfri_light):
|
|
@@ -576,24 +578,22 @@ class gui_light(tradfri_light):
|
576
|
578
|
|
577
|
579
|
def print_formatted(self, device, key, value):
|
578
|
580
|
if value is not None:
|
579
|
|
- color = COLOR_GUI_ACTIVE
|
580
|
581
|
device = " - ".join(self.topic.split('/')[1:])
|
581
|
582
|
if key == self.KEY_STATE:
|
582
|
|
- if value == True:
|
583
|
|
- print(color + 10 * ' ' + u'\u25a0' + 9 * ' ' + device + colored.attr("reset"))
|
584
|
|
- else:
|
585
|
|
- print(color + 10 * ' ' + u'\u25a1' + 9 * ' ' + device + colored.attr("reset"))
|
|
583
|
+ print_switch(COLOR_GUI_ACTIVE, value, self.topic, "")
|
586
|
584
|
elif key == self.KEY_ENABLE:
|
587
|
585
|
self.print_formatted(device, self.KEY_BRIGHTNESS, self.data.get(self.KEY_BRIGHTNESS))
|
588
|
586
|
self.print_formatted(device, self.KEY_COLOR_TEMP, self.data.get(self.KEY_COLOR_TEMP))
|
589
|
587
|
elif key in [self.KEY_BRIGHTNESS, self.KEY_COLOR_TEMP]:
|
590
|
|
- if not self.data.get(self.KEY_ENABLE, False):
|
591
|
|
- color = COLOR_GUI_PASSIVE
|
592
|
|
- value = round(value * 10 if key == self.KEY_COLOR_TEMP else value, 0)
|
593
|
|
- sys.stdout.write(color)
|
594
|
|
- sys.stdout.write('B' if key == self.KEY_BRIGHTNESS else 'C')
|
595
|
|
- sys.stdout.write(percent_bar(value))
|
596
|
|
- print("%3d%%" % value + 5 * " " + device + colored.attr("reset"))
|
|
588
|
+ perc_value = round(value * 10 if key == self.KEY_COLOR_TEMP else value, 0)
|
|
589
|
+ print_percent(
|
|
590
|
+ COLOR_GUI_PASSIVE if not self.data.get(self.KEY_ENABLE, False) else COLOR_GUI_ACTIVE,
|
|
591
|
+ 'B' if key == self.KEY_BRIGHTNESS else 'C',
|
|
592
|
+ perc_value,
|
|
593
|
+ "%3d%%" % perc_value,
|
|
594
|
+ self.topic,
|
|
595
|
+ ""
|
|
596
|
+ )
|
597
|
597
|
elif key == self.KEY_TIMER:
|
598
|
598
|
if isinstance(value, (int, float, complex)) and not isinstance(value, bool):
|
599
|
599
|
if self.maxvalue is None:
|
|
@@ -606,13 +606,10 @@ class gui_light(tradfri_light):
|
606
|
606
|
self.maxvalue = None
|
607
|
607
|
self.last_printed = None
|
608
|
608
|
if self.last_printed is None or abs(self.last_printed - perc) >= 4.95:
|
609
|
|
- print(color + 't' + percent_bar(perc) + '%3d%%' % perc + 5 * ' ' + device + ' (%.1f)' % disp_value + colored.attr('reset'))
|
|
609
|
+ print_percent(COLOR_GUI_ACTIVE, 't', perc, '%3d%%' % perc, self.topic, '(%.1f)' % disp_value)
|
610
|
610
|
self.last_printed = perc
|
611
|
611
|
elif key.startswith(self.KEY_LED_X[:-2]):
|
612
|
|
- led = green_led() if value else grey_led()
|
613
|
|
- ledname = '(%s)' % self.led_names.get(key, key)
|
614
|
|
- devicename = ' - '.join(self.topic.split('/')[1:])
|
615
|
|
- print(10 * ' ' + led + 9 * ' ' + COLOR_GUI_ACTIVE + devicename + ' ' + ledname + colored.attr("reset"))
|
|
612
|
+ print_light(COLOR_GUI_ACTIVE, value, self.topic, '(%s)' % self.led_names.get(key, key), True)
|
616
|
613
|
|
617
|
614
|
|
618
|
615
|
class tradfri_button(base):
|
|
@@ -686,10 +683,7 @@ class gui_led_array(base):
|
686
|
683
|
print("Unknown key %s in %s" % (targetkey, self.__class__.__name__))
|
687
|
684
|
|
688
|
685
|
def print_formatted(self, device, key, value):
|
689
|
|
- led = green_led() if value else grey_led()
|
690
|
|
- channel = '(%s)' % self.names.get(key, key)
|
691
|
|
- devicename = ' - '.join(self.topic.split('/')[1:])
|
692
|
|
- print(10 * ' ' + led + 9 * ' ' + COLOR_GUI_ACTIVE + devicename + ' ' + channel + colored.attr("reset"))
|
|
686
|
+ print_light(COLOR_GUI_ACTIVE, value, self.topic, '(%s)' % self.names.get(key, key), True)
|
693
|
687
|
|
694
|
688
|
|
695
|
689
|
class remote(base):
|
|
@@ -750,9 +744,7 @@ class brennenstuhl_radiator_valve(base):
|
750
|
744
|
perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0])
|
751
|
745
|
perc = 100 if perc > 100 else perc
|
752
|
746
|
perc = 0 if perc < 0 else perc
|
753
|
|
- sys.stdout.write(COLOR_RADIATOR_VALVE + '\u03d1' + percent_bar(perc))
|
754
|
|
- sys.stdout.write("%4.1f°C" % value + 3 * " ")
|
755
|
|
- print(devicename + colored.attr("reset"))
|
|
747
|
+ print_percent(COLOR_RADIATOR_VALVE, '\u03d1', perc, "%4.1f°C" % value, self.topic, "")
|
756
|
748
|
|
757
|
749
|
|
758
|
750
|
class gui_radiator_valve(base):
|
|
@@ -765,22 +757,31 @@ class gui_radiator_valve(base):
|
765
|
757
|
KEY_SETPOINT_TEMP = "setpoint_temp"
|
766
|
758
|
KEY_SETPOINT_TO_DEFAULT = "setpoint_to_default"
|
767
|
759
|
KEY_BOOST = 'boost'
|
|
760
|
+ KEY_AWAY = "away"
|
|
761
|
+ KEY_SUMMER = "summer"
|
|
762
|
+ KEY_ENABLE = "enable"
|
768
|
763
|
#
|
769
|
764
|
COMMANDS = [
|
770
|
765
|
"get_temperature",
|
771
|
766
|
"get_temperature_setpoint", "set_temperature_setpoint",
|
772
|
|
- "trigger_boost", "trigger_setpoint_to_default"
|
|
767
|
+ "trigger_boost", "trigger_setpoint_to_default",
|
|
768
|
+ "toggle_away", "toggle_summer",
|
773
|
769
|
]
|
774
|
770
|
|
775
|
771
|
def __init__(self, mqtt_client, topic):
|
776
|
772
|
super().__init__(mqtt_client, topic)
|
777
|
773
|
self.add_callback(self.KEY_SETPOINT_TEMP, self.print_formatted, None)
|
778
|
774
|
self.add_callback(self.KEY_TIMER, self.print_formatted, None)
|
|
775
|
+ self.add_callback(self.KEY_AWAY, self.print_formatted, None)
|
|
776
|
+ self.add_callback(self.KEY_SUMMER, self.print_formatted, None)
|
779
|
777
|
#
|
780
|
778
|
self.store_data(**{
|
781
|
779
|
self.KEY_TEMPERATURE: 20.7,
|
782
|
780
|
self.KEY_SETPOINT_TEMP: 20,
|
783
|
781
|
self.KEY_TIMER: 0,
|
|
782
|
+ self.KEY_AWAY: False,
|
|
783
|
+ self.KEY_SUMMER: False,
|
|
784
|
+ self.KEY_ENABLE: True
|
784
|
785
|
})
|
785
|
786
|
|
786
|
787
|
def __rx__(self, client, userdata, message):
|
|
@@ -815,26 +816,32 @@ class gui_radiator_valve(base):
|
815
|
816
|
self.send(self.KEY_BOOST, True)
|
816
|
817
|
elif command == self.COMMANDS[4]:
|
817
|
818
|
self.send(self.KEY_SETPOINT_TO_DEFAULT, True)
|
|
819
|
+ elif command == self.COMMANDS[5]:
|
|
820
|
+ self.send(self.KEY_AWAY, not self.data.get(self.KEY_AWAY))
|
|
821
|
+ elif command == self.COMMANDS[6]:
|
|
822
|
+ self.send(self.KEY_SUMMER, not self.data.get(self.KEY_SUMMER))
|
818
|
823
|
|
819
|
824
|
def print_formatted(self, device, key, value):
|
820
|
825
|
devicename = ' - '.join(self.topic.split('/')[1:])
|
821
|
|
- if key in [self.KEY_TEMPERATURE, self.KEY_SETPOINT_TEMP, self.KEY_TIMER]:
|
822
|
|
- if key in [self.KEY_TEMPERATURE, self.KEY_SETPOINT_TEMP]:
|
823
|
|
- perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0])
|
824
|
|
- info = " (Temperature)" if key == self.KEY_TEMPERATURE else " (Setpoint)"
|
825
|
|
- else:
|
826
|
|
- try:
|
827
|
|
- perc = 100 * value / 60
|
828
|
|
- except TypeError:
|
829
|
|
- value = 0
|
830
|
|
- perc = 0
|
831
|
|
- info = " (Timer)"
|
|
826
|
+ if key == self.KEY_TIMER:
|
|
827
|
+ try:
|
|
828
|
+ perc = 100 * value / 60
|
|
829
|
+ except TypeError:
|
|
830
|
+ value = 0
|
|
831
|
+ perc = 0
|
|
832
|
+ print_percent(COLOR_GUI_ACTIVE, 'T', perc, "%4.1fmin" % value, self.topic, "(Timer)")
|
|
833
|
+ elif key == self.KEY_TEMPERATURE:
|
|
834
|
+ perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0])
|
832
|
835
|
perc = 100 if perc > 100 else perc
|
833
|
836
|
perc = 0 if perc < 0 else perc
|
834
|
|
-
|
835
|
|
- sys.stdout.write(COLOR_GUI_ACTIVE)
|
836
|
|
- if key == self.KEY_TIMER:
|
837
|
|
- sys.stdout.write('T' + percent_bar(perc) + "%4.1fmin" % value + 2 * " ")
|
838
|
|
- else:
|
839
|
|
- sys.stdout.write('\u03d1' + percent_bar(perc) + "%4.1f°C" % value + 3 * " ")
|
840
|
|
- print(devicename + info + colored.attr("reset"))
|
|
837
|
+ print_percent(COLOR_GUI_ACTIVE, '\u03d1', perc, "%4.1f°C" % value, self.topic, "(Temperature)")
|
|
838
|
+ elif key == self.KEY_SETPOINT_TEMP:
|
|
839
|
+ perc = 100 * (value - self.TEMP_RANGE[0]) / (self.TEMP_RANGE[1] - self.TEMP_RANGE[0])
|
|
840
|
+ perc = 100 if perc > 100 else perc
|
|
841
|
+ perc = 0 if perc < 0 else perc
|
|
842
|
+ print_percent(COLOR_GUI_ACTIVE if self.data.get(self.KEY_ENABLE) else COLOR_GUI_PASSIVE,
|
|
843
|
+ '\u03d1', perc, "%4.1f°C" % value, self.topic, "(Setpoint)")
|
|
844
|
+ elif key == self.KEY_AWAY:
|
|
845
|
+ print_switch(COLOR_GUI_ACTIVE, value, self.topic, "(Away Mode)")
|
|
846
|
+ elif key == self.KEY_SUMMER:
|
|
847
|
+ print_switch(COLOR_GUI_ACTIVE, value, self.topic, "(Summer Mode)")
|