Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions .devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jseidl/hass-magic_areas",
"image": "mcr.microsoft.com/devcontainers/python:3.12-bookworm",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"postCreateCommand": "scripts/setup",
"forwardPorts": [
8123
Expand All @@ -17,24 +17,25 @@
"ms-python.python",
"github.vscode-pull-request-github",
"ryanluker.vscode-coverage-gutters",
"ms-python.vscode-pylance"
"ms-python.vscode-pylance",
"charliermarsh.ruff",
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 4,
"python.pythonPath": "/usr/bin/python3",
"python.analysis.autoSearchPaths": false,
"python.formatting.provider": "black",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"editor.formatOnPaste": false,
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
"files.trimTrailingWhitespace": true,
"python.analysis.typeCheckingMode": "basic",
"python.analysis.autoImportCompletions": true,
"python.defaultInterpreterPath": "/usr/local/bin/python",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
}
}
}
},
"remoteUser": "vscode",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
}
}
"features": {}
}
111 changes: 38 additions & 73 deletions custom_components/magic_areas/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,99 +151,64 @@ def _get_active_lights(self) -> list[str]:

async def async_turn_on(self, **kwargs) -> None:
"""Forward the turn_on command to all lights in the light group."""
data = {}
data = kwargs.copy()

# Copy parameters over
for arg_keyword, arg_value in kwargs.items():
data[arg_keyword] = arg_value
# Get active lights or default to all lights
active_lights = self._get_active_lights() or self._entity_ids

# Active lights
active_lights = self._get_active_lights()
targeted_lights = self._entity_ids
# Get current brightness of the group
group_state = self.hass.states.get(self.entity_id)
current_brightness = (
group_state.attributes.get("brightness", 0) if group_state else 0
)

if active_lights:
_LOGGER.debug(
"%s: restricting call to active lights: %s",
self.area.name,
str(active_lights),
)
# Desired brightness from data or default to max
desired_brightness = data.get("brightness", 255)
brightness_difference = desired_brightness - current_brightness

targeted_lights = active_lights
service_calls = []

# Split entities by supported features
entity_map = {SUPPORT_COLOR: [], SUPPORT_COLOR_TEMP: []}
for entity_id in targeted_lights:
for entity_id in active_lights:
service_data = data.copy()
state = self.hass.states.get(entity_id)
if not state:
continue
support = state.attributes.get(ATTR_SUPPORTED_FEATURES)

if bool(support & SUPPORT_COLOR):
if bool(support & SUPPORT_COLOR_TEMP):
entity_map[SUPPORT_COLOR_TEMP].append(entity_id)
else:
entity_map[SUPPORT_COLOR].append(entity_id)

no_color_support = list(
set(targeted_lights)
- set(entity_map[SUPPORT_COLOR])
- set(entity_map[SUPPORT_COLOR_TEMP])
)

service_calls = []

if entity_map[SUPPORT_COLOR_TEMP]:
service_data = data.copy()
service_data[ATTR_ENTITY_ID] = entity_map[SUPPORT_COLOR_TEMP]
service_call = self.hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
service_data,
blocking=True,
context=self._context,
)
service_calls.append(service_call)
support = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)

if entity_map[SUPPORT_COLOR]:
service_data = data.copy()
service_data[ATTR_ENTITY_ID] = entity_map[SUPPORT_COLOR]
# Adjust brightness
if "brightness" in data:
current_entity_brightness = state.attributes.get("brightness", 0)
new_brightness = max(
1, min(255, current_entity_brightness + brightness_difference)
)
service_data["brightness"] = new_brightness

# Perform color_temp emulation if ATTR_COLOR_TEMP is passed
if ATTR_COLOR_TEMP in service_data:
# Handle color temperature and color support
if support & SUPPORT_COLOR_TEMP and ATTR_COLOR_TEMP in service_data:
temp_k = color_util.color_temperature_mired_to_kelvin(
service_data[ATTR_COLOR_TEMP]
)
hs_color = color_util.color_temperature_to_hs(temp_k)
service_data[ATTR_HS_COLOR] = hs_color
del service_data[ATTR_COLOR_TEMP]

service_call = self.hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
service_data,
blocking=True,
context=self._context,
)
service_calls.append(service_call)

if no_color_support:
service_data = data.copy()
service_data[ATTR_ENTITY_ID] = no_color_support
if ATTR_COLOR_TEMP in service_data:
del service_data[ATTR_COLOR_TEMP]
if ATTR_HS_COLOR in service_data:
del service_data[ATTR_HS_COLOR]

service_call = self.hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
service_data,
blocking=True,
context=self._context,
if not support & SUPPORT_COLOR:
service_data.pop(ATTR_COLOR_TEMP, None)
service_data.pop(ATTR_HS_COLOR, None)

service_data[ATTR_ENTITY_ID] = entity_id
service_calls.append(
self.hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
service_data,
blocking=True,
context=self._context,
)
)
service_calls.append(service_call)

# Perform calls
# Perform all service calls concurrently
await asyncio.gather(*service_calls)


Expand Down
Empty file modified scripts/setup
100644 → 100755
Empty file.