Lights

bridge.lights owns Light models for on/off, dimming, color, color temperature, and effects. Split main/trim zones appear as separate Light resources (see Split devices).

Night-light color-mode

Some fixtures (e.g. Hampton Bay Penrose) expose night-light as a color-mode value with the no-brightness category hint. That is distinct from any nightlight sequence effect.

  • "night-light" in Light.color_modes — capability check

  • Light.color_mode_hints / color_mode_has_hint() — API category hints

  • set_state(..., color_mode="night-light") — omit brightness; select mode before power when turning on from off (aborting if that PUT fails); never send a color-mode change with turn-off. Leave night-light with a separate set_state(..., color_mode=...) while on, or set_state(on=False).

Dual-channel RGB+WW fixtures

Fixtures with separate color and white brightness channels (RGBCW strips, flushmounts, and similar) always stay one combined Light. Capability is detected from the device; aioafero does not split color/white into separate light resources. Integrations that want dual entities create them themselves.

Combined fixtures expose:

  • Light.channels — map of instance name → LightChannel (brightness + on)

  • Light.is_dual_channel

  • Light.channel_brightness(name) / Light.channel_on(name)

  • Light.dimming — overall brightness (usually primary)

Color/white toggles are tracked on Light.channels only — they are not cloned into Switch resources.

See is_dual_channel_rgb_fixture. True multi-zone fixtures (main/trim) still split into separate lights; see get_split_instances.

Color modes: Afero exposes color-mode values such as color, white, sequence, and (on these fixtures) mixed. mixed is a single color-mode controller that keeps both the RGB and white drivers active together — not a separate HA entity, and not the same idea as is_dual_channel (which describes the hardware: independent color/white brightness and toggles).

Writing: set_state routes dimming by command context on combined fixtures (RGB → color, CCT → white). Pass channel="color"|"white" to toggle that channel (instead of primary power) and to route brightness to that channel when color_mode is omitted. Turning a channel off moves color-mode to the remaining channel when one is still on (so leaving mixed becomes exclusive color or white). Exclusive color / white color-mode requests resolve to mixed when another channel is already on (LightChannel.on is True), so the PUT does not shut off the other driver. Unknown channel values are ignored (with a log) rather than falling through to primary power.

Controller

class aioafero.v1.controllers.light.LightController(bridge: AferoBridgeV1)[source]

Bases: BaseResourcesController[Light]

Light devices on bridge.lights (including split zones).

Parameters:

bridge (AferoBridgeV1)

ITEM_CLS

alias of Light

async turn_on(device_id: str) → None[source]

Turn on the light.

Parameters:

device_id (str) – Device ID from this controller.

Return type:

None

async turn_off(device_id: str) → None[source]

Turn off the light.

Parameters:

device_id (str) – Device ID from this controller.

Return type:

None

async set_color_temperature(device_id: str, temperature: int) → None[source]

Set color temperature or white mode when CCT is unavailable.

Parameters:
  • device_id (str) – Device ID from this controller.

  • temperature (int) – Color temperature in kelvin.

Return type:

None

async set_white(device_id: str, *, on: bool | None = True, brightness: int | None = None) → None[source]

Set white mode without a color-temperature function.

Parameters:
  • device_id (str) – Device ID from this controller.

  • on (bool | None) – Power state (defaults to True).

  • brightness (int | None) – Brightness percentage when on is True.

Return type:

None

async set_brightness(device_id: str, brightness: int) → None[source]

Set brightness, turning the light on if needed.

Parameters:
  • device_id (str) – Device ID from this controller.

  • brightness (int) – Brightness percentage.

Return type:

None

async set_rgb(device_id: str, red: int, green: int, blue: int) → None[source]

Set RGB color, turning the light on if needed.

Parameters:
  • device_id (str) – Device ID from this controller.

  • red (int) – Red channel 0–255.

  • green (int) – Green channel 0–255.

  • blue (int) – Blue channel 0–255.

Return type:

None

async set_effect(device_id: str, effect: str) → None[source]

Set a color sequence effect, turning the light on if needed.

Parameters:
  • device_id (str) – Device ID from this controller.

  • effect (str) – Effect name from the model’s effect.effects list.

Return type:

None

async initialize_elem(afero_device: AferoDevice) → Light[source]

Initialize the element.

Parameters:

afero_device (AferoDevice) – Afero Device that contains the updated states

Returns:

Newly initialized resource

Return type:

Light

async update_elem(afero_device: AferoDevice) → set[source]

Update the Light with the latest API data.

Parameters:

afero_device (AferoDevice) – Afero Device that contains the updated states

Returns:

States that have been modified

Return type:

set

async update_elem_color(cur_item: Light, color_seq_states: dict[str | None, AferoState]) → set[source]

Perform the update for effects.

Parameters:
Return type:

set

async set_state(device_id: str, *, on: bool | None = None, temperature: int | None = None, brightness: int | None = None, color_mode: str | None = None, color: tuple[int, int, int] | None = None, effect: str | None = None, force_white_mode: int | None = None, numbers: dict[tuple[str, str | None], float] | None = None, channel: str | None = None) → None[source]

Update light state in the cloud.

Parameters:
  • device_id (str) – Device ID from this controller.

  • on (bool | None) – Power state.

  • temperature (int | None) – Color temperature in kelvin.

  • brightness (int | None) – Brightness percentage.

  • color_mode (str | None) – API color mode (white, color, sequence, night-light, etc.).

  • color (tuple[int, int, int] | None) – RGB tuple (red, green, blue).

  • effect (str | None) – Named color sequence effect.

  • force_white_mode (int | None) – Brightness to apply after forcing white mode.

  • numbers (dict[tuple[str, str | None], float] | None) – Number features keyed by (functionClass, functionInstance).

  • channel (str | None) – When set, target that dual-channel instance (color / white): on uses the channel toggle, and brightness is routed to that channel when color_mode is omitted. Turning a channel off also moves color-mode to the remaining channel when one is still on. Unknown channel names are ignored (logged) and do not fall through to primary power.

Return type:

None

no-brightness modes omit brightness and, when turning on from off, select the mode before power (aborting if that PUT fails). Turn-off never includes a color-mode change.

__contains__(device_id: str) → bool

Return bool if device_id is in items.

Parameters:

device_id (str)

Return type:

bool

__getitem__(device_id: str) → AferoResource

Get item by device_id.

Parameters:

device_id (str)

Return type:

AferoResource

__init__(bridge: AferoBridgeV1) → None

Initialize instance.

Parameters:

bridge (AferoBridgeV1)

Return type:

None

__iter__() → Iterator

Iterate items.

Return type:

Iterator

async emit_to_subscribers(evt_type: EventType, item_id: str, item: AferoResource)

Emit updates to subscribers.

Parameters:
  • evt_type (EventType) – Type of event

  • item_id (str) – ID of the item

  • item (AferoResource) – Item to emit to subscribers

generate_update_dev(device_id: str, states: list[AferoState]) → AferoDevice

Generate update data for the event controller.

Parameters:
Return type:

AferoDevice

get_device(device_id: str) → AferoResource

Return the current model for a tracked device.

Parameters:

device_id (str) – Device ID on this controller (split or parent metadevice ID).

Returns:

Resource model with parsed feature state.

Raises:

DeviceNotFound – If device_id is not tracked by this controller.

Return type:

AferoResource

get_filtered_devices(initial_data: list[dict]) → list[AferoDevice]

Determine devices that align to the controller.

Parameters:

initial_data (list[dict])

Return type:

list[AferoDevice]

async initialize() → None

Initialize controller the controller.

Initialization process should only occur once. During this process, it will subscribe to all updates for the given resources and register any device split callbacks for the event controller.

Return type:

None

async initialize_number(func_def: dict, state: AferoState) → tuple[tuple[str, str | None], NumbersFeature] | None

Initialize a number from the provided data.

Parameters:
Return type:

tuple[tuple[str, str | None], NumbersFeature] | None

async initialize_select(functions: list[dict], state: AferoState) → tuple[tuple[str, str | None], SelectFeature] | None

Initialize a select from the provided data.

Parameters:
Return type:

tuple[tuple[str, str | None], SelectFeature] | None

async initialize_sensor(state: AferoState, child_id: str) → AferoSensor | AferoBinarySensor | None

Initialize the sensor.

Parameters:
  • state (AferoState) – State to update

  • child_id (str) – device_id of the parent device

Return type:

AferoSensor | AferoBinarySensor | None

property initialized: bool

Determine if the controller has been initialized.

property items: list[AferoResource]

Return all items for this resource.

async split_sensor_data(state: AferoState) → tuple[Any, str | None]

Split the sensor value and return a tuple of the sensor value and key.

Parameters:

state (AferoState)

Return type:

tuple[Any, str | None]

subscribe(callback: Callable[[EventType, dict | None], None], id_filter: str | tuple[str] | None = None, event_filter: EventType | tuple[EventType] | None = None) → Callable

Subscribe to status changes for this resource type.

Parameters:
  • callback (Callable[[EventType, dict | None], None]) – callback function to call when an event emits.

  • id_filter (str | tuple[str] | None) – Optionally provide resource ID(s) to filter events for.

  • event_filter (EventType | tuple[EventType] | None) – Optionally provide EventType(s) as filter.

Returns:

function to unsubscribe.

Return type:

Callable

property subscribers: dict[str, list[tuple[Callable[[EventType, dict | None], None], tuple[EventType] | None]]]

Get all subscribers aligned to this controller.

async update(device_id: str, obj_in: AferoResource | None = None, states: list[dict] | None = None, send_duplicate_states: bool = False) → ClientResponse | None

Update Afero IoT with the new data.

Parameters:
  • device_id (str) – Afero IoT Device ID

  • obj_in (AferoResource | None) – Afero IoT Resource elements to change

  • states (list[dict] | None) – States to manually set

  • send_duplicate_states (bool) – Send all states, regardless if there’s been a change

Return type:

ClientResponse | None

async update_afero_api(device_id: str, states: list[dict]) → ClientResponse | bool

Update Afero IoT API with the new states.

Parameters:
  • device_id (str) – Afero IoT Device ID

  • states (list[dict]) – States to manually set

Returns:

Response if successful, False otherwise.

Return type:

ClientResponse | bool

async update_number(state: AferoState, cur_item: AferoResource) → str | None

Update the number if its tracked and a change has been detected.

Parameters:
  • state (AferoState) – State to update

  • cur_item (AferoResource) – Current item to update

Returns:

Identifier of the number that was updated or None

Return type:

str | None

async update_select(state: AferoState, cur_item: AferoResource) → str | None

Update the select if its tracked and a change has been detected.

Parameters:
  • state (AferoState) – State to update

  • cur_item (AferoResource) – Current item to update

Returns:

Identifier of the select that was updated or None

Return type:

str | None

async update_sensor(state: AferoState, cur_item: AferoResource) → str | None

Update the sensor if its tracked and a change has been detected.

Parameters:
  • state (AferoState) – State to update

  • cur_item (AferoResource) – Current item to update

Returns:

Identifier of the sensor that was updated or None

Return type:

str | None

Model

class aioafero.v1.models.light.LightChannel(brightness: int | None = None, on: bool | None = None)[source]

Bases: object

Per-channel brightness/on for a dual-channel light.

Parameters:
  • brightness (int | None)

  • on (bool | None)

__init__(brightness: int | None = None, on: bool | None = None) → None
Parameters:
  • brightness (int | None)

  • on (bool | None)

Return type:

None

class aioafero.v1.models.light.Light(*, _id: str, available: bool, device_information: ~aioafero.v1.models.resource.DeviceInformation = <factory>, split: ~aioafero.device.SplitDeviceId | None = None, numbers: dict[tuple[str, str | None], ~aioafero.v1.models.features.NumbersFeature] | None = <factory>, selects: dict[tuple[str, str | None], ~aioafero.v1.models.features.SelectFeature] | None = <factory>, sensors: dict[str, ~aioafero.v1.models.sensor.AferoSensor] = <factory>, binary_sensors: dict[str, ~aioafero.v1.models.sensor.AferoBinarySensor] = <factory>, type: ~aioafero.v1.models.resource.ResourceTypes = ResourceTypes.LIGHT, on: ~aioafero.v1.models.features.OnFeature | None = None, color: ~aioafero.v1.models.features.ColorFeature | None = None, color_mode: ~aioafero.v1.models.features.ColorModeFeature | None = None, color_modes: list[str] | None = None, color_mode_hints: dict[str, list[str]] | None = None, color_temperature: ~aioafero.v1.models.features.ColorTemperatureFeature | None = None, dimming: ~aioafero.v1.models.features.DimmingFeature | None = None, effect: ~aioafero.v1.models.features.EffectFeature | None = None, supports_white: bool = False, channels: dict[str, ~aioafero.v1.models.light.LightChannel] = <factory>)[source]

Bases: StandardMixin

Representation of an Afero Light.

Parameters:
__post_init__()[source]

Determine if white only is supported.

property supports_color: bool

Return if this light supports color control.

property supports_color_temperature: bool

Return if this light supports color_temperature control.

property supports_color_white: bool

Return if this light supports setting white.

color_mode_has_hint(mode: str, hint: str) → bool[source]

Return True when mode carries the given API category hint.

Parameters:
Return type:

bool

property supports_dimming: bool

Return if this light supports brightness control.

property supports_effects: bool

Return if this light supports brightness control.

property supports_on

If the light can be toggled on or off.

property is_on: bool

Return bool if light is currently powered on.

property brightness: float

Return current brightness of light.

property is_dual_channel: bool

Return True when color and white channels are both present.

channel_brightness(channel: str) → float | None[source]

Return brightness for a channel, if known.

Parameters:

channel (str)

Return type:

float | None

channel_on(channel: str) → bool | None[source]

Return on/off for a channel toggle, if known.

Parameters:

channel (str)

Return type:

bool | None

feature_for_update_comparison(field_name: str, put_feature: object | None) → object | None[source]

Compare channel toggles/dimming against channels, not primary.

Parameters:
  • field_name (str)

  • put_feature (object | None)

Return type:

object | None

__init__(*, _id: str, available: bool, device_information: ~aioafero.v1.models.resource.DeviceInformation = <factory>, split: ~aioafero.device.SplitDeviceId | None = None, numbers: dict[tuple[str, str | None], ~aioafero.v1.models.features.NumbersFeature] | None = <factory>, selects: dict[tuple[str, str | None], ~aioafero.v1.models.features.SelectFeature] | None = <factory>, sensors: dict[str, ~aioafero.v1.models.sensor.AferoSensor] = <factory>, binary_sensors: dict[str, ~aioafero.v1.models.sensor.AferoBinarySensor] = <factory>, type: ~aioafero.v1.models.resource.ResourceTypes = ResourceTypes.LIGHT, on: ~aioafero.v1.models.features.OnFeature | None = None, color: ~aioafero.v1.models.features.ColorFeature | None = None, color_mode: ~aioafero.v1.models.features.ColorModeFeature | None = None, color_modes: list[str] | None = None, color_mode_hints: dict[str, list[str]] | None = None, color_temperature: ~aioafero.v1.models.features.ColorTemperatureFeature | None = None, dimming: ~aioafero.v1.models.features.DimmingFeature | None = None, effect: ~aioafero.v1.models.features.EffectFeature | None = None, supports_white: bool = False, channels: dict[str, ~aioafero.v1.models.light.LightChannel] = <factory>) → None
Parameters:
Return type:

None