Skip to content
This repository has been archived by the owner on Feb 29, 2024. It is now read-only.

Commit

Permalink
Merge pull request #106 from simontegelid/snappy_startup
Browse files Browse the repository at this point in the history
Fix some error cases and make startup more rapid
  • Loading branch information
Thomas55555 authored Oct 11, 2021
2 parents e681af8 + e92bb00 commit 7c1b9ff
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 34 deletions.
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ Custom component to support Automower.

## About

The idea for this component ist coming from the <https://github.com/walthowd/ha-automower> integration. As this integration doesn't use the offical API, I decided to create a
integration, which is based on the offical API: <https://developer.husqvarnagroup.cloud/>. There are some disatvanteges between, the offical API and the unoffical API:

- Offical API is limited to 10,000 accesses per 30 days. So state of the mower is only update every 5 minutes
- API-Key is needed

But the adavantage is, that Husqvarna won't close the offical API suddenly.
This integration is based on the offical
[API](https://developer.husqvarnagroup.cloud/). The integration is using the
Husqvarna websocket API for pushed updates, so no polling is performed. You
need a API key to use this integration, refer to [this
guide](https://developer.husqvarnagroup.cloud/docs/getting-started) on how to
get one.

![Screenshot of the integration](https://github.com/Thomas55555/husqvarna_automower/blob/master/screenshot_husqvarna_automower.PNG)

Expand Down
37 changes: 18 additions & 19 deletions custom_components/husqvarna_automower/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
"""The Husqvarna Automower integration."""
import logging

from aioautomower import (
AutomowerSession,
GetAccessToken,
)
import aioautomower

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import UpdateFailed

from .const import DOMAIN, PLATFORMS, STARTUP_MESSAGE

Expand All @@ -28,7 +24,7 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry):
password = entry.data.get(CONF_PASSWORD)
api_key = entry.data.get(CONF_API_KEY)

get_token = GetAccessToken(api_key, username, password)
get_token = aioautomower.GetAccessToken(api_key, username, password)
access_token = await get_token.async_get_access_token()
hass.config_entries.async_update_entry(
entry,
Expand All @@ -53,10 +49,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
api_key = entry.unique_id
access_token = entry.data.get(CONF_TOKEN)

session = AutomowerSession(api_key, access_token)
session = aioautomower.AutomowerSession(api_key, access_token)

if not await session.connect():
raise ConfigEntryAuthFailed
try:
await session.connect()
except Exception as e:
# If we haven't used the refresh_token (ie. been offline) for 10 days,
# we need to login using username and password in the config flow again.
raise ConfigEntryAuthFailed(e)

hass.data[DOMAIN][entry.entry_id] = session
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
Expand All @@ -65,11 +65,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Handle removal of an entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
"""Handle unload of an entry."""
session = hass.data[DOMAIN].pop(entry.entry_id)
try:
await session.invalidate_token()
except Exception as exception:
_LOGGER.warning("Failed to invalidate token: %s", exception)
pass

return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)


async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):
Expand All @@ -80,8 +84,3 @@ async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):

async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle removal of an entry."""
session = hass.data[DOMAIN][entry.entry_id]
try:
await session.invalidate_token()
except Exception as exception:
raise UpdateFailed(exception) from exception
4 changes: 3 additions & 1 deletion custom_components/husqvarna_automower/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def __init__(self, session, idx):
self.mower_name = mower_attributes["system"]["name"]
self.model = mower_attributes["system"]["model"]

self.session.register_cb(lambda _: self.async_write_ha_state())
self.session.register_cb(
lambda _: self.async_write_ha_state(), schedule_immediately=True
)

def __get_mower_attributes(self):
return self.session.data["data"][self.idx]["attributes"]
Expand Down
2 changes: 1 addition & 1 deletion custom_components/husqvarna_automower/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"@Thomas55555"
],
"requirements": [
"aioautomower==2021.10.1"
"aioautomower==2021.10.2"
],
"iot_class": "cloud_push",
"version": "0.0.0"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/husqvarna_automower/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"abort": {
"single_instance_allowed": "Only a single configuration of Husqvarna Automower is allowed.",
"reauth_successful": "The reauthentication was suscessfull"
"reauth_successful": "The reauthentication was successful"
}
},
"system_health": {
Expand Down
13 changes: 8 additions & 5 deletions custom_components/husqvarna_automower/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ def __init__(self, session, idx):
self.model = mower_attributes["system"]["model"]
self._available = None

self.session.register_cb(lambda _: self.async_write_ha_state())
self.session.register_cb(
lambda _: self.async_write_ha_state(), schedule_immediately=True
)

def __get_mower_attributes(self):
return self.session.data["data"][self.idx]["attributes"]
Expand Down Expand Up @@ -188,9 +190,10 @@ def battery_level(self):

def __get_status(self) -> str:
mower_attributes = self.__get_mower_attributes()
next_start_short = ""
if mower_attributes["planner"]["nextStartTimestamp"] != 0:
self.next_start_short = time.strftime(
"%a %H:%M",
next_start_short = time.strftime(
", next start: %a %H:%M",
time.gmtime((mower_attributes["planner"]["nextStartTimestamp"]) / 1000),
)
if mower_attributes["mower"]["state"] == "UNKNOWN":
Expand All @@ -209,7 +212,7 @@ def __get_status(self) -> str:
if mower_attributes["mower"]["activity"] == "GOING_HOME":
return "Going to charging station"
if mower_attributes["mower"]["activity"] == "CHARGING":
return f"Charging, next start: {self.next_start_short}"
return f"Charging{next_start_short}"
if mower_attributes["mower"]["activity"] == "LEAVING":
return "Leaving charging station"
if mower_attributes["mower"]["activity"] == "PARKED_IN_CS":
Expand All @@ -222,7 +225,7 @@ def __get_status(self) -> str:
return "Powering up"
if mower_attributes["mower"]["state"] == "RESTRICTED":
if mower_attributes["planner"]["restrictedReason"] == "WEEK_SCHEDULE":
return f"Schedule, next start: {self.next_start_short}"
return f"Schedule{next_start_short}"
if mower_attributes["planner"]["restrictedReason"] == "PARK_OVERRIDE":
return "Park override"
if mower_attributes["planner"]["restrictedReason"] == "SENSOR":
Expand Down

0 comments on commit 7c1b9ff

Please sign in to comment.