Source code for gecko_iot_client.models.lighting_zone

from typing import Any, Dict, Optional

from .abstract_zone import AbstractZone, ZoneType


[docs] class RGB: """RGB color representation"""
[docs] def __init__(self, r: int, g: int, b: int, i: Optional[int] = None): """Initialize RGB color with validation.""" if not (0 <= r <= 255): raise ValueError(f"Red component {r} must be between 0 and 255") if not (0 <= g <= 255): raise ValueError(f"Green component {g} must be between 0 and 255") if not (0 <= b <= 255): raise ValueError(f"Blue component {b} must be between 0 and 255") if i is not None and not (0 <= i <= 255): raise ValueError(f"Intensity component {i} must be between 0 and 255") self.r = r self.g = g self.b = b self.i = i
[docs] def model_dump(self) -> Dict[str, Any]: """Convert to dictionary (replaces Pydantic's model_dump).""" result = {"r": self.r, "g": self.g, "b": self.b} if self.i is not None: result["i"] = self.i return result
[docs] @AbstractZone.register_zone_type(ZoneType.LIGHTING_ZONE) class LightingZone(AbstractZone): """State representation for lighting zone v1 with validation"""
[docs] def __init__(self, zone_id: str, config: Dict[str, Any]): """Initialize LightingZone with zone_id and config.""" # Set default name if not provided if "name" not in config or config["name"] is None: config["name"] = f"Light {zone_id}" super().__init__( id=zone_id, zone_type=ZoneType.LIGHTING_ZONE, name=config.get("name"), config=config, ) # Initialize lighting zone specific attributes self.active: Optional[bool] = getattr(self, "active", None) self.rgbi: Optional[RGB] = getattr(self, "rgbi", None) self.effect: Optional[str] = getattr(self, "effect", None) # Validate effect length if present if self.effect is not None and self._is_valid_effect_name(self.effect): self._validate_effect_name(self.effect)
def _validate_effect_name(self, effect: str) -> None: """Validate effect name length.""" if len(effect) < 1 or len(effect) > 50: raise ValueError( f"Effect name '{effect}' must be between 1 and 50 characters" ) def _is_valid_effect_name(self, effect: str) -> bool: """Check if effect name should be validated.""" return isinstance(effect, str)
[docs] def get_lighting_state(self) -> Dict[str, Any]: """Get the current lighting state as a simple dictionary.""" return { "active": self.active, "color": self.rgbi.model_dump() if self.rgbi else None, "effect": self.effect, }
[docs] def set_color(self, r: int, g: int, b: int, i: Optional[int] = None) -> None: """Set lighting color.""" rgb_color = RGB(r=r, g=g, b=b, i=i) self.rgbi = rgb_color self.active = True self._publish_desired_state({"rgbi": rgb_color, "active": True})
def _get_runtime_state_fields(self) -> set: """Runtime state fields for lighting zones.""" return {"active", "rgbi", "effect"} def _get_field_mappings(self) -> Dict[str, str]: """ Lighting zone specific field mappings. Returns: Dictionary mapping external field names to internal field names """ return { "isActive": "active", "color": "rgbi", "rgb": "rgbi", "lightEffect": "effect", "lightingEffect": "effect", "mode": "effect", "running": "active", "enabled": "active", "on": "active", }
[docs] def update_from_state(self, state: Dict[str, Any]) -> None: """Update lighting zone from runtime state with special handling for RGBI.""" # Handle RGBI conversion if it's a list if "rgbi" in state: rgbi_value = state["rgbi"] if isinstance(rgbi_value, list) and len(rgbi_value) >= 3: # Convert list [r, g, b, i] to RGB object r, g, b = rgbi_value[0], rgbi_value[1], rgbi_value[2] i = rgbi_value[3] if len(rgbi_value) > 3 else None state = state.copy() # Don't modify original state["rgbi"] = RGB(r=r, g=g, b=b, i=i) # Call parent update method super().update_from_state(state)
[docs] def set_effect(self, effect_name: str) -> None: """Set lighting effect with validation.""" self._validate_effect_name(effect_name) self.effect = effect_name self.active = True self._publish_desired_state({"effect": effect_name, "active": True})
[docs] def activate(self) -> None: """Activate this zone.""" self._publish_desired_state({"active": True})
[docs] def deactivate(self) -> None: """Deactivate this zone.""" self._publish_desired_state({"active": False})