Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan
This commit is contained in:
827
app/proxy.svg
827
app/proxy.svg
@@ -4,408 +4,579 @@
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="720pt" height="1360pt"
|
||||
viewBox="0.00 0.00 719.50 1360.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 1356)">
|
||||
<svg width="846pt" height="1784pt"
|
||||
viewBox="0.00 0.00 846.00 1784.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 1780)">
|
||||
<title>G</title>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1356 715.5,-1356 715.5,4 -4,4"/>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1780 842,-1780 842,4 -4,4"/>
|
||||
<!-- A0 -->
|
||||
<g id="node1" class="node">
|
||||
<title>A0</title>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="153.6964,-1250 45.3036,-1250 45.3036,-1214 159.6964,-1214 159.6964,-1244 153.6964,-1250"/>
|
||||
<polyline fill="none" stroke="#000000" points="153.6964,-1250 153.6964,-1244 "/>
|
||||
<polyline fill="none" stroke="#000000" points="159.6964,-1244 153.6964,-1244 "/>
|
||||
<text text-anchor="middle" x="102.5" y="-1235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
|
||||
<text text-anchor="middle" x="102.5" y="-1223" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">on diagrams too!</text>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="495.6964,-1752 387.3036,-1752 387.3036,-1716 501.6964,-1716 501.6964,-1746 495.6964,-1752"/>
|
||||
<polyline fill="none" stroke="#000000" points="495.6964,-1752 495.6964,-1746 "/>
|
||||
<polyline fill="none" stroke="#000000" points="501.6964,-1746 495.6964,-1746 "/>
|
||||
<text text-anchor="middle" x="444.5" y="-1737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">You can stick notes</text>
|
||||
<text text-anchor="middle" x="444.5" y="-1725" 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="685.1817,-942 615.8183,-942 615.8183,-906 685.1817,-906 685.1817,-942"/>
|
||||
<text text-anchor="middle" x="650.5" y="-921" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Singleton</text>
|
||||
<polygon fill="none" stroke="#000000" points="118.5,-572 118.5,-616 240.5,-616 240.5,-572 118.5,-572"/>
|
||||
<text text-anchor="start" x="169.777" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Mqtt</text>
|
||||
<text text-anchor="start" x="146.9815" y="-585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<Singleton>></text>
|
||||
<polygon fill="none" stroke="#000000" points="118.5,-516 118.5,-572 240.5,-572 240.5,-516 118.5,-516"/>
|
||||
<text text-anchor="start" x="136.9875" y="-553" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>ha_restarts</text>
|
||||
<text text-anchor="start" x="144.7665" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__client</text>
|
||||
<text text-anchor="start" x="128.3735" y="-529" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__cb_MqttIsUp</text>
|
||||
<polygon fill="none" stroke="#000000" points="118.5,-472 118.5,-516 240.5,-516 240.5,-472 118.5,-472"/>
|
||||
<text text-anchor="start" x="141.436" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish()</text>
|
||||
<text text-anchor="start" x="145.6045" y="-485" 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="589.5,-644 589.5,-676 711.5,-676 711.5,-644 589.5,-644"/>
|
||||
<text text-anchor="start" x="640.777" y="-657" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Mqtt</text>
|
||||
<polygon fill="none" stroke="#000000" points="589.5,-588 589.5,-644 711.5,-644 711.5,-588 589.5,-588"/>
|
||||
<text text-anchor="start" x="607.9875" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>ha_restarts</text>
|
||||
<text text-anchor="start" x="615.7665" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__client</text>
|
||||
<text text-anchor="start" x="599.3735" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><static>__cb_MqttIsUp</text>
|
||||
<polygon fill="none" stroke="#000000" points="589.5,-544 589.5,-588 711.5,-588 711.5,-544 589.5,-544"/>
|
||||
<text text-anchor="start" x="612.436" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish()</text>
|
||||
<text text-anchor="start" x="616.6045" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>close()</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-342 125.5,-374 233.5,-374 233.5,-342 125.5,-342"/>
|
||||
<text text-anchor="start" x="162.5535" y="-355" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Inverter</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-250 125.5,-342 233.5,-342 233.5,-250 125.5,-250"/>
|
||||
<text text-anchor="start" x="155.604" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.db_stat</text>
|
||||
<text text-anchor="start" x="148.9405" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.entity_prfx</text>
|
||||
<text text-anchor="start" x="139.7755" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.discovery_prfx</text>
|
||||
<text text-anchor="start" x="139.2115" y="-287" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_node_id</text>
|
||||
<text text-anchor="start" x="135.3225" y="-275" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_unique_id</text>
|
||||
<text text-anchor="start" x="151.1655" y="-263" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.mqtt:Mqtt</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-230 125.5,-250 233.5,-250 233.5,-230 125.5,-230"/>
|
||||
</g>
|
||||
<!-- A1->A2 -->
|
||||
<g id="edge1" class="edge">
|
||||
<g id="edge3" class="edge">
|
||||
<title>A1->A2</title>
|
||||
<path fill="none" stroke="#000000" d="M650.5,-895.5395C650.5,-846.311 650.5,-744.0351 650.5,-676.2069"/>
|
||||
<polygon fill="none" stroke="#000000" points="647.0001,-895.7608 650.5,-905.7608 654.0001,-895.7608 647.0001,-895.7608"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="596.5,-348 596.5,-380 704.5,-380 704.5,-348 596.5,-348"/>
|
||||
<text text-anchor="start" x="633.5535" y="-361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Inverter</text>
|
||||
<polygon fill="none" stroke="#000000" points="596.5,-256 596.5,-348 704.5,-348 704.5,-256 596.5,-256"/>
|
||||
<text text-anchor="start" x="626.604" y="-329" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.db_stat</text>
|
||||
<text text-anchor="start" x="619.9405" y="-317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.entity_prfx</text>
|
||||
<text text-anchor="start" x="610.7755" y="-305" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.discovery_prfx</text>
|
||||
<text text-anchor="start" x="610.2115" y="-293" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_node_id</text>
|
||||
<text text-anchor="start" x="606.3225" y="-281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.proxy_unique_id</text>
|
||||
<text text-anchor="start" x="622.1655" y="-269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">cls.mqtt:Mqtt</text>
|
||||
<polygon fill="none" stroke="#000000" points="596.5,-236 596.5,-256 704.5,-256 704.5,-236 596.5,-236"/>
|
||||
</g>
|
||||
<!-- A2->A11 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A2->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M650.5,-543.7248C650.5,-495.3688 650.5,-429.8734 650.5,-380.1918"/>
|
||||
<path fill="none" stroke="#000000" d="M179.5,-461.4521C179.5,-437.2513 179.5,-410.7602 179.5,-386.443"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="179.5,-471.7198 175.0001,-461.7198 179.5,-466.7198 179.5001,-461.7198 179.5001,-461.7198 179.5001,-461.7198 179.5,-466.7198 184.0001,-461.7199 179.5,-471.7198 179.5,-471.7198"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="179.5001,-386.3256 175.5,-380.3256 179.5,-374.3256 183.5,-380.3256 179.5001,-386.3256"/>
|
||||
</g>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="318.5,-402 318.5,-434 393.5,-434 393.5,-402 318.5,-402"/>
|
||||
<text text-anchor="start" x="338.2175" y="-415" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="318.5,-250 318.5,-402 393.5,-402 393.5,-250 318.5,-250"/>
|
||||
<text text-anchor="start" x="347.6615" y="-383" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="328.49" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="329.605" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="339.6085" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="329.8895" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="337.942" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="349.8915" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="336.5535" y="-287" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="334.879" y="-275" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="349.3365" y="-263" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="318.5,-182 318.5,-250 393.5,-250 393.5,-182 318.5,-182"/>
|
||||
<text text-anchor="start" x="329.89" y="-231" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="333.224" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="330.724" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="341.0025" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<polygon fill="none" stroke="#000000" points="284.5,-100 284.5,-132 406.5,-132 406.5,-100 284.5,-100"/>
|
||||
<text text-anchor="start" x="321.8845" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="284.5,-68 284.5,-100 406.5,-100 406.5,-68 284.5,-68"/>
|
||||
<text text-anchor="start" x="314.9355" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
|
||||
<polygon fill="none" stroke="#000000" points="284.5,0 284.5,-68 406.5,-68 406.5,0 284.5,0"/>
|
||||
<text text-anchor="start" x="294.1035" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote()</text>
|
||||
<text text-anchor="start" x="304.382" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_publ_mqtt()</text>
|
||||
<text text-anchor="start" x="330.5025" y="-13" 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="M218.7146,-220.7402C226.0884,-207.4676 234.13,-194.1098 242.5,-182 254.9036,-164.0543 269.7696,-145.8518 284.2981,-129.3516"/>
|
||||
<polygon fill="none" stroke="#000000" points="215.4351,-219.4436 213.7205,-229.8988 221.5808,-222.7948 215.4351,-219.4436"/>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="308.5,-1242 308.5,-1274 379.5,-1274 379.5,-1242 308.5,-1242"/>
|
||||
<text text-anchor="start" x="318.445" y="-1255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">IterRegistry</text>
|
||||
<polygon fill="none" stroke="#000000" points="308.5,-1222 308.5,-1242 379.5,-1242 379.5,-1222 308.5,-1222"/>
|
||||
<polygon fill="none" stroke="#000000" points="308.5,-1190 308.5,-1222 379.5,-1222 379.5,-1190 308.5,-1190"/>
|
||||
<text text-anchor="start" x="325.939" y="-1203" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__</text>
|
||||
<polygon fill="none" stroke="#000000" points="120.5,-94 120.5,-126 239.5,-126 239.5,-94 120.5,-94"/>
|
||||
<text text-anchor="start" x="153.05" y="-107" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="120.5,-62 120.5,-94 239.5,-94 239.5,-62 120.5,-62"/>
|
||||
<text text-anchor="start" x="149.4355" y="-75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
|
||||
<polygon fill="none" stroke="#000000" points="120.5,-6 120.5,-62 239.5,-62 239.5,-6 120.5,-6"/>
|
||||
<text text-anchor="start" x="130.268" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote(</text>
|
||||
<text text-anchor="start" x="137.2175" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">)async_publ_mqtt()</text>
|
||||
<text text-anchor="start" x="165.0025" y="-19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M179.5,-219.6269C179.5,-188.8617 179.5,-154.5312 179.5,-126.1395"/>
|
||||
<polygon fill="none" stroke="#000000" points="176.0001,-219.9098 179.5,-229.9099 183.0001,-219.9099 176.0001,-219.9098"/>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="276.5,-1030 276.5,-1062 410.5,-1062 410.5,-1030 276.5,-1030"/>
|
||||
<text text-anchor="start" x="323.2175" y="-1043" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="276.5,-854 276.5,-1030 410.5,-1030 410.5,-854 276.5,-854"/>
|
||||
<text text-anchor="start" x="306.8265" y="-1011" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="304.043" y="-999" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="296.814" y="-987" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len:unsigned</text>
|
||||
<text text-anchor="start" x="302.648" y="-975" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len:unsigned</text>
|
||||
<text text-anchor="start" x="321.8245" y="-963" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="325.7135" y="-951" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="322.6585" y="-939" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area</text>
|
||||
<text text-anchor="start" x="293.489" y="-927" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_recv_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="292.0945" y="-915" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="286.2665" y="-903" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_forward_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="325.7135" y="-891" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:Infos</text>
|
||||
<text text-anchor="start" x="314.326" y="-879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:list</text>
|
||||
<text text-anchor="start" x="332.662" y="-867" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state</text>
|
||||
<polygon fill="none" stroke="#000000" points="276.5,-786 276.5,-854 410.5,-854 410.5,-786 276.5,-786"/>
|
||||
<text text-anchor="start" x="293.2095" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_read():void<abstract></text>
|
||||
<text text-anchor="start" x="317.9445" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close():void</text>
|
||||
<text text-anchor="start" x="303.7725" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter():void</text>
|
||||
<text text-anchor="start" x="302.1025" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter():void</text>
|
||||
</g>
|
||||
<!-- A4->A5 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A4->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M343.5,-1179.6793C343.5,-1147.2188 343.5,-1103.8616 343.5,-1062.0836"/>
|
||||
<polygon fill="none" stroke="#000000" points="340.0001,-1179.8197 343.5,-1189.8197 347.0001,-1179.8198 340.0001,-1179.8197"/>
|
||||
<polygon fill="none" stroke="#000000" points="520.5,-1744 520.5,-1776 591.5,-1776 591.5,-1744 520.5,-1744"/>
|
||||
<text text-anchor="start" x="530.445" y="-1757" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">IterRegistry</text>
|
||||
<polygon fill="none" stroke="#000000" points="520.5,-1724 520.5,-1744 591.5,-1744 591.5,-1724 520.5,-1724"/>
|
||||
<polygon fill="none" stroke="#000000" points="520.5,-1692 520.5,-1724 591.5,-1724 591.5,-1692 520.5,-1692"/>
|
||||
<text text-anchor="start" x="537.939" y="-1705" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__</text>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="415.5,-704 415.5,-736 529.5,-736 529.5,-704 415.5,-704"/>
|
||||
<text text-anchor="start" x="458.608" y="-717" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="415.5,-600 415.5,-704 529.5,-704 529.5,-600 415.5,-600"/>
|
||||
<text text-anchor="start" x="425.263" y="-685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="460.2775" y="-673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="441.1" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="444.44" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="448.0445" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="446.384" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="458.612" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="415.5,-484 415.5,-600 529.5,-600 529.5,-484 415.5,-484"/>
|
||||
<text text-anchor="start" x="429.9925" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="431.9325" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="437.7765" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="425.8285" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="427.7735" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="436.9405" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="457.5025" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<polygon fill="none" stroke="#000000" points="488.5,-1610 488.5,-1642 622.5,-1642 622.5,-1610 488.5,-1610"/>
|
||||
<text text-anchor="start" x="535.2175" y="-1623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="488.5,-1434 488.5,-1610 622.5,-1610 622.5,-1434 488.5,-1434"/>
|
||||
<text text-anchor="start" x="518.8265" y="-1591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="516.043" y="-1579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="508.814" y="-1567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len:unsigned</text>
|
||||
<text text-anchor="start" x="514.648" y="-1555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len:unsigned</text>
|
||||
<text text-anchor="start" x="533.8245" y="-1543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="537.7135" y="-1531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="534.6585" y="-1519" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area</text>
|
||||
<text text-anchor="start" x="505.489" y="-1507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_recv_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="504.0945" y="-1495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="498.2665" y="-1483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_forward_buffer:bytearray</text>
|
||||
<text text-anchor="start" x="537.7135" y="-1471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:Infos</text>
|
||||
<text text-anchor="start" x="526.326" y="-1459" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:list</text>
|
||||
<text text-anchor="start" x="544.662" y="-1447" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state</text>
|
||||
<polygon fill="none" stroke="#000000" points="488.5,-1366 488.5,-1434 622.5,-1434 622.5,-1366 488.5,-1366"/>
|
||||
<text text-anchor="start" x="505.2095" y="-1415" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_read():void<abstract></text>
|
||||
<text text-anchor="start" x="529.9445" y="-1403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close():void</text>
|
||||
<text text-anchor="start" x="515.7725" y="-1391" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter():void</text>
|
||||
<text text-anchor="start" x="514.1025" y="-1379" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter():void</text>
|
||||
</g>
|
||||
<!-- A5->A6 -->
|
||||
<g id="edge3" class="edge">
|
||||
<g id="edge4" class="edge">
|
||||
<title>A5->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M404.0814,-776.5383C409.5999,-763.1056 415.1569,-749.5794 420.5898,-736.355"/>
|
||||
<polygon fill="none" stroke="#000000" points="400.8317,-775.2382 400.269,-785.8181 407.3066,-777.8983 400.8317,-775.2382"/>
|
||||
<path fill="none" stroke="#000000" d="M555.5,-1681.5582C555.5,-1669.4749 555.5,-1656.067 555.5,-1642.189"/>
|
||||
<polygon fill="none" stroke="#000000" points="552.0001,-1681.8144 555.5,-1691.8145 559.0001,-1681.8145 552.0001,-1681.8144"/>
|
||||
</g>
|
||||
<!-- A21 -->
|
||||
<g id="node22" class="node">
|
||||
<title>A21</title>
|
||||
<polygon fill="none" stroke="#000000" points="498.5,-1284 498.5,-1316 612.5,-1316 612.5,-1284 498.5,-1284"/>
|
||||
<text text-anchor="start" x="541.608" y="-1297" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="498.5,-1180 498.5,-1284 612.5,-1284 612.5,-1180 498.5,-1180"/>
|
||||
<text text-anchor="start" x="508.263" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="543.2775" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="524.1" y="-1241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="527.44" y="-1229" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="531.0445" y="-1217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="529.384" y="-1205" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="541.612" y="-1193" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="498.5,-1064 498.5,-1180 612.5,-1180 612.5,-1064 498.5,-1064"/>
|
||||
<text text-anchor="start" x="512.9925" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="514.9325" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="520.7765" y="-1137" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="508.8285" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="510.7735" y="-1113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="519.9405" y="-1101" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="540.5025" y="-1077" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A6->A21 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>A6->A21</title>
|
||||
<path fill="none" stroke="#000000" d="M555.5,-1355.7632C555.5,-1342.5854 555.5,-1329.3251 555.5,-1316.355"/>
|
||||
<polygon fill="none" stroke="#000000" points="552.0001,-1355.8181 555.5,-1365.8181 559.0001,-1355.8181 552.0001,-1355.8181"/>
|
||||
</g>
|
||||
<!-- A22 -->
|
||||
<g id="node23" class="node">
|
||||
<title>A22</title>
|
||||
<polygon fill="none" stroke="#000000" points="387.5,-1248 387.5,-1280 478.5,-1280 478.5,-1248 387.5,-1248"/>
|
||||
<text text-anchor="start" x="405.495" y="-1261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="387.5,-1156 387.5,-1248 478.5,-1248 478.5,-1156 387.5,-1156"/>
|
||||
<text text-anchor="start" x="417.998" y="-1229" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="421.0575" y="-1217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="426.056" y="-1205" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="405.21" y="-1193" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="406.884" y="-1181" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="419.112" y="-1169" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="387.5,-1100 387.5,-1156 478.5,-1156 478.5,-1100 387.5,-1100"/>
|
||||
<text text-anchor="start" x="397.4405" y="-1137" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="418.0025" y="-1113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A6->A22 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>A6->A22</title>
|
||||
<path fill="none" stroke="#000000" d="M497.6392,-1356.2903C487.487,-1330.3733 477.2021,-1304.1174 467.8962,-1280.3611"/>
|
||||
<polygon fill="none" stroke="#000000" points="494.4651,-1357.7836 501.3714,-1365.8181 500.9829,-1355.2304 494.4651,-1357.7836"/>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="172.5,-668 172.5,-700 263.5,-700 263.5,-668 172.5,-668"/>
|
||||
<text text-anchor="start" x="190.495" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="172.5,-576 172.5,-668 263.5,-668 263.5,-576 172.5,-576"/>
|
||||
<text text-anchor="start" x="202.998" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="206.0575" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="211.056" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="190.21" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="191.884" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="204.112" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="172.5,-520 172.5,-576 263.5,-576 263.5,-520 172.5,-520"/>
|
||||
<text text-anchor="start" x="182.4405" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="203.0025" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A5->A7 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A5->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M284.228,-776.2903C273.8281,-750.3733 263.2923,-724.1174 253.7595,-700.3611"/>
|
||||
<polygon fill="none" stroke="#000000" points="281.0788,-777.8409 288.0512,-785.8181 287.5753,-775.2339 281.0788,-777.8409"/>
|
||||
</g>
|
||||
<!-- A6->A3 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A6->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M420.9917,-483.781C414.3472,-467.074 407.7026,-450.1475 401.5,-434 399.8828,-429.7898 398.247,-425.4956 396.6047,-421.154"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="393.0037,-411.5882 400.7383,-419.3616 394.7652,-416.2676 396.5268,-420.947 396.5268,-420.947 396.5268,-420.947 394.7652,-416.2676 392.3154,-422.5325 393.0037,-411.5882 393.0037,-411.5882"/>
|
||||
<text text-anchor="middle" x="407.3001" y="-422.5743" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
<text text-anchor="middle" x="406.4454" y="-467.0549" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<polygon fill="none" stroke="#000000" points="552.5,-982 552.5,-1014 669.5,-1014 669.5,-982 552.5,-982"/>
|
||||
<text text-anchor="start" x="580.429" y="-995" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="552.5,-962 552.5,-982 669.5,-982 669.5,-962 552.5,-962"/>
|
||||
<polygon fill="none" stroke="#000000" points="552.5,-666 552.5,-962 669.5,-962 669.5,-666 552.5,-666"/>
|
||||
<text text-anchor="start" x="580.436" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="578.766" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="592.6635" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="590.444" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="594.0535" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="590.1635" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="594.3335" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="590.169" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="594.3335" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="588.7745" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="586.555" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_flush()</text>
|
||||
<text text-anchor="start" x="590.4445" y="-787" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="586.28" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_clear()</text>
|
||||
<text text-anchor="start" x="593.7785" y="-763" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="589.8885" y="-751" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="594.0585" y="-739" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="589.894" y="-727" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="594.0585" y="-715" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="585.999" y="-703" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="562.3795" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-330 410.5,-362 560.5,-362 560.5,-330 410.5,-330"/>
|
||||
<text text-anchor="start" x="453.5455" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-298 410.5,-330 560.5,-330 560.5,-298 410.5,-298"/>
|
||||
<text text-anchor="start" x="420.487" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote_stream:ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="410.5,-254 410.5,-298 560.5,-298 560.5,-254 410.5,-254"/>
|
||||
<text text-anchor="start" x="466.054" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="470.5025" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<polygon fill="none" stroke="#000000" points="575.5,-574 575.5,-606 668.5,-606 668.5,-574 575.5,-574"/>
|
||||
<text text-anchor="start" x="593.664" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="575.5,-482 575.5,-574 668.5,-574 668.5,-482 575.5,-482"/>
|
||||
<text text-anchor="start" x="585.048" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="588.937" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="588.662" y="-531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="588.096" y="-519" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="604.2135" y="-507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="597.5495" y="-495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A6->A8 -->
|
||||
<!-- A7->A8 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A6->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M478.3685,-473.6691C480.0687,-434.1731 481.827,-393.3258 483.1723,-362.0732"/>
|
||||
<polygon fill="none" stroke="#000000" points="474.8712,-473.5333 477.9378,-483.6747 481.8648,-473.8345 474.8712,-473.5333"/>
|
||||
</g>
|
||||
<!-- A7->A3 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A7->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M254.1161,-519.7083C259.8714,-507.5039 266.0613,-495.3029 272.5,-484 286.0537,-460.2067 295.6001,-458.1541 308.5,-434 310.2529,-430.7178 311.9697,-427.3559 313.6482,-423.937"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="317.9998,-414.7692 317.7769,-425.7328 315.8557,-419.2862 313.7116,-423.8032 313.7116,-423.8032 313.7116,-423.8032 315.8557,-419.2862 309.6463,-421.8735 317.9998,-414.7692 317.9998,-414.7692"/>
|
||||
<text text-anchor="middle" x="317.8629" y="-431.7687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
<text text-anchor="middle" x="254.262" y="-496.7088" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M617.3637,-655.3047C618.0135,-637.8196 618.6361,-621.0638 619.1922,-606.0999"/>
|
||||
<polygon fill="none" stroke="#000000" points="613.8521,-655.5528 616.9783,-665.6759 620.8473,-655.8128 613.8521,-655.5528"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-330 125.5,-362 281.5,-362 281.5,-330 125.5,-330"/>
|
||||
<text text-anchor="start" x="168.211" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-298 125.5,-330 281.5,-330 281.5,-298 125.5,-298"/>
|
||||
<text text-anchor="start" x="135.1525" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote_stream:ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="125.5,-254 125.5,-298 281.5,-298 281.5,-254 125.5,-254"/>
|
||||
<text text-anchor="start" x="184.054" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="188.5025" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<polygon fill="none" stroke="#000000" points="635.5,-390 635.5,-422 737.5,-422 737.5,-390 635.5,-390"/>
|
||||
<text text-anchor="start" x="656.774" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="635.5,-310 635.5,-390 737.5,-390 737.5,-310 635.5,-310"/>
|
||||
<text text-anchor="start" x="672.053" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="674.283" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="676.497" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="672.053" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="672.608" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="635.5,-182 635.5,-310 737.5,-310 737.5,-182 635.5,-182"/>
|
||||
<text text-anchor="start" x="658.154" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="674.282" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="671.5025" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="667.054" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="651.7705" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="651.221" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="645.107" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A7->A9 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A7->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M212.8528,-509.7531C210.5717,-460.5471 207.9134,-403.2043 206.0152,-362.2565"/>
|
||||
<polygon fill="none" stroke="#000000" points="209.3591,-509.972 213.3185,-519.7991 216.3516,-509.6477 209.3591,-509.972"/>
|
||||
</g>
|
||||
<!-- A8->A8 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A8->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M560.6684,-348.7195C571.3394,-342.1337 578.5,-328.5605 578.5,-308 578.5,-292.9008 574.6382,-281.57 568.3604,-274.0076"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="560.6684,-267.2805 571.1583,-270.4763 564.4321,-270.5721 568.1958,-273.8637 568.1958,-273.8637 568.1958,-273.8637 564.4321,-270.5721 565.2334,-277.251 560.6684,-267.2805 560.6684,-267.2805"/>
|
||||
<text text-anchor="middle" x="579.877" y="-269.8507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
<text text-anchor="middle" x="570.593" y="-328.3557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="506.5,-100 506.5,-132 628.5,-132 628.5,-100 506.5,-100"/>
|
||||
<text text-anchor="start" x="543.8845" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="506.5,-68 506.5,-100 628.5,-100 628.5,-68 506.5,-68"/>
|
||||
<text text-anchor="start" x="536.9355" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
|
||||
<polygon fill="none" stroke="#000000" points="506.5,0 506.5,-68 628.5,-68 628.5,0 506.5,0"/>
|
||||
<text text-anchor="start" x="516.1035" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote()</text>
|
||||
<text text-anchor="start" x="526.382" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_publ_mqtt()</text>
|
||||
<text text-anchor="start" x="552.5025" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A8->A12 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A8->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M507.022,-244.4839C518.719,-209.9635 533.1714,-167.3112 545.0148,-132.3588"/>
|
||||
<polygon fill="none" stroke="#000000" points="503.6947,-243.3974 503.8003,-253.9917 510.3245,-245.6439 503.6947,-243.3974"/>
|
||||
</g>
|
||||
<!-- A9->A9 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A9->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M281.8471,-348.2542C292.4443,-341.506 299.5,-328.0879 299.5,-308 299.5,-293.248 295.6948,-282.093 289.4763,-274.5351"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="281.8471,-267.7458 292.3089,-271.0321 285.5822,-271.0697 289.3174,-274.3937 289.3174,-274.3937 289.3174,-274.3937 285.5822,-271.0697 286.3258,-277.7553 281.8471,-267.7458 281.8471,-267.7458"/>
|
||||
<text text-anchor="middle" x="301.0069" y="-270.4817" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
<text text-anchor="middle" x="291.5637" y="-327.7732" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="144.5,-94 144.5,-126 263.5,-126 263.5,-94 144.5,-94"/>
|
||||
<text text-anchor="start" x="177.05" y="-107" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="144.5,-62 144.5,-94 263.5,-94 263.5,-62 144.5,-62"/>
|
||||
<text text-anchor="start" x="173.4355" y="-75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__ha_restarts</text>
|
||||
<polygon fill="none" stroke="#000000" points="144.5,-6 144.5,-62 263.5,-62 263.5,-6 144.5,-6"/>
|
||||
<text text-anchor="start" x="154.268" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote(</text>
|
||||
<text text-anchor="start" x="161.2175" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">)async_publ_mqtt()</text>
|
||||
<text text-anchor="start" x="189.0025" y="-19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A9->A13 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A9->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M203.5,-243.955C203.5,-207.4743 203.5,-162.045 203.5,-126.2187"/>
|
||||
<polygon fill="none" stroke="#000000" points="200.0001,-243.9917 203.5,-253.9917 207.0001,-243.9917 200.0001,-243.9917"/>
|
||||
<!-- A8->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A8->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M640.7492,-472.3339C644.9969,-456.5191 649.6091,-439.3476 654.2155,-422.1976"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="638.1547,-481.9932 636.4028,-471.1682 639.4518,-477.1644 640.7488,-472.3355 640.7488,-472.3355 640.7488,-472.3355 639.4518,-477.1644 645.0948,-473.5029 638.1547,-481.9932 638.1547,-481.9932"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="281.5,-698 281.5,-730 397.5,-730 397.5,-698 281.5,-698"/>
|
||||
<text text-anchor="start" x="309.774" y="-711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="281.5,-618 281.5,-698 397.5,-698 397.5,-618 281.5,-618"/>
|
||||
<text text-anchor="start" x="325.053" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="327.283" y="-667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="329.497" y="-655" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="325.053" y="-643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="325.608" y="-631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="281.5,-490 281.5,-618 397.5,-618 397.5,-490 281.5,-490"/>
|
||||
<text text-anchor="start" x="291.1575" y="-599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="293.378" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="311.154" y="-575" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="327.282" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="324.5025" y="-551" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="304.7705" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="309.78" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_write()</text>
|
||||
<text text-anchor="start" x="298.107" y="-503" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
<polygon fill="none" stroke="#000000" points="436.5,-100 436.5,-132 614.5,-132 614.5,-100 436.5,-100"/>
|
||||
<text text-anchor="start" x="481.0515" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="436.5,-68 436.5,-100 614.5,-100 614.5,-68 436.5,-68"/>
|
||||
<text text-anchor="start" x="477.4325" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">async_create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="436.5,0 436.5,-68 614.5,-68 614.5,0 436.5,0"/>
|
||||
<text text-anchor="start" x="477.1575" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="467.9885" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="446.309" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="510.5025" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A10->A8 -->
|
||||
<!-- A9->A10 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A9->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M629.9027,-187.1874C628.7765,-185.436 627.642,-183.7056 626.5,-182 615.1346,-165.026 601.5426,-147.838 588.0698,-132.0797"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="635.4599,-196.1027 626.3512,-189.9968 632.8149,-191.8595 630.17,-187.6163 630.17,-187.6163 630.17,-187.6163 632.8149,-191.8595 633.9889,-185.2359 635.4599,-196.1027 635.4599,-196.1027"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="632.5,-82 632.5,-114 770.5,-114 770.5,-82 632.5,-82"/>
|
||||
<text text-anchor="start" x="658.997" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="632.5,-62 632.5,-82 770.5,-82 770.5,-62 632.5,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="632.5,-18 632.5,-62 770.5,-62 770.5,-18 632.5,-18"/>
|
||||
<text text-anchor="start" x="655.378" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="642.324" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A9->A11 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A9->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M694.7749,-171.8077C696.0812,-151.2556 697.3558,-131.2022 698.4379,-114.1772"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="694.1318,-181.9259 690.2753,-171.6605 694.449,-176.9359 694.7662,-171.946 694.7662,-171.946 694.7662,-171.946 694.449,-176.9359 699.2572,-172.2315 694.1318,-181.9259 694.1318,-181.9259"/>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-856 687.5,-888 838.5,-888 838.5,-856 687.5,-856"/>
|
||||
<text text-anchor="start" x="731.0455" y="-869" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-824 687.5,-856 838.5,-856 838.5,-824 687.5,-824"/>
|
||||
<text text-anchor="start" x="697.432" y="-837" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-792 687.5,-824 838.5,-824 838.5,-792 687.5,-792"/>
|
||||
<text text-anchor="start" x="743.554" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-560 687.5,-592 838.5,-592 838.5,-560 687.5,-560"/>
|
||||
<text text-anchor="start" x="718.2685" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3Client</text>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-528 687.5,-560 838.5,-560 838.5,-528 687.5,-528"/>
|
||||
<text text-anchor="start" x="697.432" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="687.5,-496 687.5,-528 838.5,-528 838.5,-496 687.5,-496"/>
|
||||
<text text-anchor="start" x="748.0025" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A12->A13 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A10->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M402.0319,-480.6532C422.1536,-439.0316 443.3588,-395.1687 459.3606,-362.0691"/>
|
||||
<polygon fill="none" stroke="#000000" points="398.824,-479.2474 397.6226,-489.7739 405.1262,-482.2941 398.824,-479.2474"/>
|
||||
</g>
|
||||
<!-- A10->A9 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A10->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M281.2511,-480.6532C262.5076,-439.0316 242.7548,-395.1687 227.849,-362.0691"/>
|
||||
<polygon fill="none" stroke="#000000" points="278.0609,-482.0929 285.3584,-489.7739 284.4435,-479.2186 278.0609,-482.0929"/>
|
||||
</g>
|
||||
<!-- A11->A12 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A11->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M622.3544,-225.9369C611.8702,-195.3687 600.1133,-161.0894 590.181,-132.1301"/>
|
||||
<polygon fill="none" stroke="#000000" points="619.1547,-227.3962 625.7097,-235.7198 625.7761,-225.1252 619.1547,-227.3962"/>
|
||||
</g>
|
||||
<!-- A11->A13 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A11->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M622.0673,-226.7211C613.147,-210.1001 601.7805,-194.0346 587.5,-182 538.0407,-140.3192 358.189,-98.0533 263.2057,-77.9953"/>
|
||||
<polygon fill="none" stroke="#000000" points="619.1257,-228.6587 626.7743,-235.9901 625.367,-225.4892 619.1257,-228.6587"/>
|
||||
<title>A12->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M762.5,-781.767C762.5,-726.3695 762.5,-644.0054 762.5,-592.1957"/>
|
||||
<polygon fill="none" stroke="#000000" points="759.0001,-781.7837 762.5,-791.7837 766.0001,-781.7837 759.0001,-781.7837"/>
|
||||
</g>
|
||||
<!-- A14 -->
|
||||
<g id="node15" class="node">
|
||||
<title>A14</title>
|
||||
<polygon fill="none" stroke="#000000" points="178.5,-1320 178.5,-1352 281.5,-1352 281.5,-1320 178.5,-1320"/>
|
||||
<text text-anchor="start" x="219.162" y="-1333" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="178.5,-1264 178.5,-1320 281.5,-1320 281.5,-1264 178.5,-1264"/>
|
||||
<text text-anchor="start" x="221.9415" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="197.486" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="211.1035" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="178.5,-1112 178.5,-1264 281.5,-1264 281.5,-1112 178.5,-1112"/>
|
||||
<text text-anchor="start" x="205.8355" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="203.8845" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="200.8305" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="199.1605" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="197.21" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="212.213" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="204.994" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="206.3745" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="190.537" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="199.9855" y="-1137" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="188.3225" y="-1125" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
<polygon fill="none" stroke="#000000" points="466.5,-324 466.5,-356 617.5,-356 617.5,-324 466.5,-324"/>
|
||||
<text text-anchor="start" x="495.323" y="-337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3Server</text>
|
||||
<polygon fill="none" stroke="#000000" points="466.5,-292 466.5,-324 617.5,-324 617.5,-292 466.5,-292"/>
|
||||
<text text-anchor="start" x="476.432" y="-305" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="466.5,-248 466.5,-292 617.5,-292 617.5,-248 466.5,-248"/>
|
||||
<text text-anchor="start" x="527.0025" y="-261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A12->A14 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A12->A14</title>
|
||||
<path fill="none" stroke="#000000" d="M745.971,-781.9742C732.8528,-744.797 711.2028,-697.74 678.5,-666 639.382,-628.0337 597.9598,-660.5189 566.5,-616 537.8593,-575.4705 537.2638,-434.5757 539.3427,-356.0029"/>
|
||||
<polygon fill="none" stroke="#000000" points="742.7431,-783.3525 749.2852,-791.6862 749.368,-781.0917 742.7431,-783.3525"/>
|
||||
</g>
|
||||
<!-- A13->A11 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A13->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M765.7562,-483.9177C768.3319,-411.4858 768.4508,-286.4642 746.5,-182 742.3769,-162.3782 735.3279,-141.7356 728.0167,-123.3919"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="765.7548,-483.9554 769.5185,-490.1064 765.2883,-495.9463 761.5246,-489.7953 765.7548,-483.9554"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="724.1836,-114.0264 732.1361,-121.5768 726.0775,-118.6539 727.9715,-123.2813 727.9715,-123.2813 727.9715,-123.2813 726.0775,-118.6539 723.8068,-124.9858 724.1836,-114.0264 724.1836,-114.0264"/>
|
||||
<text text-anchor="middle" x="738.872" y="-124.6003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A13->A14 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A13->A14</title>
|
||||
<path fill="none" stroke="#000000" d="M698.7055,-489.1877C669.7319,-463.8077 639.1408,-436.1834 626.5,-422 608.4095,-401.7018 590.66,-377.5241 576.0987,-356.2077"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="706.4202,-495.9268 695.9285,-492.737 702.6546,-492.6374 698.889,-489.348 698.889,-489.348 698.889,-489.348 702.6546,-492.6374 701.8495,-485.9589 706.4202,-495.9268 706.4202,-495.9268"/>
|
||||
</g>
|
||||
<!-- A14->A3 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A14->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M490.0309,-240.027C462.4537,-206.8219 428.4748,-165.9084 400.3932,-132.0959"/>
|
||||
<polygon fill="none" stroke="#000000" points="487.4521,-242.4001 496.5336,-247.8568 492.8371,-237.9278 487.4521,-242.4001"/>
|
||||
</g>
|
||||
<!-- A14->A10 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A14->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M537.0108,-235.7838C535.0371,-206.6727 532.7079,-172.3163 530.6628,-142.1514"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="537.0175,-235.8843 541.4142,-241.6 537.8293,-247.8568 533.4325,-242.1412 537.0175,-235.8843"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="529.9811,-132.0959 535.1473,-141.7686 530.3193,-137.0845 530.6576,-142.073 530.6576,-142.073 530.6576,-142.073 530.3193,-137.0845 526.1679,-142.3774 529.9811,-132.0959 529.9811,-132.0959"/>
|
||||
<text text-anchor="middle" x="539.6402" y="-146.6088" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="431.5,-940 431.5,-972 498.5,-972 498.5,-940 431.5,-940"/>
|
||||
<text text-anchor="start" x="447.493" y="-953" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="431.5,-920 431.5,-940 498.5,-940 498.5,-920 431.5,-920"/>
|
||||
<polygon fill="none" stroke="#000000" points="431.5,-876 431.5,-920 498.5,-920 498.5,-876 431.5,-876"/>
|
||||
<text text-anchor="start" x="441.384" y="-901" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="449.168" y="-889" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A14->A15 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A14->A15</title>
|
||||
<path fill="none" stroke="#000000" d="M287.6238,-1123.7067C291.4001,-1119.5529 295.359,-1115.6229 299.5,-1112 342.985,-1073.9563 380.3024,-1104.4478 419.5,-1062 442.1524,-1037.4693 453.4109,-1001.3633 459.0018,-972.2357"/>
|
||||
<polygon fill="none" stroke="#000000" points="284.8741,-1121.5366 281.0238,-1131.4071 290.1891,-1126.0921 284.8741,-1121.5366"/>
|
||||
<polygon fill="none" stroke="#000000" points="292.5,-862 292.5,-894 449.5,-894 449.5,-862 292.5,-862"/>
|
||||
<text text-anchor="start" x="335.711" y="-875" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="292.5,-830 292.5,-862 449.5,-862 449.5,-830 292.5,-830"/>
|
||||
<text text-anchor="start" x="302.0975" y="-843" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="292.5,-786 292.5,-830 449.5,-830 449.5,-786 292.5,-786"/>
|
||||
<text text-anchor="start" x="351.554" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="356.0025" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A16 -->
|
||||
<g id="node17" class="node">
|
||||
<title>A16</title>
|
||||
<polygon fill="none" stroke="#000000" points="187.5,-940 187.5,-972 254.5,-972 254.5,-940 187.5,-940"/>
|
||||
<text text-anchor="start" x="200.1585" y="-953" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="187.5,-920 187.5,-940 254.5,-940 254.5,-920 187.5,-920"/>
|
||||
<polygon fill="none" stroke="#000000" points="187.5,-876 187.5,-920 254.5,-920 254.5,-876 187.5,-876"/>
|
||||
<text text-anchor="start" x="197.384" y="-901" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="205.168" y="-889" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
<polygon fill="none" stroke="#000000" points="359.5,-560 359.5,-592 516.5,-592 516.5,-560 359.5,-560"/>
|
||||
<text text-anchor="start" x="389.934" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3PClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="359.5,-528 359.5,-560 516.5,-560 516.5,-528 359.5,-528"/>
|
||||
<text text-anchor="start" x="369.0975" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="359.5,-496 359.5,-528 516.5,-528 516.5,-496 359.5,-496"/>
|
||||
<text text-anchor="start" x="423.0025" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A14->A16 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>A14->A16</title>
|
||||
<path fill="none" stroke="#000000" d="M225.6878,-1101.5366C224.3454,-1055.5988 222.9195,-1006.7991 221.9029,-972.012"/>
|
||||
<polygon fill="none" stroke="#000000" points="222.191,-1101.7024 225.9817,-1111.5959 229.188,-1101.4979 222.191,-1101.7024"/>
|
||||
</g>
|
||||
<!-- A15->A6 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>A15->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M465.7237,-875.9684C466.6086,-841.2366 467.8512,-792.4655 469.031,-746.1572"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="469.2896,-736.0098 473.5333,-746.1212 469.1622,-741.0082 469.0348,-746.0066 469.0348,-746.0066 469.0348,-746.0066 469.1622,-741.0082 464.5362,-745.8919 469.2896,-736.0098 469.2896,-736.0098"/>
|
||||
</g>
|
||||
<!-- A16->A7 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>A16->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M220.0411,-875.9684C219.6216,-832.0581 218.9877,-765.7079 218.4579,-710.2644"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="218.3603,-700.0467 222.9557,-710.0032 218.4081,-705.0465 218.456,-710.0463 218.456,-710.0463 218.456,-710.0463 218.4081,-705.0465 213.9562,-710.0893 218.3603,-700.0467 218.3603,-700.0467"/>
|
||||
<!-- A15->A16 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A15->A16</title>
|
||||
<path fill="none" stroke="#000000" d="M385.0601,-775.6747C397.5656,-720.4264 415.3156,-642.0086 426.6189,-592.0719"/>
|
||||
<polygon fill="none" stroke="#000000" points="381.5829,-775.1831 382.7888,-785.709 388.4102,-776.7285 381.5829,-775.1831"/>
|
||||
</g>
|
||||
<!-- A17 -->
|
||||
<g id="node18" class="node">
|
||||
<title>A17</title>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-336 .5,-368 107.5,-368 107.5,-336 .5,-336"/>
|
||||
<text text-anchor="start" x="24.2695" y="-349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusConn</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-268 .5,-336 107.5,-336 107.5,-268 .5,-268"/>
|
||||
<text text-anchor="start" x="44.5515" y="-317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">host</text>
|
||||
<text text-anchor="start" x="45.387" y="-305" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">port</text>
|
||||
<text text-anchor="start" x="43.997" y="-293" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="10.383" y="-281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-248 .5,-268 107.5,-268 107.5,-248 .5,-248"/>
|
||||
<polygon fill="none" stroke="#000000" points="252.5,-324 252.5,-356 409.5,-356 409.5,-324 252.5,-324"/>
|
||||
<text text-anchor="start" x="280.9885" y="-337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ConnectionG3PServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="252.5,-292 252.5,-324 409.5,-324 409.5,-292 252.5,-292"/>
|
||||
<text text-anchor="start" x="262.0975" y="-305" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote.stream:ConnectionG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="252.5,-248 252.5,-292 409.5,-292 409.5,-248 252.5,-248"/>
|
||||
<text text-anchor="start" x="316.0025" y="-261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A17->A13 -->
|
||||
<!-- A15->A17 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A15->A17</title>
|
||||
<path fill="none" stroke="#000000" d="M363.8918,-775.579C359.4421,-730.8408 353.651,-669.833 349.5,-616 342.4777,-524.9291 336.5213,-418.8313 333.2353,-356.213"/>
|
||||
<polygon fill="none" stroke="#000000" points="360.4287,-776.124 364.9058,-785.7264 367.394,-775.4279 360.4287,-776.124"/>
|
||||
</g>
|
||||
<!-- A16->A11 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A16->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M432.5814,-483.65C426.5012,-392.955 420.8979,-227.2936 456.5,-182 504.3791,-121.0873 555.3805,-168.9121 623.5,-132 629.8263,-128.572 636.106,-124.5733 642.1952,-120.2709"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="432.5842,-483.6913 436.9918,-489.3986 433.4189,-495.6623 429.0112,-489.955 432.5842,-483.6913"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="650.3668,-114.2407 644.9924,-123.7993 646.3436,-117.2096 642.3205,-120.1784 642.3205,-120.1784 642.3205,-120.1784 646.3436,-117.2096 639.6485,-116.5576 650.3668,-114.2407 650.3668,-114.2407"/>
|
||||
<text text-anchor="middle" x="640.8006" y="-128.8045" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A16->A17 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A16->A17</title>
|
||||
<path fill="none" stroke="#000000" d="M412.1504,-486.6673C394.7061,-447.2138 371.6786,-395.1329 354.5264,-356.3401"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="416.2323,-495.8992 408.0728,-488.5731 414.2104,-491.3263 412.1884,-486.7533 412.1884,-486.7533 412.1884,-486.7533 414.2104,-491.3263 416.3041,-484.9336 416.2323,-495.8992 416.2323,-495.8992"/>
|
||||
</g>
|
||||
<!-- A17->A4 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>A17->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M290.2801,-239.1397C267.862,-204.1022 240.0902,-160.6973 217.9615,-126.112"/>
|
||||
<polygon fill="none" stroke="#000000" points="287.5198,-241.3198 295.8575,-247.8568 293.4162,-237.5471 287.5198,-241.3198"/>
|
||||
</g>
|
||||
<!-- A17->A10 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>A17->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M378.7264,-238.2577C392.9202,-219.9137 408.6333,-200.0024 423.5,-182 434.8823,-168.217 447.2524,-153.7473 459.3242,-139.8828"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="378.561,-238.4723 378.0657,-245.6664 371.2345,-247.9761 371.7298,-240.782 378.561,-238.4723"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="465.9919,-132.2508 462.8014,-142.7423 462.7022,-136.0162 459.4126,-139.7816 459.4126,-139.7816 459.4126,-139.7816 462.7022,-136.0162 456.0237,-136.8209 465.9919,-132.2508 465.9919,-132.2508"/>
|
||||
<text text-anchor="middle" x="460.4315" y="-148.4623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A18 -->
|
||||
<g id="node19" class="node">
|
||||
<title>A18</title>
|
||||
<polygon fill="none" stroke="#000000" points="255.5,-1278 255.5,-1310 358.5,-1310 358.5,-1278 255.5,-1278"/>
|
||||
<text text-anchor="start" x="296.162" y="-1291" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="255.5,-1222 255.5,-1278 358.5,-1278 358.5,-1222 255.5,-1222"/>
|
||||
<text text-anchor="start" x="298.9415" y="-1259" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="274.486" y="-1247" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="288.1035" y="-1235" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="255.5,-1070 255.5,-1222 358.5,-1222 358.5,-1070 255.5,-1070"/>
|
||||
<text text-anchor="start" x="282.8355" y="-1203" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="280.8845" y="-1191" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="277.8305" y="-1179" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="276.1605" y="-1167" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="274.21" y="-1155" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="289.213" y="-1143" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="281.994" y="-1131" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="283.3745" y="-1119" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="267.537" y="-1107" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="276.9855" y="-1095" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="265.3225" y="-1083" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A19 -->
|
||||
<g id="node20" class="node">
|
||||
<title>A19</title>
|
||||
<polygon fill="none" stroke="#000000" points="467.5,-856 467.5,-888 534.5,-888 534.5,-856 467.5,-856"/>
|
||||
<text text-anchor="start" x="483.493" y="-869" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="467.5,-836 467.5,-856 534.5,-856 534.5,-836 467.5,-836"/>
|
||||
<polygon fill="none" stroke="#000000" points="467.5,-792 467.5,-836 534.5,-836 534.5,-792 467.5,-792"/>
|
||||
<text text-anchor="start" x="477.384" y="-817" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="485.168" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A18->A19 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>A18->A19</title>
|
||||
<path fill="none" stroke="#000000" d="M364.1135,-1079.5989C368.3725,-1074.1218 372.8381,-1068.8788 377.5,-1064 406.4667,-1033.6857 432.8916,-1047.9478 457.5,-1014 484.2551,-977.0907 494.4701,-925.4423 498.3138,-888.0116"/>
|
||||
<polygon fill="none" stroke="#000000" points="361.1895,-1077.6653 358.0224,-1087.7757 366.8031,-1081.8471 361.1895,-1077.6653"/>
|
||||
</g>
|
||||
<!-- A20 -->
|
||||
<g id="node21" class="node">
|
||||
<title>A20</title>
|
||||
<polygon fill="none" stroke="#000000" points="207.5,-856 207.5,-888 274.5,-888 274.5,-856 207.5,-856"/>
|
||||
<text text-anchor="start" x="220.1585" y="-869" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="207.5,-836 207.5,-856 274.5,-856 274.5,-836 207.5,-836"/>
|
||||
<polygon fill="none" stroke="#000000" points="207.5,-792 207.5,-836 274.5,-836 274.5,-792 207.5,-792"/>
|
||||
<text text-anchor="start" x="217.384" y="-817" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="225.168" y="-805" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A18->A20 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>A17->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M80.8473,-247.8342C91.2165,-226.5814 103.6422,-202.8044 116.5,-182 126.2708,-166.1905 137.6417,-149.852 148.8772,-134.6044"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="155.0942,-126.2561 152.7306,-136.9642 152.1078,-130.2663 149.1214,-134.2765 149.1214,-134.2765 149.1214,-134.2765 152.1078,-130.2663 145.5123,-131.5887 155.0942,-126.2561 155.0942,-126.2561"/>
|
||||
<text text-anchor="middle" x="151.047" y="-142.8423" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
<text text-anchor="middle" x="81.2636" y="-224.8385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<title>A18->A20</title>
|
||||
<path fill="none" stroke="#000000" d="M281.9132,-1059.6156C270.6119,-999.6842 257.9,-932.2726 249.5769,-888.1352"/>
|
||||
<polygon fill="none" stroke="#000000" points="278.494,-1060.3716 283.7865,-1069.5499 285.3728,-1059.0744 278.494,-1060.3716"/>
|
||||
</g>
|
||||
<!-- A21->A7 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>A21->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M575.3563,-1063.642C577.3669,-1050.8472 579.4367,-1037.6756 581.5179,-1024.4317"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="583.1108,-1014.295 586.0038,-1024.8724 582.3345,-1019.2344 581.5583,-1024.1738 581.5583,-1024.1738 581.5583,-1024.1738 582.3345,-1019.2344 577.1129,-1023.4752 583.1108,-1014.295 583.1108,-1014.295"/>
|
||||
<text text-anchor="middle" x="569.8202" y="-1041.4234" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A21->A12 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>A21->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M618.6601,-1105.4878C638.7912,-1077.0562 660.4946,-1044.7401 678.5,-1014 702.5743,-972.8987 725.7861,-923.8582 741.6852,-888.3319"/>
|
||||
<polygon fill="none" stroke="#000000" points="615.6988,-1103.6125 612.7495,-1113.7886 621.4009,-1107.6728 615.6988,-1103.6125"/>
|
||||
</g>
|
||||
<!-- A21->A19 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>A21->A19</title>
|
||||
<path fill="none" stroke="#000000" d="M535.6437,-1063.642C526.7659,-1007.1466 516.7335,-943.3043 509.6671,-898.3363"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="508.0718,-888.1839 514.0697,-897.3641 508.848,-893.1233 509.6242,-898.0627 509.6242,-898.0627 509.6242,-898.0627 508.848,-893.1233 505.1788,-898.7613 508.0718,-888.1839 508.0718,-888.1839"/>
|
||||
</g>
|
||||
<!-- A22->A7 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>A22->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M468.0427,-1099.8226C474.4445,-1087.349 481.6217,-1075.043 489.5,-1064 508.3074,-1037.6376 524.3881,-1040.8449 542.5,-1014 543.9285,-1011.8827 545.3335,-1009.731 546.715,-1007.5491"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="551.9277,-998.9917 550.5685,-1009.873 549.3265,-1003.2618 546.7254,-1007.532 546.7254,-1007.532 546.7254,-1007.532 549.3265,-1003.2618 542.8822,-1005.1909 551.9277,-998.9917 551.9277,-998.9917"/>
|
||||
<text text-anchor="middle" x="468.9105" y="-1076.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A22->A15 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>A22->A15</title>
|
||||
<path fill="none" stroke="#000000" d="M414.749,-1089.7927C403.4687,-1026.1139 389.3056,-946.1607 380.0853,-894.1104"/>
|
||||
<polygon fill="none" stroke="#000000" points="411.3428,-1090.6301 416.5335,-1099.8663 418.2355,-1089.4091 411.3428,-1090.6301"/>
|
||||
</g>
|
||||
<!-- A22->A20 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>A22->A20</title>
|
||||
<path fill="none" stroke="#000000" d="M393.1989,-1099.7863C385.4244,-1086.9738 376.5183,-1074.5787 366.5,-1064 336.6255,-1032.4545 308.2844,-1048.9681 282.5,-1014 257.8033,-980.507 247.4516,-934.4437 243.1951,-898.1251"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="242.1493,-888.1583 247.6684,-897.6341 242.6711,-893.131 243.1929,-898.1037 243.1929,-898.1037 243.1929,-898.1037 242.6711,-893.131 238.7175,-898.5734 242.1493,-888.1583 242.1493,-888.1583"/>
|
||||
</g>
|
||||
<!-- A23 -->
|
||||
<g id="node24" class="node">
|
||||
<title>A23</title>
|
||||
<polygon fill="none" stroke="#000000" points="395.5,-1598 395.5,-1630 470.5,-1630 470.5,-1598 395.5,-1598"/>
|
||||
<text text-anchor="start" x="415.2175" y="-1611" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="395.5,-1446 395.5,-1598 470.5,-1598 470.5,-1446 395.5,-1446"/>
|
||||
<text text-anchor="start" x="424.6615" y="-1579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="405.49" y="-1555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="406.605" y="-1543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="416.6085" y="-1531" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="406.8895" y="-1519" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="414.942" y="-1507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="426.8915" y="-1495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="413.5535" y="-1483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="411.879" y="-1471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="426.3365" y="-1459" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="395.5,-1378 395.5,-1446 470.5,-1446 470.5,-1378 395.5,-1378"/>
|
||||
<text text-anchor="start" x="406.89" y="-1427" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="410.224" y="-1415" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="407.724" y="-1403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="418.0025" y="-1391" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A23->A21 -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>A23->A21</title>
|
||||
<path fill="none" stroke="#000000" d="M473.6171,-1381.5836C475.5712,-1376.3055 477.537,-1371.0921 479.5,-1366 485.7253,-1349.8514 492.5573,-1333.0014 499.4927,-1316.4014"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="470.1153,-1391.1417 469.3301,-1380.2039 471.8353,-1386.4468 473.5554,-1381.752 473.5554,-1381.752 473.5554,-1381.752 471.8353,-1386.4468 477.7808,-1383.3 470.1153,-1391.1417 470.1153,-1391.1417"/>
|
||||
<text text-anchor="middle" x="500.3258" y="-1333.384" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="468.4143" y="-1368.2141" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A23->A22 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>A23->A22</title>
|
||||
<path fill="none" stroke="#000000" d="M432.5,-1367.2886C432.5,-1337.886 432.5,-1307.5179 432.5,-1280.403"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="432.5,-1377.6415 428.0001,-1367.6414 432.5,-1372.6415 432.5001,-1367.6415 432.5001,-1367.6415 432.5001,-1367.6415 432.5,-1372.6415 437.0001,-1367.6415 432.5,-1377.6415 432.5,-1377.6415"/>
|
||||
<text text-anchor="middle" x="440.9524" y="-1295.5292" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="424.0476" y="-1356.5153" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
</g>
|
||||
<!-- A24 -->
|
||||
<g id="node25" class="node">
|
||||
<title>A24</title>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-330 .5,-362 107.5,-362 107.5,-330 .5,-330"/>
|
||||
<text text-anchor="start" x="24.2695" y="-343" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ModbusConn</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-262 .5,-330 107.5,-330 107.5,-262 .5,-262"/>
|
||||
<text text-anchor="start" x="44.5515" y="-311" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">host</text>
|
||||
<text text-anchor="start" x="45.387" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">port</text>
|
||||
<text text-anchor="start" x="43.997" y="-287" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="10.383" y="-275" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stream:InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points=".5,-242 .5,-262 107.5,-262 107.5,-242 .5,-242"/>
|
||||
</g>
|
||||
<!-- A24->A4 -->
|
||||
<g id="edge33" class="edge">
|
||||
<title>A24->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M84.8997,-241.788C94.9393,-222.6449 106.1365,-201.4067 116.5,-182 124.6218,-166.7911 133.4111,-150.5028 141.774,-135.0831"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="146.6405,-126.1193 145.824,-137.0548 144.2548,-130.5135 141.8692,-134.9077 141.8692,-134.9077 141.8692,-134.9077 144.2548,-130.5135 137.9144,-132.7607 146.6405,-126.1193 146.6405,-126.1193"/>
|
||||
<text text-anchor="middle" x="145.4203" y="-143.0821" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">1</text>
|
||||
<text text-anchor="middle" x="85.8379" y="-218.81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 49 KiB |
@@ -3,28 +3,65 @@
|
||||
// {generate:true}
|
||||
|
||||
[note: You can stick notes on diagrams too!{bg:cornsilk}]
|
||||
[Singleton]^[Mqtt|<static>ha_restarts;<static>__client;<static>__cb_MqttIsUp|<async>publish();<async>close()]
|
||||
[Modbus|que;;snd_handler;rsp_handler;timeout;max_retires;last_xxx;err;retry_cnt;req_pend;tim|build_msg();recv_req();recv_resp();close()]
|
||||
[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]
|
||||
[Message]^[Talent|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();;close()]
|
||||
[Message]^[SolarmanV5|control;serial;snr;db:InfosG3P;mb:Modbus;switch|msg_unknown();;close()]
|
||||
[Talent]^[ConnectionG3|remote_stream:ConnectionG3|healthy();close()]
|
||||
[Talent]has-1>[Modbus]
|
||||
[SolarmanV5]^[ConnectionG3P|remote_stream:ConnectionG3P|healthy();close()]
|
||||
[SolarmanV5]has-1>[Modbus]
|
||||
[AsyncStream|reader;writer;addr;r_addr;l_addr|<async>server_loop();<async>client_loop();<async>loop;disc();close();;__async_read();async_write();__async_forward()]^[ConnectionG3]
|
||||
[AsyncStream]^[ConnectionG3P]
|
||||
[Inverter|cls.db_stat;cls.entity_prfx;cls.discovery_prfx;cls.proxy_node_id;cls.proxy_unique_id;cls.mqtt:Mqtt|]^[InverterG3|__ha_restarts|async_create_remote();async_publ_mqtt();;close()]
|
||||
[Inverter]^[InverterG3P|__ha_restarts|async_create_remote(;)async_publ_mqtt();close()]
|
||||
[Mqtt]-[Inverter]
|
||||
[ConnectionG3]^[InverterG3]
|
||||
[ConnectionG3]has-0..1>[ConnectionG3]
|
||||
[ConnectionG3P]^[InverterG3P]
|
||||
[ConnectionG3P]has-0..1>[ConnectionG3P]
|
||||
|
||||
[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]^[InfosG3||ha_confs();parse()]
|
||||
[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|]
|
||||
[Inverter]^[InverterG3|__ha_restarts|async_create_remote();async_publ_mqtt();;close()]
|
||||
[Inverter]^[InverterG3P|__ha_restarts|async_create_remote(;)async_publ_mqtt();close()]
|
||||
[Mqtt;<<Singleton>>]<-++[Inverter]
|
||||
|
||||
[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]
|
||||
|
||||
[<<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]
|
||||
|
||||
|
||||
[ConnectionG3|remote.stream:ConnectionG3|healthy()]
|
||||
[ConnectionG3Client|remote.stream:ConnectionG3|close()]
|
||||
[ConnectionG3Server|remote.stream:ConnectionG3|;close()]
|
||||
[ConnectionG3]^[ConnectionG3Client]
|
||||
[ConnectionG3]^[ConnectionG3Server]
|
||||
[ConnectionG3Client]<-[ConnectionG3Server]
|
||||
[ConnectionG3Client]++-1>[AsyncStreamClient]
|
||||
[ConnectionG3Server]^[InverterG3]
|
||||
[ConnectionG3Server]++-1>[AsyncStreamServer]
|
||||
|
||||
[ConnectionG3P|remote.stream:ConnectionG3P|healthy();close()]
|
||||
[ConnectionG3PClient|remote.stream:ConnectionG3P|close()]
|
||||
[ConnectionG3PServer|remote.stream:ConnectionG3P|;close()]
|
||||
[ConnectionG3P]^[ConnectionG3PClient]
|
||||
[ConnectionG3P]^[ConnectionG3PServer]
|
||||
[ConnectionG3PClient]<-[ConnectionG3PServer]
|
||||
[ConnectionG3PClient]++-1>[AsyncStreamClient]
|
||||
[ConnectionG3PServer]^[InverterG3P]
|
||||
[ConnectionG3PServer]++-1>[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()]
|
||||
[InfosG3P]->[SolarmanV5]
|
||||
[InfosG3]->[Talent]
|
||||
|
||||
[Talent|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();;close()]
|
||||
[Talent]^[ConnectionG3]
|
||||
[Talent]use->[<<AsyncIfc>>]
|
||||
[Talent]->[InfosG3]
|
||||
[SolarmanV5|control;serial;snr;db:InfosG3P;mb:Modbus;switch|msg_unknown();;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]
|
||||
|
||||
|
||||
@@ -1,11 +1,119 @@
|
||||
if __name__ == "app.src.async_ifc":
|
||||
from app.src.byte_fifo import ByteFifo
|
||||
else: # pragma: no cover
|
||||
from byte_fifo import ByteFifo
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class AsyncIfc():
|
||||
def __init__(self):
|
||||
self.read = ByteFifo()
|
||||
self.write = ByteFifo()
|
||||
self.forward = ByteFifo()
|
||||
class AsyncIfc(ABC):
|
||||
@abstractmethod
|
||||
def get_conn_no(self):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def set_node_id(self, value: str):
|
||||
pass # pragma: no cover
|
||||
|
||||
#
|
||||
# TX - QUEUE
|
||||
#
|
||||
@abstractmethod
|
||||
def tx_add(self, data: bytearray):
|
||||
''' add data to transmit queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_flush(self):
|
||||
''' send transmit queue and clears it'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_get(self, size: int = None) -> bytearray:
|
||||
'''removes size numbers of bytes and return them'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_peek(self, size: int = None) -> bytearray:
|
||||
'''returns size numbers of byte without removing them'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_log(self, level, info):
|
||||
''' log the transmit queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_clear(self):
|
||||
''' clear transmit queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def tx_len(self):
|
||||
''' get numner of bytes in the transmit queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
#
|
||||
# FORWARD - QUEUE
|
||||
#
|
||||
@abstractmethod
|
||||
def fwd_add(self, data: bytearray):
|
||||
''' 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
|
||||
#
|
||||
@abstractmethod
|
||||
def rx_get(self, size: int = None) -> bytearray:
|
||||
'''removes size numbers of bytes and return them'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def rx_peek(self, size: int = None) -> bytearray:
|
||||
'''returns size numbers of byte without removing them'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def rx_log(self, level, info):
|
||||
''' logs the receive queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def rx_clear(self):
|
||||
''' clear receive queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def rx_len(self):
|
||||
''' get numner of bytes in the receive queue'''
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def rx_set_cb(self, callback):
|
||||
pass # pragma: no cover
|
||||
|
||||
#
|
||||
# Protocol Callbacks
|
||||
#
|
||||
@abstractmethod
|
||||
def prot_set_timeout_cb(self, callback):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def prot_set_init_new_client_conn_cb(self, callback):
|
||||
pass # pragma: no cover
|
||||
|
||||
@abstractmethod
|
||||
def prot_set_update_header_cb(self, callback):
|
||||
pass # pragma: no cover
|
||||
|
||||
@@ -7,19 +7,147 @@ from typing import Self
|
||||
from itertools import count
|
||||
|
||||
if __name__ == "app.src.async_stream":
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.byte_fifo import ByteFifo
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.messages import hex_dump_memory, State
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from inverter import Inverter
|
||||
from byte_fifo import ByteFifo
|
||||
from async_ifc import AsyncIfc
|
||||
from messages import hex_dump_memory, State
|
||||
from infos import Infos
|
||||
|
||||
|
||||
import gc
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
|
||||
class AsyncStream():
|
||||
class AsyncIfcImpl(AsyncIfc):
|
||||
_ids = count(0)
|
||||
|
||||
def __init__(self) -> None:
|
||||
logger.debug('AsyncIfcImpl.__init__')
|
||||
self.fwd_fifo = ByteFifo()
|
||||
self.tx_fifo = ByteFifo()
|
||||
self.rx_fifo = ByteFifo()
|
||||
self.conn_no = next(self._ids)
|
||||
self.node_id = ''
|
||||
self.timeout_cb = None
|
||||
self.init_new_client_conn_cb = None
|
||||
self.update_header_cb = None
|
||||
|
||||
def close(self):
|
||||
self.timeout_cb = None
|
||||
self.fwd_fifo.reg_trigger(None)
|
||||
self.tx_fifo.reg_trigger(None)
|
||||
self.rx_fifo.reg_trigger(None)
|
||||
|
||||
def set_node_id(self, value: str):
|
||||
self.node_id = value
|
||||
|
||||
def get_conn_no(self):
|
||||
return self.conn_no
|
||||
|
||||
def tx_add(self, data: bytearray):
|
||||
''' add data to transmit queue'''
|
||||
self.tx_fifo += data
|
||||
|
||||
def tx_flush(self):
|
||||
''' send transmit queue and clears it'''
|
||||
self.tx_fifo()
|
||||
|
||||
def tx_get(self, size: int = None) -> bytearray:
|
||||
'''removes size numbers of bytes and return them'''
|
||||
return self.tx_fifo.get(size)
|
||||
|
||||
def tx_peek(self, size: int = None) -> bytearray:
|
||||
'''returns size numbers of byte without removing them'''
|
||||
return self.tx_fifo.peek(size)
|
||||
|
||||
def tx_log(self, level, info):
|
||||
''' log the transmit queue'''
|
||||
self.tx_fifo.logging(level, info)
|
||||
|
||||
def tx_clear(self):
|
||||
''' clear transmit queue'''
|
||||
self.tx_fifo.clear()
|
||||
|
||||
def tx_len(self):
|
||||
''' get numner of bytes in the transmit queue'''
|
||||
return len(self.tx_fifo)
|
||||
|
||||
def fwd_add(self, data: bytearray):
|
||||
''' 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)
|
||||
|
||||
def rx_peek(self, size: int = None) -> bytearray:
|
||||
'''returns size numbers of byte without removing them'''
|
||||
return self.rx_fifo.peek(size)
|
||||
|
||||
def rx_log(self, level, info):
|
||||
''' logs the receive queue'''
|
||||
self.rx_fifo.logging(level, info)
|
||||
|
||||
def rx_clear(self):
|
||||
''' clear receive queue'''
|
||||
self.rx_fifo.clear()
|
||||
|
||||
def rx_len(self):
|
||||
''' get numner of bytes in the receive queue'''
|
||||
return len(self.rx_fifo)
|
||||
|
||||
def rx_set_cb(self, callback):
|
||||
self.rx_fifo.reg_trigger(callback)
|
||||
|
||||
def prot_set_timeout_cb(self, callback):
|
||||
self.timeout_cb = callback
|
||||
|
||||
def prot_set_init_new_client_conn_cb(self, callback):
|
||||
self.init_new_client_conn_cb = callback
|
||||
|
||||
def prot_set_update_header_cb(self, callback):
|
||||
self.update_header_cb = callback
|
||||
|
||||
|
||||
class StreamPtr():
|
||||
'''Descr StreamPtr'''
|
||||
def __init__(self, _stream):
|
||||
self.stream = _stream
|
||||
|
||||
@property
|
||||
def ifc(self):
|
||||
return self._ifc
|
||||
|
||||
@property
|
||||
def stream(self):
|
||||
return self._stream
|
||||
|
||||
@stream.setter
|
||||
def stream(self, value):
|
||||
self._stream = value
|
||||
if value:
|
||||
self._ifc = value.ifc
|
||||
else:
|
||||
self._ifc = None
|
||||
|
||||
|
||||
class AsyncStream(AsyncIfcImpl):
|
||||
MAX_PROC_TIME = 2
|
||||
'''maximum processing time for a received msg in sec'''
|
||||
MAX_START_TIME = 400
|
||||
@@ -30,81 +158,29 @@ class AsyncStream():
|
||||
'''maximum default time without a received msg in sec'''
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, ifc: "AsyncIfc") -> None:
|
||||
addr, rstream: "StreamPtr") -> None:
|
||||
AsyncIfcImpl.__init__(self)
|
||||
|
||||
logger.debug('AsyncStream.__init__')
|
||||
ifc.write.reg_trigger(self.__write_cb)
|
||||
self.ifc = ifc
|
||||
|
||||
self.remote = rstream
|
||||
self.tx_fifo.reg_trigger(self.__write_cb)
|
||||
self._reader = reader
|
||||
self._writer = writer
|
||||
self.addr = addr
|
||||
self.r_addr = ''
|
||||
self.l_addr = ''
|
||||
self.conn_no = next(self._ids)
|
||||
self.proc_start = None # start processing start timestamp
|
||||
self.proc_max = 0
|
||||
self.async_publ_mqtt = None # will be set AsyncStreamServer only
|
||||
|
||||
def __write_cb(self):
|
||||
self._writer.write(self.ifc.write.get())
|
||||
self._writer.write(self.tx_fifo.get())
|
||||
|
||||
def __timeout(self) -> int:
|
||||
if self.state == State.init or self.state == State.received:
|
||||
to = self.MAX_START_TIME
|
||||
elif self.state == State.up and \
|
||||
self.server_side and self.modbus_polling:
|
||||
to = self.MAX_INV_IDLE_TIME
|
||||
else:
|
||||
to = self.MAX_DEF_IDLE_TIME
|
||||
return to
|
||||
|
||||
async def publish_outstanding_mqtt(self):
|
||||
'''Publish all outstanding MQTT topics'''
|
||||
try:
|
||||
if self.unique_id:
|
||||
await self.async_publ_mqtt()
|
||||
await self._async_publ_mqtt_proxy_stat('proxy')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def server_loop(self, addr: str) -> None:
|
||||
'''Loop for receiving messages from the inverter (server-side)'''
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
f'Accept connection from {addr}')
|
||||
self.inc_counter('Inverter_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
await self.loop()
|
||||
self.dec_counter('Inverter_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] Server loop stopped for'
|
||||
f' r{self.r_addr}')
|
||||
|
||||
# if the server connection closes, we also have to disconnect
|
||||
# the connection to te TSUN cloud
|
||||
if self.remote_stream:
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] disc client '
|
||||
f'connection: [{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}]')
|
||||
await self.remote_stream.disc()
|
||||
|
||||
async def client_loop(self, _: str) -> None:
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
client_stream = await self.remote_stream.loop()
|
||||
logger.info(f'[{client_stream.node_id}:{client_stream.conn_no}] '
|
||||
'Client loop stopped for'
|
||||
f' l{client_stream.l_addr}')
|
||||
|
||||
# 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
|
||||
|
||||
# erase backlink to inverter
|
||||
client_stream.remote_stream = None
|
||||
|
||||
if self.remote_stream == client_stream:
|
||||
# logging.debug(f'Client l{client_stream.l_addr} refs:'
|
||||
# f' {gc.get_referrers(client_stream)}')
|
||||
# than erase client connection
|
||||
self.remote_stream = None
|
||||
if self.timeout_cb is callable:
|
||||
return self.timeout_cb
|
||||
return 360
|
||||
|
||||
async def loop(self) -> Self:
|
||||
"""Async loop handler for precessing all received messages"""
|
||||
@@ -121,9 +197,9 @@ class AsyncStream():
|
||||
await asyncio.wait_for(self.__async_read(),
|
||||
dead_conn_to)
|
||||
|
||||
if self.unique_id:
|
||||
await self.async_write()
|
||||
await self.__async_forward()
|
||||
await self.__async_write()
|
||||
await self.__async_forward()
|
||||
if self.async_publ_mqtt:
|
||||
await self.async_publ_mqtt()
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
@@ -150,19 +226,12 @@ class AsyncStream():
|
||||
return self
|
||||
|
||||
except Exception:
|
||||
self.inc_counter('SW_Exception')
|
||||
Infos.inc_counter('SW_Exception')
|
||||
logger.error(
|
||||
f"Exception for {self.addr}:\n"
|
||||
f"{traceback.format_exc()}")
|
||||
await asyncio.sleep(0) # be cooperative to other task
|
||||
|
||||
async def async_write(self, headline: str = 'Transmit to ') -> None:
|
||||
"""Async write handler to transmit the send_buffer"""
|
||||
if len(self.ifc.write) > 0:
|
||||
self.ifc.write.logging(logging.INFO, f'{headline}{self.addr}:')
|
||||
self._writer.write(self.ifc.write.get())
|
||||
await self._writer.drain()
|
||||
|
||||
async def disc(self) -> None:
|
||||
"""Async disc handler for graceful disconnect"""
|
||||
if self._writer.is_closing():
|
||||
@@ -176,18 +245,18 @@ class AsyncStream():
|
||||
|
||||
hint: must be called before releasing the connection instance
|
||||
"""
|
||||
super().close()
|
||||
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.ifc.write.reg_trigger(None)
|
||||
self._writer.close()
|
||||
|
||||
def healthy(self) -> bool:
|
||||
elapsed = 0
|
||||
if self.proc_start is not None:
|
||||
elapsed = time.time() - self.proc_start
|
||||
if self.state == State.closed or elapsed > self.MAX_PROC_TIME:
|
||||
if elapsed > self.MAX_PROC_TIME:
|
||||
logging.debug(f'[{self.node_id}:{self.conn_no}:'
|
||||
f'{type(self).__name__}]'
|
||||
f' act:{round(1000*elapsed)}ms'
|
||||
@@ -203,54 +272,47 @@ class AsyncStream():
|
||||
data = await self._reader.read(4096)
|
||||
if data:
|
||||
self.proc_start = time.time()
|
||||
self.ifc.read += data
|
||||
wait = self.ifc.read() # call read in parent class
|
||||
self.rx_fifo += data
|
||||
wait = self.rx_fifo() # call read in parent class
|
||||
if wait > 0:
|
||||
await asyncio.sleep(wait)
|
||||
else:
|
||||
raise RuntimeError("Peer closed.")
|
||||
|
||||
async def __async_write(self, headline: str = 'Transmit to ') -> None:
|
||||
"""Async write handler to transmit the send_buffer"""
|
||||
if len(self.tx_fifo) > 0:
|
||||
self.tx_fifo.logging(logging.INFO, f'{headline}{self.addr}:')
|
||||
self._writer.write(self.tx_fifo.get())
|
||||
await self._writer.drain()
|
||||
|
||||
async def __async_forward(self) -> None:
|
||||
"""forward handler transmits data over the remote connection"""
|
||||
if not self._forward_buffer:
|
||||
if len(self.fwd_fifo) == 0:
|
||||
return
|
||||
try:
|
||||
if not self.remote_stream:
|
||||
await self.async_create_remote()
|
||||
if self.remote_stream:
|
||||
if self.remote_stream._init_new_client_conn():
|
||||
await self.remote_stream.async_write()
|
||||
|
||||
if self.remote_stream:
|
||||
self.remote_stream._update_header(self._forward_buffer)
|
||||
hex_dump_memory(logging.INFO,
|
||||
f'Forward to {self.remote_stream.addr}:',
|
||||
self._forward_buffer,
|
||||
len(self._forward_buffer))
|
||||
self.remote_stream._writer.write(self._forward_buffer)
|
||||
await self.remote_stream._writer.drain()
|
||||
self._forward_buffer = bytearray(0)
|
||||
await self._async_forward()
|
||||
|
||||
except OSError as error:
|
||||
if self.remote_stream:
|
||||
rmt = self.remote_stream
|
||||
self.remote_stream = None
|
||||
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.l_addr} | r{rmt.r_addr}')
|
||||
await rmt.disc()
|
||||
rmt.close()
|
||||
f'l{rmt._ifc.l_addr} | r{rmt._ifc.r_addr}')
|
||||
await rmt._ifc.disc()
|
||||
rmt._ifc.close()
|
||||
|
||||
except RuntimeError as error:
|
||||
if self.remote_stream:
|
||||
rmt = self.remote_stream
|
||||
self.remote_stream = None
|
||||
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.l_addr}')
|
||||
await rmt.disc()
|
||||
rmt.close()
|
||||
f'Fwd: {error} for {rmt._ifc.l_addr}')
|
||||
await rmt._ifc.disc()
|
||||
rmt._ifc.close()
|
||||
|
||||
except Exception:
|
||||
self.inc_counter('SW_Exception')
|
||||
Infos.inc_counter('SW_Exception')
|
||||
logger.error(
|
||||
f"Fwd Exception for {self.addr}:\n"
|
||||
f"{traceback.format_exc()}")
|
||||
@@ -258,3 +320,103 @@ class AsyncStream():
|
||||
def __del__(self):
|
||||
logger.debug(
|
||||
f"AsyncStream.__del__ l{self.l_addr} | r{self.r_addr}")
|
||||
|
||||
|
||||
class AsyncStreamServer(AsyncStream):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, async_publ_mqtt, async_create_remote,
|
||||
rstream: "StreamPtr") -> None:
|
||||
AsyncStream.__init__(self, reader, writer, addr,
|
||||
rstream)
|
||||
self.async_create_remote = async_create_remote
|
||||
self.async_publ_mqtt = async_publ_mqtt
|
||||
|
||||
async def server_loop(self, addr: str) -> None:
|
||||
'''Loop for receiving messages from the inverter (server-side)'''
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
f'Accept connection from {addr}')
|
||||
Infos.inc_counter('Inverter_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
await self.loop()
|
||||
Infos.dec_counter('Inverter_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] Server loop stopped for'
|
||||
f' r{self.r_addr}')
|
||||
|
||||
# if the server connection closes, we also have to disconnect
|
||||
# the connection to te TSUN cloud
|
||||
if 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}]')
|
||||
await self.remote.ifc.disc()
|
||||
|
||||
async def _async_forward(self) -> None:
|
||||
"""forward handler transmits data over the remote connection"""
|
||||
if not self.remote.stream:
|
||||
await self.async_create_remote()
|
||||
if self.remote.stream and \
|
||||
self.remote.ifc.init_new_client_conn_cb():
|
||||
await self.remote.ifc._AsyncStream__async_write()
|
||||
if self.remote.stream:
|
||||
self.remote.ifc.update_header_cb(self.fwd_fifo.peek())
|
||||
self.fwd_fifo.logging(logging.INFO, 'Forward to '
|
||||
f'{self.remote.ifc.addr}:')
|
||||
self.remote.ifc._writer.write(self.fwd_fifo.get())
|
||||
await self.remote.ifc._writer.drain()
|
||||
|
||||
async def publish_outstanding_mqtt(self):
|
||||
'''Publish all outstanding MQTT topics'''
|
||||
try:
|
||||
await self.async_publ_mqtt()
|
||||
await Inverter._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,
|
||||
addr, rstream: "StreamPtr") -> None:
|
||||
AsyncStream.__init__(self, reader, writer, addr,
|
||||
rstream)
|
||||
|
||||
async def client_loop(self, _: str) -> None:
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
await self.loop()
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
'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
|
||||
|
||||
async def _async_forward(self) -> None:
|
||||
"""forward handler transmits data over the remote connection"""
|
||||
if self.remote.stream:
|
||||
self.remote.ifc.update_header_cb(self.fwd_fifo.peek())
|
||||
self.fwd_fifo.logging(logging.INFO, 'Forward to '
|
||||
f'{self.remote.ifc.addr}:')
|
||||
self.remote.ifc._writer.write(self.fwd_fifo.get())
|
||||
await self.remote.ifc._writer.drain()
|
||||
|
||||
@@ -2,36 +2,18 @@ import logging
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.gen3.connection_g3":
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.async_stream import AsyncStream
|
||||
from app.src.async_stream import AsyncStreamServer
|
||||
from app.src.async_stream import AsyncStreamClient, StreamPtr
|
||||
from app.src.gen3.talent import Talent
|
||||
else: # pragma: no cover
|
||||
from async_ifc import AsyncIfc
|
||||
from async_stream import AsyncStream
|
||||
from async_stream import AsyncStreamServer
|
||||
from async_stream import AsyncStreamClient, StreamPtr
|
||||
from gen3.talent import Talent
|
||||
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
|
||||
class ConnectionG3(AsyncStream, Talent):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, remote_stream: 'ConnectionG3', server_side: bool,
|
||||
id_str=b'') -> None:
|
||||
self._ifc = AsyncIfc()
|
||||
AsyncStream.__init__(self, reader, writer, addr, self._ifc)
|
||||
Talent.__init__(self, server_side, self._ifc, id_str)
|
||||
|
||||
self.remote_stream: 'ConnectionG3' = remote_stream
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
def close(self):
|
||||
AsyncStream.close(self)
|
||||
Talent.close(self)
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
class ConnectionG3(Talent):
|
||||
async def async_create_remote(self) -> None:
|
||||
pass # virtual interface # pragma: no cover
|
||||
|
||||
@@ -40,10 +22,40 @@ class ConnectionG3(AsyncStream, Talent):
|
||||
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('ConnectionG3 healthy()')
|
||||
return AsyncStream.healthy(self)
|
||||
return self._ifc.healthy()
|
||||
|
||||
'''
|
||||
Our private methods
|
||||
'''
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
def close(self):
|
||||
self._ifc.close()
|
||||
Talent.close(self)
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
|
||||
class ConnectionG3Server(ConnectionG3):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, rstream: 'ConnectionG3Client',
|
||||
id_str=b'') -> None:
|
||||
|
||||
server_side = True
|
||||
self.remote = StreamPtr(rstream)
|
||||
self._ifc = AsyncStreamServer(reader, writer, addr,
|
||||
self.async_publ_mqtt,
|
||||
self.async_create_remote,
|
||||
self.remote)
|
||||
self.conn_no = self._ifc.get_conn_no()
|
||||
self.addr = addr
|
||||
Talent.__init__(self, server_side, self._ifc, id_str)
|
||||
|
||||
|
||||
class ConnectionG3Client(ConnectionG3):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, rstream: 'ConnectionG3Server',
|
||||
id_str=b'') -> None:
|
||||
server_side = False
|
||||
self.remote = StreamPtr(rstream)
|
||||
self._ifc = AsyncStreamClient(reader, writer, addr,
|
||||
self.remote)
|
||||
self.conn_no = self._ifc.get_conn_no()
|
||||
self.addr = addr
|
||||
Talent.__init__(self, server_side, self._ifc, id_str)
|
||||
|
||||
@@ -8,19 +8,21 @@ from aiomqtt import MqttCodeError
|
||||
if __name__ == "app.src.gen3.inverter_g3":
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.gen3.connection_g3 import ConnectionG3Server
|
||||
from app.src.gen3.connection_g3 import ConnectionG3Client
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from config import Config
|
||||
from inverter import Inverter
|
||||
from gen3.connection_g3 import ConnectionG3
|
||||
from gen3.connection_g3 import ConnectionG3Server
|
||||
from gen3.connection_g3 import ConnectionG3Client
|
||||
from infos import Infos
|
||||
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class InverterG3(Inverter, ConnectionG3):
|
||||
class InverterG3(Inverter, ConnectionG3Server):
|
||||
'''class Inverter is a derivation of an Async_Stream
|
||||
|
||||
The class has some class method for managing common resources like a
|
||||
@@ -51,8 +53,9 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
'''
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter, addr):
|
||||
super().__init__(reader, writer, addr, None, True)
|
||||
super().__init__(reader, writer, addr, None)
|
||||
self.__ha_restarts = -1
|
||||
self.addr = addr
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
'''Establish a client connection to the TSUN cloud'''
|
||||
@@ -65,12 +68,12 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
logging.info(f'[{self.node_id}] Connect to {addr}')
|
||||
connect = asyncio.open_connection(host, port)
|
||||
reader, writer = await connect
|
||||
self.remote_stream = ConnectionG3(reader, writer, addr, self,
|
||||
False, self.id_str)
|
||||
logging.info(f'[{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}] '
|
||||
self.remote.stream = ConnectionG3Client(reader, writer, addr, self,
|
||||
self.id_str)
|
||||
logging.info(f'[{self.remote.stream.node_id}:'
|
||||
f'{self.remote.stream.conn_no}] '
|
||||
f'Connected to {addr}')
|
||||
asyncio.create_task(self.client_loop(addr))
|
||||
asyncio.create_task(self.remote.ifc.client_loop(addr))
|
||||
|
||||
except (ConnectionRefusedError, TimeoutError) as error:
|
||||
logging.info(f'{error}')
|
||||
@@ -82,6 +85,8 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
'''publish data to MQTT broker'''
|
||||
if not self.unique_id:
|
||||
return
|
||||
# check if new inverter or collector infos are available or when the
|
||||
# home assistant has changed the status back to online
|
||||
try:
|
||||
@@ -96,7 +101,7 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
for key in self.new_data:
|
||||
await self.__async_publ_mqtt_packet(key)
|
||||
for key in Infos.new_stat_data:
|
||||
await self._async_publ_mqtt_proxy_stat(key)
|
||||
await Inverter._async_publ_mqtt_proxy_stat(key)
|
||||
|
||||
except MqttCodeError as error:
|
||||
logging.error(f'Mqtt except: {error}')
|
||||
@@ -128,10 +133,6 @@ class InverterG3(Inverter, ConnectionG3):
|
||||
self.db.reg_clr_at_midnight(f'{self.entity_prfx}{self.node_id}')
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'InverterG3.close() l{self.l_addr} | r{self.r_addr}')
|
||||
logging.debug(f'InverterG3.close() {self.addr}')
|
||||
super().close() # call close handler in the parent class
|
||||
# logging.info(f'Inverter refs: {gc.get_referrers(self)}')
|
||||
|
||||
def __del__(self):
|
||||
logging.debug("InverterG3.__del__")
|
||||
super().__del__()
|
||||
|
||||
@@ -6,7 +6,7 @@ from tzlocal import get_localzone
|
||||
|
||||
if __name__ == "app.src.gen3.talent":
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.messages import hex_dump_memory, Message, State
|
||||
from app.src.messages import Message, State
|
||||
from app.src.modbus import Modbus
|
||||
from app.src.my_timer import Timer
|
||||
from app.src.config import Config
|
||||
@@ -14,7 +14,7 @@ if __name__ == "app.src.gen3.talent":
|
||||
from app.src.infos import Register
|
||||
else: # pragma: no cover
|
||||
from async_ifc import AsyncIfc
|
||||
from messages import hex_dump_memory, Message, State
|
||||
from messages import Message, State
|
||||
from modbus import Modbus
|
||||
from my_timer import Timer
|
||||
from config import Config
|
||||
@@ -48,7 +48,10 @@ class Talent(Message):
|
||||
|
||||
def __init__(self, server_side: bool, ifc: "AsyncIfc", id_str=b''):
|
||||
super().__init__(server_side, self.send_modbus_cb, mb_timeout=15)
|
||||
ifc.read.reg_trigger(self.read)
|
||||
ifc.rx_set_cb(self.read)
|
||||
ifc.prot_set_timeout_cb(self._timeout)
|
||||
ifc.prot_set_init_new_client_conn_cb(self._init_new_client_conn)
|
||||
ifc.prot_set_update_header_cb(self._update_header)
|
||||
self.ifc = ifc
|
||||
self.await_conn_resp_cnt = 0
|
||||
self.id_str = id_str
|
||||
@@ -107,7 +110,10 @@ class Talent(Message):
|
||||
self.log_lvl.clear()
|
||||
self.state = State.closed
|
||||
self.mb_timer.close()
|
||||
self.ifc.read.reg_trigger(None)
|
||||
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)
|
||||
super().close()
|
||||
|
||||
def __set_serial_no(self, serial_no: str):
|
||||
@@ -143,10 +149,10 @@ class Talent(Message):
|
||||
self._read()
|
||||
while True:
|
||||
if not self.header_valid:
|
||||
self.__parse_header(self.ifc.read.peek(), len(self.ifc.read))
|
||||
self.__parse_header(self.ifc.rx_peek(), self.ifc.rx_len())
|
||||
|
||||
if self.header_valid and \
|
||||
len(self.ifc.read) >= (self.header_len + self.data_len):
|
||||
self.ifc.rx_len() >= (self.header_len + self.data_len):
|
||||
if self.state == State.init:
|
||||
self.state = State.received # received 1st package
|
||||
|
||||
@@ -154,10 +160,10 @@ class Talent(Message):
|
||||
if callable(log_lvl):
|
||||
log_lvl = log_lvl()
|
||||
|
||||
self.ifc.read.logging(log_lvl, f'Received from {self.addr}:'
|
||||
f' BufLen: {len(self.ifc.read)}'
|
||||
f' HdrLen: {self.header_len}'
|
||||
f' DtaLen: {self.data_len}')
|
||||
self.ifc.rx_log(log_lvl, f'Received from {self.addr}:'
|
||||
f' BufLen: {self.ifc.rx_len()}'
|
||||
f' HdrLen: {self.header_len}'
|
||||
f' DtaLen: {self.data_len}')
|
||||
|
||||
self.__set_serial_no(self.id_str.decode("utf-8"))
|
||||
self.__dispatch_msg()
|
||||
@@ -170,10 +176,9 @@ class Talent(Message):
|
||||
tsun = Config.get('tsun')
|
||||
if tsun['enabled']:
|
||||
buflen = self.header_len+self.data_len
|
||||
buffer = self.ifc.read.peek(buflen)
|
||||
self._forward_buffer += buffer
|
||||
hex_dump_memory(logging.DEBUG, 'Store for forwarding:',
|
||||
buffer, buflen)
|
||||
buffer = self.ifc.rx_peek(buflen)
|
||||
self.ifc.fwd_add(buffer)
|
||||
self.ifc.fwd_log(logging.DEBUG, 'Store for forwarding:')
|
||||
|
||||
fnc = self.switch.get(self.msg_id, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'forwrd') +
|
||||
@@ -182,20 +187,18 @@ class Talent(Message):
|
||||
def forward_snd(self) -> None:
|
||||
'''add the build send msg to the forwarding queue'''
|
||||
tsun = Config.get('tsun')
|
||||
rest = self.ifc.write.get(self.send_msg_ofs)
|
||||
buffer = self.ifc.write.get(len(self.ifc.write))
|
||||
rest = self.ifc.tx_get(self.send_msg_ofs)
|
||||
buffer = self.ifc.tx_get()
|
||||
if tsun['enabled']:
|
||||
_len = len(buffer)
|
||||
struct.pack_into('!l', buffer, 0, _len-4)
|
||||
buflen = _len
|
||||
self._forward_buffer += buffer
|
||||
hex_dump_memory(logging.INFO, 'Store for forwarding:',
|
||||
buffer, buflen)
|
||||
self.ifc.fwd_add(buffer)
|
||||
self.ifc.fwd_log(logging.INFO, 'Store for forwarding:')
|
||||
|
||||
fnc = self.switch.get(self.msg_id, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'forwrd') +
|
||||
f' Ctl: {int(self.ctrl):#02x} Msg: {fnc.__name__!r}')
|
||||
self.ifc.write += rest
|
||||
self.ifc.tx_add(rest)
|
||||
|
||||
def send_modbus_cb(self, modbus_pdu: bytearray, log_lvl: int, state: str):
|
||||
if self.state != State.up:
|
||||
@@ -204,13 +207,13 @@ class Talent(Message):
|
||||
return
|
||||
|
||||
self.__build_header(0x70, 0x77)
|
||||
self.ifc.write += b'\x00\x01\xa3\x28' # magic ?
|
||||
self.ifc.write += struct.pack('!B', len(modbus_pdu))
|
||||
self.ifc.write += modbus_pdu
|
||||
self.ifc.tx_add(b'\x00\x01\xa3\x28') # magic ?
|
||||
self.ifc.tx_add(struct.pack('!B', len(modbus_pdu)))
|
||||
self.ifc.tx_add(modbus_pdu)
|
||||
self.__finish_send_msg()
|
||||
|
||||
self.ifc.write.logging(log_lvl, f'Send Modbus {state}:{self.addr}:')
|
||||
self.ifc.write()
|
||||
self.ifc.tx_log(log_lvl, f'Send Modbus {state}:{self.addr}:')
|
||||
self.ifc.tx_flush()
|
||||
|
||||
def _send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
|
||||
if self.state != State.up:
|
||||
@@ -238,9 +241,9 @@ class Talent(Message):
|
||||
self.msg_id = 0
|
||||
self.await_conn_resp_cnt += 1
|
||||
self.__build_header(0x91)
|
||||
self.ifc.write += struct.pack(f'!{len(contact_name)+1}p'
|
||||
f'{len(contact_mail)+1}p',
|
||||
contact_name, contact_mail)
|
||||
self.ifc.tx_add(struct.pack(f'!{len(contact_name)+1}p'
|
||||
f'{len(contact_mail)+1}p',
|
||||
contact_name, contact_mail))
|
||||
|
||||
self.__finish_send_msg()
|
||||
return True
|
||||
@@ -324,7 +327,7 @@ class Talent(Message):
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
|
||||
# erase broken recv buffer
|
||||
self.ifc.read.clear()
|
||||
self.ifc.rx_clear()
|
||||
return
|
||||
|
||||
hdr_len = 5+id_len+2
|
||||
@@ -345,16 +348,16 @@ class Talent(Message):
|
||||
def __build_header(self, ctrl, msg_id=None) -> None:
|
||||
if not msg_id:
|
||||
msg_id = self.msg_id
|
||||
self.send_msg_ofs = len(self.ifc.write)
|
||||
self.ifc.write += struct.pack(f'!l{len(self.id_str)+1}pBB',
|
||||
0, self.id_str, ctrl, msg_id)
|
||||
self.send_msg_ofs = self.ifc.tx_len()
|
||||
self.ifc.tx_add(struct.pack(f'!l{len(self.id_str)+1}pBB',
|
||||
0, self.id_str, ctrl, msg_id))
|
||||
fnc = self.switch.get(msg_id, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'tx') +
|
||||
f' Ctl: {int(ctrl):#02x} Msg: {fnc.__name__!r}')
|
||||
|
||||
def __finish_send_msg(self) -> None:
|
||||
_len = len(self.ifc.write) - self.send_msg_ofs
|
||||
struct.pack_into('!l', self.ifc.write.peek(), self.send_msg_ofs,
|
||||
_len = self.ifc.tx_len() - self.send_msg_ofs
|
||||
struct.pack_into('!l', self.ifc.tx_peek(), self.send_msg_ofs,
|
||||
_len-4)
|
||||
|
||||
def __dispatch_msg(self) -> None:
|
||||
@@ -369,7 +372,7 @@ class Talent(Message):
|
||||
f' Ctl: {int(self.ctrl):#02x} Msg: {fnc.__name__!r}')
|
||||
|
||||
def __flush_recv_msg(self) -> None:
|
||||
self.ifc.read.get(self.header_len+self.data_len)
|
||||
self.ifc.rx_get(self.header_len+self.data_len)
|
||||
self.header_valid = False
|
||||
|
||||
'''
|
||||
@@ -379,7 +382,7 @@ class Talent(Message):
|
||||
if self.ctrl.is_ind():
|
||||
if self.server_side and self.__process_contact_info():
|
||||
self.__build_header(0x91)
|
||||
self.ifc.write += b'\x01'
|
||||
self.ifc.tx_add(b'\x01')
|
||||
self.__finish_send_msg()
|
||||
# don't forward this contact info here, we will build one
|
||||
# when the remote connection is established
|
||||
@@ -393,7 +396,7 @@ class Talent(Message):
|
||||
self.forward()
|
||||
|
||||
def __process_contact_info(self) -> bool:
|
||||
buf = self.ifc.read.peek()
|
||||
buf = self.ifc.rx_peek()
|
||||
result = struct.unpack_from('!B', buf, self.header_len)
|
||||
name_len = result[0]
|
||||
if self.data_len == 1: # this is a response withone status byte
|
||||
@@ -420,16 +423,16 @@ class Talent(Message):
|
||||
ts = self._timestamp()
|
||||
logger.debug(f'time: {ts:08x}')
|
||||
self.__build_header(0x91)
|
||||
self.ifc.write += struct.pack('!q', ts)
|
||||
self.ifc.tx_add(struct.pack('!q', ts))
|
||||
self.__finish_send_msg()
|
||||
|
||||
elif self.data_len >= 8:
|
||||
ts = self._timestamp()
|
||||
result = struct.unpack_from('!q', self.ifc.read.peek(),
|
||||
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.remote.stream:
|
||||
self.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}')
|
||||
@@ -449,10 +452,10 @@ class Talent(Message):
|
||||
self.db.set_db_def_value(Register.POLLING_INTERVAL,
|
||||
self.mb_timeout)
|
||||
self.__build_header(0x99)
|
||||
self.ifc.write += b'\x02'
|
||||
self.ifc.tx_add(b'\x02')
|
||||
self.__finish_send_msg()
|
||||
|
||||
result = struct.unpack_from('!Bq', self.ifc.read.peek(),
|
||||
result = struct.unpack_from('!Bq', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
resp_code = result[0]
|
||||
ts = result[1]+self.ts_offset
|
||||
@@ -460,11 +463,11 @@ class Talent(Message):
|
||||
f' tsun-time: {ts:08x}'
|
||||
f' offset: {self.ts_offset}')
|
||||
self.__build_header(0x91)
|
||||
self.ifc.write += struct.pack('!Bq', resp_code, ts)
|
||||
self.ifc.tx_add(struct.pack('!Bq', resp_code, ts))
|
||||
self.forward_snd()
|
||||
return
|
||||
elif self.ctrl.is_resp():
|
||||
result = struct.unpack_from('!B', self.ifc.read.peek(),
|
||||
result = struct.unpack_from('!B', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
resp_code = result[0]
|
||||
logging.debug(f'TimeActRespCode: {resp_code}')
|
||||
@@ -476,7 +479,7 @@ class Talent(Message):
|
||||
self.forward()
|
||||
|
||||
def parse_msg_header(self):
|
||||
result = struct.unpack_from('!lB', self.ifc.read.peek(),
|
||||
result = struct.unpack_from('!lB', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
|
||||
data_id = result[0] # len of complete message
|
||||
@@ -485,7 +488,7 @@ class Talent(Message):
|
||||
|
||||
msg_hdr_len = 5+id_len+9
|
||||
|
||||
result = struct.unpack_from(f'!{id_len+1}pBq', self.ifc.read.peek(),
|
||||
result = struct.unpack_from(f'!{id_len+1}pBq', self.ifc.rx_peek(),
|
||||
self.header_len + 4)
|
||||
|
||||
timestamp = result[2]
|
||||
@@ -498,7 +501,7 @@ class Talent(Message):
|
||||
def msg_collector_data(self):
|
||||
if self.ctrl.is_ind():
|
||||
self.__build_header(0x99)
|
||||
self.ifc.write += b'\x01'
|
||||
self.ifc.tx_add(b'\x01')
|
||||
self.__finish_send_msg()
|
||||
self.__process_data()
|
||||
|
||||
@@ -513,7 +516,7 @@ class Talent(Message):
|
||||
def msg_inverter_data(self):
|
||||
if self.ctrl.is_ind():
|
||||
self.__build_header(0x99)
|
||||
self.ifc.write += b'\x01'
|
||||
self.ifc.tx_add(b'\x01')
|
||||
self.__finish_send_msg()
|
||||
self.__process_data()
|
||||
self.state = State.up # allow MODBUS cmds
|
||||
@@ -533,7 +536,7 @@ class Talent(Message):
|
||||
def __process_data(self):
|
||||
msg_hdr_len, ts = self.parse_msg_header()
|
||||
|
||||
for key, update in self.db.parse(self.ifc.read.peek(), self.header_len
|
||||
for key, update in self.db.parse(self.ifc.rx_peek(), self.header_len
|
||||
+ msg_hdr_len, self.node_id):
|
||||
if update:
|
||||
self._set_mqtt_timestamp(key, self._utcfromts(ts))
|
||||
@@ -553,7 +556,7 @@ class Talent(Message):
|
||||
|
||||
msg_hdr_len = 5
|
||||
|
||||
result = struct.unpack_from('!lBB', self.ifc.read.peek(),
|
||||
result = struct.unpack_from('!lBB', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
modbus_len = result[1]
|
||||
return msg_hdr_len, modbus_len
|
||||
@@ -562,7 +565,7 @@ class Talent(Message):
|
||||
|
||||
msg_hdr_len = 6
|
||||
|
||||
result = struct.unpack_from('!lBBB', self.ifc.read.peek(),
|
||||
result = struct.unpack_from('!lBBB', self.ifc.rx_peek(),
|
||||
self.header_len)
|
||||
modbus_len = result[2]
|
||||
return msg_hdr_len, modbus_len
|
||||
@@ -583,12 +586,12 @@ class Talent(Message):
|
||||
self.__msg_modbus(hdr_len)
|
||||
|
||||
def __msg_modbus(self, hdr_len):
|
||||
data = self.ifc.read.peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
data = self.ifc.rx_peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
|
||||
if self.ctrl.is_req():
|
||||
if self.remote_stream.mb.recv_req(data[hdr_len:],
|
||||
self.remote_stream.
|
||||
if self.remote.stream.mb.recv_req(data[hdr_len:],
|
||||
self.remote.stream.
|
||||
msg_forward):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
|
||||
@@ -2,37 +2,18 @@ import logging
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
if __name__ == "app.src.gen3plus.connection_g3p":
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.async_stream import AsyncStream
|
||||
from app.src.async_stream import AsyncStreamServer
|
||||
from app.src.async_stream import AsyncStreamClient, StreamPtr
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
else: # pragma: no cover
|
||||
from async_ifc import AsyncIfc
|
||||
from async_stream import AsyncStream
|
||||
from async_stream import AsyncStreamServer
|
||||
from async_stream import AsyncStreamClient, StreamPtr
|
||||
from gen3plus.solarman_v5 import SolarmanV5
|
||||
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
|
||||
class ConnectionG3P(AsyncStream, SolarmanV5):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, remote_stream: 'ConnectionG3P',
|
||||
server_side: bool,
|
||||
client_mode: bool) -> None:
|
||||
self._ifc = AsyncIfc()
|
||||
AsyncStream.__init__(self, reader, writer, addr, self._ifc)
|
||||
SolarmanV5.__init__(self, server_side, client_mode, self._ifc)
|
||||
|
||||
self.remote_stream: 'ConnectionG3P' = remote_stream
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
def close(self):
|
||||
AsyncStream.close(self)
|
||||
SolarmanV5.close(self)
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
class ConnectionG3P(SolarmanV5):
|
||||
async def async_create_remote(self) -> None:
|
||||
pass # virtual interface # pragma: no cover
|
||||
|
||||
@@ -41,10 +22,40 @@ class ConnectionG3P(AsyncStream, SolarmanV5):
|
||||
|
||||
def healthy(self) -> bool:
|
||||
logger.debug('ConnectionG3P healthy()')
|
||||
return AsyncStream.healthy(self)
|
||||
return self._ifc.healthy()
|
||||
|
||||
'''
|
||||
Our private methods
|
||||
'''
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
def close(self):
|
||||
self._ifc.close()
|
||||
SolarmanV5.close(self)
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
|
||||
class ConnectionG3PServer(ConnectionG3P):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, rstream: 'ConnectionG3PClient',
|
||||
client_mode: bool) -> None:
|
||||
|
||||
server_side = True
|
||||
self.remote = StreamPtr(rstream)
|
||||
self._ifc = AsyncStreamServer(reader, writer, addr,
|
||||
self.async_publ_mqtt,
|
||||
self.async_create_remote,
|
||||
self.remote)
|
||||
self.conn_no = self._ifc.get_conn_no()
|
||||
self.addr = addr
|
||||
SolarmanV5.__init__(self, server_side, client_mode, self._ifc)
|
||||
|
||||
|
||||
class ConnectionG3PClient(ConnectionG3P):
|
||||
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
addr, rstream: 'ConnectionG3PServer') -> None:
|
||||
|
||||
server_side = False
|
||||
client_mode = False
|
||||
self.remote = StreamPtr(rstream)
|
||||
self._ifc = AsyncStreamClient(reader, writer, addr, self.remote)
|
||||
self.conn_no = self._ifc.get_conn_no()
|
||||
self.addr = addr
|
||||
SolarmanV5.__init__(self, server_side, client_mode, self._ifc)
|
||||
|
||||
@@ -8,19 +8,21 @@ from aiomqtt import MqttCodeError
|
||||
if __name__ == "app.src.gen3plus.inverter_g3p":
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3PServer
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3PClient
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from config import Config
|
||||
from inverter import Inverter
|
||||
from gen3plus.connection_g3p import ConnectionG3P
|
||||
from gen3plus.connection_g3p import ConnectionG3PServer
|
||||
from gen3plus.connection_g3p import ConnectionG3PClient
|
||||
from infos import Infos
|
||||
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class InverterG3P(Inverter, ConnectionG3P):
|
||||
class InverterG3P(Inverter, ConnectionG3PServer):
|
||||
'''class Inverter is a derivation of an Async_Stream
|
||||
|
||||
The class has some class method for managing common resources like a
|
||||
@@ -53,8 +55,9 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter, addr,
|
||||
client_mode: bool = False):
|
||||
super().__init__(reader, writer, addr, None,
|
||||
server_side=True, client_mode=client_mode)
|
||||
client_mode=client_mode)
|
||||
self.__ha_restarts = -1
|
||||
self.addr = addr
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
'''Establish a client connection to the TSUN cloud'''
|
||||
@@ -67,13 +70,12 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
logging.info(f'[{self.node_id}] Connect to {addr}')
|
||||
connect = asyncio.open_connection(host, port)
|
||||
reader, writer = await connect
|
||||
self.remote_stream = ConnectionG3P(reader, writer, addr, self,
|
||||
server_side=False,
|
||||
client_mode=False)
|
||||
logging.info(f'[{self.remote_stream.node_id}:'
|
||||
f'{self.remote_stream.conn_no}] '
|
||||
self.remote.stream = ConnectionG3PClient(reader, writer,
|
||||
addr, self)
|
||||
logging.info(f'[{self.remote.stream.node_id}:'
|
||||
f'{self.remote.stream.conn_no}] '
|
||||
f'Connected to {addr}')
|
||||
asyncio.create_task(self.client_loop(addr))
|
||||
asyncio.create_task(self.remote.ifc.client_loop(addr))
|
||||
|
||||
except (ConnectionRefusedError, TimeoutError) as error:
|
||||
logging.info(f'{error}')
|
||||
@@ -85,6 +87,9 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
|
||||
async def async_publ_mqtt(self) -> None:
|
||||
'''publish data to MQTT broker'''
|
||||
if not self.unique_id:
|
||||
return
|
||||
|
||||
# check if new inverter or collector infos are available or when the
|
||||
# home assistant has changed the status back to online
|
||||
try:
|
||||
@@ -99,7 +104,7 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
for key in self.new_data:
|
||||
await self.__async_publ_mqtt_packet(key)
|
||||
for key in Infos.new_stat_data:
|
||||
await self._async_publ_mqtt_proxy_stat(key)
|
||||
await Inverter._async_publ_mqtt_proxy_stat(key)
|
||||
|
||||
except MqttCodeError as error:
|
||||
logging.error(f'Mqtt except: {error}')
|
||||
@@ -131,10 +136,6 @@ class InverterG3P(Inverter, ConnectionG3P):
|
||||
self.db.reg_clr_at_midnight(f'{self.entity_prfx}{self.node_id}')
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'InverterG3P.close() l{self.l_addr} | r{self.r_addr}')
|
||||
logging.debug(f'InverterG3P.close() {self.addr}')
|
||||
super().close() # call close handler in the parent class
|
||||
# logger.debug (f'Inverter refs: {gc.get_referrers(self)}')
|
||||
|
||||
def __del__(self):
|
||||
logging.debug("InverterG3P.__del__")
|
||||
super().__del__()
|
||||
|
||||
@@ -64,7 +64,11 @@ class SolarmanV5(Message):
|
||||
|
||||
def __init__(self, server_side: bool, client_mode: bool, ifc: "AsyncIfc"):
|
||||
super().__init__(server_side, self.send_modbus_cb, mb_timeout=8)
|
||||
ifc.read.reg_trigger(self.read)
|
||||
ifc.rx_set_cb(self.read)
|
||||
ifc.prot_set_timeout_cb(self._timeout)
|
||||
ifc.prot_set_init_new_client_conn_cb(self._init_new_client_conn)
|
||||
ifc.prot_set_update_header_cb(self._update_header)
|
||||
|
||||
self.ifc = ifc
|
||||
self.header_len = 11 # overwrite construcor in class Message
|
||||
self.control = 0
|
||||
@@ -165,7 +169,10 @@ class SolarmanV5(Message):
|
||||
self.log_lvl.clear()
|
||||
self.state = State.closed
|
||||
self.mb_timer.close()
|
||||
self.ifc.read.reg_trigger(None)
|
||||
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)
|
||||
super().close()
|
||||
|
||||
async def send_start_cmd(self, snr: int, host: str,
|
||||
@@ -250,10 +257,10 @@ class SolarmanV5(Message):
|
||||
self._read()
|
||||
while True:
|
||||
if not self.header_valid:
|
||||
self.__parse_header(self.ifc.read.peek(),
|
||||
len(self.ifc.read))
|
||||
self.__parse_header(self.ifc.rx_peek(),
|
||||
self.ifc.rx_len())
|
||||
|
||||
if self.header_valid and len(self.ifc.read) >= \
|
||||
if self.header_valid and self.ifc.rx_len() >= \
|
||||
(self.header_len + self.data_len+2):
|
||||
self.__process_complete_received_msg()
|
||||
self.__flush_recv_msg()
|
||||
@@ -264,10 +271,10 @@ class SolarmanV5(Message):
|
||||
log_lvl = self.log_lvl.get(self.control, logging.WARNING)
|
||||
if callable(log_lvl):
|
||||
log_lvl = log_lvl()
|
||||
self.ifc.read.logging(log_lvl, f'Received from {self.addr}:')
|
||||
self.ifc.rx_log(log_lvl, f'Received from {self.addr}:')
|
||||
# self._recv_buffer, self.header_len +
|
||||
# self.data_len+2)
|
||||
if self.__trailer_is_ok(self.ifc.read.peek(), self.header_len
|
||||
if self.__trailer_is_ok(self.ifc.rx_peek(), self.header_len
|
||||
+ self.data_len + 2):
|
||||
if self.state == State.init:
|
||||
self.state = State.received
|
||||
@@ -280,9 +287,8 @@ class SolarmanV5(Message):
|
||||
return
|
||||
tsun = Config.get('solarman')
|
||||
if tsun['enabled']:
|
||||
self._forward_buffer += buffer[:buflen]
|
||||
hex_dump_memory(logging.DEBUG, 'Store for forwarding:',
|
||||
buffer, buflen)
|
||||
self.ifc.fwd_add(buffer[:buflen])
|
||||
self.ifc.fwd_log(logging.DEBUG, 'Store for forwarding:')
|
||||
|
||||
fnc = self.switch.get(self.control, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'forwrd') +
|
||||
@@ -338,7 +344,7 @@ class SolarmanV5(Message):
|
||||
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
# erase broken recv buffer
|
||||
self.ifc.read.clear()
|
||||
self.ifc.rx_clear()
|
||||
return
|
||||
self.header_valid = True
|
||||
|
||||
@@ -350,11 +356,11 @@ class SolarmanV5(Message):
|
||||
'Drop packet w invalid stop byte from '
|
||||
f'{self.addr}:', buf, buf_len)
|
||||
self.inc_counter('Invalid_Msg_Format')
|
||||
if len(self.ifc.read) > (self.data_len+13):
|
||||
if self.ifc.rx_len() > (self.data_len+13):
|
||||
next_start = buf[self.data_len+13]
|
||||
if next_start != 0xa5:
|
||||
# erase broken recv buffer
|
||||
self.ifc.read.clear()
|
||||
self.ifc.rx_clear()
|
||||
|
||||
return False
|
||||
|
||||
@@ -370,22 +376,22 @@ class SolarmanV5(Message):
|
||||
|
||||
def __build_header(self, ctrl) -> None:
|
||||
'''build header for new transmit message'''
|
||||
self.send_msg_ofs = len(self.ifc.write)
|
||||
self.send_msg_ofs = self.ifc.tx_len()
|
||||
|
||||
self.ifc.write += struct.pack(
|
||||
'<BHHHL', 0xA5, 0, ctrl, self.seq.get_send(), self.snr)
|
||||
self.ifc.tx_add(struct.pack(
|
||||
'<BHHHL', 0xA5, 0, ctrl, self.seq.get_send(), self.snr))
|
||||
fnc = self.switch.get(ctrl, self.msg_unknown)
|
||||
logger.info(self.__flow_str(self.server_side, 'tx') +
|
||||
f' Ctl: {int(ctrl):#04x} Msg: {fnc.__name__!r}')
|
||||
|
||||
def __finish_send_msg(self) -> None:
|
||||
'''finish the transmit message, set lenght and checksum'''
|
||||
_len = len(self.ifc.write) - self.send_msg_ofs
|
||||
struct.pack_into('<H', self.ifc.write.peek(), self.send_msg_ofs+1,
|
||||
_len = self.ifc.tx_len() - self.send_msg_ofs
|
||||
struct.pack_into('<H', self.ifc.tx_peek(), self.send_msg_ofs+1,
|
||||
_len-11)
|
||||
check = sum(self.ifc.write.peek()[
|
||||
check = sum(self.ifc.tx_peek()[
|
||||
self.send_msg_ofs+1:self.send_msg_ofs + _len]) & 0xff
|
||||
self.ifc.write += struct.pack('<BB', check, 0x15) # crc & stop
|
||||
self.ifc.tx_add(struct.pack('<BB', check, 0x15)) # crc & stop
|
||||
|
||||
def _update_header(self, _forward_buffer):
|
||||
'''update header for message before forwarding,
|
||||
@@ -416,14 +422,14 @@ class SolarmanV5(Message):
|
||||
f' Msg: {fnc.__name__!r}')
|
||||
|
||||
def __flush_recv_msg(self) -> None:
|
||||
self.ifc.read.get(self.header_len + self.data_len+2)
|
||||
self.ifc.rx_get(self.header_len + self.data_len+2)
|
||||
self.header_valid = False
|
||||
|
||||
def __send_ack_rsp(self, msgtype, ftype, ack=1):
|
||||
self.__build_header(msgtype)
|
||||
self.ifc.write += struct.pack('<BBLL', ftype, ack,
|
||||
self._timestamp(),
|
||||
self._heartbeat())
|
||||
self.ifc.tx_add(struct.pack('<BBLL', ftype, ack,
|
||||
self._timestamp(),
|
||||
self._heartbeat()))
|
||||
self.__finish_send_msg()
|
||||
|
||||
def send_modbus_cb(self, pdu: bytearray, log_lvl: int, state: str):
|
||||
@@ -432,12 +438,12 @@ class SolarmanV5(Message):
|
||||
' cause the state is not UP anymore')
|
||||
return
|
||||
self.__build_header(0x4510)
|
||||
self.ifc.write += struct.pack('<BHLLL', self.MB_RTU_CMD,
|
||||
self.sensor_list, 0, 0, 0)
|
||||
self.ifc.write += pdu
|
||||
self.ifc.tx_add(struct.pack('<BHLLL', self.MB_RTU_CMD,
|
||||
self.sensor_list, 0, 0, 0))
|
||||
self.ifc.tx_add(pdu)
|
||||
self.__finish_send_msg()
|
||||
self.ifc.write.logging(log_lvl, f'Send Modbus {state}:{self.addr}:')
|
||||
self.ifc.write()
|
||||
self.ifc.tx_log(log_lvl, f'Send Modbus {state}:{self.addr}:')
|
||||
self.ifc.tx_flush()
|
||||
|
||||
def _send_modbus_cmd(self, mb_no, func, addr, val, log_lvl) -> None:
|
||||
if self.state != State.up:
|
||||
@@ -493,17 +499,18 @@ class SolarmanV5(Message):
|
||||
|
||||
self.forward_at_cmd_resp = False
|
||||
self.__build_header(0x4510)
|
||||
self.ifc.write += struct.pack(f'<BHLLL{len(at_cmd)}sc', self.AT_CMD,
|
||||
0x0002, 0, 0, 0,
|
||||
at_cmd.encode('utf-8'), b'\r')
|
||||
self.ifc.tx_add(struct.pack(f'<BHLLL{len(at_cmd)}sc', self.AT_CMD,
|
||||
0x0002, 0, 0, 0,
|
||||
at_cmd.encode('utf-8'), b'\r'))
|
||||
self.__finish_send_msg()
|
||||
self.ifc.tx_log(logging.INFO, 'Send AT Command:')
|
||||
try:
|
||||
await self.async_write('Send AT Command:')
|
||||
self.ifc.tx_flush()
|
||||
except Exception:
|
||||
self.ifc.write.clear()
|
||||
self.ifc.tx_clear()
|
||||
|
||||
def __forward_msg(self):
|
||||
self.forward(self.ifc.read.peek(), self.header_len+self.data_len+2)
|
||||
self.forward(self.ifc.rx_peek(), self.header_len+self.data_len+2)
|
||||
|
||||
def __build_model_name(self):
|
||||
db = self.db
|
||||
@@ -524,7 +531,7 @@ class SolarmanV5(Message):
|
||||
def __process_data(self, ftype, ts):
|
||||
inv_update = False
|
||||
msg_type = self.control >> 8
|
||||
for key, update in self.db.parse(self.ifc.read.peek(), msg_type, ftype,
|
||||
for key, update in self.db.parse(self.ifc.rx_peek(), msg_type, ftype,
|
||||
self.node_id):
|
||||
if update:
|
||||
if key == 'inverter':
|
||||
@@ -543,7 +550,7 @@ class SolarmanV5(Message):
|
||||
self.__forward_msg()
|
||||
|
||||
def msg_dev_ind(self):
|
||||
data = self.ifc.read.peek()[self.header_len:]
|
||||
data = self.ifc.rx_peek()[self.header_len:]
|
||||
result = struct.unpack_from(self.HDR_FMT, data, 0)
|
||||
ftype = result[0] # always 2
|
||||
total = result[1]
|
||||
@@ -564,7 +571,7 @@ class SolarmanV5(Message):
|
||||
self.__send_ack_rsp(0x1110, ftype)
|
||||
|
||||
def msg_data_ind(self):
|
||||
data = self.ifc.read.peek()
|
||||
data = self.ifc.rx_peek()
|
||||
result = struct.unpack_from('<BHLLLHL', data, self.header_len)
|
||||
ftype = result[0] # 1 or 0x81
|
||||
sensor = result[1]
|
||||
@@ -592,7 +599,7 @@ class SolarmanV5(Message):
|
||||
self.new_state_up()
|
||||
|
||||
def msg_sync_start(self):
|
||||
data = self.ifc.read.peek()[self.header_len:]
|
||||
data = self.ifc.rx_peek()[self.header_len:]
|
||||
result = struct.unpack_from(self.HDR_FMT, data, 0)
|
||||
ftype = result[0]
|
||||
total = result[1]
|
||||
@@ -605,8 +612,8 @@ class SolarmanV5(Message):
|
||||
self.__send_ack_rsp(0x1310, ftype)
|
||||
|
||||
def msg_command_req(self):
|
||||
data = self.ifc.read.peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
data = self.ifc.rx_peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
result = struct.unpack_from('<B', data, 0)
|
||||
ftype = result[0]
|
||||
if ftype == self.AT_CMD:
|
||||
@@ -618,8 +625,8 @@ 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.
|
||||
if self.remote.stream.mb.recv_req(data[15:],
|
||||
self.remote.stream.
|
||||
__forward_msg):
|
||||
self.inc_counter('Modbus_Command')
|
||||
else:
|
||||
@@ -634,7 +641,7 @@ class SolarmanV5(Message):
|
||||
self.mqtt.publish(key, data))
|
||||
|
||||
def get_cmd_rsp_log_lvl(self) -> int:
|
||||
ftype = self.ifc.read.peek()[self.header_len]
|
||||
ftype = self.ifc.rx_peek()[self.header_len]
|
||||
if ftype == self.AT_CMD:
|
||||
if self.forward_at_cmd_resp:
|
||||
return logging.INFO
|
||||
@@ -646,8 +653,8 @@ class SolarmanV5(Message):
|
||||
return logging.WARNING
|
||||
|
||||
def msg_command_rsp(self):
|
||||
data = self.ifc.read.peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
data = self.ifc.rx_peek()[self.header_len:
|
||||
self.header_len+self.data_len]
|
||||
ftype = data[0]
|
||||
if ftype == self.AT_CMD:
|
||||
if not self.forward_at_cmd_resp:
|
||||
@@ -690,7 +697,7 @@ class SolarmanV5(Message):
|
||||
self.__build_model_name()
|
||||
|
||||
def msg_hbeat_ind(self):
|
||||
data = self.ifc.read.peek()[self.header_len:]
|
||||
data = self.ifc.rx_peek()[self.header_len:]
|
||||
result = struct.unpack_from('<B', data, 0)
|
||||
ftype = result[0]
|
||||
|
||||
@@ -699,7 +706,7 @@ class SolarmanV5(Message):
|
||||
self.new_state_up()
|
||||
|
||||
def msg_sync_end(self):
|
||||
data = self.ifc.read.peek()[self.header_len:]
|
||||
data = self.ifc.rx_peek()[self.header_len:]
|
||||
result = struct.unpack_from(self.HDR_FMT, data, 0)
|
||||
ftype = result[0]
|
||||
total = result[1]
|
||||
@@ -712,7 +719,7 @@ class SolarmanV5(Message):
|
||||
self.__send_ack_rsp(0x1810, ftype)
|
||||
|
||||
def msg_response(self):
|
||||
data = self.ifc.read.peek()[self.header_len:]
|
||||
data = self.ifc.rx_peek()[self.header_len:]
|
||||
result = struct.unpack_from('<BBLL', data, 0)
|
||||
ftype = result[0] # always 2
|
||||
valid = result[1] == 1 # status
|
||||
|
||||
@@ -383,12 +383,14 @@ class Infos:
|
||||
'''inc proxy statistic counter'''
|
||||
db_dict = cls.stat['proxy']
|
||||
db_dict[counter] += 1
|
||||
cls.new_stat_data['proxy'] = True
|
||||
|
||||
@classmethod
|
||||
def dec_counter(cls, counter: str) -> None:
|
||||
'''dec proxy statistic counter'''
|
||||
db_dict = cls.stat['proxy']
|
||||
db_dict[counter] -= 1
|
||||
cls.new_stat_data['proxy'] = True
|
||||
|
||||
def ha_proxy_confs(self, ha_prfx: str, node_id: str, snr: str) \
|
||||
-> Generator[tuple[str, str, str, str], None, None]:
|
||||
|
||||
@@ -90,6 +90,12 @@ class State(Enum):
|
||||
|
||||
class Message(metaclass=IterRegistry):
|
||||
_registry = []
|
||||
MAX_START_TIME = 400
|
||||
'''maximum time without a received msg in sec'''
|
||||
MAX_INV_IDLE_TIME = 120
|
||||
'''maximum time without a received msg from the inverter in sec'''
|
||||
MAX_DEF_IDLE_TIME = 360
|
||||
'''maximum default time without a received msg in sec'''
|
||||
|
||||
def __init__(self, server_side: bool, send_modbus_cb:
|
||||
Callable[[bytes, int, str], None], mb_timeout: int):
|
||||
@@ -105,13 +111,21 @@ class Message(metaclass=IterRegistry):
|
||||
self.header_len = 0
|
||||
self.data_len = 0
|
||||
self.unique_id = 0
|
||||
self.node_id = '' # will be overwritten in the child class's __init__
|
||||
self._node_id = ''
|
||||
self.sug_area = ''
|
||||
self._forward_buffer = bytearray(0)
|
||||
self.new_data = {}
|
||||
self.state = State.init
|
||||
self.shutdown_started = False
|
||||
|
||||
@property
|
||||
def node_id(self):
|
||||
return self._node_id
|
||||
|
||||
@node_id.setter
|
||||
def node_id(self, value):
|
||||
self._node_id = value
|
||||
self.ifc.set_node_id(value)
|
||||
|
||||
'''
|
||||
Empty methods, that have to be implemented in any child class which
|
||||
don't use asyncio
|
||||
@@ -120,10 +134,6 @@ class Message(metaclass=IterRegistry):
|
||||
# to our _recv_buffer
|
||||
return # pragma: no cover
|
||||
|
||||
def _update_header(self, _forward_buffer):
|
||||
'''callback for updating the header of the forward buffer'''
|
||||
pass # pragma: no cover
|
||||
|
||||
def _set_mqtt_timestamp(self, key, ts: float | None):
|
||||
if key not in self.new_data or \
|
||||
not self.new_data[key]:
|
||||
@@ -139,6 +149,16 @@ class Message(metaclass=IterRegistry):
|
||||
# logger.info(f'update: key: {key} ts:{tstr}'
|
||||
self.db.set_db_def_value(info_id, round(ts))
|
||||
|
||||
def _timeout(self) -> int:
|
||||
if self.state == State.init or self.state == State.received:
|
||||
to = self.MAX_START_TIME
|
||||
elif self.state == State.up and \
|
||||
self.server_side and self.modbus_polling:
|
||||
to = self.MAX_INV_IDLE_TIME
|
||||
else:
|
||||
to = self.MAX_DEF_IDLE_TIME
|
||||
return to
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
|
||||
@@ -5,9 +5,11 @@ import asyncio
|
||||
if __name__ == "app.src.modbus_tcp":
|
||||
from app.src.config import Config
|
||||
from app.src.gen3plus.inverter_g3p import InverterG3P
|
||||
from app.src.infos import Infos
|
||||
else: # pragma: no cover
|
||||
from config import Config
|
||||
from gen3plus.inverter_g3p import InverterG3P
|
||||
from infos import Infos
|
||||
|
||||
logger = logging.getLogger('conn')
|
||||
|
||||
@@ -27,13 +29,14 @@ class ModbusConn():
|
||||
client_mode=True)
|
||||
logging.info(f'[{self.stream.node_id}:{self.stream.conn_no}] '
|
||||
f'Connected to {self.addr}')
|
||||
self.stream.inc_counter('Inverter_Cnt')
|
||||
await self.stream.publish_outstanding_mqtt()
|
||||
Infos.inc_counter('Inverter_Cnt')
|
||||
await self.stream._ifc.publish_outstanding_mqtt()
|
||||
return self.stream
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
self.stream.dec_counter('Inverter_Cnt')
|
||||
await self.stream.publish_outstanding_mqtt()
|
||||
Infos.dec_counter('Inverter_Cnt')
|
||||
await self.stream._ifc.publish_outstanding_mqtt()
|
||||
self.stream.close()
|
||||
|
||||
|
||||
class ModbusTcp():
|
||||
@@ -60,7 +63,7 @@ class ModbusTcp():
|
||||
try:
|
||||
async with ModbusConn(host, port) as stream:
|
||||
await stream.send_start_cmd(snr, host)
|
||||
await stream.loop()
|
||||
await stream._ifc.loop()
|
||||
logger.info(f'[{stream.node_id}:{stream.conn_no}] '
|
||||
f'Connection closed - Shutdown: '
|
||||
f'{stream.shutdown_started}')
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
class ObjectFactory:
|
||||
def __init__(self):
|
||||
self._builders = {}
|
||||
|
||||
def register_builder(self, key, builder):
|
||||
self._builders[key] = builder
|
||||
|
||||
def create(self, key, **kwargs):
|
||||
builder = self._builders.get(key)
|
||||
if not builder:
|
||||
raise ValueError(key)
|
||||
return builder(**kwargs)
|
||||
@@ -74,14 +74,14 @@ async def handle_client(reader: StreamReader, writer: StreamWriter):
|
||||
'''Handles a new incoming connection and starts an async loop'''
|
||||
|
||||
addr = writer.get_extra_info('peername')
|
||||
await InverterG3(reader, writer, addr).server_loop(addr)
|
||||
await InverterG3(reader, writer, addr)._ifc.server_loop(addr)
|
||||
|
||||
|
||||
async def handle_client_v2(reader: StreamReader, writer: StreamWriter):
|
||||
'''Handles a new incoming connection and starts an async loop'''
|
||||
|
||||
addr = writer.get_extra_info('peername')
|
||||
await InverterG3P(reader, writer, addr).server_loop(addr)
|
||||
await InverterG3P(reader, writer, addr)._ifc.server_loop(addr)
|
||||
|
||||
|
||||
async def handle_shutdown(web_task):
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
import pytest
|
||||
import asyncio
|
||||
|
||||
from itertools import count
|
||||
from mock import patch
|
||||
from app.src.async_stream import AsyncStream
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.async_stream import AsyncStream, AsyncIfcImpl
|
||||
from app.src.gen3.connection_g3 import ConnectionG3Server
|
||||
from app.src.gen3.talent import Talent
|
||||
|
||||
@pytest.fixture
|
||||
@@ -60,19 +61,19 @@ class FakeWriter():
|
||||
|
||||
|
||||
|
||||
def test_method_calls(patch_async_init, patch_talent_init, patch_healthy, patch_async_close, patch_talent_close):
|
||||
spy1 = patch_async_init
|
||||
def test_method_calls(patch_talent_init, patch_healthy, patch_async_close, patch_talent_close):
|
||||
AsyncIfcImpl._ids = count(5)
|
||||
spy2 = patch_talent_init
|
||||
spy3 = patch_healthy
|
||||
spy4 = patch_async_close
|
||||
spy5 = patch_talent_close
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
writer = FakeWriter()
|
||||
id_str = "id_string"
|
||||
addr = ('proxy.local', 10000)
|
||||
conn = ConnectionG3(reader, writer, addr,
|
||||
remote_stream= None, server_side=True, id_str=id_str)
|
||||
spy1.assert_called_once_with(conn, reader, writer, addr, conn._ifc)
|
||||
conn = ConnectionG3Server(reader, writer, addr,
|
||||
rstream= None, id_str=id_str)
|
||||
assert 5 == conn._ifc.get_conn_no()
|
||||
spy2.assert_called_once_with(conn, True, conn._ifc, id_str)
|
||||
conn.healthy()
|
||||
|
||||
@@ -81,4 +82,3 @@ def test_method_calls(patch_async_init, patch_talent_init, patch_healthy, patch_
|
||||
conn.close()
|
||||
spy4.assert_called_once()
|
||||
spy5.assert_called_once()
|
||||
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
import pytest
|
||||
import asyncio
|
||||
|
||||
from itertools import count
|
||||
from mock import patch
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.async_stream import AsyncStream
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.async_stream import AsyncStream, AsyncIfcImpl
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3PServer
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
|
||||
@pytest.fixture
|
||||
def patch_async_init():
|
||||
with patch.object(AsyncStream, '__init__') as conn:
|
||||
with patch.object(AsyncStream, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
@@ -66,18 +67,18 @@ class FakeWriter():
|
||||
|
||||
|
||||
|
||||
def test_method_calls(patch_async_init, patch_solarman_init, patch_healthy, patch_async_close, patch_solarman_close):
|
||||
spy1 = patch_async_init
|
||||
def test_method_calls(patch_solarman_init, patch_healthy, patch_async_close, patch_solarman_close):
|
||||
AsyncIfcImpl._ids = count(5)
|
||||
spy2 = patch_solarman_init
|
||||
spy3 = patch_healthy
|
||||
spy4 = patch_async_close
|
||||
spy5 = patch_solarman_close
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
writer = FakeWriter()
|
||||
addr = ('proxy.local', 10000)
|
||||
conn = ConnectionG3P(reader, writer, addr,
|
||||
remote_stream= None, server_side=True, client_mode=False)
|
||||
spy1.assert_called_once_with(conn, reader, writer, addr, conn._ifc)
|
||||
conn = ConnectionG3PServer(reader, writer, addr,
|
||||
rstream= None, client_mode=False)
|
||||
assert 5 == conn._ifc.get_conn_no()
|
||||
spy2.assert_called_once_with(conn, True, False, conn._ifc)
|
||||
conn.healthy()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ pytest_plugins = ('pytest_asyncio',)
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def module_init():
|
||||
def new_init(cls, cb_mqtt_is_up):
|
||||
cb_mqtt_is_up()
|
||||
pass # empty test methos
|
||||
|
||||
Singleton._instances.clear()
|
||||
with patch.object(Mqtt, '__init__', new_init):
|
||||
@@ -69,6 +69,7 @@ async def test_inverter_cb(config_conn):
|
||||
assert 'homeassistant/' == Inverter.discovery_prfx
|
||||
assert 'tsun/' == Inverter.entity_prfx
|
||||
assert 'test_1/' == Inverter.proxy_node_id
|
||||
await Inverter._cb_mqtt_is_up()
|
||||
spy.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -8,7 +8,7 @@ from app.src.infos import Infos
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.gen3.connection_g3 import ConnectionG3
|
||||
from app.src.gen3.connection_g3 import ConnectionG3Server
|
||||
from app.src.gen3.inverter_g3 import InverterG3
|
||||
|
||||
from app.tests.test_modbus_tcp import patch_mqtt_err, patch_mqtt_except, test_port, test_hostname
|
||||
@@ -44,12 +44,12 @@ def module_init():
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_init():
|
||||
with patch.object(ConnectionG3, '__init__', return_value= None) as conn:
|
||||
with patch.object(ConnectionG3Server, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_close():
|
||||
with patch.object(ConnectionG3, 'close') as conn:
|
||||
with patch.object(ConnectionG3Server, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
@@ -115,7 +115,7 @@ def test_method_calls(patch_conn_init, patch_conn_close):
|
||||
inverter.r_addr = ''
|
||||
|
||||
spy1.assert_called_once()
|
||||
spy1.assert_called_once_with(reader, writer, addr, None, True)
|
||||
spy1.assert_called_once_with(reader, writer, addr, None)
|
||||
|
||||
inverter.close()
|
||||
spy2.assert_called_once()
|
||||
@@ -132,7 +132,7 @@ async def test_remote_conn(config_conn, patch_open_connection, patch_conn_close)
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream
|
||||
assert inverter.remote.stream
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
|
||||
@@ -151,12 +151,12 @@ async def test_remote_except(config_conn, patch_open_connection, patch_conn_clos
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream==None
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream==None
|
||||
assert inverter.remote.stream==None
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
|
||||
@@ -171,6 +171,7 @@ async def test_mqtt_publish(config_conn, patch_open_connection, patch_conn_close
|
||||
Inverter.class_init()
|
||||
|
||||
inverter = InverterG3(FakeReader(), FakeWriter(), ('proxy.local', 10000))
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
inverter._Talent__set_serial_no(serial_no= "123344")
|
||||
|
||||
inverter.new_data['inverter'] = True
|
||||
|
||||
@@ -8,7 +8,7 @@ from app.src.infos import Infos
|
||||
from app.src.config import Config
|
||||
from app.src.inverter import Inverter
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3P
|
||||
from app.src.gen3plus.connection_g3p import ConnectionG3PServer
|
||||
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
|
||||
@@ -45,12 +45,12 @@ def module_init():
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_init():
|
||||
with patch.object(ConnectionG3P, '__init__', return_value= None) as conn:
|
||||
with patch.object(ConnectionG3PServer, '__init__', return_value= None) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.fixture
|
||||
def patch_conn_close():
|
||||
with patch.object(ConnectionG3P, 'close') as conn:
|
||||
with patch.object(ConnectionG3PServer, 'close') as conn:
|
||||
yield conn
|
||||
|
||||
class FakeReader():
|
||||
@@ -116,7 +116,7 @@ def test_method_calls(patch_conn_init, patch_conn_close):
|
||||
inverter.r_addr = ''
|
||||
|
||||
spy1.assert_called_once()
|
||||
spy1.assert_called_once_with(reader, writer, addr, None, server_side=True, client_mode=False)
|
||||
spy1.assert_called_once_with(reader, writer, addr, None, client_mode=False)
|
||||
|
||||
inverter.close()
|
||||
spy2.assert_called_once()
|
||||
@@ -133,7 +133,7 @@ async def test_remote_conn(config_conn, patch_open_connection, patch_conn_close)
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream
|
||||
assert inverter.remote.stream
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
|
||||
@@ -152,12 +152,12 @@ async def test_remote_except(config_conn, patch_open_connection, patch_conn_clos
|
||||
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream==None
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
test = TestType.RD_TEST_EXCEPT
|
||||
await inverter.async_create_remote()
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote_stream==None
|
||||
assert inverter.remote.stream==None
|
||||
inverter.close()
|
||||
spy1.assert_called_once()
|
||||
|
||||
@@ -172,6 +172,7 @@ async def test_mqtt_publish(config_conn, patch_open_connection, patch_conn_close
|
||||
Inverter.class_init()
|
||||
|
||||
inverter = InverterG3P(FakeReader(), FakeWriter(), ('proxy.local', 10000), client_mode=False)
|
||||
await inverter.async_publ_mqtt() # check call with invalid unique_id
|
||||
inverter._SolarmanV5__set_serial_no(snr= 123344)
|
||||
|
||||
inverter.new_data['inverter'] = True
|
||||
|
||||
@@ -157,8 +157,8 @@ async def test_modbus_conn(patch_open):
|
||||
async with ModbusConn('test.local', 1234) as stream:
|
||||
assert stream.node_id == 'G3P'
|
||||
assert stream.addr == ('test.local', 1234)
|
||||
assert type(stream._reader) is FakeReader
|
||||
assert type(stream._writer) is FakeWriter
|
||||
assert type(stream._ifc._reader) is FakeReader
|
||||
assert type(stream._ifc._writer) is FakeWriter
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 1
|
||||
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
@@ -209,7 +209,7 @@ async def test_modbus_cnf2(config_conn, patch_no_mqtt, patch_open):
|
||||
test += 1
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 1
|
||||
m.shutdown_started = True
|
||||
m._reader.on_recv.set()
|
||||
m._ifc._reader.on_recv.set()
|
||||
del m
|
||||
|
||||
assert 1 == test
|
||||
@@ -236,13 +236,13 @@ async def test_modbus_cnf3(config_conn, patch_no_mqtt, patch_open):
|
||||
test += 1
|
||||
if test == 1:
|
||||
m.shutdown_started = False
|
||||
m._reader.on_recv.set()
|
||||
m.ifc._reader.on_recv.set()
|
||||
await asyncio.sleep(0.1)
|
||||
assert m.state == State.closed
|
||||
await asyncio.sleep(0.1)
|
||||
else:
|
||||
m.shutdown_started = True
|
||||
m._reader.on_recv.set()
|
||||
m.ifc._reader.on_recv.set()
|
||||
del m
|
||||
|
||||
assert 2 == test
|
||||
@@ -269,13 +269,14 @@ async def test_mqtt_err(config_conn, patch_mqtt_err, patch_open):
|
||||
test += 1
|
||||
if test == 1:
|
||||
m.shutdown_started = False
|
||||
m._reader.on_recv.set()
|
||||
m._ifc._reader.on_recv.set()
|
||||
await asyncio.sleep(0.1)
|
||||
assert m.state == State.closed
|
||||
await asyncio.sleep(0.1)
|
||||
await asyncio.sleep(0.1)
|
||||
else:
|
||||
m.shutdown_started = True
|
||||
m._reader.on_recv.set()
|
||||
m._ifc._reader.on_recv.set()
|
||||
del m
|
||||
|
||||
await asyncio.sleep(0.01)
|
||||
@@ -301,13 +302,13 @@ async def test_mqtt_except(config_conn, patch_mqtt_except, patch_open):
|
||||
test += 1
|
||||
if test == 1:
|
||||
m.shutdown_started = False
|
||||
m._reader.on_recv.set()
|
||||
m._ifc._reader.on_recv.set()
|
||||
await asyncio.sleep(0.1)
|
||||
assert m.state == State.closed
|
||||
await asyncio.sleep(0.1)
|
||||
else:
|
||||
m.shutdown_started = True
|
||||
m._reader.on_recv.set()
|
||||
m._ifc._reader.on_recv.set()
|
||||
del m
|
||||
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
@@ -5,7 +5,7 @@ import aiomqtt
|
||||
import logging
|
||||
|
||||
from mock import patch, Mock
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.async_stream import AsyncIfcImpl
|
||||
from app.src.singleton import Singleton
|
||||
from app.src.mqtt import Mqtt
|
||||
from app.src.modbus import Modbus
|
||||
@@ -45,8 +45,7 @@ def config_no_conn(test_port):
|
||||
|
||||
@pytest.fixture
|
||||
def spy_at_cmd():
|
||||
ifc = AsyncIfc()
|
||||
conn = SolarmanV5(server_side=True, client_mode= False, ifc=ifc)
|
||||
conn = SolarmanV5(server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_2/'
|
||||
with patch.object(conn, 'send_at_cmd', wraps=conn.send_at_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
@@ -54,8 +53,7 @@ def spy_at_cmd():
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd():
|
||||
ifc = AsyncIfc()
|
||||
conn = SolarmanV5(server_side=True, client_mode= False, ifc=ifc)
|
||||
conn = SolarmanV5(server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
@@ -63,8 +61,7 @@ def spy_modbus_cmd():
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd_client():
|
||||
ifc = AsyncIfc()
|
||||
conn = SolarmanV5(server_side=False, client_mode= False, ifc=ifc)
|
||||
conn = SolarmanV5(server_side=False, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
|
||||
@@ -5,7 +5,7 @@ import asyncio
|
||||
import logging
|
||||
import random
|
||||
from math import isclose
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.async_stream import AsyncIfcImpl, StreamPtr
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
from app.src.config import Config
|
||||
from app.src.infos import Infos, Register
|
||||
@@ -34,14 +34,15 @@ class Mqtt():
|
||||
|
||||
class MemoryStream(SolarmanV5):
|
||||
def __init__(self, msg, chunks = (0,), server_side: bool = True):
|
||||
_ifc = AsyncIfc()
|
||||
_ifc = AsyncIfcImpl()
|
||||
super().__init__(server_side, client_mode=False, ifc=_ifc)
|
||||
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''
|
||||
self.ifc.write.reg_trigger(self.write_cb)
|
||||
self.ifc.tx_fifo.reg_trigger(self.write_cb)
|
||||
self.mqtt = Mqtt()
|
||||
self.__msg = msg
|
||||
self.__msg_len = len(msg)
|
||||
@@ -61,7 +62,9 @@ class MemoryStream(SolarmanV5):
|
||||
self.msg_recvd = []
|
||||
|
||||
def write_cb(self):
|
||||
self.sent_pdu = self.ifc.write.get()
|
||||
if self.test_exception_async_write:
|
||||
raise RuntimeError("Peer closed.")
|
||||
self.sent_pdu = self.ifc.tx_fifo.get()
|
||||
|
||||
def _timestamp(self):
|
||||
return timestamp
|
||||
@@ -85,25 +88,21 @@ class MemoryStream(SolarmanV5):
|
||||
chunk_len = self.__chunks[self.__chunk_idx]
|
||||
self.__chunk_idx += 1
|
||||
if chunk_len!=0:
|
||||
self.ifc.read += self.__msg[self.__offs:chunk_len]
|
||||
self.ifc.rx_fifo += self.__msg[self.__offs:chunk_len]
|
||||
copied_bytes = chunk_len - self.__offs
|
||||
self.__offs = chunk_len
|
||||
else:
|
||||
self.ifc.read += self.__msg[self.__offs:]
|
||||
self.ifc.rx_fifo += self.__msg[self.__offs:]
|
||||
copied_bytes = self.__msg_len - self.__offs
|
||||
self.__offs = self.__msg_len
|
||||
except Exception:
|
||||
pass # ignore exceptions here
|
||||
return copied_bytes
|
||||
|
||||
async def async_write(self, headline=''):
|
||||
if self.test_exception_async_write:
|
||||
raise RuntimeError("Peer closed.")
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remote_stream = c
|
||||
c. remote_stream = self
|
||||
self.remote.stream = c
|
||||
c. remote.stream = self
|
||||
return c
|
||||
|
||||
def _SolarmanV5__flush_recv_msg(self) -> None:
|
||||
@@ -689,9 +688,9 @@ def test_read_message(device_ind_msg):
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:00'
|
||||
assert m.data_len == 0xd4
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -710,9 +709,9 @@ def test_invalid_start_byte(invalid_start_byte, device_ind_msg):
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:00'
|
||||
assert m.data_len == 0xd4
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -730,9 +729,9 @@ def test_invalid_stop_byte(invalid_stop_byte):
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:00'
|
||||
assert m.data_len == 0xd4
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -755,9 +754,9 @@ def test_invalid_stop_byte2(invalid_stop_byte, device_ind_msg):
|
||||
assert m.msg_recvd[1]['data_len']==0xd4
|
||||
|
||||
assert m.unique_id == None
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -777,9 +776,9 @@ def test_invalid_stop_start_byte(invalid_stop_byte, invalid_start_byte):
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:00'
|
||||
assert m.data_len == 0xd4
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -801,9 +800,9 @@ def test_invalid_checksum(invalid_checksum, device_ind_msg):
|
||||
assert m.msg_recvd[1]['control']==0x4110
|
||||
assert m.msg_recvd[1]['seq']=='01:00'
|
||||
assert m.msg_recvd[1]['data_len']==0xd4
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -823,8 +822,8 @@ def test_read_message_twice(config_no_tsun_inv1, device_ind_msg, device_rsp_msg)
|
||||
assert m.msg_recvd[1]['control']==0x4110
|
||||
assert m.msg_recvd[1]['seq']=='01:01'
|
||||
assert m.msg_recvd[1]['data_len']==0xd4
|
||||
assert m.ifc.write.get()==device_rsp_msg+device_rsp_msg
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.tx_fifo.get()==device_rsp_msg+device_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -895,11 +894,11 @@ def test_read_two_messages(config_tsun_allow_all, device_ind_msg, device_rsp_msg
|
||||
assert m.msg_recvd[1]['data_len']==0x199
|
||||
assert '02b0' == m.db.get_db_value(Register.SENSOR_LIST, None)
|
||||
assert 0x02b0 == m.sensor_list
|
||||
assert m._forward_buffer==device_ind_msg+inverter_ind_msg
|
||||
assert m.ifc.write.get()==device_rsp_msg+inverter_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==device_ind_msg+inverter_ind_msg
|
||||
assert m.ifc.tx_fifo.get()==device_rsp_msg+inverter_rsp_msg
|
||||
|
||||
m._init_new_client_conn()
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages2(config_tsun_allow_all, inverter_ind_msg, inverter_ind_msg_81, inverter_rsp_msg, inverter_rsp_msg_81):
|
||||
@@ -920,11 +919,11 @@ def test_read_two_messages2(config_tsun_allow_all, inverter_ind_msg, inverter_in
|
||||
assert m.msg_recvd[1]['seq']=='03:03'
|
||||
assert m.msg_recvd[1]['data_len']==0x199
|
||||
assert m.time_ofs == 0x33e447a0
|
||||
assert m._forward_buffer==inverter_ind_msg+inverter_ind_msg_81
|
||||
assert m.ifc.write.get()==inverter_rsp_msg+inverter_rsp_msg_81
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg+inverter_ind_msg_81
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg+inverter_rsp_msg_81
|
||||
|
||||
m._init_new_client_conn()
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages3(config_tsun_allow_all, device_ind_msg2, device_rsp_msg2, inverter_ind_msg, inverter_rsp_msg):
|
||||
@@ -949,11 +948,11 @@ def test_read_two_messages3(config_tsun_allow_all, device_ind_msg2, device_rsp_m
|
||||
assert m.msg_recvd[1]['data_len']==0xd4
|
||||
assert '02b0' == m.db.get_db_value(Register.SENSOR_LIST, None)
|
||||
assert 0x02b0 == m.sensor_list
|
||||
assert m._forward_buffer==inverter_ind_msg+device_ind_msg2
|
||||
assert m.ifc.write.get()==inverter_rsp_msg+device_rsp_msg2
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg+device_ind_msg2
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg+device_rsp_msg2
|
||||
|
||||
m._init_new_client_conn()
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_unkown_frame_code(config_tsun_inv1, inverter_ind_msg_81, inverter_rsp_msg_81):
|
||||
@@ -968,9 +967,9 @@ def test_unkown_frame_code(config_tsun_inv1, inverter_ind_msg_81, inverter_rsp_m
|
||||
assert m.control == 0x4210
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.data_len == 0x199
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==inverter_rsp_msg_81
|
||||
assert m._forward_buffer==inverter_ind_msg_81
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg_81
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg_81
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -986,9 +985,9 @@ def test_unkown_message(config_tsun_inv1, unknown_msg):
|
||||
assert m.control == 0x5110
|
||||
assert str(m.seq) == '84:10'
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==unknown_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==unknown_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1004,9 +1003,9 @@ def test_device_rsp(config_tsun_inv1, device_rsp_msg):
|
||||
assert m.control == 0x1110
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1022,9 +1021,9 @@ def test_inverter_rsp(config_tsun_inv1, inverter_rsp_msg):
|
||||
assert m.control == 0x1210
|
||||
assert str(m.seq) == '02:02'
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1039,9 +1038,9 @@ def test_heartbeat_ind(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
assert m.control == 0x4710
|
||||
assert str(m.seq) == '84:11' # value after sending response
|
||||
assert m.data_len == 0x01
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==heartbeat_rsp_msg
|
||||
assert m._forward_buffer==heartbeat_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==heartbeat_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==heartbeat_ind_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1057,9 +1056,9 @@ def test_heartbeat_ind2(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
assert m.control == 0x4710
|
||||
assert str(m.seq) == '84:11' # value after sending response
|
||||
assert m.data_len == 0x01
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==heartbeat_rsp_msg
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==heartbeat_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1075,9 +1074,9 @@ def test_heartbeat_rsp(config_tsun_inv1, heartbeat_rsp_msg):
|
||||
assert m.control == 0x1710
|
||||
assert str(m.seq) == '11:84' # value after sending response
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1092,15 +1091,15 @@ def test_sync_start_ind(config_tsun_inv1, sync_start_ind_msg, sync_start_rsp_msg
|
||||
assert m.control == 0x4310
|
||||
assert str(m.seq) == '0d:0d' # value after sending response
|
||||
assert m.data_len == 47
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==sync_start_rsp_msg
|
||||
assert m._forward_buffer==sync_start_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==sync_start_rsp_msg
|
||||
assert m.ifc.fwd_fifo.peek()==sync_start_ind_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
|
||||
m.seq.server_side = False # simulate forawding to TSUN cloud
|
||||
m._update_header(m._forward_buffer)
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert str(m.seq) == '0d:0e' # value after forwarding indication
|
||||
assert m._forward_buffer==sync_start_fwd_msg
|
||||
assert m.ifc.fwd_fifo.get()==sync_start_fwd_msg
|
||||
|
||||
m.close()
|
||||
|
||||
@@ -1116,9 +1115,9 @@ def test_sync_start_rsp(config_tsun_inv1, sync_start_rsp_msg):
|
||||
assert m.control == 0x1310
|
||||
assert str(m.seq) == '0d:0d' # value after sending response
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1133,9 +1132,9 @@ def test_sync_end_ind(config_tsun_inv1, sync_end_ind_msg, sync_end_rsp_msg):
|
||||
assert m.control == 0x4810
|
||||
assert str(m.seq) == '07:07' # value after sending response
|
||||
assert m.data_len == 60
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==sync_end_rsp_msg
|
||||
assert m._forward_buffer==sync_end_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==sync_end_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==sync_end_ind_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1151,9 +1150,9 @@ def test_sync_end_rsp(config_tsun_inv1, sync_end_rsp_msg):
|
||||
assert m.control == 0x1810
|
||||
assert str(m.seq) == '07:07' # value after sending response
|
||||
assert m.data_len == 0x0a
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1171,9 +1170,9 @@ def test_build_modell_600(config_tsun_allow_all, inverter_ind_msg):
|
||||
assert '02b0' == m.db.get_db_value(Register.SENSOR_LIST, None)
|
||||
assert 0 == m.sensor_list # must not been set by an inverter data ind
|
||||
|
||||
m.ifc.write.clear() # clear send buffer for next test
|
||||
m.ifc.tx_clear() # clear send buffer for next test
|
||||
m._init_new_client_conn()
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_build_modell_1600(config_tsun_allow_all, inverter_ind_msg1600):
|
||||
@@ -1237,9 +1236,9 @@ def test_build_logger_modell(config_tsun_allow_all, device_ind_msg):
|
||||
|
||||
def test_msg_iterator():
|
||||
Message._registry.clear()
|
||||
m1 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfc())
|
||||
m2 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfc())
|
||||
m3 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfc())
|
||||
m1 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
m2 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
m3 = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
m3.close()
|
||||
del m3
|
||||
test1 = 0
|
||||
@@ -1257,7 +1256,7 @@ def test_msg_iterator():
|
||||
assert test2 == 1
|
||||
|
||||
def test_proxy_counter():
|
||||
m = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfc())
|
||||
m = SolarmanV5(server_side=True, client_mode=False, ifc=AsyncIfcImpl())
|
||||
assert m.new_data == {}
|
||||
m.db.stat['proxy']['Unknown_Msg'] = 0
|
||||
Infos.new_stat_data['proxy'] = False
|
||||
@@ -1281,16 +1280,14 @@ async def test_msg_build_modbus_req(config_tsun_inv1, device_ind_msg, device_rsp
|
||||
m.read()
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.ifc.write.get()==device_rsp_msg
|
||||
assert m._forward_buffer==device_ind_msg
|
||||
assert m.ifc.tx_fifo.get()==device_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==device_ind_msg
|
||||
|
||||
m.ifc.write.clear() # clear send buffer for next test
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.fwd_fifo.get() == b''
|
||||
assert m.sent_pdu == b'' # modbus command must be ignore, cause connection is still not up
|
||||
assert m.ifc.write.get() == b'' # modbus command must be ignore, cause connection is still not up
|
||||
assert m.ifc.tx_fifo.get() == b'' # modbus command must be ignore, cause connection is still not up
|
||||
|
||||
m.append_msg(inverter_ind_msg)
|
||||
m.read()
|
||||
@@ -1300,22 +1297,15 @@ async def test_msg_build_modbus_req(config_tsun_inv1, device_ind_msg, device_rsp
|
||||
assert m.msg_recvd[0]['seq']=='01:01'
|
||||
assert m.msg_recvd[1]['control']==0x4210
|
||||
assert m.msg_recvd[1]['seq']=='02:02'
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==inverter_rsp_msg
|
||||
assert m._forward_buffer==inverter_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg
|
||||
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.fwd_fifo.get() == b''
|
||||
assert m.sent_pdu == msg_modbus_cmd
|
||||
assert m.ifc.write.get()== b''
|
||||
|
||||
m.test_exception_async_write = True
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.write.get() == b''
|
||||
assert m.ifc.tx_fifo.get()== b''
|
||||
m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -1325,13 +1315,13 @@ async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inv
|
||||
m.read() # read device ind
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.ifc.write.get()==device_rsp_msg
|
||||
assert m._forward_buffer==device_ind_msg
|
||||
assert m.ifc.tx_fifo.get()==device_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==device_ind_msg
|
||||
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_at_cmd('AT+TIME=214028,1,60,120')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.sent_pdu == b''
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.mqtt.key == ''
|
||||
assert m.mqtt.data == ""
|
||||
@@ -1340,13 +1330,15 @@ async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inv
|
||||
m.read() # read inverter ind
|
||||
assert m.control == 0x4210
|
||||
assert str(m.seq) == '02:02'
|
||||
assert m.ifc.write.get()==inverter_rsp_msg
|
||||
assert m._forward_buffer==inverter_ind_msg
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg
|
||||
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_at_cmd('AT+TIME=214028,1,60,120')
|
||||
assert m.ifc.write.get()==at_command_ind_msg
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.fwd_fifo.get() == b''
|
||||
assert m.ifc.tx_fifo.get()== b''
|
||||
assert m.sent_pdu == at_command_ind_msg
|
||||
m.sent_pdu = bytearray()
|
||||
|
||||
assert str(m.seq) == '02:03'
|
||||
assert m.mqtt.key == ''
|
||||
assert m.mqtt.data == ""
|
||||
@@ -1355,17 +1347,20 @@ async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inv
|
||||
m.read() # read at resp
|
||||
assert m.control == 0x1510
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.key == 'at_resp'
|
||||
assert m.data == "+ok"
|
||||
|
||||
m.sent_pdu = bytearray()
|
||||
m.test_exception_async_write = True
|
||||
await m.send_at_cmd('AT+TIME=214028,1,60,120')
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.sent_pdu == b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.sent_pdu == b''
|
||||
assert str(m.seq) == '03:04'
|
||||
assert m.forward_at_cmd_resp == False
|
||||
assert m.mqtt.key == ''
|
||||
@@ -1379,13 +1374,12 @@ async def test_at_cmd_blocked(config_tsun_allow_all, device_ind_msg, device_rsp_
|
||||
m.read()
|
||||
assert m.control == 0x4110
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.ifc.write.get()==device_rsp_msg
|
||||
assert m._forward_buffer==device_ind_msg
|
||||
assert m.ifc.tx_fifo.get()==device_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==device_ind_msg
|
||||
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_at_cmd('AT+WEBU')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert str(m.seq) == '01:01'
|
||||
assert m.mqtt.key == ''
|
||||
assert m.mqtt.data == ""
|
||||
@@ -1394,15 +1388,14 @@ async def test_at_cmd_blocked(config_tsun_allow_all, device_ind_msg, device_rsp_
|
||||
m.read()
|
||||
assert m.control == 0x4210
|
||||
assert str(m.seq) == '02:02'
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==inverter_rsp_msg
|
||||
assert m._forward_buffer==inverter_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==inverter_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==inverter_ind_msg
|
||||
|
||||
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||
await m.send_at_cmd('AT+WEBU')
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert str(m.seq) == '02:02'
|
||||
assert m.forward_at_cmd_resp == False
|
||||
assert m.mqtt.key == 'at_resp'
|
||||
@@ -1424,9 +1417,9 @@ def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg):
|
||||
assert m.control == 0x4510
|
||||
assert str(m.seq) == '03:02'
|
||||
assert m.data_len == 39
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==at_command_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==at_command_ind_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 1
|
||||
assert m.db.stat['proxy']['AT_Command_Blocked'] == 0
|
||||
@@ -1448,9 +1441,9 @@ def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
|
||||
assert m.control == 0x4510
|
||||
assert str(m.seq) == '03:02'
|
||||
assert m.data_len == 23
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command_Blocked'] == 1
|
||||
@@ -1470,8 +1463,8 @@ def test_msg_at_command_rsp1(config_tsun_inv1, at_command_rsp_msg):
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==17
|
||||
assert m._forward_buffer==at_command_rsp_msg
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==at_command_rsp_msg
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1489,8 +1482,8 @@ def test_msg_at_command_rsp2(config_tsun_inv1, at_command_rsp_msg):
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==17
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1514,8 +1507,8 @@ def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd, msg_modbus_cmd_fwd):
|
||||
assert str(c.seq) == '03:02'
|
||||
assert c.header_len==11
|
||||
assert c.data_len==23
|
||||
assert c._forward_buffer==b''
|
||||
assert c.ifc.write.get()==b''
|
||||
assert c.ifc.fwd_fifo.get()==b''
|
||||
assert c.ifc.tx_fifo.get()==b''
|
||||
assert m.sent_pdu == msg_modbus_cmd_fwd
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
@@ -1541,8 +1534,8 @@ def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
assert str(c.seq) == '03:02'
|
||||
assert c.header_len==11
|
||||
assert c.data_len==23
|
||||
assert c._forward_buffer==b''
|
||||
assert c.ifc.write.get()==b''
|
||||
assert c.ifc.fwd_fifo.get()==b''
|
||||
assert c.ifc.tx_fifo.get()==b''
|
||||
assert m.sent_pdu==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
@@ -1564,8 +1557,8 @@ def test_msg_unknown_cmd_req(config_tsun_inv1, msg_unknown_cmd):
|
||||
assert str(m.seq) == '03:02'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==23
|
||||
assert m._forward_buffer==msg_unknown_cmd
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_unknown_cmd
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
@@ -1585,8 +1578,8 @@ def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==59
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1609,21 +1602,20 @@ def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp):
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 0
|
||||
assert m.msg_count == 1
|
||||
assert m._forward_buffer==msg_modbus_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V4.0.10'
|
||||
assert m.new_data['inverter'] == True
|
||||
m.new_data['inverter'] = False
|
||||
|
||||
m.mb.req_pend = True
|
||||
m._forward_buffer = bytearray()
|
||||
m.append_msg(msg_modbus_rsp)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 0
|
||||
assert m.msg_count == 2
|
||||
assert m._forward_buffer==msg_modbus_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V4.0.10'
|
||||
assert m.new_data['inverter'] == False
|
||||
|
||||
@@ -1647,20 +1639,19 @@ def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp):
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 0
|
||||
assert m.msg_count == 1
|
||||
assert m._forward_buffer==msg_modbus_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V4.0.10'
|
||||
assert m.new_data['inverter'] == True
|
||||
m.new_data['inverter'] = False
|
||||
|
||||
m._forward_buffer = bytearray()
|
||||
m.append_msg(msg_modbus_rsp)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 5
|
||||
assert m.msg_count == 2
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V4.0.10'
|
||||
assert m.new_data['inverter'] == False
|
||||
|
||||
@@ -1678,8 +1669,8 @@ def test_msg_unknown_rsp(config_tsun_inv1, msg_unknown_cmd_rsp):
|
||||
assert str(m.seq) == '03:03'
|
||||
assert m.header_len==11
|
||||
assert m.data_len==59
|
||||
assert m._forward_buffer==msg_unknown_cmd_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_unknown_cmd_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1692,8 +1683,8 @@ def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_invalid):
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1715,8 +1706,8 @@ def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp):
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.msg_count == 1
|
||||
assert m._forward_buffer==msg_modbus_rsp
|
||||
assert m.ifc.write.get()== b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp
|
||||
assert m.ifc.tx_fifo.get()== b''
|
||||
assert m.mb.err == 0
|
||||
assert m.modbus_elms == 20-1 # register 0x300d is unknown, so one value can't be mapped
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
@@ -1739,9 +1730,9 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp
|
||||
assert m.control == 0x4710
|
||||
assert str(m.seq) == '84:11' # value after sending response
|
||||
assert m.data_len == 0x01
|
||||
assert m.ifc.read.get()==b''
|
||||
assert m.ifc.write.get()==heartbeat_rsp_msg
|
||||
assert m._forward_buffer==heartbeat_ind_msg
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==heartbeat_rsp_msg
|
||||
assert m.ifc.fwd_fifo.get()==heartbeat_ind_msg
|
||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||
|
||||
assert m.state == State.up
|
||||
@@ -1750,16 +1741,16 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x12\x84!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x03\x30\x00\x000J\xde\x86\x15')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x13\x84!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x03\x30\x00\x000J\xde\x87\x15')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
m.state = State.closed
|
||||
m.sent_pdu = bytearray()
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==bytearray(b'')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert next(m.mb_timer.exp_count) == 4
|
||||
m.close()
|
||||
|
||||
@@ -1781,16 +1772,29 @@ async def test_start_client_mode(config_tsun_inv1, str_test_ip):
|
||||
assert m.state == State.up
|
||||
assert m.no_forwarding == True
|
||||
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert isclose(m.mb_timeout, 0.5)
|
||||
assert next(m.mb_timer.exp_count) == 0
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x02\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf2\x15')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x03\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf3\x15')
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert next(m.mb_timer.exp_count) == 3
|
||||
m.close()
|
||||
|
||||
def test_timeout(config_tsun_inv1):
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
assert m.state == State.init
|
||||
assert SolarmanV5.MAX_START_TIME == m._timeout()
|
||||
m.state = State.up
|
||||
m.modbus_polling = True
|
||||
assert SolarmanV5.MAX_INV_IDLE_TIME == m._timeout()
|
||||
m.modbus_polling = False
|
||||
assert SolarmanV5.MAX_DEF_IDLE_TIME == m._timeout()
|
||||
m.state = State.closed
|
||||
m.close()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# test_with_pytest.py
|
||||
import pytest, logging, asyncio
|
||||
from math import isclose
|
||||
from app.src.async_ifc import AsyncIfc
|
||||
from app.src.async_stream import AsyncIfcImpl, StreamPtr
|
||||
from app.src.gen3.talent import Talent, Control
|
||||
from app.src.config import Config
|
||||
from app.src.infos import Infos, Register
|
||||
@@ -19,13 +19,15 @@ tracer = logging.getLogger('tracer')
|
||||
|
||||
class MemoryStream(Talent):
|
||||
def __init__(self, msg, chunks = (0,), server_side: bool = True):
|
||||
super().__init__(server_side, AsyncIfc())
|
||||
self.ifc = AsyncIfcImpl()
|
||||
super().__init__(server_side, self.ifc)
|
||||
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''
|
||||
self.ifc.write.reg_trigger(self.write_cb)
|
||||
self.ifc.tx_fifo.reg_trigger(self.write_cb)
|
||||
self.__msg = msg
|
||||
self.__msg_len = len(msg)
|
||||
self.__chunks = chunks
|
||||
@@ -34,12 +36,11 @@ class MemoryStream(Talent):
|
||||
self.msg_count = 0
|
||||
self.addr = 'Test: SrvSide'
|
||||
self.send_msg_ofs = 0
|
||||
self.test_exception_async_write = False
|
||||
self.msg_recvd = []
|
||||
self.remote_stream = None
|
||||
self.remote.stream = None
|
||||
|
||||
def write_cb(self):
|
||||
self.sent_pdu = self.ifc.write.get()
|
||||
self.sent_pdu = self.ifc.tx_fifo.get()
|
||||
|
||||
|
||||
def append_msg(self, msg):
|
||||
@@ -53,11 +54,11 @@ class MemoryStream(Talent):
|
||||
chunk_len = self.__chunks[self.__chunk_idx]
|
||||
self.__chunk_idx += 1
|
||||
if chunk_len!=0:
|
||||
self.ifc.read += self.__msg[self.__offs:chunk_len]
|
||||
self.ifc.rx_fifo += self.__msg[self.__offs:chunk_len]
|
||||
copied_bytes = chunk_len - self.__offs
|
||||
self.__offs = chunk_len
|
||||
else:
|
||||
self.ifc.read += self.__msg[self.__offs:]
|
||||
self.ifc.rx_fifo += self.__msg[self.__offs:]
|
||||
copied_bytes = self.__msg_len - self.__offs
|
||||
self.__offs = self.__msg_len
|
||||
except Exception:
|
||||
@@ -72,8 +73,8 @@ class MemoryStream(Talent):
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
self.remote_stream = c
|
||||
c. remote_stream = self
|
||||
self.remote.stream = c
|
||||
c. remote.stream = self
|
||||
return c
|
||||
|
||||
def _Talent__flush_recv_msg(self) -> None:
|
||||
@@ -90,10 +91,6 @@ class MemoryStream(Talent):
|
||||
|
||||
self.msg_count += 1
|
||||
|
||||
async def async_write(self, headline=''):
|
||||
if self.test_exception_async_write:
|
||||
raise RuntimeError("Peer closed.")
|
||||
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -746,7 +743,9 @@ def test_read_message(msg_contact_info):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==25
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.rx_get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_read_message_twice(config_no_tsun_inv1, msg_inverter_ind):
|
||||
@@ -766,7 +765,7 @@ def test_read_message_twice(config_no_tsun_inv1, msg_inverter_ind):
|
||||
assert m.msg_recvd[1]['data_len']==120
|
||||
assert m.id_str == b"R170000000000001"
|
||||
assert m.unique_id == 'R170000000000001'
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
m.close()
|
||||
|
||||
def test_read_message_long_id(msg_contact_info_long_id):
|
||||
@@ -851,15 +850,15 @@ def test_read_two_messages(config_tsun_allow_all, msg2_contact_info,msg_contact_
|
||||
assert m.msg_recvd[1]['msg_id']==0
|
||||
assert m.msg_recvd[1]['header_len']==23
|
||||
assert m.msg_recvd[1]['data_len']==25
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_contact_rsp + msg_contact_rsp2
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_contact_rsp + msg_contact_rsp2
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
|
||||
m.ifc.write.clear() # clear send buffer for next test
|
||||
m.ifc.tx_clear() # clear send buffer for next test
|
||||
m.contact_name = b'solarhub'
|
||||
m.contact_mail = b'solarhub@123456'
|
||||
m._init_new_client_conn()
|
||||
assert m.ifc.write.get()==b'\x00\x00\x00,\x10R170000000000002\x91\x00\x08solarhub\x0fsolarhub@123456'
|
||||
assert m.ifc.tx_fifo.get()==b'\x00\x00\x00,\x10R170000000000002\x91\x00\x08solarhub\x0fsolarhub@123456'
|
||||
m.close()
|
||||
|
||||
def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp):
|
||||
@@ -876,8 +875,8 @@ def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==25
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_contact_rsp
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_contact_rsp
|
||||
m.close()
|
||||
|
||||
def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_contact_rsp):
|
||||
@@ -894,8 +893,8 @@ def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==23
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_contact_rsp
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_contact_rsp
|
||||
m.close()
|
||||
|
||||
def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp):
|
||||
@@ -912,8 +911,8 @@ def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==25
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_contact_rsp
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_contact_rsp
|
||||
m.close()
|
||||
|
||||
def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_contact_rsp):
|
||||
@@ -930,8 +929,8 @@ def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==23
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_contact_rsp
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_contact_rsp
|
||||
m.close()
|
||||
|
||||
def test_msg_contact_resp(config_tsun_inv1, msg_contact_rsp):
|
||||
@@ -949,8 +948,8 @@ def test_msg_contact_resp(config_tsun_inv1, msg_contact_rsp):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -969,8 +968,8 @@ def test_msg_contact_resp_2(config_tsun_inv1, msg_contact_rsp):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==msg_contact_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_contact_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -989,8 +988,8 @@ def test_msg_contact_resp_3(config_tsun_inv1, msg_contact_rsp):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==msg_contact_rsp
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_contact_rsp
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1007,8 +1006,8 @@ def test_msg_contact_invalid(config_tsun_inv1, msg_contact_invalid):
|
||||
assert m.msg_id==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==msg_contact_invalid
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_contact_invalid
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1028,8 +1027,8 @@ def test_msg_get_time(config_tsun_inv1, msg_get_time):
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==0
|
||||
assert m.state==State.pend
|
||||
assert m._forward_buffer==msg_get_time
|
||||
assert m.ifc.write.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00'
|
||||
assert m.ifc.fwd_fifo.get()==msg_get_time
|
||||
assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00'
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1049,8 +1048,8 @@ def test_msg_get_time_autark(config_no_tsun_inv1, msg_get_time):
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==0
|
||||
assert m.state==State.received
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==bytearray(b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00')
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==bytearray(b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00')
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1060,7 +1059,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.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
|
||||
@@ -1073,10 +1072,10 @@ def test_msg_time_resp(config_tsun_inv1, msg_time_rsp):
|
||||
assert m.ts_offset==3600000
|
||||
assert s.ts_offset==3600000
|
||||
assert m.data_len==8
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
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.remote.stream = None
|
||||
s.close()
|
||||
m.close()
|
||||
|
||||
@@ -1094,8 +1093,8 @@ def test_msg_time_resp_autark(config_no_tsun_inv1, msg_time_rsp):
|
||||
assert m.header_len==23
|
||||
assert m.ts_offset==3600000
|
||||
assert m.data_len==8
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1113,8 +1112,8 @@ def test_msg_time_inv_resp(config_tsun_inv1, msg_time_rsp_inv):
|
||||
assert m.header_len==23
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==4
|
||||
assert m._forward_buffer==msg_time_rsp_inv
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_time_rsp_inv
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1132,8 +1131,8 @@ def test_msg_time_invalid(config_tsun_inv1, msg_time_invalid):
|
||||
assert m.header_len==23
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==0
|
||||
assert m._forward_buffer==msg_time_invalid
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_time_invalid
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1151,8 +1150,8 @@ def test_msg_time_invalid_autark(config_no_tsun_inv1, msg_time_invalid):
|
||||
assert m.ts_offset==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==0
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1175,8 +1174,8 @@ def test_msg_act_time(config_no_modbus_poll, msg_act_time, msg_act_time_ack):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==9
|
||||
assert m.state == State.up
|
||||
assert m._forward_buffer==msg_act_time
|
||||
assert m.ifc.write.get()==msg_act_time_ack
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time
|
||||
assert m.ifc.tx_fifo.get()==msg_act_time_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert 125 == m.db.get_db_value(Register.POLLING_INTERVAL, 0)
|
||||
m.close()
|
||||
@@ -1199,8 +1198,8 @@ def test_msg_act_time2(config_tsun_inv1, msg_act_time, msg_act_time_ack):
|
||||
assert m.ts_offset==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==9
|
||||
assert m._forward_buffer==msg_act_time
|
||||
assert m.ifc.write.get()==msg_act_time_ack
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time
|
||||
assert m.ifc.tx_fifo.get()==msg_act_time_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert 123 == m.db.get_db_value(Register.POLLING_INTERVAL, 0)
|
||||
m.close()
|
||||
@@ -1220,8 +1219,8 @@ def test_msg_act_time_ofs(config_tsun_inv1, msg_act_time, msg_act_time_ofs, msg_
|
||||
assert m.ts_offset==3600
|
||||
assert m.header_len==23
|
||||
assert m.data_len==9
|
||||
assert m._forward_buffer==msg_act_time_ofs
|
||||
assert m.ifc.write.get()==msg_act_time_ack
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time_ofs
|
||||
assert m.ifc.tx_fifo.get()==msg_act_time_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1240,8 +1239,8 @@ def test_msg_act_time_ofs2(config_tsun_inv1, msg_act_time, msg_act_time_ofs, msg
|
||||
assert m.ts_offset==-3600
|
||||
assert m.header_len==23
|
||||
assert m.data_len==9
|
||||
assert m._forward_buffer==msg_act_time
|
||||
assert m.ifc.write.get()==msg_act_time_ack
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time
|
||||
assert m.ifc.tx_fifo.get()==msg_act_time_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1260,8 +1259,8 @@ def test_msg_act_time_autark(config_no_tsun_inv1, msg_act_time, msg_act_time_ack
|
||||
assert m.ts_offset==0
|
||||
assert m.header_len==23
|
||||
assert m.data_len==9
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==msg_act_time_ack
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==msg_act_time_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1278,8 +1277,8 @@ def test_msg_act_time_ack(config_tsun_inv1, msg_act_time_ack):
|
||||
assert m.msg_id==153
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1296,8 +1295,8 @@ def test_msg_act_time_cmd(config_tsun_inv1, msg_act_time_cmd):
|
||||
assert m.msg_id==153
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==msg_act_time_cmd
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time_cmd
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1314,8 +1313,8 @@ def test_msg_act_time_inv(config_tsun_inv1, msg_act_time_inv):
|
||||
assert m.msg_id==153
|
||||
assert m.header_len==23
|
||||
assert m.data_len==8
|
||||
assert m._forward_buffer==msg_act_time_inv
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_act_time_inv
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1333,12 +1332,12 @@ def test_msg_cntrl_ind(config_tsun_inv1, msg_controller_ind, msg_controller_ind_
|
||||
assert m.header_len==23
|
||||
assert m.data_len==284
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_controller_ind
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_controller_ind
|
||||
m.ts_offset = -4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_controller_ind_ts_offs
|
||||
assert m.ifc.write.get()==msg_controller_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_controller_ind_ts_offs
|
||||
assert m.ifc.tx_fifo.get()==msg_controller_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1355,8 +1354,8 @@ def test_msg_cntrl_ack(config_tsun_inv1, msg_controller_ack):
|
||||
assert m.msg_id==113
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1374,12 +1373,12 @@ def test_msg_cntrl_invalid(config_tsun_inv1, msg_controller_invalid):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_controller_invalid
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_controller_invalid
|
||||
m.ts_offset = -4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_controller_invalid
|
||||
assert m.ifc.write.get()==b''
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_controller_invalid
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1398,12 +1397,12 @@ def test_msg_inv_ind(config_tsun_inv1, msg_inverter_ind, msg_inverter_ind_ts_off
|
||||
assert m.header_len==23
|
||||
assert m.data_len==120
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_ind
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_inverter_ind
|
||||
m.ts_offset = +256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_ind_ts_offs
|
||||
assert m.ifc.write.get()==msg_inverter_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_ind_ts_offs
|
||||
assert m.ifc.tx_fifo.get()==msg_inverter_ack
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1425,9 +1424,9 @@ def test_msg_inv_ind1(config_tsun_inv1, msg_inverter_ind2, msg_inverter_ind_ts_o
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1263
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_ind2
|
||||
assert m.ifc.write.get()==msg_inverter_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_ind2
|
||||
assert m.ifc.tx_fifo.get()==msg_inverter_ack
|
||||
assert m.db.get_db_value(Register.TS_GRID) == 1691243349
|
||||
m.close()
|
||||
|
||||
@@ -1449,9 +1448,9 @@ def test_msg_inv_ind2(config_tsun_inv1, msg_inverter_ind_new, msg_inverter_ind_t
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1165
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_ind_new
|
||||
assert m.ifc.write.get()==msg_inverter_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_ind_new
|
||||
assert m.ifc.tx_fifo.get()==msg_inverter_ack
|
||||
assert m.db.get_db_value(Register.INVERTER_STATUS) == None
|
||||
assert m.db.get_db_value(Register.TS_GRID) == None
|
||||
m.db.db['grid'] = {'Output_Power': 100}
|
||||
@@ -1477,9 +1476,9 @@ def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1263
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_ind_0w
|
||||
assert m.ifc.write.get()==msg_inverter_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_ind_0w
|
||||
assert m.ifc.tx_fifo.get()==msg_inverter_ack
|
||||
assert m.db.get_db_value(Register.INVERTER_STATUS) == 1
|
||||
assert isclose(m.db.db['grid']['Output_Power'], 0.5)
|
||||
m.close()
|
||||
@@ -1501,8 +1500,8 @@ def test_msg_inv_ack(config_tsun_inv1, msg_inverter_ack):
|
||||
assert m.msg_id==4
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -1520,12 +1519,12 @@ def test_msg_inv_invalid(config_tsun_inv1, msg_inverter_invalid):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_invalid
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_inverter_invalid
|
||||
m.ts_offset = 256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_inverter_invalid
|
||||
assert m.ifc.write.get()==b''
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_invalid
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
@@ -1544,12 +1543,12 @@ def test_msg_ota_req(config_tsun_inv1, msg_ota_req):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==259
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_ota_req
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_ota_req
|
||||
m.ts_offset = 4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_ota_req
|
||||
assert m.ifc.write.get()==b''
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_ota_req
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['OTA_Start_Msg'] == 1
|
||||
m.close()
|
||||
@@ -1571,12 +1570,12 @@ def test_msg_ota_ack(config_tsun_inv1, msg_ota_ack):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_ota_ack
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_ota_ack
|
||||
m.ts_offset = 256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_ota_ack
|
||||
assert m.ifc.write.get()==b''
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.get()==msg_ota_ack
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['OTA_Start_Msg'] == 0
|
||||
m.close()
|
||||
@@ -1596,12 +1595,12 @@ def test_msg_ota_invalid(config_tsun_inv1, msg_ota_invalid):
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==msg_ota_invalid
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.fwd_fifo.peek()==msg_ota_invalid
|
||||
m.ts_offset = 4096
|
||||
assert m._forward_buffer==msg_ota_invalid
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_ota_invalid
|
||||
m._update_header(m.ifc.fwd_fifo.peek())
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
assert m.db.stat['proxy']['OTA_Start_Msg'] == 0
|
||||
m.close()
|
||||
@@ -1619,8 +1618,8 @@ def test_msg_unknown(config_tsun_inv1, msg_unknown):
|
||||
assert m.msg_id==23
|
||||
assert m.header_len==23
|
||||
assert m.data_len==4
|
||||
assert m._forward_buffer==msg_unknown
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_unknown
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert 1 == m.db.stat['proxy']['Unknown_Msg']
|
||||
m.close()
|
||||
|
||||
@@ -1640,9 +1639,9 @@ def test_ctrl_byte():
|
||||
|
||||
|
||||
def test_msg_iterator():
|
||||
m1 = Talent(server_side=True, ifc=AsyncIfc())
|
||||
m2 = Talent(server_side=True, ifc=AsyncIfc())
|
||||
m3 = Talent(server_side=True, ifc=AsyncIfc())
|
||||
m1 = Talent(server_side=True, ifc=AsyncIfcImpl())
|
||||
m2 = Talent(server_side=True, ifc=AsyncIfcImpl())
|
||||
m3 = Talent(server_side=True, ifc=AsyncIfcImpl())
|
||||
m3.close()
|
||||
del m3
|
||||
test1 = 0
|
||||
@@ -1744,11 +1743,11 @@ def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
assert c.msg_id==119
|
||||
assert c.header_len==23
|
||||
assert c.data_len==13
|
||||
assert c._forward_buffer==b''
|
||||
assert c.ifc.write.get()==b''
|
||||
assert c.ifc.fwd_fifo.get()==b''
|
||||
assert c.ifc.tx_fifo.get()==b''
|
||||
assert m.id_str == b"R170000000000001"
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.sent_pdu == msg_modbus_cmd
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 1
|
||||
@@ -1774,11 +1773,11 @@ def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd):
|
||||
assert c.msg_id==119
|
||||
assert c.header_len==23
|
||||
assert c.data_len==13
|
||||
assert c._forward_buffer==b''
|
||||
assert c.ifc.write.get()==b''
|
||||
assert c.ifc.fwd_fifo.get()==b''
|
||||
assert c.ifc.tx_fifo.get()==b''
|
||||
assert m.id_str == b"R170000000000001"
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.sent_pdu == b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 1
|
||||
@@ -1803,10 +1802,10 @@ def test_msg_modbus_req3(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
assert c.msg_id==119
|
||||
assert c.header_len==23
|
||||
assert c.data_len==13
|
||||
assert c._forward_buffer==b''
|
||||
assert c.ifc.write.get()==b''
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert c.ifc.fwd_fifo.get()==b''
|
||||
assert c.ifc.tx_fifo.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.sent_pdu ==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
@@ -1828,8 +1827,8 @@ def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
assert m.msg_id==119
|
||||
assert m.header_len==23
|
||||
assert m.data_len==13
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1850,8 +1849,8 @@ def test_msg_modbus_cloud_rsp(config_tsun_inv1, msg_modbus_rsp):
|
||||
assert m.msg_id==119
|
||||
assert m.header_len==23
|
||||
assert m.data_len==13
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Msg'] == 1
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
@@ -1878,8 +1877,8 @@ def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp20):
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 5
|
||||
assert m.msg_count == 2
|
||||
assert m._forward_buffer==msg_modbus_rsp20
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp20
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.db == {'collector': {'Serial_Number': 'R170000000000001'}, 'inverter': {'Version': 'V5.1.09', 'Rated_Power': 300}, 'grid': {'Timestamp': m._utc(), 'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'Timestamp': m._utc(), 'pv1': {'Voltage': 0.8, 'Current': 0.0, 'Power': 0.0}, 'pv2': {'Voltage': 34.5, 'Current': 2.89, 'Power': 99.8}, 'pv3': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}, 'pv4': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}}}
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V5.1.09'
|
||||
assert m.db.get_db_value(Register.TS_GRID) == m._utc()
|
||||
@@ -1908,8 +1907,8 @@ def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp21):
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 5
|
||||
assert m.msg_count == 2
|
||||
assert m._forward_buffer==msg_modbus_rsp21
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp21
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.db == {'collector': {'Serial_Number': 'R170000000000001'}, 'inverter': {'Version': 'V5.1.0E', 'Rated_Power': 300}, 'grid': {'Timestamp': m._utc(), 'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'Timestamp': m._utc(), 'pv1': {'Voltage': 0.8, 'Current': 0.0, 'Power': 0.0}, 'pv2': {'Voltage': 34.5, 'Current': 2.89, 'Power': 99.8}, 'pv3': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}, 'pv4': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}}}
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V5.1.0E'
|
||||
assert m.db.get_db_value(Register.TS_GRID) == m._utc()
|
||||
@@ -1937,9 +1936,9 @@ def test_msg_modbus_rsp4(config_tsun_inv1, msg_modbus_rsp21):
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
assert m.mb.err == 0
|
||||
assert m.msg_count == 1
|
||||
assert m._forward_buffer==msg_modbus_rsp21
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp21
|
||||
assert m.modbus_elms == 19
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.db == db_values
|
||||
assert m.db.get_db_value(Register.VERSION) == 'V5.1.0E'
|
||||
assert m.db.get_db_value(Register.TS_GRID) == m._utc()
|
||||
@@ -1962,8 +1961,8 @@ def test_msg_modbus_rsp_new(config_tsun_inv1, msg_modbus_rsp20_new):
|
||||
assert m.msg_id==135
|
||||
assert m.header_len==23
|
||||
assert m.data_len==107
|
||||
assert m._forward_buffer==b''
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -1982,8 +1981,8 @@ def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_inv):
|
||||
assert m.msg_id==119
|
||||
assert m.header_len==23
|
||||
assert m.data_len==13
|
||||
assert m._forward_buffer==msg_modbus_inv
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_inv
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
@@ -2011,8 +2010,8 @@ def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp20):
|
||||
assert m.msg_id == 119
|
||||
assert m.header_len == 23
|
||||
assert m.data_len == 50
|
||||
assert m._forward_buffer==msg_modbus_rsp20
|
||||
assert m.ifc.write.get() == b''
|
||||
assert m.ifc.fwd_fifo.get()==msg_modbus_rsp20
|
||||
assert m.ifc.tx_fifo.get() == b''
|
||||
assert m.mb.err == 0
|
||||
assert m.modbus_elms == 20-1 # register 0x300d is unknown, so one value can't be mapped
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
@@ -2026,24 +2025,16 @@ async def test_msg_build_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
m.id_str = b"R170000000000001"
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.write.get() == b''
|
||||
assert m.ifc.fwd_fifo.get() == b''
|
||||
assert m.ifc.tx_fifo.get() == b''
|
||||
assert m.sent_pdu == b''
|
||||
|
||||
m.state = State.up
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.write.get() == b''
|
||||
assert m.ifc.fwd_fifo.get() == b''
|
||||
assert m.ifc.tx_fifo.get() == b''
|
||||
assert m.sent_pdu == msg_modbus_cmd
|
||||
|
||||
m.sent_pdu = bytearray(0) # clear send buffer for next test
|
||||
m.test_exception_async_write = True
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
assert 0 == m.send_msg_ofs
|
||||
assert m._forward_buffer == b''
|
||||
assert m.ifc.write.get() == b''
|
||||
assert m.sent_pdu == b''
|
||||
m.close()
|
||||
|
||||
def test_modbus_no_polling(config_no_modbus_poll, msg_get_time):
|
||||
@@ -2061,8 +2052,8 @@ def test_modbus_no_polling(config_no_modbus_poll, msg_get_time):
|
||||
assert m.header_len==23
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==0
|
||||
assert m._forward_buffer==msg_get_time
|
||||
assert m.ifc.write.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00'
|
||||
assert m.ifc.fwd_fifo.get()==msg_get_time
|
||||
assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00'
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -2085,25 +2076,25 @@ async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind):
|
||||
assert m.header_len==23
|
||||
assert m.ts_offset==0
|
||||
assert m.data_len==120
|
||||
assert m._forward_buffer==msg_inverter_ind
|
||||
assert m.ifc.write.get()==b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01'
|
||||
assert m.ifc.fwd_fifo.get()==msg_inverter_ind
|
||||
assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01'
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
|
||||
m.ifc.write.clear() # clear send buffer for next test
|
||||
m.ifc.tx_clear() # clear send buffer for next test
|
||||
assert isclose(m.mb_timeout, 0.5)
|
||||
assert next(m.mb_timer.exp_count) == 0
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x030\x00\x000J\xde'
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x030\x00\x000J\xde'
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x03\x20\x00\x00`N"'
|
||||
assert m.ifc.write.get()==b''
|
||||
assert m.ifc.tx_fifo.get()==b''
|
||||
assert next(m.mb_timer.exp_count) == 4
|
||||
m.close()
|
||||
|
||||
@@ -2146,3 +2137,15 @@ def test_multiiple_recv_buf(config_tsun_allow_all, multiple_recv_buf):
|
||||
assert m.db.stat['proxy']['Invalid_Data_Type'] == 1
|
||||
|
||||
m.close()
|
||||
|
||||
def test_timeout(config_tsun_inv1):
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
assert m.state == State.init
|
||||
assert Talent.MAX_START_TIME == m._timeout()
|
||||
m.state = State.up
|
||||
m.modbus_polling = True
|
||||
assert Talent.MAX_INV_IDLE_TIME == m._timeout()
|
||||
m.modbus_polling = False
|
||||
assert Talent.MAX_DEF_IDLE_TIME == m._timeout()
|
||||
m.close()
|
||||
|
||||
11
tsun.code-workspace
Normal file
11
tsun.code-workspace
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../wiki"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
Reference in New Issue
Block a user