Source code for miio.integrations.philips.light.philips_bulb

import logging
from collections import defaultdict
from typing import Any, Dict, Optional

import click

from miio import Device, DeviceStatus
from miio.click_common import command, format_output

_LOGGER = logging.getLogger(__name__)

MODEL_PHILIPS_LIGHT_BULB = "philips.light.bulb"
MODEL_PHILIPS_LIGHT_HBULB = "philips.light.hbulb"
MODEL_PHILIPS_LIGHT_CBULB = "philips.light.cbulb"
MODEL_PHILIPS_ZHIRUI_DOWNLIGHT = "philips.light.downlight"
MODEL_PHILIPS_CANDLE = "philips.light.candle"
MODEL_PHILIPS_CANDLE2 = "philips.light.candle2"

AVAILABLE_PROPERTIES_COMMON = ["power", "dv"]
AVAILABLE_PROPERTIES_COLORTEMP = AVAILABLE_PROPERTIES_COMMON + ["bright", "cct", "snm"]

AVAILABLE_PROPERTIES = {
    MODEL_PHILIPS_LIGHT_HBULB: AVAILABLE_PROPERTIES_COMMON + ["bri"],
    MODEL_PHILIPS_LIGHT_BULB: AVAILABLE_PROPERTIES_COLORTEMP,
    MODEL_PHILIPS_LIGHT_CBULB: AVAILABLE_PROPERTIES_COLORTEMP,
    MODEL_PHILIPS_ZHIRUI_DOWNLIGHT: AVAILABLE_PROPERTIES_COLORTEMP,
    MODEL_PHILIPS_CANDLE: AVAILABLE_PROPERTIES_COLORTEMP,
    MODEL_PHILIPS_CANDLE2: AVAILABLE_PROPERTIES_COLORTEMP,
}


[docs] class PhilipsBulbStatus(DeviceStatus): """Container for status reports from Xiaomi Philips LED Ceiling Lamp.""" def __init__(self, data: Dict[str, Any]) -> None: # {'power': 'on', 'bright': 85, 'cct': 9, 'snm': 0, 'dv': 0} self.data = data @property def power(self) -> str: return self.data["power"] @property def is_on(self) -> bool: return self.power == "on" @property def brightness(self) -> Optional[int]: if "bright" in self.data: return self.data["bright"] if "bri" in self.data: return self.data["bri"] return None @property def color_temperature(self) -> Optional[int]: if "cct" in self.data: return self.data["cct"] return None @property def scene(self) -> Optional[int]: if "snm" in self.data: return self.data["snm"] return None @property def delay_off_countdown(self) -> int: return self.data["dv"]
[docs] class PhilipsWhiteBulb(Device): """Main class representing Xiaomi Philips White LED Ball Lamp.""" _supported_models = [MODEL_PHILIPS_LIGHT_HBULB]
[docs] @command( default_output=format_output( "", "Power: {result.power}\n" "Brightness: {result.brightness}\n" "Delayed turn off: {result.delay_off_countdown}\n" "Color temperature: {result.color_temperature}\n" "Scene: {result.scene}\n", ) ) def status(self) -> PhilipsBulbStatus: """Retrieve properties.""" properties = AVAILABLE_PROPERTIES.get( self.model, AVAILABLE_PROPERTIES[MODEL_PHILIPS_LIGHT_BULB] ) values = self.get_properties(properties) return PhilipsBulbStatus(defaultdict(lambda: None, zip(properties, values)))
[docs] @command(default_output=format_output("Powering on")) def on(self): """Power on.""" return self.send("set_power", ["on"])
[docs] @command(default_output=format_output("Powering off")) def off(self): """Power off.""" return self.send("set_power", ["off"])
[docs] @command( click.argument("level", type=int), default_output=format_output("Setting brightness to {level}"), ) def set_brightness(self, level: int): """Set brightness level.""" if level < 1 or level > 100: raise ValueError("Invalid brightness: %s" % level) return self.send("set_bright", [level])
[docs] @command( click.argument("seconds", type=int), default_output=format_output("Setting delayed turn off to {seconds} seconds"), ) def delay_off(self, seconds: int): """Set delay off seconds.""" if seconds < 1: raise ValueError("Invalid value for a delayed turn off: %s" % seconds) return self.send("delay_off", [seconds])
[docs] class PhilipsBulb(PhilipsWhiteBulb): """Support for philips bulbs that support color temperature and scenes.""" _supported_models = list(AVAILABLE_PROPERTIES.keys())
[docs] @command( click.argument("level", type=int), default_output=format_output("Setting color temperature to {level}"), ) def set_color_temperature(self, level: int): """Set Correlated Color Temperature.""" if level < 1 or level > 100: raise ValueError("Invalid color temperature: %s" % level) return self.send("set_cct", [level])
[docs] @command( click.argument("brightness", type=int), click.argument("cct", type=int), default_output=format_output( "Setting brightness to {brightness} and color temperature to {cct}" ), ) def set_brightness_and_color_temperature(self, brightness: int, cct: int): """Set brightness level and the correlated color temperature.""" if brightness < 1 or brightness > 100: raise ValueError("Invalid brightness: %s" % brightness) if cct < 1 or cct > 100: raise ValueError("Invalid color temperature: %s" % cct) return self.send("set_bricct", [brightness, cct])
[docs] @command( click.argument("number", type=int), default_output=format_output("Setting fixed scene to {number}"), ) def set_scene(self, number: int): """Set scene number.""" if number < 1 or number > 4: raise ValueError("Invalid fixed scene number: %s" % number) return self.send("apply_fixed_scene", [number])