Compare commits

..

8 Commits

Author SHA1 Message Date
Stefan Allius
60d142ea54 update class diagramms 2025-03-27 23:59:39 +01:00
Stefan Allius
5d09c09d8b update headline 2025-03-26 23:22:43 +01:00
Stefan Allius
911eb8d44e update 2025-03-26 23:19:46 +01:00
Stefan Allius
506076ee59 update more texts 2025-03-26 23:09:26 +01:00
Stefan Allius
4e96f077db concern ms3000 support 2025-03-26 22:53:57 +01:00
Stefan Allius
36f7c1ac1f fix compatiblity table 2025-03-26 22:48:19 +01:00
Stefan Allius
83e0f192ef add DCU-1000 storage systems/batteries 2025-03-26 22:19:57 +01:00
Stefan Allius
56b9153373 fix typo 2025-03-26 22:19:28 +01:00
44 changed files with 1148 additions and 1514 deletions

View File

@@ -6,9 +6,4 @@ PRIVAT_CONTAINER_REGISTRY=docker.io/<user>/
# registry for official container (preview, rc, rel)
PUBLIC_CONTAINER_REGISTRY=ghcr.io/<user>/
PUBLIC_CR_KEY=
# define serial number of GEN3PLUS devices for systemtests
# the serialnumber are coded as 4-byte hex-strings
SOLARMAN_INV_SNR='00000000'
SOLARMAN_DCU_SNR='00000000'
PUBLIC_CR_KEY=

View File

@@ -49,7 +49,7 @@ jobs:
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --ignore=F821 --show-source --statistics
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 --exit-zero --ignore=C901,E121,E123,E126,E133,E226,E241,E242,E704,W503,W504,W505 --format=pylint --output-file=output_flake.txt --exclude=*.pyc app/src/
- name: Test with pytest

View File

@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.13.0] - 2025-04-13
## [unreleased]
- update dependency python to 3.13
- add initial support for TSUN MS-3000

View File

@@ -1,4 +1,4 @@
.PHONY: build clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel check-docker-compose install
.PHONY: build clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel
debug dev preview rc rel:
$(MAKE) -C app $@
@@ -12,7 +12,3 @@ addon-dev addon-debug addon-rc addon-rel:
check-docker-compose:
docker-compose config -q
install:
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements-test.txt

View File

@@ -8,7 +8,7 @@
<p align="center">
<a href="https://opensource.org/licenses/BSD-3-Clause"><img alt="License: BSD-3-Clause" src="https://img.shields.io/badge/License-BSD_3--Clause-green.svg"></a>
<a href="https://www.python.org/downloads/release/python-3130/"><img alt="Supported Python versions" src="https://img.shields.io/badge/python-3.13-blue.svg"></a>
<a href="https://aiomqtt.bo3hm.com/introduction.html"><img alt="Supported aiomqtt versions" src="https://img.shields.io/badge/aiomqtt-2.3.1-lightblue.svg"></a>
<a href="https://sbtinstruments.github.io/aiomqtt/introduction.html"><img alt="Supported aiomqtt versions" src="https://img.shields.io/badge/aiomqtt-2.3.0-lightblue.svg"></a>
<a href="https://libraries.io/pypi/aiocron"><img alt="Supported aiocron versions" src="https://img.shields.io/badge/aiocron-1.8-lightblue.svg"></a>
<a href="https://toml.io/en/v1.0.0"><img alt="Supported toml versions" src="https://img.shields.io/badge/toml-1.0.0-lightblue.svg"></a>
<br>
@@ -141,7 +141,7 @@ No special configuration is required for the Docker container if it is built and
On the host, two directories (for log files and for config files) must be mapped. If necessary, the UID of the proxy process can be adjusted, which is also the owner of the log and configuration files.
A description of the configuration parameters can be found [here](https://github.com/s-allius/tsun-gen3-proxy/wiki/configuration-env#docker-compose-environment-variables)
A description of the configuration parameters can be found [here](https://github.com/s-allius/tsun-gen3-proxy/wiki/Configuration-toml#docker-compose-environment-variables).
## Proxy Configuration
@@ -430,15 +430,15 @@ A combination with a red question mark should work, but I have not checked it in
<tr><td>GEN3 micro inverters (quad MPPT):<br>MS3000</td><td align="center">✔️</td><td align="center">✔️</td><td align="center">✔️</td><td align="center"></td><td align="center"></td></tr>
<tr><td>GEN3 PLUS micro inverters:<br>MS1600, MS1800, MS2000<br>MS2000-D, MS800</td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center">✔️</td><td align="center">✔️</td></tr>
<tr><td>GEN3 PLUS storage systems:<br>DC1000</td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center">✔️</td><td align="center">✔️</td></tr>
<tr><td>GEN3 PLUS smart meter:<br>TSOL-MG3-MS, DDZY422-D2</td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center">❓</td><td align="center">❓</td></tr>
<tr><td>GEN3 PLUS smart meter:<br>TSOL-MG3-MS</td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center">❓</td><td align="center">❓</td></tr>
</<tr><td>TITAN micro inverters:<br>TSOL-MP3000, MP2250</td><td align="center">❓</td><td align="center">❓</td><td align="center">❓</td><td align="center">❓</td><td align="center">❓</td></tr>
</table>
```txt
Legend
: Firmware not available for this devices
✔️: Proxy support testet
❓: Proxy support unknown. There is an open port, but all known protocols do not work.
✔️: proxy support testet
❓: proxy support possible but not testet
🚧: Proxy support in preparation
```

View File

@@ -22,16 +22,7 @@ dev debug:
export IMAGE=$(PRIVAT_CONTAINER_REGISTRY)$(IMAGE) && \
docker buildx bake -f docker-bake.hcl $@
rc:
@[ "${RC}" ] || ( echo ">> RC is not set"; exit 1 )
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"
export VERSION=$(VERSION)-$@$(RC) && \
export IMAGE=$(PUBLIC_CONTAINER_REGISTRY)$(IMAGE) && \
docker buildx bake -f docker-bake.hcl $@
preview rel:
preview rc rel:
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"

View File

@@ -4,260 +4,257 @@
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="634pt" height="966pt"
viewBox="0.00 0.00 634.00 966.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="626pt" height="966pt"
viewBox="0.00 0.00 625.50 966.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 962)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-962 630,-962 630,4 -4,4"/>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-962 621.5,-962 621.5,4 -4,4"/>
<!-- A0 -->
<g id="node1" class="node">
<title>A0</title>
<polygon fill="#fff8dc" stroke="#000000" points="200.1964,-934 91.8036,-934 91.8036,-898 206.1964,-898 206.1964,-928 200.1964,-934"/>
<polyline fill="none" stroke="#000000" points="200.1964,-934 200.1964,-928 "/>
<polyline fill="none" stroke="#000000" points="206.1964,-928 200.1964,-928 "/>
<text text-anchor="middle" x="149" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
<text text-anchor="middle" x="149" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">on diagrams too!</text>
<polygon fill="#fff8dc" stroke="#000000" points="191.6964,-934 83.3036,-934 83.3036,-898 197.6964,-898 197.6964,-928 191.6964,-934"/>
<polyline fill="none" stroke="#000000" points="191.6964,-934 191.6964,-928 "/>
<polyline fill="none" stroke="#000000" points="197.6964,-928 191.6964,-928 "/>
<text text-anchor="middle" x="140.5" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
<text text-anchor="middle" x="140.5" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">on diagrams too!</text>
</g>
<!-- A1 -->
<g id="node2" class="node">
<title>A1</title>
<polygon fill="none" stroke="#000000" points="224,-926 224,-958 340,-958 340,-926 224,-926"/>
<text text-anchor="start" x="233.649" y="-939" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="224,-906 224,-926 340,-926 340,-906 224,-906"/>
<polygon fill="none" stroke="#000000" points="224,-874 224,-906 340,-906 340,-874 224,-874"/>
<text text-anchor="start" x="260.61" y="-887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
<polygon fill="none" stroke="#000000" points="215.5,-926 215.5,-958 331.5,-958 331.5,-926 215.5,-926"/>
<text text-anchor="start" x="225.149" y="-939" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="215.5,-906 215.5,-926 331.5,-926 331.5,-906 215.5,-906"/>
<polygon fill="none" stroke="#000000" points="215.5,-874 215.5,-906 331.5,-906 331.5,-874 215.5,-874"/>
<text text-anchor="start" x="252.11" y="-887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="187,-726 187,-758 378,-758 378,-726 187,-726"/>
<text text-anchor="start" x="248.5965" y="-739" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;InverterIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="187,-706 187,-726 378,-726 378,-706 187,-706"/>
<polygon fill="none" stroke="#000000" points="187,-650 187,-706 378,-706 378,-650 187,-650"/>
<text text-anchor="start" x="249.022" y="-687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()&#45;&gt;bool</text>
<text text-anchor="start" x="196.7835" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;disc(shutdown_started=False)</text>
<text text-anchor="start" x="228.044" y="-663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;create_remote()</text>
<polygon fill="none" stroke="#000000" points="178.5,-726 178.5,-758 369.5,-758 369.5,-726 178.5,-726"/>
<text text-anchor="start" x="240.0965" y="-739" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;InverterIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="178.5,-706 178.5,-726 369.5,-726 369.5,-706 178.5,-706"/>
<polygon fill="none" stroke="#000000" points="178.5,-650 178.5,-706 369.5,-706 369.5,-650 178.5,-650"/>
<text text-anchor="start" x="240.522" y="-687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()&#45;&gt;bool</text>
<text text-anchor="start" x="188.2835" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;disc(shutdown_started=False)</text>
<text text-anchor="start" x="219.544" y="-663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;create_remote()</text>
</g>
<!-- A1&#45;&gt;A4 -->
<g id="edge1" class="edge">
<title>A1&#45;&gt;A4</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M282,-863.7744C282,-831.6663 282,-790.6041 282,-758.1476"/>
<polygon fill="none" stroke="#000000" points="278.5001,-863.8621 282,-873.8622 285.5001,-863.8622 278.5001,-863.8621"/>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M273.5,-863.7744C273.5,-831.6663 273.5,-790.6041 273.5,-758.1476"/>
<polygon fill="none" stroke="#000000" points="270.0001,-863.8621 273.5,-873.8622 277.0001,-863.8622 270.0001,-863.8621"/>
</g>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="450,-454 450,-498 572,-498 572,-454 450,-454"/>
<text text-anchor="start" x="501.277" y="-479" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Mqtt</text>
<text text-anchor="start" x="478.4815" y="-467" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;Singleton&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="450,-398 450,-454 572,-454 572,-398 450,-398"/>
<text text-anchor="start" x="468.4875" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;ha_restarts</text>
<text text-anchor="start" x="476.2665" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;__client</text>
<text text-anchor="start" x="459.8735" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;__cb_MqttIsUp</text>
<polygon fill="none" stroke="#000000" points="450,-354 450,-398 572,-398 572,-354 450,-354"/>
<text text-anchor="start" x="472.936" y="-379" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish()</text>
<text text-anchor="start" x="477.1045" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;close()</text>
<polygon fill="none" stroke="#000000" points="441.5,-454 441.5,-498 563.5,-498 563.5,-454 441.5,-454"/>
<text text-anchor="start" x="492.777" y="-479" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Mqtt</text>
<text text-anchor="start" x="469.9815" y="-467" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;Singleton&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="441.5,-398 441.5,-454 563.5,-454 563.5,-398 441.5,-398"/>
<text text-anchor="start" x="459.9875" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;ha_restarts</text>
<text text-anchor="start" x="467.7665" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;__client</text>
<text text-anchor="start" x="451.3735" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;static&gt;__cb_MqttIsUp</text>
<polygon fill="none" stroke="#000000" points="441.5,-354 441.5,-398 563.5,-398 563.5,-354 441.5,-354"/>
<text text-anchor="start" x="464.436" y="-379" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish()</text>
<text text-anchor="start" x="468.6045" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;close()</text>
</g>
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="396,-792 396,-824 626,-824 626,-792 396,-792"/>
<text text-anchor="start" x="498.2215" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Proxy</text>
<polygon fill="none" stroke="#000000" points="396,-676 396,-792 626,-792 626,-676 396,-676"/>
<text text-anchor="start" x="482.6545" y="-773" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;db_stat</text>
<text text-anchor="start" x="475.991" y="-761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;entity_prfx</text>
<text text-anchor="start" x="466.826" y="-749" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;discovery_prfx</text>
<text text-anchor="start" x="466.262" y="-737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;proxy_node_id</text>
<text text-anchor="start" x="462.373" y="-725" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;proxy_unique_id</text>
<text text-anchor="start" x="478.216" y="-713" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;mqtt:Mqtt</text>
<text text-anchor="start" x="480.4355" y="-689" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
<polygon fill="none" stroke="#000000" points="396,-584 396,-676 626,-676 626,-584 396,-584"/>
<text text-anchor="start" x="487.1145" y="-657" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">class_init()</text>
<text text-anchor="start" x="481.834" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">class_close()</text>
<text text-anchor="start" x="453.484" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_cb_mqtt_is_up()</text>
<text text-anchor="start" x="405.697" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_register_proxy_stat_home_assistant()</text>
<text text-anchor="start" x="414.584" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_publ_mqtt_proxy_stat(key)</text>
<polygon fill="none" stroke="#000000" points="387.5,-792 387.5,-824 617.5,-824 617.5,-792 387.5,-792"/>
<text text-anchor="start" x="489.7215" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Proxy</text>
<polygon fill="none" stroke="#000000" points="387.5,-676 387.5,-792 617.5,-792 617.5,-676 387.5,-676"/>
<text text-anchor="start" x="474.1545" y="-773" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;db_stat</text>
<text text-anchor="start" x="467.491" y="-761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;entity_prfx</text>
<text text-anchor="start" x="458.326" y="-749" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;discovery_prfx</text>
<text text-anchor="start" x="457.762" y="-737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;proxy_node_id</text>
<text text-anchor="start" x="453.873" y="-725" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;proxy_unique_id</text>
<text text-anchor="start" x="469.716" y="-713" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;cls&gt;mqtt:Mqtt</text>
<text text-anchor="start" x="471.9355" y="-689" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
<polygon fill="none" stroke="#000000" points="387.5,-584 387.5,-676 617.5,-676 617.5,-584 387.5,-584"/>
<text text-anchor="start" x="478.6145" y="-657" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">class_init()</text>
<text text-anchor="start" x="473.334" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">class_close()</text>
<text text-anchor="start" x="444.984" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_cb_mqtt_is_up()</text>
<text text-anchor="start" x="397.197" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_register_proxy_stat_home_assistant()</text>
<text text-anchor="start" x="406.084" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_publ_mqtt_proxy_stat(key)</text>
</g>
<!-- A3&#45;&gt;A2 -->
<g id="edge9" class="edge">
<title>A3&#45;&gt;A2</title>
<path fill="none" stroke="#000000" d="M511,-571.373C511,-549.9571 511,-528.339 511,-508.5579"/>
<polygon fill="#000000" stroke="#000000" points="511.0001,-571.682 515,-577.6821 511,-583.682 507,-577.682 511.0001,-571.682"/>
<polygon fill="#000000" stroke="#000000" points="511,-498.392 515.5001,-508.3919 511,-503.392 511.0001,-508.392 511.0001,-508.392 511.0001,-508.392 511,-503.392 506.5001,-508.392 511,-498.392 511,-498.392"/>
<path fill="none" stroke="#000000" d="M502.5,-571.373C502.5,-549.9571 502.5,-528.339 502.5,-508.5579"/>
<polygon fill="#000000" stroke="#000000" points="502.5001,-571.682 506.5,-577.6821 502.5,-583.682 498.5,-577.682 502.5001,-571.682"/>
<polygon fill="#000000" stroke="#000000" points="502.5,-498.392 507.0001,-508.3919 502.5,-503.392 502.5001,-508.392 502.5001,-508.392 502.5001,-508.392 502.5,-503.392 498.0001,-508.392 502.5,-498.392 502.5,-498.392"/>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="214,-502 214,-534 405,-534 405,-502 214,-502"/>
<text text-anchor="start" x="281.16" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
<polygon fill="none" stroke="#000000" points="214,-386 214,-502 405,-502 405,-386 214,-386"/>
<text text-anchor="start" x="290.3335" y="-483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<text text-anchor="start" x="278.9355" y="-471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
<text text-anchor="start" x="299.497" y="-447" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="282.5505" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">config_id:str</text>
<text text-anchor="start" x="255.8785" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:MessageProt</text>
<text text-anchor="start" x="270.053" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="275.332" y="-399" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="214,-318 214,-386 405,-386 405,-318 214,-318"/>
<text text-anchor="start" x="276.022" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()&#45;&gt;bool</text>
<text text-anchor="start" x="223.7835" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;disc(shutdown_started=False)</text>
<text text-anchor="start" x="255.044" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;create_remote()</text>
<text text-anchor="start" x="249.484" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;async_publ_mqtt()</text>
<polygon fill="none" stroke="#000000" points="205.5,-502 205.5,-534 396.5,-534 396.5,-502 205.5,-502"/>
<text text-anchor="start" x="272.66" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
<polygon fill="none" stroke="#000000" points="205.5,-386 205.5,-502 396.5,-502 396.5,-386 205.5,-386"/>
<text text-anchor="start" x="281.8335" y="-483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<text text-anchor="start" x="270.4355" y="-471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
<text text-anchor="start" x="290.997" y="-447" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="274.0505" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">config_id:str</text>
<text text-anchor="start" x="247.3785" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:MessageProt</text>
<text text-anchor="start" x="261.553" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="266.832" y="-399" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="205.5,-318 205.5,-386 396.5,-386 396.5,-318 205.5,-318"/>
<text text-anchor="start" x="267.522" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()&#45;&gt;bool</text>
<text text-anchor="start" x="215.2835" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;disc(shutdown_started=False)</text>
<text text-anchor="start" x="246.544" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;create_remote()</text>
<text text-anchor="start" x="240.984" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;async_publ_mqtt()</text>
</g>
<!-- A3&#45;&gt;A5 -->
<g id="edge7" class="edge">
<title>A3&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M417.6791,-575.5683C407.6409,-561.7533 397.5008,-547.7982 387.6588,-534.2532"/>
<polygon fill="none" stroke="#000000" points="414.8649,-577.6495 423.5747,-583.682 420.5279,-573.5347 414.8649,-577.6495"/>
<path fill="none" stroke="#000000" d="M409.1791,-575.5683C399.1409,-561.7533 389.0008,-547.7982 379.1588,-534.2532"/>
<polygon fill="none" stroke="#000000" points="406.3649,-577.6495 415.0747,-583.682 412.0279,-573.5347 406.3649,-577.6495"/>
</g>
<!-- A4&#45;&gt;A5 -->
<g id="edge2" class="edge">
<title>A4&#45;&gt;A5</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M288.2719,-639.4228C291.3086,-608.1559 295.0373,-569.7639 298.491,-534.2034"/>
<polygon fill="none" stroke="#000000" points="284.7531,-639.4473 287.27,-649.7389 291.7203,-640.1241 284.7531,-639.4473"/>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M279.7719,-639.4228C282.8086,-608.1559 286.5373,-569.7639 289.991,-534.2034"/>
<polygon fill="none" stroke="#000000" points="276.2531,-639.4473 278.77,-649.7389 283.2203,-640.1241 276.2531,-639.4473"/>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="365,-236 365,-268 465,-268 465,-236 365,-236"/>
<text text-anchor="start" x="392.4995" y="-249" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">StreamPtr</text>
<polygon fill="none" stroke="#000000" points="365,-216 365,-236 465,-236 465,-216 365,-216"/>
<polygon fill="none" stroke="#000000" points="365,-172 365,-216 465,-216 465,-172 365,-172"/>
<text text-anchor="start" x="374.7175" y="-197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:ProtocolIfc</text>
<text text-anchor="start" x="389.7185" y="-185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
<polygon fill="none" stroke="#000000" points="356.5,-236 356.5,-268 456.5,-268 456.5,-236 356.5,-236"/>
<text text-anchor="start" x="383.9995" y="-249" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">StreamPtr</text>
<polygon fill="none" stroke="#000000" points="356.5,-216 356.5,-236 456.5,-236 456.5,-216 356.5,-216"/>
<polygon fill="none" stroke="#000000" points="356.5,-172 356.5,-216 456.5,-216 456.5,-172 356.5,-172"/>
<text text-anchor="start" x="366.2175" y="-197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:ProtocolIfc</text>
<text text-anchor="start" x="381.2185" y="-185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
</g>
<!-- A5&#45;&gt;A6 -->
<g id="edge8" class="edge">
<title>A5&#45;&gt;A6</title>
<path fill="none" stroke="#000000" d="M364.6387,-317.872C371.8786,-303.802 379.0526,-289.86 385.6187,-277.0995"/>
<polygon fill="#000000" stroke="#000000" points="390.2846,-268.0318 389.7105,-278.9826 387.9969,-272.4777 385.7091,-276.9237 385.7091,-276.9237 385.7091,-276.9237 387.9969,-272.4777 381.7078,-274.8647 390.2846,-268.0318 390.2846,-268.0318"/>
<text text-anchor="middle" x="389.5069" y="-285.0166" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">2</text>
<path fill="none" stroke="#000000" d="M356.1387,-317.872C363.3786,-303.802 370.5526,-289.86 377.1187,-277.0995"/>
<polygon fill="#000000" stroke="#000000" points="381.7846,-268.0318 381.2105,-278.9826 379.4969,-272.4777 377.2091,-276.9237 377.2091,-276.9237 377.2091,-276.9237 379.4969,-272.4777 373.2078,-274.8647 381.7846,-268.0318 381.7846,-268.0318"/>
<text text-anchor="middle" x="381.0069" y="-285.0166" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">2</text>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="346.7314,-238 271.2686,-238 271.2686,-202 346.7314,-202 346.7314,-238"/>
<text text-anchor="middle" x="309" y="-217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
<polygon fill="none" stroke="#000000" points="338.2314,-238 262.7686,-238 262.7686,-202 338.2314,-202 338.2314,-238"/>
<text text-anchor="middle" x="300.5" y="-217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
</g>
<!-- A5&#45;&gt;A7 -->
<g id="edge5" class="edge">
<title>A5&#45;&gt;A7</title>
<path fill="none" stroke="#000000" d="M309,-307.7729C309,-280.5002 309,-254.684 309,-238.2013"/>
<polygon fill="none" stroke="#000000" points="305.5001,-307.872 309,-317.872 312.5001,-307.872 305.5001,-307.872"/>
<path fill="none" stroke="#000000" d="M300.5,-307.7729C300.5,-280.5002 300.5,-254.684 300.5,-238.2013"/>
<polygon fill="none" stroke="#000000" points="297.0001,-307.872 300.5,-317.872 304.0001,-307.872 297.0001,-307.872"/>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="none" stroke="#000000" points="102.9001,-238 21.0999,-238 21.0999,-202 102.9001,-202 102.9001,-238"/>
<text text-anchor="middle" x="62" y="-217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
<polygon fill="none" stroke="#000000" points="94.4001,-238 12.5999,-238 12.5999,-202 94.4001,-202 94.4001,-238"/>
<text text-anchor="middle" x="53.5" y="-217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
</g>
<!-- A5&#45;&gt;A9 -->
<g id="edge6" class="edge">
<title>A5&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M205.2667,-346.4637C174.3973,-321.9347 140.8582,-294.4156 111,-268 100.2971,-258.5312 88.8616,-247.3925 79.732,-238.23"/>
<polygon fill="none" stroke="#000000" points="203.462,-349.4991 213.4739,-352.965 207.8086,-344.0121 203.462,-349.4991"/>
<path fill="none" stroke="#000000" d="M196.7667,-346.4637C165.8973,-321.9347 132.3582,-294.4156 102.5,-268 91.7971,-258.5312 80.3616,-247.3925 71.232,-238.23"/>
<polygon fill="none" stroke="#000000" points="194.962,-349.4991 204.9739,-352.965 199.3086,-344.0121 194.962,-349.4991"/>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="none" stroke="#000000" points="458.6421,-36 369.3579,-36 369.3579,0 458.6421,0 458.6421,-36"/>
<text text-anchor="middle" x="414" y="-15" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="450.1421,-36 360.8579,-36 360.8579,0 450.1421,0 450.1421,-36"/>
<text text-anchor="middle" x="405.5" y="-15" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
</g>
<!-- A6&#45;&gt;A11 -->
<g id="edge11" class="edge">
<title>A6&#45;&gt;A11</title>
<path fill="none" stroke="#000000" d="M401.1633,-171.974C395.4982,-146.4565 391.0868,-114.547 395,-86 396.8468,-72.5276 400.661,-57.9618 404.3907,-45.7804"/>
<polygon fill="#000000" stroke="#000000" points="407.4587,-36.1851 408.6994,-47.0805 405.9359,-40.9476 404.4131,-45.71 404.4131,-45.71 404.4131,-45.71 405.9359,-40.9476 400.1269,-44.3395 407.4587,-36.1851 407.4587,-36.1851"/>
<text text-anchor="middle" x="409.9892" y="-53.0243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
<path fill="none" stroke="#000000" d="M392.6633,-171.974C386.9982,-146.4565 382.5868,-114.547 386.5,-86 388.3468,-72.5276 392.161,-57.9618 395.8907,-45.7804"/>
<polygon fill="#000000" stroke="#000000" points="398.9587,-36.1851 400.1994,-47.0805 397.4359,-40.9476 395.9131,-45.71 395.9131,-45.71 395.9131,-45.71 397.4359,-40.9476 391.6269,-44.3395 398.9587,-36.1851 398.9587,-36.1851"/>
<text text-anchor="middle" x="401.4892" y="-53.0243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
</g>
<!-- A12 -->
<g id="node13" class="node">
<title>A12</title>
<polygon fill="none" stroke="#000000" points="502.0879,-122 403.9121,-122 403.9121,-86 502.0879,-86 502.0879,-122"/>
<text text-anchor="middle" x="453" y="-101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="493.5879,-122 395.4121,-122 395.4121,-86 493.5879,-86 493.5879,-122"/>
<text text-anchor="middle" x="444.5" y="-101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
</g>
<!-- A6&#45;&gt;A12 -->
<g id="edge10" class="edge">
<title>A6&#45;&gt;A12</title>
<path fill="none" stroke="#000000" d="M430.7853,-171.8133C435.2329,-158.2365 439.9225,-143.9208 443.8408,-131.9595"/>
<polygon fill="#000000" stroke="#000000" points="447.0602,-122.132 448.2235,-133.036 445.5036,-126.8835 443.9471,-131.6351 443.9471,-131.6351 443.9471,-131.6351 445.5036,-126.8835 439.6707,-130.2341 447.0602,-122.132 447.0602,-122.132"/>
<text text-anchor="middle" x="449.4498" y="-138.9887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
<path fill="none" stroke="#000000" d="M422.2853,-171.8133C426.7329,-158.2365 431.4225,-143.9208 435.3408,-131.9595"/>
<polygon fill="#000000" stroke="#000000" points="438.5602,-122.132 439.7235,-133.036 437.0036,-126.8835 435.4471,-131.6351 435.4471,-131.6351 435.4471,-131.6351 437.0036,-126.8835 431.1707,-130.2341 438.5602,-122.132 438.5602,-122.132"/>
<text text-anchor="middle" x="440.9498" y="-138.9887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="#fff8dc" stroke="#000000" points="583.406,-248 482.594,-248 482.594,-192 589.406,-192 589.406,-242 583.406,-248"/>
<polyline fill="none" stroke="#000000" points="583.406,-248 583.406,-242 "/>
<polyline fill="none" stroke="#000000" points="589.406,-242 583.406,-242 "/>
<text text-anchor="middle" x="536" y="-235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Creates an GEN3</text>
<text text-anchor="middle" x="536" y="-223" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter instance</text>
<text text-anchor="middle" x="536" y="-211" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">with</text>
<text text-anchor="middle" x="536" y="-199" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:Talent</text>
<polygon fill="#fff8dc" stroke="#000000" points="574.906,-248 474.094,-248 474.094,-192 580.906,-192 580.906,-242 574.906,-248"/>
<polyline fill="none" stroke="#000000" points="574.906,-248 574.906,-242 "/>
<polyline fill="none" stroke="#000000" points="580.906,-242 574.906,-242 "/>
<text text-anchor="middle" x="527.5" y="-235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Creates an GEN3</text>
<text text-anchor="middle" x="527.5" y="-223" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter instance</text>
<text text-anchor="middle" x="527.5" y="-211" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">with</text>
<text text-anchor="middle" x="527.5" y="-199" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:Talent</text>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge3" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M317.0491,-238.3283C325.9345,-256.0056 342.0793,-281.6949 365,-293 404.8598,-312.6598 424.0578,-310.2929 465,-293 486.6607,-283.8511 504.9784,-264.5049 517.5802,-248.0264"/>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M308.5491,-238.3283C317.4345,-256.0056 333.5793,-281.6949 356.5,-293 396.3598,-312.6598 415.5578,-310.2929 456.5,-293 478.1607,-283.8511 496.4784,-264.5049 509.0802,-248.0264"/>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="#fff8dc" stroke="#000000" points="247.522,-248 120.478,-248 120.478,-192 253.522,-192 253.522,-242 247.522,-248"/>
<polyline fill="none" stroke="#000000" points="247.522,-248 247.522,-242 "/>
<polyline fill="none" stroke="#000000" points="253.522,-242 247.522,-242 "/>
<text text-anchor="middle" x="187" y="-235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Creates an GEN3PLUS</text>
<text text-anchor="middle" x="187" y="-223" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter instance</text>
<text text-anchor="middle" x="187" y="-211" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">with</text>
<text text-anchor="middle" x="187" y="-199" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:SolarmanV5</text>
<polygon fill="#fff8dc" stroke="#000000" points="239.022,-248 111.978,-248 111.978,-192 245.022,-192 245.022,-242 239.022,-248"/>
<polyline fill="none" stroke="#000000" points="239.022,-248 239.022,-242 "/>
<polyline fill="none" stroke="#000000" points="245.022,-242 239.022,-242 "/>
<text text-anchor="middle" x="178.5" y="-235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Creates an GEN3PLUS</text>
<text text-anchor="middle" x="178.5" y="-223" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter instance</text>
<text text-anchor="middle" x="178.5" y="-211" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">with</text>
<text text-anchor="middle" x="178.5" y="-199" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_class:SolarmanV5</text>
</g>
<!-- A9&#45;&gt;A10 -->
<g id="edge4" class="edge">
<title>A9&#45;&gt;A10</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M103.0156,-220C108.8114,-220 114.6072,-220 120.403,-220"/>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M94.5156,-220C100.3114,-220 106.1072,-220 111.903,-220"/>
</g>
<!-- A12&#45;&gt;A11 -->
<g id="edge12" class="edge">
<title>A12&#45;&gt;A11</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M444.7291,-85.7616C439.4033,-74.0176 432.3824,-58.5355 426.396,-45.3349"/>
<polygon fill="#000000" stroke="#000000" points="422.259,-36.2121 430.4874,-43.4608 424.324,-40.7657 426.3891,-45.3194 426.3891,-45.3194 426.3891,-45.3194 424.324,-40.7657 422.2908,-47.1779 422.259,-36.2121 422.259,-36.2121"/>
<text text-anchor="middle" x="429.5451" y="-69.7445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M436.2291,-85.7616C430.9033,-74.0176 423.8824,-58.5355 417.896,-45.3349"/>
<polygon fill="#000000" stroke="#000000" points="413.759,-36.2121 421.9874,-43.4608 415.824,-40.7657 417.8891,-45.3194 417.8891,-45.3194 417.8891,-45.3194 415.824,-40.7657 413.7908,-47.1779 413.759,-36.2121 413.759,-36.2121"/>
<text text-anchor="middle" x="421.0451" y="-69.7445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
</g>
<!-- A13 -->
<g id="node14" class="node">
<title>A13</title>
<polygon fill="none" stroke="#000000" points="9,-454 9,-486 116,-486 116,-454 9,-454"/>
<text text-anchor="start" x="32.7695" y="-467" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusConn</text>
<polygon fill="none" stroke="#000000" points="9,-386 9,-454 116,-454 116,-386 9,-386"/>
<text text-anchor="start" x="53.0515" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">host</text>
<text text-anchor="start" x="53.887" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">port</text>
<text text-anchor="start" x="52.497" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="18.883" y="-399" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:InverterG3P</text>
<polygon fill="none" stroke="#000000" points="9,-366 9,-386 116,-386 116,-366 9,-366"/>
<polygon fill="none" stroke="#000000" points=".5,-454 .5,-486 107.5,-486 107.5,-454 .5,-454"/>
<text text-anchor="start" x="24.2695" y="-467" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusConn</text>
<polygon fill="none" stroke="#000000" points=".5,-386 .5,-454 107.5,-454 107.5,-386 .5,-386"/>
<text text-anchor="start" x="44.5515" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">host</text>
<text text-anchor="start" x="45.387" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">port</text>
<text text-anchor="start" x="43.997" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="10.383" y="-399" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:InverterG3P</text>
<polygon fill="none" stroke="#000000" points=".5,-366 .5,-386 107.5,-386 107.5,-366 .5,-366"/>
</g>
<!-- A13&#45;&gt;A9 -->
<g id="edge13" class="edge">
<title>A13&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M62,-365.8625C62,-327.1513 62,-278.6088 62,-248.4442"/>
<polygon fill="#000000" stroke="#000000" points="62,-238.2147 66.5001,-248.2147 62,-243.2147 62.0001,-248.2147 62.0001,-248.2147 62.0001,-248.2147 62,-243.2147 57.5001,-248.2148 62,-238.2147 62,-238.2147"/>
<text text-anchor="middle" x="70.4524" y="-253.3409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
<text text-anchor="middle" x="53.5476" y="-344.7363" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
<path fill="none" stroke="#000000" d="M53.5,-365.8625C53.5,-327.1513 53.5,-278.6088 53.5,-248.4442"/>
<polygon fill="#000000" stroke="#000000" points="53.5,-238.2147 58.0001,-248.2147 53.5,-243.2147 53.5001,-248.2147 53.5001,-248.2147 53.5001,-248.2147 53.5,-243.2147 49.0001,-248.2148 53.5,-238.2147 53.5,-238.2147"/>
<text text-anchor="middle" x="61.9524" y="-253.3409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
<text text-anchor="middle" x="45.0476" y="-344.7363" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
</g>
<!-- A14 -->
<g id="node15" class="node">
<title>A14</title>
<polygon fill="none" stroke="#000000" points="0,-714 0,-746 124,-746 124,-714 0,-714"/>
<text text-anchor="start" x="35.8835" y="-727" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusTcp</text>
<polygon fill="none" stroke="#000000" points="0,-694 0,-714 124,-714 124,-694 0,-694"/>
<polygon fill="none" stroke="#000000" points="0,-662 0,-694 124,-694 124,-662 0,-662"/>
<text text-anchor="start" x="9.763" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;modbus_loop()</text>
<polygon fill="none" stroke="#000000" points="93.7333,-722 13.2667,-722 13.2667,-686 93.7333,-686 93.7333,-722"/>
<text text-anchor="middle" x="53.5" y="-701" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusTcp</text>
</g>
<!-- A14&#45;&gt;A13 -->
<g id="edge14" class="edge">
<title>A14&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M62,-661.7778C62,-617.9184 62,-548.5387 62,-496.3736"/>
<polygon fill="#000000" stroke="#000000" points="62,-486.1827 66.5001,-496.1827 62,-491.1827 62.0001,-496.1827 62.0001,-496.1827 62.0001,-496.1827 62,-491.1827 57.5001,-496.1828 62,-486.1827 62,-486.1827"/>
<text text-anchor="middle" x="70.4524" y="-501.3089" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">*</text>
<text text-anchor="middle" x="53.5476" y="-640.6516" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">creates</text>
<path fill="none" stroke="#000000" d="M53.5,-685.7596C53.5,-647.9991 53.5,-559.5189 53.5,-496.3277"/>
<polygon fill="#000000" stroke="#000000" points="53.5,-486.0223 58.0001,-496.0223 53.5,-491.0223 53.5001,-496.0223 53.5001,-496.0223 53.5001,-496.0223 53.5,-491.0223 49.0001,-496.0224 53.5,-486.0223 53.5,-486.0223"/>
<text text-anchor="middle" x="61.9524" y="-501.1485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">*</text>
<text text-anchor="middle" x="45.0476" y="-664.6335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">creates</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -32,5 +32,5 @@
[ModbusConn|host;port;addr;stream:InverterG3P;|]has-1>[InverterG3P]
[ModbusTcp||<async>modbus_loop()]creates-*>[ModbusConn]
[ModbusTcp]creates-*>[ModbusConn]

View File

@@ -4,380 +4,371 @@
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="548pt" height="2000pt"
viewBox="0.00 0.00 548.12 2000.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1996)">
<svg width="539pt" height="2036pt"
viewBox="0.00 0.00 538.57 2036.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 2032)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1996 544.1155,-1996 544.1155,4 -4,4"/>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-2032 534.566,-2032 534.566,4 -4,4"/>
<!-- A0 -->
<g id="node1" class="node">
<title>A0</title>
<polygon fill="#fff8dc" stroke="#000000" points="239.7476,-1972 141.4834,-1972 141.4834,-1928 245.7476,-1928 245.7476,-1966 239.7476,-1972"/>
<polyline fill="none" stroke="#000000" points="239.7476,-1972 239.7476,-1966 "/>
<polyline fill="none" stroke="#000000" points="245.7476,-1966 239.7476,-1966 "/>
<text text-anchor="middle" x="193.6155" y="-1959" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
<text text-anchor="middle" x="193.6155" y="-1947" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
<text text-anchor="middle" x="193.6155" y="-1935" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3 inverter!</text>
<polygon fill="#fff8dc" stroke="#000000" points="98.1981,-2008 -.0661,-2008 -.0661,-1964 104.1981,-1964 104.1981,-2002 98.1981,-2008"/>
<polyline fill="none" stroke="#000000" points="98.1981,-2008 98.1981,-2002 "/>
<polyline fill="none" stroke="#000000" points="104.1981,-2002 98.1981,-2002 "/>
<text text-anchor="middle" x="52.066" y="-1995" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
<text text-anchor="middle" x="52.066" y="-1983" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
<text text-anchor="middle" x="52.066" y="-1971" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3 inverter!</text>
</g>
<!-- A1 -->
<g id="node2" class="node">
<title>A1</title>
<polygon fill="none" stroke="#000000" points="263.6155,-1960 263.6155,-1992 379.6155,-1992 379.6155,-1960 263.6155,-1960"/>
<text text-anchor="start" x="273.2645" y="-1973" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="263.6155,-1940 263.6155,-1960 379.6155,-1960 379.6155,-1940 263.6155,-1940"/>
<polygon fill="none" stroke="#000000" points="263.6155,-1908 263.6155,-1940 379.6155,-1940 379.6155,-1908 263.6155,-1908"/>
<text text-anchor="start" x="300.2255" y="-1921" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
</g>
<!-- A15 -->
<g id="node16" class="node">
<title>A15</title>
<polygon fill="none" stroke="#000000" points="276.6155,-1748 276.6155,-1780 366.6155,-1780 366.6155,-1748 276.6155,-1748"/>
<text text-anchor="start" x="286.322" y="-1761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="276.6155,-1716 276.6155,-1748 366.6155,-1748 366.6155,-1716 276.6155,-1716"/>
<text text-anchor="start" x="302.449" y="-1729" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<polygon fill="none" stroke="#000000" points="276.6155,-1684 276.6155,-1716 366.6155,-1716 366.6155,-1684 276.6155,-1684"/>
<text text-anchor="start" x="306.618" y="-1697" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A1&#45;&gt;A15 -->
<g id="edge15" class="edge">
<title>A1&#45;&gt;A15</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M321.6155,-1897.756C321.6155,-1862.0883 321.6155,-1815.1755 321.6155,-1780.3644"/>
<polygon fill="none" stroke="#000000" points="318.1156,-1897.9674 321.6155,-1907.9674 325.1156,-1897.9674 318.1156,-1897.9674"/>
</g>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="77.6155,-662 77.6155,-694 175.6155,-694 175.6155,-662 77.6155,-662"/>
<text text-anchor="start" x="98.2755" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
<polygon fill="none" stroke="#000000" points="77.6155,-606 77.6155,-662 175.6155,-662 175.6155,-606 77.6155,-606"/>
<text text-anchor="start" x="116.6125" y="-643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="87.1685" y="-631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="92.4475" y="-619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="77.6155,-550 77.6155,-606 175.6155,-606 175.6155,-550 77.6155,-550"/>
<text text-anchor="start" x="91.0575" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
<text text-anchor="start" x="111.618" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="75.3469,-320 -.1159,-320 -.1159,-284 75.3469,-284 75.3469,-320"/>
<text text-anchor="middle" x="37.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
</g>
<!-- A2&#45;&gt;A3 -->
<g id="edge1" class="edge">
<title>A2&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M103.8,-539.9668C83.1352,-465.6664 54.2132,-361.677 42.6665,-320.1609"/>
<polygon fill="none" stroke="#000000" points="100.4796,-541.0903 106.5312,-549.7868 107.2236,-539.2146 100.4796,-541.0903"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="189.9521,-320 93.2789,-320 93.2789,-284 189.9521,-284 189.9521,-320"/>
<text text-anchor="middle" x="141.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A4 -->
<g id="edge2" class="edge">
<title>A2&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M130.5679,-537.6831C133.7849,-469.0527 138.1335,-376.283 140.2896,-330.2853"/>
<polygon fill="#000000" stroke="#000000" points="130.5625,-537.7999 134.2771,-543.9807 130.0005,-549.7868 126.2859,-543.606 130.5625,-537.7999"/>
<polygon fill="#000000" stroke="#000000" points="140.7642,-320.1609 144.7909,-330.3606 140.53,-325.1554 140.2959,-330.1499 140.2959,-330.1499 140.2959,-330.1499 140.53,-325.1554 135.8008,-329.9391 140.7642,-320.1609 140.7642,-320.1609"/>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="315.0096,-320 208.2214,-320 208.2214,-284 315.0096,-284 315.0096,-320"/>
<text text-anchor="middle" x="261.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A5 -->
<g id="edge3" class="edge">
<title>A2&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M157.861,-538.7126C166.3035,-516.9056 175.6035,-493.4873 184.6155,-472 205.944,-421.1467 232.9474,-362.7699 248.6524,-329.3512"/>
<polygon fill="#000000" stroke="#000000" points="157.8454,-538.7533 159.4203,-545.7903 153.5304,-549.9506 151.9554,-542.9136 157.8454,-538.7533"/>
<polygon fill="#000000" stroke="#000000" points="252.9567,-320.2155 252.7653,-331.1797 250.8256,-324.7387 248.6945,-329.2618 248.6945,-329.2618 248.6945,-329.2618 250.8256,-324.7387 244.6237,-327.3438 252.9567,-320.2155 252.9567,-320.2155"/>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="none" stroke="#000000" points="128.6155,-100 128.6155,-132 306.6155,-132 306.6155,-100 128.6155,-100"/>
<text text-anchor="start" x="173.167" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
<polygon fill="none" stroke="#000000" points="128.6155,-68 128.6155,-100 306.6155,-100 306.6155,-68 128.6155,-68"/>
<text text-anchor="start" x="185.3865" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
<polygon fill="none" stroke="#000000" points="128.6155,0 128.6155,-68 306.6155,-68 306.6155,0 128.6155,0"/>
<text text-anchor="start" x="169.273" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;server_loop()</text>
<text text-anchor="start" x="160.104" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward()</text>
<text text-anchor="start" x="138.4245" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish_outstanding_mqtt()</text>
<text text-anchor="start" x="202.618" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A4&#45;&gt;A9 -->
<g id="edge9" class="edge">
<title>A4&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M151.2355,-272.1274C161.7441,-239.4955 178.9835,-185.9626 193.26,-141.6303"/>
<polygon fill="#000000" stroke="#000000" points="151.1313,-272.451 153.0996,-279.3883 147.4529,-283.8733 145.4847,-276.936 151.1313,-272.451"/>
<polygon fill="#000000" stroke="#000000" points="196.3509,-132.0321 197.5689,-142.9302 194.8182,-136.7914 193.2855,-141.5507 193.2855,-141.5507 193.2855,-141.5507 194.8182,-136.7914 189.0022,-140.1713 196.3509,-132.0321 196.3509,-132.0321"/>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="none" stroke="#000000" points="362.6155,-82 362.6155,-114 500.6155,-114 500.6155,-82 362.6155,-82"/>
<text text-anchor="start" x="389.1125" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
<polygon fill="none" stroke="#000000" points="362.6155,-62 362.6155,-82 500.6155,-82 500.6155,-62 362.6155,-62"/>
<polygon fill="none" stroke="#000000" points="362.6155,-18 362.6155,-62 500.6155,-62 500.6155,-18 362.6155,-18"/>
<text text-anchor="start" x="385.4935" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;client_loop()</text>
<text text-anchor="start" x="372.4395" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward())</text>
</g>
<!-- A5&#45;&gt;A10 -->
<g id="edge11" class="edge">
<title>A5&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M269.2148,-283.6405C279.6962,-259.3121 299.996,-215.5582 323.6155,-182 338.3046,-161.1299 356.5265,-140.1557 373.793,-121.8925"/>
<polygon fill="#000000" stroke="#000000" points="381.1214,-114.2395 377.4553,-124.5745 377.6632,-117.8508 374.2051,-121.4621 374.2051,-121.4621 374.2051,-121.4621 377.6632,-117.8508 370.9549,-118.3498 381.1214,-114.2395 381.1214,-114.2395"/>
<text text-anchor="middle" x="268.7308" y="-260.6464" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="396.6155,-1114 396.6155,-1146 513.6155,-1146 513.6155,-1114 396.6155,-1114"/>
<text text-anchor="start" x="424.5445" y="-1127" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="396.6155,-1094 396.6155,-1114 513.6155,-1114 513.6155,-1094 396.6155,-1094"/>
<polygon fill="none" stroke="#000000" points="396.6155,-822 396.6155,-1094 513.6155,-1094 513.6155,-822 396.6155,-822"/>
<text text-anchor="start" x="424.5515" y="-1075" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
<text text-anchor="start" x="422.8815" y="-1063" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
<text text-anchor="start" x="436.779" y="-1039" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
<text text-anchor="start" x="434.5595" y="-1027" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
<text text-anchor="start" x="438.169" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
<text text-anchor="start" x="434.279" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
<text text-anchor="start" x="438.449" y="-991" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
<text text-anchor="start" x="434.2845" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
<text text-anchor="start" x="438.449" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
<text text-anchor="start" x="432.89" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
<text text-anchor="start" x="434.56" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
<text text-anchor="start" x="437.894" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
<text text-anchor="start" x="434.004" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
<text text-anchor="start" x="438.174" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
<text text-anchor="start" x="434.0095" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
<text text-anchor="start" x="438.174" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
<text text-anchor="start" x="430.1145" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
<text text-anchor="start" x="406.495" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="447.6155,-652 447.6155,-684 540.6155,-684 540.6155,-652 447.6155,-652"/>
<text text-anchor="start" x="465.7795" y="-665" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
<polygon fill="none" stroke="#000000" points="447.6155,-560 447.6155,-652 540.6155,-652 540.6155,-560 447.6155,-560"/>
<text text-anchor="start" x="457.1635" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
<text text-anchor="start" x="461.0525" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
<text text-anchor="start" x="460.7775" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
<text text-anchor="start" x="460.2115" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
<text text-anchor="start" x="476.329" y="-585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="469.665" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
</g>
<!-- A6&#45;&gt;A7 -->
<g id="edge4" class="edge">
<title>A6&#45;&gt;A7</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M473.1735,-811.7434C478.1009,-766.0069 483.1088,-719.5241 486.9345,-684.013"/>
<polygon fill="none" stroke="#000000" points="469.682,-811.4771 472.0907,-821.7945 476.6418,-812.227 469.682,-811.4771"/>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="none" stroke="#000000" points="418.6155,-390 418.6155,-422 520.6155,-422 520.6155,-390 418.6155,-390"/>
<text text-anchor="start" x="439.8895" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
<polygon fill="none" stroke="#000000" points="418.6155,-310 418.6155,-390 520.6155,-390 520.6155,-310 418.6155,-310"/>
<text text-anchor="start" x="455.1685" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
<text text-anchor="start" x="457.3985" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
<text text-anchor="start" x="459.6125" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="455.1685" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
<text text-anchor="start" x="455.7235" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
<polygon fill="none" stroke="#000000" points="418.6155,-182 418.6155,-310 520.6155,-310 520.6155,-182 418.6155,-182"/>
<text text-anchor="start" x="441.2695" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;loop</text>
<text text-anchor="start" x="457.3975" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
<text text-anchor="start" x="454.618" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="450.1695" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="434.886" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
<text text-anchor="start" x="434.3365" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
<text text-anchor="start" x="428.2225" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge5" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M488.1838,-549.5774C485.3646,-511.9877 481.8463,-465.0771 478.6327,-422.2295"/>
<polygon fill="none" stroke="#000000" points="484.7214,-550.2112 488.9596,-559.9214 491.7018,-549.6876 484.7214,-550.2112"/>
</g>
<!-- A8&#45;&gt;A9 -->
<g id="edge6" class="edge">
<title>A8&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M412.0877,-185.8777C410.9473,-184.56 409.7899,-183.2666 408.6155,-182 380.1271,-151.2753 341.6819,-125.829 306.7513,-106.6759"/>
<polygon fill="none" stroke="#000000" points="409.4058,-188.1271 418.4338,-193.672 414.834,-183.7074 409.4058,-188.1271"/>
</g>
<!-- A8&#45;&gt;A10 -->
<g id="edge7" class="edge">
<title>A8&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M448.6523,-171.8077C445.3431,-151.2556 442.1142,-131.2022 439.3729,-114.1772"/>
<polygon fill="none" stroke="#000000" points="445.2363,-172.6095 450.2815,-181.9259 452.1472,-171.4966 445.2363,-172.6095"/>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="none" stroke="#000000" points="193.6155,-740 193.6155,-772 307.6155,-772 307.6155,-740 193.6155,-740"/>
<text text-anchor="start" x="236.7235" y="-753" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
<polygon fill="none" stroke="#000000" points="193.6155,-600 193.6155,-740 307.6155,-740 307.6155,-600 193.6155,-600"/>
<text text-anchor="start" x="231.4385" y="-721" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
<text text-anchor="start" x="240.6125" y="-709" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="203.3785" y="-685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
<text text-anchor="start" x="238.393" y="-673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
<text text-anchor="start" x="219.2155" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
<text text-anchor="start" x="222.5555" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
<text text-anchor="start" x="226.16" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
<text text-anchor="start" x="224.4995" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="236.7275" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
<polygon fill="none" stroke="#000000" points="193.6155,-472 193.6155,-600 307.6155,-600 307.6155,-472 193.6155,-472"/>
<text text-anchor="start" x="208.108" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
<text text-anchor="start" x="210.048" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
<text text-anchor="start" x="215.892" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
<text text-anchor="start" x="203.944" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
<text text-anchor="start" x="205.889" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
<text text-anchor="start" x="215.056" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
<text text-anchor="start" x="231.1695" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="235.618" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A11&#45;&gt;A4 -->
<g id="edge8" class="edge">
<title>A11&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M196.2254,-462.3225C179.1579,-412.2162 162.0761,-362.0677 151.6753,-331.5332"/>
<polygon fill="#000000" stroke="#000000" points="199.4666,-471.8382 191.9826,-463.8233 197.8544,-467.1053 196.2422,-462.3723 196.2422,-462.3723 196.2422,-462.3723 197.8544,-467.1053 200.5019,-460.9213 199.4666,-471.8382 199.4666,-471.8382"/>
<polygon fill="#000000" stroke="#000000" points="151.6435,-331.4398 145.9225,-327.05 147.7742,-320.0807 153.4952,-324.4705 151.6435,-331.4398"/>
</g>
<!-- A11&#45;&gt;A5 -->
<g id="edge10" class="edge">
<title>A11&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M256.1287,-461.6172C258.0803,-404.8425 260.0297,-348.132 260.994,-320.0807"/>
<polygon fill="#000000" stroke="#000000" points="255.7773,-471.8382 251.6236,-461.6895 255.9491,-466.8412 256.121,-461.8441 256.121,-461.8441 256.121,-461.8441 255.9491,-466.8412 260.6183,-461.9988 255.7773,-471.8382 255.7773,-471.8382"/>
<text text-anchor="middle" x="268.8186" y="-335.4866" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A13 -->
<g id="node14" class="node">
<title>A13</title>
<polygon fill="none" stroke="#000000" points="333.6155,-318 333.6155,-350 400.6155,-350 400.6155,-318 333.6155,-318"/>
<text text-anchor="start" x="349.6085" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
<polygon fill="none" stroke="#000000" points="333.6155,-298 333.6155,-318 400.6155,-318 400.6155,-298 333.6155,-298"/>
<polygon fill="none" stroke="#000000" points="333.6155,-254 333.6155,-298 400.6155,-298 400.6155,-254 333.6155,-254"/>
<text text-anchor="start" x="343.4995" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
<text text-anchor="start" x="351.2835" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
</g>
<!-- A11&#45;&gt;A13 -->
<g id="edge13" class="edge">
<title>A11&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M305.5203,-471.8728C311.6394,-455.0532 317.7699,-438.1631 323.6155,-422 330.9569,-401.7009 338.9463,-379.4498 346.0242,-359.681"/>
<polygon fill="#000000" stroke="#000000" points="349.4187,-350.1951 350.2862,-361.1266 347.734,-354.9028 346.0494,-359.6104 346.0494,-359.6104 346.0494,-359.6104 347.734,-354.9028 341.8125,-358.0942 349.4187,-350.1951 349.4187,-350.1951"/>
</g>
<!-- A12 -->
<g id="node13" class="node">
<title>A12</title>
<polygon fill="none" stroke="#000000" points="326.6155,-710 326.6155,-742 429.6155,-742 429.6155,-710 326.6155,-710"/>
<text text-anchor="start" x="367.2775" y="-723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
<polygon fill="none" stroke="#000000" points="326.6155,-654 326.6155,-710 429.6155,-710 429.6155,-654 326.6155,-654"/>
<text text-anchor="start" x="370.057" y="-691" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
<text text-anchor="start" x="345.6015" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
<text text-anchor="start" x="359.219" y="-667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
<polygon fill="none" stroke="#000000" points="326.6155,-502 326.6155,-654 429.6155,-654 429.6155,-502 326.6155,-502"/>
<text text-anchor="start" x="353.951" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
<text text-anchor="start" x="352" y="-623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
<text text-anchor="start" x="348.946" y="-611" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="347.276" y="-599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<text text-anchor="start" x="345.3255" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
<text text-anchor="start" x="360.3285" y="-575" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
<text text-anchor="start" x="353.1095" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
<text text-anchor="start" x="354.49" y="-551" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
<text text-anchor="start" x="338.6525" y="-539" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
<text text-anchor="start" x="348.101" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
<text text-anchor="start" x="336.438" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
</g>
<!-- A12&#45;&gt;A13 -->
<g id="edge12" class="edge">
<title>A12&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M373.1357,-491.6786C371.4196,-441.7544 369.5661,-387.8351 368.2756,-350.293"/>
<polygon fill="none" stroke="#000000" points="369.6466,-492.0596 373.4882,-501.9334 376.6425,-491.819 369.6466,-492.0596"/>
<polygon fill="none" stroke="#000000" points="122.066,-1996 122.066,-2028 238.066,-2028 238.066,-1996 122.066,-1996"/>
<text text-anchor="start" x="131.715" y="-2009" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="122.066,-1976 122.066,-1996 238.066,-1996 238.066,-1976 122.066,-1976"/>
<polygon fill="none" stroke="#000000" points="122.066,-1944 122.066,-1976 238.066,-1976 238.066,-1944 122.066,-1944"/>
<text text-anchor="start" x="158.676" y="-1957" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
</g>
<!-- A14 -->
<g id="node15" class="node">
<title>A14</title>
<polygon fill="none" stroke="#000000" points="297.6155,-1524 297.6155,-1556 446.6155,-1556 446.6155,-1524 297.6155,-1524"/>
<text text-anchor="start" x="351.833" y="-1537" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
<polygon fill="none" stroke="#000000" points="297.6155,-1300 297.6155,-1524 446.6155,-1524 446.6155,-1300 297.6155,-1300"/>
<text text-anchor="start" x="335.442" y="-1505" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
<text text-anchor="start" x="345.9995" y="-1493" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="346.834" y="-1481" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
<text text-anchor="start" x="354.329" y="-1469" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="332.6585" y="-1457" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
<text text-anchor="start" x="347.1055" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
<text text-anchor="start" x="352.9395" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
<text text-anchor="start" x="350.44" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
<text text-anchor="start" x="344.3305" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
<text text-anchor="start" x="341.2715" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
<text text-anchor="start" x="348.2155" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
<text text-anchor="start" x="321.82" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
<text text-anchor="start" x="341" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
<text text-anchor="start" x="337.1225" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
<text text-anchor="start" x="346.0005" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
<text text-anchor="start" x="335.168" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
<text text-anchor="start" x="326.2695" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
<polygon fill="none" stroke="#000000" points="297.6155,-1196 297.6155,-1300 446.6155,-1300 446.6155,-1196 297.6155,-1196"/>
<text text-anchor="start" x="321" y="-1281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
<text text-anchor="start" x="349.6155" y="-1269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
<text text-anchor="start" x="322.383" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
<text text-anchor="start" x="307.375" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt; end_modbus_cmd()</text>
<text text-anchor="start" x="357.118" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="342.946" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="341.276" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<polygon fill="none" stroke="#000000" points="135.066,-1784 135.066,-1816 225.066,-1816 225.066,-1784 135.066,-1784"/>
<text text-anchor="start" x="144.7725" y="-1797" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="135.066,-1752 135.066,-1784 225.066,-1784 225.066,-1752 135.066,-1752"/>
<text text-anchor="start" x="160.8995" y="-1765" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<polygon fill="none" stroke="#000000" points="135.066,-1720 135.066,-1752 225.066,-1752 225.066,-1720 135.066,-1720"/>
<text text-anchor="start" x="165.0685" y="-1733" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A14&#45;&gt;A6 -->
<!-- A1&#45;&gt;A14 -->
<g id="edge14" class="edge">
<title>A14&#45;&gt;A6</title>
<path fill="none" stroke="#000000" d="M409.7752,-1195.7758C412.5746,-1182.5547 415.3943,-1169.2373 418.1831,-1156.0662"/>
<polygon fill="#000000" stroke="#000000" points="420.3088,-1146.0268 422.6397,-1156.7421 419.2731,-1150.9183 418.2373,-1155.8099 418.2373,-1155.8099 418.2373,-1155.8099 419.2731,-1150.9183 413.8349,-1154.8777 420.3088,-1146.0268 420.3088,-1146.0268"/>
<text text-anchor="middle" x="405.2609" y="-1173.292" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
<title>A1&#45;&gt;A14</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M180.066,-1933.756C180.066,-1898.0883 180.066,-1851.1755 180.066,-1816.3644"/>
<polygon fill="none" stroke="#000000" points="176.5661,-1933.9674 180.066,-1943.9674 183.5661,-1933.9674 176.5661,-1933.9674"/>
</g>
<!-- A14&#45;&gt;A11 -->
<g id="edge17" class="edge">
<title>A14&#45;&gt;A11</title>
<path fill="none" stroke="#000000" d="M341.1152,-1185.9405C320.5475,-1057.7747 293.7865,-891.0162 274.7116,-772.1524"/>
<polygon fill="none" stroke="#000000" points="337.6695,-1186.5583 342.7099,-1195.8774 344.5811,-1185.4491 337.6695,-1186.5583"/>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="179.066,-662 179.066,-694 277.066,-694 277.066,-662 179.066,-662"/>
<text text-anchor="start" x="204.4505" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
<polygon fill="none" stroke="#000000" points="179.066,-606 179.066,-662 277.066,-662 277.066,-606 179.066,-606"/>
<text text-anchor="start" x="218.063" y="-643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="188.619" y="-631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="193.898" y="-619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="179.066,-550 179.066,-606 277.066,-606 277.066,-550 179.066,-550"/>
<text text-anchor="start" x="192.508" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
<text text-anchor="start" x="213.0685" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A15&#45;&gt;A14 -->
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="400.4026,-320 303.7294,-320 303.7294,-284 400.4026,-284 400.4026,-320"/>
<text text-anchor="middle" x="352.066" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A3 -->
<g id="edge1" class="edge">
<title>A2&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M260.3657,-538.4062C268.7304,-516.7744 277.7293,-493.5168 286.066,-472 305.502,-421.8362 328.2143,-363.368 341.2906,-329.7205"/>
<polygon fill="#000000" stroke="#000000" points="260.2523,-538.6998 261.8194,-545.7386 255.9247,-549.8923 254.3577,-542.8536 260.2523,-538.6998"/>
<polygon fill="#000000" stroke="#000000" points="345.0251,-320.1117 345.5968,-331.0627 343.2138,-324.7721 341.4024,-329.4325 341.4024,-329.4325 341.4024,-329.4325 343.2138,-324.7721 337.2081,-327.8023 345.0251,-320.1117 345.0251,-320.1117"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="285.4601,-320 178.6719,-320 178.6719,-284 285.4601,-284 285.4601,-320"/>
<text text-anchor="middle" x="232.066" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A4 -->
<g id="edge2" class="edge">
<title>A2&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M229.12,-537.6831C229.9778,-469.0527 231.1375,-376.283 231.7124,-330.2853"/>
<polygon fill="#000000" stroke="#000000" points="229.1188,-537.7877 233.0434,-543.8372 228.9687,-549.7868 225.044,-543.7372 229.1188,-537.7877"/>
<polygon fill="#000000" stroke="#000000" points="231.839,-320.1609 236.2135,-330.2164 231.7764,-325.1605 231.7139,-330.1601 231.7139,-330.1601 231.7139,-330.1601 231.7764,-325.1605 227.2143,-330.1038 231.839,-320.1609 231.839,-320.1609"/>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="none" stroke="#000000" points="246.066,-100 246.066,-132 424.066,-132 424.066,-100 246.066,-100"/>
<text text-anchor="start" x="290.6175" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
<polygon fill="none" stroke="#000000" points="246.066,-68 246.066,-100 424.066,-100 424.066,-68 246.066,-68"/>
<text text-anchor="start" x="302.837" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
<polygon fill="none" stroke="#000000" points="246.066,0 246.066,-68 424.066,-68 424.066,0 246.066,0"/>
<text text-anchor="start" x="286.7235" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;server_loop()</text>
<text text-anchor="start" x="277.5545" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward()</text>
<text text-anchor="start" x="255.875" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish_outstanding_mqtt()</text>
<text text-anchor="start" x="320.0685" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A3&#45;&gt;A8 -->
<g id="edge8" class="edge">
<title>A3&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M349.8809,-271.6651C347.5364,-239.1181 343.722,-186.1658 340.5509,-142.1431"/>
<polygon fill="#000000" stroke="#000000" points="349.898,-271.9044 354.3188,-277.6014 350.7603,-283.8733 346.3395,-278.1763 349.898,-271.9044"/>
<polygon fill="#000000" stroke="#000000" points="339.8226,-132.0321 345.0295,-141.6829 340.1818,-137.0192 340.5411,-142.0063 340.5411,-142.0063 340.5411,-142.0063 340.1818,-137.0192 336.0527,-142.3296 339.8226,-132.0321 339.8226,-132.0321"/>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="none" stroke="#000000" points="74.066,-82 74.066,-114 212.066,-114 212.066,-82 74.066,-82"/>
<text text-anchor="start" x="100.563" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
<polygon fill="none" stroke="#000000" points="74.066,-62 74.066,-82 212.066,-82 212.066,-62 74.066,-62"/>
<polygon fill="none" stroke="#000000" points="74.066,-18 74.066,-62 212.066,-62 212.066,-18 74.066,-18"/>
<text text-anchor="start" x="96.944" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;client_loop()</text>
<text text-anchor="start" x="83.89" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward())</text>
</g>
<!-- A4&#45;&gt;A9 -->
<g id="edge10" class="edge">
<title>A4&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M225.2301,-283.8733C212.4699,-250.0372 184.5329,-175.9573 164.7878,-123.5994"/>
<polygon fill="#000000" stroke="#000000" points="161.2018,-114.0904 168.941,-121.8593 162.9661,-118.7688 164.7305,-123.4472 164.7305,-123.4472 164.7305,-123.4472 162.9661,-118.7688 160.5199,-125.0351 161.2018,-114.0904 161.2018,-114.0904"/>
<text text-anchor="middle" x="210.9254" y="-266.8956" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="129.066,-1114 129.066,-1146 246.066,-1146 246.066,-1114 129.066,-1114"/>
<text text-anchor="start" x="156.995" y="-1127" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="129.066,-1094 129.066,-1114 246.066,-1114 246.066,-1094 129.066,-1094"/>
<polygon fill="none" stroke="#000000" points="129.066,-822 129.066,-1094 246.066,-1094 246.066,-822 129.066,-822"/>
<text text-anchor="start" x="157.002" y="-1075" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
<text text-anchor="start" x="155.332" y="-1063" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
<text text-anchor="start" x="169.2295" y="-1039" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
<text text-anchor="start" x="167.01" y="-1027" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
<text text-anchor="start" x="170.6195" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
<text text-anchor="start" x="166.7295" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
<text text-anchor="start" x="170.8995" y="-991" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
<text text-anchor="start" x="166.735" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
<text text-anchor="start" x="170.8995" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
<text text-anchor="start" x="165.3405" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
<text text-anchor="start" x="167.0105" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
<text text-anchor="start" x="170.3445" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
<text text-anchor="start" x="166.4545" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
<text text-anchor="start" x="170.6245" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
<text text-anchor="start" x="166.46" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
<text text-anchor="start" x="170.6245" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
<text text-anchor="start" x="162.565" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
<text text-anchor="start" x="138.9455" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="66.066,-652 66.066,-684 159.066,-684 159.066,-652 66.066,-652"/>
<text text-anchor="start" x="84.23" y="-665" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
<polygon fill="none" stroke="#000000" points="66.066,-560 66.066,-652 159.066,-652 159.066,-560 66.066,-560"/>
<text text-anchor="start" x="75.614" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
<text text-anchor="start" x="79.503" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
<text text-anchor="start" x="79.228" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
<text text-anchor="start" x="78.662" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
<text text-anchor="start" x="94.7795" y="-585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="88.1155" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
</g>
<!-- A5&#45;&gt;A6 -->
<g id="edge3" class="edge">
<title>A5&#45;&gt;A6</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M151.3775,-811.7434C141.9017,-766.0069 132.2713,-719.5241 124.914,-684.013"/>
<polygon fill="none" stroke="#000000" points="148.0039,-812.7126 153.4599,-821.7945 154.8583,-811.2924 148.0039,-812.7126"/>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="59.066,-390 59.066,-422 161.066,-422 161.066,-390 59.066,-390"/>
<text text-anchor="start" x="80.34" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
<polygon fill="none" stroke="#000000" points="59.066,-310 59.066,-390 161.066,-390 161.066,-310 59.066,-310"/>
<text text-anchor="start" x="95.619" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
<text text-anchor="start" x="97.849" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
<text text-anchor="start" x="100.063" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="95.619" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
<text text-anchor="start" x="96.174" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
<polygon fill="none" stroke="#000000" points="59.066,-182 59.066,-310 161.066,-310 161.066,-182 59.066,-182"/>
<text text-anchor="start" x="81.72" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;loop</text>
<text text-anchor="start" x="97.848" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
<text text-anchor="start" x="95.0685" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="90.62" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="75.3365" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
<text text-anchor="start" x="74.787" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
<text text-anchor="start" x="68.673" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
</g>
<!-- A6&#45;&gt;A7 -->
<g id="edge4" class="edge">
<title>A6&#45;&gt;A7</title>
<path fill="none" stroke="#000000" d="M111.6134,-549.5774C111.3784,-511.9877 111.0852,-465.0771 110.8174,-422.2295"/>
<polygon fill="none" stroke="#000000" points="108.1155,-549.9435 111.678,-559.9214 115.1153,-549.8996 108.1155,-549.9435"/>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge5" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M167.5272,-185.0204C168.3649,-184.0001 169.2111,-182.9929 170.066,-182 191.4283,-157.1889 219.1964,-135.0276 245.8416,-116.8901"/>
<polygon fill="none" stroke="#000000" points="164.637,-183.0361 161.2751,-193.0834 170.1688,-187.3255 164.637,-183.0361"/>
</g>
<!-- A7&#45;&gt;A9 -->
<g id="edge6" class="edge">
<title>A7&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M128.2709,-171.8077C131.1447,-151.2556 133.9487,-131.2022 136.3294,-114.1772"/>
<polygon fill="none" stroke="#000000" points="124.7747,-171.5375 126.856,-181.9259 131.7072,-172.5069 124.7747,-171.5375"/>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="none" stroke="#000000" points="295.066,-740 295.066,-772 409.066,-772 409.066,-740 295.066,-740"/>
<text text-anchor="start" x="338.174" y="-753" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
<polygon fill="none" stroke="#000000" points="295.066,-600 295.066,-740 409.066,-740 409.066,-600 295.066,-600"/>
<text text-anchor="start" x="332.889" y="-721" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
<text text-anchor="start" x="342.063" y="-709" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="304.829" y="-685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
<text text-anchor="start" x="339.8435" y="-673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
<text text-anchor="start" x="320.666" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
<text text-anchor="start" x="324.006" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
<text text-anchor="start" x="327.6105" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
<text text-anchor="start" x="325.95" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="338.178" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
<polygon fill="none" stroke="#000000" points="295.066,-472 295.066,-600 409.066,-600 409.066,-472 295.066,-472"/>
<text text-anchor="start" x="309.5585" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
<text text-anchor="start" x="311.4985" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
<text text-anchor="start" x="317.3425" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
<text text-anchor="start" x="305.3945" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
<text text-anchor="start" x="307.3395" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
<text text-anchor="start" x="316.5065" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
<text text-anchor="start" x="332.62" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="337.0685" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A10&#45;&gt;A3 -->
<g id="edge7" class="edge">
<title>A10&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M352.066,-461.6172C352.066,-412.1611 352.066,-362.7538 352.066,-332.2961"/>
<polygon fill="#000000" stroke="#000000" points="352.066,-471.8382 347.5661,-461.8382 352.066,-466.8382 352.0661,-461.8382 352.0661,-461.8382 352.0661,-461.8382 352.066,-466.8382 356.5661,-461.8383 352.066,-471.8382 352.066,-471.8382"/>
<polygon fill="#000000" stroke="#000000" points="352.0661,-332.0807 348.066,-326.0808 352.066,-320.0807 356.066,-326.0807 352.0661,-332.0807"/>
</g>
<!-- A10&#45;&gt;A4 -->
<g id="edge9" class="edge">
<title>A10&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M292.1869,-462.3225C270.8082,-405.3126 249.4091,-348.2482 238.8463,-320.0807"/>
<polygon fill="#000000" stroke="#000000" points="295.7553,-471.8382 288.0306,-464.055 293.9997,-467.1566 292.244,-462.4749 292.244,-462.4749 292.244,-462.4749 293.9997,-467.1566 296.4575,-460.8948 295.7553,-471.8382 295.7553,-471.8382"/>
<text text-anchor="middle" x="253.125" y="-331.0849" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A12 -->
<g id="node13" class="node">
<title>A12</title>
<polygon fill="none" stroke="#000000" points="432.066,-318 432.066,-350 499.066,-350 499.066,-318 432.066,-318"/>
<text text-anchor="start" x="448.059" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
<polygon fill="none" stroke="#000000" points="432.066,-298 432.066,-318 499.066,-318 499.066,-298 432.066,-298"/>
<polygon fill="none" stroke="#000000" points="432.066,-254 432.066,-298 499.066,-298 499.066,-254 432.066,-254"/>
<text text-anchor="start" x="441.95" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
<text text-anchor="start" x="449.734" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
</g>
<!-- A10&#45;&gt;A12 -->
<g id="edge12" class="edge">
<title>A10&#45;&gt;A12</title>
<path fill="none" stroke="#000000" d="M405.0919,-471.8382C419.1748,-431.9575 433.5466,-391.2585 444.6898,-359.7024"/>
<polygon fill="#000000" stroke="#000000" points="448.0405,-350.2137 448.9539,-361.1415 446.3756,-354.9284 444.7107,-359.6431 444.7107,-359.6431 444.7107,-359.6431 446.3756,-354.9284 440.4675,-358.1447 448.0405,-350.2137 448.0405,-350.2137"/>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="none" stroke="#000000" points="428.066,-710 428.066,-742 531.066,-742 531.066,-710 428.066,-710"/>
<text text-anchor="start" x="468.728" y="-723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
<polygon fill="none" stroke="#000000" points="428.066,-654 428.066,-710 531.066,-710 531.066,-654 428.066,-654"/>
<text text-anchor="start" x="471.5075" y="-691" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
<text text-anchor="start" x="447.052" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
<text text-anchor="start" x="460.6695" y="-667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
<polygon fill="none" stroke="#000000" points="428.066,-502 428.066,-654 531.066,-654 531.066,-502 428.066,-502"/>
<text text-anchor="start" x="455.4015" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
<text text-anchor="start" x="453.4505" y="-623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
<text text-anchor="start" x="450.3965" y="-611" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="448.7265" y="-599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<text text-anchor="start" x="446.776" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
<text text-anchor="start" x="461.779" y="-575" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
<text text-anchor="start" x="454.56" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
<text text-anchor="start" x="455.9405" y="-551" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
<text text-anchor="start" x="440.103" y="-539" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
<text text-anchor="start" x="449.5515" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
<text text-anchor="start" x="437.8885" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
</g>
<!-- A11&#45;&gt;A12 -->
<g id="edge11" class="edge">
<title>A11&#45;&gt;A12</title>
<path fill="none" stroke="#000000" d="M473.3644,-491.6786C471.1803,-441.7544 468.8213,-387.8351 467.1788,-350.293"/>
<polygon fill="none" stroke="#000000" points="469.8793,-492.0959 473.8131,-501.9334 476.8726,-491.7899 469.8793,-492.0959"/>
</g>
<!-- A13 -->
<g id="node14" class="node">
<title>A13</title>
<polygon fill="none" stroke="#000000" points="155.066,-1560 155.066,-1592 306.066,-1592 306.066,-1560 155.066,-1560"/>
<text text-anchor="start" x="210.2835" y="-1573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
<polygon fill="none" stroke="#000000" points="155.066,-1336 155.066,-1560 306.066,-1560 306.066,-1336 155.066,-1336"/>
<text text-anchor="start" x="193.8925" y="-1541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
<text text-anchor="start" x="204.45" y="-1529" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="205.2845" y="-1517" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
<text text-anchor="start" x="212.7795" y="-1505" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="191.109" y="-1493" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
<text text-anchor="start" x="205.556" y="-1481" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
<text text-anchor="start" x="211.39" y="-1469" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
<text text-anchor="start" x="208.8905" y="-1457" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
<text text-anchor="start" x="202.781" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
<text text-anchor="start" x="199.722" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
<text text-anchor="start" x="206.666" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
<text text-anchor="start" x="180.2705" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
<text text-anchor="start" x="199.4505" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
<text text-anchor="start" x="195.573" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
<text text-anchor="start" x="204.451" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
<text text-anchor="start" x="193.6185" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
<text text-anchor="start" x="184.72" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
<polygon fill="none" stroke="#000000" points="155.066,-1196 155.066,-1336 306.066,-1336 306.066,-1196 155.066,-1196"/>
<text text-anchor="start" x="169.447" y="-1317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_config_parms(inv:dict)</text>
<text text-anchor="start" x="165.0025" y="-1305" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp(key, ts)</text>
<text text-anchor="start" x="208.066" y="-1293" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
<text text-anchor="start" x="180.8335" y="-1281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
<text text-anchor="start" x="164.715" y="-1269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;send_modbus_cmd()</text>
<text text-anchor="start" x="179.7185" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_scan()</text>
<text text-anchor="start" x="178.054" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_dump_modbus_scan()</text>
<text text-anchor="start" x="215.5685" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="201.3965" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="199.7265" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
</g>
<!-- A13&#45;&gt;A5 -->
<g id="edge13" class="edge">
<title>A13&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M209.2902,-1195.9056C207.8967,-1182.6185 206.4991,-1169.2927 205.1209,-1156.1518"/>
<polygon fill="#000000" stroke="#000000" points="204.0712,-1146.1426 209.5898,-1155.6186 204.5928,-1151.1153 205.1143,-1156.0881 205.1143,-1156.0881 205.1143,-1156.0881 204.5928,-1151.1153 200.6389,-1156.5575 204.0712,-1146.1426 204.0712,-1146.1426"/>
<text text-anchor="middle" x="198.9933" y="-1175.7599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
</g>
<!-- A13&#45;&gt;A10 -->
<g id="edge16" class="edge">
<title>A15&#45;&gt;A14</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M329.7896,-1673.8004C334.3532,-1641.3079 340.3126,-1598.8764 346.2965,-1556.2713"/>
<polygon fill="none" stroke="#000000" points="326.2837,-1673.5986 328.3587,-1683.9883 333.2156,-1674.5723 326.2837,-1673.5986"/>
<title>A13&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M262.9659,-1185.8135C283.5931,-1055.2874 309.7059,-890.0494 328.3192,-772.2668"/>
<polygon fill="none" stroke="#000000" points="259.4691,-1185.519 261.3652,-1195.9428 266.3833,-1186.6118 259.4691,-1185.519"/>
</g>
<!-- A16 -->
<g id="node17" class="node">
<title>A16</title>
<polygon fill="none" stroke="#000000" points="385.6155,-1826 385.6155,-1858 460.6155,-1858 460.6155,-1826 385.6155,-1826"/>
<text text-anchor="start" x="405.333" y="-1839" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
<polygon fill="none" stroke="#000000" points="385.6155,-1674 385.6155,-1826 460.6155,-1826 460.6155,-1674 385.6155,-1674"/>
<text text-anchor="start" x="414.777" y="-1807" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
<text text-anchor="start" x="395.6055" y="-1783" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
<text text-anchor="start" x="396.7205" y="-1771" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
<text text-anchor="start" x="406.724" y="-1759" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
<text text-anchor="start" x="397.005" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
<text text-anchor="start" x="405.0575" y="-1735" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
<text text-anchor="start" x="417.007" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
<text text-anchor="start" x="403.669" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
<text text-anchor="start" x="401.9945" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
<text text-anchor="start" x="416.452" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
<polygon fill="none" stroke="#000000" points="385.6155,-1606 385.6155,-1674 460.6155,-1674 460.6155,-1606 385.6155,-1606"/>
<text text-anchor="start" x="397.0055" y="-1655" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
<text text-anchor="start" x="400.3395" y="-1643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
<text text-anchor="start" x="397.8395" y="-1631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
<text text-anchor="start" x="408.118" y="-1619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<!-- A14&#45;&gt;A13 -->
<g id="edge15" class="edge">
<title>A14&#45;&gt;A13</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M187.8521,-1709.7603C192.164,-1677.5066 197.804,-1635.3194 203.5512,-1592.3307"/>
<polygon fill="none" stroke="#000000" points="184.3563,-1709.4961 186.5003,-1719.8717 191.2946,-1710.4237 184.3563,-1709.4961"/>
</g>
<!-- A16&#45;&gt;A14 -->
<g id="edge18" class="edge">
<title>A16&#45;&gt;A14</title>
<path fill="none" stroke="#000000" d="M403.1382,-1596.041C401.2623,-1582.9463 399.3403,-1569.5297 397.4159,-1556.0971"/>
<polygon fill="#000000" stroke="#000000" points="404.563,-1605.9867 398.6903,-1596.726 403.8539,-1601.0373 403.1448,-1596.0878 403.1448,-1596.0878 403.1448,-1596.0878 403.8539,-1601.0373 407.5994,-1595.4496 404.563,-1605.9867 404.563,-1605.9867"/>
<text text-anchor="middle" x="408.3534" y="-1569.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
<text text-anchor="middle" x="393.6256" y="-1586.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
<!-- A15 -->
<g id="node16" class="node">
<title>A15</title>
<polygon fill="none" stroke="#000000" points="244.066,-1862 244.066,-1894 319.066,-1894 319.066,-1862 244.066,-1862"/>
<text text-anchor="start" x="263.7835" y="-1875" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
<polygon fill="none" stroke="#000000" points="244.066,-1710 244.066,-1862 319.066,-1862 319.066,-1710 244.066,-1710"/>
<text text-anchor="start" x="273.2275" y="-1843" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
<text text-anchor="start" x="254.056" y="-1819" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
<text text-anchor="start" x="255.171" y="-1807" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
<text text-anchor="start" x="265.1745" y="-1795" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
<text text-anchor="start" x="255.4555" y="-1783" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
<text text-anchor="start" x="263.508" y="-1771" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
<text text-anchor="start" x="275.4575" y="-1759" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
<text text-anchor="start" x="262.1195" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
<text text-anchor="start" x="260.445" y="-1735" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
<text text-anchor="start" x="274.9025" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
<polygon fill="none" stroke="#000000" points="244.066,-1642 244.066,-1710 319.066,-1710 319.066,-1642 244.066,-1642"/>
<text text-anchor="start" x="255.456" y="-1691" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
<text text-anchor="start" x="258.79" y="-1679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
<text text-anchor="start" x="256.29" y="-1667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
<text text-anchor="start" x="266.5685" y="-1655" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A15&#45;&gt;A13 -->
<g id="edge17" class="edge">
<title>A15&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M262.4684,-1631.6179C260.7062,-1618.6948 258.8964,-1605.4228 257.0763,-1592.0754"/>
<polygon fill="#000000" stroke="#000000" points="263.8708,-1641.9021 258.0609,-1632.6018 263.1952,-1636.9479 262.5196,-1631.9938 262.5196,-1631.9938 262.5196,-1631.9938 263.1952,-1636.9479 266.9783,-1631.3857 263.8708,-1641.9021 263.8708,-1641.9021"/>
<text text-anchor="middle" x="267.9002" y="-1605.8933" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
<text text-anchor="middle" x="253.0469" y="-1622.0841" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -5,10 +5,10 @@
[note: Example of instantiation for a GEN3 inverter!{bg:cornsilk}]
[<<AbstractIterMeta>>||__iter__()]
[InverterBase|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
[InverterBase]^[InverterG3]
[InverterBase]++->[local:StreamPtr]
[InverterBase]++->[remote:StreamPtr]
[InverterG3|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
[InverterG3]++->[local:StreamPtr]
[InverterG3]++->[remote:StreamPtr]
[<<AsyncIfc>>||set_node_id();get_conn_no();;tx_add();tx_flush();tx_get();tx_peek();tx_log();tx_clear();tx_len();;fwd_add();fwd_log();rx_get();rx_peek();rx_log();rx_clear();rx_len();rx_set_cb();;prot_set_timeout_cb()]
[AsyncIfcImpl|fwd_fifo:ByteFifo;tx_fifo:ByteFifo;rx_fifo:ByteFifo;conn_no:Count;node_id;timeout_cb]
[AsyncStream|reader;writer;addr;r_addr;l_addr|;<async>loop;disc();close();healthy();;__async_read();__async_write();__async_forward()]
@@ -31,7 +31,7 @@
[Talent]->[InfosG3]
[Message|server_side:bool;mb:Modbus;ifc:AsyncIfc;node_id;header_valid:bool;header_len;data_len;unique_id;sug_area:str;new_data:dict;state:State;shutdown_started:bool;modbus_elms;mb_timer:Timer;mb_timeout;mb_first_timeout;modbus_polling:bool|_set_mqtt_timestamp();_timeout();_send_modbus_cmd();<async> end_modbus_cmd();close();inc_counter();dec_counter()]
[Message|server_side:bool;mb:Modbus;ifc:AsyncIfc;node_id;header_valid:bool;header_len;data_len;unique_id;sug_area:str;new_data:dict;state:State;shutdown_started:bool;modbus_elms;mb_timer:Timer;mb_timeout;mb_first_timeout;modbus_polling:bool|_set_config_parms(inv:dict);_set_mqtt_timestamp(key, ts);_timeout();_send_modbus_cmd();<async>send_modbus_cmd();_send_modbus_scan();_dump_modbus_scan();close();inc_counter();dec_counter()]
[Message]use->[<<AsyncIfc>>]
[<<ProtocolIfc>>|_registry|close()]

View File

@@ -4,379 +4,364 @@
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="597pt" height="1940pt"
viewBox="0.00 0.00 597.00 1940.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1936)">
<svg width="539pt" height="1976pt"
viewBox="0.00 0.00 538.62 1976.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1972)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1936 593,-1936 593,4 -4,4"/>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1972 534.6165,-1972 534.6165,4 -4,4"/>
<!-- A0 -->
<g id="node1" class="node">
<title>A0</title>
<polygon fill="#fff8dc" stroke="#000000" points="287.2332,-1912 172.7668,-1912 172.7668,-1868 293.2332,-1868 293.2332,-1906 287.2332,-1912"/>
<polyline fill="none" stroke="#000000" points="287.2332,-1912 287.2332,-1906 "/>
<polyline fill="none" stroke="#000000" points="293.2332,-1906 287.2332,-1906 "/>
<text text-anchor="middle" x="233" y="-1899" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
<text text-anchor="middle" x="233" y="-1887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
<text text-anchor="middle" x="233" y="-1875" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3PLUS inverter!</text>
<polygon fill="#fff8dc" stroke="#000000" points="114.3497,-1948 -.1167,-1948 -.1167,-1904 120.3497,-1904 120.3497,-1942 114.3497,-1948"/>
<polyline fill="none" stroke="#000000" points="114.3497,-1948 114.3497,-1942 "/>
<polyline fill="none" stroke="#000000" points="120.3497,-1942 114.3497,-1942 "/>
<text text-anchor="middle" x="60.1165" y="-1935" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
<text text-anchor="middle" x="60.1165" y="-1923" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
<text text-anchor="middle" x="60.1165" y="-1911" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3PLUS inverter!</text>
</g>
<!-- A1 -->
<g id="node2" class="node">
<title>A1</title>
<polygon fill="none" stroke="#000000" points="311,-1900 311,-1932 427,-1932 427,-1900 311,-1900"/>
<text text-anchor="start" x="320.649" y="-1913" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="311,-1880 311,-1900 427,-1900 427,-1880 311,-1880"/>
<polygon fill="none" stroke="#000000" points="311,-1848 311,-1880 427,-1880 427,-1848 311,-1848"/>
<text text-anchor="start" x="347.61" y="-1861" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
</g>
<!-- A15 -->
<g id="node16" class="node">
<title>A15</title>
<polygon fill="none" stroke="#000000" points="324,-1688 324,-1720 414,-1720 414,-1688 324,-1688"/>
<text text-anchor="start" x="333.7065" y="-1701" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="324,-1656 324,-1688 414,-1688 414,-1656 324,-1656"/>
<text text-anchor="start" x="349.8335" y="-1669" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<polygon fill="none" stroke="#000000" points="324,-1624 324,-1656 414,-1656 414,-1624 324,-1624"/>
<text text-anchor="start" x="354.0025" y="-1637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A1&#45;&gt;A15 -->
<g id="edge15" class="edge">
<title>A1&#45;&gt;A15</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M369,-1837.756C369,-1802.0883 369,-1755.1755 369,-1720.3644"/>
<polygon fill="none" stroke="#000000" points="365.5001,-1837.9674 369,-1847.9674 372.5001,-1837.9674 365.5001,-1837.9674"/>
</g>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="128,-632 128,-664 226,-664 226,-632 128,-632"/>
<text text-anchor="start" x="148.66" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
<polygon fill="none" stroke="#000000" points="128,-576 128,-632 226,-632 226,-576 128,-576"/>
<text text-anchor="start" x="166.997" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="137.553" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="142.832" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="128,-520 128,-576 226,-576 226,-520 128,-520"/>
<text text-anchor="start" x="141.442" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
<text text-anchor="start" x="162.0025" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="0,-302 0,-334 116,-334 116,-302 0,-302"/>
<text text-anchor="start" x="31.05" y="-315" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
<polygon fill="none" stroke="#000000" points="0,-270 0,-302 116,-302 116,-270 0,-270"/>
<text text-anchor="start" x="9.6585" y="-283" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">forward_at_cmd_resp</text>
</g>
<!-- A2&#45;&gt;A3 -->
<g id="edge1" class="edge">
<title>A2&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M143.4931,-510.3444C119.4997,-451.8732 88.4875,-376.2972 71.177,-334.1121"/>
<polygon fill="none" stroke="#000000" points="140.3971,-512.0193 147.4314,-519.942 146.873,-509.3619 140.3971,-512.0193"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="230.3366,-320 133.6634,-320 133.6634,-284 230.3366,-284 230.3366,-320"/>
<text text-anchor="middle" x="182" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A4 -->
<g id="edge2" class="edge">
<title>A2&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M178.4553,-507.5905C179.4883,-447.68 180.8113,-370.9429 181.5127,-330.266"/>
<polygon fill="#000000" stroke="#000000" points="178.4493,-507.9438 182.3453,-514.0119 178.2424,-519.942 174.3465,-513.8739 178.4493,-507.9438"/>
<polygon fill="#000000" stroke="#000000" points="181.6851,-320.2627 186.012,-330.3388 181.5989,-325.2619 181.5126,-330.2612 181.5126,-330.2612 181.5126,-330.2612 181.5989,-325.2619 177.0133,-330.1836 181.6851,-320.2627 181.6851,-320.2627"/>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="355.3941,-320 248.6059,-320 248.6059,-284 355.3941,-284 355.3941,-320"/>
<text text-anchor="middle" x="302" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A5 -->
<g id="edge3" class="edge">
<title>A2&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M212.8581,-508.8093C238.9076,-448.3743 272.5536,-370.3156 290.1233,-329.5539"/>
<polygon fill="#000000" stroke="#000000" points="212.8095,-508.9221 214.1078,-516.0154 208.0595,-519.942 206.7612,-512.8487 212.8095,-508.9221"/>
<polygon fill="#000000" stroke="#000000" points="294.1282,-320.2627 294.3023,-331.2272 292.149,-324.8543 290.1698,-329.4459 290.1698,-329.4459 290.1698,-329.4459 292.149,-324.8543 286.0373,-327.6647 294.1282,-320.2627 294.1282,-320.2627"/>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="none" stroke="#000000" points="183,-100 183,-132 361,-132 361,-100 183,-100"/>
<text text-anchor="start" x="227.5515" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
<polygon fill="none" stroke="#000000" points="183,-68 183,-100 361,-100 361,-68 183,-68"/>
<text text-anchor="start" x="239.771" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
<polygon fill="none" stroke="#000000" points="183,0 183,-68 361,-68 361,0 183,0"/>
<text text-anchor="start" x="223.6575" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;server_loop()</text>
<text text-anchor="start" x="214.4885" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward()</text>
<text text-anchor="start" x="192.809" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish_outstanding_mqtt()</text>
<text text-anchor="start" x="257.0025" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A4&#45;&gt;A9 -->
<g id="edge9" class="edge">
<title>A4&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M193.2169,-272.5869C205.6662,-239.9419 226.2449,-185.9801 243.2484,-141.3932"/>
<polygon fill="#000000" stroke="#000000" points="193.1887,-272.661 194.7881,-279.6925 188.9127,-283.8733 187.3132,-276.8418 193.1887,-272.661"/>
<polygon fill="#000000" stroke="#000000" points="246.8183,-132.0321 247.4596,-142.9792 245.0366,-136.7039 243.2549,-141.3757 243.2549,-141.3757 243.2549,-141.3757 245.0366,-136.7039 239.0503,-139.7723 246.8183,-132.0321 246.8183,-132.0321"/>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="none" stroke="#000000" points="424,-82 424,-114 562,-114 562,-82 424,-82"/>
<text text-anchor="start" x="450.497" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
<polygon fill="none" stroke="#000000" points="424,-62 424,-82 562,-82 562,-62 424,-62"/>
<polygon fill="none" stroke="#000000" points="424,-18 424,-62 562,-62 562,-18 424,-18"/>
<text text-anchor="start" x="446.878" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;client_loop()</text>
<text text-anchor="start" x="433.824" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward())</text>
</g>
<!-- A5&#45;&gt;A10 -->
<g id="edge11" class="edge">
<title>A5&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M308.989,-283.7374C318.9281,-259.1334 338.7724,-214.6635 364,-182 380.8963,-160.1235 402.2571,-139.0239 422.71,-120.9559"/>
<polygon fill="#000000" stroke="#000000" points="430.4931,-114.1842 425.9026,-124.143 426.721,-117.4662 422.9488,-120.7481 422.9488,-120.7481 422.9488,-120.7481 426.721,-117.4662 419.9951,-117.3532 430.4931,-114.1842 430.4931,-114.1842"/>
<text text-anchor="middle" x="308.0806" y="-260.758" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="443,-1054 443,-1086 560,-1086 560,-1054 443,-1054"/>
<text text-anchor="start" x="470.929" y="-1067" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="443,-1034 443,-1054 560,-1054 560,-1034 443,-1034"/>
<polygon fill="none" stroke="#000000" points="443,-762 443,-1034 560,-1034 560,-762 443,-762"/>
<text text-anchor="start" x="470.936" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
<text text-anchor="start" x="469.266" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
<text text-anchor="start" x="483.1635" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
<text text-anchor="start" x="480.944" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
<text text-anchor="start" x="484.5535" y="-955" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
<text text-anchor="start" x="480.6635" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
<text text-anchor="start" x="484.8335" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
<text text-anchor="start" x="480.669" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
<text text-anchor="start" x="484.8335" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
<text text-anchor="start" x="479.2745" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
<text text-anchor="start" x="480.9445" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
<text text-anchor="start" x="484.2785" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
<text text-anchor="start" x="480.3885" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
<text text-anchor="start" x="484.5585" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
<text text-anchor="start" x="480.394" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
<text text-anchor="start" x="484.5585" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
<text text-anchor="start" x="476.499" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
<text text-anchor="start" x="452.8795" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="494,-622 494,-654 587,-654 587,-622 494,-622"/>
<text text-anchor="start" x="512.164" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
<polygon fill="none" stroke="#000000" points="494,-530 494,-622 587,-622 587,-530 494,-530"/>
<text text-anchor="start" x="503.548" y="-603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
<text text-anchor="start" x="507.437" y="-591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
<text text-anchor="start" x="507.162" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
<text text-anchor="start" x="506.596" y="-567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
<text text-anchor="start" x="522.7135" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="516.0495" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
</g>
<!-- A6&#45;&gt;A7 -->
<g id="edge4" class="edge">
<title>A6&#45;&gt;A7</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M521.2574,-751.5524C525.3561,-716.6607 529.4102,-682.1494 532.6937,-654.1971"/>
<polygon fill="none" stroke="#000000" points="517.7337,-751.5502 520.043,-761.8903 524.6859,-752.367 517.7337,-751.5502"/>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="none" stroke="#000000" points="487,-390 487,-422 589,-422 589,-390 487,-390"/>
<text text-anchor="start" x="508.274" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
<polygon fill="none" stroke="#000000" points="487,-310 487,-390 589,-390 589,-310 487,-310"/>
<text text-anchor="start" x="523.553" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
<text text-anchor="start" x="525.783" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
<text text-anchor="start" x="527.997" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="523.553" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
<text text-anchor="start" x="524.108" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
<polygon fill="none" stroke="#000000" points="487,-182 487,-310 589,-310 589,-182 487,-182"/>
<text text-anchor="start" x="509.654" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;loop</text>
<text text-anchor="start" x="525.782" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
<text text-anchor="start" x="523.0025" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="518.554" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="503.2705" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
<text text-anchor="start" x="502.721" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
<text text-anchor="start" x="496.607" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge5" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M539.5006,-519.5861C539.2971,-490.0737 539.0562,-455.1552 538.8278,-422.0295"/>
<polygon fill="none" stroke="#000000" points="536.002,-519.8121 539.5709,-529.7877 543.0018,-519.7638 536.002,-519.8121"/>
</g>
<!-- A8&#45;&gt;A9 -->
<g id="edge6" class="edge">
<title>A8&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M480.5271,-185.826C479.3695,-184.5245 478.1938,-183.2483 477,-182 444.7093,-148.2346 400.4099,-121.5033 361.252,-102.2528"/>
<polygon fill="none" stroke="#000000" points="477.867,-188.1011 486.9604,-193.5382 483.2424,-183.6171 477.867,-188.1011"/>
</g>
<!-- A8&#45;&gt;A10 -->
<g id="edge7" class="edge">
<title>A8&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M513.2286,-172.088C509.2911,-151.438 505.4474,-131.2796 502.1863,-114.1772"/>
<polygon fill="none" stroke="#000000" points="509.7933,-172.7584 515.1045,-181.9259 516.6695,-171.4473 509.7933,-172.7584"/>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="none" stroke="#000000" points="244,-668 244,-700 354,-700 354,-668 244,-668"/>
<text text-anchor="start" x="271.495" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
<polygon fill="none" stroke="#000000" points="244,-552 244,-668 354,-668 354,-552 244,-552"/>
<text text-anchor="start" x="279.823" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
<text text-anchor="start" x="288.997" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="253.994" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter:InverterG3P</text>
<text text-anchor="start" x="283.998" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
<text text-anchor="start" x="287.0575" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
<text text-anchor="start" x="292.056" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
<text text-anchor="start" x="271.21" y="-577" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
<text text-anchor="start" x="285.112" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
<polygon fill="none" stroke="#000000" points="244,-484 244,-552 354,-552 354,-484 244,-484"/>
<text text-anchor="start" x="263.4405" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
<text text-anchor="start" x="279.554" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="284.0025" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A11&#45;&gt;A4 -->
<g id="edge8" class="edge">
<title>A11&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M251.4932,-474.2481C230.4181,-422.0107 207.3684,-364.879 193.8227,-331.3042"/>
<polygon fill="#000000" stroke="#000000" points="255.2671,-483.6023 247.3524,-476.0123 253.3964,-478.9655 251.5256,-474.3286 251.5256,-474.3286 251.5256,-474.3286 253.3964,-478.9655 255.6988,-472.6449 255.2671,-483.6023 255.2671,-483.6023"/>
<polygon fill="#000000" stroke="#000000" points="193.7733,-331.1815 187.8189,-327.1139 189.2835,-320.053 195.2379,-324.1207 193.7733,-331.1815"/>
</g>
<!-- A11&#45;&gt;A5 -->
<g id="edge10" class="edge">
<title>A11&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M300.2256,-473.5237C300.8304,-415.0627 301.4968,-350.6465 301.8132,-320.053"/>
<polygon fill="#000000" stroke="#000000" points="300.1214,-483.6023 295.7251,-473.5562 300.1731,-478.6026 300.2249,-473.6028 300.2249,-473.6028 300.2249,-473.6028 300.1731,-478.6026 304.7247,-473.6494 300.1214,-483.6023 300.1214,-483.6023"/>
<text text-anchor="middle" x="310.0777" y="-335.2657" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A13 -->
<g id="node14" class="node">
<title>A13</title>
<polygon fill="none" stroke="#000000" points="374,-336 374,-368 469,-368 469,-336 374,-336"/>
<text text-anchor="start" x="400.6585" y="-349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
<polygon fill="none" stroke="#000000" points="374,-304 374,-336 469,-336 469,-304 374,-304"/>
<text text-anchor="start" x="383.7125" y="-317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">client_mode:bool</text>
<polygon fill="none" stroke="#000000" points="374,-236 374,-304 469,-304 469,-236 374,-236"/>
<text text-anchor="start" x="397.884" y="-285" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
<text text-anchor="start" x="405.668" y="-273" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
<text text-anchor="start" x="409.282" y="-261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">calc()</text>
<text text-anchor="start" x="407.6135" y="-249" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build()</text>
</g>
<!-- A11&#45;&gt;A13 -->
<g id="edge13" class="edge">
<title>A11&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M344.6018,-483.6023C359.4473,-448.3138 375.5948,-409.9305 389.2039,-377.5809"/>
<polygon fill="#000000" stroke="#000000" points="393.1562,-368.1861 393.4263,-379.1487 391.2173,-372.7949 389.2784,-377.4036 389.2784,-377.4036 389.2784,-377.4036 391.2173,-372.7949 385.1305,-375.6586 393.1562,-368.1861 393.1562,-368.1861"/>
</g>
<!-- A12 -->
<g id="node13" class="node">
<title>A12</title>
<polygon fill="none" stroke="#000000" points="373,-680 373,-712 476,-712 476,-680 373,-680"/>
<text text-anchor="start" x="413.662" y="-693" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
<polygon fill="none" stroke="#000000" points="373,-624 373,-680 476,-680 476,-624 373,-624"/>
<text text-anchor="start" x="416.4415" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
<text text-anchor="start" x="391.986" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
<text text-anchor="start" x="405.6035" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
<polygon fill="none" stroke="#000000" points="373,-472 373,-624 476,-624 476,-472 373,-472"/>
<text text-anchor="start" x="400.3355" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
<text text-anchor="start" x="398.3845" y="-593" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
<text text-anchor="start" x="395.3305" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="393.6605" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<text text-anchor="start" x="391.71" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
<text text-anchor="start" x="406.713" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
<text text-anchor="start" x="399.494" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
<text text-anchor="start" x="400.8745" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
<text text-anchor="start" x="385.037" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
<text text-anchor="start" x="394.4855" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
<text text-anchor="start" x="382.8225" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
</g>
<!-- A12&#45;&gt;A13 -->
<g id="edge12" class="edge">
<title>A12&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M422.6543,-461.9134C422.3183,-429.4373 421.9719,-395.9527 421.6835,-368.0691"/>
<polygon fill="none" stroke="#000000" points="419.1548,-461.9893 422.7581,-471.9525 426.1544,-461.9168 419.1548,-461.9893"/>
<polygon fill="none" stroke="#000000" points="138.1165,-1936 138.1165,-1968 254.1165,-1968 254.1165,-1936 138.1165,-1936"/>
<text text-anchor="start" x="147.7655" y="-1949" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AbstractIterMeta&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="138.1165,-1916 138.1165,-1936 254.1165,-1936 254.1165,-1916 138.1165,-1916"/>
<polygon fill="none" stroke="#000000" points="138.1165,-1884 138.1165,-1916 254.1165,-1916 254.1165,-1884 138.1165,-1884"/>
<text text-anchor="start" x="174.7265" y="-1897" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
</g>
<!-- A14 -->
<g id="node15" class="node">
<title>A14</title>
<polygon fill="none" stroke="#000000" points="345,-1464 345,-1496 494,-1496 494,-1464 345,-1464"/>
<text text-anchor="start" x="399.2175" y="-1477" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
<polygon fill="none" stroke="#000000" points="345,-1240 345,-1464 494,-1464 494,-1240 345,-1240"/>
<text text-anchor="start" x="382.8265" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
<text text-anchor="start" x="393.384" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="394.2185" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
<text text-anchor="start" x="401.7135" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="380.043" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
<text text-anchor="start" x="394.49" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
<text text-anchor="start" x="400.324" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
<text text-anchor="start" x="397.8245" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
<text text-anchor="start" x="391.715" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
<text text-anchor="start" x="388.656" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
<text text-anchor="start" x="395.6" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
<text text-anchor="start" x="369.2045" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
<text text-anchor="start" x="388.3845" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
<text text-anchor="start" x="384.507" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
<text text-anchor="start" x="393.385" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
<text text-anchor="start" x="382.5525" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
<text text-anchor="start" x="373.654" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
<polygon fill="none" stroke="#000000" points="345,-1136 345,-1240 494,-1240 494,-1136 345,-1136"/>
<text text-anchor="start" x="368.3845" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
<text text-anchor="start" x="397" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
<text text-anchor="start" x="369.7675" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
<text text-anchor="start" x="354.7595" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt; end_modbus_cmd()</text>
<text text-anchor="start" x="404.5025" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="390.3305" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="388.6605" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<polygon fill="none" stroke="#000000" points="151.1165,-1724 151.1165,-1756 241.1165,-1756 241.1165,-1724 151.1165,-1724"/>
<text text-anchor="start" x="160.823" y="-1737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;ProtocolIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="151.1165,-1692 151.1165,-1724 241.1165,-1724 241.1165,-1692 151.1165,-1692"/>
<text text-anchor="start" x="176.95" y="-1705" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
<polygon fill="none" stroke="#000000" points="151.1165,-1660 151.1165,-1692 241.1165,-1692 241.1165,-1660 151.1165,-1660"/>
<text text-anchor="start" x="181.119" y="-1673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A14&#45;&gt;A6 -->
<!-- A1&#45;&gt;A14 -->
<g id="edge14" class="edge">
<title>A14&#45;&gt;A6</title>
<path fill="none" stroke="#000000" d="M456.7,-1135.7758C459.4656,-1122.5547 462.2514,-1109.2373 465.0066,-1096.0662"/>
<polygon fill="#000000" stroke="#000000" points="467.1066,-1086.0268 469.4637,-1096.7363 466.0828,-1090.9209 465.059,-1095.8149 465.059,-1095.8149 465.059,-1095.8149 466.0828,-1090.9209 460.6544,-1094.8935 467.1066,-1086.0268 467.1066,-1086.0268"/>
<text text-anchor="middle" x="452.138" y="-1113.3031" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
<title>A1&#45;&gt;A14</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M196.1165,-1873.756C196.1165,-1838.0883 196.1165,-1791.1755 196.1165,-1756.3644"/>
<polygon fill="none" stroke="#000000" points="192.6166,-1873.9674 196.1165,-1883.9674 199.6166,-1873.9674 192.6166,-1873.9674"/>
</g>
<!-- A14&#45;&gt;A11 -->
<g id="edge17" class="edge">
<title>A14&#45;&gt;A11</title>
<path fill="none" stroke="#000000" d="M387.4309,-1125.5329C364.9447,-989.8666 335.5291,-812.3923 316.9437,-700.2604"/>
<polygon fill="none" stroke="#000000" points="384.0176,-1126.3448 389.1057,-1135.6378 390.9234,-1125.2001 384.0176,-1126.3448"/>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="202.1165,-632 202.1165,-664 300.1165,-664 300.1165,-632 202.1165,-632"/>
<text text-anchor="start" x="224.1665" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
<polygon fill="none" stroke="#000000" points="202.1165,-576 202.1165,-632 300.1165,-632 300.1165,-576 202.1165,-576"/>
<text text-anchor="start" x="241.1135" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="211.6695" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
<text text-anchor="start" x="216.9485" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
<polygon fill="none" stroke="#000000" points="202.1165,-520 202.1165,-576 300.1165,-576 300.1165,-520 202.1165,-520"/>
<text text-anchor="start" x="215.5585" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
<text text-anchor="start" x="236.119" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A15&#45;&gt;A14 -->
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="419.4531,-320 322.7799,-320 322.7799,-284 419.4531,-284 419.4531,-320"/>
<text text-anchor="middle" x="371.1165" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A3 -->
<g id="edge1" class="edge">
<title>A2&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M285.5402,-508.8093C310.5478,-448.3743 342.848,-370.3156 359.7149,-329.5539"/>
<polygon fill="#000000" stroke="#000000" points="285.5219,-508.8538 286.9238,-515.9273 280.9336,-519.942 279.5317,-512.8685 285.5219,-508.8538"/>
<polygon fill="#000000" stroke="#000000" points="363.5595,-320.2627 363.894,-331.2235 361.6477,-324.8828 359.7359,-329.5029 359.7359,-329.5029 359.7359,-329.5029 361.6477,-324.8828 355.5779,-327.7823 363.5595,-320.2627 363.5595,-320.2627"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="304.5106,-320 197.7224,-320 197.7224,-284 304.5106,-284 304.5106,-320"/>
<text text-anchor="middle" x="251.1165" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
</g>
<!-- A2&#45;&gt;A4 -->
<g id="edge2" class="edge">
<title>A2&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M251.1165,-507.5905C251.1165,-447.68 251.1165,-370.9429 251.1165,-330.266"/>
<polygon fill="#000000" stroke="#000000" points="251.1166,-507.942 255.1165,-513.942 251.1165,-519.942 247.1165,-513.942 251.1166,-507.942"/>
<polygon fill="#000000" stroke="#000000" points="251.1165,-320.2627 255.6166,-330.2626 251.1165,-325.2627 251.1166,-330.2627 251.1166,-330.2627 251.1166,-330.2627 251.1165,-325.2627 246.6166,-330.2627 251.1165,-320.2627 251.1165,-320.2627"/>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="none" stroke="#000000" points="265.1165,-100 265.1165,-132 443.1165,-132 443.1165,-100 265.1165,-100"/>
<text text-anchor="start" x="309.668" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
<polygon fill="none" stroke="#000000" points="265.1165,-68 265.1165,-100 443.1165,-100 443.1165,-68 265.1165,-68"/>
<text text-anchor="start" x="321.8875" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
<polygon fill="none" stroke="#000000" points="265.1165,0 265.1165,-68 443.1165,-68 443.1165,0 265.1165,0"/>
<text text-anchor="start" x="305.774" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;server_loop()</text>
<text text-anchor="start" x="296.605" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward()</text>
<text text-anchor="start" x="274.9255" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;publish_outstanding_mqtt()</text>
<text text-anchor="start" x="339.119" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A3&#45;&gt;A8 -->
<g id="edge8" class="edge">
<title>A3&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M368.9314,-271.6651C366.5869,-239.1181 362.7725,-186.1658 359.6014,-142.1431"/>
<polygon fill="#000000" stroke="#000000" points="368.9485,-271.9044 373.3693,-277.6014 369.8108,-283.8733 365.39,-278.1763 368.9485,-271.9044"/>
<polygon fill="#000000" stroke="#000000" points="358.8731,-132.0321 364.08,-141.6829 359.2323,-137.0192 359.5916,-142.0063 359.5916,-142.0063 359.5916,-142.0063 359.2323,-137.0192 355.1032,-142.3296 358.8731,-132.0321 358.8731,-132.0321"/>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="none" stroke="#000000" points="93.1165,-82 93.1165,-114 231.1165,-114 231.1165,-82 93.1165,-82"/>
<text text-anchor="start" x="119.6135" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
<polygon fill="none" stroke="#000000" points="93.1165,-62 93.1165,-82 231.1165,-82 231.1165,-62 93.1165,-62"/>
<polygon fill="none" stroke="#000000" points="93.1165,-18 93.1165,-62 231.1165,-62 231.1165,-18 93.1165,-18"/>
<text text-anchor="start" x="115.9945" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;client_loop()</text>
<text text-anchor="start" x="102.9405" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;_async_forward())</text>
</g>
<!-- A4&#45;&gt;A9 -->
<g id="edge10" class="edge">
<title>A4&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M244.2806,-283.8733C231.5204,-250.0372 203.5834,-175.9573 183.8383,-123.5994"/>
<polygon fill="#000000" stroke="#000000" points="180.2523,-114.0904 187.9915,-121.8593 182.0166,-118.7688 183.781,-123.4472 183.781,-123.4472 183.781,-123.4472 182.0166,-118.7688 179.5704,-125.0351 180.2523,-114.0904 180.2523,-114.0904"/>
<text text-anchor="middle" x="229.9759" y="-266.8956" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="145.1165,-1054 145.1165,-1086 262.1165,-1086 262.1165,-1054 145.1165,-1054"/>
<text text-anchor="start" x="173.0455" y="-1067" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;AsyncIfc&gt;&gt;</text>
<polygon fill="none" stroke="#000000" points="145.1165,-1034 145.1165,-1054 262.1165,-1054 262.1165,-1034 145.1165,-1034"/>
<polygon fill="none" stroke="#000000" points="145.1165,-762 145.1165,-1034 262.1165,-1034 262.1165,-762 145.1165,-762"/>
<text text-anchor="start" x="173.0525" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
<text text-anchor="start" x="171.3825" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
<text text-anchor="start" x="185.28" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
<text text-anchor="start" x="183.0605" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
<text text-anchor="start" x="186.67" y="-955" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
<text text-anchor="start" x="182.78" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
<text text-anchor="start" x="186.95" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
<text text-anchor="start" x="182.7855" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
<text text-anchor="start" x="186.95" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
<text text-anchor="start" x="181.391" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
<text text-anchor="start" x="183.061" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
<text text-anchor="start" x="186.395" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
<text text-anchor="start" x="182.505" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
<text text-anchor="start" x="186.675" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
<text text-anchor="start" x="182.5105" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
<text text-anchor="start" x="186.675" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
<text text-anchor="start" x="178.6155" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
<text text-anchor="start" x="154.996" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="87.1165,-622 87.1165,-654 180.1165,-654 180.1165,-622 87.1165,-622"/>
<text text-anchor="start" x="105.2805" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
<polygon fill="none" stroke="#000000" points="87.1165,-530 87.1165,-622 180.1165,-622 180.1165,-530 87.1165,-530"/>
<text text-anchor="start" x="96.6645" y="-603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
<text text-anchor="start" x="100.5535" y="-591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
<text text-anchor="start" x="100.2785" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
<text text-anchor="start" x="99.7125" y="-567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
<text text-anchor="start" x="115.83" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="109.166" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
</g>
<!-- A5&#45;&gt;A6 -->
<g id="edge3" class="edge">
<title>A5&#45;&gt;A6</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M166.8518,-752.0017C159.4629,-716.9571 152.1492,-682.2694 146.2303,-654.1971"/>
<polygon fill="none" stroke="#000000" points="163.4489,-752.8275 168.9367,-761.8903 170.2983,-751.3833 163.4489,-752.8275"/>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="78.1165,-390 78.1165,-422 180.1165,-422 180.1165,-390 78.1165,-390"/>
<text text-anchor="start" x="99.3905" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
<polygon fill="none" stroke="#000000" points="78.1165,-310 78.1165,-390 180.1165,-390 180.1165,-310 78.1165,-310"/>
<text text-anchor="start" x="114.6695" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
<text text-anchor="start" x="116.8995" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
<text text-anchor="start" x="119.1135" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="114.6695" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
<text text-anchor="start" x="115.2245" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
<polygon fill="none" stroke="#000000" points="78.1165,-182 78.1165,-310 180.1165,-310 180.1165,-182 78.1165,-182"/>
<text text-anchor="start" x="100.7705" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;loop</text>
<text text-anchor="start" x="116.8985" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
<text text-anchor="start" x="114.119" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="109.6705" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="94.387" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
<text text-anchor="start" x="93.8375" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
<text text-anchor="start" x="87.7235" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
</g>
<!-- A6&#45;&gt;A7 -->
<g id="edge4" class="edge">
<title>A6&#45;&gt;A7</title>
<path fill="none" stroke="#000000" d="M132.1177,-519.5861C131.7106,-490.0737 131.229,-455.1552 130.7721,-422.0295"/>
<polygon fill="none" stroke="#000000" points="128.6207,-519.837 132.2584,-529.7877 135.6201,-519.7404 128.6207,-519.837"/>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge5" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" d="M186.5777,-185.0204C187.4154,-184.0001 188.2616,-182.9929 189.1165,-182 210.4788,-157.1889 238.2469,-135.0276 264.8921,-116.8901"/>
<polygon fill="none" stroke="#000000" points="183.6875,-183.0361 180.3256,-193.0834 189.2193,-187.3255 183.6875,-183.0361"/>
</g>
<!-- A7&#45;&gt;A9 -->
<g id="edge6" class="edge">
<title>A7&#45;&gt;A9</title>
<path fill="none" stroke="#000000" d="M147.3214,-171.8077C150.1952,-151.2556 152.9992,-131.2022 155.3799,-114.1772"/>
<polygon fill="none" stroke="#000000" points="143.8252,-171.5375 145.9065,-181.9259 150.7577,-172.5069 143.8252,-171.5375"/>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="none" stroke="#000000" points="319.1165,-668 319.1165,-700 410.1165,-700 410.1165,-668 319.1165,-668"/>
<text text-anchor="start" x="337.1115" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
<polygon fill="none" stroke="#000000" points="319.1165,-552 319.1165,-668 410.1165,-668 410.1165,-552 319.1165,-552"/>
<text text-anchor="start" x="345.4395" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
<text text-anchor="start" x="354.6135" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
<text text-anchor="start" x="349.6145" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
<text text-anchor="start" x="352.674" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
<text text-anchor="start" x="357.6725" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
<text text-anchor="start" x="336.8265" y="-577" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
<text text-anchor="start" x="350.7285" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
<polygon fill="none" stroke="#000000" points="319.1165,-484 319.1165,-552 410.1165,-552 410.1165,-484 319.1165,-484"/>
<text text-anchor="start" x="329.057" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
<text text-anchor="start" x="345.1705" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
<text text-anchor="start" x="349.619" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A10&#45;&gt;A3 -->
<g id="edge7" class="edge">
<title>A10&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M366.9763,-473.5237C368.222,-421.9136 369.5798,-365.6622 370.389,-332.138"/>
<polygon fill="#000000" stroke="#000000" points="366.733,-483.6023 362.4757,-473.4966 366.8537,-478.6038 366.9744,-473.6052 366.9744,-473.6052 366.9744,-473.6052 366.8537,-478.6038 371.4731,-473.7139 366.733,-483.6023 366.733,-483.6023"/>
<polygon fill="#000000" stroke="#000000" points="370.3911,-332.0495 366.5371,-325.9547 370.6807,-320.053 374.5347,-326.1478 370.3911,-332.0495"/>
</g>
<!-- A10&#45;&gt;A4 -->
<g id="edge9" class="edge">
<title>A10&#45;&gt;A4</title>
<path fill="none" stroke="#000000" d="M318.2339,-474.2481C295.3796,-415.5956 270.1211,-350.7729 258.151,-320.053"/>
<polygon fill="#000000" stroke="#000000" points="321.8788,-483.6023 314.0551,-475.9185 320.0634,-478.9435 318.2481,-474.2847 318.2481,-474.2847 318.2481,-474.2847 320.0634,-478.9435 322.441,-472.6508 321.8788,-483.6023 321.8788,-483.6023"/>
<text text-anchor="middle" x="272.6076" y="-330.8736" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
<!-- A12 -->
<g id="node13" class="node">
<title>A12</title>
<polygon fill="none" stroke="#000000" points="442.1165,-318 442.1165,-350 509.1165,-350 509.1165,-318 442.1165,-318"/>
<text text-anchor="start" x="454.775" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
<polygon fill="none" stroke="#000000" points="442.1165,-298 442.1165,-318 509.1165,-318 509.1165,-298 442.1165,-298"/>
<polygon fill="none" stroke="#000000" points="442.1165,-254 442.1165,-298 509.1165,-298 509.1165,-254 442.1165,-254"/>
<text text-anchor="start" x="452.0005" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
<text text-anchor="start" x="459.7845" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
</g>
<!-- A10&#45;&gt;A12 -->
<g id="edge12" class="edge">
<title>A10&#45;&gt;A12</title>
<path fill="none" stroke="#000000" d="M405.6067,-483.6023C421.7045,-441.5449 439.4849,-395.0916 453.0329,-359.6958"/>
<polygon fill="#000000" stroke="#000000" points="456.737,-350.0185 457.3649,-360.9664 454.9496,-354.6881 453.1623,-359.3577 453.1623,-359.3577 453.1623,-359.3577 454.9496,-354.6881 448.9596,-357.7491 456.737,-350.0185 456.737,-350.0185"/>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="none" stroke="#000000" points="428.1165,-680 428.1165,-712 531.1165,-712 531.1165,-680 428.1165,-680"/>
<text text-anchor="start" x="468.7785" y="-693" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
<polygon fill="none" stroke="#000000" points="428.1165,-624 428.1165,-680 531.1165,-680 531.1165,-624 428.1165,-624"/>
<text text-anchor="start" x="471.558" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
<text text-anchor="start" x="447.1025" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
<text text-anchor="start" x="460.72" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
<polygon fill="none" stroke="#000000" points="428.1165,-472 428.1165,-624 531.1165,-624 531.1165,-472 428.1165,-472"/>
<text text-anchor="start" x="455.452" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
<text text-anchor="start" x="453.501" y="-593" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
<text text-anchor="start" x="450.447" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="448.777" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
<text text-anchor="start" x="446.8265" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
<text text-anchor="start" x="461.8295" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
<text text-anchor="start" x="454.6105" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
<text text-anchor="start" x="455.991" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
<text text-anchor="start" x="440.1535" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
<text text-anchor="start" x="449.602" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
<text text-anchor="start" x="437.939" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
</g>
<!-- A11&#45;&gt;A12 -->
<g id="edge11" class="edge">
<title>A11&#45;&gt;A12</title>
<path fill="none" stroke="#000000" d="M477.322,-461.8987C476.7744,-422.1971 476.206,-380.9898 475.7834,-350.352"/>
<polygon fill="none" stroke="#000000" points="473.823,-462.0018 477.4607,-471.9525 480.8223,-461.9052 473.823,-462.0018"/>
</g>
<!-- A13 -->
<g id="node14" class="node">
<title>A13</title>
<polygon fill="none" stroke="#000000" points="171.1165,-1500 171.1165,-1532 322.1165,-1532 322.1165,-1500 171.1165,-1500"/>
<text text-anchor="start" x="226.334" y="-1513" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
<polygon fill="none" stroke="#000000" points="171.1165,-1276 171.1165,-1500 322.1165,-1500 322.1165,-1276 171.1165,-1276"/>
<text text-anchor="start" x="209.943" y="-1481" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
<text text-anchor="start" x="220.5005" y="-1469" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
<text text-anchor="start" x="221.335" y="-1457" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
<text text-anchor="start" x="228.83" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
<text text-anchor="start" x="207.1595" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
<text text-anchor="start" x="221.6065" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
<text text-anchor="start" x="227.4405" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
<text text-anchor="start" x="224.941" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
<text text-anchor="start" x="218.8315" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
<text text-anchor="start" x="215.7725" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
<text text-anchor="start" x="222.7165" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
<text text-anchor="start" x="196.321" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
<text text-anchor="start" x="215.501" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
<text text-anchor="start" x="211.6235" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
<text text-anchor="start" x="220.5015" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
<text text-anchor="start" x="209.669" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
<text text-anchor="start" x="200.7705" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
<polygon fill="none" stroke="#000000" points="171.1165,-1136 171.1165,-1276 322.1165,-1276 322.1165,-1136 171.1165,-1136"/>
<text text-anchor="start" x="185.4975" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_config_parms(inv:dict)</text>
<text text-anchor="start" x="181.053" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp(key, ts)</text>
<text text-anchor="start" x="224.1165" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
<text text-anchor="start" x="196.884" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
<text text-anchor="start" x="180.7655" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;async&gt;send_modbus_cmd()</text>
<text text-anchor="start" x="195.769" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_scan()</text>
<text text-anchor="start" x="194.1045" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_dump_modbus_scan()</text>
<text text-anchor="start" x="231.619" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<text text-anchor="start" x="217.447" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
<text text-anchor="start" x="215.777" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
</g>
<!-- A13&#45;&gt;A5 -->
<g id="edge13" class="edge">
<title>A13&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M225.3407,-1135.9056C223.9472,-1122.6185 222.5496,-1109.2927 221.1714,-1096.1518"/>
<polygon fill="#000000" stroke="#000000" points="220.1217,-1086.1426 225.6403,-1095.6186 220.6433,-1091.1153 221.1648,-1096.0881 221.1648,-1096.0881 221.1648,-1096.0881 220.6433,-1091.1153 216.6894,-1096.5575 220.1217,-1086.1426 220.1217,-1086.1426"/>
<text text-anchor="middle" x="215.0438" y="-1115.7599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
</g>
<!-- A13&#45;&gt;A10 -->
<g id="edge16" class="edge">
<title>A15&#45;&gt;A14</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M377.1741,-1613.8004C381.7377,-1581.3079 387.6971,-1538.8764 393.681,-1496.2713"/>
<polygon fill="none" stroke="#000000" points="373.6682,-1613.5986 375.7432,-1623.9883 380.6001,-1614.5723 373.6682,-1613.5986"/>
<title>A13&#45;&gt;A10</title>
<path fill="none" stroke="#000000" d="M279.2341,-1125.7521C301.232,-987.426 329.217,-811.4525 346.9052,-700.227"/>
<polygon fill="none" stroke="#000000" points="275.7749,-1125.2195 277.6608,-1135.6451 282.688,-1126.319 275.7749,-1125.2195"/>
</g>
<!-- A16 -->
<g id="node17" class="node">
<title>A16</title>
<polygon fill="none" stroke="#000000" points="433,-1766 433,-1798 508,-1798 508,-1766 433,-1766"/>
<text text-anchor="start" x="452.7175" y="-1779" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
<polygon fill="none" stroke="#000000" points="433,-1614 433,-1766 508,-1766 508,-1614 433,-1614"/>
<text text-anchor="start" x="462.1615" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
<text text-anchor="start" x="442.99" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
<text text-anchor="start" x="444.105" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
<text text-anchor="start" x="454.1085" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
<text text-anchor="start" x="444.3895" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
<text text-anchor="start" x="452.442" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
<text text-anchor="start" x="464.3915" y="-1663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
<text text-anchor="start" x="451.0535" y="-1651" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
<text text-anchor="start" x="449.379" y="-1639" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
<text text-anchor="start" x="463.8365" y="-1627" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
<polygon fill="none" stroke="#000000" points="433,-1546 433,-1614 508,-1614 508,-1546 433,-1546"/>
<text text-anchor="start" x="444.39" y="-1595" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
<text text-anchor="start" x="447.724" y="-1583" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
<text text-anchor="start" x="445.224" y="-1571" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
<text text-anchor="start" x="455.5025" y="-1559" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
<!-- A14&#45;&gt;A13 -->
<g id="edge15" class="edge">
<title>A14&#45;&gt;A13</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M203.9026,-1649.7603C208.2145,-1617.5066 213.8545,-1575.3194 219.6017,-1532.3307"/>
<polygon fill="none" stroke="#000000" points="200.4068,-1649.4961 202.5508,-1659.8717 207.3451,-1650.4237 200.4068,-1649.4961"/>
</g>
<!-- A16&#45;&gt;A14 -->
<g id="edge18" class="edge">
<title>A16&#45;&gt;A14</title>
<path fill="none" stroke="#000000" d="M450.5227,-1536.041C448.6468,-1522.9463 446.7248,-1509.5297 444.8004,-1496.0971"/>
<polygon fill="#000000" stroke="#000000" points="451.9475,-1545.9867 446.0748,-1536.726 451.2384,-1541.0373 450.5293,-1536.0878 450.5293,-1536.0878 450.5293,-1536.0878 451.2384,-1541.0373 454.9839,-1535.4496 451.9475,-1545.9867 451.9475,-1545.9867"/>
<text text-anchor="middle" x="455.7379" y="-1509.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
<text text-anchor="middle" x="441.0101" y="-1526.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
<!-- A15 -->
<g id="node16" class="node">
<title>A15</title>
<polygon fill="none" stroke="#000000" points="260.1165,-1802 260.1165,-1834 335.1165,-1834 335.1165,-1802 260.1165,-1802"/>
<text text-anchor="start" x="279.834" y="-1815" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
<polygon fill="none" stroke="#000000" points="260.1165,-1650 260.1165,-1802 335.1165,-1802 335.1165,-1650 260.1165,-1650"/>
<text text-anchor="start" x="289.278" y="-1783" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
<text text-anchor="start" x="270.1065" y="-1759" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
<text text-anchor="start" x="271.2215" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
<text text-anchor="start" x="281.225" y="-1735" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
<text text-anchor="start" x="271.506" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
<text text-anchor="start" x="279.5585" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
<text text-anchor="start" x="291.508" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
<text text-anchor="start" x="278.17" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
<text text-anchor="start" x="276.4955" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
<text text-anchor="start" x="290.953" y="-1663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
<polygon fill="none" stroke="#000000" points="260.1165,-1582 260.1165,-1650 335.1165,-1650 335.1165,-1582 260.1165,-1582"/>
<text text-anchor="start" x="271.5065" y="-1631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
<text text-anchor="start" x="274.8405" y="-1619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
<text text-anchor="start" x="272.3405" y="-1607" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
<text text-anchor="start" x="282.619" y="-1595" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
</g>
<!-- A15&#45;&gt;A13 -->
<g id="edge17" class="edge">
<title>A15&#45;&gt;A13</title>
<path fill="none" stroke="#000000" d="M278.5189,-1571.6179C276.7567,-1558.6948 274.9469,-1545.4228 273.1268,-1532.0754"/>
<polygon fill="#000000" stroke="#000000" points="279.9213,-1581.9021 274.1114,-1572.6018 279.2457,-1576.9479 278.5701,-1571.9938 278.5701,-1571.9938 278.5701,-1571.9938 279.2457,-1576.9479 283.0288,-1571.3857 279.9213,-1581.9021 279.9213,-1581.9021"/>
<text text-anchor="middle" x="283.9507" y="-1545.8933" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
<text text-anchor="middle" x="269.0974" y="-1562.0841" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -5,10 +5,9 @@
[note: Example of instantiation for a GEN3PLUS inverter!{bg:cornsilk}]
[<<AbstractIterMeta>>||__iter__()]
[InverterBase|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
[InverterBase]^[InverterG3P|forward_at_cmd_resp;]
[InverterBase]++->[local:StreamPtr]
[InverterBase]++->[remote:StreamPtr]
[InverterG3P|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
[InverterG3P]++->[local:StreamPtr]
[InverterG3P]++->[remote:StreamPtr]
[<<AsyncIfc>>||set_node_id();get_conn_no();;tx_add();tx_flush();tx_get();tx_peek();tx_log();tx_clear();tx_len();;fwd_add();fwd_log();rx_get();rx_peek();rx_log();rx_clear();rx_len();rx_set_cb();;prot_set_timeout_cb()]
[AsyncIfcImpl|fwd_fifo:ByteFifo;tx_fifo:ByteFifo;rx_fifo:ByteFifo;conn_no:Count;node_id;timeout_cb]
@@ -20,18 +19,18 @@
[AsyncStream]^[AsyncStreamServer]
[AsyncStream]^[AsyncStreamClient]
[SolarmanV5|conn_no;addr;inverter:InverterG3P;control;serial;snr;db:InfosG3P;switch|msg_unknown();;healthy();close()]
[SolarmanV5|conn_no;addr;;control;serial;snr;db:InfosG3P;switch|msg_unknown();;healthy();close()]
[SolarmanV5]<-++[local:StreamPtr]
[local:StreamPtr]++->[AsyncStreamServer]
[SolarmanV5]<-0..1[remote:StreamPtr]
[remote:StreamPtr]0..1->[AsyncStreamClient]
[Infos|stat;new_stat_data;info_dev|static_init();dev_value();inc_counter();dec_counter();ha_proxy_conf;ha_conf;ha_remove;update_db;set_db_def_value;get_db_value;ignore_this_device]
[Infos]^[InfosG3P|client_mode:bool|ha_confs();parse();calc();build()]
[Infos]^[InfosG3P||ha_confs();parse()]
[SolarmanV5]->[InfosG3P]
[Message|server_side:bool;mb:Modbus;ifc:AsyncIfc;node_id;header_valid:bool;header_len;data_len;unique_id;sug_area:str;new_data:dict;state:State;shutdown_started:bool;modbus_elms;mb_timer:Timer;mb_timeout;mb_first_timeout;modbus_polling:bool|_set_mqtt_timestamp();_timeout();_send_modbus_cmd();<async> end_modbus_cmd();close();inc_counter();dec_counter()]
[Message|server_side:bool;mb:Modbus;ifc:AsyncIfc;node_id;header_valid:bool;header_len;data_len;unique_id;sug_area:str;new_data:dict;state:State;shutdown_started:bool;modbus_elms;mb_timer:Timer;mb_timeout;mb_first_timeout;modbus_polling:bool|_set_config_parms(inv:dict);_set_mqtt_timestamp(key, ts);_timeout();_send_modbus_cmd();<async>send_modbus_cmd();_send_modbus_scan();_dump_modbus_scan();close();inc_counter();dec_counter()]
[Message]use->[<<AsyncIfc>>]
[<<ProtocolIfc>>|_registry|close()]

View File

@@ -1,8 +1,8 @@
flake8==7.2.0
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.1.1
python-dotenv==1.1.0
mock==5.2.0
coverage==7.8.0
jinja2-cli==0.8.2
flake8
pytest
pytest-asyncio
pytest-cov
python-dotenv
mock
coverage
jinja2-cli

View File

@@ -1,4 +1,4 @@
aiomqtt==2.3.1
aiomqtt==2.3.0
schema==0.7.7
aiocron==2.1
aiohttp==3.11.16
aiohttp==3.11.14

View File

@@ -34,11 +34,10 @@ class Control:
class Talent(Message):
TXT_UNKNOWN_CTRL = 'Unknown Ctrl'
def __init__(self, inverter, addr, ifc: "AsyncIfc", server_side: bool,
def __init__(self, addr, ifc: "AsyncIfc", server_side: bool,
client_mode: bool = False, id_str=b''):
super().__init__('G3', ifc, server_side, self.send_modbus_cb,
mb_timeout=15)
_ = inverter
ifc.rx_set_cb(self.read)
ifc.prot_set_timeout_cb(self._timeout)
ifc.prot_set_init_new_client_conn_cb(self._init_new_client_conn)

View File

@@ -19,19 +19,6 @@ class RegisterFunc:
result += prod
return result
@staticmethod
def cmp_values(info: Infos, params: map) -> None | int:
try:
val = info.get_db_value(params['reg'])
if val < params['cmp_val']:
return params['res'][0]
if val == params['cmp_val']:
return params['res'][1]
return params['res'][2]
except Exception:
pass
return None
class RegisterMap:
# make the class read/only by using __slots__
@@ -144,54 +131,52 @@ class RegisterMap:
0x4201000c: {'reg': Register.SENSOR_LIST, 'fmt': '<H', 'func': Fmt.hex4}, # noqa: E501
0x4201001c: {'reg': Register.POWER_ON_TIME, 'fmt': '<H', 'ratio': 1, 'dep': ProxyMode.SERVER}, # noqa: E501, or packet number
0x42010020: {'reg': Register.SERIAL_NUMBER, 'fmt': '!16s'}, # noqa: E501
0x42010030: {'reg': Register.BATT_PV1_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Voltage PV1
0x42010032: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Current PV1
0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Voltage PV2
0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Current PV2
0x42010038: {'reg': Register.BATT_TOTAL_CHARG, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
0x4201003c: {'reg': Register.BATT_PV1_STATUS, 'fmt': '!H'}, # noqa: E501 MPTT-1 Operating Status: 0(Standby), 1(Work)
0x4201003e: {'reg': Register.BATT_PV2_STATUS, 'fmt': '!H'}, # noqa: E501 MPTT-2 Operating Status: 0(Standby), 1(Work)
0x42010030: {'reg': Register.BATT_PV1_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 voltage
0x42010032: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 current
0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage
0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current
0x42010038: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501
0x4201003a: {'reg': Register.BATT_TOTAL_GEN, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x4201003c: {'reg': Register.BATT_STATUS_1, 'fmt': '!h'}, # noqa: E501 MPTT-1 Status?
0x4201003e: {'reg': Register.BATT_STATUS_2, 'fmt': '!h'}, # noqa: E501 MPTT-2 Status?
0x42010040: {'reg': Register.BATT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x42010042: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 => Batterie Status: <0(Discharging), 0(Static), 0>(Loading)
0x42010042: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x42010044: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent
0x42010046: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010048: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201004a: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201004c: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201004e: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010050: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010052: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010054: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010056: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010058: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201005a: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201005c: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x4201005e: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010060: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010062: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x42010064: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501H
0x42010066: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501 Cell Temperture 1
0x42010068: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501 Cell Temperture 2
0x4201006a: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501 Cell Temperture 3
0x4201006c: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 Output Voltage
0x4201006e: {'reg': Register.BATT_OUT_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 Output Current
0x42010070: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!H'}, # noqa: E501 Output Working Status: 0(Standby), 1(Work)
0x42010072: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E50, Environment temp
0x42010074: {'reg': Register.BATT_ALARM, 'fmt': '!H'}, # noqa: E501 Warning Alarmcode 1, Bit 0..15
0x42010076: {'reg': Register.BATT_HW_VERS, 'fmt': '!h'}, # noqa: E501 hardware version
0x42010078: {'reg': Register.BATT_SW_VERS, 'fmt': '!h'}, # noqa: E501 software main version
0x42010046: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010048: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201004a: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201004c: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201004e: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010050: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010052: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010054: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010056: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010058: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201005a: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201005c: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x4201005e: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010060: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010062: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010064: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x42010066: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501
0x42010068: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501
0x4201006a: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501
0x4201006c: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x4201006e: {'reg': Register.BATT_OUT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x42010070: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!h'}, # noqa: E501, state of output value 0 or 1
0x42010072: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E501 controller temp
0x42010074: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501, control input 0..2048
0x42010076: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501
0x42010078: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501
'calc': {
1: {'reg': Register.BATT_PV_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 Generated Power
1: {'reg': Register.BATT_PV_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
'params': [[Register.BATT_PV1_VOLT, Register.BATT_PV1_CUR],
[Register.BATT_PV2_VOLT, Register.BATT_PV2_CUR]]},
2: {'reg': Register.BATT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
'params': [[Register.BATT_VOLT, Register.BATT_CUR]]},
3: {'reg': Register.BATT_OUT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 Supply Power => Power Supply State: 0(Idle), 0>(Power Supply)
3: {'reg': Register.BATT_OUT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
'params': [[Register.BATT_OUT_VOLT, Register.BATT_OUT_CUR]]},
4: {'reg': Register.BATT_PWR_SUPL_STATE, 'func': RegisterFunc.cmp_values, # noqa: E501
'params': {'reg': Register.BATT_OUT_PWR, 'cmp_val': 0, 'res': [0, 0, 1]}}, # noqa: E501
5: {'reg': Register.BATT_STATUS, 'func': RegisterFunc.cmp_values, # noqa: E501
'params': {'reg': Register.BATT_CUR, 'cmp_val': 0.0, 'res': [0, 1, 2]}} # noqa: E501
}
}

View File

@@ -8,15 +8,6 @@ from gen3plus.solarman_emu import SolarmanEmu
class InverterG3P(InverterBase):
def __init__(self, reader: StreamReader, writer: StreamWriter,
client_mode: bool = False):
# shared value between both inverter connections
self.forward_at_cmd_resp = False
'''Flag if response for the last at command must be send to the cloud.
False: send result only to the MQTT broker, cause the AT+ command
came from there
True: send response packet to the cloud, cause the AT+ command
came from the cloud'''
remote_prot = None
if client_mode:
remote_prot = SolarmanEmu

View File

@@ -10,12 +10,11 @@ logger = logging.getLogger('msg')
class SolarmanEmu(SolarmanBase):
def __init__(self, inverter, addr, ifc: "AsyncIfc",
def __init__(self, addr, ifc: "AsyncIfc",
server_side: bool, client_mode: bool):
super().__init__(addr, ifc, server_side=False,
_send_modbus_cb=None,
mb_timeout=8)
_ = inverter
logging.debug('SolarmanEmu.init()')
self.db = ifc.remote.stream.db
self.snr = ifc.remote.stream.snr

View File

@@ -253,13 +253,13 @@ class SolarmanV5(SolarmanBase):
HDR_FMT = '<BLLL'
'''format string for packing of the header'''
def __init__(self, inverter, addr, ifc: "AsyncIfc",
def __init__(self, addr, ifc: "AsyncIfc",
server_side: bool, client_mode: bool):
super().__init__(addr, ifc, server_side, self.send_modbus_cb,
mb_timeout=8)
self.inverter = inverter
self.db = InfosG3P(client_mode)
self.forward_at_cmd_resp = False
self.no_forwarding = False
'''not allowed to connect to TSUN cloud by connection type'''
self.establish_inv_emu = False
@@ -335,7 +335,6 @@ class SolarmanV5(SolarmanBase):
# we have references to methods of this class in self.switch
# so we have to erase self.switch, otherwise this instance can't be
# deallocated by the garbage collector ==> we get a memory leak
self.inverter = None
self.switch.clear()
self.log_lvl.clear()
super().close()
@@ -520,7 +519,7 @@ class SolarmanV5(SolarmanBase):
await Proxy.mqtt.publish(f'{Proxy.entity_prfx}{node_id}{key}', data_json) # noqa: E501
return
self.inverter.forward_at_cmd_resp = False
self.forward_at_cmd_resp = False
self._build_header(0x4510)
self.ifc.tx_add(struct.pack(f'<BHLLL{len(at_cmd)}sc', self.AT_CMD,
0x0002, 0, 0, 0,
@@ -645,7 +644,7 @@ class SolarmanV5(SolarmanBase):
self.inc_counter('AT_Command_Blocked')
return
self.inc_counter('AT_Command')
self.inverter.forward_at_cmd_resp = True
self.forward_at_cmd_resp = True
elif ftype == self.MB_RTU_CMD:
rstream = self.ifc.remote.stream
@@ -665,9 +664,8 @@ class SolarmanV5(SolarmanBase):
def get_cmd_rsp_log_lvl(self) -> int:
ftype = self.ifc.rx_peek()[self.header_len]
if ftype == self.AT_CMD or \
ftype == self.AT_CMD_RSP:
if self.inverter.forward_at_cmd_resp:
if ftype == self.AT_CMD:
if self.forward_at_cmd_resp:
return logging.INFO
return logging.DEBUG
elif ftype == self.MB_RTU_CMD \
@@ -682,7 +680,7 @@ class SolarmanV5(SolarmanBase):
ftype = data[0]
if ftype == self.AT_CMD or \
ftype == self.AT_CMD_RSP:
if not self.inverter.forward_at_cmd_resp:
if not self.forward_at_cmd_resp:
data_json = data[14:].decode("utf-8")
node_id = self.node_id
key = 'at_resp'

View File

@@ -125,9 +125,10 @@ class Register(Enum):
BATT_PV1_CUR = 1001
BATT_PV2_VOLT = 1002
BATT_PV2_CUR = 1003
BATT_TOTAL_CHARG = 1005
BATT_PV1_STATUS = 1006
BATT_PV2_STATUS = 1007
BATT_38 = 1004
BATT_TOTAL_GEN = 1005
BATT_STATUS_1 = 1006
BATT_STATUS_2 = 1007
BATT_VOLT = 1010
BATT_CUR = 1011
BATT_SOC = 1012
@@ -154,14 +155,12 @@ class Register(Enum):
BATT_OUT_CUR = 1033
BATT_OUT_STATUS = 1034
BATT_TEMP_4 = 1035
BATT_ALARM = 1036
BATT_HW_VERS = 1037
BATT_SW_VERS = 1038
BATT_74 = 1036
BATT_76 = 1037
BATT_78 = 1038
BATT_PV_PWR = 1040
BATT_PWR = 1041
BATT_OUT_PWR = 1042
BATT_PWR_SUPL_STATE = 1043
BATT_STATUS = 1044
TEST_VAL_0 = 2000
TEST_VAL_1 = 2001
@@ -326,11 +325,9 @@ class Infos:
SOLAR_POWER_VAR = 'mdi:solar-power-variant'
SOLAR_POWER = 'mdi:solar-power'
WIFI = 'mdi:wifi'
ALARM_LIGHT = 'mdi:alarm-light'
UPDATE = 'mdi:update'
DAILY_GEN = 'Daily Generation'
TOTAL_GEN = 'Total Generation'
TOTAL_CHARG = 'Total Charging Energy'
FMT_INT = '| int'
FMT_FLOAT = '| float'
FMT_STRING_SEC = '| string + " s"'
@@ -370,7 +367,7 @@ class Infos:
'input_pv5': {'via': 'inverter', 'name': 'Module PV5', 'mdl': Register.PV5_MODEL, 'mf': Register.PV5_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 5}}, # noqa: E501
'input_pv6': {'via': 'inverter', 'name': 'Module PV6', 'mdl': Register.PV6_MODEL, 'mf': Register.PV6_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 6}}, # noqa: E501
'batterie': {'via': 'controller', 'name': 'Batterie', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'hw': Register.BATT_HW_VERS, 'sw': Register.BATT_SW_VERS, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
'batterie': {'via': 'controller', 'name': 'Batterie', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'sw': Register.VERSION, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
'bat_inp_pv1': {'via': 'batterie', 'name': 'Module PV1', 'mdl': Register.PV1_MODEL, 'mf': Register.PV1_MANUFACTURER}, # noqa: E501
'bat_inp_pv2': {'via': 'batterie', 'name': 'Module PV2', 'mdl': Register.PV2_MODEL, 'mf': Register.PV2_MANUFACTURER}, # noqa: E501
}
@@ -378,11 +375,9 @@ class Infos:
__comm_type_val_tpl = "{%set com_types = ['n/a','Wi-Fi', 'G4', 'G5', 'GPRS'] %}{{com_types[value_json['Communication_Type']|int(0)]|default(value_json['Communication_Type'])}}" # noqa: E501
__work_mode_val_tpl = "{%set mode = ['Normal-Mode', 'Aging-Mode', 'ATE-Mode', 'Shielding GFDI', 'DTU-Mode'] %}{{mode[value_json['Work_Mode']|int(0)]|default(value_json['Work_Mode'])}}" # noqa: E501
__status_type_val_tpl = "{%set inv_status = ['Off-line', 'On-grid', 'Off-grid'] %}{{inv_status[value_json['Inverter_Status']|int(0)]|default(value_json['Inverter_Status'])}}" # noqa: E501
__mppt1_status_type_val_tpl = "{%set mppt_status = ['Standby', 'On', 'Off'] %}{{mppt_status[value_json['pv1']['MPPT-Status']|int(0)]|default(value_json['pv1']['MPPT-Status'])}}" # noqa: E501
__mppt2_status_type_val_tpl = "{%set mppt_status = ['Standby', 'On', 'Off'] %}{{mppt_status[value_json['pv2']['MPPT-Status']|int(0)]|default(value_json['pv2']['MPPT-Status'])}}" # noqa: E501
__supply_status_type_val_tpl = "{%set supply_status = ['Idle', 'Power-Supply'] %}{{supply_status[value_json['out']['Suppl_State']|int(0)]|default(value_json['out']['Suppl_State'])}}" # noqa: E501
__batt_status_type_val_tpl = "{%set batt_status = ['Discharging', 'Static', 'Loading'] %}{{batt_status[value_json['batt']['Batt_State']|int(0)]|default(value_json['batt']['Batt_State'])}}" # noqa: E501
__out_status_type_val_tpl = "{%set out_status = ['Standby', 'On', 'Off'] %}{{out_status[value_json['out']['Out_Status']|int(0)]|default(value_json['out']['Out_Status'])}}" # noqa: E501
__mppt1_status_type_val_tpl = "{%set mppt_status = ['Locked', 'On', 'Off'] %}{{mppt_status[value_json['Status_1']|int(0)]|default(value_json['Status_1'])}}" # noqa: E501
__mppt2_status_type_val_tpl = "{%set mppt_status = ['Locked', 'On', 'Off'] %}{{mppt_status[value_json['Status_2']|int(0)]|default(value_json['Status_2'])}}" # noqa: E501
__out_status_type_val_tpl = "{%set out_status = ['Off', 'On'] %}{{out_status[value_json['out']['Out_Status']|int(0)]|default(value_json['out']['Out_Status'])}}" # noqa: E501
__rated_power_val_tpl = "{% if 'Rated_Power' in value_json and value_json['Rated_Power'] != None %}{{value_json['Rated_Power']|string() +' W'}}{% else %}{{ this.state }}{% endif %}" # noqa: E501
__designed_power_val_tpl = '''
{% if 'Max_Designed_Power' in value_json and
@@ -404,52 +399,52 @@ class Infos:
{% set result = 'noAlarm'%}
{%else%}
{% set result = '' %}
{% if val_int | bitwise_and(0x0001)%}
{% if val_int | bitwise_and(1)%}
{% set result = result + 'HBridgeFault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0002)%}
{% if val_int | bitwise_and(2)%}
{% set result = result + 'DriVoltageFault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0004)%}
{% if val_int | bitwise_and(3)%}
{% set result = result + 'GFDI-Fault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0008)%}
{% if val_int | bitwise_and(4)%}
{% set result = result + 'OverTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0010)%}
{% if val_int | bitwise_and(5)%}
{% set result = result + 'CommLose, '%}
{% endif %}
{% if val_int | bitwise_and(0x0020)%}
{% if val_int | bitwise_and(6)%}
{% set result = result + 'Bit6, '%}
{% endif %}
{% if val_int | bitwise_and(0x0040)%}
{% if val_int | bitwise_and(7)%}
{% set result = result + 'Bit7, '%}
{% endif %}
{% if val_int | bitwise_and(0x0080)%}
{% if val_int | bitwise_and(8)%}
{% set result = result + 'EEPROM-Fault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0100)%}
{% if val_int | bitwise_and(9)%}
{% set result = result + 'NoUtility, '%}
{% endif %}
{% if val_int | bitwise_and(0x0200)%}
{% if val_int | bitwise_and(10)%}
{% set result = result + 'VG_Offset, '%}
{% endif %}
{% if val_int | bitwise_and(0x0400)%}
{% if val_int | bitwise_and(11)%}
{% set result = result + 'Relais_Open, '%}
{% endif %}
{% if val_int | bitwise_and(0x0800)%}
{% if val_int | bitwise_and(12)%}
{% set result = result + 'Relais_Short, '%}
{% endif %}
{% if val_int | bitwise_and(0x1000)%}
{% if val_int | bitwise_and(13)%}
{% set result = result + 'GridVoltOverRating, '%}
{% endif %}
{% if val_int | bitwise_and(0x2000)%}
{% if val_int | bitwise_and(14)%}
{% set result = result + 'GridVoltUnderRating, '%}
{% endif %}
{% if val_int | bitwise_and(0x4000)%}
{% if val_int | bitwise_and(15)%}
{% set result = result + 'GridFreqOverRating, '%}
{% endif %}
{% if val_int | bitwise_and(0x8000)%}
{% if val_int | bitwise_and(16)%}
{% set result = result + 'GridFreqUnderRating, '%}
{% endif %}
{% endif %}
@@ -466,104 +461,42 @@ class Infos:
{% set result = 'noFault'%}
{%else%}
{% set result = '' %}
{% if val_int | bitwise_and(0x0001)%}
{% if val_int | bitwise_and(1)%}
{% set result = result + 'PVOV-Fault (PV OverVolt), '%}
{% endif %}
{% if val_int | bitwise_and(0x0002)%}
{% if val_int | bitwise_and(2)%}
{% set result = result + 'PVLV-Fault (PV LowVolt), '%}
{% endif %}
{% if val_int | bitwise_and(0x0004)%}
{% if val_int | bitwise_and(3)%}
{% set result = result + 'PV OI-Fault (PV OverCurrent), '%}
{% endif %}
{% if val_int | bitwise_and(0x0008)%}
{% if val_int | bitwise_and(4)%}
{% set result = result + 'PV OFV-Fault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0010)%}
{% if val_int | bitwise_and(5)%}
{% set result = result + 'DC ShortCircuitFault, '%}
{% endif %}
{% if val_int | bitwise_and(0x0020)%}{% set result = result + 'Bit6, '%}
{% if val_int | bitwise_and(6)%}{% set result = result + 'Bit6, '%}
{% endif %}
{% if val_int | bitwise_and(0x0040)%}{% set result = result + 'Bit7, '%}
{% if val_int | bitwise_and(7)%}{% set result = result + 'Bit7, '%}
{% endif %}
{% if val_int | bitwise_and(0x0080)%}{% set result = result + 'Bit8, '%}
{% if val_int | bitwise_and(8)%}{% set result = result + 'Bit8, '%}
{% endif %}
{% if val_int | bitwise_and(0x0100)%}{% set result = result + 'Bit9, '%}
{% if val_int | bitwise_and(9)%}{% set result = result + 'Bit9, '%}
{% endif %}
{% if val_int | bitwise_and(0x0200)%}{% set result = result + 'Bit10, '%}
{% if val_int | bitwise_and(10)%}{% set result = result + 'Bit10, '%}
{% endif %}
{% if val_int | bitwise_and(0x0400)%}{% set result = result + 'Bit11, '%}
{% if val_int | bitwise_and(11)%}{% set result = result + 'Bit11, '%}
{% endif %}
{% if val_int | bitwise_and(0x0800)%}{% set result = result + 'Bit12, '%}
{% if val_int | bitwise_and(12)%}{% set result = result + 'Bit12, '%}
{% endif %}
{% if val_int | bitwise_and(0x1000)%}{% set result = result + 'Bit13, '%}
{% if val_int | bitwise_and(13)%}{% set result = result + 'Bit13, '%}
{% endif %}
{% if val_int | bitwise_and(0x2000)%}{% set result = result + 'Bit14, '%}
{% if val_int | bitwise_and(14)%}{% set result = result + 'Bit14, '%}
{% endif %}
{% if val_int | bitwise_and(0x4000)%}{% set result = result + 'Bit15, '%}
{% if val_int | bitwise_and(15)%}{% set result = result + 'Bit15, '%}
{% endif %}
{% if val_int | bitwise_and(0x8000)%}{% set result = result + 'Bit16, '%}
{% endif %}
{% endif %}
{{ result }}
{% else %}
{{ this.state }}
{% endif %}
'''
__batt_alarm_val_tpl = '''
{% if 'Batterie_Alarm' in value_json and
value_json['Batterie_Alarm'] != None %}
{% set val_int = value_json['Batterie_Alarm'] | int %}
{% if val_int == 0 %}
{% set result = 'noAlarm'%}
{%else%}
{% set result = '' %}
{% if val_int | bitwise_and(0x0001)%}
{% set result = result + 'PV1-OverVoltage, '%}
{% endif %}
{% if val_int | bitwise_and(0x0002)%}
{% set result = result + 'PV2-OverVoltage, '%}
{% endif %}
{% if val_int | bitwise_and(0x0004)%}
{% set result = result + 'EquipmentOverheating, '%}
{% endif %}
{% if val_int | bitwise_and(0x0008)%}
{% set result = result + 'EquipmentLowTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0010)%}
{% set result = result + 'BMS-CommFailed, '%}
{% endif %}
{% if val_int | bitwise_and(0x0020)%}
{% set result = result + 'UnderVoltageProt, '%}
{% endif %}
{% if val_int | bitwise_and(0x0040)%}
{% set result = result + 'ChargingHighTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0080)%}
{% set result = result + 'ChargingLowTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0100)%}
{% set result = result + 'DischargeHighTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0200)%}
{% set result = result + 'DischargeLowTemp, '%}
{% endif %}
{% if val_int | bitwise_and(0x0400)%}
{% set result = result + 'BatterieOverVoltage, '%}
{% endif %}
{% if val_int | bitwise_and(0x0800)%}
{% set result = result + 'SingleCorePressureDifferenceIsTooLarge, '%}
{% endif %}
{% if val_int | bitwise_and(0x1000)%}
{% set result = result + 'Bit-12, '%}
{% endif %}
{% if val_int | bitwise_and(0x2000)%}
{% set result = result + 'Bit-13, '%}
{% endif %}
{% if val_int | bitwise_and(0x4000)%}
{% set result = result + 'Bit-14, '%}
{% endif %}
{% if val_int | bitwise_and(0x8000)%}
{% set result = result + 'Bit-15, '%}
{% if val_int | bitwise_and(16)%}{% set result = result + 'Bit16, '%}
{% endif %}
{% endif %}
{{ result }}
@@ -629,8 +562,8 @@ class Infos:
# 0xffffff03: {'name':['proxy', 'Voltage'], 'level': logging.DEBUG, 'unit': 'V', 'ha':{'dev':'proxy', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id':'proxy_volt_', 'fmt':FMT_FLOAT,'name': 'Grid Voltage'}}, # noqa: E501
# events
Register.EVENT_ALARM: {'name': ['events', 'Inverter_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_alarm_', 'name': 'Inverter Alarm', 'val_tpl': __inv_alarm_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
Register.EVENT_FAULT: {'name': ['events', 'Inverter_Fault'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_fault_', 'name': 'Inverter Fault', 'val_tpl': __inv_fault_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
Register.EVENT_ALARM: {'name': ['events', 'Inverter_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_alarm_', 'name': 'Inverter Alarm', 'val_tpl': __inv_alarm_val_tpl, 'icon': 'mdi:alarm-light'}}, # noqa: E501
Register.EVENT_FAULT: {'name': ['events', 'Inverter_Fault'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_fault_', 'name': 'Inverter Fault', 'val_tpl': __inv_fault_val_tpl, 'icon': 'mdi:alarm-light'}}, # noqa: E501
Register.EVENT_BF1: {'name': ['events', 'Inverter_Bitfield_1'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.EVENT_BF2: {'name': ['events', 'Inverter_bitfield_2'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
# Register.EVENT_409: {'name': ['events', '409_No_Utility'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
@@ -703,53 +636,46 @@ class Infos:
Register.PROD_COMPL_TYPE: {'name': ['other', 'Prod_Compliance_Type'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.INV_UNKNOWN_1: {'name': ['inv_unknown', 'Unknown_1'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
# Batterie DC-1000: Electricity Genration
Register.BATT_PV1_STATUS: {'name': ['batterie', 'pv1', 'MPPT-Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status1_', 'name': 'MPPT-1 Status', 'val_tpl': __mppt1_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_PV1_VOLT: {'name': ['batterie', 'pv1', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv1_', 'val_tpl': "{{ (value_json['pv1']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV1_CUR: {'name': ['batterie', 'pv1', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv1_', 'val_tpl': "{{ (value_json['pv1']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV2_STATUS: {'name': ['batterie', 'pv2', 'MPPT-Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status2_', 'name': 'MPPT-2 Status', 'val_tpl': __mppt2_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_PV2_VOLT: {'name': ['batterie', 'pv2', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv2_', 'val_tpl': "{{ (value_json['pv2']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV2_CUR: {'name': ['batterie', 'pv2', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv2_', 'val_tpl': "{{ (value_json['pv2']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV_PWR: {'name': ['batterie', 'PV_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'pv_power_', 'fmt': FMT_INT, 'name': 'PV Power'}}, # noqa: E501
Register.BATT_OUT_STATUS: {'name': ['batterie', 'out', 'Out_Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'out_status_', 'name': 'Output Status', 'val_tpl': __out_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_38: {'name': ['batterie', 'Reg_38'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_38_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TOTAL_GEN: {'name': ['batterie', 'Total_Generation'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'batterie', 'dev_cla': 'energy', 'stat_cla': 'total', 'id': 'total_gen_', 'fmt': FMT_FLOAT, 'name': TOTAL_GEN, 'icon': SOLAR_POWER, 'must_incr': True}}, # noqa: E501
Register.BATT_STATUS_1: {'name': ['batterie', 'Status_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status1_', 'name': 'MPPT-1 Status', 'val_tpl': __mppt1_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_STATUS_2: {'name': ['batterie', 'Status_2'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status2_', 'name': 'MPPT-2 Status', 'val_tpl': __mppt2_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_VOLT: {'name': ['batterie', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_bat_', 'fmt': FMT_FLOAT, 'name': 'Batterie Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CUR: {'name': ['batterie', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_bat_', 'fmt': FMT_FLOAT, 'name': 'Batterie Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_SOC: {'name': ['batterie', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'fmt': FMT_FLOAT, 'name': 'State of Charge (SOC)', 'icon': 'mdi:battery-90'}}, # noqa: E501
Register.BATT_CELL1_VOLT: {'name': ['batterie', 'Cell', 'Volt1'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell1_', 'val_tpl': "{{ (value_json['Cell']['Volt1'] | float)}}", 'name': 'Cell-01 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL3_VOLT: {'name': ['batterie', 'Cell', 'Volt3'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell3_', 'val_tpl': "{{ (value_json['Cell']['Volt2'] | float)}}", 'name': 'Cell-03 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL4_VOLT: {'name': ['batterie', 'Cell', 'Volt4'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell4_', 'val_tpl': "{{ (value_json['Cell']['Volt3'] | float)}}", 'name': 'Cell-04 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL2_VOLT: {'name': ['batterie', 'Cell', 'Volt2'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell2_', 'val_tpl': "{{ (value_json['Cell']['Volt4'] | float)}}", 'name': 'Cell-02 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL5_VOLT: {'name': ['batterie', 'Cell', 'Volt5'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell5_', 'val_tpl': "{{ (value_json['Cell']['Volt5'] | float)}}", 'name': 'Cell-05 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL6_VOLT: {'name': ['batterie', 'Cell', 'Volt6'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell6_', 'val_tpl': "{{ (value_json['Cell']['Volt6'] | float)}}", 'name': 'Cell-06 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL7_VOLT: {'name': ['batterie', 'Cell', 'Volt7'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell7_', 'val_tpl': "{{ (value_json['Cell']['Volt7'] | float)}}", 'name': 'Cell-07 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL8_VOLT: {'name': ['batterie', 'Cell', 'Volt8'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell8_', 'val_tpl': "{{ (value_json['Cell']['Volt8'] | float)}}", 'name': 'Cell-08 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL9_VOLT: {'name': ['batterie', 'Cell', 'Volt9'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell9_', 'val_tpl': "{{ (value_json['Cell']['Volt9'] | float)}}", 'name': 'Cell-09 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL10_VOLT: {'name': ['batterie', 'Cell', 'Volt10'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell10_', 'val_tpl': "{{ (value_json['Cell']['Volt10'] | float)}}", 'name': 'Cell-10 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL11_VOLT: {'name': ['batterie', 'Cell', 'Volt11'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell11_', 'val_tpl': "{{ (value_json['Cell']['Volt11'] | float)}}", 'name': 'Cell-11 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL12_VOLT: {'name': ['batterie', 'Cell', 'Volt12'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell12_', 'val_tpl': "{{ (value_json['Cell']['Volt12'] | float)}}", 'name': 'Cell-12 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL13_VOLT: {'name': ['batterie', 'Cell', 'Volt13'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell13_', 'val_tpl': "{{ (value_json['Cell']['Volt13'] | float)}}", 'name': 'Cell-13 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL14_VOLT: {'name': ['batterie', 'Cell', 'Volt14'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell14_', 'val_tpl': "{{ (value_json['Cell']['Volt14'] | float)}}", 'name': 'Cell-14 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL15_VOLT: {'name': ['batterie', 'Cell', 'Volt15'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell15_', 'val_tpl': "{{ (value_json['Cell']['Volt15'] | float)}}", 'name': 'Cell-15 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL16_VOLT: {'name': ['batterie', 'Cell', 'Volt16'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell16_', 'val_tpl': "{{ (value_json['Cell']['Volt16'] | float)}}", 'name': 'Cell-16 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_1: {'name': ['batterie', 'Temp_1'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_1_', 'fmt': FMT_INT, 'name': 'Batterie Temp-1', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_2: {'name': ['batterie', 'Temp_2'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_2_', 'fmt': FMT_INT, 'name': 'Batterie Temp-2', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_3: {'name': ['batterie', 'Temp_3'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_3_', 'fmt': FMT_INT, 'name': 'Batterie Temp-3', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_OUT_VOLT: {'name': ['batterie', 'out', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'out_volt_', 'val_tpl': "{{ (value_json['out']['Voltage'] | float)}}", 'name': 'Output Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_OUT_CUR: {'name': ['batterie', 'out', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'out_cur_', 'val_tpl': "{{ (value_json['out']['Current'] | float)}}", 'name': 'Output Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_OUT_PWR: {'name': ['batterie', 'out', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'val_tpl': "{{ (value_json['out']['Power'] | int)}}", 'name': 'Supply Power'}}, # noqa: E501
Register.BATT_PWR_SUPL_STATE: {'name': ['batterie', 'out', 'Suppl_State'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status_supply_', 'name': 'Supply State', 'val_tpl': __supply_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
# Batterie DC-1000: Cell Package
Register.BATT_CELL1_VOLT: {'name': ['batterie', 'cell', 'Volt1'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell1_', 'val_tpl': "{{ (value_json['cell']['Volt1'] | float)}}", 'name': 'Cell-01 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL3_VOLT: {'name': ['batterie', 'cell', 'Volt3'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell3_', 'val_tpl': "{{ (value_json['cell']['Volt2'] | float)}}", 'name': 'Cell-03 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL4_VOLT: {'name': ['batterie', 'cell', 'Volt4'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell4_', 'val_tpl': "{{ (value_json['cell']['Volt3'] | float)}}", 'name': 'Cell-04 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL2_VOLT: {'name': ['batterie', 'cell', 'Volt2'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell2_', 'val_tpl': "{{ (value_json['cell']['Volt4'] | float)}}", 'name': 'Cell-02 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL5_VOLT: {'name': ['batterie', 'cell', 'Volt5'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell5_', 'val_tpl': "{{ (value_json['cell']['Volt5'] | float)}}", 'name': 'Cell-05 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL6_VOLT: {'name': ['batterie', 'cell', 'Volt6'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell6_', 'val_tpl': "{{ (value_json['cell']['Volt6'] | float)}}", 'name': 'Cell-06 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL7_VOLT: {'name': ['batterie', 'cell', 'Volt7'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell7_', 'val_tpl': "{{ (value_json['cell']['Volt7'] | float)}}", 'name': 'Cell-07 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL8_VOLT: {'name': ['batterie', 'cell', 'Volt8'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell8_', 'val_tpl': "{{ (value_json['cell']['Volt8'] | float)}}", 'name': 'Cell-08 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL9_VOLT: {'name': ['batterie', 'cell', 'Volt9'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell9_', 'val_tpl': "{{ (value_json['cell']['Volt9'] | float)}}", 'name': 'Cell-09 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL10_VOLT: {'name': ['batterie', 'cell', 'Volt10'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell10_', 'val_tpl': "{{ (value_json['cell']['Volt10'] | float)}}", 'name': 'Cell-10 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL11_VOLT: {'name': ['batterie', 'cell', 'Volt11'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell11_', 'val_tpl': "{{ (value_json['cell']['Volt11'] | float)}}", 'name': 'Cell-11 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL12_VOLT: {'name': ['batterie', 'cell', 'Volt12'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell12_', 'val_tpl': "{{ (value_json['cell']['Volt12'] | float)}}", 'name': 'Cell-12 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL13_VOLT: {'name': ['batterie', 'cell', 'Volt13'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell13_', 'val_tpl': "{{ (value_json['cell']['Volt13'] | float)}}", 'name': 'Cell-13 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL14_VOLT: {'name': ['batterie', 'cell', 'Volt14'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell14_', 'val_tpl': "{{ (value_json['cell']['Volt14'] | float)}}", 'name': 'Cell-14 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL15_VOLT: {'name': ['batterie', 'cell', 'Volt15'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell15_', 'val_tpl': "{{ (value_json['cell']['Volt15'] | float)}}", 'name': 'Cell-15 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CELL16_VOLT: {'name': ['batterie', 'cell', 'Volt16'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell16_', 'val_tpl': "{{ (value_json['cell']['Volt16'] | float)}}", 'name': 'Cell-16 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
# Batterie DC-1000: Batterie Pack
Register.BATT_VOLT: {'name': ['batterie', 'batt', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_bat_', 'val_tpl': "{{ (value_json['batt']['Voltage'] | float)}}", 'name': 'Batterie Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_CUR: {'name': ['batterie', 'batt', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_bat_', 'val_tpl': "{{ (value_json['batt']['Current'] | float)}}", 'name': 'Batterie Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PWR: {'name': ['batterie', 'batt', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'power_', 'val_tpl': "{{ (value_json['batt']['Power'] | int)}}", 'name': 'Batterie Power'}}, # noqa: E501
Register.BATT_SOC: {'name': ['batterie', 'batt', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'val_tpl': "{{ (value_json['batt']['SOC'] | float)}}", 'name': 'State of Charge (SOC)', 'icon': 'mdi:battery-90'}}, # noqa: E501
Register.BATT_TOTAL_CHARG: {'name': ['batterie', 'batt', 'Total_Charging'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'batterie', 'dev_cla': 'energy', 'stat_cla': 'total', 'id': 'total_charg_', 'val_tpl': "{{ (value_json['batt']['Total_Charging'] | float)}}", 'name': TOTAL_CHARG, 'icon': 'mdi:battery-charging', 'must_incr': True}}, # noqa: E501
Register.BATT_STATUS: {'name': ['batterie', 'batt', 'Batt_State'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status_batt_', 'name': 'Batterie State', 'val_tpl': __batt_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_TEMP_1: {'name': ['batterie', 'cell', 'Temp_1'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_1_', 'val_tpl': "{{ (value_json['cell']['Temp_1'] | int)}}", 'name': 'Cell Temp-1', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_2: {'name': ['batterie', 'cell', 'Temp_2'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_2_', 'val_tpl': "{{ (value_json['cell']['Temp_2'] | int)}}", 'name': 'Cell Temp-2', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_3: {'name': ['batterie', 'cell', 'Temp_3'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_3_', 'val_tpl': "{{ (value_json['cell']['Temp_3'] | int)}}", 'name': 'Cell Temp-3', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_TEMP_4: {'name': ['batterie', 'Controller_Temp'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_4_', 'fmt': FMT_INT, 'name': 'Temperature'}}, # noqa: E501
Register.BATT_ALARM: {'name': ['batterie', 'Batterie_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'batt_alarm_', 'name': 'Batterie Alarm', 'val_tpl': __batt_alarm_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
Register.BATT_HW_VERS: {'name': ['batterie', 'Hardware_Version'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.BATT_SW_VERS: {'name': ['batterie', 'Software_Version'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.BATT_OUT_STATUS: {'name': ['batterie', 'out', 'Out_Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'out_status_', 'name': 'Output Status', 'val_tpl': __out_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
Register.BATT_TEMP_4: {'name': ['batterie', 'Controller_Temp'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_4_', 'fmt': FMT_INT, 'name': 'Ctrl Temperature'}}, # noqa: E501
Register.BATT_74: {'name': ['batterie', 'Reg_74'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_74_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_76: {'name': ['batterie', 'Reg_76'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_76_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_78: {'name': ['batterie', 'Reg_78'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_78_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV_PWR: {'name': ['batterie', 'PV_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'pv_power_', 'fmt': FMT_INT, 'name': 'PV Power'}}, # noqa: E501
Register.BATT_PWR: {'name': ['batterie', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'power_', 'fmt': FMT_INT, 'name': 'Batterie Power'}}, # noqa: E501
Register.BATT_OUT_PWR: {'name': ['batterie', 'out', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'val_tpl': "{{ (value_json['out']['Power'] | int)}}", 'name': 'Output Power'}}, # noqa: E501
Register.TEST_VAL_0: {'name': ['input', 'Val_0'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'val_0_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.TEST_VAL_1: {'name': ['input', 'Val_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'val_1_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501

View File

@@ -41,7 +41,7 @@ class InverterBase(InverterIfc, Proxy):
self.remote)
self.local = StreamPtr(
prot_class(self, self.addr, ifc, True, client_mode), ifc
prot_class(self.addr, ifc, True, client_mode), ifc
)
def __enter__(self):
@@ -122,11 +122,11 @@ class InverterBase(InverterIfc, Proxy):
self.remote.ifc = ifc
if hasattr(stream, 'id_str'):
self.remote.stream = self.prot_class(
self, addr, ifc, server_side=False,
addr, ifc, server_side=False,
client_mode=False, id_str=stream.id_str)
else:
self.remote.stream = self.prot_class(
self, addr, ifc, server_side=False,
addr, ifc, server_side=False,
client_mode=False)
logging.info(f'[{self.remote.stream.node_id}:'

View File

@@ -42,38 +42,39 @@ class Modbus():
0x0009: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 current
0x000a: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage
0x000b: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current
0x000c: {'reg': Register.BATT_TOTAL_CHARG, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
0x000e: {'reg': Register.BATT_PV1_STATUS, 'fmt': '!H'}, # noqa: E501
0x000f: {'reg': Register.BATT_PV2_STATUS, 'fmt': '!H'}, # noqa: E501
0x000c: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501
0x000d: {'reg': Register.BATT_TOTAL_GEN, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x000e: {'reg': Register.BATT_STATUS_1, 'fmt': '!h'}, # noqa: E501
0x000f: {'reg': Register.BATT_STATUS_2, 'fmt': '!h'}, # noqa: E501
0x0010: {'reg': Register.BATT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x0011: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x0012: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent
0x0013: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0014: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0015: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0016: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0017: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0018: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0019: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001a: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001b: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001c: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001d: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001e: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x001f: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0020: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0021: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0022: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
0x0013: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0014: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0015: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0016: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0017: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0018: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0019: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001a: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001b: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001c: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001d: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001e: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x001f: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0020: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0021: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0022: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
0x0023: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501
0x0024: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501
0x0025: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501
0x0026: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
0x0027: {'reg': Register.BATT_OUT_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
0x0028: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!H'}, # noqa: E501
0x0026: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x0027: {'reg': Register.BATT_OUT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
0x0028: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!h'}, # noqa: E501
0x0029: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E501
0x002a: {'reg': Register.BATT_ALARM, 'fmt': '!h'}, # noqa: E501
0x002b: {'reg': Register.BATT_HW_VERS, 'fmt': '!h'}, # noqa: E501
0x002c: {'reg': Register.BATT_SW_VERS, 'fmt': '!h'}, # noqa: E501
0x002a: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501
0x002b: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501
0x002c: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501
0x2000: {'reg': Register.BOOT_STATUS, 'fmt': '!H'}, # noqa: E501
0x2001: {'reg': Register.DSP_STATUS, 'fmt': '!H'}, # noqa: E501

View File

@@ -84,10 +84,7 @@ async def test_close_cb():
return 0.1
def closed():
nonlocal cnt
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
@@ -116,6 +113,7 @@ async def test_close_cb():
@pytest.mark.asyncio
async def test_read():
global test
assert asyncio.get_running_loop()
reader = FakeReader()
reader.test = FakeReader.RD_TEST_13_BYTES
@@ -126,13 +124,11 @@ async def test_read():
return 1
def closed():
nonlocal cnt
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
def app_read():
nonlocal ifc
ifc.proc_start -= 3
return 0.01 # async wait of 0.01
cnt = 0
@@ -155,6 +151,7 @@ async def test_read():
@pytest.mark.asyncio
async def test_write():
global test
assert asyncio.get_running_loop()
reader = FakeReader()
reader.test = FakeReader.RD_TEST_13_BYTES
@@ -165,13 +162,11 @@ async def test_write():
return 1
def closed():
nonlocal cnt
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
def app_read():
nonlocal ifc
ifc.proc_start -= 3
return 0.01 # async wait of 0.01
@@ -208,6 +203,7 @@ async def test_publ_mqtt_cb():
return 0.1
async def publ_mqtt():
nonlocal cnt
nonlocal ifc
cnt += 1
cnt = 0
@@ -237,10 +233,7 @@ async def test_create_remote_cb():
return 0.1
async def create_remote():
nonlocal cnt
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
@@ -262,6 +255,7 @@ async def test_create_remote_cb():
@pytest.mark.asyncio
async def test_sw_exception():
global test
assert asyncio.get_running_loop()
reader = FakeReader()
reader.test = FakeReader.RD_TEST_SW_EXCEPT
@@ -272,10 +266,7 @@ async def test_sw_exception():
return 1
def closed():
nonlocal cnt
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
cnt = 0
@@ -294,6 +285,7 @@ async def test_sw_exception():
@pytest.mark.asyncio
async def test_os_error():
global test
assert asyncio.get_running_loop()
reader = FakeReader()
reader.test = FakeReader.RD_TEST_OS_ERROR
@@ -301,11 +293,12 @@ async def test_os_error():
reader.on_recv.set()
writer = FakeWriter()
cnt = 0
def timeout():
return 1
def closed():
nonlocal cnt
nonlocal ifc
ifc.close() # clears the closed callback
cnt += 1
cnt = 0
ifc = AsyncStreamClient(reader, writer, None, closed)
@@ -368,13 +361,10 @@ async def test_forward():
assert asyncio.get_running_loop()
remote = StreamPtr(None)
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote, ifc
create_remote(remote, TestType.FWD_NO_EXCPT)
# The callback will be called after the AsyncStreamServer
# constructer has finished and so ifc must be defined in the
# upper scope
assert "ifc" in locals()
ifc.fwd_add(b'test-forward_msg2 ')
cnt += 1
@@ -392,7 +382,7 @@ async def test_forward_with_conn():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote, ifc
cnt += 1
cnt = 0
@@ -427,7 +417,7 @@ async def test_forward_sw_except():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_SW_EXCPT)
cnt += 1
@@ -445,7 +435,7 @@ async def test_forward_os_error():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_OS_ERROR)
cnt += 1
@@ -463,7 +453,7 @@ async def test_forward_os_error2():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_OS_ERROR, True)
cnt += 1
@@ -481,7 +471,7 @@ async def test_forward_os_error3():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_OS_ERROR_NO_STREAM)
cnt += 1
@@ -499,7 +489,7 @@ async def test_forward_runtime_error():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_RUNTIME_ERROR)
cnt += 1
@@ -517,7 +507,7 @@ async def test_forward_runtime_error2():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_RUNTIME_ERROR, True)
cnt += 1
@@ -535,7 +525,7 @@ async def test_forward_runtime_error3():
cnt = 0
async def _create_remote():
nonlocal cnt
nonlocal cnt, remote
create_remote(remote, TestType.FWD_RUNTIME_ERROR_NO_STREAM, True)
cnt += 1
@@ -553,7 +543,7 @@ async def test_forward_resp():
cnt = 0
def _close_cb():
nonlocal cnt
nonlocal cnt, remote, ifc
cnt += 1
cnt = 0
@@ -569,8 +559,9 @@ async def test_forward_resp2():
assert asyncio.get_running_loop()
remote = StreamPtr(None)
cnt = 0
def _close_cb():
nonlocal cnt
nonlocal cnt, remote, ifc
cnt += 1
cnt = 0
@@ -580,4 +571,3 @@ async def test_forward_resp2():
await ifc.client_loop('')
assert cnt == 1
del ifc

View File

@@ -221,7 +221,7 @@ def inv_data_seq2(): # Data indication from the controller
return msg
@pytest.fixture
def inv_data_seq3(): # Inverter indication from MS-3000
def inv_data_seq3(): # Inverter indication from MS-2000
msg = b'\x00\x00\x01\x2c\x00\x00\x00\x64\x53\x00\x00' # | ..^.....,...dS..
msg += b'\x00\x00\x00\xc8\x53\x44\x00\x00\x00\x01\x2c\x53\x00\x00\x00\x00' # | ....SD....,S....

View File

@@ -82,25 +82,13 @@ def batterie_data(): # 0x4210 ftype: 0x01
msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01'
return msg
@pytest.fixture
def batterie_data1(): # 0x4210 ftype: 0x01
msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde'
msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00'
msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34'
msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00'
msg += b'\x01\x00\x00\x00\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89'
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x0c\x0e\x01\x00'
msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01'
return msg
@pytest.fixture
def batterie_data2(): # 0x4210 ftype: 0x01
msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde'
msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00'
msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34'
msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00'
msg += b'\x14\x0e\x02\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89'
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e'
return msg
@@ -167,32 +155,15 @@ def test_parse_4210_3026(batterie_data: bytes):
assert json.dumps(i.db) == json.dumps({
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
"inverter": {"Serial_Number": "4101240701490314"},
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
"batt": {"Total_Charging": 20.8, "Voltage": 51.34, "Current": -0.02, "SOC": 10.0, "Power": -1.0268000000000002, 'Batt_State': 0},
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
"out": {"Voltage": 0.14, "Current": 0.0, "Out_Status": 0, "Power": 0.0, "Suppl_State": 0},
"Controller_Temp": 15, "Batterie_Alarm": 0, "Hardware_Version": 517, "Software_Version": 513,
"PV_Power": 37.9232},
})
def test_parse_4210_3026_prod(batterie_data1: bytes):
i = InfosG3P(client_mode=False)
i.db.clear()
for key, update in i.parse (batterie_data1, 0x42, 1, 0x3026):
pass # side effect is calling generator i.parse()
assert json.dumps(i.db) == json.dumps({
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
"inverter": {"Serial_Number": "4101240701490314"},
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
"batt": {"Total_Charging": 20.8, "Voltage": 2.56, "Current": 0.0, "SOC": 10.0, "Power": 0.0, 'Batt_State': 1},
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
"out": {"Voltage": 30.86, "Current": 2.56, "Out_Status": 0, "Power": 79.0016, "Suppl_State": 1},
"Controller_Temp": 15, "Batterie_Alarm": 0, "Hardware_Version": 517, "Software_Version": 513,
"PV_Power": 37.9232},
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12},
"pv2": {"Voltage": 33.72, "Current": 0.0},
"Reg_38": 0, "Total_Generation": 20.8, "Status_1": 0, "Status_2": 0,
"Voltage": 51.34, "Current": -0.02, "SOC": 10.0,
"Cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21},
"Temp_1": 15, "Temp_2": 15, "Temp_3": 15,
"out": {"Voltage": 0.14, "Current": 0.0, "Out_Status": 0, "Power": 0.0},
"Controller_Temp": 15, "Reg_74": 0, "Reg_76": 517, "Reg_78": 513,
"PV_Power": 37.9232, "Power": -1.0268000000000002},
})
def test_parse_4210_3026_incomplete(batterie_data2: bytes):
@@ -205,14 +176,16 @@ def test_parse_4210_3026_incomplete(batterie_data2: bytes):
assert json.dumps(i.db) == json.dumps({
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
"inverter": {"Serial_Number": "4101240701490314"},
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
"batt": {"Total_Charging": 20.8, "Voltage": 51.34, "Current": 7.66, "SOC": 10.0, "Power": 393.2644, 'Batt_State': 2},
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
"out": {"Voltage": 0.14, "Current": None, "Out_Status": None, "Power": None, "Suppl_State": None},
"Controller_Temp": None, "Batterie_Alarm": None, "Hardware_Version": None, "Software_Version": None,
"PV_Power": 37.9232},
})
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12},
"pv2": {"Voltage": 33.72, "Current": 0.0},
"Reg_38": 0, "Total_Generation": 20.8, "Status_1": 0, "Status_2": 0,
"Voltage": 51.34, "Current": -0.02, "SOC": 10.0,
"Cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21},
"Temp_1": 15, "Temp_2": 15, "Temp_3": 15,
"out": {"Voltage": 0.14, "Current": None, "Out_Status": None, "Power": None},
"Controller_Temp": None, "Reg_74": None, "Reg_76": None, "Reg_78": None,
"PV_Power": 37.9232, "Power": -1.0268000000000002},
})
def test_build_4210(inverter_data: bytes):
i = InfosG3P(client_mode=False)
@@ -386,7 +359,7 @@ def test_build_ha_conf5():
if id == 'out_power_123':
assert comp == 'sensor'
assert d_json == json.dumps({"name": "Supply Power", "stat_t": "tsun/garagendach/batterie", "dev_cla": "power", "stat_cla": "measurement", "uniq_id": "out_power_123", "val_tpl": "{{ (value_json['out']['Power'] | int)}}", "unit_of_meas": "W", "dev": {"name": "Batterie", "sa": "Batterie", "via_device": "controller_123", "mdl": "TSOL-MSxx00", "mf": "TSUN", "ids": ["batterie_123"]}, "o": {"name": "proxy", "sw": "unknown"}})
assert d_json == json.dumps({"name": "Output Power", "stat_t": "tsun/garagendach/batterie", "dev_cla": "power", "stat_cla": "measurement", "uniq_id": "out_power_123", "val_tpl": "{{ (value_json['out']['Power'] | int)}}", "unit_of_meas": "W", "dev": {"name": "Batterie", "sa": "Batterie", "via_device": "controller_123", "mdl": "TSOL-MSxx00", "mf": "TSUN", "ids": ["batterie_123"]}, "o": {"name": "proxy", "sw": "unknown"}})
tests +=1
elif id == 'daily_gen_123':
assert False

View File

@@ -85,6 +85,7 @@ def patch_open_connection():
return FakeReader(), FakeWriter()
def new_open(host: str, port: int):
global test
if test == MockType.RD_TEST_TIMEOUT:
raise ConnectionRefusedError
elif test == MockType.RD_TEST_EXCEPT:
@@ -317,7 +318,7 @@ async def test_remote_conn_to_loopback(config_conn, patch_open_connection):
assert cnt == 0
@pytest.mark.asyncio
async def test_remote_conn_to_none(config_conn, patch_open_connection):
async def test_remote_conn_to_None(config_conn, patch_open_connection):
'''check if get_extra_info() return None in case of an error'''
_ = config_conn
_ = patch_open_connection

View File

@@ -85,6 +85,7 @@ def patch_open_connection():
return FakeReader(), FakeWriter()
def new_open(host: str, port: int):
global test
if test == MockType.RD_TEST_TIMEOUT:
raise ConnectionRefusedError
elif test == MockType.RD_TEST_EXCEPT:
@@ -155,7 +156,6 @@ async def test_remote_except(config_conn, patch_open_connection):
await asyncio.sleep(0)
assert inverter.remote.stream==None
del inverter
test = MockType.RD_TEST_0_BYTES
cnt = 0
for inv in InverterBase:

View File

@@ -84,6 +84,7 @@ def patch_open_connection():
return FakeReader(), FakeWriter()
def new_open(host: str, port: int):
global test
if test == MockType.RD_TEST_TIMEOUT:
raise ConnectionRefusedError
elif test == MockType.RD_TEST_EXCEPT:
@@ -133,9 +134,6 @@ async def test_remote_except(config_conn, patch_open_connection):
await asyncio.sleep(0)
assert inverter.remote.stream==None
test = MockType.RD_TEST_0_BYTES
@pytest.mark.asyncio
async def test_mqtt_publish(config_conn, patch_open_connection):
_ = config_conn

View File

@@ -190,8 +190,7 @@ def patch_mqtt_except():
yield conn
@pytest.mark.asyncio
async def test_modbus_conn(config_conn, patch_open):
_ = config_conn
async def test_modbus_conn(patch_open):
_ = patch_open
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
@@ -211,7 +210,6 @@ async def test_modbus_conn(config_conn, patch_open):
@pytest.mark.asyncio
async def test_modbus_no_cnf():
_ = config_conn
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
loop = asyncio.get_event_loop()
ModbusTcp(loop)

View File

@@ -47,7 +47,7 @@ def config_no_conn(test_port):
@pytest.fixture
def spy_at_cmd():
conn = SolarmanV5(None, ('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
conn = SolarmanV5(('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
conn.node_id = 'inv_2/'
with patch.object(conn, 'send_at_cmd', wraps=conn.send_at_cmd) as wrapped_conn:
yield wrapped_conn
@@ -55,7 +55,7 @@ def spy_at_cmd():
@pytest.fixture
def spy_modbus_cmd():
conn = SolarmanV5(None, ('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
conn = SolarmanV5(('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
conn.node_id = 'inv_1/'
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
yield wrapped_conn
@@ -63,7 +63,7 @@ def spy_modbus_cmd():
@pytest.fixture
def spy_modbus_cmd_client():
conn = SolarmanV5(None, ('test.local', 1234), server_side=False, client_mode= False, ifc=AsyncIfcImpl())
conn = SolarmanV5(('test.local', 1234), server_side=False, client_mode= False, ifc=AsyncIfcImpl())
conn.node_id = 'inv_1/'
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
yield wrapped_conn
@@ -96,6 +96,7 @@ def test_native_client(test_hostname, test_port):
@pytest.mark.asyncio
async def test_mqtt_connection(config_mqtt_conn):
global NO_MOSQUITTO_TEST
if NO_MOSQUITTO_TEST:
pytest.skip('skipping, since Mosquitto is not reliable at the moment')
@@ -121,6 +122,7 @@ async def test_mqtt_connection(config_mqtt_conn):
@pytest.mark.asyncio
async def test_ha_reconnect(config_mqtt_conn):
global NO_MOSQUITTO_TEST
if NO_MOSQUITTO_TEST:
pytest.skip('skipping, since Mosquitto is not reliable at the moment')

View File

@@ -4,9 +4,7 @@ import time
import asyncio
import logging
import random
from asyncio import StreamReader, StreamWriter
from math import isclose
from async_stream import AsyncIfcImpl, StreamPtr
from gen3plus.solarman_v5 import SolarmanV5, SolarmanBase
from cnf.config import Config
@@ -14,11 +12,6 @@ from infos import Infos, Register
from modbus import Modbus
from messages import State, Message
from proxy import Proxy
from test_inverter_g3p import FakeReader, FakeWriter, patch_open_connection
from inverter_base import InverterBase
from test_modbus_tcp import test_port, test_hostname
pytest_plugins = ('pytest_asyncio',)
@@ -50,14 +43,10 @@ class FakeIfc(AsyncIfcImpl):
async def create_remote(self):
await asyncio.sleep(0)
class FakeInverter():
def __init__(self):
self.forward_at_cmd_resp = False
class MemoryStream(SolarmanV5):
def __init__(self, msg, chunks = (0,), server_side: bool = True, inverter=FakeInverter()):
def __init__(self, msg, chunks = (0,), server_side: bool = True):
_ifc = FakeIfc()
super().__init__(inverter, ('test.local', 1234), _ifc, server_side, client_mode=False)
super().__init__(('test.local', 1234), _ifc, server_side, client_mode=False)
if server_side:
self.mb.timeout = 0.4 # overwrite for faster testing
self.mb_first_timeout = 0.5
@@ -827,7 +816,7 @@ def config_tsun_allow_all():
@pytest.fixture
def config_no_tsun_inv1():
Config.act_config = {'solarman':{'enabled': False},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1/', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 688}}}
Config.act_config = {'solarman':{'enabled': False},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 688}}}
@pytest.fixture
def config_tsun_inv1():
@@ -839,21 +828,21 @@ def config_tsun_inv1():
'proxy_node_id': 'test_1',
'proxy_unique_id': ''
},
'solarman':{'enabled': True, 'host': 'test_cloud.local', 'port': 1234},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1/', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 0}}}
'solarman':{'enabled': True},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 0}}}
Proxy.class_init()
Proxy.mqtt = Mqtt()
@pytest.fixture
def config_tsun_scan():
Config.act_config = {'solarman':{'enabled': True},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1/', 'modbus_polling': True, 'modbus_scanning': {'start': 0xffc0, 'step': 0x40, 'bytes':20}, 'suggested_area':'roof', 'sensor_list': 0}}}
Config.act_config = {'solarman':{'enabled': True},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1', 'modbus_polling': True, 'modbus_scanning': {'start': 0xffc0, 'step': 0x40, 'bytes':20}, 'suggested_area':'roof', 'sensor_list': 0}}}
@pytest.fixture
def config_tsun_scan_dcu():
Config.act_config = {'solarman':{'enabled': True},'inverters':{'4100000000000001':{'monitor_sn': 2070233888, 'node_id':'inv1/', 'modbus_polling': True, 'modbus_scanning': {'start': 0x0000, 'step': 0x100, 'bytes':0x2d}, 'client_mode': {'host': '192.168.1.1.'}, 'suggested_area':'roof', 'sensor_list': 0}}}
Config.act_config = {'solarman':{'enabled': True},'inverters':{'4100000000000001':{'monitor_sn': 2070233888, 'node_id':'inv1', 'modbus_polling': True, 'modbus_scanning': {'start': 0x0000, 'step': 0x100, 'bytes':0x2d}, 'client_mode': {'host': '192.168.1.1.'}, 'suggested_area':'roof', 'sensor_list': 0}}}
@pytest.fixture
def config_tsun_dcu1():
Config.act_config = {'solarman':{'enabled': True},'batteries':{'4100000000000001':{'monitor_sn': 2070233888, 'node_id':'inv1/', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 0}}}
Config.act_config = {'solarman':{'enabled': True},'batteries':{'4100000000000001':{'monitor_sn': 2070233888, 'node_id':'inv1', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 0}}}
def test_read_message(device_ind_msg):
Config.act_config = {'solarman':{'enabled': True}}
@@ -1443,9 +1432,9 @@ def test_build_logger_modell(config_tsun_allow_all, device_ind_msg):
def test_msg_iterator():
Message._registry.clear()
m1 = SolarmanV5(None, ('test1.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m2 = SolarmanV5(None, ('test2.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m3 = SolarmanV5(None, ('test3.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m1 = SolarmanV5(('test1.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m2 = SolarmanV5(('test2.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m3 = SolarmanV5(('test3.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m3.close()
del m3
test1 = 0
@@ -1463,7 +1452,7 @@ def test_msg_iterator():
assert test2 == 1
def test_proxy_counter():
m = SolarmanV5(None, ('test.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
m = SolarmanV5(('test.local', 1234), ifc=AsyncIfcImpl(), server_side=True, client_mode=False)
assert m.new_data == {}
m.db.stat['proxy']['Unknown_Msg'] = 0
Infos.new_stat_data['proxy'] = False
@@ -1570,7 +1559,7 @@ async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inv
assert m.ifc.fwd_fifo.get()==b''
assert m.sent_pdu == b''
assert str(m.seq) == '03:04'
assert m.inverter.forward_at_cmd_resp == False
assert m.forward_at_cmd_resp == False
assert Proxy.mqtt.key == ''
assert Proxy.mqtt.data == ""
m.close()
@@ -1605,12 +1594,12 @@ async def test_at_cmd_blocked(config_tsun_allow_all, device_ind_msg, device_rsp_
assert m.ifc.tx_fifo.get()==b''
assert m.ifc.fwd_fifo.get()==b''
assert str(m.seq) == '02:02'
assert m.inverter.forward_at_cmd_resp == False
assert m.forward_at_cmd_resp == False
assert Proxy.mqtt.key == 'tsun/at_resp'
assert Proxy.mqtt.data == "'AT+WEBU' is forbidden"
m.close()
def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg, at_command_rsp_msg):
def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg):
_ = config_tsun_inv1
m = MemoryStream(at_command_ind_msg, (0,), False)
m.db.stat['proxy']['Unknown_Ctrl'] = 0
@@ -1632,17 +1621,6 @@ def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg, at_command_rsp_msg):
assert m.db.stat['proxy']['AT_Command'] == 1
assert m.db.stat['proxy']['AT_Command_Blocked'] == 0
assert m.db.stat['proxy']['Modbus_Command'] == 0
m.append_msg(at_command_rsp_msg)
m.read() # read at resp
assert m.control == 0x1510
assert str(m.seq) == '03:03'
assert m.ifc.rx_get()==b''
assert m.ifc.tx_fifo.get()==b''
assert m.ifc.fwd_fifo.get()==at_command_rsp_msg
assert Proxy.mqtt.key == ''
assert Proxy.mqtt.data == ""
m.close()
def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
@@ -1652,7 +1630,6 @@ def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
m.db.stat['proxy']['AT_Command'] = 0
m.db.stat['proxy']['AT_Command_Blocked'] = 0
m.db.stat['proxy']['Modbus_Command'] = 0
m.inverter.forward_at_cmd_resp = False
m.read() # read complete msg, and dispatch msg
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
assert m.msg_count == 1
@@ -1668,9 +1645,6 @@ def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
assert m.db.stat['proxy']['AT_Command'] == 0
assert m.db.stat['proxy']['AT_Command_Blocked'] == 1
assert m.db.stat['proxy']['Modbus_Command'] == 0
assert m.inverter.forward_at_cmd_resp == False
assert Proxy.mqtt.key == ''
assert Proxy.mqtt.data == ""
m.close()
def test_msg_at_command_rsp1(config_tsun_inv1, at_command_rsp_msg):
@@ -1678,7 +1652,7 @@ def test_msg_at_command_rsp1(config_tsun_inv1, at_command_rsp_msg):
m = MemoryStream(at_command_rsp_msg)
m.db.stat['proxy']['Unknown_Ctrl'] = 0
m.db.stat['proxy']['Modbus_Command'] = 0
m.inverter.forward_at_cmd_resp = True
m.forward_at_cmd_resp = True
m.read() # read complete msg, and dispatch msg
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
assert m.msg_count == 1
@@ -1697,7 +1671,7 @@ def test_msg_at_command_rsp2(config_tsun_inv1, at_command_rsp_msg):
m = MemoryStream(at_command_rsp_msg)
m.db.stat['proxy']['Unknown_Ctrl'] = 0
m.db.stat['proxy']['Modbus_Command'] = 0
m.inverter.forward_at_cmd_resp = False
m.forward_at_cmd_resp = False
m.read() # read complete msg, and dispatch msg
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
assert m.msg_count == 1
@@ -1709,8 +1683,6 @@ def test_msg_at_command_rsp2(config_tsun_inv1, at_command_rsp_msg):
assert m.ifc.tx_fifo.get()==b''
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
assert m.db.stat['proxy']['Modbus_Command'] == 0
assert Proxy.mqtt.key == 'tsun/inv1/at_resp'
assert Proxy.mqtt.data == "+ok"
m.close()
def test_msg_at_command_rsp3(config_tsun_inv1, at_command_interim_rsp_msg):
@@ -1720,7 +1692,7 @@ def test_msg_at_command_rsp3(config_tsun_inv1, at_command_interim_rsp_msg):
m.db.stat['proxy']['Modbus_Command'] = 0
m.db.stat['proxy']['Invalid_Msg_Format'] = 0
m.db.stat['proxy']['Unknown_Msg'] = 0
m.inverter.forward_at_cmd_resp = True
m.forward_at_cmd_resp = True
m.read() # read complete msg, and dispatch msg
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
assert m.msg_count == 1
@@ -1734,8 +1706,6 @@ def test_msg_at_command_rsp3(config_tsun_inv1, at_command_interim_rsp_msg):
assert m.db.stat['proxy']['Modbus_Command'] == 0
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
assert m.db.stat['proxy']['Unknown_Msg'] == 0
assert Proxy.mqtt.key == ''
assert Proxy.mqtt.data == ""
m.close()
def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd, msg_modbus_cmd_fwd):
@@ -2248,100 +2218,4 @@ def test_timestamp():
m = MemoryStream(b'')
ts = m._timestamp()
ts_emu = m._emu_timestamp()
assert ts == ts_emu + 24*60*60
class MemoryStream2(MemoryStream):
def __init__(self, inverter, addr, ifc,
server_side: bool, client_mode: bool):
super().__init__(b'', inverter=inverter)
class InverterTest(InverterBase):
def __init__(self, reader: StreamReader, writer: StreamWriter,
client_mode: bool = False):
remote_prot = None
super().__init__(reader, writer, 'solarman',
MemoryStream2, client_mode, remote_prot)
def forward(self, src, dst) -> None:
"""forward handler transmits data over the remote connection"""
# dst.ifc.update_header_cb(src.fwd_fifo.peek())
dst.ifc.tx_add(src.ifc.fwd_fifo.get())
@pytest.mark.asyncio
async def test_proxy_at_cmd(config_tsun_inv1, patch_open_connection, at_command_ind_msg, at_command_rsp_msg):
_ = config_tsun_inv1
_ = patch_open_connection
assert asyncio.get_running_loop()
with InverterTest(FakeReader(), FakeWriter(), client_mode=False) as inverter:
await inverter.create_remote()
await asyncio.sleep(0)
r = inverter.remote.stream
l = inverter.local.stream
l.db.stat['proxy']['AT_Command'] = 0
l.db.stat['proxy']['Unknown_Ctrl'] = 0
l.db.stat['proxy']['AT_Command_Blocked'] = 0
l.db.stat['proxy']['Modbus_Command'] = 0
inverter.forward_at_cmd_resp = False
r.append_msg(at_command_ind_msg)
r.read() # read complete msg, and dispatch msg
assert inverter.forward_at_cmd_resp
inverter.forward(r,l)
assert l.ifc.tx_fifo.get()==at_command_ind_msg
assert l.db.stat['proxy']['Invalid_Msg_Format'] == 0
assert l.db.stat['proxy']['AT_Command'] == 1
assert l.db.stat['proxy']['AT_Command_Blocked'] == 0
assert l.db.stat['proxy']['Modbus_Command'] == 0
l.append_msg(at_command_rsp_msg)
l.read() # read at resp
assert l.ifc.fwd_fifo.peek()==at_command_rsp_msg
inverter.forward(l,r)
assert r.ifc.tx_fifo.get()==at_command_rsp_msg
assert Proxy.mqtt.key == ''
assert Proxy.mqtt.data == ""
@pytest.mark.asyncio
async def test_proxy_at_blocked(config_tsun_inv1, patch_open_connection, at_command_ind_msg_block, at_command_rsp_msg):
_ = config_tsun_inv1
_ = patch_open_connection
assert asyncio.get_running_loop()
with InverterTest(FakeReader(), FakeWriter(), client_mode=False) as inverter:
await inverter.create_remote()
await asyncio.sleep(0)
r = inverter.remote.stream
l = inverter.local.stream
l.db.stat['proxy']['AT_Command'] = 0
l.db.stat['proxy']['Unknown_Ctrl'] = 0
l.db.stat['proxy']['AT_Command_Blocked'] = 0
l.db.stat['proxy']['Modbus_Command'] = 0
inverter.forward_at_cmd_resp = False
r.append_msg(at_command_ind_msg_block)
r.read() # read complete msg, and dispatch msg
assert not inverter.forward_at_cmd_resp
inverter.forward(r,l)
assert l.ifc.tx_fifo.get()==b''
assert l.db.stat['proxy']['Invalid_Msg_Format'] == 0
assert l.db.stat['proxy']['AT_Command'] == 0
assert l.db.stat['proxy']['AT_Command_Blocked'] == 1
assert l.db.stat['proxy']['Modbus_Command'] == 0
l.append_msg(at_command_rsp_msg)
l.read() # read at resp
assert l.ifc.fwd_fifo.peek()==b''
inverter.forward(l,r)
assert r.ifc.tx_fifo.get()==b''
assert Proxy.mqtt.key == 'tsun/inv1/at_resp'
assert Proxy.mqtt.data == "+ok"
assert ts == ts_emu + 24*60*60

View File

@@ -6,7 +6,7 @@ from gen3plus.solarman_v5 import SolarmanV5, SolarmanBase
from gen3plus.solarman_emu import SolarmanEmu
from infos import Infos, Register
from test_solarman import FakeIfc, FakeInverter, MemoryStream, get_sn_int, get_sn, correct_checksum, config_tsun_inv1, msg_modbus_rsp
from test_solarman import FakeIfc, MemoryStream, get_sn_int, get_sn, correct_checksum, config_tsun_inv1, msg_modbus_rsp
from test_infos_g3p import str_test_ip, bytes_test_ip
timestamp = 0x3224c8bc
@@ -19,10 +19,10 @@ class InvStream(MemoryStream):
return timestamp
class CldStream(SolarmanEmu):
def __init__(self, inv: InvStream, inverter=FakeInverter()):
def __init__(self, inv: InvStream):
_ifc = FakeIfc()
_ifc.remote.stream = inv
super().__init__(inverter, ('test.local', 1234), _ifc, server_side=False, client_mode=False)
super().__init__(('test.local', 1234), _ifc, server_side=False, client_mode=False)
self.__msg = b''
self.__msg_len = 0
self.__offs = 0

View File

@@ -25,7 +25,7 @@ class FakeIfc(AsyncIfcImpl):
class MemoryStream(Talent):
def __init__(self, msg, chunks = (0,), server_side: bool = True):
self.ifc = FakeIfc()
super().__init__(None, ('test.local', 1234), self.ifc, server_side)
super().__init__(('test.local', 1234), self.ifc, server_side)
if server_side:
self.mb.timeout = 0.4 # overwrite for faster testing
self.mb_first_timeout = 0.5
@@ -2026,9 +2026,9 @@ def test_ctrl_byte():
def test_msg_iterator():
m1 = Talent(None, ('test1.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m2 = Talent(None, ('test2.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m3 = Talent(None, ('test3.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m1 = Talent(('test1.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m2 = Talent(('test2.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m3 = Talent(('test3.local', 1234), ifc=AsyncIfcImpl(), server_side=True)
m3.close()
del m3
test1 = 0

View File

@@ -1,4 +1,3 @@
.data.json
config.yaml
apparmor.txt
README.md
apparmor.txt

View File

@@ -33,7 +33,6 @@ rel : STAGE=rel
export BUILD_DATE := ${shell date -Iminutes}
BUILD_ID := ${shell date +'%y%m%d%H%M'}
rel : BUILD_ID=
VERSION := $(shell cat $(SRC)/.version)
export MAJOR := $(shell echo $(VERSION) | cut -f1 -d.)
@@ -48,16 +47,7 @@ dev debug: local_add_on
export IMAGE=$(PRIVAT_CONTAINER_REGISTRY)$(IMAGE) && \
docker buildx bake -f docker-bake.hcl $@
rc: local_add_on
@[ "${RC}" ] || ( echo ">> RC is not set"; exit 1 )
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"
export VERSION=$(VERSION)-$@$(RC) && \
export IMAGE=$(PUBLIC_CONTAINER_REGISTRY)$(IMAGE) && \
docker buildx bake -f docker-bake.hcl $@
rel: local_add_on
rc rel: local_add_on
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"
@@ -76,7 +66,7 @@ clean:
# Build the local add-on with a rootfs and config.yaml
# The rootfs is needed to build the add-on Docker container
#
local_add_on: rootfs $(ADDON_PATH)/config.yaml $(ADDON_PATH)/apparmor.txt $(ADDON_PATH)/README.md
local_add_on: rootfs $(ADDON_PATH)/config.yaml $(ADDON_PATH)/apparmor.txt
# collect source files
SRC_FILES := $(wildcard $(SRC_PROXY)/*.py)\
@@ -113,9 +103,6 @@ $(ADDON_PATH)/%.yaml: $(TEMPL)/%.jinja $(TEMPL)/.data.json
$(ADDON_PATH)/%.txt: $(TEMPL)/%.jinja $(TEMPL)/.data.json
$(JINJA) --strict --format=json $^ -o $@
$(ADDON_PATH)/%.md: $(TEMPL)/%.jinja $(TEMPL)/.data.json
$(JINJA) --strict --format=json $^ -o $@
# build a common data.json file from STAGE depending source files
# don't touch the destination if the checksum of src and dst is equal
$(TEMPL)/.data.json: FORCE
@@ -132,7 +119,6 @@ repro_files = DOCS.md icon.png logo.png translations/de.yaml translations/en.yam
repro_root = CHANGELOG.md LICENSE.md
repro_templates = config.yaml
repro_apparmor = apparmor.txt
repro_readme = README.md
repro_subdirs = translations rootfs
repro_vers = debug dev rc rel
@@ -140,34 +126,29 @@ repro_all_files := $(foreach dir,$(repro_vers), $(foreach file,$(repro_files),$(
repro_root_files := $(foreach dir,$(repro_vers), $(foreach file,$(repro_root),$(INST_BASE)/ha_addon_$(dir)/$(file)))
repro_all_templates := $(foreach dir,$(repro_vers), $(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_$(dir)/$(file)))
repro_all_apparmor := $(foreach dir,$(repro_vers), $(foreach file,$(repro_apparmor),$(INST_BASE)/ha_addon_$(dir)/$(file)))
repro_all_readme := $(foreach dir,$(repro_vers), $(foreach file,$(repro_readme),$(INST_BASE)/ha_addon_$(dir)/$(file)))
repro_all_subdirs := $(foreach dir,$(repro_vers), $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_$(dir)/$(file)))
debug: $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_debug/$(file)) \
$(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_debug/$(file)) \
$(foreach file,$(repro_apparmor),$(INST_BASE)/ha_addon_debug/$(file)) \
$(foreach file,$(repro_readme),$(INST_BASE)/ha_addon_debug/$(file)) \
$(foreach file,$(repro_files),$(INST_BASE)/ha_addon_debug/$(file)) \
$(foreach file,$(repro_root),$(INST_BASE)/ha_addon_debug/$(file))
dev: $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_dev/$(file)) \
$(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_dev/$(file)) \
$(foreach file,$(repro_apparmor),$(INST_BASE)/ha_addon_dev/$(file)) \
$(foreach file,$(repro_readme),$(INST_BASE)/ha_addon_dev/$(file)) \
$(foreach file,$(repro_files),$(INST_BASE)/ha_addon_dev/$(file)) \
$(foreach file,$(repro_root),$(INST_BASE)/ha_addon_dev/$(file))
rc: $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_rc/$(file)) \
$(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_rc/$(file)) \
$(foreach file,$(repro_apparmor),$(INST_BASE)/ha_addon_rc/$(file)) \
$(foreach file,$(repro_readme),$(INST_BASE)/ha_addon_rc/$(file)) \
$(foreach file,$(repro_files),$(INST_BASE)/ha_addon_rc/$(file)) \
$(foreach file,$(repro_root),$(INST_BASE)/ha_addon_rc/$(file))
rel: $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_rel/$(file)) \
$(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_rel/$(file)) \
$(foreach file,$(repro_apparmor),$(INST_BASE)/ha_addon_rel/$(file)) \
$(foreach file,$(repro_readme),$(INST_BASE)/ha_addon_rel/$(file)) \
$(foreach file,$(repro_files),$(INST_BASE)/ha_addon_rel/$(file)) \
$(foreach file,$(repro_root),$(INST_BASE)/ha_addon_rel/$(file))
@@ -180,9 +161,6 @@ $(repro_all_templates) : $(INST_BASE)/ha_addon_%/config.yaml: $(TEMPL)/config.ji
$(repro_all_apparmor) : $(INST_BASE)/ha_addon_%/apparmor.txt: $(TEMPL)/apparmor.jinja $(TEMPL)/%_data.json
$(JINJA) --strict $< $(filter %.json,$^) -o $@
$(repro_all_readme) : $(INST_BASE)/ha_addon_%/README.md: $(TEMPL)/README.jinja $(TEMPL)/%_data.json
$(JINJA) --strict $< $(filter %.json,$^) -o $@
$(filter $(INST_BASE)/ha_addon_debug/%,$(repro_root_files)) : $(INST_BASE)/ha_addon_debug/% : ../%
cp $< $@
$(filter $(INST_BASE)/ha_addon_dev/%,$(repro_root_files)) : $(INST_BASE)/ha_addon_dev/% : ../%

View File

@@ -90,7 +90,6 @@ target "preview" {
target "rc" {
inherits = ["_common", "_prod"]
tags = ["${IMAGE}:rc", "${IMAGE}:${VERSION}"]
no-cache = true
}
target "rel" {

View File

@@ -50,7 +50,7 @@ Example add-on configuration after installation:
```yaml
inverters:
- serial: R17E000000000000
- serial: R17E760702080400
node_id: PV-Garage
suggested_area: Garage
modbus_polling: false
@@ -89,7 +89,7 @@ Example add-on configuration for GEN3PLUS energie storages:
```yaml
batteries:
- serial: 4100000000000000
monitor_sn: 3000000000
monitor_sn: 2300000000
node_id: bat_1
suggested_area: Garage
modbus_polling: false
@@ -174,4 +174,4 @@ SOFTWARE.
[AdGuard]: https://github.com/hassio-addons/addon-adguard-home
[repository-badge]: https://img.shields.io/badge/Add%20repository%20to%20my-Home%20Assistant-41BDF5?logo=home-assistant&style=for-the-badge
[repository-url]: https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fs-allius%2Fha-addons
[configdetails]: https://github.com/s-allius/tsun-gen3-proxy/wiki/Configuration-addon
[configdetails]: https://github.com/s-allius/tsun-gen3-proxy/wiki/Configuration-toml

View File

@@ -13,12 +13,12 @@
# 1 Build Base Image #
######################
ARG BUILD_FROM="ghcr.io/hassio-addons/base:17.2.3"
ARG BUILD_FROM="ghcr.io/hassio-addons/base:17.2.2"
# hadolint ignore=DL3006
FROM $BUILD_FROM AS base
# Installiere Python, pip und virtuelle Umgebungstools
RUN apk add --no-cache python3=3.12.10-r0 py3-pip=24.3.1-r0 && \
RUN apk add --no-cache python3=3.12.9-r0 py3-pip=24.3.1-r0 && \
python -m venv /opt/venv && \
. /opt/venv/bin/activate

View File

@@ -1,21 +0,0 @@
# Home Assistant Add-on: {{name}}
{{readme_descr}}
## Features
- Supports TSUN GEN3 PLUS inverters: TSOL-MS2000, MS1800 and MS1600
- Supports TSUN GEN3 PLUS batteries: TSOL-DC1000 (from version 0.13)
- Supports TSUN GEN3 inverters: TSOL-MS3000, MS800, MS700, MS600, MS400, MS350 and MS300
- `Home-Assistant` auto-discovery support
- `MODBUS` support via MQTT topics
- `AT-Command` support via MQTT topics (GEN3PLUS only)
- Faster DataUp interval sends measurement data to the MQTT broker every minute
- Self-sufficient island operation without internet
- Security-Features:
- control access via `AT-commands`
## About
This Add-on and the TSUN Proxy is not related to the company TSUN. It is a private initiative that aims to connect TSUN inverters and storage systems with an MQTT broker. There is no support and no warranty from TSUN.
{{readme_links}}

View File

@@ -5,7 +5,5 @@
"image": "docker.io/sallius/tsun-gen3-addon",
"slug": "tsun-proxy-debug",
"advanced": true,
"stage": "experimental",
"readme_descr": "This is a bleeding-edge version of the `TSUN Proxy` Add-On with debuging enabled by default.\n\nThe versions may be based on different feature branches and therefore the range of functions may change.\n\nIt is intended to be used to simulate special situations/problems and should only be used in consultation with the maintainer.\n\nFor production please use the stable version `TSUN Proxy`. If you are interested in a bleeding edge version, we offer the `TSUN Proxy (dev)` version.",
"readme_links": ""
"stage": "experimental"
}

View File

@@ -5,7 +5,5 @@
"image": "docker.io/sallius/tsun-gen3-addon",
"slug": "tsun-proxy-dev",
"advanced": false,
"stage": "experimental",
"readme_descr": "This is a bleeding-edge version of the `TSUN Proxy` Add-On.\n\nThe versions may be based on different feature branches and therefore the range of functions may change.\n\nIt is intended for testing new functions or testing new devices that are to be supported with the next release.\nFor production, please use the stable version 'TSUN Proxy'.",
"readme_links": ""
"stage": "experimental"
}

View File

@@ -6,8 +6,5 @@
"image": "ghcr.io/s-allius/tsun-gen3-addon",
"slug": "tsun-proxy-rc",
"advanced": true,
"stage": "experimental",
"readme_descr": "This is a release candidate of the `TSUN Proxy` Add-On.\n\nIt is intended for testing the next release.\nFor production, please use the stable version 'TSUN Proxy'.",
"readme_links": ""
"stage": "experimental"
}

View File

@@ -5,7 +5,5 @@
"image": "ghcr.io/s-allius/tsun-gen3-addon",
"slug": "tsun-proxy",
"advanced": false,
"stage": "stable",
"readme_descr": "Integrates TSUN inverters (e.g. TSOL MS800, MS2000, MS3000) and batteries (TSOL DC1000) into Home Assistant.\n\nIt is based on the [TSUN Proxy][tsunproxy] and enables a reliable connection between TSUN devices and an MQTT broker.\n\nWith the Add-on, you can easily retrieve real-time values such as power, current and daily energy and integrate the inverter into Home Assistant.\nThis works even without an internet connection.\n\nThe optional connection to the TSUN Cloud can be disabled!",
"readme_links": "\n[tsunproxy]: https://github.com/s-allius/tsun-gen3-proxy\n"
"stage": "stable"
}

View File

@@ -5,14 +5,13 @@ from dotenv import load_dotenv
load_dotenv()
SOLARMAN_INV_SNR = os.getenv('SOLARMAN_INV_SNR', '00000080')
SOLARMAN_DCU_SNR = os.getenv('SOLARMAN_DCU_SNR', '00000080')
SOLARMAN_SNR = os.getenv('SOLARMAN_SNR', '00000080')
def get_sn() -> bytes:
return bytes.fromhex(SOLARMAN_INV_SNR)
return bytes.fromhex(SOLARMAN_SNR)
def get_dcu_sn() -> bytes:
return bytes.fromhex(SOLARMAN_DCU_SNR)
return b'\x20\x43\x65\x7b'
def get_dcu_no() -> bytes:
return b'4100000000000001'
@@ -28,7 +27,7 @@ def correct_checksum(buf):
return checksum.to_bytes(length=1)
@pytest.fixture
def msg_contact_info(): # Contact Info message
def MsgContactInfo(): # Contact Info message
msg = b'\xa5\xd4\x00\x10\x41\x00\x01' +get_sn() +b'\x02\xba\xd2\x00\x00'
msg += b'\x19\x00\x00\x00\x00\x00\x00\x00\x05\x3c\x78\x01\x64\x01\x4c\x53'
msg += b'\x57\x35\x42\x4c\x45\x5f\x31\x37\x5f\x30\x32\x42\x30\x5f\x31\x2e'
@@ -47,13 +46,13 @@ def msg_contact_info(): # Contact Info message
return msg
@pytest.fixture
def msg_contact_resp(): # Contact Response message
def MsgContactResp(): # Contact Response message
msg = b'\xa5\x0a\x00\x10\x11\x01\x01' +get_sn() +b'\x02\x01\x6a\xfd\x8f'
msg += b'\x65\x3c\x00\x00\x00\x75\x15'
return msg
@pytest.fixture
def msg_data_ind():
def MsgDataInd():
msg = b'\xa5\x99\x01\x10\x42\x59\x84' +get_sn() +b'\x01\xb0\x02\x2c\x87'
msg += b'\x22\x32\xb7\x29\x00\x00\xd6\xcf\xe1\x33\x01\x00\x0c\x05\x00\x00'
msg += b'\x59\x31\x37\x45\x37\x41\x30\x46\x30\x31\x30\x42\x30\x31\x33\x45'
@@ -87,14 +86,14 @@ def msg_data_ind():
return msg
@pytest.fixture
def msg_data_rsp(): # Contact Response message
def MsgDataResp(): # Contact Response message
msg = b'\xa5\x0a\x00\x10\x12\x80\x84' +get_sn() +b'\x01\x01\xd1\x96\x04'
msg += b'\x66\x3c\x00\x00\x00\xed\x15'
return msg
@pytest.fixture
def msg_invalid_info(): # Contact Info message wrong start byte
def MsgInvalidInfo(): # Contact Info message wrong start byte
msg = b'\x47\xd4\x00\x10\x41\x00\x01' +get_sn() +b'\x02\xba\xd2\x00\x00'
msg += b'\x19\x00\x00\x00\x00\x00\x00\x00\x05\x3c\x78\x01\x64\x01\x4c\x53'
msg += b'\x57\x35\x42\x4c\x45\x5f\x31\x37\x5f\x30\x32\x42\x30\x5f\x31\x2e'
@@ -153,9 +152,9 @@ def dcu_data_ind_msg(): # 0x4210
msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00'
msg += get_dcu_no()
msg += b'\x0d\x3a\x00\x0a\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00'
msg += b'\x14\x0e\x05\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89'
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e\x02\x00'
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e\x00\x00'
msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01'
msg += correct_checksum(msg)
msg += b'\x15'
@@ -170,7 +169,7 @@ def dcu_data_rsp_msg(): # 0x1210
return msg
@pytest.fixture(scope="session")
def client_connection():
def ClientConnection():
host = 'logger.talent-monitoring.com'
port = 10000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
@@ -179,15 +178,15 @@ def client_connection():
yield s
s.close()
def check_response(data, msg):
def checkResponse(data, Msg):
check = bytearray(data)
check[5]= msg[5] # ignore seq
check[13:18]= msg[13:18] # ignore timestamp + first byte of repeat time
check[21]= msg[21] # ignore crc
assert check == msg
check[5]= Msg[5] # ignore seq
check[13:18]= Msg[13:18] # ignore timestamp + first byte of repeat time
check[21]= Msg[21] # ignore crc
assert check == Msg
def tempclient_connection():
def tempClientConnection():
host = 'logger.talent-monitoring.com'
port = 10000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
@@ -199,53 +198,53 @@ def tempclient_connection():
def test_open_close():
try:
for _ in tempclient_connection():
pass # test generator tempclient_connection()
except TimeoutError:
for _ in tempClientConnection():
pass # test generator tempClientConnection()
except:
assert False
def test_conn_msg(client_connection,msg_contact_info, msg_contact_resp):
s = client_connection
def test_conn_msg(ClientConnection,MsgContactInfo, MsgContactResp):
s = ClientConnection
try:
s.sendall(msg_contact_info)
time.sleep(2.5)
data = s.recv(1024)
except TimeoutError:
pass
# time.sleep(2.5)
check_response(data, msg_contact_resp)
def test_data_ind(client_connection,msg_data_ind, msg_data_rsp):
s = client_connection
try:
s.sendall(msg_data_ind)
s.sendall(MsgContactInfo)
# time.sleep(2.5)
data = s.recv(1024)
except TimeoutError:
pass
# time.sleep(2.5)
check_response(data, msg_data_rsp)
checkResponse(data, MsgContactResp)
def test_inavlid_msg(client_connection,msg_invalid_info,msg_contact_info, msg_contact_resp):
s = client_connection
def test_data_ind(ClientConnection,MsgDataInd, MsgDataResp):
s = ClientConnection
try:
s.sendall(msg_invalid_info)
s.sendall(MsgDataInd)
# time.sleep(2.5)
data = s.recv(1024)
except TimeoutError:
pass
# time.sleep(2.5)
checkResponse(data, MsgDataResp)
def test_inavlid_msg(ClientConnection,MsgInvalidInfo,MsgContactInfo, MsgContactResp):
s = ClientConnection
try:
s.sendall(MsgInvalidInfo)
# time.sleep(2.5)
data = s.recv(1024)
except TimeoutError:
pass
# time.sleep(2.5)
try:
s.sendall(msg_contact_info)
s.sendall(MsgContactInfo)
# time.sleep(2.5)
data = s.recv(1024)
except TimeoutError:
pass
# time.sleep(2.5)
check_response(data, msg_contact_resp)
checkResponse(data, MsgContactResp)
def test_dcu_dev(client_connection,dcu_dev_ind_msg, dcu_dev_rsp_msg):
s = client_connection
def test_dcu_dev(ClientConnection,dcu_dev_ind_msg, dcu_dev_rsp_msg):
s = ClientConnection
try:
s.sendall(dcu_dev_ind_msg)
# time.sleep(2.5)
@@ -253,10 +252,10 @@ def test_dcu_dev(client_connection,dcu_dev_ind_msg, dcu_dev_rsp_msg):
except TimeoutError:
pass
# time.sleep(2.5)
check_response(data, dcu_dev_rsp_msg)
checkResponse(data, dcu_dev_rsp_msg)
def test_dcu_ind(client_connection,dcu_data_ind_msg, dcu_data_rsp_msg):
s = client_connection
def test_dcu_ind(ClientConnection,dcu_data_ind_msg, dcu_data_rsp_msg):
s = ClientConnection
try:
s.sendall(dcu_data_ind_msg)
# time.sleep(2.5)
@@ -264,4 +263,4 @@ def test_dcu_ind(client_connection,dcu_data_ind_msg, dcu_data_rsp_msg):
except TimeoutError:
pass
# time.sleep(2.5)
check_response(data, dcu_data_rsp_msg)
checkResponse(data, dcu_data_rsp_msg)