2023-10-29 15:10:06 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
from devices.base import base
|
|
|
|
from devices.base import BATTERY_WARN_LEVEL
|
2023-10-29 15:45:14 +01:00
|
|
|
from devices.base import warning
|
2023-10-29 15:10:06 +01:00
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
class tradfri_light(base):
|
|
|
|
""" Communication (MQTT)
|
|
|
|
|
|
|
|
tradfri_light {
|
|
|
|
| "state": ["ON" / "OFF" / "TOGGLE"]
|
|
|
|
| "linkquality": [0...255] lqi
|
|
|
|
| "brightness": [0...254]
|
|
|
|
| "color_mode": ["color_temp"]
|
|
|
|
| "color_temp": ["coolest", "cool", "neutral", "warm", "warmest", 250...454]
|
|
|
|
| "color_temp_startup": ["coolest", "cool", "neutral", "warm", "warmest", "previous", 250...454]
|
|
|
|
| "update": []
|
|
|
|
| }
|
|
|
|
+- get {
|
|
|
|
| "state": ""
|
|
|
|
| }
|
|
|
|
+- set {
|
|
|
|
"state": ["ON" / "OFF"]
|
|
|
|
"brightness": [0...256]
|
|
|
|
"color_temp": [250...454]
|
|
|
|
"transition": [0...] seconds
|
|
|
|
"brightness_move": [-X...0...X] X/s
|
|
|
|
"brightness_step": [-X...0...X]
|
|
|
|
"color_temp_move": [-X...0...X] X/s
|
|
|
|
"color_temp_step": [-X...0...X]
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
KEY_LINKQUALITY = "linkquality"
|
|
|
|
KEY_OUTPUT_0 = "state"
|
|
|
|
KEY_BRIGHTNESS = "brightness"
|
|
|
|
KEY_COLOR_TEMP = "color_temp"
|
|
|
|
KEY_BRIGHTNESS_FADE = "brightness_move"
|
|
|
|
#
|
|
|
|
TX_TYPE = base.TX_DICT
|
|
|
|
TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP, KEY_BRIGHTNESS_FADE]
|
|
|
|
#
|
|
|
|
RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
|
|
|
|
RX_IGNORE_KEYS = ['update', 'color_mode', 'color_temp_startup']
|
|
|
|
RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic):
|
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
|
|
|
|
def __device_to_instance_filter__(self, key, data):
|
|
|
|
if key == self.KEY_BRIGHTNESS:
|
|
|
|
return int(round((data - 1) * 100 / 253, 0))
|
|
|
|
elif key == self.KEY_COLOR_TEMP:
|
|
|
|
return int(round((data - 250) * 10 / 204, 0))
|
|
|
|
return super().__device_to_instance_filter__(key, data)
|
|
|
|
|
|
|
|
def __instance_to_device_filter__(self, key, data):
|
|
|
|
if key == self.KEY_BRIGHTNESS:
|
|
|
|
return int(round(data * 253 / 100 + 1, 0))
|
|
|
|
elif key == self.KEY_COLOR_TEMP:
|
|
|
|
return int(round(data * 204 / 10 + 250, 0))
|
|
|
|
return super().__instance_to_device_filter__(key, data)
|
|
|
|
|
|
|
|
#
|
|
|
|
# RX
|
|
|
|
#
|
|
|
|
@property
|
|
|
|
def output_0(self):
|
|
|
|
"""rv: [True, False]"""
|
|
|
|
return self.get(self.KEY_OUTPUT_0, False)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def linkquality(self):
|
|
|
|
"""rv: numeric value"""
|
|
|
|
return self.get(self.KEY_LINKQUALITY, 0)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def brightness(self):
|
|
|
|
"""rv: numeric value [0%, ..., 100%]"""
|
|
|
|
return self.get(self.KEY_BRIGHTNESS, 0)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def color_temp(self):
|
|
|
|
"""rv: numeric value [0, ..., 10]"""
|
|
|
|
return self.get(self.KEY_COLOR_TEMP, 0)
|
|
|
|
|
|
|
|
#
|
|
|
|
# TX
|
|
|
|
#
|
|
|
|
def request_data(self, device=None, key=None, data=None):
|
|
|
|
self.mqtt_client.send(self.topic + "/get", '{"%s": ""}' % self.KEY_OUTPUT_0)
|
|
|
|
|
|
|
|
def set_output_0(self, state):
|
|
|
|
"""state: [True, False]"""
|
|
|
|
self.send_command(self.KEY_OUTPUT_0, state)
|
|
|
|
|
|
|
|
def set_output_0_mcb(self, device, key, data):
|
|
|
|
self.logger.log(logging.INFO if data != self.output_0 else logging.DEBUG, "Changing output 0 to %s", str(data))
|
|
|
|
self.set_output_0(data)
|
|
|
|
|
|
|
|
def toggle_output_0_mcb(self, device, key, data):
|
|
|
|
self.logger.info("Toggeling output 0")
|
|
|
|
self.set_output_0(not self.output_0)
|
|
|
|
|
|
|
|
def set_brightness(self, brightness):
|
|
|
|
"""brightness: [0, ..., 100]"""
|
|
|
|
self.send_command(self.KEY_BRIGHTNESS, brightness)
|
|
|
|
|
|
|
|
def set_brightness_mcb(self, device, key, data):
|
|
|
|
self.logger.log(logging.INFO if data != self.brightness else logging.DEBUG, "Changing brightness to %s", str(data))
|
|
|
|
self.set_brightness(data)
|
|
|
|
|
|
|
|
def default_inc(self, speed=40):
|
|
|
|
self.send_command(self.KEY_BRIGHTNESS_FADE, speed)
|
|
|
|
|
|
|
|
def default_dec(self, speed=-40):
|
|
|
|
self.default_inc(speed)
|
|
|
|
|
|
|
|
def default_stop(self):
|
|
|
|
self.default_inc(0)
|
|
|
|
|
|
|
|
def set_color_temp(self, color_temp):
|
|
|
|
"""color_temp: [0, ..., 10]"""
|
|
|
|
self.send_command(self.KEY_COLOR_TEMP, color_temp)
|
|
|
|
|
|
|
|
def set_color_temp_mcb(self, device, key, data):
|
|
|
|
self.logger.log(logging.INFO if data != self.color_temp else logging.DEBUG, "Changing color temperature to %s", str(data))
|
|
|
|
self.set_color_temp(data)
|
|
|
|
|
|
|
|
def all_off(self):
|
|
|
|
if self.output_0:
|
|
|
|
self.set_output_0(False)
|
|
|
|
|
|
|
|
|
|
|
|
class tradfri_button(base):
|
|
|
|
""" Communication (MQTT)
|
|
|
|
|
|
|
|
tradfri_button {
|
|
|
|
"action": [
|
|
|
|
"arrow_left_click",
|
|
|
|
"arrow_left_hold",
|
|
|
|
"arrow_left_release",
|
|
|
|
"arrow_right_click",
|
|
|
|
"arrow_right_hold",
|
|
|
|
"arrow_right_release",
|
|
|
|
"brightness_down_click",
|
|
|
|
"brightness_down_hold",
|
|
|
|
"brightness_down_release",
|
|
|
|
"brightness_up_click",
|
|
|
|
"brightness_up_hold",
|
|
|
|
"brightness_up_release",
|
|
|
|
"toggle"
|
|
|
|
]
|
|
|
|
"action_duration": [0...] s
|
|
|
|
"battery": [0...100] %
|
|
|
|
"linkquality": [0...255] lqi
|
|
|
|
"update": []
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
ACTION_TOGGLE = "toggle"
|
|
|
|
ACTION_BRIGHTNESS_UP = "brightness_up_click"
|
|
|
|
ACTION_BRIGHTNESS_DOWN = "brightness_down_click"
|
|
|
|
ACTION_RIGHT = "arrow_right_click"
|
|
|
|
ACTION_LEFT = "arrow_left_click"
|
|
|
|
ACTION_BRIGHTNESS_UP_LONG = "brightness_up_hold"
|
|
|
|
ACTION_BRIGHTNESS_UP_RELEASE = "brightness_up_release"
|
|
|
|
ACTION_BRIGHTNESS_DOWN_LONG = "brightness_down_hold"
|
|
|
|
ACTION_BRIGHTNESS_DOWN_RELEASE = "brightness_down_release"
|
|
|
|
ACTION_RIGHT_LONG = "arrow_right_hold"
|
|
|
|
ACTION_RIGHT_RELEASE = "arrow_right_release"
|
|
|
|
ACTION_LEFT_LONG = "arrow_left_hold"
|
|
|
|
ACTION_LEFT_RELEASE = "arrow_left_release"
|
|
|
|
#
|
|
|
|
KEY_LINKQUALITY = "linkquality"
|
|
|
|
KEY_BATTERY = "battery"
|
|
|
|
KEY_ACTION = "action"
|
|
|
|
KEY_ACTION_DURATION = "action_duration"
|
|
|
|
#
|
|
|
|
RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_ACTION]
|
|
|
|
RX_IGNORE_KEYS = ['update', KEY_ACTION_DURATION]
|
|
|
|
|
|
|
|
def __init__(self, mqtt_client, topic):
|
|
|
|
super().__init__(mqtt_client, topic)
|
|
|
|
#
|
|
|
|
self.add_callback(self.KEY_BATTERY, None, self.__warning__, True)
|
|
|
|
self.__battery_warning__ = False
|
|
|
|
|
|
|
|
#
|
|
|
|
# WARNING CALL
|
|
|
|
#
|
|
|
|
def __warning__(self, client, key, data):
|
|
|
|
if data <= BATTERY_WARN_LEVEL:
|
|
|
|
if not self.__battery_warning__:
|
|
|
|
w = warning(self.topic, warning.TYPE_BATTERY_LOW, "Battery low (%.1f%%)", data)
|
|
|
|
self.logger.warning(w)
|
|
|
|
self.set(self.KEY_WARNING, w)
|
|
|
|
else:
|
|
|
|
self.__battery_warning__ = False
|
|
|
|
|
|
|
|
#
|
|
|
|
# RX
|
|
|
|
#
|
|
|
|
@property
|
|
|
|
def action(self):
|
|
|
|
"""rv: action_txt"""
|
|
|
|
return self.get(self.KEY_ACTION)
|