Skip to content
Merged
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
11 changes: 6 additions & 5 deletions aioesphomeapi/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -987,8 +987,8 @@ message ListEntitiesClimateResponse {
string name = 3;
reserved 4; // Deprecated: was string unique_id

bool supports_current_temperature = 5;
bool supports_two_point_target_temperature = 6;
bool supports_current_temperature = 5; // Deprecated: use feature_flags
bool supports_two_point_target_temperature = 6; // Deprecated: use feature_flags
repeated ClimateMode supported_modes = 7 [(container_pointer) = "std::set<climate::ClimateMode>"];
float visual_min_temperature = 8;
float visual_max_temperature = 9;
Expand All @@ -997,7 +997,7 @@ message ListEntitiesClimateResponse {
// is if CLIMATE_PRESET_AWAY exists is supported_presets
// Deprecated in API version 1.5
bool legacy_supports_away = 11 [deprecated=true];
bool supports_action = 12;
bool supports_action = 12; // Deprecated: use feature_flags
repeated ClimateFanMode supported_fan_modes = 13 [(container_pointer) = "std::set<climate::ClimateFanMode>"];
repeated ClimateSwingMode supported_swing_modes = 14 [(container_pointer) = "std::set<climate::ClimateSwingMode>"];
repeated string supported_custom_fan_modes = 15 [(container_pointer) = "std::set"];
Expand All @@ -1007,11 +1007,12 @@ message ListEntitiesClimateResponse {
string icon = 19 [(field_ifdef) = "USE_ENTITY_ICON"];
EntityCategory entity_category = 20;
float visual_current_temperature_step = 21;
bool supports_current_humidity = 22;
bool supports_target_humidity = 23;
bool supports_current_humidity = 22; // Deprecated: use feature_flags
bool supports_target_humidity = 23; // Deprecated: use feature_flags
float visual_min_humidity = 24;
float visual_max_humidity = 25;
uint32 device_id = 26 [(field_ifdef) = "USE_DEVICES"];
uint32 feature_flags = 27;
}
message ClimateStateResponse {
option (id) = 47;
Expand Down
512 changes: 256 additions & 256 deletions aioesphomeapi/api_pb2.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion aioesphomeapi/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class ConnectionState(enum.Enum):
def _make_hello_request(client_info: str) -> HelloRequest:
"""Make a HelloRequest."""
return HelloRequest(
client_info=client_info, api_version_major=1, api_version_minor=12
client_info=client_info, api_version_major=1, api_version_minor=13
)


Expand Down
27 changes: 27 additions & 0 deletions aioesphomeapi/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ class BluetoothProxyFeature(enum.IntFlag):
FEATURE_STATE_AND_MODE = 1 << 6


class ClimateFeature(enum.IntFlag):
SUPPORTS_CURRENT_TEMPERATURE = 1 << 0
SUPPORTS_TWO_POINT_TARGET_TEMPERATURE = 1 << 1
REQUIRES_TWO_POINT_TARGET_TEMPERATURE = 1 << 2
SUPPORTS_CURRENT_HUMIDITY = 1 << 3
SUPPORTS_TARGET_HUMIDITY = 1 << 4
SUPPORTS_ACTION = 1 << 5


class BluetoothProxySubscriptionFlag(enum.IntFlag):
RAW_ADVERTISEMENTS = 1 << 0

Expand Down Expand Up @@ -643,6 +652,7 @@ class ClimatePreset(APIIntEnum):

@_frozen_dataclass_decorator
class ClimateInfo(EntityInfo):
feature_flags: int = 0
supports_current_temperature: bool = False
supports_two_point_target_temperature: bool = False
supported_modes: list[ClimateMode] = converter_field(
Expand Down Expand Up @@ -682,6 +692,23 @@ class ClimateInfo(EntityInfo):
visual_min_humidity: float = 0
visual_max_humidity: float = 0

def supported_feature_flags_compat(self, api_version: APIVersion) -> int:
if api_version < APIVersion(1, 13):
flags: int = 0
if self.supports_current_temperature:
flags |= ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
if self.supports_two_point_target_temperature:
# Use REQUIRES_TWO_POINT_TARGET_TEMPERATURE to mimic previous behavior
flags |= ClimateFeature.REQUIRES_TWO_POINT_TARGET_TEMPERATURE
if self.supports_current_humidity:
flags |= ClimateFeature.SUPPORTS_CURRENT_HUMIDITY
if self.supports_target_humidity:
flags |= ClimateFeature.SUPPORTS_TARGET_HUMIDITY
if self.supports_action:
flags |= ClimateFeature.SUPPORTS_ACTION
return flags
return self.feature_flags

def supported_presets_compat(self, api_version: APIVersion) -> list[ClimatePreset]:
if api_version < APIVersion(1, 5):
return (
Expand Down
40 changes: 40 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
BluetoothScannerStateResponse as BluetoothScannerStateResponseModel,
ButtonInfo,
CameraInfo,
ClimateFeature,
ClimateInfo,
ClimatePreset,
ClimateState,
Expand Down Expand Up @@ -335,6 +336,45 @@ def test_cover_state_legacy_state(state, version, out):
assert state.is_closed(APIVersion(*version)) is out


@pytest.mark.parametrize(
"state, version, out",
[
(
ClimateInfo(supports_current_temperature=True),
(1, 12),
ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE,
),
(
ClimateInfo(supports_two_point_target_temperature=True),
(1, 12),
ClimateFeature.REQUIRES_TWO_POINT_TARGET_TEMPERATURE,
),
(
ClimateInfo(supports_current_humidity=True),
(1, 12),
ClimateFeature.SUPPORTS_CURRENT_HUMIDITY,
),
(
ClimateInfo(supports_target_humidity=True),
(1, 12),
ClimateFeature.SUPPORTS_TARGET_HUMIDITY,
),
(ClimateInfo(supports_action=True), (1, 12), ClimateFeature.SUPPORTS_ACTION),
(
ClimateInfo(
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
| ClimateFeature.SUPPORTS_ACTION
),
(1, 13),
ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
| ClimateFeature.SUPPORTS_ACTION,
),
],
)
def test_climate_info_supported_feature_flags_compat(state, version, out):
assert state.supported_feature_flags_compat(APIVersion(*version)) == out


@pytest.mark.parametrize(
"state, version, out",
[
Expand Down