diff --git a/.coverage b/.coverage index 6fef892..954afdd 100644 Binary files a/.coverage and b/.coverage differ diff --git a/homewizard_energy/__init__.py b/homewizard_energy/__init__.py index f34780a..3341ee6 100644 --- a/homewizard_energy/__init__.py +++ b/homewizard_energy/__init__.py @@ -1,5 +1,6 @@ """HomeWizard Energy API library.""" +from .brand import Product from .errors import DisabledError, InvalidStateError, RequestError, UnsupportedError from .homewizard_energy import HomeWizardEnergy from .models import Data, Device, ExternalDevice, State, System @@ -15,4 +16,5 @@ "ExternalDevice", "State", "System", + "Product", ] diff --git a/homewizard_energy/brand.py b/homewizard_energy/brand.py new file mode 100644 index 0000000..9bf5305 --- /dev/null +++ b/homewizard_energy/brand.py @@ -0,0 +1,95 @@ +"""Brand specific information for HomeWizard Energy.""" + +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class Product: + """Represent a product.""" + + model: str + name: str | None + url: str | None + description: str | None + + def __str__(self): + """Return a string representation of the product.""" + return f"HomeWizard {self.name} - {self.model}" + + def __hash__(self): + """Hash a product for unit-test snapshots.""" + return hash((self.model, self.name, self.url, self.description)) + + def __eq__(self, other): + """Compare two products.""" + if isinstance(other, Product): + return ( + self.model == other.model + and self.name == other.name + and self.url == other.url + and self.description == other.description + ) + return False + + +PRODUCTS = { + Product( + "HWE-P1", + "Wi-Fi P1 Meter", + "https://www.homewizard.com/p1-meter/", + "The HomeWizard P1 Meter gives you detailed insight in your electricity-, gas consumption and solar surplus.", + ), + Product( + "HWE-SKT", + "Energy Socket", + "https://www.homewizard.com/energy-socket/", + "Measure and switch every device.", + ), + Product( + "HWE-WTR", + "Wi-Fi Watermeter", + "https://www.homewizard.com/watermeter/", + "Real-time water consumption insights", + ), + Product( + "HWE-KWH1", + "Wi-Fi kWh meter 1-phase", + "https://www.homewizard.com/kwh-meter/", + "Measure solar panels, car chargers and more.", + ), + Product( + "HWE-KWH3", + "Wi-Fi kWh meter 3-phase", + "https://www.homewizard.com/kwh-meter/", + "Measure solar panels, car chargers and more.", + ), + Product( + "SDM230-wifi", + "Wi-Fi kWh meter 1-phase", + "https://www.homewizard.com/kwh-meter/", + "Measure solar panels, car chargers and more.", + ), + Product( + "SDM630-wifi", + "Wi-Fi kWh meter 3-phase", + "https://www.homewizard.com/kwh-meter/", + "Measure solar panels, car chargers and more.", + ), +} + + +def from_type(product_type: str, _: str | None = None) -> Product | None: + """Return a Product object from a type. + + :param type: The type of the product. + :param locale: The locale to use for the description. Currently ignored. Should be an ISO 639-1 language code. + """ + + # pylint: disable=unused-argument + + for product in PRODUCTS: + if product.model == product_type: + return product + return None diff --git a/homewizard_energy/models.py b/homewizard_energy/models.py index 26a30ae..73a38cd 100644 --- a/homewizard_energy/models.py +++ b/homewizard_energy/models.py @@ -8,11 +8,14 @@ from enum import Enum from typing import Any +from .brand import Product, from_type + @dataclass class Device: """Represent Device config.""" + product: Product | None product_name: str | None product_type: str | None serial: str | None @@ -30,6 +33,7 @@ def from_dict(data: dict[str, str]) -> Device: A Device object. """ return Device( + product=from_type(data.get("product_type")), product_name=data.get("product_name"), product_type=data.get("product_type"), serial=data.get("serial"), diff --git a/tests/__snapshots__/test_brand.ambr b/tests/__snapshots__/test_brand.ambr new file mode 100644 index 0000000..e09a82c --- /dev/null +++ b/tests/__snapshots__/test_brand.ambr @@ -0,0 +1,55 @@ +# serializer version: 1 +# name: test_known_product_strings[HWE-KWH1] + 'HomeWizard Wi-Fi kWh meter 1-phase - HWE-KWH1' +# --- +# name: test_known_product_strings[HWE-KWH3] + 'HomeWizard Wi-Fi kWh meter 3-phase - HWE-KWH3' +# --- +# name: test_known_product_strings[HWE-P1] + 'HomeWizard Wi-Fi P1 Meter - HWE-P1' +# --- +# name: test_known_product_strings[HWE-SKT] + 'HomeWizard Energy Socket - HWE-SKT' +# --- +# name: test_known_product_strings[HWE-WTR] + 'HomeWizard Wi-Fi Watermeter - HWE-WTR' +# --- +# name: test_known_product_strings[SDM230-wifi] + 'HomeWizard Wi-Fi kWh meter 1-phase - SDM230-wifi' +# --- +# name: test_known_product_strings[SDM630-wifi] + 'HomeWizard Wi-Fi kWh meter 3-phase - SDM630-wifi' +# --- +# name: test_known_products[HWE-KWH1] + Product(model='HWE-KWH1', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.') +# --- +# name: test_known_products[HWE-KWH3] + Product(model='HWE-KWH3', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.') +# --- +# name: test_known_products[HWE-P1] + Product(model='HWE-P1', name='Wi-Fi P1 Meter', url='https://www.homewizard.com/p1-meter/', description='The HomeWizard P1 Meter gives you detailed insight in your electricity-, gas consumption and solar surplus.') +# --- +# name: test_known_products[HWE-SKT] + Product(model='HWE-SKT', name='Energy Socket', url='https://www.homewizard.com/energy-socket/', description='Measure and switch every device.') +# --- +# name: test_known_products[HWE-WTR] + Product(model='HWE-WTR', name='Wi-Fi Watermeter', url='https://www.homewizard.com/watermeter/', description='Real-time water consumption insights') +# --- +# name: test_known_products[SDM230-wifi] + Product(model='SDM230-wifi', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.') +# --- +# name: test_known_products[SDM630-wifi] + Product(model='SDM630-wifi', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.') +# --- +# name: test_unknown_or_invalid_products[HWE-P2] + None +# --- +# name: test_unknown_or_invalid_products[None] + None +# --- +# name: test_unknown_or_invalid_products[WTR] + None +# --- +# name: test_unknown_or_invalid_products[] + None +# --- diff --git a/tests/__snapshots__/test_homewizard_energy.ambr b/tests/__snapshots__/test_homewizard_energy.ambr index 398f15d..6521d20 100644 --- a/tests/__snapshots__/test_homewizard_energy.ambr +++ b/tests/__snapshots__/test_homewizard_energy.ambr @@ -60,25 +60,25 @@ Data(wifi_ssid='HW WiFi', wifi_strength=84, smr_version=None, meter_model=None, unique_meter_id=None, active_tariff=None, total_energy_import_kwh=2940.101, total_energy_import_t1_kwh=2940.101, total_energy_import_t2_kwh=None, total_energy_import_t3_kwh=None, total_energy_import_t4_kwh=None, total_energy_export_kwh=0, total_energy_export_t1_kwh=0, total_energy_export_t2_kwh=None, total_energy_export_t3_kwh=None, total_energy_export_t4_kwh=None, active_power_w=7100.278, active_power_l1_w=0, active_power_l2_w=3547.015, active_power_l3_w=3553.263, active_voltage_v=None, active_voltage_l1_v=230.751, active_voltage_l2_v=228.391, active_voltage_l3_v=229.612, active_current_a=30.999, active_current_l1_a=0, active_current_l2_a=15.521, active_current_l3_a=15.477, active_apparent_power_va=7112.293, active_apparent_power_l1_va=0, active_apparent_power_l2_va=3548.879, active_apparent_power_l3_va=3563.414, active_reactive_power_var=-429.025, active_reactive_power_l1_var=0, active_reactive_power_l2_var=-166.675, active_reactive_power_l3_var=-262.35, active_power_factor=None, active_power_factor_l1=1, active_power_factor_l2=0.999, active_power_factor_l3=0.997, active_frequency_hz=49.926, voltage_sag_l1_count=None, voltage_sag_l2_count=None, voltage_sag_l3_count=None, voltage_swell_l1_count=None, voltage_swell_l2_count=None, voltage_swell_l3_count=None, any_power_fail_count=None, long_power_fail_count=None, active_power_average_w=None, monthly_power_peak_w=None, monthly_power_peak_timestamp=None, total_gas_m3=None, gas_timestamp=None, gas_unique_id=None, active_liter_lpm=None, total_liter_m3=None, external_devices=None) # --- # name: test_get_device_object[HWE-KWH1-fixtures3] - Device(product_name='kWh Meter', product_type='HWE-KWH1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-KWH1', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter', product_type='HWE-KWH1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[HWE-KWH3-fixtures4] - Device(product_name='kWh Meter 3-phase', product_type='HWE-KWH3', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-KWH3', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter 3-phase', product_type='HWE-KWH3', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[HWE-P1-fixtures0] - Device(product_name='P1 Meter', product_type='HWE-P1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-P1', name='Wi-Fi P1 Meter', url='https://www.homewizard.com/p1-meter/', description='The HomeWizard P1 Meter gives you detailed insight in your electricity-, gas consumption and solar surplus.'), product_name='P1 Meter', product_type='HWE-P1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[HWE-SKT-fixtures1] - Device(product_name='Energy Socket', product_type='HWE-SKT', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-SKT', name='Energy Socket', url='https://www.homewizard.com/energy-socket/', description='Measure and switch every device.'), product_name='Energy Socket', product_type='HWE-SKT', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[HWE-WTR-fixtures2] - Device(product_name='Water Meter', product_type='HWE-WTR', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-WTR', name='Wi-Fi Watermeter', url='https://www.homewizard.com/watermeter/', description='Real-time water consumption insights'), product_name='Water Meter', product_type='HWE-WTR', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[SDM230-wifi-fixtures5] - Device(product_name='kWh Meter', product_type='SDM230-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='SDM230-wifi', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter', product_type='SDM230-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_device_object[SDM630-wifi-fixtures6] - Device(product_name='kWh Meter 3-phase', product_type='SDM630-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='SDM630-wifi', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter 3-phase', product_type='SDM630-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_get_state_object[HWE-SKT-fixtures0] State(power_on=False, switch_lock=False, brightness=255) diff --git a/tests/__snapshots__/test_models.ambr b/tests/__snapshots__/test_models.ambr index 5493c66..11832dc 100644 --- a/tests/__snapshots__/test_models.ambr +++ b/tests/__snapshots__/test_models.ambr @@ -33,25 +33,25 @@ Data(wifi_ssid='HW WiFi', wifi_strength=84, smr_version=None, meter_model=None, unique_meter_id=None, active_tariff=None, total_energy_import_kwh=2940.101, total_energy_import_t1_kwh=2940.101, total_energy_import_t2_kwh=None, total_energy_import_t3_kwh=None, total_energy_import_t4_kwh=None, total_energy_export_kwh=0, total_energy_export_t1_kwh=0, total_energy_export_t2_kwh=None, total_energy_export_t3_kwh=None, total_energy_export_t4_kwh=None, active_power_w=7100.278, active_power_l1_w=0, active_power_l2_w=3547.015, active_power_l3_w=3553.263, active_voltage_v=None, active_voltage_l1_v=230.751, active_voltage_l2_v=228.391, active_voltage_l3_v=229.612, active_current_a=30.999, active_current_l1_a=0, active_current_l2_a=15.521, active_current_l3_a=15.477, active_apparent_power_va=7112.293, active_apparent_power_l1_va=0, active_apparent_power_l2_va=3548.879, active_apparent_power_l3_va=3563.414, active_reactive_power_var=-429.025, active_reactive_power_l1_var=0, active_reactive_power_l2_var=-166.675, active_reactive_power_l3_var=-262.35, active_power_factor=None, active_power_factor_l1=1, active_power_factor_l2=0.999, active_power_factor_l3=0.997, active_frequency_hz=49.926, voltage_sag_l1_count=None, voltage_sag_l2_count=None, voltage_sag_l3_count=None, voltage_swell_l1_count=None, voltage_swell_l2_count=None, voltage_swell_l3_count=None, any_power_fail_count=None, long_power_fail_count=None, active_power_average_w=None, monthly_power_peak_w=None, monthly_power_peak_timestamp=None, total_gas_m3=None, gas_timestamp=None, gas_unique_id=None, active_liter_lpm=None, total_liter_m3=None, external_devices=None) # --- # name: test_device[HWE-KWH1-fixtures3] - Device(product_name='kWh Meter', product_type='HWE-KWH1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-KWH1', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter', product_type='HWE-KWH1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[HWE-KWH3-fixtures4] - Device(product_name='kWh Meter 3-phase', product_type='HWE-KWH3', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-KWH3', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter 3-phase', product_type='HWE-KWH3', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[HWE-P1-fixtures0] - Device(product_name='P1 Meter', product_type='HWE-P1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-P1', name='Wi-Fi P1 Meter', url='https://www.homewizard.com/p1-meter/', description='The HomeWizard P1 Meter gives you detailed insight in your electricity-, gas consumption and solar surplus.'), product_name='P1 Meter', product_type='HWE-P1', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[HWE-SKT-fixtures1] - Device(product_name='Energy Socket', product_type='HWE-SKT', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-SKT', name='Energy Socket', url='https://www.homewizard.com/energy-socket/', description='Measure and switch every device.'), product_name='Energy Socket', product_type='HWE-SKT', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[HWE-WTR-fixtures2] - Device(product_name='Water Meter', product_type='HWE-WTR', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='HWE-WTR', name='Wi-Fi Watermeter', url='https://www.homewizard.com/watermeter/', description='Real-time water consumption insights'), product_name='Water Meter', product_type='HWE-WTR', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[SDM230-wifi-fixtures5] - Device(product_name='kWh Meter', product_type='SDM230-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='SDM230-wifi', name='Wi-Fi kWh meter 1-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter', product_type='SDM230-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_device[SDM630-wifi-fixtures6] - Device(product_name='kWh Meter 3-phase', product_type='SDM630-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') + Device(product=Product(model='SDM630-wifi', name='Wi-Fi kWh meter 3-phase', url='https://www.homewizard.com/kwh-meter/', description='Measure solar panels, car chargers and more.'), product_name='kWh Meter 3-phase', product_type='SDM630-wifi', serial='3c39e7aabbcc', api_version='v1', firmware_version='2.11') # --- # name: test_state[HWE-SKT-fixtures0] State(power_on=False, switch_lock=False, brightness=255) diff --git a/tests/test_brand.py b/tests/test_brand.py new file mode 100644 index 0000000..d04d814 --- /dev/null +++ b/tests/test_brand.py @@ -0,0 +1,82 @@ +"""Test for HomeWizard Energy Models.""" + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homewizard_energy.brand import from_type + +pytestmark = [pytest.mark.asyncio] + + +@pytest.mark.parametrize( + ("model"), + [ + ("HWE-P1"), + ("HWE-SKT"), + ("HWE-WTR"), + ("HWE-KWH1"), + ("HWE-KWH3"), + ("SDM230-wifi"), + ("SDM630-wifi"), + ], +) +async def test_known_products(model: str, snapshot: SnapshotAssertion): + """Test known products.""" + + product = from_type(model) + assert product is not None + assert snapshot == product + + +@pytest.mark.parametrize( + ("model"), + [ + ("HWE-P1"), + ("HWE-SKT"), + ("HWE-WTR"), + ("HWE-KWH1"), + ("HWE-KWH3"), + ("SDM230-wifi"), + ("SDM630-wifi"), + ], +) +async def test_known_product_strings(model: str, snapshot: SnapshotAssertion): + """Test generating product strings.""" + + product = from_type(model) + assert product is not None + assert snapshot == str(product) + + +@pytest.mark.parametrize( + ("model"), + [ + ("HWE-P2"), + (None), + ("WTR"), + (""), + ], +) +async def test_unknown_or_invalid_products(model: str, snapshot: SnapshotAssertion): + """Test unknown or invalid products types.""" + + product = from_type(model) + assert product is None + assert snapshot == product + + +@pytest.mark.parametrize( + ("lhs", "rhs", "value"), + [ + ("HWE-P1", "HWE-P1", True), + ("HWE-P1", "HWE-SKT", False), + ("HWE-P1", None, False), + ("HWE-P1", "", False), + ], +) +async def test_comparison_between_products(lhs: str, rhs: str, value: bool): + """Test comparison between products.""" + + lhs = from_type(lhs) + rhs = from_type(rhs) + assert (lhs == rhs) == value