From 79208c658d52ac49631b90ba40e59b2a147fd092 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:00:26 +0100 Subject: [PATCH 01/13] Correct excception order --- custom_components/stromer/coordinator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/stromer/coordinator.py b/custom_components/stromer/coordinator.py index 567afa3..5d4cf73 100644 --- a/custom_components/stromer/coordinator.py +++ b/custom_components/stromer/coordinator.py @@ -42,8 +42,8 @@ async def _async_update_data(self) -> StromerData: data = [bike_data, self.stromer.bike_id, self.stromer.bike_name] LOGGER.debug("Stromer data %s updated", data) - except Exception as err: - raise ConfigEntryAuthFailed from err except ApiError as err: raise UpdateFailed(f"Error communicating with API: {err}") + except Exception as err: + raise ConfigEntryAuthFailed from err return StromerData(*data) From 9d3b26182d90f59ea76f540c7528eb66204489c8 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:03:14 +0100 Subject: [PATCH 02/13] Remove unused data + cleanup logging --- custom_components/stromer/stromer.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/custom_components/stromer/stromer.py b/custom_components/stromer/stromer.py index 569a63d..69b3219 100644 --- a/custom_components/stromer/stromer.py +++ b/custom_components/stromer/stromer.py @@ -44,11 +44,9 @@ async def stromer_connect(self): # Retrieve authorization token await self.stromer_get_code() - # LOGGER.debug("Stromer code: {}".format(self._code)) # Retrieve access token await self.stromer_get_access_token() - # LOGGER.debug("Stromer token: {}".format(self._token)) try: await self.stromer_update() @@ -77,12 +75,11 @@ async def stromer_update(self): endpoint = f"bike/{self.bike_id}/state/" data = {"cached": "false"} - # LOGGER.debug("Stromer endpoint: {}".format(endpoint)) - self.status = await self.stromer_call_api(endpoint=endpoint, data=data) + self.status = await self.stromer_call_api(endpoint=endpoint) LOGGER.debug("Stromer status: {}".format(self.status)) endpoint = f"bike/{self.bike_id}/position/" - self.position = await self.stromer_call_api(endpoint=endpoint, data=data) + self.position = await self.stromer_call_api(endpoint=endpoint) LOGGER.debug("Stromer position: {}".format(self.position)) return @@ -152,17 +149,16 @@ async def stromer_get_access_token(self): token = json.loads(await res.text()) self._token = token["access_token"] - async def stromer_call_api(self, endpoint, data={}): + async def stromer_call_api(self, endpoint): url = f"{self.base_url}/rapi/mobile/v4.1/{endpoint}" if self._api_version == 'v3': url = f"{self.base_url}/rapi/mobile/v2/{endpoint}" headers = {"Authorization": f"Bearer {self._token}"} - # LOGGER.debug("token %s" % self._token) res = await self._websession.get(url, headers=headers, data={}) ret = json.loads(await res.text()) - # LOGGER.debug("ret %s" % ret) - # LOGGER.debug("res status %s" % res.status) + LOGGER.debug("API call status: %s" % res.status) + LOGGER.debug("API call returns: %s" % ret) return ret["data"][0] class ApiError(Exception): From 087decb9ca18ace258b3596c8d81b167ab827f8e Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:10:46 +0100 Subject: [PATCH 03/13] Autofix --- README.md | 66 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index beb4dce..cc17c42 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -**:warning::warning::warning:Read the [release notes]() before upgrading, in case there are BREAKING changes!:warning::warning::warning:** +**:warning::warning::warning:Read the [release notes](https://github.com/CoMPaTech/stromer/releases) before upgrading, in case there are BREAKING changes!:warning::warning::warning:** # Stromer Custom Component for Home Assistant - [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/CoMPaTech/stomer/) - [![CodeFactor](https://www.codefactor.io/repository/github/CoMPaTech/stromer/badge)](https://www.codefactor.io/repository/github/CoMPaTech/stromer) - [![HASSfest](https://github.com/CoMPaTech/stromer/workflows/Validate%20with%20hassfest/badge.svg)](https://github.com/CoMPaTech/stromer/actions) - [![Generic badge](https://img.shields.io/github/v/release/CoMPaTech/stromer)](https://github.com/CoMPaTech/stromer) +[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/CoMPaTech/stomer/) +[![CodeFactor](https://www.codefactor.io/repository/github/CoMPaTech/stromer/badge)](https://www.codefactor.io/repository/github/CoMPaTech/stromer) +[![HASSfest](https://github.com/CoMPaTech/stromer/workflows/Validate%20with%20hassfest/badge.svg)](https://github.com/CoMPaTech/stromer/actions) +[![Generic badge](https://img.shields.io/github/v/release/CoMPaTech/stromer)](https://github.com/CoMPaTech/stromer) - [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) - [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) - [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) +[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_stromer&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_stromer) -[![Open your Home Assistant instance and show your integrations.](https://my.home-assistant.io/badges/integrations.svg)](https://my.home-assistant.io/redirect/integrations/) +[![Open your Home Assistant instance and show your integrations.](https://my.home-assistant.io/badges/integrations.svg)](https://my.home-assistant.io/redirect/integrations/) ## Configuration -Configure this integration the usual way, before starting you will need to retrieve your +Configure this integration the usual way, before starting you will need to retrieve your - [ ] Client ID - [ ] Client Secret @@ -125,45 +125,57 @@ Even though available does not mean it's stable yet, the HA part is solid but th # Changelog ## NOV 2023 [0.2.7] - - Fix to appropriate `device_class` from 0.2.5 + +- Fix to appropriate `device_class` from 0.2.5 ## NOV 2023 [0.2.6] - - Fix API recall (reverted maintenance approach from 0.2.5) tnx to @simonwolf83 + +- Fix API recall (reverted maintenance approach from 0.2.5) tnx to @simonwolf83 ## NOV 2023 [0.2.5] - - Fix unit from W to Wh (thanks @Tinus78) via #46 + +- Fix unit from W to Wh (thanks @Tinus78) via #46 ## OCT 2023 [0.2.4] - - Improve quality + +- Improve quality ## SEP 2023 [0.2.3] - - Conform to hacs and HA files - - Adding HACS validation + +- Conform to hacs and HA files +- Adding HACS validation ## SEP 2023 [0.2.2] - - Fix location (i.e. `device_tracker`) reporting + +- Fix location (i.e. `device_tracker`) reporting ## AUG 2023 [0.2.1] - - Quickfix sensors lost due to some data not available + +- Quickfix sensors lost due to some data not available ## MAR 2023 [0.2.0] - - Fix 2023.3 compliancy + +- Fix 2023.3 compliancy ## APR 2022 [0.1.0] - - Include last update sensors + +- Include last update sensors ## APR 2022 [0.0.8] - - v4 API support - - Data handling and reconnection + +- v4 API support +- Data handling and reconnection ## APR 2022 [0.0.7] - - Fix sensory updates - - Potentially fix token expiration + +- Fix sensory updates +- Potentially fix token expiration ## MAR 2022 [0.0.4] - - Initial release - - Creates a device for your bike in Home Assistant - - Refreshed location and other information every 10 minutes + +- Initial release +- Creates a device for your bike in Home Assistant +- Refreshed location and other information every 10 minutes # What does it support? From 882ca16778204bd83efde7fc27694efb7e9607e7 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:11:54 +0100 Subject: [PATCH 04/13] Yamllint --- .github/workflows/hassfest.yaml | 1 - .pre-commit-config.yaml | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/hassfest.yaml b/.github/workflows/hassfest.yaml index 695b8c8..75144ef 100644 --- a/.github/workflows/hassfest.yaml +++ b/.github/workflows/hassfest.yaml @@ -12,4 +12,3 @@ jobs: steps: - uses: "actions/checkout@v4.1.1" - uses: home-assistant/actions/hassfest@master - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3e0e85f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,92 @@ +# For pre-commit.ci +ci: + # Defer autoupdate to quarterly (there is no 'off' button) to have renovate pick up first + autoupdate_schedule: quarterly + submodules: true + +default_language_version: + # force all unspecified python hooks to run python3 + python: python3.12 + +repos: + # Run manually in CI skipping the branch checks + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 + hooks: + - id: ruff + name: "Ruff-ing code" + args: + - --fix + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-executables-have-shebangs + stages: [manual] + - id: no-commit-to-branch + name: "Verifying git branch exists" + args: + - --branch=main + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + name: "Checking pyupgrade" + args: [--py311-plus] + - repo: https://github.com/psf/black + rev: 23.10.1 + hooks: + - id: black + name: "Verifying/updating code using black" + args: + - --safe + - --quiet + files: ^((custom_components|tests)/.+)?[^/]+\.py$ + - repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + name: "Verifying/updating code for spelling issues" + args: + - --ignore-words-list=hass,alot,datas,dof,dur,ether,farenheit,hist,iff,iif,ines,ist,lightsensor,mut,nd,pres,referer,rime,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing,iam,incomfort,ba,haa,pullrequests + - --skip="./.*,*.csv,*.json" + - --quiet-level=2 + exclude_types: [csv, json] + - repo: https://github.com/PyCQA/bandit + rev: 1.7.5 + hooks: + - id: bandit + name: "Linting with bandit" + args: + - --quiet + - --format=custom + - --configfile=tests/bandit.yaml + files: ^(custom_components|tests)/.+\.py$ + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.32.0 + hooks: + - id: yamllint + name: "Linting yaml" + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.3 + hooks: + - id: prettier + name: "Verifying/updating code with prettier" + - repo: https://github.com/cdce8p/python-typing-update + rev: v0.6.0 + hooks: + # Run `python-typing-update` hook manually from time to time + # to update python typing syntax. + # Will require manual work, before submitting changes! + - id: python-typing-update + name: "Verifying code for typing-update" + stages: [manual] + args: + - --py311-plus + - --force + - --keep-updates + files: ^(custom_components|tests)/.+\.py$ + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.37.0 + hooks: + - id: markdownlint + name: "Linting Markdown" From 6675e279158ff0fbed09da8b94af5340e4f102ed Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:12:46 +0100 Subject: [PATCH 05/13] iSort/ruff --- custom_components/stromer/__init__.py | 8 +++-- custom_components/stromer/binary_sensor.py | 4 ++- custom_components/stromer/config_flow.py | 1 - custom_components/stromer/coordinator.py | 3 +- custom_components/stromer/device_tracker.py | 4 +-- custom_components/stromer/entity.py | 10 +++--- custom_components/stromer/sensor.py | 27 +++++++++++----- custom_components/stromer/stromer.py | 34 ++++++++++----------- 8 files changed, 54 insertions(+), 37 deletions(-) diff --git a/custom_components/stromer/__init__.py b/custom_components/stromer/__init__.py index d4f73c1..b7ff1be 100644 --- a/custom_components/stromer/__init__.py +++ b/custom_components/stromer/__init__.py @@ -14,7 +14,11 @@ SCAN_INTERVAL = timedelta(minutes=10) -PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER] +PLATFORMS: list[Platform] = [ + Platform.SENSOR, + Platform.BINARY_SENSOR, + Platform.DEVICE_TRACKER, +] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @@ -34,7 +38,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: except ApiError as ex: raise ConfigEntryNotReady("Error while communicating to Stromer API") from ex - LOGGER.debug("Stromer entry: {}".format(entry)) + LOGGER.debug(f"Stromer entry: {entry}") # Use Bike ID as unique id if entry.unique_id is None: diff --git a/custom_components/stromer/binary_sensor.py b/custom_components/stromer/binary_sensor.py index 3461ef9..6c7c5a1 100644 --- a/custom_components/stromer/binary_sensor.py +++ b/custom_components/stromer/binary_sensor.py @@ -4,7 +4,9 @@ from dataclasses import dataclass from homeassistant.components.binary_sensor import ( - BinarySensorEntity, BinarySensorEntityDescription) + BinarySensorEntity, + BinarySensorEntityDescription, +) from homeassistant.helpers.entity import EntityCategory from custom_components.stromer.coordinator import StromerDataUpdateCoordinator diff --git a/custom_components/stromer/config_flow.py b/custom_components/stromer/config_flow.py index 114fc33..da55cc7 100644 --- a/custom_components/stromer/config_flow.py +++ b/custom_components/stromer/config_flow.py @@ -6,7 +6,6 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError diff --git a/custom_components/stromer/coordinator.py b/custom_components/stromer/coordinator.py index 5d4cf73..81b06a3 100644 --- a/custom_components/stromer/coordinator.py +++ b/custom_components/stromer/coordinator.py @@ -3,8 +3,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed -from homeassistant.helpers.update_coordinator import (DataUpdateCoordinator, - UpdateFailed) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DOMAIN, LOGGER from .stromer import Stromer, ApiError diff --git a/custom_components/stromer/device_tracker.py b/custom_components/stromer/device_tracker.py index 4ceb5a9..d59ec99 100644 --- a/custom_components/stromer/device_tracker.py +++ b/custom_components/stromer/device_tracker.py @@ -43,9 +43,9 @@ def source_type(self) -> SourceType | str: @property def latitude(self) -> float | None: """Return latitude value of the device.""" - return self._coordinator.data.bikedata.get('latitude') + return self._coordinator.data.bikedata.get("latitude") @property def longitude(self) -> float | None: """Return longitude value of the device.""" - return self._coordinator.data.bikedata.get('longitude') + return self._coordinator.data.bikedata.get("longitude") diff --git a/custom_components/stromer/entity.py b/custom_components/stromer/entity.py index 10be940..4776a51 100644 --- a/custom_components/stromer/entity.py +++ b/custom_components/stromer/entity.py @@ -35,11 +35,11 @@ def __init__( name=data.get("nickname"), sw_version=data.get("suiversion"), hw_version=data.get("tntversion"), -# stromer_id=data.get("bike_id"), -# type=data.get("bikemodel"), -# frame_color=data.get("color"), -# frame_size=data.get("size"), -# hardware=data.get("hardware"), + # stromer_id=data.get("bike_id"), + # type=data.get("bikemodel"), + # frame_color=data.get("color"), + # frame_size=data.get("size"), + # hardware=data.get("hardware"), ) self._attr_device_info.update( diff --git a/custom_components/stromer/sensor.py b/custom_components/stromer/sensor.py index 2a8ea87..8a1e200 100644 --- a/custom_components/stromer/sensor.py +++ b/custom_components/stromer/sensor.py @@ -1,12 +1,21 @@ """Stromer Sensor component for Home Assistant.""" from __future__ import annotations -from homeassistant.components.sensor import (SensorDeviceClass, SensorEntity, - SensorEntityDescription, - SensorStateClass) -from homeassistant.const import (ENERGY_WATT_HOUR, LENGTH_KILOMETERS, PERCENTAGE, POWER_WATT, - PRESSURE_BAR, SPEED_KILOMETERS_PER_HOUR, - TEMP_CELSIUS, TIME_SECONDS) +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.const import ( + ENERGY_WATT_HOUR, + LENGTH_KILOMETERS, + PERCENTAGE, + PRESSURE_BAR, + SPEED_KILOMETERS_PER_HOUR, + TEMP_CELSIUS, + TIME_SECONDS, +) from homeassistant.helpers.entity import EntityCategory from custom_components.stromer.coordinator import StromerDataUpdateCoordinator @@ -211,6 +220,10 @@ def _ensure_timezone(timestamp: datetime | None) -> datetime | None: def native_value(self): """Return the state of the sensor.""" if self.entity_description.device_class == SensorDeviceClass.TIMESTAMP: - return self._ensure_timezone(datetime.fromtimestamp(int(self._coordinator.data.bikedata.get(self._ent)))) + return self._ensure_timezone( + datetime.fromtimestamp( + int(self._coordinator.data.bikedata.get(self._ent)) + ) + ) return self._coordinator.data.bikedata.get(self._ent) diff --git a/custom_components/stromer/stromer.py b/custom_components/stromer/stromer.py index 69b3219..5843bdc 100644 --- a/custom_components/stromer/stromer.py +++ b/custom_components/stromer/stromer.py @@ -19,10 +19,10 @@ def __init__(self, username, password, client_id, client_secret, timeout=60): self.bike = {} self.status = {} self.position = {} - - self._api_version = 'v4' + + self._api_version = "v4" if client_secret: - self._api_version = 'v3' + self._api_version = "v3" self.base_url = "https://api3.stromer-portal.ch" self._timeout = timeout @@ -51,7 +51,7 @@ async def stromer_connect(self): try: await self.stromer_update() except Exception as e: - LOGGER.error("Stromer unable to update: {}".format(e)) + LOGGER.error(f"Stromer unable to update: {e}") LOGGER.debug("Stromer connected!") @@ -65,9 +65,9 @@ async def stromer_update(self): await self.stromer_connect() attempts += 1 try: - LOGGER.debug("Stromer attempt: {}/10".format(attempts)) + LOGGER.debug(f"Stromer attempt: {attempts}/10") self.bike = await self.stromer_call_api(endpoint="bike/") - LOGGER.debug("Stromer bike: {}".format(self.bike)) + LOGGER.debug(f"Stromer bike: {self.bike}") self.bike_id = self.bike["bikeid"] self.bike_name = self.bike["nickname"] @@ -76,23 +76,23 @@ async def stromer_update(self): endpoint = f"bike/{self.bike_id}/state/" data = {"cached": "false"} self.status = await self.stromer_call_api(endpoint=endpoint) - LOGGER.debug("Stromer status: {}".format(self.status)) + LOGGER.debug(f"Stromer status: {self.status}") endpoint = f"bike/{self.bike_id}/position/" self.position = await self.stromer_call_api(endpoint=endpoint) - LOGGER.debug("Stromer position: {}".format(self.position)) + LOGGER.debug(f"Stromer position: {self.position}") return except Exception as e: - LOGGER.error("Stromer error: api call failed: {}".format(e)) - LOGGER.debug("Stromer retry: {}/10".format(attempts)) + LOGGER.error(f"Stromer error: api call failed: {e}") + LOGGER.debug(f"Stromer retry: {attempts}/10") LOGGER.error("Stromer error: api call failed 10 times, cowardly failing") raise ApiError async def stromer_get_code(self): url = f"{self.base_url}/mobile/v4/login/" - if self._api_version == 'v3': + if self._api_version == "v3": url = f"{self.base_url}/users/login/" res = await self._websession.get(url) try: @@ -116,11 +116,11 @@ async def stromer_get_code(self): "password": self._password, "username": self._username, "csrfmiddlewaretoken": csrftoken, - "next": "/mobile/v4/o/authorize/?" + qs + "next": "/mobile/v4/o/authorize/?" + qs, } - if self._api_version == 'v3': - data["next"]= "/o/authorize/?" + qs + if self._api_version == "v3": + data["next"] = "/o/authorize/?" + qs res = await self._websession.post( url, data=data, headers=dict(Referer=url), allow_redirects=False @@ -140,7 +140,7 @@ async def stromer_get_access_token(self): "redirect_uri": "stromer://auth", } - if self._api_version == 'v3': + if self._api_version == "v3": url = f"{self.base_url}/o/token/" data["client_secret"] = self._client_secret data["redirect_uri"] = "stromerauth://auth" @@ -151,7 +151,7 @@ async def stromer_get_access_token(self): async def stromer_call_api(self, endpoint): url = f"{self.base_url}/rapi/mobile/v4.1/{endpoint}" - if self._api_version == 'v3': + if self._api_version == "v3": url = f"{self.base_url}/rapi/mobile/v2/{endpoint}" headers = {"Authorization": f"Bearer {self._token}"} @@ -161,6 +161,6 @@ async def stromer_call_api(self, endpoint): LOGGER.debug("API call returns: %s" % ret) return ret["data"][0] + class ApiError(Exception): """Error to indicate something wrong with the API.""" - From 993f0d6ebaa11b88e40dd857ba99747e71af54d9 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:13:16 +0100 Subject: [PATCH 06/13] jsonlint --- custom_components/stromer/strings.json | 2 +- custom_components/stromer/translations/en.json | 2 +- custom_components/stromer/translations/nl.json | 2 +- renovate.json | 9 ++------- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/custom_components/stromer/strings.json b/custom_components/stromer/strings.json index baccae9..66b48fa 100644 --- a/custom_components/stromer/strings.json +++ b/custom_components/stromer/strings.json @@ -6,7 +6,7 @@ "description": "Provide your Stromer API details", "data": { "password": "Password", - "username" : "Username", + "username": "Username", "client_id": "Client ID", "client_secret": "Client Secret (optional, not needed if you client id starts with 4P" } diff --git a/custom_components/stromer/translations/en.json b/custom_components/stromer/translations/en.json index 8fc3aa2..f7d16bd 100644 --- a/custom_components/stromer/translations/en.json +++ b/custom_components/stromer/translations/en.json @@ -6,7 +6,7 @@ "description": "Provide your Stromer API details", "data": { "password": "Password", - "username" : "Username", + "username": "Username", "client_id": "Client ID", "client_secret": "Client Secret (optional, not needed if your Client ID starts with 4P" } diff --git a/custom_components/stromer/translations/nl.json b/custom_components/stromer/translations/nl.json index 7e0bc24..862ee06 100644 --- a/custom_components/stromer/translations/nl.json +++ b/custom_components/stromer/translations/nl.json @@ -6,7 +6,7 @@ "description": "Stromer API gegevens", "data": { "password": "Wachtwoord", - "username" : "Gebruikersnaam", + "username": "Gebruikersnaam", "client_id": "Client ID", "client_secret": "Client Secret (optioneel, niet nodig als je client id met 4P begint" } diff --git a/renovate.json b/renovate.json index ac3c9bf..7730d28 100644 --- a/renovate.json +++ b/renovate.json @@ -1,17 +1,13 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base", - ":dependencyDashboard", - "schedule:weekly" - ], + "extends": ["config:base", ":dependencyDashboard", "schedule:weekly"], "packageRules": [ { "matchManagers": ["github-actions"], "automerge": true }, { - "matchManagers": ["pip_requirements","poetry","setup-cfg"], + "matchManagers": ["pip_requirements", "poetry", "setup-cfg"], "automerge": true }, { @@ -20,4 +16,3 @@ } ] } - From cc66d01cb74ebc8deca560bb2343bfa1a28f299e Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:14:22 +0100 Subject: [PATCH 07/13] Introduce markdownlint --- .markdownlint.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..320406d --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,2 @@ +default: true +MD013: false From d75bb95dc932919439c670b8b9b1bf9dcb0f64ff Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:16:15 +0100 Subject: [PATCH 08/13] Markdownlint --- README.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index cc17c42..ffbfccd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -**:warning::warning::warning:Read the [release notes](https://github.com/CoMPaTech/stromer/releases) before upgrading, in case there are BREAKING changes!:warning::warning::warning:** - # Stromer Custom Component for Home Assistant +**:warning::warning::warning:Read the [release notes](https://github.com/CoMPaTech/stromer/releases) before upgrading, in case there are BREAKING changes!:warning::warning::warning:** + [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/CoMPaTech/stomer/) [![CodeFactor](https://www.codefactor.io/repository/github/CoMPaTech/stromer/badge)](https://www.codefactor.io/repository/github/CoMPaTech/stromer) [![HASSfest](https://github.com/CoMPaTech/stromer/workflows/Validate%20with%20hassfest/badge.svg)](https://github.com/CoMPaTech/stromer/actions) @@ -38,7 +38,7 @@ Basically you'll have to trigger (through automations) the updates yourself. But - [![Open your automations.](https://my.home-assistant.io/badges/automations.svg)](https://my.home-assistant.io/redirect/automations/) - Create a new automation, click on the right-top three dots and select 'Edit as YAML'. Don't worry, most of it you will be able to use the visual editor for, it's just that pasting is much easier this way. Do note that you'll have to change the `stromer` part of the bike (or after pasting, select the three dots, go back to visual editor and pick the correct entity). -``` +```automation.yml alias: Stromer cancel updates when locked description: '' trigger: @@ -59,7 +59,7 @@ mode: single - Create another automation, same process as above -``` +```automation.yml alias: Stromer start updates when unlocked description: '' trigger: @@ -80,7 +80,7 @@ mode: single - And the final one, actually calling the updates (example every 30 seconds). We'll only point to speed, but it will update the other sensors -``` +```automation.yml alias: Stromer update sensors description: '' trigger: @@ -100,7 +100,7 @@ mode: single - Final step is adding a button to your dashboard if you want to trigger updates right now. Do note that your bike must be **unlocked** before triggering, otherwise it will 'cancel itself' :) In a dashboard, click the three buttons right top, and add a `button`-card, through `view code editor` paste, switch back to visual editor and customize the below to your taste. Again pointing at speed but it will refresh if the bike is unlocked and trigger the updates helper. -``` +```lovelace.yml show_name: true show_icon: true type: button @@ -122,17 +122,17 @@ show_state: false Even though available does not mean it's stable yet, the HA part is solid but the class used to interact with the API is in need of improvement (e.g. better overall handling). This might also warrant having the class available as a module from pypi. -# Changelog +## Changelog -## NOV 2023 [0.2.7] +### NOV 2023 [0.2.7] - Fix to appropriate `device_class` from 0.2.5 -## NOV 2023 [0.2.6] +### NOV 2023 [0.2.6] - Fix API recall (reverted maintenance approach from 0.2.5) tnx to @simonwolf83 -## NOV 2023 [0.2.5] +### NOV 2023 [0.2.5] - Fix unit from W to Wh (thanks @Tinus78) via #46 @@ -140,44 +140,44 @@ Even though available does not mean it's stable yet, the HA part is solid but th - Improve quality -## SEP 2023 [0.2.3] +### SEP 2023 [0.2.3] - Conform to hacs and HA files - Adding HACS validation -## SEP 2023 [0.2.2] +### SEP 2023 [0.2.2] - Fix location (i.e. `device_tracker`) reporting -## AUG 2023 [0.2.1] +### AUG 2023 [0.2.1] - Quickfix sensors lost due to some data not available -## MAR 2023 [0.2.0] +### MAR 2023 [0.2.0] - Fix 2023.3 compliancy -## APR 2022 [0.1.0] +### APR 2022 [0.1.0] - Include last update sensors -## APR 2022 [0.0.8] +### APR 2022 [0.0.8] - v4 API support - Data handling and reconnection -## APR 2022 [0.0.7] +### APR 2022 [0.0.7] - Fix sensory updates - Potentially fix token expiration -## MAR 2022 [0.0.4] +### MAR 2022 [0.0.4] - Initial release - Creates a device for your bike in Home Assistant - Refreshed location and other information every 10 minutes -# What does it support? +## What does it support? - Location - It inherits zones, but you could also plot your location on a map @@ -186,14 +186,14 @@ Even though available does not mean it's stable yet, the HA part is solid but th - Binary Sensors - Light-status and Omni-lock status and theft status -# How to install? +## How to install? - Use [HACS](https://hacs.xyz) - Navigate to the `Integrations` page and use the three-dots icon on the top right to add a custom repository. - Use the link to this page as the URL and select 'Integrations' as the category. - Look for `Stromer` in `Integrations` and install it! -## How to add the integration to HA Core +### How to add the integration to HA Core For each bike (i.e. api-user) you will have to add it as an integration. Do note that you first have to retrieve your client ID and Secret using some tool like [mitmproxy](https://mitmproxy.org) to fetch these. If you don't know how to do this or what this implies; search from someone who can eloborate on this or do not use this integration. For more details and/or helpful users see [the Dutch Stromer forum](https://www.speedpedelecreview.com/forum/viewtopic.php?f=8&t=1445) @@ -203,9 +203,9 @@ For each bike (i.e. api-user) you will have to add it as an integration. Do note - [ ] Search or browse for 'Stromer e-bike' and click it - [ ] Enter your e-mail address, password and the client ID and Secret -# Frequently Asked Questions (FAQ) +## Frequently Asked Questions (FAQ) -## I don't like the name of the sensor or the icon +### I don't like the name of the sensor or the icon You can adjust these in `Configuration`, `Integration` -> `Entities` (e.g. `https://{Your HA address}/config/entities`) @@ -213,11 +213,11 @@ Just click on the device and adjust accordingly! Please note that you can also click the cogwheel right top corner to rename all entities of a device at once. -## It doesn't work +### It doesn't work I'm on Discord and used to frequent the Dutch Stromer forum more often, but feel free to add a Bug through the Issues tab on [Github](https://github.com/CoMPaTech/stromer). -## Is it tested? +### Is it tested? It works on my bike and Home Assistant installation :) Let me know if it works on yours! From a4c932dbab3b5acc3a5912105a9d732f3dc8d896 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:16:50 +0100 Subject: [PATCH 09/13] Introduce yamllint --- .yamllint | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .yamllint diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..f93caaf --- /dev/null +++ b/.yamllint @@ -0,0 +1,66 @@ +# Copy of github.com/home-assistant/core .yamllint +# Our addition to truthy +# truthy: +# allowed-values: ['true', 'false', 'on'] +ignore: | + azure-*.yml +rules: + braces: + level: error + min-spaces-inside: 0 + max-spaces-inside: 1 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + brackets: + level: error + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + colons: + level: error + max-spaces-before: 0 + max-spaces-after: 1 + commas: + level: error + max-spaces-before: 0 + min-spaces-after: 1 + max-spaces-after: 1 + comments: + level: error + require-starting-space: true + min-spaces-from-content: 2 + comments-indentation: + level: error + document-end: + level: error + present: false + document-start: + level: error + present: false + empty-lines: + level: error + max: 1 + max-start: 0 + max-end: 1 + hyphens: + level: error + max-spaces-after: 1 + indentation: + level: error + spaces: 2 + indent-sequences: true + check-multi-line-strings: false + key-duplicates: + level: error + line-length: disable + new-line-at-end-of-file: + level: error + new-lines: + level: error + type: unix + trailing-spaces: + level: error + truthy: + allowed-values: ['true', 'false', 'on', 'False'] # 'on' for github actions, 'False' for our services.yaml + level: error From 960b64f3114396c0d5ca69f529f26bf3ce3f19f7 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:18:16 +0100 Subject: [PATCH 10/13] Typo/spelling --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ffbfccd..9cb86cd 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ Even though available does not mean it's stable yet, the HA part is solid but th ### MAR 2023 [0.2.0] -- Fix 2023.3 compliancy +- Fix 2023.3 compliance ### APR 2022 [0.1.0] @@ -197,7 +197,7 @@ Even though available does not mean it's stable yet, the HA part is solid but th For each bike (i.e. api-user) you will have to add it as an integration. Do note that you first have to retrieve your client ID and Secret using some tool like [mitmproxy](https://mitmproxy.org) to fetch these. If you don't know how to do this or what this implies; search from someone who can eloborate on this or do not use this integration. For more details and/or helpful users see [the Dutch Stromer forum](https://www.speedpedelecreview.com/forum/viewtopic.php?f=8&t=1445) -- [ ] In Home Assitant click on `Configuration` +- [ ] In Home Assistant click on `Configuration` - [ ] Click on `Integrations` - [ ] Hit the `+` button in the right lower corner - [ ] Search or browse for 'Stromer e-bike' and click it From 4f34197a61246387e7e8dc5fee1e76a01249dd46 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:19:09 +0100 Subject: [PATCH 11/13] No tests (yet) --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e0e85f..c474d19 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -59,7 +59,6 @@ repos: args: - --quiet - --format=custom - - --configfile=tests/bandit.yaml files: ^(custom_components|tests)/.+\.py$ - repo: https://github.com/adrienverge/yamllint.git rev: v1.32.0 From b3aa4166d59ddaf3f7bce55a3353497c7c748d52 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:19:46 +0100 Subject: [PATCH 12/13] Another unused data var --- custom_components/stromer/stromer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/stromer/stromer.py b/custom_components/stromer/stromer.py index 5843bdc..2eebd2d 100644 --- a/custom_components/stromer/stromer.py +++ b/custom_components/stromer/stromer.py @@ -74,7 +74,6 @@ async def stromer_update(self): self.bike_model = self.bike["biketype"] endpoint = f"bike/{self.bike_id}/state/" - data = {"cached": "false"} self.status = await self.stromer_call_api(endpoint=endpoint) LOGGER.debug(f"Stromer status: {self.status}") From cfa56ed66671ca457e03eeec8098e7b7b02b00fb Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Tue, 7 Nov 2023 13:21:44 +0100 Subject: [PATCH 13/13] Dependabot comments --- .github/dependabot.yml | 4 ++-- .pre-commit-config.yaml | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b2aaf22..dd9ad17 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ version: 2 updates: - - package-ecosystem: "github-actions" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "github-actions" + directory: "/" schedule: interval: "daily" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c474d19..4065f45 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,15 +51,6 @@ repos: - --skip="./.*,*.csv,*.json" - --quiet-level=2 exclude_types: [csv, json] - - repo: https://github.com/PyCQA/bandit - rev: 1.7.5 - hooks: - - id: bandit - name: "Linting with bandit" - args: - - --quiet - - --format=custom - files: ^(custom_components|tests)/.+\.py$ - repo: https://github.com/adrienverge/yamllint.git rev: v1.32.0 hooks: