Skip to content

Commit

Permalink
Dev - merge latest from dev (#158)
Browse files Browse the repository at this point in the history
* Check for cached consumption first

If a Miele device is temporarily disconnected from the Miele cloud while
running, the Miele API returns a "not connected" state for the device. If the
"not running" check is done first, it causes the energy/water consumption to be
reset to 0. This in turn means that the statistics generated by Home Assistant
will be messed up, it will look like more energy/water was consumed than in
reality.

* Fix missing ecoFeedback object

* fixes on capabilities:
- check that signaInfo, signalDoor, signalFailure are supported by device type
- add sensors for drying step (tumble dryer), spinning speed (washer), program phase
- check water/energy sub capability on ecofeedback (tumble dryer has no water consumption)

* fix the coroutine error (#108)

* Bump version

* Switching back to manual versioning

* fix the coroutine error

* warn if unable to delete the cached token
check if authorized before creating a new session

Co-authored-by: sebltm
Co-authored-by: kloknibor <kloknibor@users.noreply.github.com>

* Adding changeable interval

Fixing #112

* Update README.md

* add signalDoor capability to washer, tumble dryer and washer dryer

* adding service to start and stop programs

* Implement binary sensor for mobile start feature in order to allow automations watch this status change (for example to implement Wash2Dry feature)

* Fix null eco feedback returning cached consumption

* Expose only target temperature 0 on washers, washer-dryers, dishwashers

* Fix disconnection of appliance from Miele cloud, by caching consumption and time sensor values

* Keep time sensor value after program end

* Fix time sensor for decreasing timers

* Add battery sensor for robot vacuum cleaner

* Show target temperature 0 as int

* Implement energy/water forecast sensors

* Use new enum for sensor device class

* remove iot_class from hacs.json

* Use rinse hold status as running to avoid messing up energy stats when adding "rinse hold" option on washer / washer-dryer

* Fix fan state sometimes being incorrectly shown as on

---------

Co-authored-by: Sebastian Lövdahl <slovdahl@hibox.fi>
Co-authored-by: mundschenk_at <github@mundschenk.at>
Co-authored-by: Andrea Turri <andrea.turri92@gmail.com>
Co-authored-by: Sébastien Michel <26392528+sebltm@users.noreply.github.com>
Co-authored-by: kloknibor <kloknibor@users.noreply.github.com>
Co-authored-by: Tereza Tomcova <tereza.tomcova@gmail.com>
  • Loading branch information
7 people authored May 25, 2023
1 parent 5a1ef78 commit c33617a
Show file tree
Hide file tree
Showing 9 changed files with 575 additions and 313 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
**/*.pyc
.idea/
*.iml
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ miele:
client_secret: <your Miele ClientSecret>
lang: <optional. en=english, de=german>
cache_path: <optional. where to store the cached access token>
interval: <optional. the interval between miele polling updates>
```

* Restart Home Assistant.
Expand Down
291 changes: 290 additions & 1 deletion custom_components/miele/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,18 @@
DATA_DEVICES = "devices"
DATA_CLIENT = "client"
SERVICE_ACTION = "action"
SERVICE_START_PROGRAM = "start_program"
SERVICE_STOP_PROGRAM = "stop_program"
SCOPE = "code"
DEFAULT_LANG = "en"
DEFAULT_INTERVAL = 5
AUTH_CALLBACK_PATH = "/api/miele/callback"
AUTH_CALLBACK_NAME = "api:miele:callback"
CONF_CLIENT_ID = "client_id"
CONF_CLIENT_SECRET = "client_secret"
CONF_LANG = "lang"
CONF_CACHE_PATH = "cache_path"
CONF_INTERVAL = "interval"
CONFIGURATOR_LINK_NAME = "Link Miele account"
CONFIGURATOR_SUBMIT_CAPTION = "I have authorized Miele@home."
CONFIGURATOR_DESCRIPTION = (
Expand All @@ -62,12 +66,282 @@
vol.Required(CONF_CLIENT_SECRET): cv.string,
vol.Optional(CONF_LANG): cv.string,
vol.Optional(CONF_CACHE_PATH): cv.string,
vol.Optional(CONF_INTERVAL): cv.positive_int,
}
),
},
extra=vol.ALLOW_EXTRA,
)

CAPABILITIES = {
"1": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature.0",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
"spinningSpeed",
"ecoFeedback.energyConsumption",
"ecoFeedback.waterConsumption",
],
"2": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
"dryingStep",
"ecoFeedback.energyConsumption",
],
"7": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"signalInfo",
"signalFailure",
"remoteEnable",
"elapsedTime",
"ecoFeedback.energyConsumption",
"ecoFeedback.waterConsumption",
],
"12": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"13": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"14": ["status", "signalFailure", "plateStep"],
"15": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"16": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"17": [
"ProgramID",
"status",
"programPhase",
"signalInfo",
"signalFailure",
"remoteEnable",
],
"18": [
"status",
"signalInfo",
"signalFailure",
"remoteEnable",
"ventilationStep",
],
"19": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"20": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"21": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"23": [
"ProgramID",
"status",
"programType",
"signalInfo",
"signalFailure",
"remoteEnable",
"batteryLevel",
],
"24": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"targetTemperature.0",
"startTime",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
"spinningSpeed",
"dryingStep",
"ecoFeedback.energyConsumption",
"ecoFeedback.waterConsumption",
],
"25": [
"status",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"elapsedTime",
],
"27": ["status", "signalFailure", "plateStep"],
"31": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"32": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"33": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"34": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
],
"45": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"67": [
"ProgramID",
"status",
"programType",
"programPhase",
"remainingTime",
"startTime",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"signalDoor",
"remoteEnable",
"elapsedTime",
],
"68": [
"status",
"targetTemperature",
"temperature",
"signalInfo",
"signalFailure",
"remoteEnable",
],
}


def request_configuration(hass, config, oauth):
"""Request Miele authorization."""
Expand Down Expand Up @@ -181,8 +455,8 @@ async def refresh_devices(event_time):
platform.update_device_state()

register_services(hass)
interval = timedelta(seconds=config[DOMAIN].get(CONF_INTERVAL, DEFAULT_INTERVAL))

interval = timedelta(seconds=5)
async_track_time_interval(hass, refresh_devices, interval)

return True
Expand All @@ -191,6 +465,8 @@ async def refresh_devices(event_time):
def register_services(hass):
"""Register all services for Miele devices."""
hass.services.async_register(DOMAIN, SERVICE_ACTION, _action_service)
hass.services.async_register(DOMAIN, SERVICE_START_PROGRAM, _action_start_program)
hass.services.async_register(DOMAIN, SERVICE_STOP_PROGRAM, _action_stop_program)


async def _apply_service(service, service_func, *service_func_args):
Expand All @@ -217,6 +493,16 @@ async def _action_service(service):
await _apply_service(service, MieleDevice.action, body)


async def _action_start_program(service):
program_id = service.data.get("program_id")
await _apply_service(service, MieleDevice.start_program, program_id)


async def _action_stop_program(service):
body = {"processAction": 2}
await _apply_service(service, MieleDevice.action, body)


class MieleAuthCallbackView(HomeAssistantView):
"""Miele Authorization Callback View."""

Expand Down Expand Up @@ -341,6 +627,9 @@ def extra_state_attributes(self):
async def action(self, action):
await self._client.action(self.unique_id, action)

async def start_program(self, program_id):
await self._client.start_program(self.unique_id, program_id)

async def async_update(self):
if not self.unique_id in self._hass.data[DOMAIN][DATA_DEVICES]:
_LOGGER.debug("Miele device not found: {}".format(self.unique_id))
Expand Down
Loading

0 comments on commit c33617a

Please sign in to comment.