From 040ab7b0019370a3e0142807c9ba5c9d32645cfd Mon Sep 17 00:00:00 2001 From: psimsa Date: Thu, 20 Jul 2023 17:42:08 +0200 Subject: [PATCH] Refactor (#44) --- .github/workflows/hassfest.yml | 6 +- .github/workflows/release.yml | 102 +++++++++--------- README.md | 1 + custom_components/oig_cloud/__init__.py | 4 +- .../oig_cloud/oig_cloud_computed_sensor.py | 101 ++++++++--------- .../oig_cloud/oig_cloud_data_sensor.py | 76 ++++++++----- custom_components/oig_cloud/sensor.py | 50 +++++---- custom_components/oig_cloud/services.yaml | 12 +-- 8 files changed, 192 insertions(+), 160 deletions(-) diff --git a/.github/workflows/hassfest.yml b/.github/workflows/hassfest.yml index afbde1a..9b033ef 100644 --- a/.github/workflows/hassfest.yml +++ b/.github/workflows/hassfest.yml @@ -4,11 +4,11 @@ on: push: pull_request: schedule: - - cron: '0 0 * * *' + - cron: '0 0 * * *' jobs: validate: runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v3" - - uses: "home-assistant/actions/hassfest@master" \ No newline at end of file + - uses: "actions/checkout@v3" + - uses: "home-assistant/actions/hassfest@master" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e2e1a69..eb73798 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,62 +16,62 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: '18' + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' - - name: Replace version and service in release_const.py - working-directory: ./custom_components/oig_cloud - run: | - echo 'COMPONENT_VERSION = "${{ github.event.inputs.version }}"' > release_const.py - if [ "${{ github.event.inputs.version }}" == "dev" ]; then - echo 'SERVICE_NAME = "oig_cloud_dev"' >> release_const.py - else - echo 'SERVICE_NAME = "oig_cloud"' >> release_const.py - fi + - name: Replace version and service in release_const.py + working-directory: ./custom_components/oig_cloud + run: | + echo 'COMPONENT_VERSION = "${{ github.event.inputs.version }}"' > release_const.py + if [ "${{ github.event.inputs.version }}" == "dev" ]; then + echo 'SERVICE_NAME = "oig_cloud_dev"' >> release_const.py + else + echo 'SERVICE_NAME = "oig_cloud"' >> release_const.py + fi - - name: Update version property in manifest.json - working-directory: ./custom_components/oig_cloud - run: | - if [ "${{ github.event.inputs.version }}" == "dev" ]; then - jq --arg version '0.0.0' '.version = $version' manifest.json > manifest.tmp && mv manifest.tmp manifest.json - else - jq --arg version ${{ github.event.inputs.version }} '.version = $version' manifest.json > manifest.tmp && mv manifest.tmp manifest.json - fi + - name: Update version property in manifest.json + working-directory: ./custom_components/oig_cloud + run: | + if [ "${{ github.event.inputs.version }}" == "dev" ]; then + jq --arg version '0.0.0' '.version = $version' manifest.json > manifest.tmp && mv manifest.tmp manifest.json + else + jq --arg version ${{ github.event.inputs.version }} '.version = $version' manifest.json > manifest.tmp && mv manifest.tmp manifest.json + fi - - name: Commit changes - working-directory: ./custom_components/oig_cloud - run: | - git config --global user.name "Pavel Simsa" - git config --global user.email "pavel@simsa.cz" - git add release_const.py manifest.json - git commit -m "Setting release variables to ${{ github.event.inputs.version }}" + - name: Commit changes + working-directory: ./custom_components/oig_cloud + run: | + git config --global user.name "Pavel Simsa" + git config --global user.email "pavel@simsa.cz" + git add release_const.py manifest.json + git commit -m "Setting release variables to ${{ github.event.inputs.version }}" - - name: Push changes - working-directory: ./custom_components/oig_cloud - if: ${{ github.event.inputs.create-tag != 'true' }} - run: | - git push - - - name: Create tag - if: ${{ github.event.inputs.create-tag == 'true' }} - working-directory: ./custom_components/oig_cloud - run: | - git tag -a v${{ github.event.inputs.version }} -m "Version ${{ github.event.inputs.version }}" - git push --tags + - name: Push changes + working-directory: ./custom_components/oig_cloud + if: ${{ github.event.inputs.create-tag != 'true' }} + run: | + git push - - name: Create draft release - uses: actions/create-release@v1 - if: ${{ github.event.inputs.create-tag == 'true' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ github.event.inputs.version }} - release_name: Release ${{ github.event.inputs.version }} - draft: true + - name: Create tag + if: ${{ github.event.inputs.create-tag == 'true' }} + working-directory: ./custom_components/oig_cloud + run: | + git tag -a v${{ github.event.inputs.version }} -m "Version ${{ github.event.inputs.version }}" + git push --tags + + - name: Create draft release + uses: actions/create-release@v1 + if: ${{ github.event.inputs.create-tag == 'true' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ github.event.inputs.version }} + release_name: Release ${{ github.event.inputs.version }} + draft: true diff --git a/README.md b/README.md index e3de5eb..0f4fe2c 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ![GitHub Release Date - Published_At](https://img.shields.io/github/release-date/psimsa/oig_cloud) [![Validate with hassfest](https://github.com/psimsa/oig_cloud/actions/workflows/hassfest.yml/badge.svg)](https://github.com/psimsa/oig_cloud/actions/workflows/hassfest.yml) [![HACS Action](https://github.com/psimsa/oig_cloud/actions/workflows/hacs.yml/badge.svg)](https://github.com/psimsa/oig_cloud/actions/workflows/hacs.yml) +[![CodeFactor](https://www.codefactor.io/repository/github/psimsa/oig_cloud/badge)](https://www.codefactor.io/repository/github/psimsa/oig_cloud) --- # OIG Cloud Integrace pro Home Assistant diff --git a/custom_components/oig_cloud/__init__.py b/custom_components/oig_cloud/__init__.py index 547e588..283b9f9 100644 --- a/custom_components/oig_cloud/__init__.py +++ b/custom_components/oig_cloud/__init__.py @@ -35,8 +35,8 @@ async def async_setup_entry( no_telemetry = entry.data[CONF_NO_TELEMETRY] if no_telemetry is False: - email_hash = hashlib.md5(username.encode("utf-8")).hexdigest() - hass_id = hashlib.md5(hass.data["core.uuid"].encode("utf-8")).hexdigest() + email_hash = hashlib.sha256(username.encode("utf-8")).hexdigest() + hass_id = hashlib.sha256(hass.data["core.uuid"].encode("utf-8")).hexdigest() setup_tracing(email_hash, hass_id) api_logger = logging.getLogger(oig_cloud_api.__name__) diff --git a/custom_components/oig_cloud/oig_cloud_computed_sensor.py b/custom_components/oig_cloud/oig_cloud_computed_sensor.py index b1a660e..17a5195 100644 --- a/custom_components/oig_cloud/oig_cloud_computed_sensor.py +++ b/custom_components/oig_cloud/oig_cloud_computed_sensor.py @@ -25,7 +25,6 @@ class OigCloudComputedSensor(OigCloudSensor): - @property def state(self): _LOGGER.debug(f"Getting state for {self.entity_id}") @@ -52,62 +51,68 @@ def state(self): return float(pv_data["dc_in"]["fv_p1"] + pv_data["dc_in"]["fv_p2"]) if self._node_id == "boiler" or self._sensor_type == "boiler_current_w": - if len(pv_data["boiler"]) > 0 and pv_data["boiler"]["p"] is not None: - # Spotreba bojleru - if ( - self._sensor_type == "boiler_current_w" - and pv_data["boiler"]["p"] > 0 - and ( - pv_data["ac_in"]["aci_wr"] - + pv_data["ac_in"]["aci_ws"] - + pv_data["ac_in"]["aci_wt"] - ) - < 0 - ): - return float( - pv_data["boiler"]["p"] - + ( - pv_data["ac_in"]["aci_wr"] - + pv_data["ac_in"]["aci_ws"] - + pv_data["ac_in"]["aci_wt"] - ) - ) - elif self._sensor_type == "boiler_current_w": - return float(pv_data["boiler"]["p"]) - else: - return None + return self._get_boiler_consumption(pv_data) # Spotreba CBB if self._sensor_type == "cbb_consumption_w": - boiler_p = 0 + return self._get_cbb_consumption(pv_data) + + return None + + def _get_cbb_consumption(self, pv_data) -> float: + boiler_p = 0 + if ( + len(pv_data["boiler"]) > 0 + and pv_data["boiler"]["p"] is not None + and pv_data["boiler"]["p"] > 0 + ): + boiler_p = pv_data["boiler"]["p"] + return float( + # Výkon FVE + (pv_data["dc_in"]["fv_p1"] + pv_data["dc_in"]["fv_p2"]) + - + # Spotřeba bojleru + boiler_p + - + # Spotřeba zátěž + pv_data["ac_out"]["aco_p"] + + + # Odběr ze sítě + ( + pv_data["ac_in"]["aci_wr"] + + pv_data["ac_in"]["aci_ws"] + + pv_data["ac_in"]["aci_wt"] + ) + + + # Nabíjení/vybíjení baterie + (pv_data["batt"]["bat_i"] * pv_data["batt"]["bat_v"] * -1) + ) + + def _get_boiler_consumption(self, pv_data): + if len(pv_data["boiler"]) > 0 and pv_data["boiler"]["p"] is not None: + # Spotreba bojleru if ( - len(pv_data["boiler"]) > 0 - and pv_data["boiler"]["p"] is not None - and pv_data["boiler"]["p"] > 0 + self._sensor_type == "boiler_current_w" + and pv_data["boiler"]["p"] > 0 + and ( + pv_data["ac_in"]["aci_wr"] + + pv_data["ac_in"]["aci_ws"] + + pv_data["ac_in"]["aci_wt"] + ) + < 0 ): - boiler_p = pv_data["boiler"]["p"] - return float( - # Výkon FVE - (pv_data["dc_in"]["fv_p1"] + pv_data["dc_in"]["fv_p2"]) - - - # Spotřeba bojleru - boiler_p - - - # Spotřeba zátěž - pv_data["ac_out"]["aco_p"] - + - # Odběr ze sítě - ( + return float( + pv_data["boiler"]["p"] + + ( pv_data["ac_in"]["aci_wr"] + pv_data["ac_in"]["aci_ws"] + pv_data["ac_in"]["aci_wt"] + ) ) - + - # Nabíjení/vybíjení baterie - (pv_data["batt"]["bat_i"] * pv_data["batt"]["bat_v"] * -1) - ) - - return None + elif self._sensor_type == "boiler_current_w": + return float(pv_data["boiler"]["p"]) + else: + return None async def async_update(self): # Request the coordinator to fetch new data and update the entity's state diff --git a/custom_components/oig_cloud/oig_cloud_data_sensor.py b/custom_components/oig_cloud/oig_cloud_data_sensor.py index d3b838c..b6496a3 100644 --- a/custom_components/oig_cloud/oig_cloud_data_sensor.py +++ b/custom_components/oig_cloud/oig_cloud_data_sensor.py @@ -43,40 +43,60 @@ def state(self): # special cases if self._sensor_type == "box_prms_mode": - if node_value == 0: - return "Home 1" - elif node_value == 1: - return "Home 2" - elif node_value == 2: - return "Home 3" - elif node_value == 3: - return "Home UPS" - return _LANGS["unknown"][language] + return self._get_mode_name(node_value, language) if self._sensor_type == "invertor_prms_to_grid": - grid_enabled = int(pv_data["box_prms"]["crcte"]) - to_grid = int(node_value) - max_grid_feed = int(pv_data["invertor_prm1"]["p_max_feed_grid"]) + return self._grid_mode(pv_data, node_value, language) - if bool(pv_data["queen"]): - vypnuto = 0 == to_grid and 0 == max_grid_feed - zapnuto = 1 == to_grid - limited = 0 == to_grid and 0 < max_grid_feed - else: - vypnuto = 0 == grid_enabled and 0 == to_grid - zapnuto = 1 == grid_enabled and 1 == to_grid and 10000 == max_grid_feed - limited = 1 == grid_enabled and 1 == to_grid and 9999 >= max_grid_feed - - if vypnuto: - return GridMode.OFF.value - elif limited: - return GridMode.LIMITED.value - elif zapnuto: - return GridMode.ON.value - return _LANGS["changing"][language] try: return float(node_value) except ValueError: return node_value except KeyError: return None + + def _get_mode_name(self, node_value, language): + if node_value == 0: + return "Home 1" + elif node_value == 1: + return "Home 2" + elif node_value == 2: + return "Home 3" + elif node_value == 3: + return "Home UPS" + return _LANGS["unknown"][language] + + def _grid_mode(self, pv_data, node_value, language): + grid_enabled = int(pv_data["box_prms"]["crcte"]) + to_grid = int(node_value) + max_grid_feed = int(pv_data["invertor_prm1"]["p_max_feed_grid"]) + + if bool(pv_data["queen"]): + return self._grid_mode_queen(grid_enabled, to_grid, max_grid_feed, language) + return self._grid_mode_king(grid_enabled, to_grid, max_grid_feed, language) + + def _grid_mode_queen(self, grid_enabled, to_grid, max_grid_feed, language): + vypnuto = 0 == to_grid and 0 == max_grid_feed + zapnuto = 1 == to_grid + limited = 0 == to_grid and 0 < max_grid_feed + + if vypnuto: + return GridMode.OFF.value + elif limited: + return GridMode.LIMITED.value + elif zapnuto: + return GridMode.ON.value + return _LANGS["changing"][language] + + def _grid_mode_king(self, grid_enabled, to_grid, max_grid_feed, language): + vypnuto = 0 == grid_enabled and 0 == to_grid + zapnuto = 1 == grid_enabled and 1 == to_grid and 10000 == max_grid_feed + limited = 1 == grid_enabled and 1 == to_grid and 9999 >= max_grid_feed + + if vypnuto: + return GridMode.OFF.value + elif limited: + return GridMode.LIMITED.value + elif zapnuto: + return GridMode.ON.value + return _LANGS["changing"][language] \ No newline at end of file diff --git a/custom_components/oig_cloud/sensor.py b/custom_components/oig_cloud/sensor.py index c592528..afbccb9 100644 --- a/custom_components/oig_cloud/sensor.py +++ b/custom_components/oig_cloud/sensor.py @@ -40,37 +40,43 @@ async def update_data(): _LOGGER.debug("First refresh done, will add entities") # Add common entities + _register_common_entities(async_add_entities, coordinator) + + box_id = list(oig_cloud.last_state.keys())[0] + # Add entities that require 'boiler' + if len(oig_cloud.last_state[box_id]["boiler"]) > 0: + _register_boiler_entities(async_add_entities, coordinator) + + _LOGGER.debug("async_setup_entry done") + + +def _register_boiler_entities(async_add_entities, coordinator): async_add_entities( OigCloudDataSensor(coordinator, sensor_type) for sensor_type in SENSOR_TYPES - if not "requires" in SENSOR_TYPES[sensor_type].keys() + if "requires" in SENSOR_TYPES[sensor_type].keys() + and "boiler" in SENSOR_TYPES[sensor_type]["requires"] and SENSOR_TYPES[sensor_type]["node_id"] is not None ) async_add_entities( OigCloudComputedSensor(coordinator, sensor_type) for sensor_type in SENSOR_TYPES - if not "requires" in SENSOR_TYPES[sensor_type].keys() + if "requires" in SENSOR_TYPES[sensor_type].keys() + and "boiler" in SENSOR_TYPES[sensor_type]["requires"] and SENSOR_TYPES[sensor_type]["node_id"] is None ) - box_id = list(oig_cloud.last_state.keys())[0] - # Add entities that require 'boiler' - if len(oig_cloud.last_state[box_id]["boiler"]) > 0: - async_add_entities( - OigCloudDataSensor(coordinator, sensor_type) - for sensor_type in SENSOR_TYPES - if "requires" in SENSOR_TYPES[sensor_type].keys() - and "boiler" in SENSOR_TYPES[sensor_type]["requires"] - and SENSOR_TYPES[sensor_type]["node_id"] is not None - - ) - async_add_entities( - OigCloudComputedSensor(coordinator, sensor_type) - for sensor_type in SENSOR_TYPES - if "requires" in SENSOR_TYPES[sensor_type].keys() - and "boiler" in SENSOR_TYPES[sensor_type]["requires"] - and SENSOR_TYPES[sensor_type]["node_id"] is None - - ) - _LOGGER.debug("async_setup_entry done") +def _register_common_entities(async_add_entities, coordinator): + async_add_entities( + OigCloudDataSensor(coordinator, sensor_type) + for sensor_type in SENSOR_TYPES + if not "requires" in SENSOR_TYPES[sensor_type].keys() + and SENSOR_TYPES[sensor_type]["node_id"] is not None + ) + async_add_entities( + OigCloudComputedSensor(coordinator, sensor_type) + for sensor_type in SENSOR_TYPES + if not "requires" in SENSOR_TYPES[sensor_type].keys() + and SENSOR_TYPES[sensor_type]["node_id"] is None + ) diff --git a/custom_components/oig_cloud/services.yaml b/custom_components/oig_cloud/services.yaml index cc04c46..e7ef2ef 100644 --- a/custom_components/oig_cloud/services.yaml +++ b/custom_components/oig_cloud/services.yaml @@ -8,14 +8,14 @@ set_box_mode: fields: Mode: description: The mode to set - example: "Home 1" + example: 'Home 1' selector: select: options: - - "Home 1" - - "Home 2" - - "Home 3" - - "Home UPS" + - 'Home 1' + - 'Home 2' + - 'Home 3' + - 'Home UPS' Acknowledgement: description: | I acknowledge that calling the service will result in parameter modification of a live system. @@ -70,7 +70,7 @@ set_grid_delivery: NEJSME ZODPOVĚDNI ZA TAKOVÉ JEDNÁNÍ Z VAŠÍ STRANY. Povolením přetoků BATTERY BOX umožňuje posílat přebytky z výroby do distribuční sítě (DS). Nadvýroba vzniká v případě, kdy elektrárna vyrábí, v objektu již došlo k uspokojení veškeré zátěže a BATTERY BOX má nabité - baterie. Dle Pravidel provozování distribučních soustav (dále PPDS) je možné posílat do DS přebytky energie + baterie. Dle Pravidel provozování distribučních soustav (dále PPDS) je možné posílat do DS přebytky energie pouze pokud **máte dle Smlouvy o připojení (SoP) tento stav schválen provozovatelem DS** odpovídající skutečnému výkonu FVE, již došlo k **Prvnímu paralelnímu připojení** (dále jen PPP) a obdrželi jste Protokol o PPP. Jako majitel zařízení BATTERY BOX máte možnost sám aktivovat nebo deaktivovat povolení přetoků. Pokud