From 86a7b1dd9f304e20c22ee4a6ebfddb289aa7a11e Mon Sep 17 00:00:00 2001 From: faanskit Date: Thu, 25 Jan 2024 10:04:14 +0000 Subject: [PATCH 1/9] Untested push to git, awaiting new pyCheckwatt --- custom_components/checkwatt/__init__.py | 150 ++++---- custom_components/checkwatt/config_flow.py | 19 +- custom_components/checkwatt/const.py | 19 +- custom_components/checkwatt/manifest.json | 4 +- custom_components/checkwatt/sensor.py | 323 +++++------------- custom_components/checkwatt/strings.json | 50 +-- .../checkwatt/translations/en.json | 50 +-- .../checkwatt/translations/sv.json | 51 +-- 8 files changed, 168 insertions(+), 498 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index fc779fa..b9eb1b9 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -4,7 +4,6 @@ import asyncio from datetime import time, timedelta import logging -import random import re from typing import TypedDict @@ -22,7 +21,7 @@ from .const import ( BASIC_TEST, CONF_CM10_SENSOR, - CONF_DETAILED_SENSORS, + CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL_FCRD, @@ -46,17 +45,26 @@ class CheckwattResp(TypedDict): zip: str city: str display_name: str - revenue: float - fees: float - battery_charge_peak: float - battery_discharge_peak: float - tomorrow_revenue: float - tomorrow_fees: float + dso: str + energy_provider: str + + battery_power: float + grid_power: float + solar_power: float + battery_soc: float + charge_peak_ac: float + charge_peak_dc: float + discharge_peak_ac: float + discharge_peak_dc: float + + today_net_revenue: float + tomorrow_net_revenue: float + monthly_net_revenue: float + annual_net_revenue: float + update_time: str next_update_time: str - fcr_d_status: str - fcr_d_info: str - fcr_d_date: str + total_solar_energy: float total_charging_energy: float total_discharging_energy: float @@ -64,20 +72,12 @@ class CheckwattResp(TypedDict): total_export_energy: float spot_price: float price_zone: str - annual_revenue: float - annual_fees: float - grid_power: float - solar_power: float - battery_power: float - battery_soc: float - dso: str - energy_provider: str + cm10_status: str cm10_version: str - charge_peak_ac: float - charge_peak_dc: float - discharge_peak_ac: float - discharge_peak_dc: float + fcr_d_status: str + fcr_d_info: str + fcr_d_date: str async def update_listener(hass: HomeAssistant, entry): @@ -177,26 +177,19 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: update_interval=timedelta(minutes=CONF_UPDATE_INTERVAL), ) self._entry = entry - self.update_monetary = 0 self.update_time = None self.next_update_time = None - self.today_revenue = None - self.today_fees = None - self.tomorrow_revenue = None - self.tomorrow_fees = None - self.annual_revenue = None - self.annual_fees = None - self.last_annual_update = None + self.today_net_revenue = None + self.tomorrow_net_revenue = None + self.monthly_net_revenue = None + self.annual_net_revenue = None self.last_cw_rank_push = None self.is_boot = True self.energy_provider = None - self.random_offset = random.randint(0, 14) self.fcrd_state = None self.fcrd_info = None self.fcrd_timestamp = None self._id = None - self.update_no = 0 - _LOGGER.debug("Fetching annual revenue at 3:%02d am", self.random_offset) @property def entry_id(self) -> str: @@ -209,7 +202,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 try: username = self._entry.data.get(CONF_USERNAME) password = self._entry.data.get(CONF_PASSWORD) - use_detailed_sensors = self._entry.options.get(CONF_DETAILED_SENSORS) + use_detailed_sensors = self._entry.options.get(CONF_POWER_SENSORS) push_to_cw_rank = self._entry.options.get(CONF_PUSH_CW_TO_RANK) use_cm10_sensor = self._entry.options.get(CONF_CM10_SENSOR) @@ -238,10 +231,8 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 # Prevent slow funcion to be called at boot. # The revenue sensors will be updated after ca 1 min - self.update_no += 1 - if self.update_no > 2: - self.is_boot = False if self.is_boot: + self.is_boot = False if ( "Meter" in cw_inst.customer_details and len(cw_inst.customer_details["Meter"]) > 0 @@ -255,36 +246,26 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 self.fcrd_state = fcrd_state self._id = cw_inst.customer_details["Id"] - else: - if self.update_monetary == 0: - _LOGGER.debug("Fetching FCR-D data from CheckWatt") - self.update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") - end_date = dt_util.now() + timedelta( - minutes=CONF_UPDATE_INTERVAL_FCRD - ) - self.next_update_time = end_date.strftime("%Y-%m-%d %H:%M:%S") - self.update_monetary = CONF_UPDATE_INTERVAL_FCRD - if not await cw_inst.get_fcrd_revenue(): - raise UpdateFailed("Unknown error get_fcrd_revenue") - self.today_revenue, self.today_fees = cw_inst.today_revenue - ( - self.tomorrow_revenue, - self.tomorrow_fees, - ) = cw_inst.tomorrow_revenue - - if self.last_annual_update is None or ( - dt_util.now().time() - >= time(3, self.random_offset) # Wait until 3am +- 15 min - and dt_util.start_of_local_day(dt_util.now()) - != dt_util.start_of_local_day(self.last_annual_update) - ): - _LOGGER.debug("Fetching annual revenue") - if not await cw_inst.get_fcrd_revenueyear(): - raise UpdateFailed("Unknown error get_fcrd_revenueyear") - self.annual_revenue, self.annual_fees = cw_inst.year_revenue - self.last_annual_update = dt_util.now() + self.update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") + end_date = dt_util.now() + timedelta(minutes=CONF_UPDATE_INTERVAL_FCRD) + self.next_update_time = end_date.strftime("%Y-%m-%d %H:%M:%S") + + _LOGGER.debug("Fetching daily revenue") + if not await cw_inst.get_net_revenue_today(): + raise UpdateFailed("Unknown error get_fcrd_revenue") + + _LOGGER.debug("Fetching annual revenue") + if not await cw_inst.get_revenue_year(): + raise UpdateFailed("Unknown error get_revenue_year") + + _LOGGER.debug("Fetching monthly revenue") + if not await cw_inst.get_revenue_month(): + raise UpdateFailed("Unknown error get_revenue_month") - self.update_monetary -= 1 + self.today_net_revenue = cw_inst.today_net_revenue + self.tomorrow_net_revenue = cw_inst.tomorrow_net_revenue + self.monthly_net_revenue = cw_inst.monthly_net_revenue + self.annual_net_revenue = cw_inst.annual_net_revenue # Price Zone is used both as Detailed Sensor and by Push to CheckWattRank if push_to_cw_rank or use_detailed_sensors: @@ -315,13 +296,6 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 "zip": cw_inst.customer_details["ZipCode"], "city": cw_inst.customer_details["City"], "display_name": cw_inst.customer_details["Meter"][0]["DisplayName"], - "update_time": self.update_time, - "next_update_time": self.next_update_time, - "fcr_d_status": fcrd_state, - "fcr_d_info": fcrd_info, - "fcr_d_date": fcrd_timestamp, - "battery_charge_peak": cw_inst.battery_charge_peak, - "battery_discharge_peak": cw_inst.battery_discharge_peak, "dso": cw_inst.battery_registration["Dso"], "energy_provider": self.energy_provider, } @@ -342,15 +316,16 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["discharge_peak_dc"] = discharge_peak_dc # Use self stored variant of revenue parameters as they are not always fetched - if self.today_revenue is not None: - resp["revenue"] = self.today_revenue - resp["fees"] = self.today_fees - resp["tomorrow_revenue"] = self.tomorrow_revenue - resp["tomorrow_fees"] = self.tomorrow_fees + if self.today_net_revenue is not None: + resp["today_net_revenue"] = self.today_net_revenue + resp["tomorrow_net_revenue"] = self.tomorrow_net_revenue + if self.monthly_net_revenue is not None: + resp["monthly_net_revenue"] = self.monthly_net_revenue + if self.annual_net_revenue is not None: + resp["annual_net_revenue"] = self.annual_net_revenue - if self.annual_revenue is not None: - resp["annual_revenue"] = self.annual_revenue - resp["annual_fees"] = self.annual_fees + resp["update_time"] = self.update_time + resp["next_update_time"] = self.next_update_time if use_detailed_sensors: resp["total_solar_energy"] = cw_inst.total_solar_energy @@ -371,6 +346,9 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["cm10_status"] = "Active" resp["cm10_version"] = cw_inst.meter_version + resp["fcr_d_status"] = fcrd_state + resp["fcr_d_info"] = fcrd_info + resp["fcr_d_date"] = fcrd_timestamp # Check if FCR-D State has changed and dispatch it ACTIVATED/ DEACTIVATED old_state = self.fcrd_state @@ -423,7 +401,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 async def push_to_checkwatt_rank(self, cw_inst): """Push data to CheckWattRank.""" - if self.today_revenue is not None: + if self.today_net_revenue is not None: if ( "Meter" in cw_inst.customer_details and len(cw_inst.customer_details["Meter"]) > 0 @@ -437,9 +415,9 @@ async def push_to_checkwatt_rank(self, cw_inst): "electricity_company": self.energy_provider, "electricity_area": cw_inst.price_zone, "installed_power": cw_inst.battery_charge_peak, - "today_gross_income": self.today_revenue, - "today_fee": self.today_fees, - "today_net_income": self.today_revenue - self.today_fees, + "today_gross_income": 0, + "today_fee": 0, + "today_net_income": self.today_net_revenue, "reseller_id": cw_inst.customer_details["Meter"][0]["ResellerId"], } if BASIC_TEST: diff --git a/custom_components/checkwatt/config_flow.py b/custom_components/checkwatt/config_flow.py index 9ecaa22..157fd38 100644 --- a/custom_components/checkwatt/config_flow.py +++ b/custom_components/checkwatt/config_flow.py @@ -13,13 +13,7 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError -from .const import ( - CONF_CM10_SENSOR, - CONF_DETAILED_ATTRIBUTES, - CONF_DETAILED_SENSORS, - CONF_PUSH_CW_TO_RANK, - DOMAIN, -) +from .const import CONF_CM10_SENSOR, CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, DOMAIN CONF_TITLE = "CheckWatt" @@ -76,8 +70,7 @@ async def async_step_user( title=CONF_TITLE, data=self.data, options={ - CONF_DETAILED_SENSORS: False, - CONF_DETAILED_ATTRIBUTES: False, + CONF_POWER_SENSORS: False, CONF_PUSH_CW_TO_RANK: False, CONF_CM10_SENSOR: False, }, @@ -115,12 +108,8 @@ async def async_step_init( data_schema=vol.Schema( { vol.Required( - CONF_DETAILED_SENSORS, - default=self.config_entry.options.get(CONF_DETAILED_SENSORS), - ): bool, - vol.Required( - CONF_DETAILED_ATTRIBUTES, - default=self.config_entry.options.get(CONF_DETAILED_ATTRIBUTES), + CONF_POWER_SENSORS, + default=self.config_entry.options.get(CONF_POWER_SENSORS), ): bool, vol.Required( CONF_PUSH_CW_TO_RANK, diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index 225a5f4..ab25aba 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -7,15 +7,14 @@ # Update interval for regular sensors is once every minute # For FCR-D since it is slow and resource consuming, is set to once per 15 minute CONF_UPDATE_INTERVAL = 1 -CONF_UPDATE_INTERVAL_FCRD = 15 +CONF_UPDATE_INTERVAL_FCRD = 60 ATTRIBUTION = "Data provided by CheckWatt EnergyInBalance" MANUFACTURER = "CheckWatt" CHECKWATT_MODEL = "CheckWatt" -CONF_DETAILED_SENSORS: Final = "show_details" -CONF_DETAILED_ATTRIBUTES: Final = "show_detailed_attributes" +CONF_POWER_SENSORS: Final = "show_details" CONF_PUSH_CW_TO_RANK: Final = "push_to_cw_rank" -CONF_CM10_SENSOR = "cm10_sensor" +CONF_CM10_SENSOR: Final = "cm10_sensor" # Misc P_UNKNOWN = "Unknown" @@ -27,14 +26,9 @@ # NOTE Keep these names aligned with strings.json # C_ADR = "street_address" -C_ANNUAL_FEES = "annual_fees" -C_ANNUAL_FEE_RATE = "annual_fee_rate" -C_ANNUAL_GROSS = "annual_gross_income" C_BATTERY_POWER = "battery_power" -C_CHARGE_PEAK = "charge_peak" C_CITY = "city" C_CM10_VERSION = "cm10_version" -C_DISCHARGE_PEAK = "discharge_peak" C_DISPLAY_NAME = "display_name" C_DSO = "dso" C_GRID_POWER = "grid_power" @@ -45,12 +39,6 @@ C_NEXT_UPDATE_TIME = "next_update" C_PRICE_ZONE = "price_zone" C_SOLAR_POWER = "solar_power" -C_TODAY_FEES = "today_fees" -C_TODAY_FEE_RATE = "today_fees_rate" -C_TODAY_GROSS = "today_gross_income" -C_TOMORROW_FEES = "tomorrow_fees" -C_TOMORROW_FEE_RATE = "tomorrow_fee_rate" -C_TOMORROW_GROSS = "tomorrow_gross_income" C_TOMORROW_NET = "tomorrow_net_income" C_UPDATE_TIME = "last_update" C_VAT = "vat" @@ -60,6 +48,5 @@ C_DISCHARGE_PEAK_AC = "discharge_peak_ac" C_DISCHARGE_PEAK_DC = "discharge_peak_dc" - # CheckWatt Event Signals EVENT_SIGNAL_FCRD = "fcrd" diff --git a/custom_components/checkwatt/manifest.json b/custom_components/checkwatt/manifest.json index 3206055..2d1399c 100644 --- a/custom_components/checkwatt/manifest.json +++ b/custom_components/checkwatt/manifest.json @@ -12,8 +12,8 @@ "homekit": {}, "iot_class": "cloud_polling", "issue_tracker": "https://github.com/faanskit/ha-checkwatt/issues", - "requirements": ["pycheckwatt>=0.1.10", "aiohttp>=3.9.1"], + "requirements": ["pycheckwatt>=0.1.11", "aiohttp>=3.9.1"], "ssdp": [], - "version": "0.1.7", + "version": "0.1.8", "zeroconf": [] } diff --git a/custom_components/checkwatt/sensor.py b/custom_components/checkwatt/sensor.py index 1bc462d..2a7a141 100644 --- a/custom_components/checkwatt/sensor.py +++ b/custom_components/checkwatt/sensor.py @@ -21,16 +21,11 @@ from .const import ( ATTRIBUTION, C_ADR, - C_ANNUAL_FEE_RATE, - C_ANNUAL_FEES, - C_ANNUAL_GROSS, C_BATTERY_POWER, - C_CHARGE_PEAK, C_CHARGE_PEAK_AC, C_CHARGE_PEAK_DC, C_CITY, C_CM10_VERSION, - C_DISCHARGE_PEAK, C_DISCHARGE_PEAK_AC, C_DISCHARGE_PEAK_DC, C_DISPLAY_NAME, @@ -43,20 +38,13 @@ C_NEXT_UPDATE_TIME, C_PRICE_ZONE, C_SOLAR_POWER, - C_TODAY_FEE_RATE, - C_TODAY_FEES, - C_TODAY_GROSS, - C_TOMORROW_FEE_RATE, - C_TOMORROW_FEES, - C_TOMORROW_GROSS, C_TOMORROW_NET, C_UPDATE_TIME, C_VAT, C_ZIP, CHECKWATT_MODEL, CONF_CM10_SENSOR, - CONF_DETAILED_ATTRIBUTES, - CONF_DETAILED_SENSORS, + CONF_POWER_SENSORS, DOMAIN, MANUFACTURER, ) @@ -75,6 +63,15 @@ state_class=SensorStateClass.TOTAL, translation_key="daily_yield_sensor", ), + "monthly": SensorEntityDescription( + key="monthly_yield", + name="CheckWatt Monthly Yield", + icon="mdi:account-cash-outline", + device_class=SensorDeviceClass.MONETARY, + native_unit_of_measurement="SEK", + state_class=SensorStateClass.TOTAL, + translation_key="monthly_yield_sensor", + ), "annual": SensorEntityDescription( key="annual_yield", name="CheckWatt Annual Yield", @@ -179,26 +176,23 @@ async def async_setup_entry( coordinator: CheckwattCoordinator = hass.data[DOMAIN][entry.entry_id] entities: list[AbstractCheckwattSensor] = [] checkwatt_data: CheckwattResp = coordinator.data - use_detailed_sensors = entry.options.get(CONF_DETAILED_SENSORS) - use_detailed_attributes = entry.options.get(CONF_DETAILED_ATTRIBUTES) + use_power_sensors = entry.options.get(CONF_POWER_SENSORS) use_cm10_sensor = entry.options.get(CONF_CM10_SENSOR) _LOGGER.debug("Setting up CheckWatt sensor for %s", checkwatt_data["display_name"]) for key, description in CHECKWATT_MONETARY_SENSORS.items(): if key == "daily": - entities.append( - CheckwattSensor(coordinator, description, use_detailed_attributes) - ) + entities.append(CheckwattSensor(coordinator, description)) + elif key == "monthly": + entities.append(CheckwattMonthlySensor(coordinator, description)) elif key == "annual": - entities.append( - CheckwattAnnualSensor(coordinator, description, use_detailed_attributes) - ) + entities.append(CheckwattAnnualSensor(coordinator, description)) elif key == "battery": entities.append(CheckwattBatterySoCSensor(coordinator, description)) elif key == "cm10" and use_cm10_sensor: entities.append(CheckwattCM10Sensor(coordinator, description)) - if use_detailed_sensors: + if use_power_sensors: _LOGGER.debug( "Setting up detailed CheckWatt sensors for %s", checkwatt_data["display_name"], @@ -223,6 +217,7 @@ def __init__( description: SensorEntityDescription, ) -> None: """Initialize the sensor.""" + _LOGGER.debug("Creating %s sensor", description.name) super().__init__(coordinator) self._coordinator = coordinator self._device_model = CHECKWATT_MODEL @@ -253,11 +248,9 @@ def __init__( self, coordinator: CheckwattCoordinator, description: SensorEntityDescription, - use_detailed_attributes, ) -> None: """Initialize the sensor.""" super().__init__(coordinator=coordinator, description=description) - self.use_detailed_attributes = use_detailed_attributes self._attr_unique_id = f'checkwattUid_{self._coordinator.data["id"]}' self._attr_extra_state_attributes = {} @@ -285,60 +278,18 @@ def __init__( self._attr_extra_state_attributes.update( {C_ENERGY_PROVIDER: self._coordinator.data["energy_provider"]} ) - if "revenue" in self._coordinator.data and "fees" in self._coordinator.data: - revenue = self._coordinator.data["revenue"] - fees = self._coordinator.data["fees"] - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_TODAY_GROSS] = round(revenue, 2) - self._attr_extra_state_attributes[C_TODAY_FEES] = round(fees, 2) - if revenue > 0: - self._attr_extra_state_attributes[ - C_TODAY_FEE_RATE - ] = f"{round((fees / revenue) * 100, 2)} %" - else: - self._attr_extra_state_attributes[C_TODAY_FEE_RATE] = "N/A %" - - if ( - "tomorrow_revenue" in self._coordinator.data - and "tomorrow_fees" in self._coordinator.data - ): - tomorrow_revenue = self._coordinator.data["tomorrow_revenue"] - tomorrow_fees = self._coordinator.data["tomorrow_fees"] + if "tomorrow_net_revenue" in self._coordinator.data: self._attr_extra_state_attributes[C_TOMORROW_NET] = round( - (tomorrow_revenue - tomorrow_fees), 2 - ) - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_TOMORROW_GROSS] = round( - tomorrow_revenue, 2 - ) - self._attr_extra_state_attributes[C_TOMORROW_FEES] = round( - tomorrow_fees, 2 - ) - if tomorrow_revenue > 0: - self._attr_extra_state_attributes[ - C_TOMORROW_FEE_RATE - ] = f"{round((tomorrow_fees / tomorrow_revenue) * 100, 2 )} %" - else: - self._attr_extra_state_attributes[C_TOMORROW_FEE_RATE] = "N/A %" - - if use_detailed_attributes: - # Add extra attributes as required - if "update_time" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_UPDATE_TIME: self._coordinator.data["update_time"]} - ) - if "next_update_time" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_NEXT_UPDATE_TIME: self._coordinator.data["next_update_time"]} - ) - if "battery_charge_peak" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_CHARGE_PEAK: self._coordinator.data["battery_charge_peak"]} - ) - if "battery_discharge_peak" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_DISCHARGE_PEAK: self._coordinator.data["battery_discharge_peak"]} - ) + self._coordinator.data["tomorrow_net_revenue"], 2 + ) + if "update_time" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_UPDATE_TIME: self._coordinator.data["update_time"]} + ) + if "next_update_time" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_NEXT_UPDATE_TIME: self._coordinator.data["next_update_time"]} + ) self._attr_available = False @@ -350,71 +301,60 @@ async def async_update(self) -> None: def _handle_coordinator_update(self) -> None: """Get the latest data and updates the states.""" # Update the native value - if "revenue" in self._coordinator.data and "fees" in self._coordinator.data: - revenue = self._coordinator.data["revenue"] - fees = self._coordinator.data["fees"] - self._attr_native_value = round((revenue - fees), 2) - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_TODAY_GROSS] = round(revenue, 2) - self._attr_extra_state_attributes[C_TODAY_FEES] = round(fees, 2) - if revenue > 0: - self._attr_extra_state_attributes[ - C_TODAY_FEE_RATE - ] = f"{round((fees / revenue) * 100, 2)} %" - else: - self._attr_extra_state_attributes[C_TODAY_FEE_RATE] = "N/A %" - - # Update the normal attributes - if ( - "tomorrow_revenue" in self._coordinator.data - and "tomorrow_fees" in self._coordinator.data - ): - tomorrow_revenue = self._coordinator.data["tomorrow_revenue"] - tomorrow_fees = self._coordinator.data["tomorrow_fees"] + if "tomorrow_net_revenue" in self._coordinator.data: self._attr_extra_state_attributes[C_TOMORROW_NET] = round( - (tomorrow_revenue - tomorrow_fees), 2 - ) - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_TOMORROW_GROSS] = round( - tomorrow_revenue, 2 - ) - self._attr_extra_state_attributes[C_TOMORROW_FEES] = round( - tomorrow_fees, 2 - ) - if tomorrow_revenue > 0: - self._attr_extra_state_attributes[ - C_TOMORROW_FEE_RATE - ] = f"{round((tomorrow_fees / tomorrow_revenue) * 100, 2)} %" - else: - self._attr_extra_state_attributes[C_TOMORROW_FEE_RATE] = "N/A %" - - # Update the extra attributes - if self.use_detailed_attributes: - if "update_time" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_UPDATE_TIME: self._coordinator.data["update_time"]} - ) - if "next_update_time" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_NEXT_UPDATE_TIME: self._coordinator.data["next_update_time"]} - ) - if "battery_charge_peak" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_CHARGE_PEAK: self._coordinator.data["battery_charge_peak"]} - ) - if "battery_discharge_peak" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_DISCHARGE_PEAK: self._coordinator.data["battery_discharge_peak"]} - ) + self._coordinator.data["tomorrow_net_revenue"], 2 + ) + if "update_time" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_UPDATE_TIME: self._coordinator.data["update_time"]} + ) + if "next_update_time" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_NEXT_UPDATE_TIME: self._coordinator.data["next_update_time"]} + ) + self._attr_native_value = round(self._coordinator.data["today_net_revenue"], 2) super()._handle_coordinator_update() @property def native_value(self) -> str | None: """Get the latest state value.""" - if "revenue" in self._coordinator.data and "fees" in self._coordinator.data: - return round( - self._coordinator.data["revenue"] - self._coordinator.data["fees"], 2 - ) + if "today_net_revenue" in self._coordinator.data: + return round(self._coordinator.data["today_net_revenue"], 2) + return None + + +class CheckwattMonthlySensor(AbstractCheckwattSensor): + """Representation of a CheckWatt Monthly Revenue sensor.""" + + def __init__( + self, + coordinator: CheckwattCoordinator, + description: SensorEntityDescription, + ) -> None: + """Initialize the sensor.""" + super().__init__(coordinator=coordinator, description=description) + self._attr_unique_id = f'checkwattUid_Monthly_{self._coordinator.data["id"]}' + self._attr_extra_state_attributes = {} + self._attr_available = False + + async def async_update(self) -> None: + """Get the latest data and updates the states.""" + self._attr_available = False + + @callback + def _handle_coordinator_update(self) -> None: + """Get the latest data and updates the states.""" + self._attr_native_value = round( + self._coordinator.data["monthly_net_revenue"], 2 + ) + super()._handle_coordinator_update() + + @property + def native_value(self) -> str | None: + """Get the latest state value.""" + if "monthly_net_revenue" in self._coordinator.data: + return round(self._coordinator.data["monthly_net_revenue"], 2) return None @@ -425,127 +365,28 @@ def __init__( self, coordinator: CheckwattCoordinator, description: SensorEntityDescription, - use_detailed_attributes, ) -> None: """Initialize the sensor.""" super().__init__(coordinator=coordinator, description=description) - self.use_detailed_attributes = use_detailed_attributes self._attr_unique_id = f'checkwattUid_Annual_{self._coordinator.data["id"]}' - self.total_annual_revenue = None - self.total_annual_fee = None - self._attr_extra_state_attributes = {} - if "address" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_ADR: self._coordinator.data["address"]} - ) - if "zip" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_ZIP: self._coordinator.data["zip"]} - ) - if "city" in self._coordinator.data: - self._attr_extra_state_attributes.update( - {C_CITY: self._coordinator.data["city"]} - ) - if ( - "annual_revenue" in self._coordinator.data - and "annual_fees" in self._coordinator.data - and "revenue" in self._coordinator.data - and "fees" in self._coordinator.data - and "tomorrow_revenue" in self._coordinator.data - and "tomorrow_fees" in self._coordinator.data - ): - # Annual revenue does not contain today and tomorrow revenue - # and is only fetched once daily. - # To obtain Total Annual revenue, it needs to be calculated - annual_revenue = self._coordinator.data["annual_revenue"] - annual_fees = self._coordinator.data["annual_fees"] - today_revenue = self._coordinator.data["revenue"] - today_fees = self._coordinator.data["fees"] - tomorrow_revenue = self._coordinator.data["tomorrow_revenue"] - tomorrow_fees = self._coordinator.data["tomorrow_fees"] - self.total_annual_revenue = ( - annual_revenue + today_revenue + tomorrow_revenue - ) - self.total_annual_fee = annual_fees + today_fees + tomorrow_fees - self._attr_native_value = round( - (self.total_annual_revenue - self.total_annual_fee), 2 - ) - - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_ANNUAL_GROSS] = round( - self.total_annual_revenue, 2 - ) - self._attr_extra_state_attributes[C_ANNUAL_FEES] = round( - self.total_annual_fee, 2 - ) - if self.total_annual_revenue > 0: - self._attr_extra_state_attributes[ - C_ANNUAL_FEE_RATE - ] = f"{round((self.total_annual_fee / self.total_annual_revenue) * 100, 2)} %" - else: - self._attr_extra_state_attributes[C_ANNUAL_FEE_RATE] = "N/A %" self._attr_available = False async def async_update(self) -> None: """Get the latest data and updates the states.""" - self._attr_available = True + self._attr_available = False @callback def _handle_coordinator_update(self) -> None: """Get the latest data and updates the states.""" - # Update the native value - if ( - "annual_revenue" in self._coordinator.data - and "annual_fees" in self._coordinator.data - and "revenue" in self._coordinator.data - and "fees" in self._coordinator.data - and "tomorrow_revenue" in self._coordinator.data - and "tomorrow_fees" in self._coordinator.data - ): - # Annual revenue does not contain today and tomorrow revenue - # and is only fetched once daily. - # To obtain Total Annual revenue, it needs to be calculated - annual_revenue = self._coordinator.data["annual_revenue"] - annual_fees = self._coordinator.data["annual_fees"] - today_revenue = self._coordinator.data["revenue"] - today_fees = self._coordinator.data["fees"] - tomorrow_revenue = self._coordinator.data["tomorrow_revenue"] - tomorrow_fees = self._coordinator.data["tomorrow_fees"] - - self.total_annual_revenue = ( - annual_revenue + today_revenue + tomorrow_revenue - ) - - self.total_annual_fee = annual_fees + today_fees + tomorrow_fees - - self._attr_native_value = round( - (self.total_annual_revenue - self.total_annual_fee), 2 - ) - if self.use_detailed_attributes: # Only show these at detailed attribues - self._attr_extra_state_attributes[C_ANNUAL_GROSS] = round( - self.total_annual_revenue, 2 - ) - self._attr_extra_state_attributes[C_ANNUAL_FEES] = round( - self.total_annual_fee, 2 - ) - if self.total_annual_revenue > 0: - self._attr_extra_state_attributes[ - C_ANNUAL_FEE_RATE - ] = f"{round((self.total_annual_fee / self.total_annual_revenue) * 100, 2)} %" - else: - self._attr_extra_state_attributes[C_ANNUAL_FEE_RATE] = "N/A %" - + self._attr_native_value = round(self._coordinator.data["annual_net_revenue"], 2) super()._handle_coordinator_update() @property def native_value(self) -> str | None: """Get the latest state value.""" - if self.total_annual_revenue is not None and self.total_annual_fee is not None: - return round( - self.total_annual_revenue - self.total_annual_fee, - 2, - ) + if "annual_net_revenue" in self._coordinator.data: + return round(self._coordinator.data["annual_net_revenue"], 2) return None @@ -559,7 +400,6 @@ def __init__( data_key, ) -> None: """Initialize the sensor.""" - _LOGGER.debug("Creating %s sensor", description.name) super().__init__(coordinator=coordinator, description=description) self.data_key = data_key @@ -589,7 +429,6 @@ def __init__( vat_key, ) -> None: """Initialize the sensor.""" - _LOGGER.debug("Creating %s sensor", description.name) super().__init__(coordinator=coordinator, description=description) self.vat_key = vat_key @@ -631,7 +470,6 @@ def __init__( description: SensorEntityDescription, ) -> None: """Initialize the sensor.""" - _LOGGER.debug("Creating %s sensor", description.name) super().__init__(coordinator=coordinator, description=description) async def async_update(self) -> None: @@ -716,7 +554,6 @@ def __init__( description: SensorEntityDescription, ) -> None: """Initialize the sensor.""" - _LOGGER.debug("Creating %s sensor", description.name) super().__init__(coordinator=coordinator, description=description) async def async_update(self) -> None: diff --git a/custom_components/checkwatt/strings.json b/custom_components/checkwatt/strings.json index 62b00fc..4a61d61 100644 --- a/custom_components/checkwatt/strings.json +++ b/custom_components/checkwatt/strings.json @@ -24,7 +24,6 @@ "init": { "data": { "show_details": "Provide energy sensors", - "show_detailed_attributes": "Offer detailed attributes", "push_to_cw_rank": "Push data to CheckWattRank", "cm10_sensor": "Provide CM10 sensor" }, @@ -56,63 +55,24 @@ "energy_provider": { "name": "Energy Provider" }, - "today_gross_income": { - "name": "Today Gross Income" - }, - "today_fees": { - "name": "Today Fees" - }, - "today_fees_rate": { - "name": "Today Fee Rate" - }, "tomorrow_net_income": { "name": "Tomorrow Net Income" }, - "tomorrow_gross_income": { - "name": "Tomorrow Gross Income" - }, - "tomorrow_fees": { - "name": "Tomorrow Fees" - }, - "tomorrow_fee_rate": { - "name": "Tomorrow Fee Rate" - }, "last_update": { "name": "Last update" }, "next_update": { "name": "Next update" - }, - "charge_peak": { - "name": "Charge Peak" - }, - "discharge_peak": { - "name": "Discharge Peak" } } }, + "monthly_yield_sensor": { + "name": "CheckWatt Monthly Net Income", + "state_attributes": {} + }, "annual_yield_sensor": { "name": "CheckWatt Annual Net Income", - "state_attributes": { - "street_address": { - "name": "Street Address" - }, - "zip_code": { - "name": "Zip Code" - }, - "city": { - "name": "City" - }, - "annual_gross_income": { - "name": "Annual Gross Income" - }, - "annual_fees": { - "name": "Annual Fees" - }, - "annual_fee_rate": { - "name": "Annual Fee Rate" - } - } + "state_attributes": {} }, "solar_sensor": { "name": "Solar Energy" diff --git a/custom_components/checkwatt/translations/en.json b/custom_components/checkwatt/translations/en.json index b2702d1..9b97f2d 100644 --- a/custom_components/checkwatt/translations/en.json +++ b/custom_components/checkwatt/translations/en.json @@ -24,7 +24,6 @@ "init": { "data": { "show_details": "Provide energy sensors", - "show_detailed_attributes": "Offer detailed attributes", "push_to_cw_rank": "Push data to CheckWattRank", "cm10_sensor": "Provide CM10 sensor" }, @@ -56,63 +55,24 @@ "energy_provider": { "name": "Energy Provider" }, - "today_gross_income": { - "name": "Today Gross Income" - }, - "today_fees": { - "name": "Today Fees" - }, - "today_fees_rate": { - "name": "Today Fee Rate" - }, "tomorrow_net_income": { "name": "Tomorrow Net Income" }, - "tomorrow_gross_income": { - "name": "Tomorrow Gross Income" - }, - "tomorrow_fees": { - "name": "Tomorrow Fees" - }, - "tomorrow_fee_rate": { - "name": "Tomorrow Fee Rate" - }, "last_update": { "name": "Last update" }, "next_update": { "name": "Next update" - }, - "charge_peak": { - "name": "Charge Peak" - }, - "discharge_peak": { - "name": "Discharge Peak" } } }, + "monthly_yield_sensor": { + "name": "CheckWatt Monthly Net Income", + "state_attributes": {} + }, "annual_yield_sensor": { "name": "CheckWatt Annual Net Income", - "state_attributes": { - "street_address": { - "name": "Street Address" - }, - "zip_code": { - "name": "Zip Code" - }, - "city": { - "name": "City" - }, - "annual_gross_income": { - "name": "Annual Gross Income" - }, - "annual_fees": { - "name": "Annual Fees" - }, - "annual_fee_rate": { - "name": "Annual Fee Rate" - } - } + "state_attributes": {} }, "solar_sensor": { "name": "Solar Energy" diff --git a/custom_components/checkwatt/translations/sv.json b/custom_components/checkwatt/translations/sv.json index cc62cb9..798b4f0 100644 --- a/custom_components/checkwatt/translations/sv.json +++ b/custom_components/checkwatt/translations/sv.json @@ -24,7 +24,6 @@ "init": { "data": { "show_details": "Skapa energisensorer", - "show_detailed_attributes": "Visa detaljerade attribut", "push_to_cw_rank": "Skicka data till CheckWattRank", "cm10_sensor": "Skapa CM10 sensor" }, @@ -56,63 +55,24 @@ "energy_provider": { "name": "Elhandelsbolag" }, - "today_gross_income": { - "name": "Dagens Bruttoinkomst" - }, - "today_fees": { - "name": "Dagens Avgifter" - }, - "today_fees_rate": { - "name": "Dagens Avgiftssats" - }, "tomorrow_net_income": { "name": "Morgondagens Nettointäkt" }, - "tomorrow_gross_income": { - "name": "Morgondagens Bruttoinkomst" - }, - "tomorrow_fees": { - "name": "Morgondagens Avgifter" - }, - "tomorrow_fee_rate": { - "name": "Morgondagens Avgiftssats" - }, "last_update": { "name": "Senaste uppdateringen" }, "next_update": { "name": "Nästa uppdatering" - }, - "charge_peak": { - "name": "Laddningstopp" - }, - "discharge_peak": { - "name": "Urladdningstopp" } } }, + "monthly_yield_sensor": { + "name": "CheckWatt Månadens Intäkt", + "state_attributes": {} + }, "annual_yield_sensor": { "name": "CheckWatt Årets Intäkt", - "state_attributes": { - "street_address": { - "name": "Adress" - }, - "zip_code": { - "name": "Postnummer" - }, - "city": { - "name": "Stad" - }, - "annual_gross_income": { - "name": "Årets Bruttoinkomst" - }, - "annual_fees": { - "name": "Årets Avgifter" - }, - "annual_fee_rate": { - "name": "Årets Avgiftssats" - } - } + "state_attributes": {} }, "solar_sensor": { "name": "Solenergi" @@ -172,7 +132,6 @@ "discharge_peak_dc": { "name": "Urladdningstopp DC" } - } }, "cm10_sensor": { From e9a1694626c0477b07a63ccd20987c8abaf3ec66 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 09:49:22 +0000 Subject: [PATCH 2/9] Update as per prel version of pyCheckwatt --- custom_components/checkwatt/__init__.py | 125 +++++++-------------- custom_components/checkwatt/config_flow.py | 2 +- custom_components/checkwatt/const.py | 3 +- 3 files changed, 40 insertions(+), 90 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index b9eb1b9..823a63d 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -4,7 +4,6 @@ import asyncio from datetime import time, timedelta import logging -import re from typing import TypedDict import aiohttp @@ -24,7 +23,6 @@ CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, CONF_UPDATE_INTERVAL, - CONF_UPDATE_INTERVAL_FCRD, DOMAIN, EVENT_SIGNAL_FCRD, INTEGRATION_NAME, @@ -134,37 +132,6 @@ async def getPeakData(cw_inst): return (charge_peak_ac, charge_peak_dc, discharge_peak_ac, discharge_peak_dc) -def extract_fcrd_status(cw_inst): - """Extract status from data and logbook.""" - - if cw_inst.customer_details is None: - return (None, None, None) - - pattern = re.compile( - r"\[ FCR-D (ACTIVATED|DEACTIVATE|FAIL ACTIVATION) \](?:.*?(\d+,\d+/\d+,\d+/\d+,\d+ %))?(?:\s*(.*?))?(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})" - ) - for entry in cw_inst.logbook_entries: - match = pattern.search(entry) - if match: - fcrd_state = match.group(1) - fcrd_percentage = ( - match.group(2) - if fcrd_state in ["ACTIVATED", "FAIL ACTIVATION"] - else None - ) - error_info = match.group(3) if fcrd_state == "DEACTIVATE" else None - fcrd_timestamp = match.group(4) - if fcrd_percentage is not None: - fcrd_info = fcrd_percentage - elif error_info is not None: - fcrd_info = error_info - else: - fcrd_info = None - break - - return (fcrd_state, fcrd_info, fcrd_timestamp) - - class CheckwattCoordinator(DataUpdateCoordinator[CheckwattResp]): """Data update coordinator.""" @@ -177,12 +144,6 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: update_interval=timedelta(minutes=CONF_UPDATE_INTERVAL), ) self._entry = entry - self.update_time = None - self.next_update_time = None - self.today_net_revenue = None - self.tomorrow_net_revenue = None - self.monthly_net_revenue = None - self.annual_net_revenue = None self.last_cw_rank_push = None self.is_boot = True self.energy_provider = None @@ -202,7 +163,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 try: username = self._entry.data.get(CONF_USERNAME) password = self._entry.data.get(CONF_PASSWORD) - use_detailed_sensors = self._entry.options.get(CONF_POWER_SENSORS) + use_power_sensors = self._entry.options.get(CONF_POWER_SENSORS) push_to_cw_rank = self._entry.options.get(CONF_PUSH_CW_TO_RANK) use_cm10_sensor = self._entry.options.get(CONF_CM10_SENSOR) @@ -212,25 +173,20 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 if not await cw_inst.login(): _LOGGER.error("Failed to login, abort update") raise UpdateFailed("Failed to login") + if not await cw_inst.get_customer_details(): _LOGGER.error("Failed to obtain customer details, abort update") raise UpdateFailed("Unknown error get_customer_details") + if use_cm10_sensor: if not await cw_inst.get_meter_status(): _LOGGER.error("Failed to obtain meter details, abort update") raise UpdateFailed("Unknown error get_meter_status") + if not await cw_inst.get_energy_flow(): _LOGGER.error("Failed to get energy flows, abort update") raise UpdateFailed("Unknown error get_energy_flow") - ( - fcrd_state, - fcrd_info, - fcrd_timestamp, - ) = extract_fcrd_status(cw_inst) - - # Prevent slow funcion to be called at boot. - # The revenue sensors will be updated after ca 1 min if self.is_boot: self.is_boot = False if ( @@ -243,35 +199,26 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 ) # Store fcrd_state at boot, used to spark event - self.fcrd_state = fcrd_state + self.fcrd_state = cw_inst.fcrd_state self._id = cw_inst.customer_details["Id"] - self.update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") - end_date = dt_util.now() + timedelta(minutes=CONF_UPDATE_INTERVAL_FCRD) - self.next_update_time = end_date.strftime("%Y-%m-%d %H:%M:%S") - _LOGGER.debug("Fetching daily revenue") - if not await cw_inst.get_net_revenue_today(): + if not await cw_inst.get_fcrd_today_net_revenue(): raise UpdateFailed("Unknown error get_fcrd_revenue") - _LOGGER.debug("Fetching annual revenue") - if not await cw_inst.get_revenue_year(): - raise UpdateFailed("Unknown error get_revenue_year") - _LOGGER.debug("Fetching monthly revenue") - if not await cw_inst.get_revenue_month(): + if not await cw_inst.get_fcrd_month_net_revenue(): raise UpdateFailed("Unknown error get_revenue_month") - self.today_net_revenue = cw_inst.today_net_revenue - self.tomorrow_net_revenue = cw_inst.tomorrow_net_revenue - self.monthly_net_revenue = cw_inst.monthly_net_revenue - self.annual_net_revenue = cw_inst.annual_net_revenue + _LOGGER.debug("Fetching annual revenue") + if not await cw_inst.get_fcrd_year_net_revenue(): + raise UpdateFailed("Unknown error get_revenue_year") # Price Zone is used both as Detailed Sensor and by Push to CheckWattRank - if push_to_cw_rank or use_detailed_sensors: + if push_to_cw_rank or use_power_sensors: if not await cw_inst.get_price_zone(): raise UpdateFailed("Unknown error get_price_zone") - if use_detailed_sensors: + if use_power_sensors: if not await cw_inst.get_power_data(): raise UpdateFailed("Unknown error get_power_data") if not await cw_inst.get_spot_price(): @@ -316,25 +263,29 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["discharge_peak_dc"] = discharge_peak_dc # Use self stored variant of revenue parameters as they are not always fetched - if self.today_net_revenue is not None: - resp["today_net_revenue"] = self.today_net_revenue - resp["tomorrow_net_revenue"] = self.tomorrow_net_revenue - if self.monthly_net_revenue is not None: - resp["monthly_net_revenue"] = self.monthly_net_revenue - if self.annual_net_revenue is not None: - resp["annual_net_revenue"] = self.annual_net_revenue - - resp["update_time"] = self.update_time - resp["next_update_time"] = self.next_update_time - - if use_detailed_sensors: + if cw_inst.fcrd_today_net_revenue is not None: + resp["today_net_revenue"] = cw_inst.fcrd_today_net_revenue + resp["tomorrow_net_revenue"] = cw_inst.fcrd_tomorrow_net_revenue + if cw_inst.fcrd_month_net_revenue is not None: + resp["monthly_net_revenue"] = cw_inst.fcrd_month_net_revenue + if cw_inst.fcrd_year_net_revenue is not None: + resp["annual_net_revenue"] = cw_inst.fcrd_year_net_revenue + + update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") + next_update = dt_util.now() + timedelta(minutes=CONF_UPDATE_INTERVAL) + next_update_time = next_update.strftime("%Y-%m-%d %H:%M:%S") + resp["update_time"] = update_time + resp["next_update_time"] = next_update_time + + if use_power_sensors: resp["total_solar_energy"] = cw_inst.total_solar_energy resp["total_charging_energy"] = cw_inst.total_charging_energy resp["total_discharging_energy"] = cw_inst.total_discharging_energy resp["total_import_energy"] = cw_inst.total_import_energy resp["total_export_energy"] = cw_inst.total_export_energy - time_hour = int(dt_util.now().strftime("%H")) - resp["spot_price"] = cw_inst.get_spot_price_excl_vat(time_hour) + resp["spot_price"] = cw_inst.get_spot_price_excl_vat( + int(dt_util.now().strftime("%H")) + ) resp["price_zone"] = cw_inst.price_zone if cw_inst.meter_data is not None and use_cm10_sensor: @@ -346,13 +297,13 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["cm10_status"] = "Active" resp["cm10_version"] = cw_inst.meter_version - resp["fcr_d_status"] = fcrd_state - resp["fcr_d_info"] = fcrd_info - resp["fcr_d_date"] = fcrd_timestamp + resp["fcr_d_status"] = cw_inst.fcrd_state + resp["fcr_d_info"] = cw_inst.fcrd_info + resp["fcr_d_date"] = cw_inst.fcrd_timestamp # Check if FCR-D State has changed and dispatch it ACTIVATED/ DEACTIVATED old_state = self.fcrd_state - new_state = fcrd_state + new_state = cw_inst.fcrd_state # During test, toggle (every minute) if BASIC_TEST is True: @@ -374,8 +325,8 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 }, "new_fcrd": { "state": new_state, - "info": fcrd_info, - "date": fcrd_timestamp, + "info": cw_inst.fcrd_info, + "date": cw_inst.fcrd_timestamp, }, }, } @@ -389,8 +340,8 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 # Update self to discover next change self.fcrd_state = new_state - self.fcrd_info = fcrd_info - self.fcrd_timestamp = fcrd_timestamp + self.fcrd_info = cw_inst.fcrd_info + self.fcrd_timestamp = cw_inst.fcrd_timestamp return resp diff --git a/custom_components/checkwatt/config_flow.py b/custom_components/checkwatt/config_flow.py index 157fd38..0e39978 100644 --- a/custom_components/checkwatt/config_flow.py +++ b/custom_components/checkwatt/config_flow.py @@ -72,7 +72,7 @@ async def async_step_user( options={ CONF_POWER_SENSORS: False, CONF_PUSH_CW_TO_RANK: False, - CONF_CM10_SENSOR: False, + CONF_CM10_SENSOR: True, }, ) diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index ab25aba..0a71b60 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -6,8 +6,7 @@ # Update interval for regular sensors is once every minute # For FCR-D since it is slow and resource consuming, is set to once per 15 minute -CONF_UPDATE_INTERVAL = 1 -CONF_UPDATE_INTERVAL_FCRD = 60 +CONF_UPDATE_INTERVAL = 15 ATTRIBUTION = "Data provided by CheckWatt EnergyInBalance" MANUFACTURER = "CheckWatt" CHECKWATT_MODEL = "CheckWatt" From 4b90bf517df223501825ffc4522a1509af676e57 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 10:42:39 +0000 Subject: [PATCH 3/9] Added properties for monthly sensor --- custom_components/checkwatt/__init__.py | 4 ++ custom_components/checkwatt/const.py | 2 + custom_components/checkwatt/sensor.py | 37 ++++++++++++++++--- custom_components/checkwatt/strings.json | 9 ++++- .../checkwatt/translations/en.json | 9 ++++- .../checkwatt/translations/sv.json | 9 ++++- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index 823a63d..b3e2f63 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -59,6 +59,8 @@ class CheckwattResp(TypedDict): tomorrow_net_revenue: float monthly_net_revenue: float annual_net_revenue: float + month_estimate: float + daily_average: float update_time: str next_update_time: str @@ -268,6 +270,8 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["tomorrow_net_revenue"] = cw_inst.fcrd_tomorrow_net_revenue if cw_inst.fcrd_month_net_revenue is not None: resp["monthly_net_revenue"] = cw_inst.fcrd_month_net_revenue + resp["month_estimate"] = cw_inst.fcrd_month_net_estimate + resp["daily_average"] = cw_inst.fcrd_daily_net_average if cw_inst.fcrd_year_net_revenue is not None: resp["annual_net_revenue"] = cw_inst.fcrd_year_net_revenue diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index 0a71b60..1eac8f3 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -28,6 +28,7 @@ C_BATTERY_POWER = "battery_power" C_CITY = "city" C_CM10_VERSION = "cm10_version" +C_DAILY_AVERAGE = "daily_average" C_DISPLAY_NAME = "display_name" C_DSO = "dso" C_GRID_POWER = "grid_power" @@ -35,6 +36,7 @@ C_FCRD_DATE = "fcr_d_date" C_FCRD_INFO = "fcr_d_info" C_FCRD_STATUS = "fcr_d_status" +C_MONTH_ESITIMATE = "month_estimate" C_NEXT_UPDATE_TIME = "next_update" C_PRICE_ZONE = "price_zone" C_SOLAR_POWER = "solar_power" diff --git a/custom_components/checkwatt/sensor.py b/custom_components/checkwatt/sensor.py index 2a7a141..f1cc459 100644 --- a/custom_components/checkwatt/sensor.py +++ b/custom_components/checkwatt/sensor.py @@ -26,6 +26,7 @@ C_CHARGE_PEAK_DC, C_CITY, C_CM10_VERSION, + C_DAILY_AVERAGE, C_DISCHARGE_PEAK_AC, C_DISCHARGE_PEAK_DC, C_DISPLAY_NAME, @@ -35,6 +36,7 @@ C_FCRD_INFO, C_FCRD_STATUS, C_GRID_POWER, + C_MONTH_ESITIMATE, C_NEXT_UPDATE_TIME, C_PRICE_ZONE, C_SOLAR_POWER, @@ -279,8 +281,12 @@ def __init__( {C_ENERGY_PROVIDER: self._coordinator.data["energy_provider"]} ) if "tomorrow_net_revenue" in self._coordinator.data: - self._attr_extra_state_attributes[C_TOMORROW_NET] = round( - self._coordinator.data["tomorrow_net_revenue"], 2 + self._attr_extra_state_attributes.update( + { + C_TOMORROW_NET: round( + self._coordinator.data["tomorrow_net_revenue"], 2 + ) + } ) if "update_time" in self._coordinator.data: self._attr_extra_state_attributes.update( @@ -302,8 +308,12 @@ def _handle_coordinator_update(self) -> None: """Get the latest data and updates the states.""" # Update the native value if "tomorrow_net_revenue" in self._coordinator.data: - self._attr_extra_state_attributes[C_TOMORROW_NET] = round( - self._coordinator.data["tomorrow_net_revenue"], 2 + self._attr_extra_state_attributes.update( + { + C_TOMORROW_NET: round( + self._coordinator.data["tomorrow_net_revenue"], 2 + ) + } ) if "update_time" in self._coordinator.data: self._attr_extra_state_attributes.update( @@ -313,7 +323,6 @@ def _handle_coordinator_update(self) -> None: self._attr_extra_state_attributes.update( {C_NEXT_UPDATE_TIME: self._coordinator.data["next_update_time"]} ) - self._attr_native_value = round(self._coordinator.data["today_net_revenue"], 2) super()._handle_coordinator_update() @property @@ -340,7 +349,15 @@ def __init__( async def async_update(self) -> None: """Get the latest data and updates the states.""" - self._attr_available = False + if "month_estimate" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_MONTH_ESITIMATE: round(self._coordinator.data["month_estimate"], 2)} + ) + if "daily_average" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_DAILY_AVERAGE: round(self._coordinator.data["daily_average"], 2)} + ) + self._attr_available = True @callback def _handle_coordinator_update(self) -> None: @@ -348,6 +365,14 @@ def _handle_coordinator_update(self) -> None: self._attr_native_value = round( self._coordinator.data["monthly_net_revenue"], 2 ) + if "month_estimate" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_MONTH_ESITIMATE: round(self._coordinator.data["month_estimate"], 2)} + ) + if "daily_average" in self._coordinator.data: + self._attr_extra_state_attributes.update( + {C_DAILY_AVERAGE: round(self._coordinator.data["daily_average"], 2)} + ) super()._handle_coordinator_update() @property diff --git a/custom_components/checkwatt/strings.json b/custom_components/checkwatt/strings.json index 4a61d61..55d949e 100644 --- a/custom_components/checkwatt/strings.json +++ b/custom_components/checkwatt/strings.json @@ -68,7 +68,14 @@ }, "monthly_yield_sensor": { "name": "CheckWatt Monthly Net Income", - "state_attributes": {} + "state_attributes": { + "month_estimate": { + "name": "Month Estimate" + }, + "daily_average": { + "name": "Daily Average" + } + } }, "annual_yield_sensor": { "name": "CheckWatt Annual Net Income", diff --git a/custom_components/checkwatt/translations/en.json b/custom_components/checkwatt/translations/en.json index 9b97f2d..9615107 100644 --- a/custom_components/checkwatt/translations/en.json +++ b/custom_components/checkwatt/translations/en.json @@ -68,7 +68,14 @@ }, "monthly_yield_sensor": { "name": "CheckWatt Monthly Net Income", - "state_attributes": {} + "state_attributes": { + "month_estimate": { + "name": "Month Estimate" + }, + "daily_average": { + "name": "Daily Average" + } + } }, "annual_yield_sensor": { "name": "CheckWatt Annual Net Income", diff --git a/custom_components/checkwatt/translations/sv.json b/custom_components/checkwatt/translations/sv.json index 798b4f0..bfdedbc 100644 --- a/custom_components/checkwatt/translations/sv.json +++ b/custom_components/checkwatt/translations/sv.json @@ -68,7 +68,14 @@ }, "monthly_yield_sensor": { "name": "CheckWatt Månadens Intäkt", - "state_attributes": {} + "state_attributes": { + "month_estimate": { + "name": "Månadsestimat" + }, + "daily_average": { + "name": "Daglig medelintäkt" + } + } }, "annual_yield_sensor": { "name": "CheckWatt Årets Intäkt", From c41ce3ec6ea6426dfa47d067a8d89a4b9f72d037 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 16:06:45 +0000 Subject: [PATCH 4/9] Bumped varsion --- custom_components/checkwatt/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/checkwatt/manifest.json b/custom_components/checkwatt/manifest.json index 2d1399c..e57d01c 100644 --- a/custom_components/checkwatt/manifest.json +++ b/custom_components/checkwatt/manifest.json @@ -12,8 +12,8 @@ "homekit": {}, "iot_class": "cloud_polling", "issue_tracker": "https://github.com/faanskit/ha-checkwatt/issues", - "requirements": ["pycheckwatt>=0.1.11", "aiohttp>=3.9.1"], + "requirements": ["pycheckwatt>=0.2.0", "aiohttp>=3.9.1"], "ssdp": [], - "version": "0.1.8", + "version": "0.2.0", "zeroconf": [] } From c746f824a97df570605e9dc125368d6714ca0c83 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 16:12:38 +0000 Subject: [PATCH 5/9] Black fixes --- custom_components/checkwatt/__init__.py | 1 + custom_components/checkwatt/config_flow.py | 1 + custom_components/checkwatt/const.py | 1 + custom_components/checkwatt/event.py | 3 ++- custom_components/checkwatt/sensor.py | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index b3e2f63..7efae2a 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -1,4 +1,5 @@ """The CheckWatt integration.""" + from __future__ import annotations import asyncio diff --git a/custom_components/checkwatt/config_flow.py b/custom_components/checkwatt/config_flow.py index 0e39978..93fc3e6 100644 --- a/custom_components/checkwatt/config_flow.py +++ b/custom_components/checkwatt/config_flow.py @@ -1,4 +1,5 @@ """Config flow for CheckWatt integration.""" + from __future__ import annotations import logging diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index 1eac8f3..4c680f9 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -1,4 +1,5 @@ """Constants for the CheckWatt integration.""" + from typing import Final DOMAIN = "checkwatt" diff --git a/custom_components/checkwatt/event.py b/custom_components/checkwatt/event.py index 3674f64..2654d05 100644 --- a/custom_components/checkwatt/event.py +++ b/custom_components/checkwatt/event.py @@ -1,4 +1,5 @@ -"""Events for Withings.""" +"""Events for CheckWatt.""" + from __future__ import annotations import logging diff --git a/custom_components/checkwatt/sensor.py b/custom_components/checkwatt/sensor.py index f1cc459..011afa8 100644 --- a/custom_components/checkwatt/sensor.py +++ b/custom_components/checkwatt/sensor.py @@ -1,4 +1,5 @@ """Support for CheckWatt sensors.""" + from __future__ import annotations from datetime import timedelta From a90b9e5a67d5f6caf52c35b2ab39d2d186c17baf Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 17:07:58 +0000 Subject: [PATCH 6/9] Update revenue every 15 min --- custom_components/checkwatt/__init__.py | 77 ++++++++++++++++--------- custom_components/checkwatt/const.py | 4 +- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index 7efae2a..5d123db 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -23,7 +23,8 @@ CONF_CM10_SENSOR, CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, - CONF_UPDATE_INTERVAL, + CONF_UPDATE_INTERVAL_ALL, + CONF_UPDATE_INTERVAL_NON_POWER, DOMAIN, EVENT_SIGNAL_FCRD, INTEGRATION_NAME, @@ -144,7 +145,7 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: hass, _LOGGER, name=DOMAIN, - update_interval=timedelta(minutes=CONF_UPDATE_INTERVAL), + update_interval=timedelta(minutes=CONF_UPDATE_INTERVAL_ALL), ) self._entry = entry self.last_cw_rank_push = None @@ -154,6 +155,13 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: self.fcrd_info = None self.fcrd_timestamp = None self._id = None + self.update_all = 0 + self.fcrd_today_net_revenue = None + self.fcrd_tomorrow_net_revenue = None + self.fcrd_month_net_revenue = None + self.fcrd_month_net_estimate = None + self.fcrd_daily_net_average = None + self.fcrd_year_net_revenue = None @property def entry_id(self) -> str: @@ -181,14 +189,39 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 _LOGGER.error("Failed to obtain customer details, abort update") raise UpdateFailed("Unknown error get_customer_details") + if not await cw_inst.get_energy_flow(): + _LOGGER.error("Failed to get energy flows, abort update") + raise UpdateFailed("Unknown error get_energy_flow") + if use_cm10_sensor: if not await cw_inst.get_meter_status(): _LOGGER.error("Failed to obtain meter details, abort update") raise UpdateFailed("Unknown error get_meter_status") - if not await cw_inst.get_energy_flow(): - _LOGGER.error("Failed to get energy flows, abort update") - raise UpdateFailed("Unknown error get_energy_flow") + # Only fetch some parameters every 15 min + if self.update_all == 0 and not self.is_boot: + self.update_all = CONF_UPDATE_INTERVAL_NON_POWER + _LOGGER.debug("Fetching daily revenue") + if not await cw_inst.get_fcrd_today_net_revenue(): + raise UpdateFailed("Unknown error get_fcrd_revenue") + + _LOGGER.debug("Fetching monthly revenue") + if not await cw_inst.get_fcrd_month_net_revenue(): + raise UpdateFailed("Unknown error get_revenue_month") + + _LOGGER.debug("Fetching annual revenue") + if not await cw_inst.get_fcrd_year_net_revenue(): + raise UpdateFailed("Unknown error get_revenue_year") + + self.fcrd_today_net_revenue = cw_inst.fcrd_today_net_revenue + self.fcrd_tomorrow_net_revenue = cw_inst.fcrd_tomorrow_net_revenue + self.fcrd_month_net_revenue = cw_inst.fcrd_month_net_revenue + self.fcrd_month_net_estimate = cw_inst.fcrd_month_net_estimate + self.fcrd_daily_net_average = cw_inst.fcrd_daily_net_average + self.fcrd_year_net_revenue = cw_inst.fcrd_year_net_revenue + + if not self.is_boot: + self.update_all -= 1 if self.is_boot: self.is_boot = False @@ -205,18 +238,6 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 self.fcrd_state = cw_inst.fcrd_state self._id = cw_inst.customer_details["Id"] - _LOGGER.debug("Fetching daily revenue") - if not await cw_inst.get_fcrd_today_net_revenue(): - raise UpdateFailed("Unknown error get_fcrd_revenue") - - _LOGGER.debug("Fetching monthly revenue") - if not await cw_inst.get_fcrd_month_net_revenue(): - raise UpdateFailed("Unknown error get_revenue_month") - - _LOGGER.debug("Fetching annual revenue") - if not await cw_inst.get_fcrd_year_net_revenue(): - raise UpdateFailed("Unknown error get_revenue_year") - # Price Zone is used both as Detailed Sensor and by Push to CheckWattRank if push_to_cw_rank or use_power_sensors: if not await cw_inst.get_price_zone(): @@ -266,18 +287,20 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 resp["discharge_peak_dc"] = discharge_peak_dc # Use self stored variant of revenue parameters as they are not always fetched - if cw_inst.fcrd_today_net_revenue is not None: - resp["today_net_revenue"] = cw_inst.fcrd_today_net_revenue - resp["tomorrow_net_revenue"] = cw_inst.fcrd_tomorrow_net_revenue - if cw_inst.fcrd_month_net_revenue is not None: - resp["monthly_net_revenue"] = cw_inst.fcrd_month_net_revenue - resp["month_estimate"] = cw_inst.fcrd_month_net_estimate - resp["daily_average"] = cw_inst.fcrd_daily_net_average - if cw_inst.fcrd_year_net_revenue is not None: - resp["annual_net_revenue"] = cw_inst.fcrd_year_net_revenue + if self.fcrd_today_net_revenue is not None: + resp["today_net_revenue"] = self.fcrd_today_net_revenue + resp["tomorrow_net_revenue"] = self.fcrd_tomorrow_net_revenue + if self.fcrd_month_net_revenue is not None: + resp["monthly_net_revenue"] = self.fcrd_month_net_revenue + resp["month_estimate"] = self.fcrd_month_net_estimate + resp["daily_average"] = self.fcrd_daily_net_average + if self.fcrd_year_net_revenue is not None: + resp["annual_net_revenue"] = self.fcrd_year_net_revenue update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") - next_update = dt_util.now() + timedelta(minutes=CONF_UPDATE_INTERVAL) + next_update = dt_util.now() + timedelta( + minutes=CONF_UPDATE_INTERVAL_NON_POWER + ) next_update_time = next_update.strftime("%Y-%m-%d %H:%M:%S") resp["update_time"] = update_time resp["next_update_time"] = next_update_time diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index 4c680f9..aa32d46 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -6,8 +6,8 @@ INTEGRATION_NAME = "ha-checkwatt" # Update interval for regular sensors is once every minute -# For FCR-D since it is slow and resource consuming, is set to once per 15 minute -CONF_UPDATE_INTERVAL = 15 +CONF_UPDATE_INTERVAL_ALL = 1 +CONF_UPDATE_INTERVAL_NON_POWER = 15 ATTRIBUTION = "Data provided by CheckWatt EnergyInBalance" MANUFACTURER = "CheckWatt" CHECKWATT_MODEL = "CheckWatt" From 19094c8e7e4c98b552c48ba597fe98157908c458 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 17:10:01 +0000 Subject: [PATCH 7/9] Rename constant --- custom_components/checkwatt/__init__.py | 6 +++--- custom_components/checkwatt/const.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index 5d123db..476289b 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -24,7 +24,7 @@ CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, CONF_UPDATE_INTERVAL_ALL, - CONF_UPDATE_INTERVAL_NON_POWER, + CONF_UPDATE_INTERVAL_MONETARY, DOMAIN, EVENT_SIGNAL_FCRD, INTEGRATION_NAME, @@ -200,7 +200,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 # Only fetch some parameters every 15 min if self.update_all == 0 and not self.is_boot: - self.update_all = CONF_UPDATE_INTERVAL_NON_POWER + self.update_all = CONF_UPDATE_INTERVAL_MONETARY _LOGGER.debug("Fetching daily revenue") if not await cw_inst.get_fcrd_today_net_revenue(): raise UpdateFailed("Unknown error get_fcrd_revenue") @@ -299,7 +299,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 update_time = dt_util.now().strftime("%Y-%m-%d %H:%M:%S") next_update = dt_util.now() + timedelta( - minutes=CONF_UPDATE_INTERVAL_NON_POWER + minutes=CONF_UPDATE_INTERVAL_MONETARY ) next_update_time = next_update.strftime("%Y-%m-%d %H:%M:%S") resp["update_time"] = update_time diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index aa32d46..ede5e08 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -7,7 +7,7 @@ # Update interval for regular sensors is once every minute CONF_UPDATE_INTERVAL_ALL = 1 -CONF_UPDATE_INTERVAL_NON_POWER = 15 +CONF_UPDATE_INTERVAL_MONETARY = 15 ATTRIBUTION = "Data provided by CheckWatt EnergyInBalance" MANUFACTURER = "CheckWatt" CHECKWATT_MODEL = "CheckWatt" From f20d0e52a574f38fb63c4b4a52cc115110f12d59 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 17:32:35 +0000 Subject: [PATCH 8/9] Option for CRW name added --- custom_components/checkwatt/__init__.py | 9 +++++++-- custom_components/checkwatt/config_flow.py | 13 ++++++++++++- custom_components/checkwatt/const.py | 1 + custom_components/checkwatt/strings.json | 3 ++- custom_components/checkwatt/translations/en.json | 3 ++- custom_components/checkwatt/translations/sv.json | 3 ++- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index 476289b..70e6303 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -21,6 +21,7 @@ from .const import ( BASIC_TEST, CONF_CM10_SENSOR, + CONF_CWR_NAME, CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, CONF_UPDATE_INTERVAL_ALL, @@ -177,6 +178,8 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 use_power_sensors = self._entry.options.get(CONF_POWER_SENSORS) push_to_cw_rank = self._entry.options.get(CONF_PUSH_CW_TO_RANK) use_cm10_sensor = self._entry.options.get(CONF_CM10_SENSOR) + cwr_name = self._entry.options.get(CONF_CWR_NAME) + _LOGGER.debug("Configured name for CheckWattRank: %s", cwr_name) async with CheckwattManager( username, password, INTEGRATION_NAME @@ -256,7 +259,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 != dt_util.start_of_local_day(self.last_cw_rank_push) ): _LOGGER.debug("Pushing to CheckWattRank") - if await self.push_to_checkwatt_rank(cw_inst): + if await self.push_to_checkwatt_rank(cw_inst, cwr_name): self.last_cw_rank_push = dt_util.now() resp: CheckwattResp = { @@ -378,7 +381,7 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 except CheckwattError as err: raise UpdateFailed(str(err)) from err - async def push_to_checkwatt_rank(self, cw_inst): + async def push_to_checkwatt_rank(self, cw_inst, cwr_name): """Push data to CheckWattRank.""" if self.today_net_revenue is not None: if ( @@ -401,6 +404,8 @@ async def push_to_checkwatt_rank(self, cw_inst): } if BASIC_TEST: payload["display_name"] = "xxTESTxx" + elif cwr_name != "": + payload["display_name"] = cwr_name else: payload["display_name"] = cw_inst.customer_details["Meter"][0][ "DisplayName" diff --git a/custom_components/checkwatt/config_flow.py b/custom_components/checkwatt/config_flow.py index 93fc3e6..5141711 100644 --- a/custom_components/checkwatt/config_flow.py +++ b/custom_components/checkwatt/config_flow.py @@ -14,7 +14,13 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError -from .const import CONF_CM10_SENSOR, CONF_POWER_SENSORS, CONF_PUSH_CW_TO_RANK, DOMAIN +from .const import ( + CONF_CM10_SENSOR, + CONF_CWR_NAME, + CONF_POWER_SENSORS, + CONF_PUSH_CW_TO_RANK, + DOMAIN, +) CONF_TITLE = "CheckWatt" @@ -74,6 +80,7 @@ async def async_step_user( CONF_POWER_SENSORS: False, CONF_PUSH_CW_TO_RANK: False, CONF_CM10_SENSOR: True, + CONF_CWR_NAME: "", }, ) @@ -120,6 +127,10 @@ async def async_step_init( CONF_CM10_SENSOR, default=self.config_entry.options.get(CONF_CM10_SENSOR), ): bool, + vol.Optional( + CONF_CWR_NAME, + default=self.config_entry.options.get(CONF_CWR_NAME), + ): str, } ), ) diff --git a/custom_components/checkwatt/const.py b/custom_components/checkwatt/const.py index ede5e08..7a50588 100644 --- a/custom_components/checkwatt/const.py +++ b/custom_components/checkwatt/const.py @@ -15,6 +15,7 @@ CONF_POWER_SENSORS: Final = "show_details" CONF_PUSH_CW_TO_RANK: Final = "push_to_cw_rank" CONF_CM10_SENSOR: Final = "cm10_sensor" +CONF_CWR_NAME: Final = "cwr_name" # Misc P_UNKNOWN = "Unknown" diff --git a/custom_components/checkwatt/strings.json b/custom_components/checkwatt/strings.json index 55d949e..a26b73c 100644 --- a/custom_components/checkwatt/strings.json +++ b/custom_components/checkwatt/strings.json @@ -25,7 +25,8 @@ "data": { "show_details": "Provide energy sensors", "push_to_cw_rank": "Push data to CheckWattRank", - "cm10_sensor": "Provide CM10 sensor" + "cm10_sensor": "Provide CM10 sensor", + "cwr_name": "System name for CheckWattRank" }, "description": "Select options", "title": "CheckWatt" diff --git a/custom_components/checkwatt/translations/en.json b/custom_components/checkwatt/translations/en.json index 9615107..e1687ae 100644 --- a/custom_components/checkwatt/translations/en.json +++ b/custom_components/checkwatt/translations/en.json @@ -25,7 +25,8 @@ "data": { "show_details": "Provide energy sensors", "push_to_cw_rank": "Push data to CheckWattRank", - "cm10_sensor": "Provide CM10 sensor" + "cm10_sensor": "Provide CM10 sensor", + "cwr_name": "System name for CheckWattRank" }, "description": "Select options", "title": "CheckWatt" diff --git a/custom_components/checkwatt/translations/sv.json b/custom_components/checkwatt/translations/sv.json index bfdedbc..f35ba8a 100644 --- a/custom_components/checkwatt/translations/sv.json +++ b/custom_components/checkwatt/translations/sv.json @@ -25,7 +25,8 @@ "data": { "show_details": "Skapa energisensorer", "push_to_cw_rank": "Skicka data till CheckWattRank", - "cm10_sensor": "Skapa CM10 sensor" + "cm10_sensor": "Skapa CM10 sensor", + "cwr_name": "Systemnamn till CheckWattRank" }, "description": "Dina val", "title": "CheckWatt" From 679ef8da5d2ab2be078df01e533644d9e01121a7 Mon Sep 17 00:00:00 2001 From: faanskit Date: Sat, 27 Jan 2024 17:37:09 +0000 Subject: [PATCH 9/9] Remved debug log --- custom_components/checkwatt/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/checkwatt/__init__.py b/custom_components/checkwatt/__init__.py index 70e6303..74454cd 100644 --- a/custom_components/checkwatt/__init__.py +++ b/custom_components/checkwatt/__init__.py @@ -179,7 +179,6 @@ async def _async_update_data(self) -> CheckwattResp: # noqa: C901 push_to_cw_rank = self._entry.options.get(CONF_PUSH_CW_TO_RANK) use_cm10_sensor = self._entry.options.get(CONF_CM10_SENSOR) cwr_name = self._entry.options.get(CONF_CWR_NAME) - _LOGGER.debug("Configured name for CheckWattRank: %s", cwr_name) async with CheckwattManager( username, password, INTEGRATION_NAME