Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan
This commit is contained in:
655
app/proxy.svg
655
app/proxy.svg
@@ -4,526 +4,257 @@
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="751pt" height="1880pt"
|
||||
viewBox="0.00 0.00 751.00 1880.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 1876)">
|
||||
<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,-1876 747,-1876 747,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="295.6964,-1848 187.3036,-1848 187.3036,-1812 301.6964,-1812 301.6964,-1842 295.6964,-1848"/>
|
||||
<polyline fill="none" stroke="#000000" points="295.6964,-1848 295.6964,-1842 "/>
|
||||
<polyline fill="none" stroke="#000000" points="301.6964,-1842 295.6964,-1842 "/>
|
||||
<text text-anchor="middle" x="244.5" y="-1833" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
|
||||
<text text-anchor="middle" x="244.5" y="-1821" 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="428.5,-904 428.5,-948 550.5,-948 550.5,-904 428.5,-904"/>
|
||||
<text text-anchor="start" x="479.777" y="-929" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Mqtt</text>
|
||||
<text text-anchor="start" x="456.9815" y="-917" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<Singleton>></text>
|
||||
<polygon fill="none" stroke="#000000" points="428.5,-848 428.5,-904 550.5,-904 550.5,-848 428.5,-848"/>
|
||||
<text text-anchor="start" x="446.9875" y="-885" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>ha_restarts</text>
|
||||
<text text-anchor="start" x="454.7665" y="-873" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__client</text>
|
||||
<text text-anchor="start" x="438.3735" y="-861" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__cb_MqttIsUp</text>
|
||||
<polygon fill="none" stroke="#000000" points="428.5,-804 428.5,-848 550.5,-848 550.5,-804 428.5,-804"/>
|
||||
<text text-anchor="start" x="451.436" y="-829" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish()</text>
|
||||
<text text-anchor="start" x="455.6045" y="-817" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>close()</text>
|
||||
</g>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="345.5,-620 345.5,-652 641.5,-652 641.5,-620 345.5,-620"/>
|
||||
<text text-anchor="start" x="476.5535" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Inverter</text>
|
||||
<polygon fill="none" stroke="#000000" points="345.5,-504 345.5,-620 641.5,-620 641.5,-504 345.5,-504"/>
|
||||
<text text-anchor="start" x="469.604" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.db_stat</text>
|
||||
<text text-anchor="start" x="462.9405" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.entity_prfx</text>
|
||||
<text text-anchor="start" x="453.7755" y="-577" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.discovery_prfx</text>
|
||||
<text text-anchor="start" x="453.2115" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_node_id</text>
|
||||
<text text-anchor="start" x="449.3225" y="-553" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_unique_id</text>
|
||||
<text text-anchor="start" x="465.1655" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.mqtt:Mqtt</text>
|
||||
<text text-anchor="start" x="462.9355" y="-517" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
|
||||
<polygon fill="none" stroke="#000000" points="345.5,-472 345.5,-504 641.5,-504 641.5,-472 345.5,-472"/>
|
||||
<text text-anchor="start" x="355.418" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote(inv_prot, conn_class)async_publ_mqtt()</text>
|
||||
</g>
|
||||
<!-- A1->A2 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A1->A2</title>
|
||||
<path fill="none" stroke="#000000" d="M490.5482,-793.7124C491.0521,-754.1609 491.661,-706.3601 492.1946,-664.4723"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="490.4177,-803.9621 486.0455,-793.9055 490.4814,-798.9625 490.5452,-793.9629 490.5452,-793.9629 490.5452,-793.9629 490.4814,-798.9625 495.0448,-794.0202 490.4177,-803.9621 490.4177,-803.9621"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="492.1973,-664.2532 488.2741,-658.2027 492.3503,-652.2542 496.2735,-658.3047 492.1973,-664.2532"/>
|
||||
</g>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="432.5,-342 432.5,-374 554.5,-374 554.5,-342 432.5,-342"/>
|
||||
<text text-anchor="start" x="469.8845" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="432.5,-286 432.5,-342 554.5,-342 554.5,-286 432.5,-286"/>
|
||||
<text text-anchor="start" x="483.497" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="454.053" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="459.332" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="432.5,-230 432.5,-286 554.5,-286 554.5,-230 432.5,-230"/>
|
||||
<text text-anchor="start" x="442.1035" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote()</text>
|
||||
<text text-anchor="start" x="478.5025" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A2->A3 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A2->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M493.5,-461.5694C493.5,-432.385 493.5,-401.1011 493.5,-374.0334"/>
|
||||
<polygon fill="none" stroke="#000000" points="490.0001,-461.7943 493.5,-471.7943 497.0001,-461.7943 490.0001,-461.7943"/>
|
||||
<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"><<AbstractIterMeta>></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="255.439" 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="109.5,-342 109.5,-374 231.5,-374 231.5,-342 109.5,-342"/>
|
||||
<text text-anchor="start" x="143.55" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="109.5,-286 109.5,-342 231.5,-342 231.5,-286 109.5,-286"/>
|
||||
<text text-anchor="start" x="160.497" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="131.053" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="136.332" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="109.5,-230 109.5,-286 231.5,-286 231.5,-230 109.5,-230"/>
|
||||
<text text-anchor="start" x="119.1035" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote()</text>
|
||||
<text text-anchor="start" x="155.5025" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</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"><<InverterIfc>></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()->bool</text>
|
||||
<text text-anchor="start" x="188.2835" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>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"><async>create_remote()</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M336.3402,-472.102C291.9351,-449.5364 273.2132,-453.1826 240.5,-422 226.1844,-408.3541 213.8577,-391.1382 203.7145,-374.0392"/>
|
||||
<polygon fill="none" stroke="#000000" points="334.7789,-475.2356 345.2564,-476.808 338.0464,-469.0449 334.7789,-475.2356"/>
|
||||
<!-- A1->A4 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A1->A4</title>
|
||||
<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>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="146.5,-100 146.5,-132 324.5,-132 324.5,-100 146.5,-100"/>
|
||||
<text text-anchor="start" x="191.0515" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="146.5,-68 146.5,-100 324.5,-100 324.5,-68 146.5,-68"/>
|
||||
<text text-anchor="start" x="187.4325" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="146.5,0 146.5,-68 324.5,-68 324.5,0 146.5,0"/>
|
||||
<text text-anchor="start" x="187.1575" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="177.9885" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="156.309" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="220.5025" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<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"><<Singleton>></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"><static>ha_restarts</text>
|
||||
<text text-anchor="start" x="467.7665" y="-423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__client</text>
|
||||
<text text-anchor="start" x="451.3735" y="-411" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__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"><async>publish()</text>
|
||||
<text text-anchor="start" x="468.6045" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>close()</text>
|
||||
</g>
|
||||
<!-- A3->A10 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A3->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M423.406,-237.883C390.0272,-207.3505 349.9479,-170.6888 315.394,-139.0813"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="423.5032,-237.9719 430.6302,-239.0701 432.3576,-246.0713 425.2306,-244.9731 423.5032,-237.9719"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="307.6541,-132.0015 318.0701,-135.4306 311.3435,-135.3762 315.0328,-138.751 315.0328,-138.751 315.0328,-138.751 311.3435,-135.3762 311.9955,-142.0714 307.6541,-132.0015 307.6541,-132.0015"/>
|
||||
<text text-anchor="middle" x="413.278" y="-237.0738" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<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"><cls>db_stat</text>
|
||||
<text text-anchor="start" x="467.491" y="-761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><cls>entity_prfx</text>
|
||||
<text text-anchor="start" x="458.326" y="-749" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><cls>discovery_prfx</text>
|
||||
<text text-anchor="start" x="457.762" y="-737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><cls>proxy_node_id</text>
|
||||
<text text-anchor="start" x="453.873" y="-725" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><cls>proxy_unique_id</text>
|
||||
<text text-anchor="start" x="469.716" y="-713" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><cls>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"><async>_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"><async>_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"><async>_async_publ_mqtt_proxy_stat(key)</text>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="342.5,-82 342.5,-114 480.5,-114 480.5,-82 342.5,-82"/>
|
||||
<text text-anchor="start" x="368.997" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="342.5,-62 342.5,-82 480.5,-82 480.5,-62 342.5,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="342.5,-18 342.5,-62 480.5,-62 480.5,-18 342.5,-18"/>
|
||||
<text text-anchor="start" x="365.378" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="352.324" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A3->A11 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A3->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M468.4517,-229.9099C456.6284,-195.8818 442.7083,-155.8191 431.5897,-123.8193"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="428.2345,-114.1628 435.7674,-122.1318 429.8756,-118.8858 431.5167,-123.6088 431.5167,-123.6088 431.5167,-123.6088 429.8756,-118.8858 427.266,-125.0858 428.2345,-114.1628 428.2345,-114.1628"/>
|
||||
<text text-anchor="middle" x="442.1678" y="-125.5107" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A4->A10 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A4->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M193.635,-218.0021C200.4711,-193.1818 207.9116,-166.167 214.5982,-141.8895"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="193.5418,-218.3407 195.805,-225.1874 190.3553,-229.9099 188.0922,-223.0631 193.5418,-218.3407"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="217.3156,-132.0235 218.9986,-142.8595 215.9878,-136.844 214.6601,-141.6645 214.6601,-141.6645 214.6601,-141.6645 215.9878,-136.844 210.3217,-140.4696 217.3156,-132.0235 217.3156,-132.0235"/>
|
||||
<text text-anchor="middle" x="187.0196" y="-207.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
</g>
|
||||
<!-- A4->A11 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A4->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M204.0248,-229.7777C214.1298,-212.7789 226.361,-195.6557 240.5,-182 274.2553,-149.3986 294.7096,-158.4116 333.5,-132 338.7924,-128.3965 344.1429,-124.4972 349.43,-120.4571"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="357.6686,-114.0147 352.5631,-123.7196 353.7298,-117.0947 349.7911,-120.1747 349.7911,-120.1747 349.7911,-120.1747 353.7298,-117.0947 347.0191,-116.6298 357.6686,-114.0147 357.6686,-114.0147"/>
|
||||
<text text-anchor="middle" x="348.5964" y="-128.8387" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
<!-- A3->A2 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A3->A2</title>
|
||||
<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="320.5,-1840 320.5,-1872 391.5,-1872 391.5,-1840 320.5,-1840"/>
|
||||
<text text-anchor="start" x="330.445" y="-1853" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">IterRegistry</text>
|
||||
<polygon fill="none" stroke="#000000" points="320.5,-1820 320.5,-1840 391.5,-1840 391.5,-1820 320.5,-1820"/>
|
||||
<polygon fill="none" stroke="#000000" points="320.5,-1788 320.5,-1820 391.5,-1820 391.5,-1788 320.5,-1788"/>
|
||||
<text text-anchor="start" x="337.939" y="-1801" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__</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()->bool</text>
|
||||
<text text-anchor="start" x="215.2835" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>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"><async>create_remote()</text>
|
||||
<text text-anchor="start" x="240.984" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>async_publ_mqtt()</text>
|
||||
</g>
|
||||
<!-- A3->A5 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A3->A5</title>
|
||||
<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->A5 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A4->A5</title>
|
||||
<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="288.5,-1706 288.5,-1738 422.5,-1738 422.5,-1706 288.5,-1706"/>
|
||||
<text text-anchor="start" x="335.2175" y="-1719" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="288.5,-1530 288.5,-1706 422.5,-1706 422.5,-1530 288.5,-1530"/>
|
||||
<text text-anchor="start" x="318.8265" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="316.043" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="308.814" y="-1663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len:unsigned</text>
|
||||
<text text-anchor="start" x="314.648" y="-1651" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len:unsigned</text>
|
||||
<text text-anchor="start" x="333.8245" y="-1639" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="337.7135" y="-1627" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="334.6585" y="-1615" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area</text>
|
||||
<text text-anchor="start" x="305.489" y="-1603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_recv_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="304.0945" y="-1591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="298.2665" y="-1579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_forward_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="337.7135" y="-1567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:Infos</text>
|
||||
<text text-anchor="start" x="326.326" y="-1555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:list</text>
|
||||
<text text-anchor="start" x="344.662" y="-1543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state</text>
|
||||
<polygon fill="none" stroke="#000000" points="288.5,-1462 288.5,-1530 422.5,-1530 422.5,-1462 288.5,-1462"/>
|
||||
<text text-anchor="start" x="305.2095" y="-1511" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_read():void<abstract></text>
|
||||
<text text-anchor="start" x="329.9445" y="-1499" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close():void</text>
|
||||
<text text-anchor="start" x="315.7725" y="-1487" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter():void</text>
|
||||
<text text-anchor="start" x="314.1025" y="-1475" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter():void</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->A6 -->
|
||||
<g id="edge4" class="edge">
|
||||
<g id="edge8" class="edge">
|
||||
<title>A5->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M355.5,-1777.5582C355.5,-1765.4749 355.5,-1752.067 355.5,-1738.189"/>
|
||||
<polygon fill="none" stroke="#000000" points="352.0001,-1777.8144 355.5,-1787.8145 359.0001,-1777.8145 352.0001,-1777.8144"/>
|
||||
</g>
|
||||
<!-- A17 -->
|
||||
<g id="node18" class="node">
|
||||
<title>A17</title>
|
||||
<polygon fill="none" stroke="#000000" points="481.5,-1380 481.5,-1412 595.5,-1412 595.5,-1380 481.5,-1380"/>
|
||||
<text text-anchor="start" x="524.608" y="-1393" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="481.5,-1228 481.5,-1380 595.5,-1380 595.5,-1228 481.5,-1228"/>
|
||||
<text text-anchor="start" x="513.2185" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="519.323" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="528.497" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="491.263" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="526.2775" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="507.1" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="510.44" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="514.0445" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="512.384" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="524.612" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="481.5,-1100 481.5,-1228 595.5,-1228 595.5,-1100 481.5,-1100"/>
|
||||
<text text-anchor="start" x="495.9925" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="497.9325" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="503.7765" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="491.8285" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="493.7735" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="502.9405" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="519.054" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="523.5025" y="-1113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A6->A17 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>A6->A17</title>
|
||||
<path fill="none" stroke="#000000" d="M427.9888,-1489.9254C443.4425,-1464.7479 459.121,-1437.7954 472.5,-1412 475.4787,-1406.2569 478.4329,-1400.3487 481.3448,-1394.3464"/>
|
||||
<polygon fill="none" stroke="#000000" points="424.814,-1488.4051 422.5361,-1498.7522 430.7693,-1492.084 424.814,-1488.4051"/>
|
||||
</g>
|
||||
<!-- A18 -->
|
||||
<g id="node19" class="node">
|
||||
<title>A18</title>
|
||||
<polygon fill="none" stroke="#000000" points="251.5,-1344 251.5,-1376 342.5,-1376 342.5,-1344 251.5,-1344"/>
|
||||
<text text-anchor="start" x="269.495" y="-1357" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="251.5,-1204 251.5,-1344 342.5,-1344 342.5,-1204 251.5,-1204"/>
|
||||
<text text-anchor="start" x="271.7185" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="277.823" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="286.997" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="281.998" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="285.0575" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="290.056" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="269.21" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="270.884" y="-1229" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="283.112" y="-1217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="251.5,-1136 251.5,-1204 342.5,-1204 342.5,-1136 251.5,-1136"/>
|
||||
<text text-anchor="start" x="261.4405" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="277.554" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="282.0025" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A6->A18 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>A6->A18</title>
|
||||
<path fill="none" stroke="#000000" d="M330.044,-1451.5785C325.7233,-1426.3869 321.2847,-1400.5076 317.1084,-1376.1574"/>
|
||||
<polygon fill="none" stroke="#000000" points="326.6173,-1452.3046 331.7575,-1461.569 333.5166,-1451.1212 326.6173,-1452.3046"/>
|
||||
<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="293.5,-1018 293.5,-1050 410.5,-1050 410.5,-1018 293.5,-1018"/>
|
||||
<text text-anchor="start" x="321.429" y="-1031" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="293.5,-998 293.5,-1018 410.5,-1018 410.5,-998 293.5,-998"/>
|
||||
<polygon fill="none" stroke="#000000" points="293.5,-702 293.5,-998 410.5,-998 410.5,-702 293.5,-702"/>
|
||||
<text text-anchor="start" x="321.436" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="319.766" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="333.6635" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="331.444" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="335.0535" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="331.1635" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="335.3335" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="331.169" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="335.3335" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="329.7745" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="327.555" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_flush()</text>
|
||||
<text text-anchor="start" x="331.4445" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="327.28" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_clear()</text>
|
||||
<text text-anchor="start" x="334.7785" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="330.8885" y="-787" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="335.0585" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="330.894" y="-763" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="335.0585" y="-751" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="326.999" y="-739" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="303.3795" y="-715" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</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>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="234.5,-592 234.5,-624 327.5,-624 327.5,-592 234.5,-592"/>
|
||||
<text text-anchor="start" x="252.664" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="234.5,-500 234.5,-592 327.5,-592 327.5,-500 234.5,-500"/>
|
||||
<text text-anchor="start" x="244.048" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="247.937" y="-561" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="247.662" y="-549" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="247.096" y="-537" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="263.2135" y="-525" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="256.5495" y="-513" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A7->A8 -->
|
||||
<!-- A5->A7 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M309.7911,-691.541C304.3381,-667.4249 299.0868,-644.201 294.5737,-624.2415"/>
|
||||
<polygon fill="none" stroke="#000000" points="306.4357,-692.5718 312.0551,-701.5536 313.2634,-691.0279 306.4357,-692.5718"/>
|
||||
<title>A5->A7</title>
|
||||
<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="249.5,-390 249.5,-422 351.5,-422 351.5,-390 249.5,-390"/>
|
||||
<text text-anchor="start" x="270.774" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="249.5,-310 249.5,-390 351.5,-390 351.5,-310 249.5,-310"/>
|
||||
<text text-anchor="start" x="286.053" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="288.283" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="290.497" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="286.053" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="286.608" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="249.5,-182 249.5,-310 351.5,-310 351.5,-182 249.5,-182"/>
|
||||
<text text-anchor="start" x="272.154" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="288.282" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="285.5025" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="281.054" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="265.7705" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="265.221" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="259.107" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</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>
|
||||
<!-- A8->A9 -->
|
||||
<!-- A5->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A8->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M286.0661,-489.6408C287.6796,-468.6648 289.4863,-445.1785 291.2608,-422.1099"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="285.2905,-499.7235 281.5708,-489.4078 285.674,-494.7382 286.0576,-489.753 286.0576,-489.753 286.0576,-489.753 285.674,-494.7382 290.5443,-490.0982 285.2905,-499.7235 285.2905,-499.7235"/>
|
||||
<title>A5->A9</title>
|
||||
<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>
|
||||
<!-- A9->A10 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A9->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M264.6771,-171.9352C260.9087,-158.2531 257.2005,-144.7897 253.7581,-132.2911"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="267.4287,-181.9259 260.4348,-173.4798 266.101,-177.1054 264.7733,-172.2849 264.7733,-172.2849 264.7733,-172.2849 266.101,-177.1054 269.1118,-171.0899 267.4287,-181.9259 267.4287,-181.9259"/>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<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"><<AsyncIfc>></text>
|
||||
</g>
|
||||
<!-- A9->A11 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A9->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M355.9159,-184.1788C367.6037,-159.329 379.2966,-134.4686 388.921,-114.0059"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="351.6139,-193.3253 351.798,-182.361 353.742,-188.8008 355.8701,-184.2763 355.8701,-184.2763 355.8701,-184.2763 353.742,-188.8008 359.9422,-186.1915 351.6139,-193.3253 351.6139,-193.3253"/>
|
||||
<!-- A6->A11 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A6->A11</title>
|
||||
<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="660.5,-566 660.5,-598 743.5,-598 743.5,-566 660.5,-566"/>
|
||||
<text text-anchor="start" x="670.0455" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="660.5,-546 660.5,-566 743.5,-566 743.5,-546 660.5,-546"/>
|
||||
<polygon fill="none" stroke="#000000" points="660.5,-526 660.5,-546 743.5,-546 743.5,-526 660.5,-526"/>
|
||||
<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"><<ProtocolIfc>></text>
|
||||
</g>
|
||||
<!-- A12->A3 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A12->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M670.0413,-516.8237C661.3918,-502.0835 651.6725,-485.9341 641.5,-472 615.4427,-436.3073 582.7913,-399.9006 554.7376,-369.9836"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="675.2831,-525.787 666.3503,-519.4264 672.759,-521.4709 670.2349,-517.1547 670.2349,-517.1547 670.2349,-517.1547 672.759,-521.4709 674.1194,-514.883 675.2831,-525.787 675.2831,-525.787"/>
|
||||
<text text-anchor="middle" x="658.8364" y="-511.4069" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
<!-- A6->A12 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A6->A12</title>
|
||||
<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>
|
||||
<!-- A12->A3 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A12->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M687.0902,-516.8237C679.3918,-502.0835 669.6725,-485.9341 659.5,-472 631.135,-433.1461 594.956,-393.4463 563.5578,-362.1925"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="691.6084,-525.787 683.0888,-518.8829 689.3578,-521.3222 687.1072,-516.8573 687.1072,-516.8573 687.1072,-516.8573 689.3578,-521.3222 691.1255,-514.8318 691.6084,-525.787 691.6084,-525.787"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="563.3904,-362.0278 556.3085,-360.6689 554.8391,-353.609 561.921,-354.968 563.3904,-362.0278"/>
|
||||
<text text-anchor="middle" x="573.6858" y="-357.3024" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<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->A8 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<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="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->A10 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A9->A10</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M94.5156,-220C100.3114,-220 106.1072,-220 111.903,-220"/>
|
||||
</g>
|
||||
<!-- A12->A11 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A12->A11</title>
|
||||
<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="125.5,-566 125.5,-598 215.5,-598 215.5,-566 125.5,-566"/>
|
||||
<text text-anchor="start" x="135.211" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-546 125.5,-566 215.5,-566 215.5,-546 125.5,-546"/>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-526 125.5,-546 215.5,-546 215.5,-526 125.5,-526"/>
|
||||
<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->A4 -->
|
||||
<!-- A13->A9 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A13->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M165.1942,-515.7657C163.5941,-476.4902 163.3236,-419.4483 164.3827,-374.1655"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="165.655,-525.8481 160.7031,-516.064 165.4267,-520.8533 165.1984,-515.8585 165.1984,-515.8585 165.1984,-515.8585 165.4267,-520.8533 169.6937,-515.653 165.655,-525.8481 165.655,-525.8481"/>
|
||||
<text text-anchor="middle" x="156.3839" y="-505.1268" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A13->A4 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A13->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M175.8058,-515.7657C177.2652,-479.9422 177.6185,-429.338 176.8658,-386.3578"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="175.345,-525.8481 171.3063,-515.653 175.5733,-520.8533 175.8016,-515.8585 175.8016,-515.8585 175.8016,-515.8585 175.5733,-520.8533 180.2969,-516.064 175.345,-525.8481 175.345,-525.8481"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="176.8619,-386.163 172.7404,-380.2458 176.6173,-374.1655 180.7388,-380.0827 176.8619,-386.163"/>
|
||||
<text text-anchor="middle" x="185.4372" y="-389.1157" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
<title>A13->A9</title>
|
||||
<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="360.5,-1344 360.5,-1376 463.5,-1376 463.5,-1344 360.5,-1344"/>
|
||||
<text text-anchor="start" x="401.162" y="-1357" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="360.5,-1288 360.5,-1344 463.5,-1344 463.5,-1288 360.5,-1288"/>
|
||||
<text text-anchor="start" x="403.9415" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="379.486" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="393.1035" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="360.5,-1136 360.5,-1288 463.5,-1288 463.5,-1136 360.5,-1136"/>
|
||||
<text text-anchor="start" x="387.8355" y="-1269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="385.8845" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="382.8305" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="381.1605" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="379.21" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="394.213" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="386.994" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="388.3745" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="372.537" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="381.9855" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="370.3225" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</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>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="569.5,-892 569.5,-924 636.5,-924 636.5,-892 569.5,-892"/>
|
||||
<text text-anchor="start" x="585.493" y="-905" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="569.5,-872 569.5,-892 636.5,-892 636.5,-872 569.5,-872"/>
|
||||
<polygon fill="none" stroke="#000000" points="569.5,-828 569.5,-872 636.5,-872 636.5,-828 569.5,-828"/>
|
||||
<text text-anchor="start" x="579.384" y="-853" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="587.168" y="-841" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A14->A15 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A14->A15</title>
|
||||
<path fill="none" stroke="#000000" d="M453.5702,-1126.8365C459.1676,-1117.273 465.4534,-1108.1823 472.5,-1100 501.6027,-1066.2069 532.6622,-1085.6184 559.5,-1050 586.933,-1013.5917 597.05,-961.8709 600.6858,-924.2866"/>
|
||||
<polygon fill="none" stroke="#000000" points="450.4206,-1125.2989 448.6212,-1135.7398 456.5389,-1128.6999 450.4206,-1125.2989"/>
|
||||
</g>
|
||||
<!-- A16 -->
|
||||
<g id="node17" class="node">
|
||||
<title>A16</title>
|
||||
<polygon fill="none" stroke="#000000" points="208.5,-892 208.5,-924 275.5,-924 275.5,-892 208.5,-892"/>
|
||||
<text text-anchor="start" x="221.1585" y="-905" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="208.5,-872 208.5,-892 275.5,-892 275.5,-872 208.5,-872"/>
|
||||
<polygon fill="none" stroke="#000000" points="208.5,-828 208.5,-872 275.5,-872 275.5,-828 208.5,-828"/>
|
||||
<text text-anchor="start" x="218.384" y="-853" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="226.168" y="-841" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A14->A16 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A14->A16</title>
|
||||
<path fill="none" stroke="#000000" d="M368.702,-1126.8311C363.5287,-1117.3934 357.8082,-1108.3251 351.5,-1100 329.0603,-1070.3857 305.0477,-1080.957 284.5,-1050 259.462,-1012.2779 248.9948,-961.2276 244.6235,-924.1849"/>
|
||||
<polygon fill="none" stroke="#000000" points="365.7545,-1128.7471 373.4957,-1135.9807 371.9551,-1125.4985 365.7545,-1128.7471"/>
|
||||
</g>
|
||||
<!-- A17->A7 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>A17->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M481.2663,-1113.4759C478.4435,-1108.8532 475.521,-1104.3466 472.5,-1100 454.0182,-1073.4084 437.6119,-1076.8449 419.5,-1050 418.0715,-1047.8827 416.6665,-1045.731 415.285,-1043.5491"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="410.0723,-1034.9917 419.1178,-1041.1909 412.6735,-1039.2618 415.2746,-1043.532 415.2746,-1043.532 415.2746,-1043.532 412.6735,-1039.2618 411.4315,-1045.873 410.0723,-1034.9917 410.0723,-1034.9917"/>
|
||||
<text text-anchor="middle" x="464.576" y="-1099.4562" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A17->A12 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>A17->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M600.4516,-1154.6847C617.6767,-1122.289 634.6239,-1085.5805 645.5,-1050 695.4203,-886.6897 701.5078,-680.2741 701.7917,-598.1154"/>
|
||||
<polygon fill="none" stroke="#000000" points="597.2545,-1153.2396 595.5908,-1163.703 603.4164,-1156.5609 597.2545,-1153.2396"/>
|
||||
</g>
|
||||
<!-- A17->A15 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>A17->A15</title>
|
||||
<path fill="none" stroke="#000000" d="M564.8083,-1099.7944C574.6598,-1041.3014 585.2548,-978.3931 592.6952,-934.2163"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="594.3746,-924.2447 597.1512,-934.8533 593.5441,-929.1753 592.7137,-934.1059 592.7137,-934.1059 592.7137,-934.1059 593.5441,-929.1753 588.2762,-933.3585 594.3746,-924.2447 594.3746,-924.2447"/>
|
||||
</g>
|
||||
<!-- A18->A7 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>A18->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M313.9023,-1135.7656C317.3752,-1111.771 321.0977,-1086.0526 324.8007,-1060.468"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="326.2737,-1050.2909 329.2948,-1060.8324 325.5574,-1055.2393 324.8412,-1060.1877 324.8412,-1060.1877 324.8412,-1060.1877 325.5574,-1055.2393 320.3876,-1059.5431 326.2737,-1050.2909 326.2737,-1050.2909"/>
|
||||
<text text-anchor="middle" x="308.1336" y="-1113.6156" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A18->A13 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>A18->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M246.2928,-1168.5418C228.2709,-1132.9118 209.8568,-1090.6085 199.5,-1050 157.5515,-885.5216 163.4473,-680.1892 168.0341,-598.2267"/>
|
||||
<polygon fill="none" stroke="#000000" points="243.1839,-1170.1499 250.861,-1177.4515 249.4129,-1166.956 243.1839,-1170.1499"/>
|
||||
</g>
|
||||
<!-- A18->A16 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>A18->A16</title>
|
||||
<path fill="none" stroke="#000000" d="M279.0977,-1135.7656C269.3705,-1068.56 257.686,-987.8309 249.9522,-934.3969"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="248.5077,-924.4166 254.3938,-933.6689 249.2239,-929.3651 249.9402,-934.3135 249.9402,-934.3135 249.9402,-934.3135 249.2239,-929.3651 245.4866,-934.9581 248.5077,-924.4166 248.5077,-924.4166"/>
|
||||
</g>
|
||||
<!-- A19 -->
|
||||
<g id="node20" class="node">
|
||||
<title>A19</title>
|
||||
<polygon fill="none" stroke="#000000" points="471.5,-1694 471.5,-1726 546.5,-1726 546.5,-1694 471.5,-1694"/>
|
||||
<text text-anchor="start" x="491.2175" y="-1707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="471.5,-1542 471.5,-1694 546.5,-1694 546.5,-1542 471.5,-1542"/>
|
||||
<text text-anchor="start" x="500.6615" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="481.49" y="-1651" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="482.605" y="-1639" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="492.6085" y="-1627" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="482.8895" y="-1615" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="490.942" y="-1603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="502.8915" y="-1591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="489.5535" y="-1579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="487.879" y="-1567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="502.3365" y="-1555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="471.5,-1474 471.5,-1542 546.5,-1542 546.5,-1474 471.5,-1474"/>
|
||||
<text text-anchor="start" x="482.89" y="-1523" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="486.224" y="-1511" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="483.724" y="-1499" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="494.0025" y="-1487" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A19->A17 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>A19->A17</title>
|
||||
<path fill="none" stroke="#000000" d="M520.408,-1463.4549C521.8748,-1446.6352 523.3829,-1429.3425 524.8728,-1412.2588"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="519.5005,-1473.8604 515.8864,-1463.5072 519.935,-1468.8793 520.3694,-1463.8982 520.3694,-1463.8982 520.3694,-1463.8982 519.935,-1468.8793 524.8524,-1464.2892 519.5005,-1473.8604 519.5005,-1473.8604"/>
|
||||
<text text-anchor="middle" x="531.7184" y="-1428.0507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="512.6549" y="-1452.0685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A19->A18 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>A19->A18</title>
|
||||
<path fill="none" stroke="#000000" d="M465.5007,-1507.5446C455.6528,-1491.3512 444.2658,-1475.4159 431.5,-1462 402.597,-1431.625 377.7201,-1444.719 351.5,-1412 342.88,-1401.2435 335.5589,-1389.0363 329.3527,-1376.3006"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="470.8124,-1516.5531 461.8569,-1510.2246 468.2729,-1512.246 465.7333,-1507.939 465.7333,-1507.939 465.7333,-1507.939 468.2729,-1512.246 469.6096,-1505.6533 470.8124,-1516.5531 470.8124,-1516.5531"/>
|
||||
<text text-anchor="middle" x="345.0021" y="-1385.7544" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="454.325" y="-1502.2321" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A20 -->
|
||||
<g id="node21" class="node">
|
||||
<title>A20</title>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-590 .5,-622 107.5,-622 107.5,-590 .5,-590"/>
|
||||
<text text-anchor="start" x="24.2695" y="-603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusConn</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-522 .5,-590 107.5,-590 107.5,-522 .5,-522"/>
|
||||
<text text-anchor="start" x="44.5515" y="-571" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">host</text>
|
||||
<text text-anchor="start" x="45.387" y="-559" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">port</text>
|
||||
<text text-anchor="start" x="43.997" y="-547" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="10.383" y="-535" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-502 .5,-522 107.5,-522 107.5,-502 .5,-502"/>
|
||||
</g>
|
||||
<!-- A20->A4 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>A20->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M80.6362,-501.6973C96.3809,-466.7091 116.429,-422.1579 133.5925,-384.0168"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="137.8895,-374.4677 137.8895,-385.4336 135.8377,-379.0273 133.7858,-383.5869 133.7858,-383.5869 133.7858,-383.5869 135.8377,-379.0273 129.6822,-381.7402 137.8895,-374.4677 137.8895,-374.4677"/>
|
||||
<text text-anchor="middle" x="138.1591" y="-391.4659" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
<text text-anchor="middle" x="80.3667" y="-478.6991" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<!-- A14->A13 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A14->A13</title>
|
||||
<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: 47 KiB After Width: | Height: | Size: 20 KiB |
@@ -3,57 +3,34 @@
|
||||
// {generate:true}
|
||||
|
||||
[note: You can stick notes on diagrams too!{bg:cornsilk}]
|
||||
[<<AbstractIterMeta>>||__iter__]
|
||||
|
||||
[Mqtt;<<Singleton>>|<static>ha_restarts;<static>__client;<static>__cb_MqttIsUp|<async>publish();<async>close()]
|
||||
[Inverter|cls.db_stat;cls.entity_prfx;cls.discovery_prfx;cls.proxy_node_id;cls.proxy_unique_id;cls.mqtt:Mqtt;;__ha_restarts|async_create_remote(inv_prot, conn_class)async_publ_mqtt()]
|
||||
[Inverter]^[InverterG3|addr;remote:StreamPtr;local:StreamPtr|async_create_remote();;close()]
|
||||
[Inverter]^[InverterG3P|addr;remote:StreamPtr;local:StreamPtr|async_create_remote();;close()]
|
||||
[Mqtt;<<Singleton>>]<-++[Inverter]
|
||||
[Proxy|<cls>db_stat;<cls>entity_prfx;<cls>discovery_prfx;<cls>proxy_node_id;<cls>proxy_unique_id;<cls>mqtt:Mqtt;;__ha_restarts|class_init();class_close();;<async>_cb_mqtt_is_up();<async>_register_proxy_stat_home_assistant();<async>_async_publ_mqtt_proxy_stat(key)]
|
||||
|
||||
[IterRegistry||__iter__]^[Message|server_side:bool;header_valid:bool;header_len:unsigned;data_len:unsigned;unique_id;node_id;sug_area;_recv_buffer:bytearray;_send_buffer:bytearray;_forward_buffer:bytearray;db:Infos;new_data:list;state|_read():void<abstract>;close():void;inc_counter():void;dec_counter():void]
|
||||
[<<InverterIfc>>||healthy()->bool;<async>disc(shutdown_started=False);<async>create_remote();]
|
||||
[<<AbstractIterMeta>>]^-.-[<<InverterIfc>>]
|
||||
[InverterBase|_registry;__ha_restarts;;addr;config_id:str;prot_class:MessageProt;remote:StreamPtr;local:StreamPtr;|healthy()->bool;<async>disc(shutdown_started=False);<async>create_remote();<async>async_publ_mqtt()]
|
||||
[StreamPtr||stream:ProtocolIfc;ifc:AsyncIfc]
|
||||
[<<InverterIfc>>]^-.-[InverterBase]
|
||||
[InverterG3]-[note: Creates an GEN3 inverter instance with prot_class:Talent{bg:cornsilk}]
|
||||
[InverterG3P]-[note: Creates an GEN3PLUS inverter instance with prot_class:SolarmanV5{bg:cornsilk}]
|
||||
[InverterBase]^[InverterG3]
|
||||
[InverterBase]^[InverterG3P]
|
||||
[Proxy]^[InverterBase]
|
||||
[InverterBase]-2>[StreamPtr]
|
||||
[Proxy]++->[Mqtt;<<Singleton>>]
|
||||
|
||||
[<<AsyncIfc>>||set_node_id();get_conn_no();;tx_add();tx_flush();tx_get();tx_peek();tx_log();tx_clear();tx_len();;fwd_add();fwd_flush();fwd_log();fwd_clear();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()]
|
||||
[AsyncStreamServer|async_create_remote|<async>server_loop();<async>_async_forward();<async>publish_outstanding_mqtt();close()]
|
||||
[AsyncStreamClient||<async>client_loop();<async>_async_forward())]
|
||||
[<<AsyncIfc>>]^-.-[AsyncIfcImpl]
|
||||
[AsyncIfcImpl]<-[AsyncStream]
|
||||
[AsyncStream]<-[AsyncStreamServer]
|
||||
[AsyncStream]<-[AsyncStreamClient]
|
||||
[<<AsyncIfc>>]
|
||||
|
||||
|
||||
[ConnectionG3||]
|
||||
[ConnectionG3]<remote-[InverterG3]
|
||||
[InverterG3]-remote>[AsyncStreamClient]
|
||||
[ConnectionG3]<-local++[InverterG3]
|
||||
[InverterG3]++local->[AsyncStreamServer]
|
||||
[StreamPtr]-1>[<<ProtocolIfc>>]
|
||||
[StreamPtr]-1>[<<AsyncIfc>>]
|
||||
|
||||
[ConnectionG3P||]
|
||||
[ConnectionG3P]<remote-[InverterG3P]
|
||||
[InverterG3P]-remote>[AsyncStreamClient]
|
||||
[ConnectionG3P]<-local++[InverterG3P]
|
||||
[InverterG3P]++local->[AsyncStreamServer]
|
||||
|
||||
[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]^[InfosG3||ha_confs();parse()]
|
||||
[Infos]^[InfosG3P||ha_confs();parse()]
|
||||
[<<ProtocolIfc>>]use-.->[<<AsyncIfc>>]
|
||||
|
||||
[Talent|ifc:AsyncIfc;conn_no;addr;;await_conn_resp_cnt;id_str;contact_name;contact_mail;db:InfosG3;mb:Modbus;switch|msg_contact_info();msg_ota_update();msg_get_time();msg_collector_data();msg_inverter_data();msg_unknown();;healthy();close()]
|
||||
[Talent]^[ConnectionG3]
|
||||
[Talent]use->[<<AsyncIfc>>]
|
||||
[Talent]->[InfosG3]
|
||||
[SolarmanV5|ifc:AsyncIfc;conn_no;addr;;control;serial;snr;db:InfosG3P;mb:Modbus;switch|msg_unknown();;healthy();close()]
|
||||
[SolarmanV5]^[ConnectionG3P]
|
||||
[SolarmanV5]use->[<<AsyncIfc>>]
|
||||
[SolarmanV5]->[InfosG3P]
|
||||
|
||||
[Message]^[Talent]
|
||||
[Message]^[SolarmanV5]
|
||||
|
||||
[Modbus|que;;snd_handler;rsp_handler;timeout;max_retires;last_xxx;err;retry_cnt;req_pend;tim|build_msg();recv_req();recv_resp();close()]
|
||||
[Modbus]<1-has[SolarmanV5]
|
||||
[Modbus]<1-has[Talent]
|
||||
|
||||
[ModbusConn|host;port;addr;stream:InverterG3P;|]has-1>[InverterG3P]
|
||||
[ModbusTcp]creates-*>[ModbusConn]
|
||||
|
||||
|
||||
416
app/proxy_2.svg
Normal file
416
app/proxy_2.svg
Normal file
@@ -0,0 +1,416 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="446pt" height="1796pt"
|
||||
viewBox="0.00 0.00 446.35 1796.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 1792)">
|
||||
<title>G</title>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1792 442.348,-1792 442.348,4 -4,4"/>
|
||||
<!-- A0 -->
|
||||
<g id="node1" class="node">
|
||||
<title>A0</title>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="108.5444,-1764 .1516,-1764 .1516,-1728 114.5444,-1728 114.5444,-1758 108.5444,-1764"/>
|
||||
<polyline fill="none" stroke="#000000" points="108.5444,-1764 108.5444,-1758 "/>
|
||||
<polyline fill="none" stroke="#000000" points="114.5444,-1758 108.5444,-1758 "/>
|
||||
<text text-anchor="middle" x="57.348" y="-1749" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
|
||||
<text text-anchor="middle" x="57.348" y="-1737" 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="133.348,-1756 133.348,-1788 204.348,-1788 204.348,-1756 133.348,-1756"/>
|
||||
<text text-anchor="start" x="143.293" y="-1769" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">IterRegistry</text>
|
||||
<polygon fill="none" stroke="#000000" points="133.348,-1736 133.348,-1756 204.348,-1756 204.348,-1736 133.348,-1736"/>
|
||||
<polygon fill="none" stroke="#000000" points="133.348,-1704 133.348,-1736 204.348,-1736 204.348,-1704 133.348,-1704"/>
|
||||
<text text-anchor="start" x="150.787" y="-1717" 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="128.348,-1550 128.348,-1582 209.348,-1582 209.348,-1550 128.348,-1550"/>
|
||||
<text text-anchor="start" x="148.5655" y="-1563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="128.348,-1518 128.348,-1550 209.348,-1550 209.348,-1518 128.348,-1518"/>
|
||||
<text text-anchor="start" x="151.0615" y="-1531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<polygon fill="none" stroke="#000000" points="128.348,-1474 128.348,-1518 209.348,-1518 209.348,-1474 128.348,-1474"/>
|
||||
<text text-anchor="start" x="139.6785" y="-1499" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="138.0085" y="-1487" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
</g>
|
||||
<!-- A1->A14 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>A1->A14</title>
|
||||
<path fill="none" stroke="#000000" d="M168.348,-1693.8572C168.348,-1660.1684 168.348,-1616.4162 168.348,-1582.3079"/>
|
||||
<polygon fill="none" stroke="#000000" points="164.8481,-1693.9674 168.348,-1703.9674 171.8481,-1693.9674 164.8481,-1693.9674"/>
|
||||
</g>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="340.348,-584 340.348,-616 438.348,-616 438.348,-584 340.348,-584"/>
|
||||
<text text-anchor="start" x="365.7325" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="340.348,-528 340.348,-584 438.348,-584 438.348,-528 340.348,-528"/>
|
||||
<text text-anchor="start" x="379.345" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="349.901" y="-553" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="355.18" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="340.348,-472 340.348,-528 438.348,-528 438.348,-472 340.348,-472"/>
|
||||
<text text-anchor="start" x="353.79" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="374.3505" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="7.348,-100 7.348,-132 185.348,-132 185.348,-100 7.348,-100"/>
|
||||
<text text-anchor="start" x="51.8995" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="7.348,-68 7.348,-100 185.348,-100 185.348,-68 7.348,-68"/>
|
||||
<text text-anchor="start" x="64.119" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="7.348,0 7.348,-68 185.348,-68 185.348,0 7.348,0"/>
|
||||
<text text-anchor="start" x="48.0055" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="38.8365" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="17.157" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="81.3505" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A2->A7 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A2->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M355.1669,-460.7015C350.2935,-447.8271 345.5247,-434.6178 341.348,-422 306.6206,-317.0888 342.6855,-270.3837 276.348,-182 250.7246,-147.8611 230.2817,-155.039 194.348,-132 194.2563,-131.9412 194.1645,-131.8823 194.0727,-131.8234"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="355.1669,-460.7018 361.0503,-464.8714 359.4643,-471.9059 353.5809,-467.7363 355.1669,-460.7018"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="185.433,-126.2441 196.2748,-127.8888 189.6333,-128.9566 193.8336,-131.6691 193.8336,-131.6691 193.8336,-131.6691 189.6333,-128.9566 191.3923,-135.4493 185.433,-126.2441 185.433,-126.2441"/>
|
||||
<text text-anchor="middle" x="345.0813" y="-455.0087" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="203.348,-82 203.348,-114 341.348,-114 341.348,-82 203.348,-82"/>
|
||||
<text text-anchor="start" x="229.845" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="203.348,-62 203.348,-82 341.348,-82 341.348,-62 203.348,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="203.348,-18 203.348,-62 341.348,-62 341.348,-18 203.348,-18"/>
|
||||
<text text-anchor="start" x="226.226" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="213.172" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A2->A8 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A2->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M388.2845,-471.9734C385.2471,-397.4776 374.9339,-278.7213 341.348,-182 334.28,-161.6455 323.3872,-140.9471 312.3293,-122.7781"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="306.9036,-114.0745 316.0125,-120.18 309.5487,-118.3175 312.1938,-122.5606 312.1938,-122.5606 312.1938,-122.5606 309.5487,-118.3175 308.375,-124.9412 306.9036,-114.0745 306.9036,-114.0745"/>
|
||||
<text text-anchor="middle" x="323.6654" y="-121.9851" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="18.348,-342 18.348,-374 116.348,-374 116.348,-342 18.348,-342"/>
|
||||
<text text-anchor="start" x="40.398" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="18.348,-286 18.348,-342 116.348,-342 116.348,-286 18.348,-286"/>
|
||||
<text text-anchor="start" x="57.345" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="27.901" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="33.18" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="18.348,-230 18.348,-286 116.348,-286 116.348,-230 18.348,-230"/>
|
||||
<text text-anchor="start" x="31.79" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="52.3505" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A3->A7 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A3->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M77.7163,-217.6237C80.7418,-193.0021 84.0292,-166.2494 86.9885,-142.1671"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="77.6702,-217.9995 80.9085,-224.4425 76.2065,-229.9099 72.9682,-223.4668 77.6702,-217.9995"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="88.2349,-132.0235 91.4816,-142.4978 87.6251,-136.9862 87.0152,-141.9489 87.0152,-141.9489 87.0152,-141.9489 87.6251,-136.9862 82.5488,-141.4 88.2349,-132.0235 88.2349,-132.0235"/>
|
||||
<text text-anchor="middle" x="70.028" y="-207.8882" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
</g>
|
||||
<!-- A3->A8 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A3->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M116.4873,-232.1115C129.0204,-215.3231 142.7944,-197.7122 156.348,-182 174.1632,-161.3474 194.8826,-139.9135 213.8403,-121.173"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="221.01,-114.1296 217.0299,-124.3477 217.4432,-117.6336 213.8763,-121.1375 213.8763,-121.1375 213.8763,-121.1375 217.4432,-117.6336 210.7227,-117.9274 221.01,-114.1296 221.01,-114.1296"/>
|
||||
<text text-anchor="middle" x="214.0028" y="-129.8619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="158.348,-958 158.348,-990 275.348,-990 275.348,-958 158.348,-958"/>
|
||||
<text text-anchor="start" x="186.277" y="-971" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="158.348,-938 158.348,-958 275.348,-958 275.348,-938 158.348,-938"/>
|
||||
<polygon fill="none" stroke="#000000" points="158.348,-666 158.348,-938 275.348,-938 275.348,-666 158.348,-666"/>
|
||||
<text text-anchor="start" x="186.284" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="184.614" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="198.5115" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="196.292" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="199.9015" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="196.0115" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="200.1815" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="196.017" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="200.1815" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="194.6225" y="-787" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="196.2925" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="199.6265" y="-763" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="195.7365" y="-751" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="199.9065" y="-739" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="195.742" y="-727" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="199.9065" y="-715" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="191.847" y="-703" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="168.2275" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="170.348,-574 170.348,-606 263.348,-606 263.348,-574 170.348,-574"/>
|
||||
<text text-anchor="start" x="188.512" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="170.348,-482 170.348,-574 263.348,-574 263.348,-482 170.348,-482"/>
|
||||
<text text-anchor="start" x="179.896" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="183.785" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="183.51" y="-531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="182.944" y="-519" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="199.0615" y="-507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="192.3975" y="-495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A4->A5 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A4->A5</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M216.348,-655.339C216.348,-637.8929 216.348,-621.0952 216.348,-606.0686"/>
|
||||
<polygon fill="none" stroke="#000000" points="212.8481,-655.6774 216.348,-665.6775 219.8481,-655.6775 212.8481,-655.6774"/>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="165.348,-390 165.348,-422 267.348,-422 267.348,-390 165.348,-390"/>
|
||||
<text text-anchor="start" x="186.622" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="165.348,-310 165.348,-390 267.348,-390 267.348,-310 165.348,-310"/>
|
||||
<text text-anchor="start" x="201.901" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="204.131" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="206.345" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="201.901" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="202.456" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="165.348,-182 165.348,-310 267.348,-310 267.348,-182 165.348,-182"/>
|
||||
<text text-anchor="start" x="188.002" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="204.13" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="201.3505" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="196.902" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="181.6185" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="181.069" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="174.955" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A5->A6 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A5->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M216.348,-471.886C216.348,-456.1951 216.348,-439.1858 216.348,-422.1976"/>
|
||||
<polygon fill="none" stroke="#000000" points="212.8481,-471.9932 216.348,-481.9932 219.8481,-471.9933 212.8481,-471.9932"/>
|
||||
</g>
|
||||
<!-- A6->A7 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A6->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M160.6502,-192.461C150.1789,-171.8674 139.5319,-150.9284 129.9938,-132.1701"/>
|
||||
<polygon fill="none" stroke="#000000" points="157.6308,-194.2451 165.2832,-201.5725 163.8705,-191.0723 157.6308,-194.2451"/>
|
||||
</g>
|
||||
<!-- A6->A8 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A6->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M247.1746,-172.088C252.0746,-151.438 256.8579,-131.2796 260.9161,-114.1772"/>
|
||||
<polygon fill="none" stroke="#000000" points="243.7436,-171.3879 244.8402,-181.9259 250.5545,-173.0041 243.7436,-171.3879"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="280.348,-1320 280.348,-1352 394.348,-1352 394.348,-1320 280.348,-1320"/>
|
||||
<text text-anchor="start" x="323.456" y="-1333" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="280.348,-1168 280.348,-1320 394.348,-1320 394.348,-1168 280.348,-1168"/>
|
||||
<text text-anchor="start" x="312.0665" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="318.171" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="327.345" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="290.111" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="325.1255" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="305.948" y="-1229" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="309.288" y="-1217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="312.8925" y="-1205" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="311.232" y="-1193" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="323.46" y="-1181" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="280.348,-1040 280.348,-1168 394.348,-1168 394.348,-1040 280.348,-1040"/>
|
||||
<text text-anchor="start" x="294.8405" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="296.7805" y="-1137" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="302.6245" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="290.6765" y="-1113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="292.6215" y="-1101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="301.7885" y="-1089" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="317.902" y="-1065" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="322.3505" y="-1053" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A9->A2 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A9->A2</title>
|
||||
<path fill="none" stroke="#000000" d="M355.8061,-1029.6429C357.5037,-1016.2527 359.0593,-1002.9144 360.348,-990 373.4702,-858.5013 377.9848,-704.3277 382.1955,-616.0127"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="354.4823,-1039.8864 351.3012,-1029.3921 355.1232,-1034.9276 355.764,-1029.9689 355.764,-1029.9689 355.764,-1029.9689 355.1232,-1034.9276 360.2269,-1030.5457 354.4823,-1039.8864 354.4823,-1039.8864"/>
|
||||
<text text-anchor="middle" x="348.4228" y="-1017.8264" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A9->A2 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A9->A2</title>
|
||||
<path fill="none" stroke="#000000" d="M373.7566,-1029.6429C375.5037,-1016.2527 377.0593,-1002.9144 378.348,-990 390.8936,-864.2801 395.5714,-717.8344 394.9909,-628.0298"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="372.3845,-1039.8864 369.2521,-1029.3774 373.0484,-1034.9307 373.7122,-1029.9749 373.7122,-1029.9749 373.7122,-1029.9749 373.0484,-1034.9307 378.1724,-1030.5724 372.3845,-1039.8864 372.3845,-1039.8864"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="394.9908,-628.0122 390.9345,-622.0501 394.8778,-616.0127 398.9341,-621.9747 394.9908,-628.0122"/>
|
||||
<text text-anchor="middle" x="403.5004" y="-631.0585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
</g>
|
||||
<!-- A9->A4 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A9->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M286.0331,-1039.9349C281.6793,-1026.6936 277.2605,-1013.2547 272.8698,-999.9011"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="269.679,-990.1968 277.0774,-998.2908 271.2408,-994.9466 272.8026,-999.6964 272.8026,-999.6964 272.8026,-999.6964 271.2408,-994.9466 268.5277,-1001.102 269.679,-990.1968 269.679,-990.1968"/>
|
||||
<text text-anchor="middle" x="272.3419" y="-1022.3558" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="293.348,-844 293.348,-876 360.348,-876 360.348,-844 293.348,-844"/>
|
||||
<text text-anchor="start" x="309.341" y="-857" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="293.348,-824 293.348,-844 360.348,-844 360.348,-824 293.348,-824"/>
|
||||
<polygon fill="none" stroke="#000000" points="293.348,-780 293.348,-824 360.348,-824 360.348,-780 293.348,-780"/>
|
||||
<text text-anchor="start" x="303.232" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="311.016" y="-793" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A9->A12 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A9->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M332.683,-1039.9349C331.0582,-985.577 329.3338,-927.8888 328.095,-886.4463"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="327.7909,-876.272 332.5878,-886.1331 327.9404,-881.2698 328.0898,-886.2676 328.0898,-886.2676 328.0898,-886.2676 327.9404,-881.2698 323.5918,-886.4021 327.7909,-876.272 327.7909,-876.272"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="50.348,-1284 50.348,-1316 141.348,-1316 141.348,-1284 50.348,-1284"/>
|
||||
<text text-anchor="start" x="68.343" y="-1297" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="50.348,-1144 50.348,-1284 141.348,-1284 141.348,-1144 50.348,-1144"/>
|
||||
<text text-anchor="start" x="70.5665" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="76.671" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="85.845" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="80.846" y="-1217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="83.9055" y="-1205" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="88.904" y="-1193" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="68.058" y="-1181" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="69.732" y="-1169" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="81.96" y="-1157" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="50.348,-1076 50.348,-1144 141.348,-1144 141.348,-1076 50.348,-1076"/>
|
||||
<text text-anchor="start" x="60.2885" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="76.402" y="-1101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="80.8505" y="-1089" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A10->A3 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A10->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M63.2254,-1066.0442C59.4271,-1040.8951 56.2542,-1014.6889 54.348,-990 37.0619,-766.107 47.322,-500.0139 57.5568,-374.449"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="64.7695,-1075.9973 58.7895,-1066.8055 64.0029,-1071.0565 63.2364,-1066.1156 63.2364,-1066.1156 63.2364,-1066.1156 64.0029,-1071.0565 67.6832,-1065.4256 64.7695,-1075.9973 64.7695,-1075.9973"/>
|
||||
<text text-anchor="middle" x="53.6382" y="-1056.3813" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote</text>
|
||||
</g>
|
||||
<!-- A10->A3 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A10->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M80.8817,-1066.0442C77.4271,-1040.8951 74.2542,-1014.6889 72.348,-990 55.6021,-773.1036 64.7076,-516.6035 68.1168,-386.6269"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="82.2701,-1075.9973 76.4317,-1066.7149 81.5793,-1071.0453 80.8885,-1066.0932 80.8885,-1066.0932 80.8885,-1066.0932 81.5793,-1071.0453 85.3454,-1065.4715 82.2701,-1075.9973 82.2701,-1075.9973"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="68.1213,-386.4451 64.2759,-380.3449 68.4278,-374.449 72.2733,-380.5493 68.1213,-386.4451"/>
|
||||
<text text-anchor="middle" x="76.4146" y="-389.7851" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local</text>
|
||||
</g>
|
||||
<!-- A10->A4 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A10->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M134.8842,-1075.7577C142.8622,-1051.494 151.3952,-1025.5424 159.8248,-999.9053"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="163.0491,-990.0992 164.2003,-1001.0045 161.4873,-994.849 159.9255,-999.5989 159.9255,-999.5989 159.9255,-999.5989 161.4873,-994.849 155.6506,-998.1932 163.0491,-990.0992 163.0491,-990.0992"/>
|
||||
<text text-anchor="middle" x="132.5165" y="-1052.8983" 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="73.348,-844 73.348,-876 140.348,-876 140.348,-844 73.348,-844"/>
|
||||
<text text-anchor="start" x="86.0065" y="-857" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="73.348,-824 73.348,-844 140.348,-844 140.348,-824 73.348,-824"/>
|
||||
<polygon fill="none" stroke="#000000" points="73.348,-780 73.348,-824 140.348,-824 140.348,-780 73.348,-780"/>
|
||||
<text text-anchor="start" x="83.232" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="91.016" y="-793" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A10->A13 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A10->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M98.9422,-1075.7577C100.842,-1012.1995 103.0881,-937.0598 104.6045,-886.3285"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="104.9072,-876.2026 109.1063,-886.3326 104.7577,-881.2004 104.6083,-886.1981 104.6083,-886.1981 104.6083,-886.1981 104.7577,-881.2004 100.1103,-886.0636 104.9072,-876.2026 104.9072,-876.2026"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="159.348,-1284 159.348,-1316 262.348,-1316 262.348,-1284 159.348,-1284"/>
|
||||
<text text-anchor="start" x="200.01" y="-1297" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="159.348,-1228 159.348,-1284 262.348,-1284 262.348,-1228 159.348,-1228"/>
|
||||
<text text-anchor="start" x="202.7895" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="178.334" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="191.9515" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="159.348,-1076 159.348,-1228 262.348,-1228 262.348,-1076 159.348,-1076"/>
|
||||
<text text-anchor="start" x="186.6835" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="184.7325" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="181.6785" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="180.0085" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="178.058" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="193.061" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="185.842" y="-1137" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="187.2225" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="171.385" y="-1113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="180.8335" y="-1101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="169.1705" y="-1089" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A11->A12 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A11->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M258.9382,-1066.3836C267.808,-1041.1849 276.6736,-1014.8736 284.348,-990 296.0407,-952.103 307.205,-908.562 315.0802,-876.1703"/>
|
||||
<polygon fill="none" stroke="#000000" points="255.5783,-1065.3868 255.541,-1075.9815 262.1771,-1067.7225 255.5783,-1065.3868"/>
|
||||
</g>
|
||||
<!-- A11->A13 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A11->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M170.4636,-1066.2454C162.9411,-1041.0063 155.2684,-1014.7156 148.348,-990 137.6936,-951.9489 126.506,-908.6064 118.3587,-876.3336"/>
|
||||
<polygon fill="none" stroke="#000000" points="167.1205,-1067.2825 173.3374,-1075.8616 173.8274,-1065.2781 167.1205,-1067.2825"/>
|
||||
</g>
|
||||
<!-- A14->A9 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>A14->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M207.7336,-1465.2507C227.8317,-1432.1375 252.0435,-1390.492 271.348,-1352 274.3143,-1346.0855 277.269,-1340.0055 280.1912,-1333.8349"/>
|
||||
<polygon fill="none" stroke="#000000" points="204.6683,-1463.555 202.4506,-1473.9151 210.6449,-1467.1992 204.6683,-1463.555"/>
|
||||
</g>
|
||||
<!-- A14->A10 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>A14->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M154.3052,-1464.1339C145.0994,-1422.2665 132.7762,-1366.2214 121.7769,-1316.197"/>
|
||||
<polygon fill="none" stroke="#000000" points="150.8909,-1464.9045 156.4568,-1473.9196 157.7276,-1463.4012 150.8909,-1464.9045"/>
|
||||
</g>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="263.348,-1622 263.348,-1654 338.348,-1654 338.348,-1622 263.348,-1622"/>
|
||||
<text text-anchor="start" x="283.0655" y="-1635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="263.348,-1470 263.348,-1622 338.348,-1622 338.348,-1470 263.348,-1470"/>
|
||||
<text text-anchor="start" x="292.5095" y="-1603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="273.338" y="-1579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="274.453" y="-1567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="284.4565" y="-1555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="274.7375" y="-1543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="282.79" y="-1531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="294.7395" y="-1519" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="281.4015" y="-1507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="279.727" y="-1495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="294.1845" y="-1483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="263.348,-1402 263.348,-1470 338.348,-1470 338.348,-1402 263.348,-1402"/>
|
||||
<text text-anchor="start" x="274.738" y="-1451" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="278.072" y="-1439" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="275.572" y="-1427" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="285.8505" y="-1415" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A15->A9 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>A15->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M315.5861,-1391.2689C317.0212,-1378.3918 318.4833,-1365.272 319.9365,-1352.2329"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="314.4417,-1401.5379 311.077,-1391.101 314.9955,-1396.5687 315.5493,-1391.5995 315.5493,-1391.5995 315.5493,-1391.5995 314.9955,-1396.5687 320.0217,-1392.0979 314.4417,-1401.5379 314.4417,-1401.5379"/>
|
||||
<text text-anchor="middle" x="326.3292" y="-1368.1837" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="308.049" y="-1379.5871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A15->A10 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>A15->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M257.1725,-1451.7757C245.6828,-1434.4941 232.4915,-1416.871 218.348,-1402 192.2483,-1374.5578 171.9188,-1382.411 149.348,-1352 141.2346,-1341.0684 134.273,-1328.8227 128.315,-1316.1269"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="262.6729,-1460.2184 253.4437,-1454.2962 259.9435,-1456.0291 257.2141,-1451.8397 257.2141,-1451.8397 257.2141,-1451.8397 259.9435,-1456.0291 260.9845,-1449.3833 262.6729,-1460.2184 262.6729,-1460.2184"/>
|
||||
<text text-anchor="middle" x="143.7688" y="-1325.8225" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="245.6964" y="-1446.645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 37 KiB |
49
app/proxy_2.yuml
Normal file
49
app/proxy_2.yuml
Normal file
@@ -0,0 +1,49 @@
|
||||
// {type:class}
|
||||
// {direction:topDown}
|
||||
// {generate:true}
|
||||
|
||||
[note: You can stick notes on diagrams too!{bg:cornsilk}]
|
||||
[IterRegistry||__iter__]
|
||||
|
||||
[InverterG3|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
[InverterG3P|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
|
||||
[<<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()]
|
||||
[AsyncStreamServer|create_remote|<async>server_loop();<async>_async_forward();<async>publish_outstanding_mqtt();close()]
|
||||
[AsyncStreamClient||<async>client_loop();<async>_async_forward())]
|
||||
[<<AsyncIfc>>]^-.-[AsyncIfcImpl]
|
||||
[AsyncIfcImpl]^[AsyncStream]
|
||||
[AsyncStream]^[AsyncStreamServer]
|
||||
[AsyncStream]^[AsyncStreamClient]
|
||||
|
||||
|
||||
[Talent|ifc:AsyncIfc;conn_no;addr;;await_conn_resp_cnt;id_str;contact_name;contact_mail;db:InfosG3;mb:Modbus;switch|msg_contact_info();msg_ota_update();msg_get_time();msg_collector_data();msg_inverter_data();msg_unknown();;healthy();close()]
|
||||
[Talent]<remote-[InverterG3]
|
||||
[InverterG3]-remote>[AsyncStreamClient]
|
||||
[Talent]<-local++[InverterG3]
|
||||
[InverterG3]++local->[AsyncStreamServer]
|
||||
|
||||
[SolarmanV5|ifc:AsyncIfc;conn_no;addr;;control;serial;snr;db:InfosG3P;mb:Modbus;switch|msg_unknown();;healthy();close()]
|
||||
[SolarmanV5]<remote-[InverterG3P]
|
||||
[InverterG3P]-remote>[AsyncStreamClient]
|
||||
[SolarmanV5]<-local++[InverterG3P]
|
||||
[InverterG3P]++local->[AsyncStreamServer]
|
||||
|
||||
[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]^[InfosG3||ha_confs();parse()]
|
||||
[Infos]^[InfosG3P||ha_confs();parse()]
|
||||
|
||||
[Talent]use->[<<AsyncIfc>>]
|
||||
[Talent]->[InfosG3]
|
||||
[SolarmanV5]use->[<<AsyncIfc>>]
|
||||
[SolarmanV5]->[InfosG3P]
|
||||
|
||||
[IterRegistry]^[Message|node_id|inc_counter();dec_counter()]
|
||||
[Message]^[Talent]
|
||||
[Message]^[SolarmanV5]
|
||||
|
||||
[Modbus|que;;snd_handler;rsp_handler;timeout;max_retires;last_xxx;err;retry_cnt;req_pend;tim|build_msg();recv_req();recv_resp();close()]
|
||||
[Modbus]<1-has[SolarmanV5]
|
||||
[Modbus]<1-has[Talent]
|
||||
@@ -56,21 +56,11 @@ class AsyncIfc(ABC):
|
||||
''' add data to forward queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def fwd_flush(self):
|
||||
''' send forward queue and clears it'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def fwd_log(self, level, info):
|
||||
''' log the forward queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def fwd_clear(self):
|
||||
''' clear forward queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
#
|
||||
# RX - QUEUE
|
||||
#
|
||||
|
||||
@@ -7,12 +7,12 @@ from typing import Self
|
||||
from itertools import count
|
||||
|
||||
if __name__ == "app.src.async_stream":
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.byte_fifo import ByteFifo
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from inverter import Inverter
|
||||
from proxy import Proxy
|
||||
from byte_fifo import ByteFifo
|
||||
from async_ifc import AsyncIfc
|
||||
from infos import Infos
|
||||
@@ -80,18 +80,10 @@ class AsyncIfcImpl(AsyncIfc):
|
||||
''' add data to forward queue'''
|
||||
self.fwd_fifo += data
|
||||
|
||||
def fwd_flush(self):
|
||||
''' send forward queue and clears it'''
|
||||
self.fwd_fifo()
|
||||
|
||||
def fwd_log(self, level, info):
|
||||
''' log the forward queue'''
|
||||
self.fwd_fifo.logging(level, info)
|
||||
|
||||
def fwd_clear(self):
|
||||
''' clear forward queue'''
|
||||
self.fwd_fifo.clear()
|
||||
|
||||
def rx_get(self, size: int = None) -> bytearray:
|
||||
'''removes size numbers of bytes and return them'''
|
||||
return self.rx_fifo.get(size)
|
||||
@@ -127,13 +119,18 @@ class AsyncIfcImpl(AsyncIfc):
|
||||
|
||||
class StreamPtr():
|
||||
'''Descr StreamPtr'''
|
||||
def __init__(self, _stream):
|
||||
def __init__(self, _stream, _ifc=None):
|
||||
self.stream = _stream
|
||||
self.ifc = _ifc
|
||||
|
||||
@property
|
||||
def ifc(self):
|
||||
return self._ifc
|
||||
|
||||
@ifc.setter
|
||||
def ifc(self, value):
|
||||
self._ifc = value
|
||||
|
||||
@property
|
||||
def stream(self):
|
||||
return self._stream
|
||||
@@ -141,10 +138,6 @@ class StreamPtr():
|
||||
@stream.setter
|
||||
def stream(self, value):
|
||||
self._stream = value
|
||||
if value:
|
||||
self._ifc = value.ifc
|
||||
else:
|
||||
self._ifc = None
|
||||
|
||||
|
||||
class AsyncStream(AsyncIfcImpl):
|
||||
@@ -177,8 +170,8 @@ class AsyncStream(AsyncIfcImpl):
|
||||
self._writer.write(self.tx_fifo.get())
|
||||
|
||||
def __timeout(self) -> int:
|
||||
if self.timeout_cb is callable:
|
||||
return self.timeout_cb
|
||||
if self.timeout_cb:
|
||||
return self.timeout_cb()
|
||||
return 360
|
||||
|
||||
async def loop(self) -> Self:
|
||||
@@ -186,10 +179,7 @@ class AsyncStream(AsyncIfcImpl):
|
||||
self.proc_start = time.time()
|
||||
while True:
|
||||
try:
|
||||
proc = time.time() - self.proc_start
|
||||
if proc > self.proc_max:
|
||||
self.proc_max = proc
|
||||
self.proc_start = None
|
||||
self.__calc_proc_time()
|
||||
dead_conn_to = self.__timeout()
|
||||
await asyncio.wait_for(self.__async_read(),
|
||||
dead_conn_to)
|
||||
@@ -204,7 +194,6 @@ class AsyncStream(AsyncIfcImpl):
|
||||
f'connection timeout ({dead_conn_to}s) '
|
||||
f'for {self.l_addr}')
|
||||
await self.disc()
|
||||
self.close()
|
||||
return self
|
||||
|
||||
except OSError as error:
|
||||
@@ -212,14 +201,12 @@ class AsyncStream(AsyncIfcImpl):
|
||||
f'{error} for l{self.l_addr} | '
|
||||
f'r{self.r_addr}')
|
||||
await self.disc()
|
||||
self.close()
|
||||
return self
|
||||
|
||||
except RuntimeError as error:
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
f'{error} for {self.l_addr}')
|
||||
await self.disc()
|
||||
self.close()
|
||||
return self
|
||||
|
||||
except Exception:
|
||||
@@ -229,8 +216,16 @@ class AsyncStream(AsyncIfcImpl):
|
||||
f"{traceback.format_exc()}")
|
||||
await asyncio.sleep(0) # be cooperative to other task
|
||||
|
||||
def __calc_proc_time(self):
|
||||
if self.proc_start:
|
||||
proc = time.time() - self.proc_start
|
||||
if proc > self.proc_max:
|
||||
self.proc_max = proc
|
||||
self.proc_start = None
|
||||
|
||||
async def disc(self) -> None:
|
||||
"""Async disc handler for graceful disconnect"""
|
||||
self.remote = None
|
||||
if self._writer.is_closing():
|
||||
return
|
||||
logger.debug(f'AsyncStream.disc() l{self.l_addr} | r{self.r_addr}')
|
||||
@@ -238,6 +233,7 @@ class AsyncStream(AsyncIfcImpl):
|
||||
await self._writer.wait_closed()
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'AsyncStream.close() l{self.l_addr} | r{self.r_addr}')
|
||||
"""close handler for a no waiting disconnect
|
||||
|
||||
hint: must be called before releasing the connection instance
|
||||
@@ -246,7 +242,6 @@ class AsyncStream(AsyncIfcImpl):
|
||||
self._reader.feed_eof() # abort awaited read
|
||||
if self._writer.is_closing():
|
||||
return
|
||||
logger.debug(f'AsyncStream.close() l{self.l_addr} | r{self.r_addr}')
|
||||
self._writer.close()
|
||||
|
||||
def healthy(self) -> bool:
|
||||
@@ -271,7 +266,7 @@ class AsyncStream(AsyncIfcImpl):
|
||||
self.proc_start = time.time()
|
||||
self.rx_fifo += data
|
||||
wait = self.rx_fifo() # call read in parent class
|
||||
if wait > 0:
|
||||
if wait and wait > 0:
|
||||
await asyncio.sleep(wait)
|
||||
else:
|
||||
raise RuntimeError("Peer closed.")
|
||||
@@ -292,21 +287,22 @@ class AsyncStream(AsyncIfcImpl):
|
||||
|
||||
except OSError as error:
|
||||
if self.remote.stream:
|
||||
rmt = self.remote.stream
|
||||
self.remote.stream = None
|
||||
logger.error(f'[{rmt.node_id}:{rmt.conn_no}] Fwd: {error} for '
|
||||
f'l{rmt._ifc.l_addr} | r{rmt._ifc.r_addr}')
|
||||
await rmt._ifc.disc()
|
||||
rmt._ifc.close()
|
||||
rmt = self.remote
|
||||
logger.error(f'[{rmt.stream.node_id}:{rmt.stream.conn_no}] '
|
||||
f'Fwd: {error} for '
|
||||
f'l{rmt.ifc.l_addr} | r{rmt.ifc.r_addr}')
|
||||
await rmt.ifc.disc()
|
||||
if rmt.ifc.close_cb:
|
||||
rmt.ifc.close_cb()
|
||||
|
||||
except RuntimeError as error:
|
||||
if self.remote.stream:
|
||||
rmt = self.remote.stream
|
||||
self.remote.stream = None
|
||||
logger.info(f'[{rmt.node_id}:{rmt.conn_no}] '
|
||||
f'Fwd: {error} for {rmt._ifc.l_addr}')
|
||||
await rmt._ifc.disc()
|
||||
rmt._ifc.close()
|
||||
rmt = self.remote
|
||||
logger.info(f'[{rmt.stream.node_id}:{rmt.stream.conn_no}] '
|
||||
f'Fwd: {error} for {rmt.ifc.l_addr}')
|
||||
await rmt.ifc.disc()
|
||||
if rmt.ifc.close_cb:
|
||||
rmt.ifc.close_cb()
|
||||
|
||||
except Exception:
|
||||
Infos.inc_counter('SW_Exception')
|
||||
@@ -315,18 +311,24 @@ class AsyncStream(AsyncIfcImpl):
|
||||
f"{traceback.format_exc()}")
|
||||
|
||||
def __del__(self):
|
||||
logger.debug(
|
||||
logger.info(
|
||||
f"AsyncStream.__del__ l{self.l_addr} | r{self.r_addr}")
|
||||
|
||||
|
||||
class AsyncStreamServer(AsyncStream):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
async_publ_mqtt, async_create_remote,
|
||||
async_publ_mqtt, create_remote,
|
||||
rstream: "StreamPtr") -> None:
|
||||
AsyncStream.__init__(self, reader, writer, rstream)
|
||||
self.async_create_remote = async_create_remote
|
||||
self.create_remote = create_remote
|
||||
self.async_publ_mqtt = async_publ_mqtt
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug('AsyncStreamServer.close()')
|
||||
self.create_remote = None
|
||||
self.async_publ_mqtt = None
|
||||
super().close()
|
||||
|
||||
async def server_loop(self) -> None:
|
||||
'''Loop for receiving messages from the inverter (server-side)'''
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
@@ -341,7 +343,7 @@ class AsyncStreamServer(AsyncStream):
|
||||
|
||||
# if the server connection closes, we also have to disconnect
|
||||
# the connection to te TSUN cloud
|
||||
if self.remote.stream:
|
||||
if self.remote and self.remote.stream:
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] disc client '
|
||||
f'connection: [{self.remote.ifc.node_id}:'
|
||||
f'{self.remote.ifc.conn_no}]')
|
||||
@@ -350,7 +352,7 @@ class AsyncStreamServer(AsyncStream):
|
||||
async def _async_forward(self) -> None:
|
||||
"""forward handler transmits data over the remote connection"""
|
||||
if not self.remote.stream:
|
||||
await self.async_create_remote()
|
||||
await self.create_remote()
|
||||
if self.remote.stream and \
|
||||
self.remote.ifc.init_new_client_conn_cb():
|
||||
await self.remote.ifc._AsyncStream__async_write()
|
||||
@@ -365,24 +367,21 @@ class AsyncStreamServer(AsyncStream):
|
||||
'''Publish all outstanding MQTT topics'''
|
||||
try:
|
||||
await self.async_publ_mqtt()
|
||||
await Inverter._async_publ_mqtt_proxy_stat('proxy')
|
||||
await Proxy._async_publ_mqtt_proxy_stat('proxy')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def close(self) -> None:
|
||||
"""close handler for a no waiting disconnect
|
||||
|
||||
hint: must be called before releasing the connection instance
|
||||
"""
|
||||
self.async_create_remote = None
|
||||
self.async_publ_mqtt = None
|
||||
super().close()
|
||||
|
||||
|
||||
class AsyncStreamClient(AsyncStream):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
rstream: "StreamPtr") -> None:
|
||||
rstream: "StreamPtr", close_cb) -> None:
|
||||
AsyncStream.__init__(self, reader, writer, rstream)
|
||||
self.close_cb = close_cb
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug('AsyncStreamClient.close()')
|
||||
self.close_cb = None
|
||||
super().close()
|
||||
|
||||
async def client_loop(self, _: str) -> None:
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
@@ -391,21 +390,8 @@ class AsyncStreamClient(AsyncStream):
|
||||
'Client loop stopped for'
|
||||
f' l{self.l_addr}')
|
||||
|
||||
server_stream = self.remote.stream
|
||||
|
||||
# if the client connection closes, we don't touch the server
|
||||
# connection. Instead we erase the client connection stream,
|
||||
# thus on the next received packet from the inverter, we can
|
||||
# establish a new connection to the TSUN cloud
|
||||
|
||||
if server_stream.remote.ifc == self:
|
||||
# logging.debug(f'Client l{client_stream.l_addr} refs:'
|
||||
# f' {gc.get_referrers(client_stream)}')
|
||||
# than erase client connection
|
||||
server_stream.remote.stream = None # erases stream and ifc link
|
||||
|
||||
# erase backlink to inverter
|
||||
self.remote.stream = None
|
||||
if self.close_cb:
|
||||
self.close_cb()
|
||||
|
||||
async def _async_forward(self) -> None:
|
||||
"""forward handler transmits data over the remote connection"""
|
||||
|
||||
@@ -18,10 +18,11 @@ class ByteFifo:
|
||||
self.__buf.extend(data)
|
||||
return self
|
||||
|
||||
def __call__(self) -> None:
|
||||
def __call__(self):
|
||||
'''triggers the observer'''
|
||||
if callable(self.__trigger_cb):
|
||||
return self.__trigger_cb()
|
||||
return None
|
||||
|
||||
def get(self, size: int = None) -> bytearray:
|
||||
'''removes size numbers of byte and return them'''
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import logging
|
||||
|
||||
if __name__ == "app.src.gen3.connection_g3":
|
||||
from app.src.gen3.talent import Talent
|
||||
else: # pragma: no cover
|
||||
from gen3.talent import Talent
|
||||
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
|
||||
class ConnectionG3(Talent):
|
||||
def __init__(self, addr, ifc, server_side, id_str=b'') -> None:
|
||||
super().__init__(addr, server_side, ifc, id_str)
|
||||
|
||||
def close(self):
|
||||
super().close()
|
||||
@@ -1,41 +1,13 @@
|
||||
import logging
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.gen3.inverter_g3":
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.async_stream import StreamPtr
|
||||
from app.src.async_stream import AsyncStreamServer
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.gen3.talent import Talent
|
||||
else: # pragma: no cover
|
||||
from inverter_base import InverterBase
|
||||
from async_stream import StreamPtr
|
||||
from async_stream import AsyncStreamServer
|
||||
from gen3.connection_g3 import ConnectionG3
|
||||
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
from gen3.talent import Talent
|
||||
|
||||
|
||||
class InverterG3(InverterBase):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter, addr):
|
||||
super().__init__()
|
||||
self.addr = addr
|
||||
self.remote = StreamPtr(None)
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
self.async_publ_mqtt,
|
||||
self.async_create_remote,
|
||||
self.remote)
|
||||
|
||||
self.remote = StreamPtr(None)
|
||||
self.local = StreamPtr(
|
||||
ConnectionG3(addr, ifc, True)
|
||||
)
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
await InverterBase.async_create_remote(
|
||||
self, 'tsun', ConnectionG3)
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'InverterG3.close() {self.addr}')
|
||||
self.local.stream.close()
|
||||
# logging.info(f'Inverter refs: {gc.get_referrers(self)}')
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter):
|
||||
super().__init__(reader, writer, 'tsun', Talent)
|
||||
|
||||
@@ -46,7 +46,8 @@ class Talent(Message):
|
||||
MB_REGULAR_TIMEOUT = 60
|
||||
TXT_UNKNOWN_CTRL = 'Unknown Ctrl'
|
||||
|
||||
def __init__(self, addr, server_side: bool, ifc: "AsyncIfc", id_str=b''):
|
||||
def __init__(self, addr, ifc: "AsyncIfc", server_side: bool,
|
||||
client_mode: bool = False, id_str=b''):
|
||||
super().__init__(server_side, self.send_modbus_cb, mb_timeout=15)
|
||||
ifc.rx_set_cb(self.read)
|
||||
ifc.prot_set_timeout_cb(self._timeout)
|
||||
@@ -95,10 +96,6 @@ class Talent(Message):
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('Talent healthy()')
|
||||
return self.ifc.healthy()
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug('Talent.close()')
|
||||
if self.server_side:
|
||||
@@ -116,11 +113,11 @@ class Talent(Message):
|
||||
self.log_lvl.clear()
|
||||
self.state = State.closed
|
||||
self.mb_timer.close()
|
||||
self.ifc.close()
|
||||
self.ifc.rx_set_cb(None)
|
||||
self.ifc.prot_set_timeout_cb(None)
|
||||
self.ifc.prot_set_init_new_client_conn_cb(None)
|
||||
self.ifc.prot_set_update_header_cb(None)
|
||||
self.ifc = None
|
||||
super().close()
|
||||
|
||||
def __set_serial_no(self, serial_no: str):
|
||||
@@ -438,8 +435,8 @@ class Talent(Message):
|
||||
result = struct.unpack_from('!q', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
self.ts_offset = result[0]-ts
|
||||
if self.remote.stream:
|
||||
self.remote.stream.ts_offset = self.ts_offset
|
||||
if self.ifc.remote.stream:
|
||||
self.ifc.remote.stream.ts_offset = self.ts_offset
|
||||
logger.debug(f'tsun-time: {int(result[0]):08x}'
|
||||
f' proxy-time: {ts:08x}'
|
||||
f' offset: {self.ts_offset}')
|
||||
@@ -597,9 +594,8 @@ class Talent(Message):
|
||||
self.header_len+self.data_len]
|
||||
|
||||
if self.ctrl.is_req():
|
||||
if self.remote.stream.mb.recv_req(data[hdr_len:],
|
||||
self.remote.stream.
|
||||
msg_forward):
|
||||
rstream = self.ifc.remote.stream
|
||||
if rstream.mb.recv_req(data[hdr_len:], rstream.msg_forward):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import logging
|
||||
|
||||
if __name__ == "app.src.gen3plus.connection_g3p":
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
else: # pragma: no cover
|
||||
from gen3plus.solarman_v5 import SolarmanV5
|
||||
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
|
||||
class ConnectionG3P(SolarmanV5):
|
||||
def __init__(self, addr, ifc, server_side,
|
||||
client_mode: bool = False) -> None:
|
||||
super().__init__(addr, server_side, client_mode, ifc)
|
||||
|
||||
def close(self):
|
||||
super().close()
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
@@ -1,41 +1,15 @@
|
||||
import logging
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.gen3plus.inverter_g3p":
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.async_stream import StreamPtr
|
||||
from app.src.async_stream import AsyncStreamServer
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
else: # pragma: no cover
|
||||
from inverter_base import InverterBase
|
||||
from async_stream import StreamPtr
|
||||
from async_stream import AsyncStreamServer
|
||||
from gen3plus.connection_g3p import ConnectionG3P
|
||||
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
from gen3plus.solarman_v5 import SolarmanV5
|
||||
|
||||
|
||||
class InverterG3P(InverterBase):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter, addr,
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
client_mode: bool = False):
|
||||
super().__init__()
|
||||
self.addr = addr
|
||||
self.remote = StreamPtr(None)
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
self.async_publ_mqtt,
|
||||
self.async_create_remote,
|
||||
self.remote)
|
||||
|
||||
self.local = StreamPtr(
|
||||
ConnectionG3P(addr, ifc, True, client_mode)
|
||||
)
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
await InverterBase.async_create_remote(
|
||||
self, 'solarman', ConnectionG3P)
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'InverterG3P.close() {self.addr}')
|
||||
self.local.stream.close()
|
||||
# logger.debug (f'Inverter refs: {gc.get_referrers(self)}')
|
||||
super().__init__(reader, writer, 'solarman',
|
||||
SolarmanV5, client_mode)
|
||||
|
||||
@@ -62,8 +62,8 @@ class SolarmanV5(Message):
|
||||
HDR_FMT = '<BLLL'
|
||||
'''format string for packing of the header'''
|
||||
|
||||
def __init__(self, addr, server_side: bool, client_mode: bool,
|
||||
ifc: "AsyncIfc"):
|
||||
def __init__(self, addr, ifc: "AsyncIfc",
|
||||
server_side: bool, client_mode: bool):
|
||||
super().__init__(server_side, self.send_modbus_cb, mb_timeout=8)
|
||||
ifc.rx_set_cb(self.read)
|
||||
ifc.prot_set_timeout_cb(self._timeout)
|
||||
@@ -155,10 +155,6 @@ class SolarmanV5(Message):
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('SolarmanV5 healthy()')
|
||||
return self.ifc.healthy()
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug('Solarman.close()')
|
||||
if self.server_side:
|
||||
@@ -176,11 +172,11 @@ class SolarmanV5(Message):
|
||||
self.log_lvl.clear()
|
||||
self.state = State.closed
|
||||
self.mb_timer.close()
|
||||
self.ifc.close()
|
||||
self.ifc.rx_set_cb(None)
|
||||
self.ifc.prot_set_timeout_cb(None)
|
||||
self.ifc.prot_set_init_new_client_conn_cb(None)
|
||||
self.ifc.prot_set_update_header_cb(None)
|
||||
self.ifc = None
|
||||
super().close()
|
||||
|
||||
async def send_start_cmd(self, snr: int, host: str,
|
||||
@@ -633,9 +629,9 @@ class SolarmanV5(Message):
|
||||
self.forward_at_cmd_resp = True
|
||||
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
if self.remote.stream.mb.recv_req(data[15:],
|
||||
self.remote.stream.
|
||||
__forward_msg):
|
||||
rstream = self.ifc.remote.stream
|
||||
if rstream.mb.recv_req(data[15:],
|
||||
rstream.__forward_msg):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
logger.error('Invalid Modbus Msg')
|
||||
|
||||
@@ -1,30 +1,99 @@
|
||||
import weakref
|
||||
import asyncio
|
||||
import logging
|
||||
import traceback
|
||||
import json
|
||||
from aiomqtt import MqttCodeError
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.inverter_base":
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.inverter_ifc import InverterIfc
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.async_stream import StreamPtr
|
||||
from app.src.async_stream import AsyncStreamClient
|
||||
from app.src.async_stream import AsyncStreamServer
|
||||
from app.src.config import Config
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from inverter import Inverter
|
||||
from inverter_ifc import InverterIfc
|
||||
from proxy import Proxy
|
||||
from async_stream import StreamPtr
|
||||
from async_stream import AsyncStreamClient
|
||||
from async_stream import AsyncStreamServer
|
||||
from config import Config
|
||||
from infos import Infos
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class InverterBase(Inverter):
|
||||
def __init__(self):
|
||||
self.__ha_restarts = -1
|
||||
class InverterBase(InverterIfc, Proxy):
|
||||
|
||||
async def async_create_remote(self, inv_prot: str, conn_class) -> None:
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
config_id: str, prot_class,
|
||||
client_mode: bool = False):
|
||||
Proxy.__init__(self)
|
||||
self._registry.append(weakref.ref(self))
|
||||
self.addr = writer.get_extra_info('peername')
|
||||
self.config_id = config_id
|
||||
self.prot_class = prot_class
|
||||
self.__ha_restarts = -1
|
||||
self.remote = StreamPtr(None)
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
self.async_publ_mqtt,
|
||||
self.create_remote,
|
||||
self.remote)
|
||||
|
||||
self.local = StreamPtr(
|
||||
self.prot_class(self.addr, ifc, True, client_mode), ifc
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb) -> None:
|
||||
logging.debug(f'InverterBase.__exit__() {self.addr}')
|
||||
self.__del_remote()
|
||||
|
||||
self.local.stream.close()
|
||||
self.local.stream = None
|
||||
self.local.ifc.close()
|
||||
self.local.ifc = None
|
||||
|
||||
def __del__(self) -> None:
|
||||
logging.debug(f'InverterBase.__del__() {self.addr}')
|
||||
|
||||
def __del_remote(self):
|
||||
if self.remote.stream:
|
||||
self.remote.stream.close()
|
||||
self.remote.stream = None
|
||||
|
||||
if self.remote.ifc:
|
||||
self.remote.ifc.close()
|
||||
self.remote.ifc = None
|
||||
|
||||
async def disc(self, shutdown_started=False) -> None:
|
||||
if self.remote.stream:
|
||||
self.remote.stream.shutdown_started = shutdown_started
|
||||
if self.remote.ifc:
|
||||
await self.remote.ifc.disc()
|
||||
if self.local.stream:
|
||||
self.local.stream.shutdown_started = shutdown_started
|
||||
if self.local.ifc:
|
||||
await self.local.ifc.disc()
|
||||
|
||||
def healthy(self) -> bool:
|
||||
logging.debug('InverterBase healthy()')
|
||||
|
||||
if self.local.ifc and not self.local.ifc.healthy():
|
||||
return False
|
||||
if self.remote.ifc and not self.remote.ifc.healthy():
|
||||
return False
|
||||
return True
|
||||
|
||||
async def create_remote(self) -> None:
|
||||
'''Establish a client connection to the TSUN cloud'''
|
||||
tsun = Config.get(inv_prot)
|
||||
|
||||
tsun = Config.get(self.config_id)
|
||||
host = tsun['host']
|
||||
port = tsun['port']
|
||||
addr = (host, port)
|
||||
@@ -34,15 +103,18 @@ class InverterBase(Inverter):
|
||||
logging.info(f'[{stream.node_id}] Connect to {addr}')
|
||||
connect = asyncio.open_connection(host, port)
|
||||
reader, writer = await connect
|
||||
ifc = AsyncStreamClient(reader, writer,
|
||||
self.remote)
|
||||
ifc = AsyncStreamClient(
|
||||
reader, writer, self.local, self.__del_remote)
|
||||
|
||||
self.remote.ifc = ifc
|
||||
if hasattr(stream, 'id_str'):
|
||||
self.remote.stream = conn_class(
|
||||
addr, ifc, False, stream.id_str)
|
||||
self.remote.stream = self.prot_class(
|
||||
addr, ifc, server_side=False,
|
||||
client_mode=False, id_str=stream.id_str)
|
||||
else:
|
||||
self.remote.stream = conn_class(
|
||||
addr, ifc, False)
|
||||
self.remote.stream = self.prot_class(
|
||||
addr, ifc, server_side=False,
|
||||
client_mode=False)
|
||||
|
||||
logging.info(f'[{self.remote.stream.node_id}:'
|
||||
f'{self.remote.stream.conn_no}] '
|
||||
@@ -60,7 +132,7 @@ class InverterBase(Inverter):
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
'''publish data to MQTT broker'''
|
||||
stream = self.local.stream
|
||||
if not stream.unique_id:
|
||||
if not stream or not stream.unique_id:
|
||||
return
|
||||
# check if new inverter or collector infos are available or when the
|
||||
# home assistant has changed the status back to online
|
||||
@@ -76,7 +148,7 @@ class InverterBase(Inverter):
|
||||
for key in stream.new_data:
|
||||
await self.__async_publ_mqtt_packet(stream, key)
|
||||
for key in Infos.new_stat_data:
|
||||
await Inverter._async_publ_mqtt_proxy_stat(key)
|
||||
await Proxy._async_publ_mqtt_proxy_stat(key)
|
||||
|
||||
except MqttCodeError as error:
|
||||
logging.error(f'Mqtt except: {error}')
|
||||
|
||||
40
app/src/inverter_ifc.py
Normal file
40
app/src/inverter_ifc.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from abc import abstractmethod
|
||||
import logging
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.inverter_ifc":
|
||||
from app.src.iter_registry import AbstractIterMeta
|
||||
else: # pragma: no cover
|
||||
from iter_registry import AbstractIterMeta
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class InverterIfc(metaclass=AbstractIterMeta):
|
||||
_registry = []
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
config_id: str, prot_class,
|
||||
client_mode: bool):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def __enter__(self):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def healthy(self) -> bool:
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
async def disc(self, shutdown_started=False) -> None:
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
async def create_remote(self) -> None:
|
||||
pass # pragma: no cover
|
||||
9
app/src/iter_registry.py
Normal file
9
app/src/iter_registry.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class AbstractIterMeta(ABCMeta):
|
||||
def __iter__(cls):
|
||||
for ref in cls._registry:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
yield obj
|
||||
@@ -1,13 +1,15 @@
|
||||
import logging
|
||||
import weakref
|
||||
from typing import Callable, Generator
|
||||
from typing import Callable
|
||||
from enum import Enum
|
||||
|
||||
|
||||
if __name__ == "app.src.messages":
|
||||
from app.src.protocol_ifc import ProtocolIfc
|
||||
from app.src.infos import Infos, Register
|
||||
from app.src.modbus import Modbus
|
||||
else: # pragma: no cover
|
||||
from protocol_ifc import ProtocolIfc
|
||||
from infos import Infos, Register
|
||||
from modbus import Modbus
|
||||
|
||||
@@ -66,14 +68,6 @@ def hex_dump_memory(level, info, data, data_len):
|
||||
tracer.log(level, '\n'.join(lines))
|
||||
|
||||
|
||||
class IterRegistry(type):
|
||||
def __iter__(cls) -> Generator['Message', None, None]:
|
||||
for ref in cls._registry:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
yield obj
|
||||
|
||||
|
||||
class State(Enum):
|
||||
'''state of the logical connection'''
|
||||
init = 0
|
||||
@@ -88,8 +82,7 @@ class State(Enum):
|
||||
'''connection closed'''
|
||||
|
||||
|
||||
class Message(metaclass=IterRegistry):
|
||||
_registry = []
|
||||
class Message(ProtocolIfc):
|
||||
MAX_START_TIME = 400
|
||||
'''maximum time without a received msg in sec'''
|
||||
MAX_INV_IDLE_TIME = 120
|
||||
|
||||
@@ -25,8 +25,9 @@ class ModbusConn():
|
||||
'''Establish a client connection to the TSUN cloud'''
|
||||
connection = asyncio.open_connection(self.host, self.port)
|
||||
reader, writer = await connection
|
||||
self.inverter = InverterG3P(reader, writer, self.addr,
|
||||
self.inverter = InverterG3P(reader, writer,
|
||||
client_mode=True)
|
||||
self.inverter.__enter__()
|
||||
stream = self.inverter.local.stream
|
||||
logging.info(f'[{stream.node_id}:{stream.conn_no}] '
|
||||
f'Connected to {self.addr}')
|
||||
@@ -37,7 +38,7 @@ class ModbusConn():
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
Infos.dec_counter('Inverter_Cnt')
|
||||
await self.inverter.local.ifc.publish_outstanding_mqtt()
|
||||
self.inverter.close()
|
||||
self.inverter.__exit__(exc_type, exc, tb)
|
||||
|
||||
|
||||
class ModbusTcp():
|
||||
|
||||
21
app/src/protocol_ifc.py
Normal file
21
app/src/protocol_ifc.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
if __name__ == "app.src.protocol_ifc":
|
||||
from app.src.iter_registry import AbstractIterMeta
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
else: # pragma: no cover
|
||||
from iter_registry import AbstractIterMeta
|
||||
from async_ifc import AsyncIfc
|
||||
|
||||
|
||||
class ProtocolIfc(metaclass=AbstractIterMeta):
|
||||
_registry = []
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, addr, ifc: "AsyncIfc", server_side: bool,
|
||||
client_mode: bool = False, id_str=b''):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def close(self):
|
||||
pass # pragma: no cover
|
||||
@@ -2,7 +2,7 @@ import asyncio
|
||||
import logging
|
||||
import json
|
||||
|
||||
if __name__ == "app.src.inverter":
|
||||
if __name__ == "app.src.proxy":
|
||||
from app.src.config import Config
|
||||
from app.src.mqtt import Mqtt
|
||||
from app.src.infos import Infos
|
||||
@@ -14,8 +14,8 @@ else: # pragma: no cover
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class Inverter():
|
||||
'''class Inverter is a baseclass
|
||||
class Proxy():
|
||||
'''class Proxy is a baseclass
|
||||
|
||||
The class has some class method for managing common resources like a
|
||||
connection to the MQTT broker or proxy error counter which are common
|
||||
@@ -34,12 +34,12 @@ class Inverter():
|
||||
destroyed
|
||||
|
||||
methods:
|
||||
async_create_remote(): Establish a client connection to the TSUN cloud
|
||||
create_remote(): Establish a client connection to the TSUN cloud
|
||||
async_publ_mqtt(): Publish data to MQTT broker
|
||||
'''
|
||||
@classmethod
|
||||
def class_init(cls) -> None:
|
||||
logging.debug('Inverter.class_init')
|
||||
logging.debug('Proxy.class_init')
|
||||
# initialize the proxy statistics
|
||||
Infos.static_init()
|
||||
cls.db_stat = Infos()
|
||||
@@ -61,7 +61,7 @@ class Inverter():
|
||||
# reset at midnight when you restart the proxy just before
|
||||
# midnight!
|
||||
inverters = Config.get('inverters')
|
||||
# logger.debug(f'Inverters: {inverters}')
|
||||
# logger.debug(f'Proxys: {inverters}')
|
||||
for inv in inverters.values():
|
||||
if (type(inv) is dict):
|
||||
node_id = inv['node_id']
|
||||
@@ -100,7 +100,7 @@ class Inverter():
|
||||
|
||||
@classmethod
|
||||
def class_close(cls, loop) -> None: # pragma: no cover
|
||||
logging.debug('Inverter.class_close')
|
||||
logging.debug('Proxy.class_close')
|
||||
logging.info('Close MQTT Task')
|
||||
loop.run_until_complete(cls.mqtt.close())
|
||||
cls.mqtt = None
|
||||
@@ -5,8 +5,8 @@ import os
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from aiohttp import web
|
||||
from logging import config # noqa F401
|
||||
from messages import Message
|
||||
from inverter import Inverter
|
||||
from proxy import Proxy
|
||||
from inverter_ifc import InverterIfc
|
||||
from gen3.inverter_g3 import InverterG3
|
||||
from gen3plus.inverter_g3p import InverterG3P
|
||||
from scheduler import Schedule
|
||||
@@ -38,9 +38,9 @@ async def healthy(request):
|
||||
|
||||
if proxy_is_up:
|
||||
# logging.info('web reqeust healthy()')
|
||||
for stream in Message:
|
||||
for inverter in InverterIfc:
|
||||
try:
|
||||
res = stream.healthy()
|
||||
res = inverter.healthy()
|
||||
if not res:
|
||||
return web.Response(status=503, text="I have a problem")
|
||||
except Exception as err:
|
||||
@@ -73,8 +73,8 @@ async def webserver(addr, port):
|
||||
async def handle_client(reader: StreamReader, writer: StreamWriter, inv_class):
|
||||
'''Handles a new incoming connection and starts an async loop'''
|
||||
|
||||
addr = writer.get_extra_info('peername')
|
||||
await inv_class(reader, writer, addr).local.ifc.server_loop()
|
||||
with inv_class(reader, writer) as inv:
|
||||
await inv.local.ifc.server_loop()
|
||||
|
||||
|
||||
async def handle_shutdown(web_task):
|
||||
@@ -87,25 +87,13 @@ async def handle_shutdown(web_task):
|
||||
#
|
||||
# first, disc all open TCP connections gracefully
|
||||
#
|
||||
for stream in Message:
|
||||
stream.shutdown_started = True
|
||||
try:
|
||||
await asyncio.wait_for(stream.disc(), 2)
|
||||
except Exception:
|
||||
pass
|
||||
for inverter in InverterIfc:
|
||||
await inverter.disc(True)
|
||||
|
||||
logging.info('Proxy disconnecting done')
|
||||
|
||||
#
|
||||
# second, close all open TCP connections
|
||||
#
|
||||
for stream in Message:
|
||||
stream.close()
|
||||
|
||||
await asyncio.sleep(0.1) # give time for closing
|
||||
logging.info('Proxy closing done')
|
||||
|
||||
#
|
||||
# third, cancel the web server
|
||||
# second, cancel the web server
|
||||
#
|
||||
web_task.cancel()
|
||||
await web_task
|
||||
@@ -164,9 +152,9 @@ if __name__ == "__main__":
|
||||
ConfigErr = Config.class_init()
|
||||
if ConfigErr is not None:
|
||||
logging.info(f'ConfigErr: {ConfigErr}')
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
Schedule.start()
|
||||
mb_tcp = ModbusTcp(loop)
|
||||
ModbusTcp(loop)
|
||||
|
||||
#
|
||||
# Create tasks for our listening servers. These must be tasks! If we call
|
||||
@@ -197,7 +185,7 @@ if __name__ == "__main__":
|
||||
pass
|
||||
finally:
|
||||
logging.info("Event loop is stopped")
|
||||
Inverter.class_close(loop)
|
||||
Proxy.class_close(loop)
|
||||
logging.debug('Close event loop')
|
||||
loop.close()
|
||||
logging.info(f'Finally, exit Server "{serv_name}"')
|
||||
|
||||
292
app/tests/test_async_stream.py
Normal file
292
app/tests/test_async_stream.py
Normal file
@@ -0,0 +1,292 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
import gc
|
||||
import time
|
||||
|
||||
from app.src.infos import Infos
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.async_stream import AsyncStreamServer, AsyncStreamClient
|
||||
|
||||
from app.tests.test_modbus_tcp import FakeReader, FakeWriter
|
||||
from app.tests.test_inverter_base import config_conn, patch_open_connection
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
|
||||
# initialize the proxy statistics
|
||||
Infos.static_init()
|
||||
|
||||
def test_timeout_cb():
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
def timeout():
|
||||
return 13
|
||||
|
||||
ifc = AsyncStreamClient(reader, writer, None, None)
|
||||
assert 360 == ifc._AsyncStream__timeout()
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
assert 13 == ifc._AsyncStream__timeout()
|
||||
ifc.prot_set_timeout_cb(None)
|
||||
assert 360 == ifc._AsyncStream__timeout()
|
||||
|
||||
# call healthy outside the contexter manager (__exit__() was called)
|
||||
assert ifc.healthy()
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
def test_health():
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
ifc = AsyncStreamClient(reader, writer, None, None)
|
||||
ifc.proc_start = time.time()
|
||||
assert ifc.healthy()
|
||||
ifc.proc_start = time.time() -10
|
||||
assert not ifc.healthy()
|
||||
ifc.proc_start = None
|
||||
assert ifc.healthy()
|
||||
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close_cb():
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
cnt = 0
|
||||
def timeout():
|
||||
return 0.1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(reader, writer, None, closed)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.client_loop('')
|
||||
assert cnt == 1
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.client_loop('')
|
||||
assert cnt == 1 # check that the closed method would not be called
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(reader, writer, None, None)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.client_loop('')
|
||||
assert cnt == 0
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_13_BYTES
|
||||
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
|
||||
def app_read():
|
||||
nonlocal ifc
|
||||
ifc.proc_start -= 3
|
||||
return 0.01 # async wait of 0.01
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(reader, writer, None, closed)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
ifc.rx_set_cb(app_read)
|
||||
await ifc.client_loop('')
|
||||
print('End loop')
|
||||
assert ifc.proc_max >= 3
|
||||
assert 13 == ifc.rx_len()
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_13_BYTES
|
||||
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)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
ifc.tx_add(b'test-data-resp')
|
||||
assert 14 == ifc.tx_len()
|
||||
await ifc.client_loop('')
|
||||
print('End loop')
|
||||
assert 13 == ifc.rx_len()
|
||||
assert 0 == ifc.tx_len()
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_publ_mqtt_cb():
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_13_BYTES
|
||||
reader.on_recv.set()
|
||||
writer = FakeWriter()
|
||||
cnt = 0
|
||||
def timeout():
|
||||
return 0.1
|
||||
async def publ_mqtt():
|
||||
nonlocal cnt
|
||||
nonlocal ifc
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamServer(reader, writer, publ_mqtt, None, None)
|
||||
assert ifc.async_publ_mqtt
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.server_loop()
|
||||
assert cnt == 3 # 2 calls in server_loop() and 1 in loop()
|
||||
assert ifc.async_publ_mqtt
|
||||
ifc.close() # clears the closed callback
|
||||
assert not ifc.async_publ_mqtt
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_remote_cb():
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
cnt = 0
|
||||
def timeout():
|
||||
return 0.1
|
||||
async def create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamServer(reader, writer, None, create_remote, None)
|
||||
assert ifc.create_remote
|
||||
await ifc.create_remote()
|
||||
assert cnt == 1
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.server_loop()
|
||||
assert not ifc.create_remote
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sw_exception():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_SW_EXCEPT
|
||||
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)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.client_loop('')
|
||||
print('End loop')
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_os_error():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_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)
|
||||
ifc.prot_set_timeout_cb(timeout)
|
||||
await ifc.client_loop('')
|
||||
print('End loop')
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
@@ -1,100 +0,0 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
|
||||
from itertools import count
|
||||
from mock import patch
|
||||
from app.src.async_stream import StreamPtr
|
||||
from app.src.async_stream import AsyncStream, AsyncStreamServer, AsyncIfcImpl
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.gen3.talent import Talent
|
||||
|
||||
|
||||
class FakeInverter():
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
pass # dummy funcion
|
||||
|
||||
async def async_create_remote(self, inv_prot: str, conn_class) -> None:
|
||||
pass # dummy function
|
||||
|
||||
def __init__ (self):
|
||||
self.remote = StreamPtr(None)
|
||||
self.local = StreamPtr(None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_async_init():
|
||||
with patch.object(AsyncStream, '__init__') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_talent_init():
|
||||
with patch.object(Talent, '__init__') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_healthy():
|
||||
with patch.object(AsyncStream, 'healthy') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_async_close():
|
||||
with patch.object(AsyncStream, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_talent_close():
|
||||
with patch.object(Talent, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
async def read(self, max_len: int):
|
||||
await self.on_recv.wait()
|
||||
return b''
|
||||
def feed_eof(self):
|
||||
return
|
||||
|
||||
|
||||
class FakeWriter():
|
||||
def write(self, buf: bytes):
|
||||
return
|
||||
def get_extra_info(self, sel: str):
|
||||
if sel == 'peername':
|
||||
return 'remote.intern'
|
||||
elif sel == 'sockname':
|
||||
return 'sock:1234'
|
||||
assert False
|
||||
def is_closing(self):
|
||||
return False
|
||||
def close(self):
|
||||
return
|
||||
async def wait_closed(self):
|
||||
return
|
||||
|
||||
|
||||
|
||||
def test_method_calls(patch_healthy, patch_async_close):
|
||||
AsyncIfcImpl._ids = count(5)
|
||||
spy3 = patch_healthy
|
||||
spy4 = patch_async_close
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
id_str = "id_string"
|
||||
addr = ('proxy.local', 10000)
|
||||
inv = FakeInverter()
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
inv.async_publ_mqtt,
|
||||
inv.async_create_remote,
|
||||
inv.remote)
|
||||
|
||||
conn = ConnectionG3(addr, ifc, server_side=True, id_str=id_str)
|
||||
assert 5 == conn.conn_no
|
||||
assert 5 == conn.ifc.get_conn_no()
|
||||
conn.healthy()
|
||||
|
||||
spy3.assert_called_once()
|
||||
|
||||
conn.close()
|
||||
spy4.assert_called_once()
|
||||
@@ -1,105 +0,0 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
|
||||
from itertools import count
|
||||
from mock import patch
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.async_stream import StreamPtr
|
||||
from app.src.async_stream import AsyncStream, AsyncStreamServer, AsyncIfcImpl
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
|
||||
|
||||
class FakeInverter():
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
pass # dummy funcion
|
||||
|
||||
async def async_create_remote(self, inv_prot: str, conn_class) -> None:
|
||||
pass # dummy function
|
||||
|
||||
def __init__ (self):
|
||||
self.remote = StreamPtr(None)
|
||||
self.local = StreamPtr(None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_async_init():
|
||||
with patch.object(AsyncStream, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_solarman_init():
|
||||
with patch.object(SolarmanV5, '__init__') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def module_init():
|
||||
Singleton._instances.clear()
|
||||
yield
|
||||
|
||||
@pytest.fixture
|
||||
def patch_healthy():
|
||||
with patch.object(AsyncStream, 'healthy') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_async_close():
|
||||
with patch.object(AsyncStream, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_solarman_close():
|
||||
with patch.object(SolarmanV5, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
async def read(self, max_len: int):
|
||||
await self.on_recv.wait()
|
||||
return b''
|
||||
def feed_eof(self):
|
||||
return
|
||||
|
||||
|
||||
class FakeWriter():
|
||||
def write(self, buf: bytes):
|
||||
return
|
||||
def get_extra_info(self, sel: str):
|
||||
if sel == 'peername':
|
||||
return 'remote.intern'
|
||||
elif sel == 'sockname':
|
||||
return 'sock:1234'
|
||||
assert False
|
||||
def is_closing(self):
|
||||
return False
|
||||
def close(self):
|
||||
return
|
||||
async def wait_closed(self):
|
||||
return
|
||||
|
||||
|
||||
|
||||
def test_method_calls(patch_healthy, patch_async_close):
|
||||
AsyncIfcImpl._ids = count(5)
|
||||
spy3 = patch_healthy
|
||||
spy4 = patch_async_close
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
addr = ('proxy.local', 10000)
|
||||
inv = FakeInverter()
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
inv.async_publ_mqtt,
|
||||
inv.async_create_remote,
|
||||
inv.remote)
|
||||
conn = ConnectionG3P(addr, ifc, server_side=True, client_mode=False)
|
||||
assert 5 == conn.conn_no
|
||||
assert 5 == conn.ifc.get_conn_no()
|
||||
conn.healthy()
|
||||
|
||||
spy3.assert_called_once()
|
||||
|
||||
conn.close()
|
||||
spy4.assert_called_once()
|
||||
|
||||
304
app/tests/test_inverter_base.py
Normal file
304
app/tests/test_inverter_base.py
Normal file
@@ -0,0 +1,304 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
import gc
|
||||
|
||||
from mock import patch
|
||||
from enum import Enum
|
||||
from app.src.infos import Infos
|
||||
from app.src.config import Config
|
||||
from app.src.gen3.talent import Talent
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.async_stream import AsyncStream, AsyncStreamClient
|
||||
|
||||
from app.tests.test_modbus_tcp import patch_mqtt_err, patch_mqtt_except, test_port, test_hostname
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
|
||||
# initialize the proxy statistics
|
||||
Infos.static_init()
|
||||
|
||||
@pytest.fixture
|
||||
def config_conn():
|
||||
Config.act_config = {
|
||||
'mqtt':{
|
||||
'host': test_hostname,
|
||||
'port': test_port,
|
||||
'user': '',
|
||||
'passwd': ''
|
||||
},
|
||||
'ha':{
|
||||
'auto_conf_prefix': 'homeassistant',
|
||||
'discovery_prefix': 'homeassistant',
|
||||
'entity_prefix': 'tsun',
|
||||
'proxy_node_id': 'test_1',
|
||||
'proxy_unique_id': ''
|
||||
},
|
||||
'tsun':{'enabled': True, 'host': 'test_cloud.local', 'port': 1234}, 'inverters':{'allow_all':True}
|
||||
}
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def module_init():
|
||||
Singleton._instances.clear()
|
||||
yield
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
async def read(self, max_len: int):
|
||||
await self.on_recv.wait()
|
||||
return b''
|
||||
def feed_eof(self):
|
||||
return
|
||||
|
||||
|
||||
class FakeWriter():
|
||||
def write(self, buf: bytes):
|
||||
return
|
||||
def get_extra_info(self, sel: str):
|
||||
if sel == 'peername':
|
||||
return 'remote.intern'
|
||||
elif sel == 'sockname':
|
||||
return 'sock:1234'
|
||||
assert False
|
||||
def is_closing(self):
|
||||
return False
|
||||
def close(self):
|
||||
return
|
||||
async def wait_closed(self):
|
||||
return
|
||||
|
||||
class TestType(Enum):
|
||||
RD_TEST_0_BYTES = 1
|
||||
RD_TEST_TIMEOUT = 2
|
||||
RD_TEST_EXCEPT = 3
|
||||
|
||||
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
|
||||
@pytest.fixture
|
||||
def patch_open_connection():
|
||||
async def new_conn(conn):
|
||||
await asyncio.sleep(0)
|
||||
return FakeReader(), FakeWriter()
|
||||
|
||||
def new_open(host: str, port: int):
|
||||
global test
|
||||
if test == TestType.RD_TEST_TIMEOUT:
|
||||
raise ConnectionRefusedError
|
||||
elif test == TestType.RD_TEST_EXCEPT:
|
||||
raise ValueError("Value cannot be negative") # Compliant
|
||||
return new_conn(None)
|
||||
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_healthy():
|
||||
with patch.object(AsyncStream, 'healthy') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_unhealthy():
|
||||
def new_healthy(self):
|
||||
return False
|
||||
with patch.object(AsyncStream, 'healthy', new_healthy) as conn:
|
||||
yield conn
|
||||
@pytest.fixture
|
||||
def patch_unhealthy_remote():
|
||||
def new_healthy(self):
|
||||
return False
|
||||
with patch.object(AsyncStreamClient, 'healthy', new_healthy) as conn:
|
||||
yield conn
|
||||
|
||||
def test_inverter_iter():
|
||||
InverterBase._registry.clear()
|
||||
cnt = 0
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
for inv in InverterBase:
|
||||
assert inv == inverter
|
||||
cnt += 1
|
||||
del inv
|
||||
del inverter
|
||||
assert cnt == 1
|
||||
|
||||
for inv in InverterBase:
|
||||
assert False
|
||||
|
||||
def test_method_calls(patch_healthy):
|
||||
spy = patch_healthy
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
# call healthy inside the contexter manager
|
||||
for inv in InverterBase:
|
||||
assert inv.healthy()
|
||||
del inv
|
||||
spy.assert_called_once()
|
||||
|
||||
# outside context manager the health function of AsyncStream is not reachable
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
assert inv.healthy()
|
||||
cnt += 1
|
||||
del inv
|
||||
assert cnt == 1
|
||||
spy.assert_called_once() # counter don't increase and keep one!
|
||||
|
||||
del inverter
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
def test_unhealthy(patch_unhealthy):
|
||||
_ = patch_unhealthy
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
# call healthy inside the contexter manager
|
||||
assert not inverter.healthy()
|
||||
|
||||
# outside context manager the unhealth AsyncStream is released
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
assert inv.healthy() # inverter is healthy again (without the unhealty AsyncStream)
|
||||
cnt += 1
|
||||
del inv
|
||||
assert cnt == 1
|
||||
|
||||
del inverter
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
def test_unhealthy_remote(patch_unhealthy_remote):
|
||||
_ = patch_unhealthy
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
# call healthy inside the contexter manager
|
||||
assert not inverter.healthy()
|
||||
|
||||
# outside context manager the unhealth AsyncStream is released
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
assert inv.healthy() # inverter is healthy again (without the unhealty AsyncStream)
|
||||
cnt += 1
|
||||
del inv
|
||||
assert cnt == 1
|
||||
|
||||
del inverter
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
assert inverter.remote.ifc
|
||||
# call healthy inside the contexter manager
|
||||
assert inverter.healthy()
|
||||
|
||||
# call healthy outside the contexter manager (__exit__() was called)
|
||||
assert inverter.healthy()
|
||||
del inverter
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unhealthy_remote(config_conn, patch_open_connection, patch_unhealthy_remote):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_unhealthy_remote
|
||||
assert asyncio.get_running_loop()
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
assert inverter.remote.ifc
|
||||
assert inverter.local.ifc.healthy()
|
||||
assert not inverter.remote.ifc.healthy()
|
||||
# call healthy inside the contexter manager
|
||||
assert not inverter.healthy()
|
||||
|
||||
# outside context manager the unhealth AsyncStream is released
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
assert inv.healthy() # inverter is healthy again (without the unhealty AsyncStream)
|
||||
cnt += 1
|
||||
del inv
|
||||
assert cnt == 1
|
||||
|
||||
del inverter
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_disc(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
# call disc inside the contexter manager
|
||||
await inverter.disc()
|
||||
|
||||
# call disc outside the contexter manager (__exit__() was called)
|
||||
await inverter.disc()
|
||||
del inverter
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
@@ -1,15 +1,17 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
import sys,gc
|
||||
|
||||
from mock import patch
|
||||
from enum import Enum
|
||||
from app.src.infos import Infos
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.gen3.inverter_g3 import InverterG3
|
||||
from app.src.async_stream import AsyncStream
|
||||
|
||||
from app.tests.test_modbus_tcp import patch_mqtt_err, patch_mqtt_except, test_port, test_hostname
|
||||
|
||||
@@ -42,16 +44,6 @@ def module_init():
|
||||
Singleton._instances.clear()
|
||||
yield
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_init():
|
||||
with patch.object(ConnectionG3, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_close():
|
||||
with patch.object(ConnectionG3, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
@@ -103,132 +95,132 @@ def patch_open_connection():
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_healthy():
|
||||
with patch.object(AsyncStream, 'healthy') as conn:
|
||||
yield conn
|
||||
|
||||
def test_method_calls(patch_conn_close):
|
||||
spy2 = patch_conn_close
|
||||
def test_method_calls(patch_healthy):
|
||||
spy = patch_healthy
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
addr = ('proxy.local', 10000)
|
||||
inverter = InverterG3(reader, writer, addr)
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
InverterBase._registry.clear()
|
||||
|
||||
inverter.close()
|
||||
spy2.assert_called_once()
|
||||
with InverterG3(reader, writer) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
for inv in InverterBase:
|
||||
inv.healthy()
|
||||
del inv
|
||||
spy.assert_called_once()
|
||||
del inverter
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
with InverterG3(FakeReader(), FakeWriter()) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
del inverter
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_except(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_remote_except(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
global test
|
||||
test = TestType.RD_TEST_TIMEOUT
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
with InverterG3(FakeReader(), FakeWriter()) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
del inverter
|
||||
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
print(f'InverterBase refs:{gc.get_referrers(inv)}')
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
stream = inverter.local.stream
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == False
|
||||
with InverterG3(FakeReader(), FakeWriter()) as inverter:
|
||||
stream = inverter.local.stream
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
|
||||
stream.new_data['env'] = True
|
||||
stream.db.db['env'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['env'] == False
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == False
|
||||
|
||||
Infos.new_stat_data['proxy'] = True
|
||||
await inverter.async_publ_mqtt()
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
stream.new_data['env'] = True
|
||||
stream.db.db['env'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['env'] == False
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
Infos.new_stat_data['proxy'] = True
|
||||
await inverter.async_publ_mqtt()
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err, patch_conn_close):
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_err
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
stream = inverter.local.stream
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
with InverterG3(FakeReader(), FakeWriter()) as inverter:
|
||||
stream = inverter.local.stream
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except, patch_conn_close):
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_except
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
stream = inverter.local.stream
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
with InverterG3(FakeReader(), FakeWriter()) as inverter:
|
||||
stream = inverter.local.stream
|
||||
stream._Talent__set_serial_no(serial_no= "123344")
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@@ -6,9 +6,9 @@ from mock import patch
|
||||
from enum import Enum
|
||||
from app.src.infos import Infos
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.inverter_base import InverterBase
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.gen3plus.inverter_g3p import InverterG3P
|
||||
|
||||
from app.tests.test_modbus_tcp import patch_mqtt_err, patch_mqtt_except, test_port, test_hostname
|
||||
@@ -43,16 +43,6 @@ def module_init():
|
||||
Singleton._instances.clear()
|
||||
yield
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_init():
|
||||
with patch.object(ConnectionG3P, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_close():
|
||||
with patch.object(ConnectionG3P, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
@@ -104,132 +94,103 @@ def patch_open_connection():
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
|
||||
|
||||
def test_method_calls(patch_conn_close):
|
||||
spy2 = patch_conn_close
|
||||
def test_method_calls():
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
addr = ('proxy.local', 10000)
|
||||
inverter = InverterG3P(reader, writer, addr, client_mode=False)
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
InverterBase._registry.clear()
|
||||
|
||||
inverter.close()
|
||||
spy2.assert_called_once()
|
||||
with InverterG3P(reader, writer, client_mode=False) as inverter:
|
||||
assert inverter.local.stream
|
||||
assert inverter.local.ifc
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
with InverterG3P(FakeReader(), FakeWriter(), client_mode=False) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_except(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_remote_except(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
global test
|
||||
test = TestType.RD_TEST_TIMEOUT
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
with InverterG3P(FakeReader(), FakeWriter(), client_mode=False) as inverter:
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection, patch_conn_close):
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
stream = inverter.local.stream
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == False
|
||||
with InverterG3P(FakeReader(), FakeWriter(), client_mode=False) as inverter:
|
||||
stream = inverter.local.stream
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
|
||||
stream.new_data['env'] = True
|
||||
stream.db.db['env'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['env'] == False
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == False
|
||||
|
||||
Infos.new_stat_data['proxy'] = True
|
||||
await inverter.async_publ_mqtt()
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
stream.new_data['env'] = True
|
||||
stream.db.db['env'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['env'] == False
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
Infos.new_stat_data['proxy'] = True
|
||||
await inverter.async_publ_mqtt()
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err, patch_conn_close):
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_err
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
stream = inverter.local.stream
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
with InverterG3P(FakeReader(), FakeWriter(), client_mode=False) as inverter:
|
||||
stream = inverter.local.stream
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except, patch_conn_close):
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_except
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
spy1 = patch_conn_close
|
||||
|
||||
Inverter.class_init()
|
||||
Proxy.class_init()
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
stream = inverter.local.stream
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
with InverterG3P(FakeReader(), FakeWriter(), client_mode=False) as inverter:
|
||||
stream = inverter.local.stream
|
||||
stream._SolarmanV5__set_serial_no(snr= 123344)
|
||||
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
stream.new_data['inverter'] = True
|
||||
stream.db.db['inverter'] = {}
|
||||
await inverter.async_publ_mqtt()
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@@ -10,7 +10,7 @@ from app.src.config import Config
|
||||
from app.src.infos import Infos
|
||||
from app.src.mqtt import Mqtt
|
||||
from app.src.messages import Message, State
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.modbus_tcp import ModbusConn, ModbusTcp
|
||||
|
||||
|
||||
@@ -71,55 +71,77 @@ def config_conn(test_hostname, test_port):
|
||||
}
|
||||
|
||||
|
||||
class TestType(Enum):
|
||||
class FakeReader():
|
||||
RD_TEST_0_BYTES = 1
|
||||
RD_TEST_TIMEOUT = 2
|
||||
RD_TEST_13_BYTES = 3
|
||||
RD_TEST_SW_EXCEPT = 4
|
||||
RD_TEST_OS_ERROR = 5
|
||||
|
||||
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
|
||||
|
||||
class FakeReader():
|
||||
def __init__(self):
|
||||
self.on_recv = asyncio.Event()
|
||||
self.test = self.RD_TEST_0_BYTES
|
||||
|
||||
async def read(self, max_len: int):
|
||||
print(f'fakeReader test: {self.test}')
|
||||
await self.on_recv.wait()
|
||||
if test == TestType.RD_TEST_0_BYTES:
|
||||
if self.test == self.RD_TEST_0_BYTES:
|
||||
return b''
|
||||
elif test == TestType.RD_TEST_TIMEOUT:
|
||||
elif self.test == self.RD_TEST_13_BYTES:
|
||||
print('fakeReader return 13 bytes')
|
||||
self.test = self.RD_TEST_0_BYTES
|
||||
return b'test-data-req'
|
||||
elif self.test == self.RD_TEST_TIMEOUT:
|
||||
raise TimeoutError
|
||||
elif self.test == self.RD_TEST_SW_EXCEPT:
|
||||
self.test = self.RD_TEST_0_BYTES
|
||||
self.unknown_var += 1
|
||||
elif self.test == self.RD_TEST_OS_ERROR:
|
||||
self.test = self.RD_TEST_0_BYTES
|
||||
raise ConnectionRefusedError
|
||||
|
||||
def feed_eof(self):
|
||||
return
|
||||
|
||||
|
||||
class FakeWriter():
|
||||
def __init__(self, conn='remote.intern'):
|
||||
self.conn = conn
|
||||
self.closing = False
|
||||
def write(self, buf: bytes):
|
||||
return
|
||||
async def drain(self):
|
||||
await asyncio.sleep(0)
|
||||
def get_extra_info(self, sel: str):
|
||||
if sel == 'peername':
|
||||
return 'remote.intern'
|
||||
return self.conn
|
||||
elif sel == 'sockname':
|
||||
return 'sock:1234'
|
||||
assert False
|
||||
def is_closing(self):
|
||||
return False
|
||||
return self.closing
|
||||
def close(self):
|
||||
return
|
||||
self.closing = True
|
||||
async def wait_closed(self):
|
||||
return
|
||||
await asyncio.sleep(0)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_open():
|
||||
async def new_conn(conn):
|
||||
await asyncio.sleep(0)
|
||||
return FakeReader(), FakeWriter()
|
||||
return FakeReader(), FakeWriter(conn)
|
||||
|
||||
def new_open(host: str, port: int):
|
||||
global test
|
||||
if test == TestType.RD_TEST_TIMEOUT:
|
||||
raise TimeoutError
|
||||
return new_conn(None)
|
||||
return new_conn(f'{host}:{port}')
|
||||
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_open_timeout():
|
||||
def new_open(host: str, port: int):
|
||||
raise TimeoutError
|
||||
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
@@ -153,7 +175,7 @@ async def test_modbus_conn(patch_open):
|
||||
async with ModbusConn('test.local', 1234) as inverter:
|
||||
stream = inverter.local.stream
|
||||
assert stream.node_id == 'G3P'
|
||||
assert stream.addr == ('test.local', 1234)
|
||||
assert stream.addr == ('test.local:1234')
|
||||
assert type(stream.ifc._reader) is FakeReader
|
||||
assert type(stream.ifc._writer) is FakeWriter
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 1
|
||||
@@ -168,13 +190,11 @@ async def test_modbus_no_cnf():
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_cnf1(config_conn, patch_open):
|
||||
async def test_modbus_cnf1(config_conn, patch_open_timeout):
|
||||
_ = config_conn
|
||||
_ = patch_open
|
||||
global test
|
||||
_ = patch_open_timeout
|
||||
assert asyncio.get_running_loop()
|
||||
Inverter.class_init()
|
||||
test = TestType.RD_TEST_TIMEOUT
|
||||
Proxy.class_init()
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
loop = asyncio.get_event_loop()
|
||||
@@ -192,10 +212,8 @@ async def test_modbus_cnf2(config_conn, patch_no_mqtt, patch_open):
|
||||
_ = config_conn
|
||||
_ = patch_open
|
||||
_ = patch_no_mqtt
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
Inverter.class_init()
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
Proxy.class_init()
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
ModbusTcp(asyncio.get_event_loop())
|
||||
@@ -218,10 +236,8 @@ async def test_modbus_cnf3(config_conn, patch_no_mqtt, patch_open):
|
||||
_ = config_conn
|
||||
_ = patch_open
|
||||
_ = patch_no_mqtt
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
Inverter.class_init()
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
Proxy.class_init()
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
ModbusTcp(asyncio.get_event_loop(), tim_restart= 0)
|
||||
@@ -251,10 +267,8 @@ async def test_mqtt_err(config_conn, patch_mqtt_err, patch_open):
|
||||
_ = config_conn
|
||||
_ = patch_open
|
||||
_ = patch_mqtt_err
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
Inverter.class_init()
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
Proxy.class_init()
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
ModbusTcp(asyncio.get_event_loop(), tim_restart= 0)
|
||||
@@ -284,10 +298,8 @@ async def test_mqtt_except(config_conn, patch_mqtt_except, patch_open):
|
||||
_ = config_conn
|
||||
_ = patch_open
|
||||
_ = patch_mqtt_except
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
Inverter.class_init()
|
||||
test = TestType.RD_TEST_0_BYTES
|
||||
Proxy.class_init()
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
ModbusTcp(asyncio.get_event_loop(), tim_restart= 0)
|
||||
|
||||
@@ -6,7 +6,7 @@ import logging
|
||||
|
||||
from mock import patch, Mock
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.proxy import Proxy
|
||||
from app.src.mqtt import Mqtt
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
from app.src.config import Config
|
||||
@@ -63,13 +63,13 @@ def config_conn(test_hostname, test_port):
|
||||
async def test_inverter_cb(config_conn):
|
||||
_ = config_conn
|
||||
|
||||
with patch.object(Inverter, '_cb_mqtt_is_up', wraps=Inverter._cb_mqtt_is_up) as spy:
|
||||
print('call Inverter.class_init')
|
||||
Inverter.class_init()
|
||||
assert 'homeassistant/' == Inverter.discovery_prfx
|
||||
assert 'tsun/' == Inverter.entity_prfx
|
||||
assert 'test_1/' == Inverter.proxy_node_id
|
||||
await Inverter._cb_mqtt_is_up()
|
||||
with patch.object(Proxy, '_cb_mqtt_is_up', wraps=Proxy._cb_mqtt_is_up) as spy:
|
||||
print('call Proxy.class_init')
|
||||
Proxy.class_init()
|
||||
assert 'homeassistant/' == Proxy.discovery_prfx
|
||||
assert 'tsun/' == Proxy.entity_prfx
|
||||
assert 'test_1/' == Proxy.proxy_node_id
|
||||
await Proxy._cb_mqtt_is_up()
|
||||
spy.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -77,8 +77,8 @@ async def test_mqtt_is_up(config_conn):
|
||||
_ = config_conn
|
||||
|
||||
with patch.object(Mqtt, 'publish') as spy:
|
||||
Inverter.class_init()
|
||||
await Inverter._cb_mqtt_is_up()
|
||||
Proxy.class_init()
|
||||
await Proxy._cb_mqtt_is_up()
|
||||
spy.assert_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -86,6 +86,6 @@ async def test_mqtt_proxy_statt_invalid(config_conn):
|
||||
_ = config_conn
|
||||
|
||||
with patch.object(Mqtt, 'publish') as spy:
|
||||
Inverter.class_init()
|
||||
await Inverter._async_publ_mqtt_proxy_stat('InValId_kEy')
|
||||
Proxy.class_init()
|
||||
await Proxy._async_publ_mqtt_proxy_stat('InValId_kEy')
|
||||
spy.assert_not_called()
|
||||
@@ -32,13 +32,17 @@ class Mqtt():
|
||||
self.data = data
|
||||
|
||||
|
||||
class FakeIfc(AsyncIfcImpl):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.remote = StreamPtr(None)
|
||||
|
||||
class MemoryStream(SolarmanV5):
|
||||
def __init__(self, msg, chunks = (0,), server_side: bool = True):
|
||||
_ifc = AsyncIfcImpl()
|
||||
super().__init__(('test.local', 1234), server_side, client_mode=False, ifc=_ifc)
|
||||
_ifc = FakeIfc()
|
||||
super().__init__(('test.local', 1234), _ifc, server_side, client_mode=False)
|
||||
if server_side:
|
||||
self.mb.timeout = 0.4 # overwrite for faster testing
|
||||
self.remote = StreamPtr(None)
|
||||
self.mb_first_timeout = 0.5
|
||||
self.mb_timeout = 0.5
|
||||
self.sent_pdu = b''
|
||||
@@ -101,8 +105,8 @@ class MemoryStream(SolarmanV5):
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remote.stream = c
|
||||
c. remote.stream = self
|
||||
self.ifc.remote.stream = c
|
||||
c.ifc.remote.stream = self
|
||||
return c
|
||||
|
||||
def _SolarmanV5__flush_recv_msg(self) -> None:
|
||||
@@ -678,6 +682,7 @@ def config_tsun_inv1():
|
||||
Config.act_config = {'solarman':{'enabled': True},'inverters':{'Y170000000000001':{'monitor_sn': 2070233889, 'node_id':'inv1', 'modbus_polling': True, 'suggested_area':'roof', 'sensor_list': 688}}}
|
||||
|
||||
def test_read_message(device_ind_msg):
|
||||
Config.act_config = {'solarman':{'enabled': True}}
|
||||
m = MemoryStream(device_ind_msg, (0,))
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1236,9 +1241,9 @@ def test_build_logger_modell(config_tsun_allow_all, device_ind_msg):
|
||||
|
||||
def test_msg_iterator():
|
||||
Message._registry.clear()
|
||||
m1 = SolarmanV5(('test1.local', 1234), server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
m2 = SolarmanV5(('test2.local', 1234), server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
m3 = SolarmanV5(('test3.local', 1234), server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
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
|
||||
@@ -1256,7 +1261,7 @@ def test_msg_iterator():
|
||||
assert test2 == 1
|
||||
|
||||
def test_proxy_counter():
|
||||
m = SolarmanV5(('test.local', 1234), server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
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
|
||||
|
||||
@@ -16,14 +16,17 @@ Infos.static_init()
|
||||
|
||||
tracer = logging.getLogger('tracer')
|
||||
|
||||
class FakeIfc(AsyncIfcImpl):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.remote = StreamPtr(None)
|
||||
|
||||
class MemoryStream(Talent):
|
||||
def __init__(self, msg, chunks = (0,), server_side: bool = True):
|
||||
self.ifc = AsyncIfcImpl()
|
||||
super().__init__(('test.local', 1234), server_side, self.ifc)
|
||||
self.ifc = FakeIfc()
|
||||
super().__init__(('test.local', 1234), self.ifc, server_side)
|
||||
if server_side:
|
||||
self.mb.timeout = 0.4 # overwrite for faster testing
|
||||
self.remote = StreamPtr(None)
|
||||
self.mb_first_timeout = 0.5
|
||||
self.mb_timeout = 0.5
|
||||
self.sent_pdu = b''
|
||||
@@ -37,7 +40,6 @@ class MemoryStream(Talent):
|
||||
self.addr = 'Test: SrvSide'
|
||||
self.send_msg_ofs = 0
|
||||
self.msg_recvd = []
|
||||
self.remote.stream = None
|
||||
|
||||
def write_cb(self):
|
||||
self.sent_pdu = self.ifc.tx_fifo.get()
|
||||
@@ -73,8 +75,8 @@ class MemoryStream(Talent):
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remote.stream = c
|
||||
c. remote.stream = self
|
||||
self.ifc.remote.stream = c
|
||||
c.ifc.remote.stream = self
|
||||
return c
|
||||
|
||||
def _Talent__flush_recv_msg(self) -> None:
|
||||
@@ -1059,7 +1061,7 @@ def test_msg_time_resp(config_tsun_inv1, msg_time_rsp):
|
||||
m = MemoryStream(msg_time_rsp, (0,), False)
|
||||
s = MemoryStream(b'', (0,), True)
|
||||
assert s.ts_offset==0
|
||||
m.remote.stream = s
|
||||
m.ifc.remote.stream = s
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1075,7 +1077,7 @@ def test_msg_time_resp(config_tsun_inv1, msg_time_rsp):
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.remote.stream = None
|
||||
m.ifc.remote.stream = None
|
||||
s.close()
|
||||
m.close()
|
||||
|
||||
@@ -1639,9 +1641,9 @@ def test_ctrl_byte():
|
||||
|
||||
|
||||
def test_msg_iterator():
|
||||
m1 = Talent(('test1.local', 1234), server_side=True, ifc=AsyncIfcImpl())
|
||||
m2 = Talent(('test2.local', 1234), server_side=True, ifc=AsyncIfcImpl())
|
||||
m3 = Talent(('test3.local', 1234), server_side=True, ifc=AsyncIfcImpl())
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user