Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import appdaemon.plugins.hass.hassapi as hass
- import math
- import time
- #
- # Maps HUE lights to the KNX bus
- #
- # Args:
- #
- class Hue2Knx(hass.Hass):
- DIM_STEP_SIZE = 12.7
- DIM_DELAY = 0.3
- BRIGHTNESS_MAX = 254
- BRIGHTNESS_MIN = 0
- HSV_STEP_SIZE = 12
- HSV_DELAY = 0.3
- HSV_MODE_HUE = 1
- HSV_MODE_SATURATION = 2
- HUE_MAX = 360
- HUE_MIN = 0
- SATURATION_MAX = 100
- SATURATION_MIN = 0
- KNX_MODE_INCREASE = 9
- KNX_MODE_DECREASE = 1
- KNX_MODE_END = 0
- KNX_MAX_VALUE = 255
- KNX_MIN_VALUE = 0
- def initialize(self):
- self._state = ""
- self._brightness = 0
- self._hue = False
- self._saturation = False
- self._isDimming = False
- self._isChangingColor = False
- self._dimHandle = False
- self._hsvHandle = False
- # init states
- states = self.get_state(self.args["entity"], attribute="all")["attributes"]
- if ("brightness" in states):
- self._brightness = states["brightness"]
- if ("hs_color" in states):
- self._hue = int(states["hs_color"][0])
- self._saturation = int(states["hs_color"][1])
- # register listeners
- self._stateListener = self.listen_state(self.light_changed, entity = self.args["entity"], attribue = "all")
- self._eventListener = self.listen_event(self.event_triggered, "knx_event")
- def terminate(self):
- self.clear_timer(self._dimHandle)
- self.clear_timer(self._hsvHandle)
- self.cancel_listen_state(self._stateListener)
- self.cancel_listen_event(self._eventListener)
- # HASS EVENT
- def light_changed(self, entity, attribute, old, new, kwargs):
- states = self.get_state(self.args["entity"], attribute="all")["attributes"]
- #self.log(states)
- if (new != self._state):
- self._state = new
- state = 1 if new == "on" else 0
- self.update_knx_value("stateAddress", state, 0, 1)
- # KNX switches that can dimm need a brightness of 0 in the "off" state to correctly show the lights state
- if (state == 0):
- states["brightness"] = self.BRIGHTNESS_MIN
- if ("brightnessAddress" in self.args and "brightness" in states):
- brightness = int(states["brightness"])
- if (self._brightness != brightness and self._isDimming == False):
- self._brightness = brightness
- self.update_knx_value("brightnessAddress", brightness, self.BRIGHTNESS_MIN, self.BRIGHTNESS_MAX)
- if ("hueStateAddress" in self.args and "hs_color" in states):
- hue = int(states["hs_color"][0])
- if (self._hue != hue and self._isChangingColor == False):
- self._hue = hue
- self.update_knx_value("hueStateAddress", hue, self.HUE_MIN, self.HUE_MAX)
- if ("saturationStateAddress" in self.args and "hs_color" in states):
- saturation = int(states["hs_color"][1])
- if (self._saturation != saturation and self._isChangingColor == False):
- self._saturation = saturation
- self.update_knx_value("saturationStateAddress", saturation, self.SATURATION_MIN, self.SATURATION_MAX)
- # KNX event
- def event_triggered(self, event, payload, kwargs):
- value = payload["data"]
- address = payload["address"]
- #self.log(["knx event", value, address])
- # handle button presses and toogle the light
- if ("toggleAddress" in self.args and address == self.args["toggleAddress"]):
- mode = "turn_on" if int(value) == 1 else "turn_off"
- self.call_service("light/" + mode, entity_id=self.args["entity"])
- # handle dimming of the lights
- elif ("dimmAddress" in self.args and address == self.args["dimmAddress"]):
- value = int(value)
- self.clear_timer(self._dimHandle)
- self._isDimming = False
- if (value != self.KNX_MODE_END):
- if (self._brightness == self.BRIGHTNESS_MAX and value == self.KNX_MODE_INCREASE):
- return
- elif (self._brightness == self.BRIGHTNESS_MIN and value == self.KNX_MODE_DECREASE):
- return
- self._isDimming = True
- direction = 1 if value == self.KNX_MODE_INCREASE else -1
- step = self.DIM_STEP_SIZE * direction
- self.dim_light({"step": step})
- # handle color cycle
- elif ("hueAddress" in self.args and address == self.args["hueAddress"]):
- value = int(value)
- self.clear_timer(self._hsvHandle)
- self._isChangingColor = False
- if (value != self.KNX_MODE_END):
- if (self._hue == self.HUE_MAX and value == self.KNX_MODE_INCREASE):
- return
- elif (self._hue == self.HUE_MIN and value == self.KNX_MODE_DECREASE):
- return
- self._isChangingColor = True
- direction = 1 if value == self.KNX_MODE_INCREASE else -1
- step = self.HSV_STEP_SIZE * direction
- self.tune_color({"step": step, "mode": self.HSV_MODE_HUE})
- # handle saturation changes
- elif ("saturationAddress" in self.args and address == self.args["saturationAddress"]):
- value = int(value)
- self.clear_timer(self._hsvHandle)
- self._isChangingColor = False
- if (value != self.KNX_MODE_END):
- if (self._saturation == self.SATURATION_MAX and value == self.KNX_MODE_INCREASE):
- return
- elif (self._saturation == self.SATURATION_MIN and value == self.KNX_MODE_DECREASE):
- return
- self._isChangingColor = True
- direction = 1 if value == self.KNX_MODE_INCREASE else -1
- step = self.HSV_STEP_SIZE * direction
- self.tune_color({"step": step, "mode": self.HSV_MODE_SATURATION})
- def dim_light(self, kwargs):
- self.clear_timer(self._dimHandle);
- lastCycle = time.time();
- while (self._isDimming):
- if (lastCycle + self.DIM_DELAY > time.time()):
- time.sleep(0.1);
- continue;
- brightness = min( max(self.BRIGHTNESS_MIN, self._brightness + kwargs["step"]), self.BRIGHTNESS_MAX)
- if (brightness == self._brightness):
- return
- self._brightness = brightness;
- #self.log(["dim light via KNX", self._brightness])
- # update KNX right here, to get feedback there ASAP
- self.update_knx_value("brightnessAddress", self._brightness, self.BRIGHTNESS_MIN, self.BRIGHTNESS_MAX)
- self.set_light_properties({"brightness":self._brightness})
- #self._dimHandle = self.run_in(self.dim_light, self.DIM_DELAY, **kwargs)
- def tune_color(self, kwargs):
- self.clear_timer(self._hsvHandle);
- lastCycle = time.time();
- while (self._isChangingColor):
- if (lastCycle + self.HSV_DELAY > time.time()):
- time.sleep(0.1);
- continue;
- lastCycle = time.time();
- if (self._saturation == False or self._hue == False):
- states = self.get_state(self.args["entity"], attribute="all")["attributes"]
- self._hue = int(states["hs_color"][0])
- self._saturation = int(states["hs_color"][1])
- if (kwargs["mode"] == self.HSV_MODE_HUE):
- hue = min( max(self.HUE_MIN, self._hue + kwargs["step"]), self.HUE_MAX)
- if (hue == self._hue):
- return
- self._hue = hue
- # update KNX right here, to get feedback there ASAP
- self.update_knx_value("hueStateAddress", self._hue, self.HUE_MIN, self.HUE_MAX)
- if (kwargs["mode"] == self.HSV_MODE_SATURATION):
- saturation = min( max(self.SATURATION_MIN, self._saturation + kwargs["step"]), self.SATURATION_MAX)
- if (saturation == self._saturation):
- return
- self._saturation = saturation
- # update KNX right here, to get feedback there ASAP
- self.update_knx_value("saturationStateAddress", self._saturation, self.SATURATION_MIN, self.SATURATION_MAX)
- #self.log(["set hsv via KNX", self._hue, self._saturation])
- self.set_light_properties({"hs_color":[self._hue, self._saturation]})
- #self._hsvHandle = self.run_in(self.tune_color, self.HSV_DELAY, **kwargs)
- def update_knx_value(self, groupAddress, value, min, max):
- sanitizedValue = self.sanitize_knx_value(value, min, max)
- #self.log(["update KNX status [addressType, value, sanitized value]", groupAddress, value, sanitizedValue])
- self.call_service("knx/send", address=self.args[groupAddress], payload=[sanitizedValue])
- def sanitize_knx_value(self, value, minVal, maxVal):
- sanitizedValue = max(minVal, value)
- if (maxVal != self.KNX_MAX_VALUE):
- if (value == maxVal):
- sanitizedValue = self.KNX_MAX_VALUE
- elif (value == minVal):
- sanitizedValue = self.KNX_MIN_VALUE
- else :
- sanitizedValue = min( math.ceil(self.KNX_MAX_VALUE / maxVal * sanitizedValue), self.KNX_MAX_VALUE )
- #self.log(["sanitized knx value",value, sanitizedValue])
- return sanitizedValue
- def set_light_properties(self, kwargs):
- kwargs["entity_id"] = self.args["entity"]
- self.call_service("light/turn_on", **kwargs)
- def clear_timer(self, handle):
- if (handle):
- self.cancel_timer(handle)
- handle = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement