Skip to content

Commit

Permalink
Library improvements (#1931)
Browse files Browse the repository at this point in the history
* Add optional model id on library

* WIP

* New device form

* Apply automatic changes

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Docs

* WIP

* Fixes

* WIP

* matching docs

* Library sorting

* Apply automatic changes

* Remove test

* Docs

* Docs

* Add condition inputs to blueprints

* Bump min HA version to 2024.5

* Add icon translations

* Add manual library message

* Update device: Vibration_sensor_TS0210 by Tuya (#1849)

* Apply automatic changes

* Update device: Water_leak_sensor_IH_K665 by Aubess (#1851)

* Apply automatic changes

* Update device: Hue_secure_contact_sensor_SOC001 by Signify_Netherlands_B_V (#1853)

Co-authored-by: Mariusthvdb <[email protected]>

* Apply automatic changes

* Update device: Smart_button_ZG_101ZL by Loginovo (#1857)

* Apply automatic changes

* Update device: MJYD02YL by Xiaomi (#1855)

* Apply automatic changes

* Plant Sensor SGS01 via TuyaBLE integration (#1862)

* Apply automatic changes

* Update device: BRZ1 by Springs_Window_Fashions (#1865)

* Apply automatic changes

* Update device: BRZ1 by Springs_Window_Fashions (#1867)

* Apply automatic changes

* Update device: CSZ1 by Springs_Window_Fashions (#1869)

* Apply automatic changes

* Update device: VCZ1 by Springs_Window_Fashions (#1873)

* Apply automatic changes

* Update device: MCZ1 by Springs_Window_Fashions (#1871)

* Apply automatic changes

* Update device: 914C by Kwikset (#1875)

* Apply automatic changes

* Update device: 916 by Kwikset (#1877)

* Apply automatic changes

* Update device: 2844_222_0x10_0x16 by SmartLabs_Inc (#1879)

* Apply automatic changes

* Update device: 2845_222_0x10_0x11 by SmartLabs_Inc (#1883)

* Apply automatic changes

* Add Moes thermostat radiator valve variants (#1884)

* Apply automatic changes

* Update device: 2842_222_0x10_0x01 by SmartLabs_Inc (#1886)

Co-authored-by: andrew-codechimp <[email protected]>

* Apply automatic changes

* Bump softprops/action-gh-release from 2.0.6 to 2.0.8 (#1887)

* Update crowdin.yml

* New Crowdin translations by GitHub Action (#1888)

Co-authored-by: Crowdin Bot <[email protected]>

* Update device: T8160 by Eufy_Security (#1891)

* Apply automatic changes

* Update device: T8210C by Eufy_Security (#1893)

* Apply automatic changes

* Update device: T8113_V by Eufy_Security (#1895)

* Apply automatic changes

* Update device: AS008 by Aqara (#1898)

* Apply automatic changes

* Update device: ZEN37_800LR by Zooz (#1901)

* Apply automatic changes

* Update library.json

Change ZSE42 to manual

* Apply automatic changes

* Update device: Yale by YRL256 (#1903)

* Apply automatic changes

* Update device: M3_2_9 by OpenEpaperLink (#1905)

* Apply automatic changes

* Update device: SNZB_05P by Sonoff (#1907)

* Apply automatic changes

* Device: Shelly H&T (gen1) (#1908)

* Apply automatic changes

* Correct Yale YRL256 (#1909)

The manufacturer and model were swapped

* Apply automatic changes

* Fix crowdin.yml

* New Crowdin translations by GitHub Action (#1911)

Co-authored-by: Crowdin Bot <[email protected]>

* Update device: Hinge_PIN_Door_Sensor_500S by GE (#1916)

* Apply automatic changes

* Update device: Q_Sensor by Zooz (#1920)

* Apply automatic changes

* Update device: Q_Sensor by GE (#1918)

* Apply automatic changes

* Update device: FRITZ_DECT_302 by AMV_FritzBox (#1922)

* Apply automatic changes

* Update device: FRITZ_DECT_350 by AMV_FritzBox (#1924)

* Apply automatic changes

* Update device: FRITZ_DECT_440 by AMV_FritzBox (#1926)

* Apply automatic changes

* Update library.json

* Apply automatic changes

* Device: Eaton - Ellipse ECO 650 (#1927)

Added new device Eaton - Ellipse ECO 650

* Apply automatic changes

* Update device: 99120_021 by Kwikset (#1929)

Co-authored-by: CobraDunn <[email protected]>

* Apply automatic changes

* New Crowdin translations by GitHub Action (#1930)

* Apply automatic changes

---------

Co-authored-by: andrew-codechimp <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mariusthvdb <[email protected]>
Co-authored-by: Piotr Szulc <[email protected]>
Co-authored-by: mbuett <[email protected]>
Co-authored-by: andrew-codechimp <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <[email protected]>
Co-authored-by: Rohan Kapoor <[email protected]>
Co-authored-by: Jeffrey <[email protected]>
Co-authored-by: CobraDunn <[email protected]>
  • Loading branch information
12 people authored Aug 3, 2024
1 parent 7dfd96f commit c9cf787
Show file tree
Hide file tree
Showing 40 changed files with 420 additions and 122 deletions.
27 changes: 23 additions & 4 deletions .github/ISSUE_TEMPLATE/new_device_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ body:
The battery library is a JSON document at [custom_components/battery_notes/data/library.json](https://github.com/andrew-codechimp/HA-Battery-Notes/blob/main/custom_components/battery_notes/data/library.json)
To contribute, submit your device details via this form and the relevant code changes will be proposed on your behalf.
Note: The title above is not used and can be just a friendly description of the device. Manufacturer and model should be exactly what is displayed on the Device screen within Home Assistant.
If your device has a Model ID or HW Version then these must be included.
To see your devices, click here:
[![Open your Home Assistant instance and show your devices.](https://my.home-assistant.io/badges/devices.svg)](https://my.home-assistant.io/redirect/devices/)
Expand All @@ -18,7 +19,7 @@ body:
attributes:
label: Manufacturer
description: The manufacturer should be exactly what is displayed on the Devices screen within Home Assistant.
placeholder: ex. eWeLink
placeholder: ex. Philips
validations:
required: true

Expand All @@ -27,12 +28,30 @@ body:
attributes:
label: Model
description: The model should be exactly what is displayed on the Devices screen within Home Assistant.
placeholder: ex. DS01
placeholder: ex. Hue dimmer switch
validations:
required: true

- type: input
id: battery-type
id: model_id
attributes:
label: Model ID
description: If the device has a Model ID in the Devices screen within Home Assistant it must be included.
placeholder: ex. 324131092621
validations:
required: false

- type: input
id: hw_version
attributes:
label: HW Version
description: If the device has a Hardware version shown in the Devices screen within Home Assistant it must be included.
placeholder: ex. V7.2
validations:
required: false

- type: input
id: battery_type
attributes:
label: Battery Type
description: When specifying battery types please use the Most Common naming for general batteries and the IEC naming for battery cells according to [Wikipedia](https://en.wikipedia.org/wiki/List_of_battery_sizes).
Expand All @@ -41,7 +60,7 @@ body:
required: true

- type: input
id: battery-quantity
id: battery_quantity
attributes:
label: Battery Quantity
description: The battery_quantity attribute is numeric (no letters or special characters).
Expand Down
24 changes: 17 additions & 7 deletions .github/scripts/library_doc/generate_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ def generate_device_list():
"""Generate static file containing the device library."""

# Load the existing JSON library file
with open("custom_components/battery_notes/data/library.json",
encoding="UTF-8") as f:
with open(
"custom_components/battery_notes/data/library.json", encoding="UTF-8"
) as f:
devices_json = json.loads(f.read())
devices = devices_json.get("devices")

Expand All @@ -26,6 +27,8 @@ def generate_device_list():
headers = [
"Manufacturer",
"Model",
"Model ID",
"Hardware",
"Battery Type",
]

Expand All @@ -37,14 +40,20 @@ def generate_device_list():
else:
battery_type_qty = device["battery_type"]

if "hw_version" in device:
model = f"{device['model']} ({device['hw_version']})"
else:
model = device['model']
model = device["model"]
model_match_method = device.get("model_match_method", "")
if model_match_method == "startswith":
model = rf"{model}\*"
if model_match_method == "endswith":
model = rf"\*{model}"
if model_match_method == "contains":
model = rf"\*{model}\*"

row = [
device['manufacturer'],
device["manufacturer"],
model,
device.get("model_id", ""),
device.get("hw_version", ""),
battery_type_qty,
]
rows.append(row)
Expand All @@ -59,4 +68,5 @@ def generate_device_list():
md_file.write("".join(toc_links) + tables_output)
md_file.close()


generate_device_list()
2 changes: 1 addition & 1 deletion .github/workflows/json_librarian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
devices = devices_json.get("devices")
# Sort the devices by manufacturer and model
devices.sort(key=lambda k: (k["manufacturer"].lower(), k["model"].lower(), k.get("hw_version", "").lower()))
devices.sort(key=lambda k: (k["manufacturer"].lower(), k.get("model_match_method", "").lower(), k["model"].lower(), k.get("model_id", "").lower(), k.get("hw_version", "").lower()))
with open("custom_components/battery_notes/data/library.json", "w", encoding="UTF-8") as f:
f.write(json.dumps(devices_json, indent=4))
Expand Down
27 changes: 20 additions & 7 deletions .github/workflows/new_device.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,20 @@ jobs:
# Remove the "battery_quantity" key from the device dictionary if it's 1
new_device = ${{ steps.device-data.outputs.json }}
# Convert battery_quantity field to a numeric
numeric_quantity = int(new_device["battery_quantity"])
numeric_quantity = int(new_device["battery_quantity"])
del new_device["battery_quantity"]
# Add numeric "battery_quantity" key if it's more than 1
if numeric_quantity > 1:
new_device["battery_quantity"] = numeric_quantity
if new_device.get("model_id", "MISSING").strip() == "":
del new_device["model_id"]
if new_device.get("hw_version", "MISSING").strip() == "":
del new_device["hw_version"]
# Check for duplicates and replace old entry with new one
duplicate_found = False
for i, device in enumerate(devices):
if device["manufacturer"] == new_device["manufacturer"] and device["model"] == new_device["model"]:
if device["manufacturer"] == new_device["manufacturer"] and device["model"] == new_device["model"] and device.get("model_id", "") == new_device.get("model_id", "") and device.get("hw_version", "") == new_device.get("hw_version", ""):
devices[i] = new_device
duplicate_found = True
break
Expand All @@ -62,15 +66,17 @@ jobs:
devices.append(new_device)
# Save manufacturer and model for later use
set_output("mm", "_".join(re.findall(r"\w+",f"{new_device['manufacturer']}{new_device['model']})".lower())))
set_output("branch", "_".join(re.findall(r"\w+",f"{new_device['manufacturer']}{new_device['model']}{new_device.get('model_id', '')}{new_device.get('hw_version', '')})".lower())))
set_output("manufacturer", "_".join(re.findall(r"\w+",f"{new_device['manufacturer']})")))
set_output("model", "_".join(re.findall(r"\w+",f"{new_device['model']})")))
set_output("model_id", "_".join(re.findall(r"\w+",f"{new_device.get('model_id', '')})")))
set_output("hw_version", "_".join(re.findall(r"\w+",f"{new_device.get('hw_version', '')})")))
set_output("bqt", f"{numeric_quantity}x {new_device['battery_type']}")
if duplicate_found:
set_output("mode", "updates")
else:
set_output("mode", "adds")
set_output("mode", "adds")
with open("custom_components/battery_notes/data/library.json", "w") as f:
f.write(json.dumps(devices_json, indent=4))
Expand All @@ -96,10 +102,17 @@ jobs:
with:
commit-message: "Update device: ${{ steps.update-json.outputs.model }} by ${{ steps.update-json.outputs.manufacturer }}"
title: "Device: ${{ steps.update-json.outputs.manufacturer }} - ${{ steps.update-json.outputs.model }}"
body: "This pull request ${{ steps.update-json.outputs.mode }} the device information for ${{ steps.update-json.outputs.model }} by ${{ steps.update-json.outputs.manufacturer }} with ${{ steps.update-json.outputs.bqt }}\nIt closes issue #${{ github.event.issue.number }}"
branch: "device-${{ steps.update-json.outputs.mm }}"
body: |
This pull request ${{ steps.update-json.outputs.mode }} the device information for:
Manufacturer: ${{ steps.update-json.outputs.manufacturer }}
Model: ${{ steps.update-json.outputs.model }}
Model ID: ${{ steps.update-json.outputs.model_id }}
Hardware: ${{ steps.update-json.outputs.hw_version }}
Battery: ${{ steps.update-json.outputs.bqt }}
It closes issue #${{ github.event.issue.number }}
branch: "device-${{ steps.update-json.outputs.branch }}"

- name: Close Issue
run: gh issue close --comment "Thanks for the contribution. We're auto-closing this issue. If it's a new device, a pull request will be created that will be reviewed and merged." ${{github.event.issue.number}}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 0 additions & 1 deletion custom_components/battery_notes/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ async def async_registry_updated(event: Event) -> None:
unique_id_suffix="_battery_low",
key="_battery_plus_low",
translation_key="battery_low",
icon="mdi:battery-alert",
entity_category=EntityCategory.DIAGNOSTIC,
device_class=BinarySensorDeviceClass.BATTERY,
)
Expand Down
1 change: 0 additions & 1 deletion custom_components/battery_notes/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ async def async_registry_updated(event: Event) -> None:
unique_id_suffix="_battery_replaced_button",
key="battery_replaced",
translation_key="battery_replaced",
icon="mdi:battery-sync",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=enable_replaced,
)
Expand Down
9 changes: 9 additions & 0 deletions custom_components/battery_notes/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Common functions for battery_notes."""

from homeassistant.helpers.device_registry import DeviceEntry


def validate_is_float(num):
"""Validate value is a float."""
Expand All @@ -10,3 +12,10 @@ def validate_is_float(num):
except ValueError:
return False
return False

def get_device_model_id(device_entry: DeviceEntry) -> str | None:
"""Get the device model if available."""
if hasattr(device_entry, "model_id"):
return device_entry.model_id
else:
return None
41 changes: 36 additions & 5 deletions custom_components/battery_notes/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from homeassistant.helpers.typing import DiscoveryInfoType
from homeassistant.util import dt as dt_util

from .common import get_device_model_id
from .const import (
CONF_BATTERY_LOW_TEMPLATE,
CONF_BATTERY_LOW_THRESHOLD,
Expand All @@ -31,6 +32,7 @@
CONF_DEVICE_NAME,
CONF_MANUFACTURER,
CONF_MODEL,
CONF_MODEL_ID,
CONF_SHOW_ALL_DEVICES,
CONF_SOURCE_ENTITY_ID,
DATA_LIBRARY_UPDATER,
Expand Down Expand Up @@ -131,6 +133,7 @@ async def async_step_integration_discovery(
"name": discovery_info[CONF_DEVICE_NAME],
"manufacturer": discovery_info[CONF_MANUFACTURER],
"model": discovery_info[CONF_MODEL],
"model_id": discovery_info[CONF_MODEL_ID],
}

return await self.async_step_device(discovery_info)
Expand All @@ -149,6 +152,8 @@ async def async_step_device(
) -> config_entries.FlowResult:
"""Handle a flow for a device or discovery."""
errors: dict[str, str] = {}
device_battery_details = None

if user_input is not None:
self.data = user_input

Expand All @@ -167,14 +172,15 @@ async def async_step_device(
device_entry = device_registry.async_get(device_id)

_LOGGER.debug(
"Looking up device %s %s %s",
"Looking up device %s %s %s %s",
device_entry.manufacturer,
device_entry.model,
get_device_model_id(device_entry) or "",
device_entry.hw_version,
)

model_info = ModelInfo(
device_entry.manufacturer, device_entry.model, device_entry.hw_version
device_entry.manufacturer, device_entry.model, get_device_model_id(device_entry), device_entry.hw_version
)

library = await Library.factory(self.hass)
Expand All @@ -188,9 +194,10 @@ async def async_step_device(

if device_battery_details and not device_battery_details.is_manual:
_LOGGER.debug(
"Found device %s %s %s",
"Found device %s %s %s %s",
device_entry.manufacturer,
device_entry.model,
get_device_model_id(device_entry) or "",
device_entry.hw_version,
)
self.data[CONF_BATTERY_TYPE] = device_battery_details.battery_type
Expand All @@ -199,6 +206,9 @@ async def async_step_device(
device_battery_details.battery_quantity
)

if device_battery_details and device_battery_details.is_manual:
return await self.async_step_manual()

return await self.async_step_battery()

schema = DEVICE_SCHEMA
Expand All @@ -221,6 +231,8 @@ async def async_step_entity(
) -> config_entries.FlowResult:
"""Handle a flow for a device or discovery."""
errors: dict[str, str] = {}
device_battery_details = None

if user_input is not None:
self.data = user_input

Expand Down Expand Up @@ -249,15 +261,17 @@ async def async_step_entity(
device_entry = device_registry.async_get(entity_entry.device_id)

_LOGGER.debug(
"Looking up device %s %s %s",
"Looking up device %s %s %s %s",
device_entry.manufacturer,
device_entry.model,
get_device_model_id(device_entry) or "",
device_entry.hw_version,
)

model_info = ModelInfo(
device_entry.manufacturer,
device_entry.model,
get_device_model_id(device_entry),
device_entry.hw_version,
)

Expand All @@ -269,9 +283,10 @@ async def async_step_entity(

if device_battery_details and not device_battery_details.is_manual:
_LOGGER.debug(
"Found device %s %s %s",
"Found device %s %s %s %s",
device_entry.manufacturer,
device_entry.model,
get_device_model_id(device_entry) or "",
device_entry.hw_version,
)
self.data[CONF_BATTERY_TYPE] = (
Expand All @@ -282,6 +297,8 @@ async def async_step_entity(
device_battery_details.battery_quantity
)

if device_battery_details and device_battery_details.is_manual:
return await self.async_step_manual()
return await self.async_step_battery()
else:
# No entity_registry entry, must be a config.yaml entity which we can't support
Expand All @@ -296,6 +313,20 @@ async def async_step_entity(
last_step=False,
)

async def async_step_manual(self, user_input: dict[str, Any] | None = None):
"""Second step in config flow to add the battery type."""
errors: dict[str, str] = {}
if user_input is not None:
return await self.async_step_battery()

return self.async_show_form(
step_id="manual",
data_schema=None,
last_step=False,
errors=errors,
)


async def async_step_battery(self, user_input: dict[str, Any] | None = None):
"""Second step in config flow to add the battery type."""
errors: dict[str, str] = {}
Expand Down
6 changes: 3 additions & 3 deletions custom_components/battery_notes/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
from logging import Logger, getLogger
from pathlib import Path
from typing import Final
import voluptuous as vol

import voluptuous as vol
from homeassistant.const import Platform

from homeassistant.helpers import config_validation as cv

LOGGER: Logger = getLogger(__package__)

MIN_HA_VERSION = "2024.4"
MIN_HA_VERSION = "2024.5"

manifestfile = Path(__file__).parent / "manifest.json"
with open(file=manifestfile, encoding="UTF-8") as json_file:
Expand Down Expand Up @@ -40,6 +39,7 @@
CONF_ENABLE_AUTODISCOVERY = "enable_autodiscovery"
CONF_USER_LIBRARY = "user_library"
CONF_MODEL = "model"
CONF_MODEL_ID = "model_id"
CONF_MANUFACTURER = "manufacturer"
CONF_DEVICE_NAME = "device_name"
CONF_LIBRARY_URL = "https://raw.githubusercontent.com/andrew-codechimp/HA-Battery-Notes/main/custom_components/battery_notes/data/library.json" # pylint: disable=line-too-long
Expand Down
Loading

0 comments on commit c9cf787

Please sign in to comment.