mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2024-12-21 16:37:41 +01:00
Color mode implementation (#74)
Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
parent
f90ffcf3b8
commit
32d2df8e24
@ -353,6 +353,18 @@ message FanCommandRequest {
|
||||
}
|
||||
|
||||
// ==================== LIGHT ====================
|
||||
enum ColorMode {
|
||||
COLOR_MODE_UNKNOWN = 0;
|
||||
COLOR_MODE_ON_OFF = 1;
|
||||
COLOR_MODE_BRIGHTNESS = 2;
|
||||
COLOR_MODE_WHITE = 7;
|
||||
COLOR_MODE_COLOR_TEMPERATURE = 11;
|
||||
COLOR_MODE_COLD_WARM_WHITE = 19;
|
||||
COLOR_MODE_RGB = 35;
|
||||
COLOR_MODE_RGB_WHITE = 39;
|
||||
COLOR_MODE_RGB_COLOR_TEMPERATURE = 47;
|
||||
COLOR_MODE_RGB_COLD_WARM_WHITE = 51;
|
||||
}
|
||||
message ListEntitiesLightResponse {
|
||||
option (id) = 15;
|
||||
option (source) = SOURCE_SERVER;
|
||||
@ -363,10 +375,12 @@ message ListEntitiesLightResponse {
|
||||
string name = 3;
|
||||
string unique_id = 4;
|
||||
|
||||
bool supports_brightness = 5;
|
||||
bool supports_rgb = 6;
|
||||
bool supports_white_value = 7;
|
||||
bool supports_color_temperature = 8;
|
||||
repeated ColorMode supported_color_modes = 12;
|
||||
// next four supports_* are for legacy clients, newer clients should use color modes
|
||||
bool legacy_supports_brightness = 5 [deprecated=true];
|
||||
bool legacy_supports_rgb = 6 [deprecated=true];
|
||||
bool legacy_supports_white_value = 7 [deprecated=true];
|
||||
bool legacy_supports_color_temperature = 8 [deprecated=true];
|
||||
float min_mireds = 9;
|
||||
float max_mireds = 10;
|
||||
repeated string effects = 11;
|
||||
@ -380,11 +394,15 @@ message LightStateResponse {
|
||||
fixed32 key = 1;
|
||||
bool state = 2;
|
||||
float brightness = 3;
|
||||
ColorMode color_mode = 11;
|
||||
float color_brightness = 10;
|
||||
float red = 4;
|
||||
float green = 5;
|
||||
float blue = 6;
|
||||
float white = 7;
|
||||
float color_temperature = 8;
|
||||
float cold_white = 12;
|
||||
float warm_white = 13;
|
||||
string effect = 9;
|
||||
}
|
||||
message LightCommandRequest {
|
||||
@ -398,6 +416,10 @@ message LightCommandRequest {
|
||||
bool state = 3;
|
||||
bool has_brightness = 4;
|
||||
float brightness = 5;
|
||||
bool has_color_mode = 22;
|
||||
ColorMode color_mode = 23;
|
||||
bool has_color_brightness = 20;
|
||||
float color_brightness = 21;
|
||||
bool has_rgb = 6;
|
||||
float red = 7;
|
||||
float green = 8;
|
||||
@ -406,6 +428,10 @@ message LightCommandRequest {
|
||||
float white = 11;
|
||||
bool has_color_temperature = 12;
|
||||
float color_temperature = 13;
|
||||
bool has_cold_white = 24;
|
||||
float cold_white = 25;
|
||||
bool has_warm_white = 26;
|
||||
float warm_white = 27;
|
||||
bool has_transition_length = 14;
|
||||
uint32 transition_length = 15;
|
||||
bool has_flash_length = 16;
|
||||
|
@ -1,9 +1,8 @@
|
||||
# type: ignore
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: api_options.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
@ -22,7 +21,8 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
package='',
|
||||
syntax='proto2',
|
||||
serialized_options=None,
|
||||
serialized_pb=_b('\n\x11\x61pi_options.proto\x1a google/protobuf/descriptor.proto\"\x06\n\x04void*F\n\rAPISourceType\x12\x0f\n\x0bSOURCE_BOTH\x10\x00\x12\x11\n\rSOURCE_SERVER\x10\x01\x12\x11\n\rSOURCE_CLIENT\x10\x02:E\n\x16needs_setup_connection\x12\x1e.google.protobuf.MethodOptions\x18\x8e\x08 \x01(\x08:\x04true:C\n\x14needs_authentication\x12\x1e.google.protobuf.MethodOptions\x18\x8f\x08 \x01(\x08:\x04true:/\n\x02id\x12\x1f.google.protobuf.MessageOptions\x18\x8c\x08 \x01(\r:\x01\x30:M\n\x06source\x12\x1f.google.protobuf.MessageOptions\x18\x8d\x08 \x01(\x0e\x32\x0e.APISourceType:\x0bSOURCE_BOTH:/\n\x05ifdef\x12\x1f.google.protobuf.MessageOptions\x18\x8e\x08 \x01(\t:3\n\x03log\x12\x1f.google.protobuf.MessageOptions\x18\x8f\x08 \x01(\x08:\x04true:9\n\x08no_delay\x12\x1f.google.protobuf.MessageOptions\x18\x90\x08 \x01(\x08:\x05\x66\x61lse')
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\x11\x61pi_options.proto\x1a google/protobuf/descriptor.proto\"\x06\n\x04void*F\n\rAPISourceType\x12\x0f\n\x0bSOURCE_BOTH\x10\x00\x12\x11\n\rSOURCE_SERVER\x10\x01\x12\x11\n\rSOURCE_CLIENT\x10\x02:E\n\x16needs_setup_connection\x12\x1e.google.protobuf.MethodOptions\x18\x8e\x08 \x01(\x08:\x04true:C\n\x14needs_authentication\x12\x1e.google.protobuf.MethodOptions\x18\x8f\x08 \x01(\x08:\x04true:/\n\x02id\x12\x1f.google.protobuf.MessageOptions\x18\x8c\x08 \x01(\r:\x01\x30:M\n\x06source\x12\x1f.google.protobuf.MessageOptions\x18\x8d\x08 \x01(\x0e\x32\x0e.APISourceType:\x0bSOURCE_BOTH:/\n\x05ifdef\x12\x1f.google.protobuf.MessageOptions\x18\x8e\x08 \x01(\t:3\n\x03log\x12\x1f.google.protobuf.MessageOptions\x18\x8f\x08 \x01(\x08:\x04true:9\n\x08no_delay\x12\x1f.google.protobuf.MessageOptions\x18\x90\x08 \x01(\x08:\x05\x66\x61lse'
|
||||
,
|
||||
dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
|
||||
|
||||
@ -31,19 +31,23 @@ _APISOURCETYPE = _descriptor.EnumDescriptor(
|
||||
full_name='APISourceType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SOURCE_BOTH', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SOURCE_SERVER', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SOURCE_CLIENT', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
@ -64,7 +68,7 @@ needs_setup_connection = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=True,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
NEEDS_AUTHENTICATION_FIELD_NUMBER = 1039
|
||||
needs_authentication = _descriptor.FieldDescriptor(
|
||||
name='needs_authentication', full_name='needs_authentication', index=1,
|
||||
@ -72,7 +76,7 @@ needs_authentication = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=True,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
ID_FIELD_NUMBER = 1036
|
||||
id = _descriptor.FieldDescriptor(
|
||||
name='id', full_name='id', index=2,
|
||||
@ -80,7 +84,7 @@ id = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
SOURCE_FIELD_NUMBER = 1037
|
||||
source = _descriptor.FieldDescriptor(
|
||||
name='source', full_name='source', index=3,
|
||||
@ -88,15 +92,15 @@ source = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
IFDEF_FIELD_NUMBER = 1038
|
||||
ifdef = _descriptor.FieldDescriptor(
|
||||
name='ifdef', full_name='ifdef', index=4,
|
||||
number=1038, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
LOG_FIELD_NUMBER = 1039
|
||||
log = _descriptor.FieldDescriptor(
|
||||
name='log', full_name='log', index=5,
|
||||
@ -104,7 +108,7 @@ log = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=True,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
NO_DELAY_FIELD_NUMBER = 1040
|
||||
no_delay = _descriptor.FieldDescriptor(
|
||||
name='no_delay', full_name='no_delay', index=6,
|
||||
@ -112,7 +116,7 @@ no_delay = _descriptor.FieldDescriptor(
|
||||
has_default_value=True, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=True, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR)
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)
|
||||
|
||||
|
||||
_VOID = _descriptor.Descriptor(
|
||||
@ -121,6 +125,7 @@ _VOID = _descriptor.Descriptor(
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
],
|
||||
extensions=[
|
||||
@ -149,11 +154,11 @@ DESCRIPTOR.extensions_by_name['log'] = log
|
||||
DESCRIPTOR.extensions_by_name['no_delay'] = no_delay
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
void = _reflection.GeneratedProtocolMessageType('void', (_message.Message,), dict(
|
||||
DESCRIPTOR = _VOID,
|
||||
__module__ = 'api_options_pb2'
|
||||
void = _reflection.GeneratedProtocolMessageType('void', (_message.Message,), {
|
||||
'DESCRIPTOR' : _VOID,
|
||||
'__module__' : 'api_options_pb2'
|
||||
# @@protoc_insertion_point(class_scope:void)
|
||||
))
|
||||
})
|
||||
_sym_db.RegisterMessage(void)
|
||||
|
||||
google_dot_protobuf_dot_descriptor__pb2.MethodOptions.RegisterExtension(needs_setup_connection)
|
||||
|
File diff suppressed because one or more lines are too long
@ -88,6 +88,7 @@ from .model import (
|
||||
FanState,
|
||||
HomeassistantServiceCall,
|
||||
LegacyCoverCommand,
|
||||
LightColorMode,
|
||||
LightInfo,
|
||||
LightState,
|
||||
LogLevel,
|
||||
@ -430,9 +431,13 @@ class APIClient:
|
||||
key: int,
|
||||
state: Optional[bool] = None,
|
||||
brightness: Optional[float] = None,
|
||||
color_mode: Optional[LightColorMode] = None,
|
||||
color_brightness: Optional[float] = None,
|
||||
rgb: Optional[Tuple[float, float, float]] = None,
|
||||
white: Optional[float] = None,
|
||||
color_temperature: Optional[float] = None,
|
||||
cold_white: Optional[float] = None,
|
||||
warm_white: Optional[float] = None,
|
||||
transition_length: Optional[float] = None,
|
||||
flash_length: Optional[float] = None,
|
||||
effect: Optional[str] = None,
|
||||
@ -447,6 +452,12 @@ class APIClient:
|
||||
if brightness is not None:
|
||||
req.has_brightness = True
|
||||
req.brightness = brightness
|
||||
if color_mode is not None:
|
||||
req.has_color_mode = True
|
||||
req.color_mode = color_mode
|
||||
if color_brightness is not None:
|
||||
req.has_color_brightness = True
|
||||
req.color_brightness = color_brightness
|
||||
if rgb is not None:
|
||||
req.has_rgb = True
|
||||
req.red = rgb[0]
|
||||
@ -458,6 +469,12 @@ class APIClient:
|
||||
if color_temperature is not None:
|
||||
req.has_color_temperature = True
|
||||
req.color_temperature = color_temperature
|
||||
if cold_white is not None:
|
||||
req.has_cold_white = True
|
||||
req.cold_white = cold_white
|
||||
if warm_white is not None:
|
||||
req.has_warm_white = True
|
||||
req.warm_white = warm_white
|
||||
if transition_length is not None:
|
||||
req.has_transition_length = True
|
||||
req.transition_length = int(round(transition_length * 1000))
|
||||
|
@ -207,26 +207,75 @@ class FanState(EntityState):
|
||||
|
||||
|
||||
# ==================== LIGHT ====================
|
||||
class LightColorMode(APIIntEnum):
|
||||
UNKNOWN = 0
|
||||
ON_OFF = 1
|
||||
BRIGHTNESS = 2
|
||||
WHITE = 7
|
||||
COLOR_TEMPERATURE = 11
|
||||
COLD_WARM_WHITE = 19
|
||||
RGB = 35
|
||||
RGB_WHITE = 39
|
||||
RGB_COLOR_TEMPERATURE = 47
|
||||
RGB_COLD_WARM_WHITE = 51
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LightInfo(EntityInfo):
|
||||
supports_brightness: bool = False
|
||||
supports_rgb: bool = False
|
||||
supports_white_value: bool = False
|
||||
supports_color_temperature: bool = False
|
||||
supported_color_modes: List[LightColorMode] = converter_field(
|
||||
default_factory=list, converter=LightColorMode.convert_list
|
||||
)
|
||||
min_mireds: float = 0.0
|
||||
max_mireds: float = 0.0
|
||||
effects: List[str] = converter_field(default_factory=list, converter=list)
|
||||
|
||||
# deprecated, do not use
|
||||
legacy_supports_brightness: bool = False
|
||||
legacy_supports_rgb: bool = False
|
||||
legacy_supports_white_value: bool = False
|
||||
legacy_supports_color_temperature: bool = False
|
||||
|
||||
def supported_color_modes_compat(
|
||||
self, api_version: APIVersion
|
||||
) -> List[LightColorMode]:
|
||||
if api_version < APIVersion(1, 6):
|
||||
key = (
|
||||
self.legacy_supports_brightness,
|
||||
self.legacy_supports_rgb,
|
||||
self.legacy_supports_white_value,
|
||||
self.legacy_supports_color_temperature,
|
||||
)
|
||||
# map legacy flags to color modes,
|
||||
# key: (brightness, rgb, white, color_temp)
|
||||
modes_map = {
|
||||
(False, False, False, False): [LightColorMode.ON_OFF],
|
||||
(True, False, False, False): [LightColorMode.BRIGHTNESS],
|
||||
(True, False, False, True): [LightColorMode.COLOR_TEMPERATURE],
|
||||
(True, True, False, False): [LightColorMode.RGB],
|
||||
(True, True, True, False): [LightColorMode.RGB_WHITE],
|
||||
(True, True, True, True): [LightColorMode.RGB_COLOR_TEMPERATURE],
|
||||
}
|
||||
|
||||
return modes_map[key] if key in modes_map else []
|
||||
|
||||
return self.supported_color_modes
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LightState(EntityState):
|
||||
state: bool = False
|
||||
brightness: float = 0.0
|
||||
color_mode: Optional[LightColorMode] = converter_field(
|
||||
default=LightColorMode.UNKNOWN, converter=LightColorMode.convert
|
||||
)
|
||||
color_brightness: float = 0.0
|
||||
red: float = 0.0
|
||||
green: float = 0.0
|
||||
blue: float = 0.0
|
||||
white: float = 0.0
|
||||
color_temperature: float = 0.0
|
||||
cold_white: float = 0.0
|
||||
warm_white: float = 0.0
|
||||
effect: str = ""
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user