From cf76e8879a4fececf7ac49a9f556c0661fa108a3 Mon Sep 17 00:00:00 2001 From: Alessandro Del Prete Date: Fri, 9 Feb 2024 14:16:24 +0100 Subject: [PATCH] Initial commit --- .devcontainer.json | 55 ++ .gitattributes | 1 + .github/FUNDING.yml | 2 + .github/ISSUE_TEMPLATE/bug.yml | 55 ++ .github/ISSUE_TEMPLATE/config.yml | 11 + .github/ISSUE_TEMPLATE/feature_request.yml | 47 ++ .github/dependabot.yml | 15 + .github/workflows/lint.yml | 45 ++ .github/workflows/release.yml | 37 + .github/workflows/validate.yml | 39 ++ .gitignore | 17 + .ruff.toml | 67 ++ .vscode/tasks.json | 11 + LICENSE | 21 + README.md | 84 +++ config/configuration.yaml | 10 + custom_components/sinapsi_alfa/__init__.py | 161 +++++ custom_components/sinapsi_alfa/api.py | 647 ++++++++++++++++++ custom_components/sinapsi_alfa/config_flow.py | 228 ++++++ custom_components/sinapsi_alfa/const.py | 480 +++++++++++++ custom_components/sinapsi_alfa/coordinator.py | 94 +++ custom_components/sinapsi_alfa/manifest.json | 13 + custom_components/sinapsi_alfa/sensor.py | 194 ++++++ .../sinapsi_alfa/translations/en.json | 38 + doc/alfa-ha-modbus-configuration.yaml | 135 ++++ doc/distacco.yaml | 9 + gfxfiles/alfa-400-200x35.png | Bin 0 -> 2483 bytes gfxfiles/alfa-400.png | Bin 0 -> 4506 bytes gfxfiles/config.png | Bin 0 -> 18498 bytes gfxfiles/demo.png | Bin 0 -> 48457 bytes gfxfiles/icon.png | Bin 0 -> 8166 bytes gfxfiles/icon@2x.png | Bin 0 -> 20594 bytes gfxfiles/logo.png | Bin 0 -> 20206 bytes gfxfiles/logo@2x.png | Bin 0 -> 47117 bytes hacs.json | 8 + requirements.txt | 5 + scripts/develop | 20 + scripts/lint | 7 + scripts/setup | 7 + 39 files changed, 2563 insertions(+) create mode 100644 .devcontainer.json create mode 100644 .gitattributes create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/validate.yml create mode 100644 .gitignore create mode 100644 .ruff.toml create mode 100644 .vscode/tasks.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 config/configuration.yaml create mode 100644 custom_components/sinapsi_alfa/__init__.py create mode 100644 custom_components/sinapsi_alfa/api.py create mode 100644 custom_components/sinapsi_alfa/config_flow.py create mode 100644 custom_components/sinapsi_alfa/const.py create mode 100644 custom_components/sinapsi_alfa/coordinator.py create mode 100644 custom_components/sinapsi_alfa/manifest.json create mode 100644 custom_components/sinapsi_alfa/sensor.py create mode 100644 custom_components/sinapsi_alfa/translations/en.json create mode 100644 doc/alfa-ha-modbus-configuration.yaml create mode 100644 doc/distacco.yaml create mode 100644 gfxfiles/alfa-400-200x35.png create mode 100644 gfxfiles/alfa-400.png create mode 100644 gfxfiles/config.png create mode 100644 gfxfiles/demo.png create mode 100644 gfxfiles/icon.png create mode 100644 gfxfiles/icon@2x.png create mode 100644 gfxfiles/logo.png create mode 100644 gfxfiles/logo@2x.png create mode 100644 hacs.json create mode 100644 requirements.txt create mode 100644 scripts/develop create mode 100644 scripts/lint create mode 100644 scripts/setup diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 0000000..47dd79b --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,55 @@ +{ + "name": "Sinapsi Alfa Modbus integration development", + "image": "mcr.microsoft.com/devcontainers/python:3.11-bullseye", + "postCreateCommand": "scripts/setup", + "forwardPorts": [ + 8123 + ], + "portsAttributes": { + "8123": { + "label": "Home Assistant", + "onAutoForward": "notify" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "github.vscode-pull-request-github", + "ryanluker.vscode-coverage-gutters", + "ms-python.vscode-pylance", + "charliermarsh.ruff", + "ms-python.black-formatter", + "esbenp.prettier-vscode" + ], + "settings": { + "files.eol": "\n", + "files.trimTrailingWhitespace": true, + "editor.tabSize": 4, + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + // Ruff config + "notebook.formatOnSave.enabled": false, + "notebook.codeActionsOnSave": { + "notebook.source.fixAll": false, + "notebook.source.organizeImports": false + }, + "[python]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": true, + "source.organizeImports": true + }, + "editor.defaultFormatter": "charliermarsh.ruff" + } + // End Ruff config + } + } + }, + "remoteUser": "vscode", + "features": { + "ghcr.io/devcontainers/features/rust:1": {} + } +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94f480d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7aab465 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +# Want to support the project? Donate here! +custom: https://www.buymeacoffee.com/alexdelprete diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..92fe7a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,55 @@ +--- +name: "Bug report" +description: "Report a bug with the integration" +labels: "Bug" +body: +- type: markdown + attributes: + value: Before you open a new issue, search through the existing issues to see if others have had the same problem. +- type: textarea + attributes: + label: "System Health details" + description: "Paste the data from the System Health card in Home Assistant (https://www.home-assistant.io/more-info/system-health#github-issues)" + validations: + required: true +- type: checkboxes + attributes: + label: Checklist + options: + - label: I have enabled debug logging for my installation. + required: true + - label: I have filled out the issue template to the best of my ability. + required: true + - label: This issue only contains 1 issue (if you have multiple issues, open one issue for each issue). + required: true + - label: This issue is not a duplicate issue of any [previous issues](https://github.com/ludeeus/integration_blueprint/issues?q=is%3Aissue+label%3A%22Bug%22+).. + required: true +- type: textarea + attributes: + label: "Describe the issue" + description: "A clear and concise description of what the issue is." + validations: + required: true +- type: textarea + attributes: + label: Reproduction steps + description: "Without steps to reproduce, it will be hard to fix. It is very important that you fill out this part. Issues without it will be closed." + value: | + 1. + 2. + 3. + ... + validations: + required: true +- type: textarea + attributes: + label: "Debug logs" + description: "To enable debug logs check this https://www.home-assistant.io/integrations/logger/, this **needs** to include _everything_ from startup of Home Assistant to the point where you encounter the issue." + render: text + validations: + required: true + +- type: textarea + attributes: + label: "Diagnostics dump" + description: "Drag the diagnostics dump file here. (see https://www.home-assistant.io/integrations/diagnostics/ for info)" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..b0b5ee8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: I need support + url: https://github.com/nathanmarlor/alexdelprete/ha-abb-powerone-pvi-sunspec/discussions/new?category=support + about: Questions? Problems? Get help here + - name: Feature request + url: https://github.com/nathanmarlor/alexdelprete/ha-abb-powerone-pvi-sunspec/discussions/new?category=ideas + about: Share ideas for new features + - name: Anything else + url: https://github.com/nathanmarlor/alexdelprete/ha-abb-powerone-pvi-sunspec/discussions/new?category=general + about: If it's something else or you're not sure, open a discussion \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..433467b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,47 @@ +--- +name: "Feature request" +description: "Suggest an idea for this project" +labels: "Feature+Request" +body: +- type: markdown + attributes: + value: Before you open a new feature request, search through the existing feature requests to see if others have had the same idea. +- type: checkboxes + attributes: + label: Checklist + options: + - label: I have filled out the template to the best of my ability. + required: true + - label: This only contains 1 feature request (if you have multiple feature requests, open one feature request for each feature request). + required: true + - label: This issue is not a duplicate feature request of [previous feature requests](https://github.com/ludeeus/integration_blueprint/issues?q=is%3Aissue+label%3A%22Feature+Request%22+). + required: true + +- type: textarea + attributes: + label: "Is your feature request related to a problem? Please describe." + description: "A clear and concise description of what the problem is." + placeholder: "I'm always frustrated when [...]" + validations: + required: true + +- type: textarea + attributes: + label: "Describe the solution you'd like" + description: "A clear and concise description of what you want to happen." + validations: + required: true + +- type: textarea + attributes: + label: "Describe alternatives you've considered" + description: "A clear and concise description of any alternative solutions or features you've considered." + validations: + required: true + +- type: textarea + attributes: + label: "Additional context" + description: "Add any other context or screenshots about the feature request here." + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..28adb41 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + ignore: + # Dependabot should not update Home Assistant as that should match the homeassistant key in hacs.json + - dependency-name: "homeassistant" \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..4799b87 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,45 @@ +name: "Lint" + +on: + push: + branches: + - master + pull_request: + +jobs: + ruff: + name: "Ruff" + runs-on: "ubuntu-latest" + + # see: https://github.com/stefanzweifel/git-auto-commit-action#usage + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push the + # added or changed files to the repository. + contents: write + + steps: + - name: "Checkout the repository" + uses: "actions/checkout@v4.1.1" + with: + token: ${{ secrets.WORKFLOW_PAT || github.token }} + ref: ${{ github.head_ref }} + + - name: "Set up Python" + uses: actions/setup-python@v5.0.0 + with: + python-version: "3.11" + cache: "pip" + + - name: "Install requirements" + run: python3 -m pip install -r requirements.txt + + - name: "Format" + run: python3 -m ruff format . + + - name: "Check" + run: python3 -m ruff check . + + - name: "Auto Commit" + uses: stefanzweifel/git-auto-commit-action@v5.0.0 + with: + commit_message: 'Style fixes by ruff' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1267ccc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: "Release" + +on: + release: + types: + - "published" + +permissions: {} + +jobs: + release: + name: "Release" + runs-on: "ubuntu-latest" + permissions: + contents: write + steps: + - name: "Checkout the repository" + uses: "actions/checkout@v4.1.1" + with: + token: ${{ secrets.WORKFLOW_PAT || github.token }} + + - name: "Adjust version number" + shell: "bash" + run: | + yq -i -o json '.version="${{ github.event.release.tag_name }}"' \ + "${{ github.workspace }}/custom_components/abb_powerone_pvi_sunspec/manifest.json" + + - name: "ZIP the integration directory" + shell: "bash" + run: | + cd "${{ github.workspace }}/custom_components/abb_powerone_pvi_sunspec" + zip abb_powerone_pvi_sunspec.zip -r ./ + + - name: "Upload the ZIP file to the release" + uses: softprops/action-gh-release@v0.1.15 + with: + files: ${{ github.workspace }}/custom_components/abb_powerone_pvi_sunspec/abb_powerone_pvi_sunspec.zip diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..42f6aa4 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,39 @@ +name: "Validate" + +on: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: "0 0 * * *" + +jobs: + hassfest: # https://developers.home-assistant.io/blog/2020/04/16/hassfest + name: "Hassfest Validation" + runs-on: "ubuntu-latest" + steps: + - name: "Checkout the repository" + uses: "actions/checkout@v4.1.1" + with: + token: ${{ secrets.WORKFLOW_PAT || github.token }} + ref: ${{ github.head_ref }} + + - name: "Run hassfest validation" + uses: "home-assistant/actions/hassfest@master" + + hacs: # https://github.com/hacs/action + name: "HACS Validation" + runs-on: "ubuntu-latest" + steps: + - name: "Checkout the repository" + uses: "actions/checkout@v4.1.1" + with: + token: ${{ secrets.WORKFLOW_PAT || github.token }} + ref: ${{ github.head_ref }} + + - name: "Run HACS validation" + uses: "hacs/action@main" + with: + category: "integration" + # Remove this 'ignore' key when you have added brand images for your integration to https://github.com/home-assistant/brands + #ignore: "brands" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..94fa16c --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# artifacts +__pycache__ +.pytest* +*.egg-info +*/build/* +*/dist/* + + +# misc +.coverage +.vscode +coverage.xml + + +# Home Assistant configuration +config/* +!config/configuration.yaml \ No newline at end of file diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..52bd904 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,67 @@ +# The contents of this file is based on https://github.com/home-assistant/core/blob/dev/pyproject.toml + +target-version = "py311" + +select = [ + "B007", # Loop control variable {name} not used within loop body + "B014", # Exception handler with duplicate exception + "C", # complexity + "D", # docstrings + "E", # pycodestyle + "F", # pyflakes/autoflake + "ICN001", # import concentions; {name} should be imported as {asname} + "PGH004", # Use specific rule codes when using noqa + "PLC0414", # Useless import alias. Import alias does not rename original package. + "SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass + "SIM117", # Merge with-statements that use the same scope + "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() + "SIM201", # Use {left} != {right} instead of not {left} == {right} + "SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a} + "SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'. + "SIM401", # Use get from dict with default instead of an if block + "T20", # flake8-print + "TRY004", # Prefer TypeError exception for invalid type + "RUF006", # Store a reference to the return value of asyncio.create_task + "UP", # pyupgrade + "W", # pycodestyle +] + +ignore = [ + "D202", # No blank lines allowed after function docstring + "D203", # 1 blank line required before class docstring + "D213", # Multi-line docstring summary should start at the second line + "D404", # First word of the docstring should not be This + "D406", # Section name should end with a newline + "D407", # Section name underlining + "D411", # Missing blank line before section + "E501", # line too long + "E731", # do not assign a lambda expression, use a def + + # May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "W191", + "E111", + "E114", + "E117", + "D206", + "D300", + "Q000", + "Q001", + "Q002", + "Q003", + "COM812", + "COM819", + "ISC001", + "ISC002", + + # Disabled because ruff does not understand type of __all__ generated by a function + "PLE0605", +] + +[flake8-pytest-style] +fixture-parentheses = false + +[pyupgrade] +keep-runtime-typing = true + +[mccabe] +max-complexity = 25 \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3f09cee --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run Home Assistant on port 8123", + "type": "shell", + "command": "scripts/develop", + "problemMatcher": [] + }, + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..30ff413 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 - 2024 Alessandro Del Prete @alexdelprete + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..36ec975 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# HA Custom Component for Sinapsi Alfa energy monitoring device + +[![GitHub Release][releases-shield]][releases] +[![BuyMeCoffee][buymecoffee-shield]][buymecoffee] +[![Community Forum][forum-shield]][forum] + +_This project is not endorsed by, directly affiliated with, maintained, authorized, or sponsored by ABB or FIMER_ + +# Introduction + +HA Custom Component to integrate data from ABB/Power-One/FIMER PV mono-phase and three-phase inverters that support SunSpec Modbus Models M1/M103/M160, natively or through the VSN300/VSN700 wifi logger card. The VSN300/VSN700 cards provide a SunSpec to Aurora protocol adapter so that all modbus commands are translated to the proprietary Aurora protocol. + +The component has been originally developed by @binsentsu for SolarEdge inverters, I adapted it, adding some features, rewriting all the registers' mapping, for my Power-One Aurora PVI-10.0-OUTD 3-phase inverter to which I added a VSN300 card. It has also been tested with an ABB TRIO-8.5-TL-OUTD-S through a VSN300 and REACT2-3.6-TL through a VSN700 datalogger. + +Register address map has been implemented following the vendor's specification documentation, available in the [doc](https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec/tree/master/doc) folder. + + +### Features + +- Installation/Configuration through Config Flow UI +- Separate sensor per register +- Configurable TCP modbus port, also at runtime (no restart needed) +- Configurable modbus slave address, also at runtime (no restart needed) +- Configurable register map base address, also at runtime (no restart needed) +- Configurable polling interval, also at runtime (no restart needed) +- Supports SunSpec models M1, M103, M160 + +# Installation through HACS + +This integration is available in [HACS][hacs] official repository. Click this button to open HA directly on the integration page so you can easily install it: + +[![Quick installation link](https://my.home-assistant.io/badges/hacs_repository.svg)][my-hacs] + +1. Either click the button above, or navigate to HACS in Home Assistant and: + - 'Explore & Download Repositories' + - Search for 'ABB Power-One PVI SunSpec' + - Download +2. Restart Home Assistant +3. Go to Settings > Devices and Services > Add Integration +4. Search for and select 'ABB Power-One PVI SunSpec' (if the integration is not found, do a hard-refresh (ctrl+F5) in the browser) +5. Proceed with the configuration + +# Manual Installation + +Download the source code archive from the release page. Unpack the archive and copy the contents of custom_components folder to your home-assistant config/custom_components folder. Restart Home Assistant, and then the integration can be added and configured through the native integration setup UI. If you don't see it in the native integrations list, press ctrl-F5 to refresh the browser while you're on that page and retry. + +# Enabling Modbus TCP on the inverter + +Enable Modbus TCP client on the VSN300, take note of the Unit ID (aka Slave ID) of the inverter (depends on the model, default on some models is 2 on others is 247) and during the configuration of the component, use the appropriate Slave address. Another important parameter is the registers map base address, default is 40000 but it may vary. All these parameters can be reconfigured after installation, clicking CONFIGURE on the integration. + +# Configuration + +Configuration is done via config flow right after adding the integration. After the first configuration you can change parameters (except custom name and ip/hostname) at runtime through the integration page configuration, without the need to restart HA (this works since v2.5.0). + +![](https://user-images.githubusercontent.com/7027842/214734702-bf899013-5e28-47b5-87a7-827e49ca465b.gif) + +- **custom name**: custom name for the inverter, that will be used as prefix for sensors created by the component +- **ip/hostname**: IP/hostname of the inverter - this is used as unique_id, if you change it and reinstall you will lose historical data, that's why I advice to use hostname, so you can change IP without losing historical data +- **tcp port**: TCP port of the datalogger +- **slave id**: the unit id of the inverter in the chain: default is 254, if using VS300/VS700 it's usually 2 +- **register map base address**: the base address from where the register map starts, usually it's 40000, but for ABB VSN300/VSN700 dataloggers it's 0 +- **polling period**: frequency, in seconds, to read the registers and update the sensors + +Config + +# Sensor screenshot +Config + +# Coffee + +_If you like this integration, I'll gladly accept some quality coffee, but please don't feel obliged._ :) + +[![BuyMeCoffee][buymecoffee-shield]][buymecoffee] + +--- + +[buymecoffee]: https://www.buymeacoffee.com/alexdelprete +[buymecoffee-shield]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-white?style=for-the-badge +[hacs]: https://hacs.xyz +[my-hacs]: https://my.home-assistant.io/redirect/hacs_repository/?owner=alexdelprete&repository=ha-abb-powerone-pvi-sunspec&category=integration +[forum-shield]: https://img.shields.io/badge/community-forum-darkred?style=for-the-badge +[forum]: https://community.home-assistant.io/t/custom-component-abb-power-one-fimer-pv-inverters-sunspec-modbus-tcp/316363?u=alexdelprete +[releases-shield]: https://img.shields.io/github/v/release/alexdelprete/ha-abb-powerone-pvi-sunspec?style=for-the-badge&color=darkgreen +[releases]: https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec/releases diff --git a/config/configuration.yaml b/config/configuration.yaml new file mode 100644 index 0000000..f27fc5e --- /dev/null +++ b/config/configuration.yaml @@ -0,0 +1,10 @@ +# https://www.home-assistant.io/integrations/default_config/ +default_config: + +# https://www.home-assistant.io/integrations/logger/ +logger: + default: info + logs: + custom_components.sinapsi_alfa: debug +# If you need to debug uncommment the line below (doc: https://www.home-assistant.io/integrations/debugpy/) +debugpy: diff --git a/custom_components/sinapsi_alfa/__init__.py b/custom_components/sinapsi_alfa/__init__.py new file mode 100644 index 0000000..9c4dff3 --- /dev/null +++ b/custom_components/sinapsi_alfa/__init__.py @@ -0,0 +1,161 @@ +"""ABB Power-One PVI SunSpec Integration. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +import asyncio +import logging + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import device_registry as dr + +from .const import ( + CONF_HOST, + CONF_NAME, + DATA, + DOMAIN, + PLATFORMS, + STARTUP_MESSAGE, + UPDATE_LISTENER, +) +from .coordinator import ABBPowerOneFimerCoordinator + +_LOGGER = logging.getLogger(__name__) + + +def get_instance_count(hass: HomeAssistant) -> int: + """Return number of instances.""" + entries = [ + entry + for entry in hass.config_entries.async_entries(DOMAIN) + if not entry.disabled_by + ] + return len(entries) + + +async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): + """Set up this integration using UI.""" + if hass.data.get(DOMAIN) is None: + hass.data.setdefault(DOMAIN, {}) + _LOGGER.info(STARTUP_MESSAGE) + + _LOGGER.debug(f"Setup config_entry for {DOMAIN}") + coordinator = ABBPowerOneFimerCoordinator(hass, config_entry) + # If the refresh fails, async_config_entry_first_refresh() will + # raise ConfigEntryNotReady and setup will try again later + # ref.: https://developers.home-assistant.io/docs/integration_setup_failures + await coordinator.async_config_entry_first_refresh() + if not coordinator.api.data["comm_sernum"]: + raise ConfigEntryNotReady( + f"Timeout connecting to {config_entry.data.get(CONF_NAME)}" + ) + + # Update listener for config option changes + update_listener = config_entry.add_update_listener(_async_update_listener) + + # Add coordinator and update_listener to config_entry + hass.data[DOMAIN][config_entry.entry_id] = { + DATA: coordinator, + UPDATE_LISTENER: update_listener, + } + + # Setup platforms + for platform in PLATFORMS: + hass.async_add_job( + hass.config_entries.async_forward_entry_setup(config_entry, platform) + ) + + # Regiser device + await async_update_device_registry(hass, config_entry) + + return True + + +async def async_update_device_registry(hass: HomeAssistant, config_entry): + """Manual device registration.""" + coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA] + device_registry = dr.async_get(hass) + device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + hw_version=None, + configuration_url=f"http://{config_entry.data.get(CONF_HOST)}", + identifiers={(DOMAIN, coordinator.api.data["comm_sernum"])}, + manufacturer=coordinator.api.data["comm_manufact"], + model=coordinator.api.data["comm_model"], + name=config_entry.data.get(CONF_NAME), + serial_number=coordinator.api.data["comm_sernum"], + sw_version=coordinator.api.data["comm_version"], + via_device=None, + ) + + +async def _async_update_listener(hass: HomeAssistant, config_entry): + """Handle options update.""" + await hass.config_entries.async_reload(config_entry.entry_id) + + +async def async_remove_config_entry_device( + hass: HomeAssistant, config_entry, device_entry +) -> bool: + """Delete device if not entities.""" + if DOMAIN in device_entry.identifiers: + _LOGGER.error( + "You cannot delete the device using device delete. Remove the integration instead." + ) + return False + return True + + +async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: + """Handle removal of config_entry.""" + _LOGGER.debug("Unload config_entry") + # Check if there are other instances + if get_instance_count(hass) == 0: + _LOGGER.debug("Unload config_entry: no more entries found") + + _LOGGER.debug("Unload integration platforms") + # Unload a config entry + unloaded = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(config_entry, platform) + for platform in PLATFORMS + ] + ) + ) + + _LOGGER.debug("Detach config update listener") + hass.data[DOMAIN][config_entry.entry_id][UPDATE_LISTENER]() + + if unloaded: + _LOGGER.debug("Unload integration") + hass.data[DOMAIN].pop(config_entry.entry_id) + return True # unloaded + else: + _LOGGER.debug("Unload config_entry failed: integration not unloaded") + return False # unload failed + + +# Sample migration code in case it's needed +# async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry): +# """Migrate an old config_entry.""" +# version = config_entry.version + +# # 1-> 2: Migration format +# if version == 1: +# # Get handler to coordinator from config +# coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA] +# _LOGGER.debug("Migrating from version %s", version) +# old_uid = config_entry.unique_id +# new_uid = coordinator.api.data["comm_sernum"] +# if old_uid != new_uid: +# hass.config_entries.async_update_entry( +# config_entry, unique_id=new_uid +# ) +# _LOGGER.debug("Migration to version %s complete: OLD_UID: %s - NEW_UID: %s", config_entry.version, old_uid, new_uid) +# if config_entry.unique_id == new_uid: +# config_entry.version = 2 +# _LOGGER.debug("Migration to version %s complete: NEW_UID: %s", config_entry.version, config_entry.unique_id) +# return True diff --git a/custom_components/sinapsi_alfa/api.py b/custom_components/sinapsi_alfa/api.py new file mode 100644 index 0000000..89690cc --- /dev/null +++ b/custom_components/sinapsi_alfa/api.py @@ -0,0 +1,647 @@ +"""API Platform for ABB Power-One PVI SunSpec. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +import logging +import socket +import threading + +from pymodbus.client import ModbusTcpClient +from pymodbus.constants import Endian +from pymodbus.exceptions import ConnectionException, ModbusException +from pymodbus.payload import BinaryPayloadDecoder + +from .const import DEVICE_GLOBAL_STATUS, DEVICE_MODEL, DEVICE_STATUS, INVERTER_TYPE + +_LOGGER = logging.getLogger(__name__) + + +class ConnectionError(Exception): + """Empty Error Class.""" + + pass + + +class ModbusError(Exception): + """Empty Error Class.""" + + pass + + +class ABBPowerOneFimerAPI: + """Thread safe wrapper class for pymodbus.""" + + def __init__( + self, + hass, + name, + host, + port, + slave_id, + base_addr, + scan_interval, + ): + """Initialize the Modbus API Client.""" + self._hass = hass + self._name = name + self._host = host + self._port = port + self._slave_id = slave_id + self._base_addr = base_addr + self._update_interval = scan_interval + # Ensure ModBus Timeout is 1s less than scan_interval + # https://github.com/binsentsu/home-assistant-solaredge-modbus/pull/183 + self._timeout = self._update_interval - 1 + self._client = ModbusTcpClient( + host=self._host, port=self._port, timeout=self._timeout + ) + self._lock = threading.Lock() + self._sensors = [] + self.data = {} + # Initialize ModBus data structure before first read + self.data["accurrent"] = 1 + self.data["accurrenta"] = 1 + self.data["accurrentb"] = 1 + self.data["accurrentc"] = 1 + self.data["acvoltageab"] = 1 + self.data["acvoltagebc"] = 1 + self.data["acvoltageca"] = 1 + self.data["acvoltagean"] = 1 + self.data["acvoltagebn"] = 1 + self.data["acvoltagecn"] = 1 + self.data["acpower"] = 1 + self.data["acfreq"] = 1 + self.data["comm_options"] = 1 + self.data["comm_manufact"] = "" + self.data["comm_model"] = "" + self.data["comm_version"] = "" + self.data["comm_sernum"] = "" + self.data["mppt_nr"] = 1 + self.data["dccurr"] = 1 + self.data["dcvolt"] = 1 + self.data["dcpower"] = 1 + self.data["dc1curr"] = 1 + self.data["dc1volt"] = 1 + self.data["dc1power"] = 1 + self.data["dc2curr"] = 1 + self.data["dc2volt"] = 1 + self.data["dc2power"] = 1 + self.data["invtype"] = "" + self.data["status"] = "" + self.data["statusvendor"] = "" + self.data["totalenergy"] = 1 + self.data["tempcab"] = 1 + self.data["tempoth"] = 1 + + @property + def name(self): + """Return the device name.""" + return self._name + + @property + def host(self): + """Return the device name.""" + return self._host + + def check_port(self) -> bool: + """Check if port is available.""" + with self._lock: + sock_timeout = float(3) + _LOGGER.debug( + f"Check_Port: opening socket on {self._host}:{self._port} with a {sock_timeout}s timeout." + ) + socket.setdefaulttimeout(sock_timeout) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock_res = sock.connect_ex((self._host, self._port)) + is_open = sock_res == 0 # True if open, False if not + if is_open: + sock.shutdown(socket.SHUT_RDWR) + _LOGGER.debug( + f"Check_Port (SUCCESS): port open on {self._host}:{self._port}" + ) + else: + _LOGGER.debug( + f"Check_Port (ERROR): port not available on {self._host}:{self._port} - error: {sock_res}" + ) + sock.close() + return is_open + + def close(self): + """Disconnect client.""" + try: + if self._client.is_socket_open(): + _LOGGER.debug("Closing Modbus TCP connection") + with self._lock: + self._client.close() + return True + else: + _LOGGER.debug("Modbus TCP connection already closed") + except ConnectionException as connect_error: + _LOGGER.debug(f"Close Connection connect_error: {connect_error}") + raise ConnectionError() from connect_error + + def connect(self): + """Connect client.""" + _LOGGER.debug( + f"API Client connect to IP: {self._host} port: {self._port} slave id: {self._slave_id} timeout: {self._timeout}" + ) + if self.check_port(): + _LOGGER.debug("Inverter ready for Modbus TCP connection") + try: + with self._lock: + self._client.connect() + if not self._client.connected: + raise ConnectionError( + f"Failed to connect to {self._host}:{self._port} slave id {self._slave_id} timeout: {self._timeout}" + ) + else: + _LOGGER.debug("Modbus TCP Client connected") + return True + except ModbusException: + raise ConnectionError( + f"Failed to connect to {self._host}:{self._port} slave id {self._slave_id} timeout: {self._timeout}" + ) + else: + _LOGGER.debug("Inverter not ready for Modbus TCP connection") + raise ConnectionError(f"Inverter not active on {self._host}:{self._port}") + + def read_holding_registers(self, slave, address, count): + """Read holding registers.""" + kwargs = {"slave": slave} if slave else {} + try: + with self._lock: + return self._client.read_holding_registers(address, count, **kwargs) + except ConnectionException as connect_error: + _LOGGER.debug(f"Read Holding Registers connect_error: {connect_error}") + raise ConnectionError() from connect_error + except ModbusException as modbus_error: + _LOGGER.debug(f"Read Holding Registers modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + + def calculate_value(self, value, scalefactor): + """Apply Scale Factor.""" + return value * 10**scalefactor + + async def async_get_data(self): + """Read Data Function.""" + + try: + if self.connect(): + _LOGGER.debug( + "Start Get data (Slave ID: %s - Base Address: %s)", + self._slave_id, + self._base_addr, + ) + # HA way to call a sync function from async function + # https://developers.home-assistant.io/docs/asyncio_working_with_async?#calling-sync-functions-from-async + result = await self._hass.async_add_executor_job( + self.read_sunspec_modbus + ) + self.close() + _LOGGER.debug("End Get data") + if result: + _LOGGER.debug("Get Data Result: valid") + return True + else: + _LOGGER.debug("Get Data Result: invalid") + return False + else: + _LOGGER.debug("Get Data failed: client not connected") + return False + except ConnectionException as connect_error: + _LOGGER.debug(f"Async Get Data connect_error: {connect_error}") + raise ConnectionError() from connect_error + except ModbusException as modbus_error: + _LOGGER.debug(f"Async Get Data modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + + def read_sunspec_modbus(self): + """Read Modbus Data Function.""" + try: + self.read_sunspec_modbus_model_1() + self.read_sunspec_modbus_model_101_103() + self.read_sunspec_modbus_model_160() + result = True + _LOGGER.debug(f"read_sunspec_modbus: success {result}") + except Exception as modbus_error: + _LOGGER.debug(f"read_sunspec_modbus: failed with error: {modbus_error}") + result = False + raise ModbusError() from modbus_error + return result + + def read_sunspec_modbus_model_1(self): + """Read SunSpec Model 1 Data.""" + # A single register is 2 bytes. Max number of registers in one read for Modbus/TCP is 123 + # https://control.com/forums/threads/maximum-amount-of-holding-registers-per-request.9904/post-86251 + # + # So we have to do 2 read-cycles, one for M1 and the other for M103+M160 + # + # Start address 4 read 64 registers to read M1 (Common Inverter Info) in 1-pass + # Start address 72 read 92 registers to read (M101 or M103)+M160 (Realtime Power/Energy Data) in 1-pass + try: + read_model_1_data = self.read_holding_registers( + slave=self._slave_id, address=(self._base_addr + 4), count=64 + ) + _LOGGER.debug("(read_rt_1) Slave ID: %s", self._slave_id) + _LOGGER.debug("(read_rt_1) Base Address: %s", self._base_addr) + except ModbusException as modbus_error: + _LOGGER.debug(f"ReadM1 modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + + # No connection errors, we can start scraping registers + decoder = BinaryPayloadDecoder.fromRegisters( + read_model_1_data.registers, byteorder=Endian.BIG + ) + + # registers 4 to 43 + comm_manufact = str.strip(decoder.decode_string(size=32).decode("ascii")) + comm_model = str.strip(decoder.decode_string(size=32).decode("ascii")) + comm_options = str.strip(decoder.decode_string(size=16).decode("ascii")) + self.data["comm_manufact"] = comm_manufact.rstrip(" \t\r\n\0\u0000") + self.data["comm_model"] = comm_model.rstrip(" \t\r\n\0\u0000") + self.data["comm_options"] = comm_options.rstrip(" \t\r\n\0\u0000") + _LOGGER.debug("(read_rt_1) Manufacturer: %s", self.data["comm_manufact"]) + _LOGGER.debug("(read_rt_1) Model: %s", self.data["comm_model"]) + _LOGGER.debug("(read_rt_1) Options: %s", self.data["comm_options"]) + + # Model based on options register, if unknown, raise an error to report it + # First char is the model: if non-printable char, hex string of the char is provided + # So we need to check if it's a char or an hex value string and convert both to a number + # Then we lookup in the model table, if it's there, good, otherwise we provide the given model + # test also with opt_model = '0x0DED/0xFFFF' + opt_model = self.data["comm_options"] + if opt_model.startswith("0x"): + opt_model_int = int(opt_model[0:4], 16) + _LOGGER.debug( + "(opt_notprintable) opt_model: %s - opt_model_int: %s", + opt_model, + opt_model_int, + ) + else: + opt_model_int = ord(opt_model[0]) + _LOGGER.debug( + "(opt_printable) opt_model: %s - opt_model_int: %s", + opt_model, + opt_model_int, + ) + if opt_model_int in DEVICE_MODEL: + self.data["comm_model"] = DEVICE_MODEL[opt_model_int] + _LOGGER.debug("(opt_comm_model) comm_model: %s", self.data["comm_model"]) + else: + _LOGGER.error( + "(opt_comm_model) Model unknown, report to @alexdelprete on the forum the following data: Manuf.: %s - Model: %s - Options: %s - OptModel: %s - OptModelInt: %s", + self.data["comm_manufact"], + self.data["comm_model"], + self.data["comm_options"], + opt_model, + opt_model_int, + ) + + # registers 44 to 67 + comm_version = str.strip(decoder.decode_string(size=16).decode("ascii")) + comm_sernum = str.strip(decoder.decode_string(size=32).decode("ascii")) + self.data["comm_version"] = comm_version.rstrip(" \t\r\n\0\u0000") + self.data["comm_sernum"] = comm_sernum.rstrip(" \t\r\n\0\u0000") + _LOGGER.debug("(read_rt_1) Version: %s", self.data["comm_version"]) + _LOGGER.debug("(read_rt_1) Sernum: %s", self.data["comm_sernum"]) + + return True + + def read_sunspec_modbus_model_101_103(self): + """Read SunSpec Model 101/103 Data.""" + # Max number of registers in one read for Modbus/TCP is 123 + # (ref.: https://control.com/forums/threads/maximum-amount-of-holding-registers-per-request.9904/post-86251) + # + # So we could do 2 sweeps, one for M1 and the other for M103+M160. Since some old inverters have problems + # with large sweeps, we'll split it in 3 sweeps: + # - Sweep 1 (M1): Start address 4 read 64 registers to read M1 (Common Inverter Info) + # - Sweep 2 (M103): Start address 70 read 40 registers to read M103+M160 (Realtime Power/Energy Data) + # - Sweep 3 (M160): Start address 124 read 40 registers to read M1 (Common Inverter Info) + try: + read_model_101_103_data = self.read_holding_registers( + slave=self._slave_id, address=(self._base_addr + 70), count=40 + ) + _LOGGER.debug("(read_rt_101_103) Slave ID: %s", self._slave_id) + _LOGGER.debug("(read_rt_101_103) Base Address: %s", self._base_addr) + except ModbusException as modbus_error: + _LOGGER.debug(f"Read M101/M103 modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + + # No connection errors, we can start scraping registers + decoder = BinaryPayloadDecoder.fromRegisters( + read_model_101_103_data.registers, byteorder=Endian.BIG + ) + + # register 70 + invtype = decoder.decode_16bit_uint() + _LOGGER.debug("(read_rt_101_103) Inverter Type (int): %s", invtype) + _LOGGER.debug( + "(read_rt_101_103) Inverter Type (str): %s", INVERTER_TYPE[invtype] + ) + # make sure the value is in the known status list + if invtype not in INVERTER_TYPE: + invtype = 999 + _LOGGER.debug("(read_rt_101_103) Inverter Type Unknown (int): %s", invtype) + _LOGGER.debug( + "(read_rt_101_103) Inverter Type Unknown (str): %s", + INVERTER_TYPE[invtype], + ) + self.data["invtype"] = INVERTER_TYPE[invtype] + + # skip register 71 + decoder.skip_bytes(2) + + # registers 72 to 76 + accurrent = decoder.decode_16bit_uint() + + if invtype == 103: + accurrenta = decoder.decode_16bit_uint() + accurrentb = decoder.decode_16bit_uint() + accurrentc = decoder.decode_16bit_uint() + else: + decoder.skip_bytes(6) + + accurrentsf = decoder.decode_16bit_int() + accurrent = self.calculate_value(accurrent, accurrentsf) + self.data["accurrent"] = round(accurrent, abs(accurrentsf)) + + if invtype == 103: + accurrenta = self.calculate_value(accurrenta, accurrentsf) + accurrentb = self.calculate_value(accurrentb, accurrentsf) + accurrentc = self.calculate_value(accurrentc, accurrentsf) + self.data["accurrenta"] = round(accurrenta, abs(accurrentsf)) + self.data["accurrentb"] = round(accurrentb, abs(accurrentsf)) + self.data["accurrentc"] = round(accurrentc, abs(accurrentsf)) + + # registers 77 to 83 + if invtype == 103: + acvoltageab = decoder.decode_16bit_uint() + acvoltagebc = decoder.decode_16bit_uint() + acvoltageca = decoder.decode_16bit_uint() + else: + decoder.skip_bytes(6) + + acvoltagean = decoder.decode_16bit_uint() + + if invtype == 103: + acvoltagebn = decoder.decode_16bit_uint() + acvoltagecn = decoder.decode_16bit_uint() + else: + decoder.skip_bytes(4) + + acvoltagesf = decoder.decode_16bit_int() + + acvoltagean = self.calculate_value(acvoltagean, acvoltagesf) + self.data["acvoltagean"] = round(acvoltagean, abs(acvoltagesf)) + + if invtype == 103: + acvoltageab = self.calculate_value(acvoltageab, acvoltagesf) + acvoltagebc = self.calculate_value(acvoltagebc, acvoltagesf) + acvoltageca = self.calculate_value(acvoltageca, acvoltagesf) + acvoltagebn = self.calculate_value(acvoltagebn, acvoltagesf) + acvoltagecn = self.calculate_value(acvoltagecn, acvoltagesf) + self.data["acvoltageab"] = round(acvoltageab, abs(acvoltagesf)) + self.data["acvoltagebc"] = round(acvoltagebc, abs(acvoltagesf)) + self.data["acvoltageca"] = round(acvoltageca, abs(acvoltagesf)) + self.data["acvoltagebn"] = round(acvoltagebn, abs(acvoltagesf)) + self.data["acvoltagecn"] = round(acvoltagecn, abs(acvoltagesf)) + + # registers 84 to 85 + acpower = decoder.decode_16bit_int() + acpowersf = decoder.decode_16bit_int() + acpower = self.calculate_value(acpower, acpowersf) + self.data["acpower"] = round(acpower, abs(acpowersf)) + + # registers 86 to 87 + acfreq = decoder.decode_16bit_uint() + acfreqsf = decoder.decode_16bit_int() + acfreq = self.calculate_value(acfreq, acfreqsf) + self.data["acfreq"] = round(acfreq, abs(acfreqsf)) + + # skip register 88-93 + decoder.skip_bytes(12) + + # registers 94 to 96 + totalenergy = decoder.decode_32bit_uint() + totalenergysf = decoder.decode_16bit_uint() + totalenergy = self.calculate_value(totalenergy, totalenergysf) + # ensure that totalenergy is always an increasing value (total_increasing) + _LOGGER.debug("(read_rt_101_103) Total Energy Value Read: %s", totalenergy) + _LOGGER.debug( + "(read_rt_101_103) Total Energy Previous Value: %s", + self.data["totalenergy"], + ) + if totalenergy < self.data["totalenergy"]: + _LOGGER.error( + "(read_rt_101_103) Total Energy less than previous value! Value Read: %s - Previous Value: %s", + totalenergy, + self.data["totalenergy"], + ) + else: + self.data["totalenergy"] = totalenergy + + # registers 97 to 100 (for monophase inverters) + if invtype == 101: + dccurr = decoder.decode_16bit_int() + dccurrsf = decoder.decode_16bit_int() + dcvolt = decoder.decode_16bit_int() + dcvoltsf = decoder.decode_16bit_int() + dccurr = self.calculate_value(dccurr, dccurrsf) + dcvolt = self.calculate_value(dcvolt, dcvoltsf) + self.data["dccurr"] = round(dccurr, abs(dccurrsf)) + self.data["dcvolt"] = round(dcvolt, abs(dcvoltsf)) + _LOGGER.debug( + "(read_rt_101_103) DC Current Value read: %s", self.data["dccurr"] + ) + _LOGGER.debug( + "(read_rt_101_103) DC Voltage Value read: %s", self.data["dcvolt"] + ) + else: + decoder.skip_bytes(8) + + # registers 101 to 102 + dcpower = decoder.decode_16bit_int() + dcpowersf = decoder.decode_16bit_int() + dcpower = self.calculate_value(dcpower, dcpowersf) + self.data["dcpower"] = round(dcpower, abs(dcpowersf)) + _LOGGER.debug("(read_rt_101_103) DC Power Value read: %s", self.data["dcpower"]) + # register 103 + tempcab = decoder.decode_16bit_int() + # skip registers 104-105 + decoder.skip_bytes(4) + # register 106 to 107 + tempoth = decoder.decode_16bit_int() + tempsf = decoder.decode_16bit_int() + # Fix for tempcab: in some inverters SF must be -2 not -1 as per specs + tempcab_fix = tempcab + tempcab = self.calculate_value(tempcab, tempsf) + if tempcab > 50: + tempcab = self.calculate_value(tempcab_fix, -2) + tempoth = self.calculate_value(tempoth, tempsf) + self.data["tempoth"] = round(tempoth, abs(tempsf)) + self.data["tempcab"] = round(tempcab, abs(tempsf)) + _LOGGER.debug("(read_rt_101_103) Temp Oth Value read: %s", self.data["tempoth"]) + _LOGGER.debug("(read_rt_101_103) Temp Cab Value read: %s", self.data["tempcab"]) + # register 108 + status = decoder.decode_16bit_int() + # make sure the value is in the known status list + if status not in DEVICE_STATUS: + _LOGGER.debug("Unknown Operating State: %s", status) + status = 999 + self.data["status"] = DEVICE_STATUS[status] + _LOGGER.debug( + "(read_rt_101_103) Device Status Value read: %s", self.data["status"] + ) + + # register 109 + statusvendor = decoder.decode_16bit_int() + # make sure the value is in the known status list + if statusvendor not in DEVICE_GLOBAL_STATUS: + _LOGGER.debug( + "(read_rt_101_103) Unknown Vendor Operating State: %s", statusvendor + ) + statusvendor = 999 + self.data["statusvendor"] = DEVICE_GLOBAL_STATUS[statusvendor] + _LOGGER.debug( + "(read_rt_101_103) Status Vendor Value read: %s", self.data["statusvendor"] + ) + _LOGGER.debug("(read_rt_101_103) Completed") + return True + + def read_sunspec_modbus_model_160(self): + """Read SunSpec Model 160 Data.""" + # Max number of registers in one read for Modbus/TCP is 123 + # https://control.com/forums/threads/maximum-amount-of-holding-registers-per-request.9904/post-86251 + # + # So we have to do 2 read-cycles, one for M1 and the other for M103+M160 + # + # Start address 4 read 64 registers to read M1 (Common Inverter Info) in 1-pass + # Start address 70 read 94 registers to read M103+M160 (Realtime Power/Energy Data) in 1-pass + try: + read_model_160_data = self.read_holding_registers( + slave=self._slave_id, address=(self._base_addr + 122), count=42 + ) + _LOGGER.debug("(read_rt_160) Slave ID: %s", self._slave_id) + _LOGGER.debug("(read_rt_160) Base Address: %s", self._base_addr) + except ModbusException as modbus_error: + _LOGGER.debug(f"Read M160 modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + + # No connection errors, we can start scraping registers + decoder = BinaryPayloadDecoder.fromRegisters( + read_model_160_data.registers, byteorder=Endian.BIG + ) + + # register 122 + multi_mppt_id = decoder.decode_16bit_int() + + # Model 160 has different offset for UNO-DM-PLUS and REACT2 inverters + # need to check and try the specific offset address (start address is 41104) + if multi_mppt_id != 160: + _LOGGER.debug( + "(read_rt_160) Model not 160 try another offset - multi_mppt_id: %s", + multi_mppt_id, + ) + try: + # try address 41104 for UNO-DM-PLUS and REACT2 + read_model_160_data = self.read_holding_registers( + slave=self._slave_id, address=(self._base_addr + 1104), count=42 + ) + _LOGGER.debug("(read_rt_160) Slave ID: %s", self._slave_id) + _LOGGER.debug("(read_rt_160) Base Address: %s", self._base_addr) + except ModbusException as modbus_error: + _LOGGER.debug(f"Read M160 modbus_error: {modbus_error}") + raise ModbusError() from modbus_error + # No connection errors, we can start scraping registers + decoder = BinaryPayloadDecoder.fromRegisters( + read_model_160_data.registers, byteorder=Endian.BIG + ) + + # register 122 + multi_mppt_id = decoder.decode_16bit_int() + + if multi_mppt_id != 160: + _LOGGER.debug( + "(read_rt_160) Model not 160 (UNO-DM/REACT2) - multi_mppt_id: %s", + multi_mppt_id, + ) + return False + else: + _LOGGER.debug( + "(read_rt_160) Model is 160 (UNO-DM/REACT2) - multi_mppt_id: %s", + multi_mppt_id, + ) + else: + _LOGGER.debug( + "(read_rt_160) Model is 160 - multi_mppt_id: %s", multi_mppt_id + ) + + # skip register 123 + decoder.skip_bytes(2) + + # registers 124 to 126 + dcasf = decoder.decode_16bit_int() + dcvsf = decoder.decode_16bit_int() + dcwsf = decoder.decode_16bit_int() + + # skip register 127 to 129 + decoder.skip_bytes(6) + + # register 130 (# of DC modules) + multi_mppt_nr = decoder.decode_16bit_int() + self.data["mppt_nr"] = multi_mppt_nr + _LOGGER.debug("(read_rt_160) mppt_nr %s", multi_mppt_nr) + + # if we have at least one DC module + if multi_mppt_nr >= 1: + # skip register 131 to 140 + decoder.skip_bytes(20) + + # registers 141 to 143 + dc1curr = decoder.decode_16bit_uint() + dc1volt = decoder.decode_16bit_uint() + dc1power = decoder.decode_16bit_uint() + dc1curr = self.calculate_value(dc1curr, dcasf) + self.data["dc1curr"] = round(dc1curr, abs(dcasf)) + dc1volt = self.calculate_value(dc1volt, dcvsf) + self.data["dc1volt"] = round(dc1volt, abs(dcvsf)) + # this fixes dcvolt -0.0 for UNO-DM/REACT2 models + self.data["dcvolt"] = round(dc1volt, abs(dcvsf)) + dc1power = self.calculate_value(dc1power, dcwsf) + self.data["dc1power"] = round(dc1power, abs(dcwsf)) + _LOGGER.debug( + "(read_rt_160) dc1curr: %s Round: %s SF: %s", + dc1curr, + self.data["dc1curr"], + dcasf, + ) + _LOGGER.debug("(read_rt_160) dc1volt %s", self.data["dc1volt"]) + _LOGGER.debug("(read_rt_160) dc1power %s", self.data["dc1power"]) + + # if we have more than one DC module + if multi_mppt_nr > 1: + # skip register 144 to 160 + decoder.skip_bytes(34) + + # registers 161 to 163 + dc2curr = decoder.decode_16bit_uint() + dc2volt = decoder.decode_16bit_uint() + dc2power = decoder.decode_16bit_uint() + dc2curr = self.calculate_value(dc2curr, dcasf) + self.data["dc2curr"] = round(dc2curr, abs(dcasf)) + dc2volt = self.calculate_value(dc2volt, dcvsf) + self.data["dc2volt"] = round(dc2volt, abs(dcvsf)) + dc2power = self.calculate_value(dc2power, dcwsf) + self.data["dc2power"] = round(dc2power, abs(dcwsf)) + _LOGGER.debug( + "(read_rt_160) dc2curr: %s Round: %s SF: %s", + dc2curr, + self.data["dc2curr"], + dcasf, + ) + _LOGGER.debug("(read_rt_160) dc2volt %s", self.data["dc2volt"]) + _LOGGER.debug("(read_rt_160) dc2power %s", self.data["dc2power"]) + + _LOGGER.debug("(read_rt_160) Completed") + return True diff --git a/custom_components/sinapsi_alfa/config_flow.py b/custom_components/sinapsi_alfa/config_flow.py new file mode 100644 index 0000000..23ae319 --- /dev/null +++ b/custom_components/sinapsi_alfa/config_flow.py @@ -0,0 +1,228 @@ +"""Config Flow for ABB Power-One PVI SunSpec. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +import ipaddress +import logging +import re + +import voluptuous as vol +from homeassistant import config_entries +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.selector import selector +from pymodbus.exceptions import ConnectionException + +from .api import ABBPowerOneFimerAPI +from .const import ( + CONF_BASE_ADDR, + CONF_HOST, + CONF_NAME, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_SLAVE_ID, + DEFAULT_BASE_ADDR, + DEFAULT_NAME, + DEFAULT_PORT, + DEFAULT_SCAN_INTERVAL, + DEFAULT_SLAVE_ID, + DOMAIN, +) + +_LOGGER = logging.getLogger(__name__) + + +def host_valid(host): + """Return True if hostname or IP address is valid.""" + try: + if ipaddress.ip_address(host).version == (4 or 6): + return True + except ValueError: + disallowed = re.compile(r"[^a-zA-Z\d\-]") + return all(x and not disallowed.search(x) for x in host.split(".")) + + +@callback +def get_host_from_config(hass: HomeAssistant): + """Return the hosts already configured.""" + return { + config_entry.data.get(CONF_HOST) + for config_entry in hass.config_entries.async_entries(DOMAIN) + } + + +class ABBPowerOneFimerConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """ABB Power-One PVI SunSpec config flow.""" + + VERSION = 1 + CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL + + @staticmethod + @callback + def async_get_options_flow(config_entry: ConfigEntry): + """Initiate Options Flow Instance.""" + return ABBPowerOneFimerOptionsFlow(config_entry) + + def _host_in_configuration_exists(self, host) -> bool: + """Return True if host exists in configuration.""" + if host in get_host_from_config(self.hass): + return True + return False + + async def test_connection( + self, name, host, port, slave_id, base_addr, scan_interval + ): + """Return true if credentials is valid.""" + _LOGGER.debug(f"Test connection to {host}:{port} slave id {slave_id}") + try: + _LOGGER.debug("Creating API Client") + self.api = ABBPowerOneFimerAPI( + self.hass, name, host, port, slave_id, base_addr, scan_interval + ) + _LOGGER.debug("API Client created: calling get data") + self.api_data = await self.api.async_get_data() + _LOGGER.debug("API Client: get data") + _LOGGER.debug(f"API Client Data: {self.api_data}") + return self.api.data["comm_sernum"] + except ConnectionException as connerr: + _LOGGER.error( + f"Failed to connect to host: {host}:{port} - slave id: {slave_id} - Exception: {connerr}" + ) + return False + + async def async_step_user(self, user_input=None): + """Handle the initial step.""" + errors = {} + + if user_input is not None: + name = user_input[CONF_NAME] + host = user_input[CONF_HOST] + port = user_input[CONF_PORT] + slave_id = user_input[CONF_SLAVE_ID] + base_addr = user_input[CONF_BASE_ADDR] + scan_interval = user_input[CONF_SCAN_INTERVAL] + + if self._host_in_configuration_exists(host): + errors[CONF_HOST] = "Device Already Configured" + elif not host_valid(user_input[CONF_HOST]): + errors[CONF_HOST] = "invalid Host IP" + else: + uid = await self.test_connection( + name, host, port, slave_id, base_addr, scan_interval + ) + if uid is not False: + _LOGGER.debug(f"Device unique id: {uid}") + await self.async_set_unique_id(uid) + self._abort_if_unique_id_configured() + return self.async_create_entry( + title=user_input[CONF_NAME], data=user_input + ) + else: + errors[ + CONF_HOST + ] = "Connection to device failed (S/N not retreived)" + + return self.async_show_form( + step_id="user", + data_schema=vol.Schema( + { + vol.Required( + CONF_NAME, + default=DEFAULT_NAME, + ): cv.string, + vol.Required( + CONF_HOST, + ): cv.string, + vol.Required( + CONF_PORT, + default=DEFAULT_PORT, + ): vol.Coerce(int), + vol.Required( + CONF_SLAVE_ID, + default=DEFAULT_SLAVE_ID, + ): vol.Coerce(int), + vol.Required( + CONF_BASE_ADDR, + default=DEFAULT_BASE_ADDR, + ): vol.Coerce(int), + vol.Required( + CONF_SCAN_INTERVAL, + default=DEFAULT_SCAN_INTERVAL, + ): selector( + { + "number": { + "min": 30, + "max": 600, + "step": 10, + "unit_of_measurement": "s", + "mode": "slider", + } + } + ), + }, + ), + errors=errors, + ) + + +class ABBPowerOneFimerOptionsFlow(config_entries.OptionsFlow): + """Config flow options handler.""" + + VERSION = 1 + + def __init__(self, config_entry: ConfigEntry) -> None: + """Initialize option flow instance.""" + self.config_entry = config_entry + self.data_schema = vol.Schema( + { + vol.Required( + CONF_PORT, + default=self.config_entry.data.get(CONF_PORT), + ): vol.Coerce(int), + vol.Required( + CONF_SLAVE_ID, + default=self.config_entry.data.get(CONF_SLAVE_ID), + ): vol.Coerce(int), + vol.Required( + CONF_BASE_ADDR, + default=self.config_entry.data.get(CONF_BASE_ADDR), + ): vol.Coerce(int), + vol.Required( + CONF_SCAN_INTERVAL, + default=self.config_entry.data.get(CONF_SCAN_INTERVAL), + ): selector( + { + "number": { + "min": 30, + "max": 600, + "step": 10, + "unit_of_measurement": "s", + "mode": "slider", + } + } + ), + } + ) + + async def async_step_init(self, user_input=None): + """Manage the options.""" + + if user_input is not None: + # complete non-edited entries before update (ht @PeteRage) + if CONF_NAME in self.config_entry.data: + user_input[CONF_NAME] = self.config_entry.data.get(CONF_NAME) + if CONF_HOST in self.config_entry.data: + user_input[CONF_HOST] = self.config_entry.data.get(CONF_HOST) + + # write updated config entries (ht @PeteRage / @fuatakgun) + self.hass.config_entries.async_update_entry( + self.config_entry, data=user_input, options=self.config_entry.options + ) + self.async_abort(reason="configuration updated") + + # write empty options entries (ht @PeteRage / @fuatakgun) + return self.async_create_entry(title="", data={}) + + return self.async_show_form(step_id="init", data_schema=self.data_schema) diff --git a/custom_components/sinapsi_alfa/const.py b/custom_components/sinapsi_alfa/const.py new file mode 100644 index 0000000..735fc28 --- /dev/null +++ b/custom_components/sinapsi_alfa/const.py @@ -0,0 +1,480 @@ +"""Constants for ABB Power-One PVI SunSpec. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass +from homeassistant.const import ( + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfPower, + UnitOfTemperature, +) + +# Base component constants +NAME = "ABB/Power-One/FIMER PVI SunSpec ModBus TCP" +DOMAIN = "abb_powerone_pvi_sunspec" +DOMAIN_DATA = f"{DOMAIN}_data" +VERSION = "3.0.0" +ATTRIBUTION = "by @alexdelprete" +ISSUE_URL = "https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec/issues" + +# Icons +ICON = "mdi:format-quote-close" + +# Device classes +BINARY_SENSOR_DEVICE_CLASS = "connectivity" + +# Platforms +SENSOR = "sensor" +PLATFORMS = [ + "sensor", +] +UPDATE_LISTENER = "update_listener" +DATA = "data" + +# Configuration and options +CONF_NAME = "name" +CONF_HOST = "host" +CONF_PORT = "port" +CONF_SLAVE_ID = "slave_id" +CONF_BASE_ADDR = "base_addr" +CONF_SCAN_INTERVAL = "scan_interval" +DEFAULT_NAME = "ABB Inverter" +DEFAULT_PORT = 502 +DEFAULT_SLAVE_ID = 2 +DEFAULT_BASE_ADDR = 0 +DEFAULT_SCAN_INTERVAL = 60 +MIN_SCAN_INTERVAL = 30 +STARTUP_MESSAGE = f""" +------------------------------------------------------------------- +{NAME} +Version: {VERSION} +{ATTRIBUTION} +This is a custom integration! +If you have any issues with this you need to open an issue here: +{ISSUE_URL} +------------------------------------------------------------------- +""" + +# Sensors for all inverters +SENSOR_TYPES_COMMON = { + "Manufacturer": [ + "Manufacturer", + "comm_manufact", + None, + "mdi:information-outline", + None, + None, + ], + "Model": ["Model", "comm_model", None, "mdi:information-outline", None, None], + "Options": ["Options", "comm_options", None, "mdi:information-outline", None, None], + "Version": [ + "Firmware Version", + "comm_version", + None, + "mdi:information-outline", + None, + None, + ], + "Serial": ["Serial", "comm_sernum", None, "mdi:information-outline", None, None], + "Inverter_Type": [ + "Inverter Type", + "invtype", + None, + "mdi:information-outline", + None, + None, + ], + "AC_Current": [ + "AC Current", + "accurrent", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageAN": [ + "AC Voltage AN", + "acvoltagean", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "AC_Power": [ + "AC Power", + "acpower", + UnitOfPower.WATT, + "mdi:solar-power", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + ], + "AC_Frequency": [ + "AC Frequency", + "acfreq", + UnitOfFrequency.HERTZ, + "mdi:sine-wave", + SensorDeviceClass.FREQUENCY, + SensorStateClass.MEASUREMENT, + ], + "DC_Power": [ + "DC Power", + "dcpower", + UnitOfPower.WATT, + "mdi:solar-power", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + ], + "Total_Energy": [ + "Total Energy", + "totalenergy", + UnitOfEnergy.WATT_HOUR, + "mdi:solar-power", + SensorDeviceClass.ENERGY, + SensorStateClass.TOTAL_INCREASING, + ], + "Status": [ + "Operating State", + "status", + None, + "mdi:information-outline", + None, + None, + ], + "Status_Vendor": [ + "Vendor Operating State", + "statusvendor", + None, + "mdi:information-outline", + None, + None, + ], + "Temp_Cab": [ + "Ambient Temperature", + "tempcab", + UnitOfTemperature.CELSIUS, + "mdi:temperature-celsius", + SensorDeviceClass.TEMPERATURE, + SensorStateClass.MEASUREMENT, + ], + "Temp_Oth": [ + "Inverter Temperature", + "tempoth", + UnitOfTemperature.CELSIUS, + "mdi:temperature-celsius", + SensorDeviceClass.TEMPERATURE, + SensorStateClass.MEASUREMENT, + ], + "MPPT_Count": [ + "MPPT Count", + "mppt_nr", + None, + "mdi:information-outline", + None, + None, + ], +} + +# Sensors for single phase inverters, apparently does not have any specific sensors +SENSOR_TYPES_SINGLE_PHASE = {} + +# Sensors for three phase inverters +SENSOR_TYPES_THREE_PHASE = { + "AC_CurrentA": [ + "AC Current A", + "accurrenta", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "AC_CurrentB": [ + "AC Current B", + "accurrentb", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "AC_CurrentC": [ + "AC Current C", + "accurrentc", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageAB": [ + "AC Voltage AB", + "acvoltageab", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageBC": [ + "AC Voltage BC", + "acvoltagebc", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageCA": [ + "AC Voltage CA", + "acvoltageca", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageBN": [ + "AC Voltage BN", + "acvoltagebn", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "AC_VoltageCN": [ + "AC Voltage CN", + "acvoltagecn", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], +} + +# Sensors for single mppt inverters +SENSOR_TYPES_SINGLE_MPPT = { + "DC_Curr": [ + "DC Current", + "dccurr", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "DC_Volt": [ + "DC Voltage", + "dcvolt", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], +} + +# Sensors for single dual inverters +SENSOR_TYPES_DUAL_MPPT = { + "DC1_Curr": [ + "DC1 Current", + "dc1curr", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "DC1_Volt": [ + "DC1 Voltage", + "dc1volt", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "DC1_Power": [ + "DC1 Power", + "dc1power", + UnitOfPower.WATT, + "mdi:solar-power", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + ], + "DC2_Curr": [ + "DC2 Current", + "dc2curr", + UnitOfElectricCurrent.AMPERE, + "mdi:current-ac", + SensorDeviceClass.CURRENT, + SensorStateClass.MEASUREMENT, + ], + "DC2_Volt": [ + "DC2 Voltage", + "dc2volt", + UnitOfElectricPotential.VOLT, + "mdi:lightning-bolt", + SensorDeviceClass.VOLTAGE, + SensorStateClass.MEASUREMENT, + ], + "DC2_Power": [ + "DC2 Power", + "dc2power", + UnitOfPower.WATT, + "mdi:solar-power", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + ], +} + +INVERTER_TYPE = {101: "Single Phase", 103: "Three Phase", 999: "Unknown"} + +DEVICE_GLOBAL_STATUS = { + 0: "Sending Parameters", + 1: "Wait Sun/Grid", + 2: "Checking Grid", + 3: "Measuring Riso", + 4: "DcDc Start", + 5: "Inverter Start", + 6: "Run", + 7: "Recovery", + 8: "Pause", + 9: "Ground Fault", + 10: "OTH Fault", + 11: "Address Setting", + 12: "Self Test", + 13: "Self Test Fail", + 14: "Sensor Test + Measure Riso", + 15: "Leak Fault", + 16: "Waiting for manual reset", + 17: "Internal Error E026", + 18: "Internal Error E027", + 19: "Internal Error E028", + 20: "Internal Error E029", + 21: "Internal Error E030", + 22: "Sending Wind Table", + 23: "Failed Sending table", + 24: "UTH Fault", + 25: "Remote OFF", + 26: "Interlock Fail", + 27: "Executing Autotest", + 30: "Waiting Sun", + 31: "Temperature Fault", + 32: "Fan Staucked", + 33: "Int. Com. Fault", + 34: "Slave Insertion", + 35: "DC Switch Open", + 36: "TRAS Switch Open", + 37: "MASTER Exclusion", + 38: "Auto Exclusion", + 98: "Erasing Internal EEprom", + 99: "Erasing External EEprom", + 100: "Counting EEprom", + 101: "Freeze", + 116: "Standby", + 200: "Dsp Programming", + 999: "Unknown", +} + +DEVICE_STATUS = { + 0: "Stand By", + 1: "Checking Grid", + 2: "Run", + 3: "Bulk OV", + 4: "Out OC", + 5: "IGBT Sat", + 6: "Bulk UV", + 7: "Degauss Error", + 8: "No Parameters", + 9: "Bulk Low", + 10: "Grid OV", + 11: "Communication Error", + 12: "Degaussing", + 13: "Starting", + 14: "Bulk Cap Fail", + 15: "Leak Fail", + 16: "DcDc Fail", + 17: "Ileak Sensor Fail", + 18: "SelfTest: relay inverter", + 19: "SelfTest: wait for sensor test", + 20: "SelfTest: test relay DcDc + sensor", + 21: "SelfTest: relay inverter fail", + 22: "SelfTest timeout fail", + 23: "SelfTest: relay DcDc fail", + 24: "Self Test 1", + 25: "Waiting self test start", + 26: "Dc Injection", + 27: "Self Test 2", + 28: "Self Test 3", + 29: "Self Test 4", + 30: "Internal Error", + 31: "Internal Error", + 40: "Forbidden State", + 41: "Input UC", + 42: "Zero Power", + 43: "Grid Not Present", + 44: "Waiting Start", + 45: "MPPT", + 46: "Grid Fail", + 47: "Input OC", + 255: "Inverter Dsp not programmed", + 999: "Unkown", +} + +DEVICE_MODEL = { + 0: "UNO-DM-3.3-TL-PLUS", + 1: "UNO-DM-4.0-TL-PLUS", + 3: "UNO-DM-4.6-TL-PLUS", + 4: "UNO-DM-5.0-TL-PLUS", + 5: "UNO-DM-6.0-TL-PLUS", + 11: "UNO-DM-2.0-TL-PLUS", + 12: "UNO-DM-3.0-TL-PLUS", + 13: "REACT2-UNO-5.0-TL", + 14: "REACT2-UNO-3.6-TL", + 15: "UNO-DM-5.0-TL-PLUS", + 16: "UNO-DM-6.0-TL-PLUS", + 19: "REACT2-5.0-TL", + 49: "PVI-3.0-OUTD", + 50: "PVI-3.3-OUTD", + 51: "PVI-3.6-OUTD", + 52: "PVI-4.2-OUTD", + 53: "PVI-5000-OUTD", + 54: "PVI-6000-OUTD", + 65: "PVI-CENTRAL-350", + 66: "PVI-CENTRAL-350", + 67: "PVI-CENTRAL-50", + 68: "PVI-12.5-OUTD", + 69: "PVI-CENTRAL-67", + 70: "TRIO-27.6-TL-OUTD", + 71: "UNO-2.5-OUTD", + 72: "PVI-4.6-OUTD-I", + 74: "PVI-1700-OUTD", + 76: "PVI-CENTRAL-350", + 77: "PVI-CENTRAL-250", + 78: "PVI-12.5-OUTD", + 79: "PVI-3600-OUTD", + 80: "3-phase interface (3G74)", + 81: "PVI-8.0-OUTD-PLUS", + 82: "TRIO-8.5-TL-OUTD-S", + 83: "PVS-12.5-TL", + 84: "PVI-12.5-OUTD-I", + 85: "PVI-12.5-OUTD-I", + 86: "PVI-12.5-OUTD-I", + 88: "PVI-10.0-OUTD", + 89: "TRIO-27.6-TL-OUTD", + 90: "PVI-12.5-OUTD-I", + 99: "CDD", + 102: "TRIO-20-TL-OUTD", + 103: "UNO-2.0-OUTD", + 104: "PVI-3.8-OUTD-I", + 105: "PVI-2000-IND", + 106: "PVI-1700-IND", + 107: "TRIO-7.5-OUTD", + 108: "PVI-3600-IND", + 110: "PVI-10.0-OUTD", + 111: "PVI-2000-OUTD", + 113: "PVI-8.0-OUTD", + 114: "TRIO-5.8-OUTD", + 116: "PVI-10.0-OUTD-I", + 117: "PVI-10.0-OUTD-I", + 118: "PVI-10.0-OUTD-I", + 119: "PVI-10.0-I-OUTD", + 121: "TRIO-20-TL-OUTD", + 122: "PVI-10.0-OUTD-I", + 224: "UNO-2.0-TL-OUTD", + 242: "UNO-3.0-TL-OUTD", +} diff --git a/custom_components/sinapsi_alfa/coordinator.py b/custom_components/sinapsi_alfa/coordinator.py new file mode 100644 index 0000000..f5e5d8b --- /dev/null +++ b/custom_components/sinapsi_alfa/coordinator.py @@ -0,0 +1,94 @@ +"""Data Update Coordinator for ABB Power-One PVI SunSpec. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +import logging +from datetime import datetime, timedelta + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .api import ABBPowerOneFimerAPI +from .const import ( + CONF_BASE_ADDR, + CONF_HOST, + CONF_NAME, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_SLAVE_ID, + DEFAULT_SCAN_INTERVAL, + DOMAIN, + MIN_SCAN_INTERVAL, +) + +_LOGGER = logging.getLogger(__name__) + + +class ABBPowerOneFimerCoordinator(DataUpdateCoordinator): + """Class to manage fetching data from the API.""" + + config_entry: ConfigEntry + + def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: + """Initialize data update coordinator.""" + + # get scan_interval from user config + self.scan_interval = config_entry.data.get( + CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL + ) + # enforce scan_interval lower bound + if self.scan_interval < MIN_SCAN_INTERVAL: + self.scan_interval = MIN_SCAN_INTERVAL + # set coordinator update interval + self.update_interval = timedelta(seconds=self.scan_interval) + _LOGGER.debug( + f"Scan Interval: scan_interval={self.scan_interval} update_interval={self.update_interval}" + ) + + # set update method and interval for coordinator + super().__init__( + hass, + _LOGGER, + name=f"{DOMAIN} ({config_entry.unique_id})", + update_method=self.async_update_data, + update_interval=self.update_interval, + ) + + self.last_update_time = datetime.now() + self.last_update_success = True + + self.api = ABBPowerOneFimerAPI( + hass, + config_entry.data.get(CONF_NAME), + config_entry.data.get(CONF_HOST), + config_entry.data.get(CONF_PORT), + config_entry.data.get(CONF_SLAVE_ID), + config_entry.data.get(CONF_BASE_ADDR), + self.scan_interval, + ) + + _LOGGER.debug("Coordinator Config Data: %s", config_entry.data) + _LOGGER.debug( + "Coordinator API init: Host: %s Port: %s ID: %s ScanInterval: %s", + config_entry.data.get(CONF_HOST), + config_entry.data.get(CONF_PORT), + config_entry.data.get(CONF_SLAVE_ID), + self.scan_interval, + ) + + async def async_update_data(self): + """Update data method.""" + _LOGGER.debug(f"Data Coordinator: Update started at {datetime.now()}") + try: + self.last_update_status = await self.api.async_get_data() + self.last_update_time = datetime.now() + _LOGGER.debug( + f"Data Coordinator: Update completed at {self.last_update_time}" + ) + return self.last_update_status + except Exception as ex: + self.last_update_status = False + _LOGGER.debug(f"Coordinator Update Error: {ex} at {self.last_update_time}") + raise UpdateFailed() from ex diff --git a/custom_components/sinapsi_alfa/manifest.json b/custom_components/sinapsi_alfa/manifest.json new file mode 100644 index 0000000..d465788 --- /dev/null +++ b/custom_components/sinapsi_alfa/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "sinapsi_alfa", + "name": "Alfa by Sinapsi", + "codeowners": ["@alexdelprete"], + "config_flow": true, + "documentation": "https://github.com/alexdelprete/ha-sinapsi-alfa", + "integration_type": "hub", + "iot_class": "local_polling", + "issue_tracker": "https://github.com/alexdelprete/ha-sinapsi-alfa/issues", + "loggers": ["custom_components.sinapsi_alfa"], + "requirements": ["pymodbus>=3.5.4"], + "version": "0.1.0" +} \ No newline at end of file diff --git a/custom_components/sinapsi_alfa/sensor.py b/custom_components/sinapsi_alfa/sensor.py new file mode 100644 index 0000000..d8553a5 --- /dev/null +++ b/custom_components/sinapsi_alfa/sensor.py @@ -0,0 +1,194 @@ +"""Sensor Platform Device for ABB Power-One PVI SunSpec. + +https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec +""" + +import logging +from typing import Any + +from homeassistant.components.sensor import SensorEntity +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import ( + CONF_NAME, + DATA, + DOMAIN, + INVERTER_TYPE, + SENSOR_TYPES_COMMON, + SENSOR_TYPES_DUAL_MPPT, + SENSOR_TYPES_SINGLE_MPPT, + SENSOR_TYPES_SINGLE_PHASE, + SENSOR_TYPES_THREE_PHASE, +) + +_LOGGER = logging.getLogger(__name__) + + +def add_sensor_defs(coordinator, config_entry, sensor_list, sensor_definitions): + """Class Initializitation.""" + + for sensor_info in sensor_definitions.values(): + sensor_data = { + "name": sensor_info[0], + "key": sensor_info[1], + "unit": sensor_info[2], + "icon": sensor_info[3], + "device_class": sensor_info[4], + "state_class": sensor_info[5], + } + sensor_list.append( + ABBPowerOneFimerSensor(coordinator, config_entry, sensor_data) + ) + + +async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities): + """Sensor Platform setup.""" + + # Get handler to coordinator from config + coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA] + + _LOGGER.debug("(sensor) Name: %s", config_entry.data.get(CONF_NAME)) + _LOGGER.debug("(sensor) Manufacturer: %s", coordinator.api.data["comm_manufact"]) + _LOGGER.debug("(sensor) Model: %s", coordinator.api.data["comm_model"]) + _LOGGER.debug("(sensor) SW Version: %s", coordinator.api.data["comm_version"]) + _LOGGER.debug("(sensor) Inverter Type (str): %s", coordinator.api.data["invtype"]) + _LOGGER.debug("(sensor) MPPT #: %s", coordinator.api.data["mppt_nr"]) + _LOGGER.debug("(sensor) Serial#: %s", coordinator.api.data["comm_sernum"]) + + sensor_list = [] + add_sensor_defs(coordinator, config_entry, sensor_list, SENSOR_TYPES_COMMON) + + if coordinator.api.data["invtype"] == INVERTER_TYPE[101]: + add_sensor_defs( + coordinator, config_entry, sensor_list, SENSOR_TYPES_SINGLE_PHASE + ) + elif coordinator.api.data["invtype"] == INVERTER_TYPE[103]: + add_sensor_defs( + coordinator, config_entry, sensor_list, SENSOR_TYPES_THREE_PHASE + ) + + _LOGGER.debug( + "(sensor) DC Voltages : single=%s dc1=%s dc2=%s", + coordinator.api.data["dcvolt"], + coordinator.api.data["dc1volt"], + coordinator.api.data["dc2volt"], + ) + if coordinator.api.data["mppt_nr"] == 1: + add_sensor_defs( + coordinator, config_entry, sensor_list, SENSOR_TYPES_SINGLE_MPPT + ) + else: + add_sensor_defs(coordinator, config_entry, sensor_list, SENSOR_TYPES_DUAL_MPPT) + + async_add_entities(sensor_list) + + return True + + +class ABBPowerOneFimerSensor(CoordinatorEntity, SensorEntity): + """Representation of an ABB SunSpec Modbus sensor.""" + + def __init__(self, coordinator, config_entry, sensor_data): + """Class Initializitation.""" + super().__init__(coordinator) + self.coordinator = coordinator + self._name = sensor_data["name"] + self._key = sensor_data["key"] + self._unit_of_measurement = sensor_data["unit"] + self._icon = sensor_data["icon"] + self._device_class = sensor_data["device_class"] + self._state_class = sensor_data["state_class"] + self._device_name = self.coordinator.api.name + self._device_host = self.coordinator.api.host + self._device_model = self.coordinator.api.data["comm_model"] + self._device_manufact = self.coordinator.api.data["comm_manufact"] + self._device_sn = self.coordinator.api.data["comm_sernum"] + self._device_swver = self.coordinator.api.data["comm_version"] + self._device_hwver = self.coordinator.api.data["comm_options"] + + @callback + def _handle_coordinator_update(self) -> None: + """Fetch new state data for the sensor.""" + self._state = self.coordinator.api.data[self._key] + self.async_write_ha_state() + # write debug log only on first sensor to avoid spamming the log + if self.name == "Manufacturer": + _LOGGER.debug( + "_handle_coordinator_update: sensors state written to state machine" + ) + + @property + def has_entity_name(self): + """Return the name state.""" + return True + + @property + def name(self): + """Return the name.""" + return f"{self._name}" + + @property + def native_unit_of_measurement(self): + """Return the unit of measurement.""" + return self._unit_of_measurement + + @property + def icon(self): + """Return the sensor icon.""" + return self._icon + + @property + def device_class(self): + """Return the sensor device_class.""" + return self._device_class + + @property + def state_class(self): + """Return the sensor state_class.""" + return self._state_class + + @property + def entity_category(self): + """Return the sensor entity_category.""" + if self._state_class is None: + return EntityCategory.DIAGNOSTIC + else: + return None + + @property + def native_value(self): + """Return the state of the sensor.""" + if self._key in self.coordinator.api.data: + return self.coordinator.api.data[self._key] + + @property + def state_attributes(self) -> dict[str, Any] | None: + """Return the attributes.""" + return None + + @property + def should_poll(self) -> bool: + """No need to poll. Coordinator notifies entity of updates.""" + return False + + @property + def unique_id(self): + """Return a unique ID to use for this entity.""" + return f"{self._device_sn}_{self._key}" + + @property + def device_info(self): + """Return device specific attributes.""" + return { + "configuration_url": f"http://{self._device_host}", + "hw_version": None, + "identifiers": {(DOMAIN, self._device_sn)}, + "manufacturer": self._device_manufact, + "model": self._device_model, + "name": self._device_name, + "serial_number": self._device_sn, + "sw_version": self._device_swver, + "via_device": None, + } diff --git a/custom_components/sinapsi_alfa/translations/en.json b/custom_components/sinapsi_alfa/translations/en.json new file mode 100644 index 0000000..93becaa --- /dev/null +++ b/custom_components/sinapsi_alfa/translations/en.json @@ -0,0 +1,38 @@ +{ + "config": { + "step": { + "user": { + "title": "Alfa Connection Configuration", + "description": "If you need help with the configuration go to: https://github.com/alexdelprete/ha-sinapsi-alfa", + "data": { + "name": "Custom Name of the device (used for sensors' prefix)", + "host": "IP or hostname", + "port": "TCP port", + "slave_id": "Modbus Slave address of the device", + "base_addr": "Modbus Register Map Base Address", + "scan_interval": "Polling Period (min: 30s max: 600s)" + } + } + }, + "error": { + "already_configured": "Device is already configured" + }, + "abort": { + "already_configured": "Device is already configured" + } + }, + "options": { + "step": { + "init": { + "title": "Alfa Connection Options", + "description": "Set Connection Options", + "data": { + "port": "TCP port", + "slave_id": "Modbus Slave address of the inverter", + "base_addr": "Modbus Register Map Base Address", + "scan_interval": "Polling Period (min: 30s max: 600s)" + } + } + } + } +} \ No newline at end of file diff --git a/doc/alfa-ha-modbus-configuration.yaml b/doc/alfa-ha-modbus-configuration.yaml new file mode 100644 index 0000000..206c31b --- /dev/null +++ b/doc/alfa-ha-modbus-configuration.yaml @@ -0,0 +1,135 @@ +modbus: + - name: Alfa + type: tcp + host: + port: 502 + sensors: + - name: Potenza Attiva Prelevata Istantanea + device_class: power + unit_of_measurement: W + state_class: measurement + data_type: uint16 + address: 2 + - name: Potenza Attiva Immessa Istantanea + device_class: power + unit_of_measurement: W + state_class: measurement + data_type: uint16 + address: 12 + - name: Potenza Attiva Prodotta Istantanea + device_class: power + unit_of_measurement: W + state_class: measurement + data_type: uint16 + address: 921 + - name: Energia Attiva Prelevata Totale + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 5 + - name: Energia Attiva Immessa Totale + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 15 + - name: Energia Attiva Prodotta Totale + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 924 + - name: Pot Att Prel Quart Media + device_class: power + unit_of_measurement: W + state_class: measurement + data_type: uint16 + address: 9 + - name: Pot Att Imm Quart Media + device_class: power + unit_of_measurement: W + state_class: measurement + data_type: uint16 + address: 19 + - name: Tot Energ Att Prel Giorno-1 F1 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 30 + - name: Tot Energ Att Prel Giorno-1 F2 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 32 + - name: Tot Energ Att Prel Giorno-1 F3 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 34 + - name: Tot Energ Att Prel Giorno-1 F4 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 36 + - name: Tot Energ Att Prel Giorno-1 F5 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 38 + - name: Tot Energ Att Prel Giorno-1 F6 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 40 + - name: Tot Energ Att Imm Giorno-1 F1 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 54 + - name: Tot Energ Att Imm Giorno-1 F2 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 56 + - name: Tot Energ Att Imm Giorno-1 F3 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 58 + - name: Tot Energ Att Imm Giorno-1 F4 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 60 + - name: Tot Energ Att Imm Giorno-1 F5 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 62 + - name: Tot Energ Att Imm Giorno-1 F6 + device_class: energy + unit_of_measurement: Wh + state_class: total_increasing + data_type: uint32 + address: 64 + - name: Fascia oraria corrente + data_type: uint16 + address: 203 + - name: Data evento + data_type: uint32 + address: 780 + - name: Tempo residuo distacco + data_type: uint16 + address: 782 \ No newline at end of file diff --git a/doc/distacco.yaml b/doc/distacco.yaml new file mode 100644 index 0000000..19b07ee --- /dev/null +++ b/doc/distacco.yaml @@ -0,0 +1,9 @@ +sensor: + - platform: template + sensors: + distacco: + friendly_name: "Avviso distacco" + value_template: > + {% if (states('sensor.data_evento') | int ) > 4294967294 %} Nessun avviso + {% else %} {{ (states('sensor.data_evento') | int + (states('sensor.tempo_residuo_distacco') | int)) | timestamp_local }} + {% endif %} \ No newline at end of file diff --git a/gfxfiles/alfa-400-200x35.png b/gfxfiles/alfa-400-200x35.png new file mode 100644 index 0000000000000000000000000000000000000000..37e8f88b4d21b83a51a87281ed92a509c60d091d GIT binary patch literal 2483 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 literal 0 HcmV?d00001 diff --git a/gfxfiles/alfa-400.png b/gfxfiles/alfa-400.png new file mode 100644 index 0000000000000000000000000000000000000000..d8195368debff7e9a7f2db34ec63608045216d04 GIT binary patch literal 4506 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 literal 0 HcmV?d00001 diff --git a/gfxfiles/config.png b/gfxfiles/config.png new file mode 100644 index 0000000000000000000000000000000000000000..aa2bf889817a2dba3a48341f3fa1d4f4853fffd4 GIT binary patch literal 18498 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 O360x2$bwrIFaHPUE3Pa6 literal 0 HcmV?d00001 diff --git a/gfxfiles/demo.png b/gfxfiles/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..86842c2726a6c0969deee12eb175b9e985122a34 GIT binary patch literal 48457 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

*2Q-ZU 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 z zLPC>(KG6{YDC!b!TCwYFxXr&o@m1bJM|_C3|19SQ4x_9%;?#@-^5 zQp<$v71VCx=PK<_uH~FaCac^tK_r>CaWxXM#EDsOcMj^s{!q{Aw85^}kC7YVnICOky0Uu5vn=fP+3O$Oa%=ws3yn9i#PM zh}P>iw1sWi zqRt%)s(J57i44#nRJi#g0|+v&c|#TNnK|GPOwo#hs{C3JhAxv}^rGCLtB%C6+_a-- z_QgjcbqWQ=b#C4EJsD8keSR!ENho%75;*-_D8TVL{mEmDZ@w^h>GS21EQ#xOUqimZ z3XTlBVY}eGO_gn^?#1?L=e14Rn~8TCvsd(0-<0^@J`as=Ct-l6%Ocs9G^W-Tts2P zt_m#F;2IQ?1FM03A|e_@kb>J;I^LI$hfRBlDb{(5^Cjj3hJs&`nU$+N@RJ-brrhUm$M?HBHej zSY+6bHsa;Y+>`&~JV6zmQq!f=yH8(Zy`u28vr*o%=U)Exd>#b#UEQFP>L;KV)qr#s z65X@ZG_PI(YLj(grVKC(c_D4@S~;ZqR%+Q&NbeDue4`a&O*VPwSa4NgZu{K=LZm?e z0MBP+_0hh0N?tit6v-h~bd29aY*?4hTVw&4d@m<3fF?HmxR8ZlV9?y#y`h$rF;qoba&|| zp2H&}mXhY_Lar9nBdQ`VlAv!wr*q=;jd=K|dp%?zGGCeQR~Q8I>>l(%Horc<5Q{~c zsZtR>C`1Agj3=l%_q%@rhK(A zW-Uty2kg|Xc3orf+MGGI%4QQ5rojAOh)9W(J7njH?G1`%n z223P`P*yo9s9~>4-nv=va1rD^baVgL z`fKKcl}&W1U4WRIHYuHAP^JXQoMO&unz1z1w&D-3;6+Yj=(=LG8u3vyiy)4K{e4y_ zI3m|9aKP`!X>1)F5><`l*;s2N1F@0w+bu|f;(RwrLcv3Fd!y-z*c!zD#Q+cdtDQY# zUxjyeXz9!Jv1KXh{n*++Ptcvmb)UHP+e1&D(sty2ZaG$hX)I7i z9jN5;GdBXh{@^z9hTQ#{GjgO?h<4-yu)69LNI)cWa4VFu_a)hD zJcvKyZ$s0p5cHp10YsO$90c`Z4u(wMo+GA@JV0L8xBZUgDYRXDu)r?iXS~a>zwm|> z!=%!Bg9tu{=iYq+fB=4VirV48CYyMi1-_8{61#LecfZ@rb?lL_m+%MKlS_f@P$9@9 zAXeN(S@R?}J0bNvm@YynwfQeXi=L6QbP_*o1mUdWLNpTHa)2mOz4fyJfH&DG#CB#B z&G-7P!!%Rwd9?(811aDJ1>eS@0JXCB(a+!1JCkzzLoWRvN9~vO1kUnKrI2@5tdPCWV8pdomm7EgWot2{jV$(?&~y%krTglCPG0yl!)bgBs$6h8eS z*F5_PsMMDMg+%AW+M%E3NhYjVOg-ygRoUZtW-|ZLSHV+Ab);S*OrZVzvlzACEkXp) zD8IS=YS)feiuf83%E{0q7WsdJ<7l8T)xFj;)=4g@MffOD!j`n$RI6LaY=??!kJX$a zH(Nal{|<<^8^T9=ZT`5I^OWP@t)TUDdqK0+zT8)h7EFYWNYOpmDYxJmuUph!uI3*8 zN9LzqaO#xosFX=MJ>Fep0Ph6B)(`hErpoNp1HGhu|JU~k&SItK6X&gg9cgFdwNL!D z6$dV}QFK;o#`M+&n}Dav zw$oN}qW-`01oBKIP_o6pKPLyA#wGqF9G#1?PI?CY_daYw?u^2M>=et`FwH}tlC$CA z2~jw=C-p+WbjgEM|1zSA&2b!d1w~PO7{BHoN`LLamR#;0$d1y#1xf@0hPp zN`$%hTxIzzzRZ8jeXhdYuxp34o)4R6I@mV}+g)>t}lX9wncet&m3-JI# zBRkYmN-fEH@8YIFE%)AHL9YX8A|=mQ^`bPhAjfbu$Ac@8ee4kYU*h2VvKa_IzmA&C zY_gsyo((M}OwWlhR!p%O;_p-zI=3p}*&oW7;Isf&Awpi8#k?`2C+H$o2nmio&>*Lp zagfLh^I%Yap$^J)xTfI$RW(x_B=dBMk>FUl33EcW-zP_7_mLv*=^iSOjaFpu+Ru+Z zlvcA}s$U#D^lx-nedx-K`ZQ?`tv=V#Fu<p)EiHo zuv)<3qvp>5{*;a(%}+PXJu83i)=G$Fe%y%sp6`dj&r1s8MnZY$qur}+G7kw=MQbn= zq7)*ehbx~_c8+ctb9!`42V#DrYy65K=f%2zm|`izw~xX=!(N=ZW0CLI8CP=n^vQ;P zqW%j+hC5BuY@sqcd^7F!d8URtaDgze|zuB}v?r$V@l!BaC1}8#ULW6wjH=d^lr7~)P z%@DjD*T8-sRfCZBGwC);9<&DLgLNNU7rZ%bnF1`VLjh|O=O_cS$>07?*L(`pK=l3w2?dAkE}`K*~~_RWzl_GASy7t`UG zGeHT5B3=*ZpY2WtB8j(Eq=yCy&2J-D4s&iisMCS;2hSd(;z6c4s%>Ng?W;sdL_J4j z^02g_$Jw64I~*$qG$vw__#>b*v*LlpU)jMf*I}PilkVA2qWX{`>8p1=b2fEcyMcus zZ2JFd%+j{RGjgtU+Hd`B2b8P9mre#?=AF=Q;xQ((8-sUEtdwu9oUQ?p(>k#WUtgBz z+G0Y5`@jqJX92|fhK+|J=ds-v+xiLw{(tBrsivWMku)q}`eWCZzd83_uz50RXOG^9 zvg?bWc~q)wolSf?caW&`#n;pt53e0u1*lEs*Q(i~+S5d62$oLD<5*-U!r=(_Txhe; zw7#B*E3%j6i0!Coi{H}8O$WI8@?1y%@1e3#IR>RrN0{!malM&?U2{BGvL)8*sl0-@ z&Q|@Z7s>vFC4sw{ zo>8b_OZ+07XV!e!EBmlUhtdiVHO~L{iKBB&?6cO&5^(SL_MEFjyu)6^)Swy34!mjM z?^9*@9~J|?^9pYw)7)*$XiCJ_27z=8=d<_+q@q$z6$mnS1?P=SYYzV=W z!<|u03EUIF2m{E%fFs|=;pKelI`oqcoqEs<1;ZHhanY9N)JU_kF{RiS2|rjI=4rVyYG6WunW{c&`y1j)!0U%D6|lqE2VrIlDS ztI^)2qtnGw)DH;_HAq!_@t5r_MeJ2?U!R1kqGH?6;^JbYuvU`ez1h>AmN5%o)OTe8 zcZ6SGJ7E|1TmQJTpkZGxqp z#P z_nOzS5eFX%;>CrLei{9RQk*x*zRT?V92F&u9fs5wNgH6*O%!ZufX-Lll_3iK(IzDo ze%neigAj+fh`jmE?2RC5x#kg!&KDop!t{Rn#TdcY-PH`hRrDs<^dfbcyh;WD#r zMc=hi@C{6dpn~gjd%tN=vsw*mX2rr6@E$!K(E@>Bxzm{z)%D%!PO1@qs8z6CIbtB? z>KQ2^;g#rT38C|DWW`xz#A`)g5ILOP(qkis^T%RP|S=*X?^B5{_!d}@G`BTFpp)%_8=b;~O zmJ0~iX9&rp6UCTL*b`12R3=99(%L$t*Kcvw#aTHeUcQU=J?ju4Le5!FW*hN95g;K* zSX$D(n#_}~Q@ive8L@|-lbKbvU5>Dh(GjJI-~A2!bbK|YFn34;oYvB%a7ot0)HE{W z4qJd+194src~YyXY8{)1)p3 z0Wr)=r0GR2e;ND8jOgfScDiQ-^Bs-KP>gJJl5dHLgp#c+Ko-f#7JcZQ*@8T@>1w6S zSS^bO{OT4>I4ynduneWnn^JU7DHgHRN;1UGCq|2A6h%vLr>p3BmRNDk4Wna33PU1P z_*wN4FY0)7Y^(xpYI8eLm7hTonh1L$Fnja{h95o2N7Q26g+I5^N(&Nz8afm;42d?R z^@CR1$EEAWKY#uZs*Qa@v5rLa-yjCnbs-ei(R)p3EYl-RMS_JXYY#9NXqt{)j)D-8 z(L%jybt_VRZf}|$N$|d*1-oeg9xdLLD^9-?pasGCjx0Q?^*ko-vQCh2TEZ`MBBZ>m zA{PG9X`7Z82IUE{3jfwgx^i`ri+S|=2F)5*p|VUAT@jd~u#oe*dF>Xs2ygFoi(-6) zK5Le6eb(G_l$DcP$Jta(n5w)GtafF^Kow6?mCG;Pu`R-N=ta`<2eqw>tN`pm}5_aZJpQ#0W9JpSzkb1}I}e z4F)@3f3hOxbz9agWEmYyC@fZ%0Am;f;#31=4|1WiD;9M1#VoM-dDl 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.0,<24.1 +ruff==0.2.1 +pymodbus>=3.5 \ No newline at end of file diff --git a/scripts/develop b/scripts/develop new file mode 100644 index 0000000..20366e8 --- /dev/null +++ b/scripts/develop @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +# Create config dir if not present +if [[ ! -d "${PWD}/config" ]]; then + mkdir -p "${PWD}/config" + hass --config "${PWD}/config" --script ensure_config +fi + +# Set the path to custom_components +## This let's us have the structure we want /custom_components/integration_blueprint +## while at the same time have Home Assistant configuration inside /config +## without resulting to symlinks. +export PYTHONPATH="${PYTHONPATH}:${PWD}/custom_components" + +# Start Home Assistant +hass --config "${PWD}/config" --debug \ No newline at end of file diff --git a/scripts/lint b/scripts/lint new file mode 100644 index 0000000..752d23a --- /dev/null +++ b/scripts/lint @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +ruff check . --fix \ No newline at end of file diff --git a/scripts/setup b/scripts/setup new file mode 100644 index 0000000..abe537a --- /dev/null +++ b/scripts/setup @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +python3 -m pip install --requirement requirements.txt \ No newline at end of file