PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/proxy/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/proxy/philips_hue.py |
# # Copyright 2015 SUSE LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Philips HUE lamps module for proxy. .. versionadded:: 2015.8.3 First create a new user on the Hue bridge by following the `Meet hue <https://www.developers.meethue.com/documentation/getting-started>`_ instructions. To configure the proxy minion: .. code-block:: yaml proxy: proxytype: philips_hue host: [hostname or ip] user: [username] """ # pylint: disable=import-error,no-name-in-module,redefined-builtin import http.client import logging import time import salt.utils.json from salt.exceptions import CommandExecutionError, MinionError __proxyenabled__ = ["philips_hue"] CONFIG = {} log = logging.getLogger(__file__) class Const: """ Constants for the lamp operations. """ LAMP_ON = {"on": True, "transitiontime": 0} LAMP_OFF = {"on": False, "transitiontime": 0} COLOR_WHITE = {"xy": [0.3227, 0.329]} COLOR_DAYLIGHT = {"xy": [0.3806, 0.3576]} COLOR_RED = {"hue": 0, "sat": 254} COLOR_GREEN = {"hue": 25500, "sat": 254} COLOR_ORANGE = {"hue": 12000, "sat": 254} COLOR_PINK = {"xy": [0.3688, 0.2095]} COLOR_BLUE = {"hue": 46920, "sat": 254} COLOR_YELLOW = {"xy": [0.4432, 0.5154]} COLOR_PURPLE = {"xy": [0.3787, 0.1724]} def __virtual__(): """ Validate the module. """ return True def init(cnf): """ Initialize the module. """ CONFIG["host"] = cnf.get("proxy", {}).get("host") if not CONFIG["host"]: raise MinionError( message="Cannot find 'host' parameter in the proxy configuration" ) CONFIG["user"] = cnf.get("proxy", {}).get("user") if not CONFIG["user"]: raise MinionError( message="Cannot find 'user' parameter in the proxy configuration" ) CONFIG["uri"] = "/api/{}".format(CONFIG["user"]) def ping(*args, **kw): """ Ping the lamps. """ # Here blink them return True def shutdown(opts, *args, **kw): """ Shuts down the service. """ # This is no-op method, which is required but makes nothing at this point. return True def _query(lamp_id, state, action="", method="GET"): """ Query the URI :return: """ # Because salt.utils.query is that dreadful... :( err = None url = "{}/lights{}".format(CONFIG["uri"], lamp_id and f"/{lamp_id}" or "") + ( action and f"/{action}" or "" ) conn = http.client.HTTPConnection(CONFIG["host"]) if method == "PUT": conn.request(method, url, salt.utils.json.dumps(state)) else: conn.request(method, url) resp = conn.getresponse() if resp.status == http.client.OK: res = salt.utils.json.loads(resp.read()) else: err = f"HTTP error: {resp.status}, {resp.reason}" conn.close() if err: raise CommandExecutionError(err) return res def _set(lamp_id, state, method="state"): """ Set state to the device by ID. :param lamp_id: :param state: :return: """ try: res = _query(lamp_id, state, action=method, method="PUT") except Exception as err: # pylint: disable=broad-except raise CommandExecutionError(err) res = len(res) > 1 and res[-1] or res[0] if res.get("success"): res = {"result": True} elif res.get("error"): res = { "result": False, "description": res["error"]["description"], "type": res["error"]["type"], } return res def _get_devices(params): """ Parse device(s) ID(s) from the common params. :param params: :return: """ if "id" not in params: raise CommandExecutionError("Parameter ID is required.") return ( isinstance(params["id"], int) and [params["id"]] or [int(dev) for dev in params["id"].split(",")] ) def _get_lights(): """ Get all available lighting devices. """ return _query(None, None) # Callers def call_lights(*args, **kwargs): """ Get info about all available lamps. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. CLI Example: .. code-block:: bash salt '*' hue.lights salt '*' hue.lights id=1 salt '*' hue.lights id=1,2,3 """ res = dict() lights = _get_lights() for dev_id in "id" in kwargs and _get_devices(kwargs) or sorted(lights.keys()): if lights.get(str(dev_id)): res[dev_id] = lights[str(dev_id)] return res or False def call_switch(*args, **kwargs): """ Switch lamp ON/OFF. If no particular state is passed, then lamp will be switched to the opposite state. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **on**: True or False. Inverted current, if omitted CLI Example: .. code-block:: bash salt '*' hue.switch salt '*' hue.switch id=1 salt '*' hue.switch id=1,2,3 on=True """ out = dict() devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): if "on" in kwargs: state = kwargs["on"] and Const.LAMP_ON or Const.LAMP_OFF else: # Invert the current state state = ( devices[str(dev_id)]["state"]["on"] and Const.LAMP_OFF or Const.LAMP_ON ) out[dev_id] = _set(dev_id, state) return out def call_blink(*args, **kwargs): """ Blink a lamp. If lamp is ON, then blink ON-OFF-ON, otherwise OFF-ON-OFF. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **pause**: Time in seconds. Can be less than 1, i.e. 0.7, 0.5 sec. CLI Example: .. code-block:: bash salt '*' hue.blink id=1 salt '*' hue.blink id=1,2,3 """ devices = _get_lights() pause = kwargs.get("pause", 0) res = dict() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): state = devices[str(dev_id)]["state"]["on"] _set(dev_id, state and Const.LAMP_OFF or Const.LAMP_ON) if pause: time.sleep(pause) res[dev_id] = _set(dev_id, not state and Const.LAMP_OFF or Const.LAMP_ON) return res def call_ping(*args, **kwargs): """ Ping the lamps by issuing a short inversion blink to all available devices. CLI Example: .. code-block:: bash salt '*' hue.ping """ errors = dict() for dev_id, dev_status in call_blink().items(): if not dev_status["result"]: errors[dev_id] = False return errors or True def call_status(*args, **kwargs): """ Return the status of the lamps. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. CLI Example: .. code-block:: bash salt '*' hue.status salt '*' hue.status id=1 salt '*' hue.status id=1,2,3 """ res = dict() devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): dev_id = str(dev_id) res[dev_id] = { "on": devices[dev_id]["state"]["on"], "reachable": devices[dev_id]["state"]["reachable"], } return res def call_rename(*args, **kwargs): """ Rename a device. Options: * **id**: Specifies a device ID. Only one device at a time. * **title**: Title of the device. CLI Example: .. code-block:: bash salt '*' hue.rename id=1 title='WC for cats' """ dev_id = _get_devices(kwargs) if len(dev_id) > 1: raise CommandExecutionError("Only one device can be renamed at a time") if "title" not in kwargs: raise CommandExecutionError("Title is missing") return _set(dev_id[0], {"name": kwargs["title"]}, method="") def call_alert(*args, **kwargs): """ Lamp alert Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **on**: Turns on or off an alert. Default is True. CLI Example: .. code-block:: bash salt '*' hue.alert salt '*' hue.alert id=1 salt '*' hue.alert id=1,2,3 on=false """ res = dict() devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): res[dev_id] = _set( dev_id, {"alert": kwargs.get("on", True) and "lselect" or "none"} ) return res def call_effect(*args, **kwargs): """ Set an effect to the lamp. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **type**: Type of the effect. Possible values are "none" or "colorloop". Default "none". CLI Example: .. code-block:: bash salt '*' hue.effect salt '*' hue.effect id=1 salt '*' hue.effect id=1,2,3 type=colorloop """ res = dict() devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): res[dev_id] = _set(dev_id, {"effect": kwargs.get("type", "none")}) return res def call_color(*args, **kwargs): """ Set a color to the lamp. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **color**: Fixed color. Values are: red, green, blue, orange, pink, white, yellow, daylight, purple. Default white. * **transition**: Transition 0~200. Advanced: * **gamut**: XY coordinates. Use gamut according to the Philips HUE devices documentation. More: http://www.developers.meethue.com/documentation/hue-xy-values CLI Example: .. code-block:: bash salt '*' hue.color salt '*' hue.color id=1 salt '*' hue.color id=1,2,3 oolor=red transition=30 salt '*' hue.color id=1 gamut=0.3,0.5 """ res = dict() colormap = { "red": Const.COLOR_RED, "green": Const.COLOR_GREEN, "blue": Const.COLOR_BLUE, "orange": Const.COLOR_ORANGE, "pink": Const.COLOR_PINK, "white": Const.COLOR_WHITE, "yellow": Const.COLOR_YELLOW, "daylight": Const.COLOR_DAYLIGHT, "purple": Const.COLOR_PURPLE, } devices = _get_lights() color = kwargs.get("gamut") if color: color = color.split(",") if len(color) == 2: try: color = {"xy": [float(color[0]), float(color[1])]} except Exception as ex: # pylint: disable=broad-except color = None else: color = None if not color: color = colormap.get(kwargs.get("color", "white"), Const.COLOR_WHITE) color.update({"transitiontime": max(min(kwargs.get("transition", 0), 200), 0)}) for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): res[dev_id] = _set(dev_id, color) return res def call_brightness(*args, **kwargs): """ Set an effect to the lamp. Arguments: * **value**: 0~255 brightness of the lamp. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. * **transition**: Transition 0~200. Default 0. CLI Example: .. code-block:: bash salt '*' hue.brightness value=100 salt '*' hue.brightness id=1 value=150 salt '*' hue.brightness id=1,2,3 value=255 """ res = dict() if "value" not in kwargs: raise CommandExecutionError("Parameter 'value' is missing") try: brightness = max(min(int(kwargs["value"]), 244), 1) except Exception as err: # pylint: disable=broad-except raise CommandExecutionError("Parameter 'value' does not contains an integer") try: transition = max(min(int(kwargs["transition"]), 200), 0) except Exception as err: # pylint: disable=broad-except transition = 0 devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): res[dev_id] = _set(dev_id, {"bri": brightness, "transitiontime": transition}) return res def call_temperature(*args, **kwargs): """ Set the mired color temperature. More: http://en.wikipedia.org/wiki/Mired Arguments: * **value**: 150~500. Options: * **id**: Specifies a device ID. Can be a comma-separated values. All, if omitted. CLI Example: .. code-block:: bash salt '*' hue.temperature value=150 salt '*' hue.temperature value=150 id=1 salt '*' hue.temperature value=150 id=1,2,3 """ res = dict() if "value" not in kwargs: raise CommandExecutionError("Parameter 'value' (150~500) is missing") try: value = max(min(int(kwargs["value"]), 500), 150) except Exception as err: # pylint: disable=broad-except raise CommandExecutionError("Parameter 'value' does not contains an integer") devices = _get_lights() for dev_id in "id" not in kwargs and sorted(devices.keys()) or _get_devices(kwargs): res[dev_id] = _set(dev_id, {"ct": value}) return res