Skip to content

Commit c93dea7

Browse files
committed
suppoer brew strength and services
1 parent 2401567 commit c93dea7

File tree

14 files changed

+201
-523
lines changed

14 files changed

+201
-523
lines changed

custom_components/smarter/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
)
6262
)
6363

64-
SERVICE_SCHEMA_QUICK_BOIL = cv.make_entity_service_schema({})
64+
SERVICE_SCHEMA_EMPTY = cv.make_entity_service_schema({})
6565
SERVICE_SCHEMA_GET_COMMANDS = cv.make_entity_service_schema({})
6666

6767

custom_components/smarter/devices/smarter_coffee_SMCOF01.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ secondary_entities:
4848
state_class: measurement
4949
setter: set_coffee_strength
5050
range:
51-
min: 0
52-
max: 100
53-
step: 10
51+
min: 20
52+
max: 80
53+
step: 30
5454
- entity: number
5555
translation_key: number_of_cups
5656
unit: "cups"
@@ -76,3 +76,5 @@ secondary_entities:
7676
value: true
7777
- native_value: "Keeping warm"
7878
value: true
79+
- default: true
80+
value: false

custom_components/smarter/devices/smarter_kettle_SMKET01.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,24 @@ secondary_entities:
3737
mapping:
3838
- native_value: "Boiling"
3939
value: true
40+
- default: true
41+
value: false
4042
- entity: binary_sensor
4143
translation_key: is_cooling
4244
state_field: "state"
4345
mapping:
4446
- native_value: "Cooling"
4547
value: true
48+
- default: true
49+
value: false
4650
- entity: binary_sensor
4751
translation_key: is_keep_warm
4852
state_field: "state"
4953
mapping:
5054
- native_value: "Keeping warm"
5155
value: true
56+
- default: true
57+
value: false
5258
- entity: binary_sensor
5359
translation_key: kettle_is_present
5460
- entity: switch
@@ -67,6 +73,12 @@ secondary_entities:
6773
value: true
6874
- native_value: "Keeping warm"
6975
value: true
76+
- default: true
77+
value: false
78+
- entity: switch
79+
translation_key: formula_mode_enable
80+
icon: "mdi:baby-bottle"
81+
setter: set_formula_mode_enable
7082
- entity: number
7183
translation_key: boil_temperature
7284
unit: C
@@ -78,6 +90,17 @@ secondary_entities:
7890
min: 0
7991
max: 100
8092
step: 1
93+
- entity: number
94+
translation_key: formula_mode_temperature
95+
unit: C
96+
setter: set_formula_mode_temperature
97+
device_class: temperature
98+
state_class: measurement
99+
icon: "mdi:thermometer"
100+
range:
101+
min: 0
102+
max: 100
103+
step: 1
81104
- entity: number
82105
translation_key: keep_warm_time
83106
unit: minutes

custom_components/smarter/entity.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
from __future__ import annotations
44

55
import logging
6-
from typing import Protocol
6+
from collections.abc import Callable
77

88
from homeassistant.const import UnitOfTemperature
99
from homeassistant.core import callback
1010
from homeassistant.helpers.device_registry import DeviceInfo
11-
from homeassistant.helpers.entity import EntityDescription
11+
from homeassistant.helpers.entity import Entity, EntityDescription
1212
from propcache import cached_property
1313
from smarter_client.managed_devices.base import BaseDevice
1414

@@ -23,15 +23,15 @@
2323
_LOGGER = logging.getLogger(__name__)
2424

2525

26-
class SmarterEntityConstructor(Protocol):
27-
"""Type representing constructor of all Smarter entities."""
26+
# class SmarterEntityConstructor(Protocol):
27+
# """Type representing constructor of all Smarter entities."""
2828

29-
def __init__(self, device: BaseDevice, config: SmarterEntityConfig):
30-
"""Create instance of entity."""
31-
pass
29+
# def __init__(self, device: BaseDevice, config: SmarterEntityConfig):
30+
# """Create instance of entity."""
31+
# pass
3232

3333

34-
class SmarterEntity:
34+
class SmarterEntity(Entity):
3535
"""Representation of a Smarter sensor."""
3636

3737
# _attr_has_entity_name = True
@@ -133,14 +133,43 @@ def available(self) -> bool:
133133
@property
134134
def extra_state_attributes(self):
135135
"""Return extra device attributes associated with entity."""
136-
if not self.config._is_primary:
136+
if not self.config.is_primary:
137137
return {
138138
"device_id": self.device.id,
139139
"kettle_is_present": self.device.status.get("kettle_is_present"),
140140
"calibrated": self.device.status.get("calibrated"),
141141
}
142142
return {**self.device.status}
143143

144+
async def async_send_command(
145+
self,
146+
command_name: str,
147+
command_data_text: str | None = None,
148+
command_data_number: float | None = None,
149+
command_data_boolean: bool | None = None,
150+
):
151+
"""Send command to device."""
152+
# The API requires a `value` to be set. The official client sends `True` if no
153+
# actual value is needed
154+
return await self.hass.async_add_executor_job(
155+
self.device.send_command,
156+
command_name,
157+
command_data_text or command_data_number or command_data_boolean or True,
158+
)
159+
160+
async def async_get_commands(self):
161+
"""
162+
Get list of commands supported by the underlying device.
163+
164+
Returns a list of dictionaries. Each dictionary has `name` and `example` keys.
165+
The value under the `example` key is a dictionary providing information on the
166+
data that can be passed to the command.
167+
168+
Returns:
169+
list[dict["name"|"example]]
170+
"""
171+
return [{"name": command.name, "example": command.example} for command in self.device.device.commands.values()]
172+
144173

145174
# @dataclass(frozen=True, kw_only=True)
146175
# class SmarterEntityDescription(EntityDescription):
@@ -177,3 +206,6 @@ def extra_state_attributes(self):
177206

178207
# get_fn: Callable[[BaseDevice], bool]
179208
# set_fn: Callable[[BaseDevice, Any], None]
209+
210+
211+
SmarterEntityConstructor = Callable[[BaseDevice, SmarterEntityConfig], SmarterEntity]

custom_components/smarter/helpers/base.py

Lines changed: 5 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,107 +2,20 @@
22

33
from __future__ import annotations
44

5-
from abc import abstractmethod
6-
from collections.abc import Awaitable, Callable, Iterable
75
from dataclasses import dataclass
8-
from itertools import chain
96
from typing import Any
107

11-
from homeassistant.components.binary_sensor import BinarySensorEntityDescription
12-
from homeassistant.components.number import NumberEntityDescription
13-
from homeassistant.components.sensor import SensorEntityDescription
14-
from homeassistant.components.switch import SwitchEntityDescription
15-
from homeassistant.const import Platform
16-
from homeassistant.helpers.entity import EntityDescription
178
from homeassistant.helpers.typing import VolSchemaType
18-
from smarter_client.managed_devices.base import BaseDevice
9+
10+
# from smarter_client.managed_devices.base import BaseDevice
1911

2012

2113
@dataclass(frozen=True, kw_only=True)
2214
class ServiceMetadata:
2315
"""Metadata for service registration."""
2416

25-
service_name: str
2617
handler_name: str
18+
service_name: str
19+
command_name: str | None = None
20+
command_data: dict[str, Any] | None = None
2721
schema: VolSchemaType
28-
29-
30-
class DeviceConfig:
31-
"""Represents configuration for a Smarter device."""
32-
33-
@property
34-
@abstractmethod
35-
def device_entity(self) -> SmarterEntityDescription:
36-
"""Get device-level entity associated with this device."""
37-
pass
38-
39-
@property
40-
@abstractmethod
41-
def secondary_entities(self) -> Iterable[SmarterEntityDescription]:
42-
"""Get all non-device-level entities associated with this device."""
43-
pass
44-
45-
@property
46-
@abstractmethod
47-
def service_metadata(self) -> Iterable[ServiceMetadata]:
48-
"""Get metadata for all services associated with this device."""
49-
pass
50-
51-
@property
52-
def all_entities(self) -> Iterable[SmarterEntityDescription]:
53-
"""Get all entities."""
54-
return chain([self.device_entity], self.secondary_entities)
55-
56-
def get_secondary_entities(self, platform: Platform) -> Iterable[SmarterEntityDescription]:
57-
"""Get all non-device-level entities for platform."""
58-
return (entity for entity in self.secondary_entities if entity.platform == platform)
59-
60-
def get_device_entities(self, platform: Platform) -> Iterable[EntityDescription]:
61-
"""Get main device-level entities for target platform."""
62-
return [self.device_entity] if self.device_entity.platform == platform else []
63-
64-
def get_service_metadata(self, platform: Platform) -> Iterable[ServiceMetadata]:
65-
"""Get metadata for services on target platform."""
66-
return self.service_metadata if self.device_entity.platform == platform else []
67-
68-
69-
@dataclass(frozen=True, kw_only=True)
70-
class SmarterEntityDescription(EntityDescription):
71-
"""Smarter entity base description."""
72-
73-
@property
74-
@abstractmethod
75-
def platform(self) -> Platform:
76-
"""Get the platform for this entity."""
77-
raise NotImplementedError()
78-
79-
80-
@dataclass(frozen=True, kw_only=True)
81-
class SmarterSensorEntityDescription(SensorEntityDescription, SmarterEntityDescription):
82-
"""Represent the Smarter sensor entity description."""
83-
84-
platform = Platform.SENSOR
85-
86-
87-
@dataclass(frozen=True, kw_only=True)
88-
class SmarterBinarySensorEntityDescription(SmarterEntityDescription, BinarySensorEntityDescription):
89-
"""Represent the Smarter sensor entity description."""
90-
91-
platform = Platform.BINARY_SENSOR
92-
get_status_field: str
93-
state_on_values: tuple[str | bool]
94-
95-
96-
@dataclass(frozen=True, kw_only=True)
97-
class SmarterSwitchEntityDescription(SwitchEntityDescription):
98-
"""Represent the Smarter sensor entity description."""
99-
100-
get_fn: Callable[[BaseDevice], bool]
101-
set_fn: Callable[[BaseDevice, Any], None]
102-
103-
104-
@dataclass(frozen=True, kw_only=True)
105-
class SmarterNumberEntityDescription(NumberEntityDescription):
106-
"""Class describing Ecobee number entities."""
107-
108-
set_fn: Callable[[BaseDevice, int], Awaitable]

0 commit comments

Comments
 (0)