Merge remote-tracking branch 'origin/main'
# Conflicts: # typescript/Frontend/src/config/axiosConfig.tsx
This commit is contained in:
commit
107a439e44
|
@ -267,7 +267,7 @@ public class Controller : ControllerBase
|
|||
if (! await session.Create(installation))
|
||||
return Unauthorized();
|
||||
|
||||
return installation.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(session!.User);
|
||||
return installation;
|
||||
}
|
||||
|
||||
[HttpPost(nameof(CreateFolder))]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"dotnetRunMessages": true,
|
||||
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7087;http://localhost:5031",
|
||||
"applicationUrl": "https://localhost:8000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="582.0523615909593" y="160.75568014793453"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="393.7937432135768" y="243.91085524521077"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="10.864044189453125" x="29.567977905273438" xml:space="preserve" y="4.0">5</y:NodeLabel>
|
||||
|
@ -154,7 +154,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="175.8255534152188" y="188.59145941969348"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="241.37121964689652" y="243.91085524521077"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="10.864044189453125" x="29.567977905273438" xml:space="preserve" y="4.0">7</y:NodeLabel>
|
||||
|
@ -172,7 +172,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="779.8955241254705" y="229.98399686669086"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="913.7233840476495" y="390.20661887776083"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">11</y:NodeLabel>
|
||||
|
@ -190,11 +190,11 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="1080.1411072770327" y="505.0251575795813"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="1032.06702167392" y="683.7966785548988"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="3.999999999999943">15</y:NodeLabel>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="53.0323429107666" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#683A00" verticalTextPosition="top" visible="true" width="30.628189086914062" x="2.0" xml:space="preserve" y="32.34411430358881">K1 ✓
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="53.0323429107666" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#683A00" verticalTextPosition="top" visible="true" width="30.628189086914062" x="2.0" xml:space="preserve" y="32.34411430358887">K1 ✓
|
||||
K2 ✓
|
||||
K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParameter><y:ErdAttributesNodeLabelModelParameter/></y:ModelParameter></y:NodeLabel>
|
||||
<y:StyleProperties>
|
||||
|
@ -207,7 +207,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="614.6002578542565" y="0.0"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="393.7937432135768" y="32.482490272373525"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">21</y:NodeLabel>
|
||||
|
@ -224,7 +224,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="448.50893604095756" y="145.7089497868842"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="546.2162667802571" y="243.91085524521077"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">17</y:NodeLabel>
|
||||
|
@ -242,7 +242,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="893.6854614285201" y="301.4829532979212"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="913.7233840476495" y="243.91085524521077"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">25</y:NodeLabel>
|
||||
|
@ -260,7 +260,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="854.6780813018231" y="84.0068637493531"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="1110.6401046481265" y="390.20661887776083"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">27</y:NodeLabel>
|
||||
|
@ -278,7 +278,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="1219.0187296181307" y="417.76256385308943"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="1268.5061818399" y="683.7966785548988"/>
|
||||
<y:Fill color="#FFEB9C" color2="#FF0000" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">31</y:NodeLabel>
|
||||
|
@ -414,7 +414,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="410.66241765886343" y="1681.8835044865843"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="381.1829957002519" y="1666.836774125534"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">16</y:NodeLabel>
|
||||
|
@ -448,7 +448,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="244.57109584556457" y="1827.5924542734685"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="247.63957015025017" y="1827.5924542734685"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">18</y:NodeLabel>
|
||||
|
@ -465,7 +465,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="277.1189921088617" y="1666.836774125534"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="247.63957015025017" y="1666.836774125534"/>
|
||||
<y:Fill color="#B4B4FF" transparent="false"/>
|
||||
<y:BorderStyle color="#000068" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B4B4FF" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000068" verticalTextPosition="bottom" visible="true" width="10.864044189453125" x="29.567977905273438" xml:space="preserve" y="4.0">2</y:NodeLabel>
|
||||
|
@ -482,7 +482,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="745.7969893047066" y="1614.0294463149824"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="735.2707053490758" y="1666.836774125534"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">10</y:NodeLabel>
|
||||
|
@ -499,7 +499,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="618.9499887405645" y="1658.4151315081558"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="572.3666077540471" y="1666.836774125534"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">12</y:NodeLabel>
|
||||
|
@ -516,7 +516,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="659.3746230785885" y="1817.3729975910535"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="572.3666077540471" y="1827.5924542734685"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">14</y:NodeLabel>
|
||||
|
@ -533,7 +533,7 @@ K3 ✓<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="813.3003459398944" y="1763.512057658155"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="735.2707053490758" y="1827.5924542734685"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">26</y:NodeLabel>
|
||||
|
@ -550,7 +550,7 @@ K3 ✘<y:LabelModel><y:ErdAttributesNodeLabelModel/></y:LabelModel><y:ModelParam
|
|||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
|
||||
<y:Geometry height="90.0" width="70.0" x="699.7992574166124" y="1976.3308636739512"/>
|
||||
<y:Geometry height="90.0" width="70.0" x="572.3666077540471" y="1988.348134421403"/>
|
||||
<y:Fill color="#FFEB9C" transparent="false"/>
|
||||
<y:BorderStyle color="#683A00" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#FFEB9C" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#683A00" verticalTextPosition="bottom" visible="true" width="17.72808837890625" x="26.135955810546875" xml:space="preserve" y="4.0">30</y:NodeLabel>
|
||||
|
@ -582,8 +582,8 @@ Inverters<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0"
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-22.56775183821742" anchorY="-48.88515038132459" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="-0.33027906195516804" upY="0.9438833303083672" verticalTextPosition="bottom" visible="true" width="57.61639404296875" x="-89.06825945702936" xml:space="preserve" y="-67.91463895907565">switch to
|
||||
grid tie<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-22.56775183821742" anchorY="-5.777885637190593" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="-0.33027906195516804" upY="0.9438833303083672" verticalTextPosition="bottom" visible="true" width="57.61639404296875" x="-89.06825945702936" xml:space="preserve" y="-24.807374214941643">switch to
|
||||
grid tie<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -641,10 +641,13 @@ Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="21.046829314938122" ty="-45.01680098318991">
|
||||
<y:Point x="874.0493776621389" y="435.20661887776083"/>
|
||||
<y:Point x="715.6320547466846" y="519.7002048682145"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-30.708326355243116" anchorY="86.75687917585009" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.935215143023455" upY="0.3540799856806631" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-48.49600469839221" xml:space="preserve" y="86.75687917585009">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-95.81164490935862" anchorY="32.19070766070081" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.47060708552926384" upY="0.8823428874590944" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-140.13731172251363" xml:space="preserve" y="32.19070766070081">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5000000000000019" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -656,7 +659,7 @@ Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-91.4265773429479" anchorY="31.058243169626735" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.5320320765153349" upY="0.8467241992282852" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-133.9628920467579" xml:space="preserve" y="31.058243169626735">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-58.091523252820025" anchorY="-22.344127643221327" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="-1.2246467991473532E-16" upY="1.0" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-108.32785137782002" xml:space="preserve" y="-22.344127643221334">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -665,11 +668,14 @@ Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="15.152106842485068" ty="-45.029446684529034">
|
||||
<y:Point x="581.2162667802571" y="365.51788910504735"/>
|
||||
<y:Point x="528.1404648420541" y="447.09481487826343"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-29.97425394733284" anchorY="101.74082753289088" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.9962292767888588" upY="-0.0867595992887667" verticalTextPosition="bottom" visible="true" width="48.38832092285156" x="-29.97425394733284" xml:space="preserve" y="98.55777152031747">turn off
|
||||
inverter<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-11.667059533747079" anchorY="53.20739194515636" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.8382050245156525" upY="0.5453552391576654" verticalTextPosition="bottom" visible="true" width="48.38832092285156" x="-38.055883863066654" xml:space="preserve" y="53.20739194515636">turn off
|
||||
inverter<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5000000000000003" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -681,7 +687,7 @@ inverter<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEna
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="side_slider" preferredPlacement="center" ratio="0.0" textColor="#000000" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-61.48240607634398" xml:space="preserve" y="-30.072393595089466">turn off
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="side_slider" preferredPlacement="center" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-110.27792003264085" xml:space="preserve" y="-34.688241946810194">turn off
|
||||
inverters<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -694,7 +700,7 @@ inverters<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0"
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-40.1366872375786" anchorY="3.276745889159926" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.9801127226267146" upY="0.19844155548989476" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-50.87959227195731" xml:space="preserve" y="3.276745889159926">turn off
|
||||
<y:EdgeLabel alignment="center" anchorX="-38.68821708305404" anchorY="33.66069253418277" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="1.0" upY="1.8369701987210297E-16" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-38.68821708305405" xml:space="preserve" y="33.66069253418277">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -707,7 +713,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-36.42344224440467" anchorY="-13.753969151122476" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.8900092690299531" upY="0.45594243171783055" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-61.106509422527964" xml:space="preserve" y="-13.753969151122476">turn off
|
||||
<y:EdgeLabel alignment="center" anchorX="-36.34321140162365" anchorY="-38.68821373332315" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="-1.2246467991473532E-16" upY="1.0" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-90.47957919947521" xml:space="preserve" y="-38.68821373332316">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -717,11 +723,14 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="875.759476311287" y="288.91085524521077"/>
|
||||
<y:Point x="694.5852254317465" y="500.95688054473624"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-87.60097524632454" anchorY="36.001631487133864" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.7247896869799892" upY="0.6889701805212248" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-124.89931834077376" xml:space="preserve" y="36.001631487133864">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-140.36047493803812" anchorY="60.311953252495755" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="center" ratio="0.5" textColor="#000000" upX="0.7602822957199457" upY="0.6495928192451093" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-175.52707071953466" xml:space="preserve" y="60.311953252495755">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5000000000000003" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -743,8 +752,8 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-2.720348770062401" anchorY="-8.184439221301773" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9962292767888588" upY="0.08675959928876727" verticalTextPosition="bottom" visible="true" width="55.108367919921875" x="-44.05141614024578" xml:space="preserve" y="-63.085008739179884">turn off
|
||||
Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="38.68824090899216" anchorY="-89.20073479644952" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="55.108367919921875" x="2.0000123018144222" xml:space="preserve" y="-144.3091027163714">turn off
|
||||
Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.4999999999999987" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -817,7 +826,7 @@ Inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-0.601812832179121" anchorY="-7.106143485136727" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9801127226267147" upY="-0.19844155548989376" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-36.56041246071141" xml:space="preserve" y="-67.4463554735874">turn off
|
||||
<y:EdgeLabel alignment="center" anchorX="-1.9999867345154598" anchorY="-8.293373776572935" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-38.688215341693194" xml:space="preserve" y="-62.4297415744245">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -827,10 +836,13 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-13.677119243026084" ty="44.9895375252479">
|
||||
<y:Point x="282.63957015025017" y="1624.6814853696424"/>
|
||||
<y:Point x="402.50587645722584" y="1481.6545842023272"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="26.767035729346617" anchorY="-89.72842788087337" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9519459018107578" upY="-0.30626622410201093" verticalTextPosition="bottom" visible="true" width="50.236328125" x="7.400539492075577" xml:space="preserve" y="-143.7814096319475">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="42.26630925296365" anchorY="-95.71994547025815" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.7664335365409145" upY="-0.6423236209772972" verticalTextPosition="bottom" visible="true" width="50.236328125" x="26.67389777947143" xml:space="preserve" y="-147.29025726298894">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.4999999999999997" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -839,10 +851,13 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="19.39352371895791" ty="45.01703178967159">
|
||||
<y:Point x="770.2707053490758" y="1624.8477957198368"/>
|
||||
<y:Point x="626.760131473005" y="1451.0534797665293"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-24.296235447239155" anchorY="-84.70970920941136" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.8599279843359526" upY="0.5104153815823985" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-67.43210324264501" xml:space="preserve" y="-127.90933359438213">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-38.53255297975011" anchorY="-123.76381877365907" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.7710894922153189" upY="0.6367267820620722" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-86.20650129732047" xml:space="preserve" y="-162.50052351832747">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.500000000000001" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -854,7 +869,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-15.439448720854557" anchorY="-96.96505251280405" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9905575559375823" upY="0.13709751410935023" verticalTextPosition="bottom" visible="true" width="55.984375" x="-43.26678350459801" xml:space="preserve" y="-152.42079818349714">K3 opens<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-2.000030429546655" anchorY="-99.48622193119718" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="55.984375" x="-22.344144733135522" xml:space="preserve" y="-155.47059693119718">K3 opens<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -866,7 +881,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="19.787500125521547" anchorY="-12.849807218343813" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9691516142140085" upY="0.24646530925544397" verticalTextPosition="bottom" visible="true" width="50.236328125" x="-12.310543238741985" xml:space="preserve" y="-61.53642571287216">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="22.344083874042212" anchorY="-10.243393612998716" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="50.236328125" x="1.9999695704533451" xml:space="preserve" y="-60.479721737998716">open K2<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -878,7 +893,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="33.170622230079175" anchorY="-20.54894307703944" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9113818501099502" upY="0.4115618098052396" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-22.546824942353155" xml:space="preserve" y="-69.88784611887813">turn off
|
||||
<y:EdgeLabel alignment="center" anchorX="38.68824303828478" anchorY="-8.293373776572935" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="2.000014431107047" xml:space="preserve" y="-62.4297415744245">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -891,7 +906,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="35.867743762755254" anchorY="-15.93315162786348" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-0.9691516142140085" upY="0.24646530925544397" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="-13.031448845807557" xml:space="preserve" y="-68.39949986683459">turn off
|
||||
<y:EdgeLabel alignment="center" anchorX="38.68819817763108" anchorY="-8.293308863013408" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="-1.0" upY="-6.123233995736766E-17" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="1.9999695704533451" xml:space="preserve" y="-62.42967666086497">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
|
@ -914,7 +929,7 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-24.918635525422495" anchorY="21.594702697511707" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="0.9937122098932426" upY="0.11196447610330804" verticalTextPosition="bottom" visible="true" width="55.984375" x="-31.18689674226863" xml:space="preserve" y="21.594702697511707">K1 opens<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.4999999999999979" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
|
@ -925,11 +940,14 @@ inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEn
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="55.81460729275682" y="1523.820754474699"/>
|
||||
<y:Point x="234.58612826807462" y="1404.8536338521308"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="67.5676531310973" xml:space="preserve" y="-100.68725537689579">turn off
|
||||
inverters<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="36.32125205930789" distanceToCenter="true" position="right" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="88.28491738649134" anchorY="-52.831225794193415" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.688228607177734" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="-0.5540104212935304" upY="-0.832509731533611" verticalTextPosition="bottom" visible="true" width="54.13636779785156" x="67.95925639931545" xml:space="preserve" y="-113.36664507338794">turn off
|
||||
inverters<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5000000000000027" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -938,10 +956,13 @@ inverters<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaul
|
|||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-12.103675434707498" ty="-0.8973455153978875">
|
||||
<y:Point x="428.7937432135768" y="368.2394927091691"/>
|
||||
<y:Point x="500.8846825648616" y="448.27634874029746"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="-51.04636249792975" anchorY="85.707351023137" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="0.9519459018107576" upY="0.3062662241020115" verticalTextPosition="bottom" visible="true" width="58.68438720703125" x="-69.0194081815676" xml:space="preserve" y="85.707351023137">K3's open<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5000000000000006" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-0.19439353507226542" anchorY="67.52807422348087" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="0.7430274178867984" upY="-0.669260977697398" verticalTextPosition="bottom" visible="true" width="58.68438720703125" x="-0.19439353507226542" xml:space="preserve" y="53.91255239427337">K3's open<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
@ -949,10 +970,13 @@ inverters<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaul
|
|||
<edge id="e31" source="n8" target="n2">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="276.3712196468965" y="371.2720580009981"/>
|
||||
<y:Point x="321.80474594577396" y="464.4058541099475"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="delta"/>
|
||||
<y:EdgeLabel alignment="center" anchorX="7.546056019917529" anchorY="89.21761327127075" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="0.9438833303083674" upY="-0.3302790619551677" verticalTextPosition="bottom" visible="true" width="58.68438720703125" x="7.546056019917529" xml:space="preserve" y="82.4983782827727">K3's open<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:EdgeLabel alignment="center" anchorX="-10.230074924814858" anchorY="67.35206739565979" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" ratio="0.5" textColor="#000000" upX="0.8987592955167517" upY="-0.43844238928533374" verticalTextPosition="bottom" visible="true" width="58.68438720703125" x="-10.230074924814858" xml:space="preserve" y="58.43234531250035">K3's open<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="false" ratio="0.5" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="left|right" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
|
|
|
@ -3,4 +3,6 @@ Prototype ie-entwicklung@10.2.3.115
|
|||
Salimax001 ie-entwicklung@10.2.3.104
|
||||
Salimax002 ie-entwicklung@10.2.4.29
|
||||
Salimax003 ie-entwicklung@10.2.4.33
|
||||
Salimax004 ie-entwicklung@10.2.4.32
|
||||
Salimax004 ie-entwicklung@10.2.4.32
|
||||
Salimax005 ie-entwicklung@10.2.4.36
|
||||
Salimax006 ie-entwicklung@10.2.4.35
|
|
@ -18,5 +18,5 @@ echo -e "\n============================ Deploy ============================\n"
|
|||
|
||||
rsync -v \
|
||||
./bin/Release/$dotnet_version/linux-x64/publish/* \
|
||||
$username@$salimax_ip:~/salimax
|
||||
$username@"$salimax_ip":~/salimax
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
|
|||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
namespace InnovEnergy.App.SaliMax.Ess;
|
||||
|
@ -9,12 +10,13 @@ namespace InnovEnergy.App.SaliMax.Ess;
|
|||
public static class Controller
|
||||
{
|
||||
private static readonly UnixTimeSpan MaxTimeWithoutEoc = UnixTimeSpan.FromDays(7); // TODO: move to config
|
||||
private static readonly Double BatteryHeatingPower = 200.0; // TODO: move to config
|
||||
|
||||
public static EssMode SelectControlMode(this StatusRecord s)
|
||||
{
|
||||
//return EssMode.OptimizeSelfConsumption;
|
||||
|
||||
return s.StateMachine.State != 16 ? EssMode.Off
|
||||
return s.StateMachine.State != 23 ? EssMode.Off
|
||||
: s.MustHeatBatteries() ? EssMode.HeatBatteries
|
||||
: s.MustDoCalibrationCharge() ? EssMode.CalibrationCharge
|
||||
: s.MustReachMinSoc() ? EssMode.ReachMinSoc
|
||||
|
@ -25,9 +27,7 @@ public static class Controller
|
|||
|
||||
public static EssControl ControlEss(this StatusRecord s)
|
||||
{
|
||||
var mode = s.SelectControlMode();
|
||||
|
||||
mode.WriteLine();
|
||||
var mode = s.SelectControlMode().WriteLine();
|
||||
|
||||
if (mode is EssMode.Off or EssMode.NoGridMeter)
|
||||
return EssControl.Default;
|
||||
|
@ -85,7 +85,7 @@ public static class Controller
|
|||
|
||||
|
||||
// find out if we reach the lower or upper Dc limit by comparing the current Dc voltage to the reference voltage
|
||||
return s.AcDc.Dc.Voltage > s.Config.ReferenceDcBusVoltage
|
||||
return s.AcDc.Dc.Voltage > s.Config.ReferenceDcLinkVoltageFromAcDc
|
||||
? control with { PowerCorrection = clampedPowerDelta.ClampMax(-correction), LimitedBy = EssLimit.ChargeLimitedByMaxDcBusVoltage }
|
||||
: control with { PowerCorrection = clampedPowerDelta.ClampMin(correction), LimitedBy = EssLimit.DischargeLimitedByMinDcBusVoltage };
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public static class Controller
|
|||
private static Double ComputePowerDelta(this StatusRecord s, EssMode mode)
|
||||
{
|
||||
var chargePower = s.AcDc.Devices.Sum(d => d.Status.Nominal.Power.Value);
|
||||
|
||||
|
||||
return mode switch
|
||||
{
|
||||
EssMode.HeatBatteries => s.ControlInverterPower(chargePower),
|
||||
|
@ -153,7 +153,19 @@ public static class Controller
|
|||
|
||||
private static Double MaxBatteryChargePower(this StatusRecord s)
|
||||
{
|
||||
return s.Battery.Devices.Sum(b => b.MaxChargePower);
|
||||
// This introduce a limit when we don't have communication with batteries
|
||||
// Otherwise the limit will be 0 and the batteries will be not heated
|
||||
|
||||
var maxChargePower = s.Config.Devices.BatteryNodes.Length * BatteryHeatingPower;
|
||||
|
||||
if (s.Battery.Devices.Count != 0)
|
||||
{
|
||||
maxChargePower = s.Battery.Devices.Sum(b => b.MaxChargePower);
|
||||
}
|
||||
|
||||
maxChargePower.W().ToDisplayString().WriteLine(" Max Charge Power");
|
||||
|
||||
return maxChargePower;
|
||||
}
|
||||
|
||||
private static Double CurrentPowerSetPoint(this StatusRecord s)
|
||||
|
|
|
@ -12,7 +12,9 @@ public static class Flow
|
|||
private static readonly String DownArrowChar = "V";
|
||||
private static readonly String UpArrowChar = "^";
|
||||
|
||||
public static TextBlock Horizontal(Unit amount, Int32 width = 10)
|
||||
public static TextBlock Horizontal(Unit amount) => Horizontal(amount, 10);
|
||||
|
||||
public static TextBlock Horizontal(Unit amount, Int32 width)
|
||||
{
|
||||
var label = amount.ToDisplayString();
|
||||
var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar;
|
||||
|
@ -21,19 +23,21 @@ public static class Flow
|
|||
// note : appending "fake label" below to make it vertically symmetric
|
||||
return TextBlock.AlignCenterHorizontal(label, arrow, "");
|
||||
}
|
||||
|
||||
|
||||
public static TextBlock Vertical(Unit amount) => Vertical(amount, 4);
|
||||
|
||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
||||
[SuppressMessage("ReSharper", "CoVariantArrayConversion")]
|
||||
public static TextBlock Vertical(Unit amount, Int32 height = 4)
|
||||
public static TextBlock Vertical(Unit amount, Int32 height)
|
||||
{
|
||||
var label = amount.ToDisplayString();
|
||||
var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar;
|
||||
var halfArrow = Enumerable.Repeat(arrowChar, height/2);
|
||||
|
||||
var lines = halfArrow
|
||||
.Append(label)
|
||||
.Concat(halfArrow)
|
||||
.ToArray(height / 2 * 2 + 1);
|
||||
.Append(label)
|
||||
.Concat(halfArrow)
|
||||
.ToArray(height / 2 * 2 + 1);
|
||||
|
||||
return TextBlock.AlignCenterHorizontal(lines);
|
||||
}
|
||||
|
|
|
@ -18,15 +18,9 @@ public class CustomLogger : ILogger
|
|||
_CurrentFileSizeBytes = File.Exists(logFilePath) ? new FileInfo(logFilePath).Length : 0;
|
||||
}
|
||||
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => throw new NotImplementedException();
|
||||
|
||||
public Boolean IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true; // Enable logging for all levels
|
||||
}
|
||||
public Boolean IsEnabled(LogLevel logLevel) => true; // Enable logging for all levels
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception, String> formatter)
|
||||
{
|
||||
|
@ -43,7 +37,7 @@ public class CustomLogger : ILogger
|
|||
File.AppendAllText(_LogFilePath, logMessage + Environment.NewLine);
|
||||
_CurrentFileSizeBytes += logMessage.Length;
|
||||
|
||||
Console.WriteLine( logMessage + Environment.NewLine);
|
||||
Console.WriteLine(logMessage);
|
||||
}
|
||||
|
||||
private void RotateLogFile()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Threading.Tasks;
|
||||
using Flurl.Http;
|
||||
using InnovEnergy.App.SaliMax.Ess;
|
||||
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
||||
|
@ -13,10 +14,10 @@ using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
|
|||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Units.Power;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
||||
using AcPower = InnovEnergy.Lib.Units.Composite.AcPower;
|
||||
|
@ -28,10 +29,7 @@ namespace InnovEnergy.App.SaliMax;
|
|||
|
||||
internal static class Program
|
||||
{
|
||||
[DllImport("libsystemd.so.0")]
|
||||
private static extern Int32 sd_notify(Int32 unsetEnvironment, String state);
|
||||
|
||||
private const UInt32 UpdateIntervalSeconds = 2;
|
||||
private static readonly UnixTimeSpan UpdateInterval = UnixTimeSpan.FromSeconds(2);
|
||||
|
||||
private static readonly IReadOnlyList<Byte> BatteryNodes;
|
||||
|
||||
|
@ -59,7 +57,7 @@ internal static class Program
|
|||
BatteryNodes = config
|
||||
.Devices
|
||||
.BatteryNodes
|
||||
.Select(n=>n.ConvertTo<Byte>())
|
||||
.Select(n => n.ConvertTo<Byte>())
|
||||
.ToArray(config.Devices.BatteryNodes.Length);
|
||||
}
|
||||
|
||||
|
@ -82,8 +80,7 @@ internal static class Program
|
|||
{
|
||||
"Starting SaliMax".LogInfo();
|
||||
|
||||
// Send the initial "service started" message to systemd
|
||||
var sdNotifyReturn = sd_notify(0, "READY=1");
|
||||
Watchdog.Ready();
|
||||
|
||||
var battery48TlDevices = BatteryNodes
|
||||
.Select(n => new Battery48TlDevice(BatteriesChannel, n))
|
||||
|
@ -99,25 +96,12 @@ internal static class Program
|
|||
|
||||
StatusRecord ReadStatus()
|
||||
{
|
||||
"Reading AcDC".LogInfo();
|
||||
var acDc = acDcDevices.Read();
|
||||
|
||||
"Reading dcDc".LogInfo();
|
||||
var dcDc = dcDcDevices.Read();
|
||||
|
||||
"Reading battery".LogInfo();
|
||||
var battery = batteryDevices.Read();
|
||||
|
||||
"Reading relays".LogInfo();
|
||||
var acDc = acDcDevices.Read();
|
||||
var dcDc = dcDcDevices.Read();
|
||||
var relays = saliMaxRelaysDevice.Read();
|
||||
|
||||
"Reading loadOnAcIsland".LogInfo();
|
||||
var loadOnAcIsland = acIslandLoadMeter.Read();
|
||||
|
||||
"Reading gridMeter".LogInfo();
|
||||
var gridMeter = gridMeterDevice.Read();
|
||||
|
||||
"Reading pvOnDc".LogInfo();
|
||||
var pvOnDc = amptDevice.Read();
|
||||
|
||||
var pvOnAcGrid = AcPowerDevice.Null;
|
||||
|
@ -144,7 +128,6 @@ internal static class Program
|
|||
|
||||
var loadOnDc = new DcPowerDevice { Power = dcPower} ;
|
||||
|
||||
|
||||
return new StatusRecord
|
||||
{
|
||||
AcDc = acDc ?? AcDcDevicesRecord.Null,
|
||||
|
@ -176,223 +159,69 @@ internal static class Program
|
|||
acDcDevices.Write(r.AcDc);
|
||||
dcDcDevices.Write(r.DcDc);
|
||||
}
|
||||
|
||||
const Int32 delayTime = 10;
|
||||
|
||||
Console.WriteLine("press ctrl-C to stop");
|
||||
Console.WriteLine("press ctrl-c to stop");
|
||||
|
||||
while (true)
|
||||
{
|
||||
sd_notify(0, "WATCHDOG=1");
|
||||
|
||||
await Observable
|
||||
.Interval(UpdateInterval.ToTimeSpan())
|
||||
.Select(_ => RunIteration())
|
||||
.SelectMany(r => UploadCsv(r, UnixTime.Now.RoundTo(UpdateInterval)))
|
||||
.SelectError()
|
||||
.ToTask();
|
||||
}
|
||||
|
||||
|
||||
// var iterations = from _ in Observable.Interval(UpdateInterval.ToTimeSpan())
|
||||
// let t = UnixTime.Now.RoundTo(UpdateInterval)
|
||||
// let record = RunIteration()
|
||||
// from uploaded in UploadCsv(record, t)
|
||||
// select uploaded;
|
||||
//
|
||||
// using var running = iterations.Subscribe();
|
||||
|
||||
|
||||
StatusRecord RunIteration()
|
||||
{
|
||||
Watchdog.Alive();
|
||||
|
||||
var t = UnixTime.Now;
|
||||
while (t.Ticks % UpdateIntervalSeconds != 0)
|
||||
{
|
||||
await Task.Delay(delayTime);
|
||||
t = UnixTime.Now;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var record = ReadStatus();
|
||||
|
||||
if (record.Relays is not null)
|
||||
record.Relays.ToCsv().LogInfo();
|
||||
|
||||
record.ControlConstants();
|
||||
|
||||
record.ControlConstants();
|
||||
record.ControlSystemState();
|
||||
|
||||
(t + "\n").LogInfo();
|
||||
$"{record.StateMachine.State}: {record.StateMachine.Message}".LogInfo();
|
||||
$"Batteries SOC: {record.Battery.Soc}".LogInfo();
|
||||
|
||||
var essControl = record.ControlEss().LogInfo();
|
||||
|
||||
record.EssControl = essControl;
|
||||
|
||||
record.AcDc.SystemControl.ApplyAcDcDefaultSettings();
|
||||
record.DcDc.SystemControl.ApplyDcDcDefaultSettings();
|
||||
|
||||
|
||||
DistributePower(record, essControl);
|
||||
|
||||
WriteControl(record);
|
||||
|
||||
PrintTopology(record);
|
||||
|
||||
await UploadCsv(record, t);
|
||||
Topology.From(record).WriteLine();
|
||||
|
||||
//record.ToCsv().WriteLine();
|
||||
|
||||
//await UploadCsv(record, t);
|
||||
|
||||
record.Config.Save();
|
||||
|
||||
|
||||
"===========================================".LogInfo();
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
private static void PrintTopology(StatusRecord s)
|
||||
{
|
||||
// Power Measurement Values
|
||||
var gridPower = s.GridMeter is not null ? s.GridMeter!.Ac.Power.Active : 0;
|
||||
var inverterPower = s.AcDc.Ac.Power.Active;
|
||||
var islandLoadPower = s.LoadOnAcIsland is not null ? s.LoadOnAcIsland.Ac.Power.Active : 0;
|
||||
var dcBatteryPower = s.DcDc.Dc.Battery.Power;
|
||||
var dcdcPower = s.DcDc.Dc.Link.Power;
|
||||
var pvOnDcPower = s.PvOnDc.Dc!.Power.Value;
|
||||
|
||||
// Power Calculated Values
|
||||
var islandToGridBusPower = inverterPower + islandLoadPower;
|
||||
var gridLoadPower = s.LoadOnAcGrid is null ? 0: s.LoadOnAcGrid.Power.Active;
|
||||
|
||||
TextBlock gridBusColumn;
|
||||
TextBlock gridBox;
|
||||
TextBlock totalBoxes;
|
||||
|
||||
|
||||
if (s.GridMeter is not null)
|
||||
{
|
||||
var gridPowerByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Power.Active.ToDisplayString(),
|
||||
s.GridMeter.Ac.L2.Power.Active.ToDisplayString(),
|
||||
s.GridMeter.Ac.L3.Power.Active.ToDisplayString());
|
||||
|
||||
var gridVoltageByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Voltage.ToDisplayString(),
|
||||
s.GridMeter.Ac.L2.Voltage.ToDisplayString(),
|
||||
s.GridMeter.Ac.L3.Voltage.ToDisplayString());
|
||||
|
||||
gridBusColumn = ColumnBox("Pv", "Grid Bus", "Load" , gridVoltageByPhase , gridLoadPower);
|
||||
gridBox = TextBlock.AlignLeft(gridPowerByPhase).TitleBox("Grid");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBusColumn = TextBlock.Spacer(0);
|
||||
gridBox = TextBlock.Spacer(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var inverterPowerByPhase = TextBlock.AlignLeft(s.AcDc.Ac.L1.Power.Active.ToDisplayString(),
|
||||
s.AcDc.Ac.L2.Power.Active.ToDisplayString(),
|
||||
s.AcDc.Ac.L3.Power.Active.ToDisplayString());
|
||||
|
||||
// ReSharper disable once CoVariantArrayConversion
|
||||
var inverterPowerByAcDc = TextBlock.AlignLeft(s.AcDc.Devices
|
||||
.Select(s1 => s1.Status.Ac.Power)
|
||||
.ToArray());
|
||||
|
||||
var dcLinkVoltage = TextBlock.AlignCenterHorizontal("",
|
||||
s.DcDc.Dc.Link.Voltage.ToDisplayString(),
|
||||
"");
|
||||
|
||||
var dc48Voltage = s.DcDc.Dc.Battery.Voltage.ToDisplayString();
|
||||
var batteryVoltage = s.Battery.Dc.Voltage.Value.RoundToSignificantDigits(3);
|
||||
var batterySoc = s.Battery.Devices.Any()? s.Battery.Devices.Average(b=>b.Soc).Percent().ToDisplayString() : "0";
|
||||
var batteryCurrent = s.Battery.Dc.Current.ToDisplayString();
|
||||
var batteryTemp = s.Battery.Temperature.ToDisplayString();
|
||||
var batteryHeatingCurrent = s.Battery.HeatingCurrent.ToDisplayString();
|
||||
var anyBatteryAlarm = s.Battery.Alarms.Any();
|
||||
var anyBatteryWarning = s.Battery.Warnings.Any();
|
||||
|
||||
var islandBusColumn = ColumnBox("Pv", "Island Bus", "Load" , inverterPowerByPhase, islandLoadPower);
|
||||
var dcBusColumn = ColumnBox("Pv", "Dc Bus", "Load" , dcLinkVoltage, 0, pvOnDcPower);
|
||||
var gridBusFlow = Flow.Horizontal(gridPower);
|
||||
var flowGridBusToIslandBus = Flow.Horizontal((ActivePower)islandToGridBusPower);
|
||||
var flowIslandBusToInverter = Flow.Horizontal(inverterPower);
|
||||
var flowInverterToDcBus = Flow.Horizontal(inverterPower);
|
||||
var flowDcBusToDcDc = Flow.Horizontal(dcdcPower);
|
||||
var flowDcDcToBattery = Flow.Horizontal(dcBatteryPower);
|
||||
|
||||
var inverterBox = TextBlock.AlignLeft(inverterPowerByAcDc).TitleBox("AC/DC");
|
||||
var dcDcBox = TextBlock.AlignLeft(dc48Voltage).TitleBox("DC/DC");
|
||||
var batteryAvgBox = TextBlock.AlignLeft(batteryVoltage,
|
||||
batterySoc,
|
||||
batteryCurrent,
|
||||
batteryTemp,
|
||||
batteryHeatingCurrent,
|
||||
anyBatteryWarning,
|
||||
anyBatteryAlarm)
|
||||
.TitleBox("Battery");
|
||||
|
||||
|
||||
//////////////////// Batteries /////////////////////////
|
||||
|
||||
IReadOnlyList<TextBlock> batteryBoxes = s.Battery
|
||||
.Devices
|
||||
.Select(CreateIndividualBattery)
|
||||
.ToArray(s.Battery.Devices.Count);
|
||||
|
||||
var individualBatteries = batteryBoxes.Any()
|
||||
? TextBlock.AlignLeft(batteryBoxes)
|
||||
: TextBlock.Spacer(1);
|
||||
|
||||
if (s.GridMeter is not null)
|
||||
{
|
||||
totalBoxes = TextBlock.AlignCenterVertical(gridBox,
|
||||
gridBusFlow,
|
||||
gridBusColumn,
|
||||
flowGridBusToIslandBus,
|
||||
islandBusColumn,
|
||||
flowIslandBusToInverter,
|
||||
inverterBox,
|
||||
flowInverterToDcBus,
|
||||
dcBusColumn,
|
||||
flowDcBusToDcDc,
|
||||
dcDcBox,
|
||||
flowDcDcToBattery,
|
||||
batteryAvgBox,
|
||||
individualBatteries);
|
||||
}
|
||||
else
|
||||
{
|
||||
totalBoxes = TextBlock.AlignCenterVertical(
|
||||
islandBusColumn,
|
||||
flowIslandBusToInverter,
|
||||
inverterBox,
|
||||
flowInverterToDcBus,
|
||||
dcBusColumn,
|
||||
flowDcBusToDcDc,
|
||||
dcDcBox,
|
||||
flowDcDcToBattery,
|
||||
batteryAvgBox,
|
||||
individualBatteries);
|
||||
}
|
||||
|
||||
totalBoxes.WriteLine();
|
||||
}
|
||||
|
||||
private static TextBlock CreateIndividualBattery(Battery48TlRecord battery, Int32 i)
|
||||
{
|
||||
var batteryWarnings = battery.Warnings.Any();
|
||||
var batteryAlarms = battery.Alarms.Any();
|
||||
|
||||
var content = TextBlock.AlignLeft(battery.Dc.Voltage.ToDisplayString(),
|
||||
battery.Soc.ToDisplayString(),
|
||||
battery.Dc.Current.ToDisplayString(),
|
||||
battery.Temperatures.Cells.Average.ToDisplayString(),
|
||||
// battery.BusCurrent.ToDisplayString(),
|
||||
battery.HeatingCurrent.ToDisplayString(),
|
||||
batteryWarnings,
|
||||
batteryAlarms);
|
||||
|
||||
var box = content.TitleBox($"Battery {i + 1}");
|
||||
|
||||
var flow = Flow.Horizontal(battery.Dc.Power);
|
||||
|
||||
return TextBlock.AlignCenterVertical(flow, box);
|
||||
}
|
||||
|
||||
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower)
|
||||
{
|
||||
return ColumnBox(pvTitle, busTitle, loadTitle, dataBox, loadPower, 0);
|
||||
}
|
||||
|
||||
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower, ActivePower pvPower)
|
||||
{
|
||||
var pvBox = TextBlock.FromString(pvTitle).Box();
|
||||
var pvToBus = Flow.Vertical(pvPower);
|
||||
var busBox = TextBlock.AlignLeft(dataBox).TitleBox(busTitle);
|
||||
var busToLoad = Flow.Vertical(loadPower);
|
||||
var loadBox = TextBlock.FromString(loadTitle).Box();
|
||||
|
||||
return TextBlock.AlignCenterHorizontal(pvBox, pvToBus, busBox, busToLoad, loadBox);
|
||||
}
|
||||
|
||||
|
||||
private static async Task<T?> ResultOrNull<T>(this Task<T> task)
|
||||
{
|
||||
|
@ -407,14 +236,20 @@ internal static class Program
|
|||
var inverters = r.AcDc.Devices;
|
||||
var dcDevices = r.DcDc.Devices;
|
||||
|
||||
inverters.ForEach(d => d.Control.Dc.MaxVoltage = r.Config.MaxDcBusVoltage);
|
||||
inverters.ForEach(d => d.Control.Dc.MinVoltage = r.Config.MinDcBusVoltage);
|
||||
inverters.ForEach(d => d.Control.Dc.ReferenceVoltage = r.Config.ReferenceDcBusVoltage);
|
||||
inverters.ForEach(d => d.Control.Dc.MaxVoltage = r.Config.MaxDcLinkVoltageFromAcDc);
|
||||
inverters.ForEach(d => d.Control.Dc.MinVoltage = r.Config.MinDcLinkVoltageFromAcDc);
|
||||
inverters.ForEach(d => d.Control.Dc.ReferenceVoltage = r.Config.ReferenceDcLinkVoltageFromAcDc);
|
||||
inverters.ForEach(d => d.Control.Dc.PrechargeConfig = DcPrechargeConfig.PrechargeDcWithInternal);
|
||||
|
||||
dcDevices.ForEach(d => d.Control.DroopControl.UpperVoltage = r.Config.UpperDcLinkVoltageFromDc);
|
||||
dcDevices.ForEach(d => d.Control.DroopControl.LowerVoltage = r.Config.LowerDcLinkVoltageFromDc);
|
||||
dcDevices.ForEach(d => d.Control.DroopControl.ReferenceVoltage = r.Config.ReferenceDcLinkVoltageFromDc);
|
||||
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryChargingCurrent = r.Config.MaxBatteryChargingCurrent);
|
||||
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryDischargingCurrent = r.Config.MaxBatteryDischargingCurrent);
|
||||
dcDevices.ForEach(d => d.Control.VoltageLimits.MaxBatteryVoltage = r.Config.MaxChargeBatteryVoltage);
|
||||
dcDevices.ForEach(d => d.Control.VoltageLimits.MinBatteryVoltage = r.Config.MinDischargeBatteryVoltage);
|
||||
dcDevices.ForEach(d => d.Control.ControlMode = DcControlMode.VoltageDroop);
|
||||
|
||||
// dcDevices.ForEach(d => d.Control. Dc.MaxVoltage = r.Config.MaxDcBusVoltage);
|
||||
// dcDevices.ForEach(d => d.Control. Dc.MinVoltage = r.Config.MinDcBusVoltage);
|
||||
// dcDevices.ForEach(d => d.Control. Dc.ReferenceVoltage = r.Config.ReferenceDcBusVoltage);
|
||||
|
||||
r.DcDc.ResetAlarms();
|
||||
r.AcDc.ResetAlarms();
|
||||
}
|
||||
|
@ -483,11 +318,11 @@ internal static class Program
|
|||
sc.ResetAlarmsAndWarnings = true;
|
||||
}
|
||||
|
||||
private static async Task UploadCsv(StatusRecord status, UnixTime timeStamp)
|
||||
private static async Task<Boolean> UploadCsv(StatusRecord status, UnixTime timeStamp)
|
||||
{
|
||||
var s3Config = status.Config.S3;
|
||||
if (s3Config is null)
|
||||
return;
|
||||
return false;
|
||||
|
||||
var csv = status.ToCsv();
|
||||
var s3Path = timeStamp + ".csv";
|
||||
|
@ -500,6 +335,7 @@ internal static class Program
|
|||
var error = response.GetStringAsync();
|
||||
Console.WriteLine(error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using InnovEnergy.App.SaliMax.Ess;
|
||||
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
||||
using InnovEnergy.Lib.Devices.Battery48TL;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.GridType;
|
||||
|
@ -21,14 +20,18 @@ public static class Controller
|
|||
if (acDcs.NotAvailable())
|
||||
return 102;
|
||||
|
||||
var k4 = acDcs.AllDisabled() ? 0
|
||||
: acDcs.AllGridTied() ? 1
|
||||
: acDcs.AllIsland() ? 2
|
||||
|
||||
var k4 = acDcs.AllGridTied() ? 0
|
||||
: acDcs.AllIsland() ? 1
|
||||
: 4;
|
||||
|
||||
if (k4 == 4)
|
||||
return 103; //Message = "Panic: ACDCs have unequal grid types",
|
||||
var k5 = acDcs.AllDisabled() ? 0
|
||||
: acDcs.AllEnabled() ? 1
|
||||
: 4;
|
||||
|
||||
if (k4 == 4 || k5 == 4)
|
||||
return 103; //Message = "Panic: ACDCs have unequal grid types or power stage",
|
||||
|
||||
var nInverters = r.AcDc.Devices.Count;
|
||||
|
||||
var k1 = relays.K1GridBusIsConnectedToGrid ? 1 : 0;
|
||||
|
@ -36,32 +39,34 @@ public static class Controller
|
|||
var k3 = relays.K3InverterIsConnectedToIslandBus.Take(nInverters).Any(c => c) ? 1 : 0;
|
||||
|
||||
// states as defined in states excel sheet
|
||||
return 1
|
||||
+ 1*k1
|
||||
+ 2*k2
|
||||
+ 4*k3
|
||||
+ 8*k4;
|
||||
return 1 * k1
|
||||
+ 2 * k2
|
||||
+ 4 * k3
|
||||
+ 8 * k4
|
||||
+ 16 * k5;
|
||||
}
|
||||
|
||||
public static Boolean ControlSystemState(this StatusRecord s)
|
||||
{
|
||||
s.StateMachine.State = s.GetSystemState();
|
||||
|
||||
|
||||
return s.StateMachine.State switch
|
||||
{
|
||||
0 => State0(s),
|
||||
1 => State1(s),
|
||||
2 => State2(s),
|
||||
3 => State3(s),
|
||||
4 => State4(s),
|
||||
6 => State6(s),
|
||||
8 => State8(s),
|
||||
9 => State9(s),
|
||||
//10 => State10(s),
|
||||
12 => State12(s),
|
||||
13 => State13(s),
|
||||
15 => State15(s),
|
||||
16 => State16(s),
|
||||
17 => State17(s),
|
||||
18 => State18(s),
|
||||
21 => State21(s),
|
||||
19 => State19(s),
|
||||
22 => State22(s),
|
||||
23 => State23(s),
|
||||
24 => State24(s),
|
||||
28 => State28(s),
|
||||
29 => State29(s),
|
||||
|
||||
|
||||
101 => State101(s),
|
||||
102 => State102(s),
|
||||
|
@ -75,111 +80,82 @@ public static class Controller
|
|||
{
|
||||
return acDcs.SystemControl == null || acDcs.Devices.Count == 0;
|
||||
}
|
||||
|
||||
private static Boolean NotAvailable(this DcDcDevicesRecord dcDcs)
|
||||
{
|
||||
return dcDcs.SystemControl == null || dcDcs.Devices.Count == 0;
|
||||
}
|
||||
|
||||
|
||||
private static Boolean NotAvailable(this Battery48TlRecords batteries)
|
||||
{
|
||||
return batteries.Devices.Count <= 0;
|
||||
}
|
||||
|
||||
private static Boolean State1(StatusRecord s)
|
||||
private static Boolean State0(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Inverters are off. Switching to Island Mode.";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
s.StateMachine.Message = "Ac/Dc are off. Switching to Island Mode.";
|
||||
|
||||
return false;
|
||||
|
||||
// => 17
|
||||
}
|
||||
|
||||
private static Boolean State2(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Inverters are disconnected from Island Bus. Switching to GridTie Mode. C";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 10
|
||||
}
|
||||
|
||||
private static Boolean State4(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Turning on Inverters";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 12
|
||||
}
|
||||
|
||||
|
||||
private static Boolean State6(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Inverters are off. Waiting for them to disconnect from Island Bus.";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 2
|
||||
}
|
||||
return false;
|
||||
|
||||
// => 8
|
||||
}
|
||||
|
||||
private static Boolean State9(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Ac/Dc are disconnected from Island Bus. Switching to GridTie Mode.";
|
||||
|
||||
s.StateMachine.Message = "Inverters have disconnected from Island Bus. Turning them off.";
|
||||
|
||||
s.DcDc.Disable(); // TODO: leave enabled?
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// => 1
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// private static Boolean State10(StatusRecord s)
|
||||
// {
|
||||
//
|
||||
// s.SystemState.Message = "Inverters have disconnected from AcOut. Turning them off.";
|
||||
//
|
||||
// s.DcDc.Disable(); // TODO: leave enabled?
|
||||
// s.AcDc.Disable();
|
||||
// s.AcDc.EnableGridTieMode();
|
||||
// s.Relays.DisconnectIslandBusFromGrid();
|
||||
//
|
||||
// return true;
|
||||
//
|
||||
// // => 12
|
||||
// }
|
||||
|
||||
private static Boolean State12(StatusRecord s)
|
||||
private static Boolean State1(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Waiting for Inverters to connect to Island Bus";
|
||||
s.StateMachine.Message = "Grid Tied mode active, closing k2";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 3
|
||||
}
|
||||
|
||||
private static Boolean State3(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "K2 closed, Turning on Ac/Dc";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 19
|
||||
}
|
||||
|
||||
private static Boolean State13(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Ac/Dc are off. Waiting for them to disconnect from Island Bus.";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 9
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Boolean State19(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Waiting for Ac/Dc to connect to Island Bus";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
|
@ -188,66 +164,71 @@ public static class Controller
|
|||
|
||||
return true;
|
||||
|
||||
// => 16
|
||||
// => 23
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Boolean State13(StatusRecord s)
|
||||
private static Boolean State23(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Disconnected from AcIn (K2), awaiting inverters to disconnect from AcOut (K3)";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 9
|
||||
}
|
||||
|
||||
private static Boolean State15(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Grid has been lost, disconnecting AcIn from AcOut (K2)";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 13
|
||||
}
|
||||
|
||||
private static Boolean State16(StatusRecord s)
|
||||
{
|
||||
// return new
|
||||
// (
|
||||
// " Inverter is in grid-tie\n Waiting for K1AcInIsConnectedToGrid to open to leave it",
|
||||
// AcPowerStageEnable: true,
|
||||
// DcPowerStageEnable: true,
|
||||
// GridType.GridTied400V50Hz,
|
||||
// HighActivePinState.Closed
|
||||
// );
|
||||
|
||||
s.StateMachine.Message = "ESS";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.EnableDcLinkGridTie();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 15
|
||||
// => 22
|
||||
}
|
||||
|
||||
private static Boolean State22(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "K1 opened, switching inverters off";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.ConnectIslandBusToGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 6
|
||||
}
|
||||
|
||||
|
||||
private static Boolean State17(StatusRecord s)
|
||||
private static Boolean State6(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Inverters are in Island Mode. Waiting for them to connect to AcIn.";
|
||||
s.StateMachine.Message = "Inverters are off, opening K2";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 4
|
||||
}
|
||||
|
||||
private static Boolean State4(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "K2 is open, waiting K3 to open";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 0
|
||||
}
|
||||
|
||||
private static Boolean State8(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Ac/Dc are off and in Island Mode.";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
|
@ -255,48 +236,27 @@ public static class Controller
|
|||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
|
||||
// => 21
|
||||
// => 24
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Boolean State18(StatusRecord s)
|
||||
{
|
||||
// return new
|
||||
// (
|
||||
// " Didn't succeed to go to Island mode and K1AcInIsConnectedToGrid close\n Turning off power stage of inverter\n Moving to Grid Tie",
|
||||
// AcPowerStageEnable: false,
|
||||
// DcPowerStageEnable: false,
|
||||
// GridType.GridTied400V50Hz,
|
||||
// HighActivePinState.Open
|
||||
// );
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Boolean State21(StatusRecord s)
|
||||
private static Boolean State28(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Island Mode";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.EnableDcLinkIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 22
|
||||
// => 29
|
||||
}
|
||||
|
||||
private static Boolean State22(StatusRecord s)
|
||||
|
||||
private static Boolean State29(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Grid became available (K1). Turning off inverters.";
|
||||
s.StateMachine.Message = "K1 closed, Switching off Inverters and moving to grid tie";
|
||||
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
|
@ -305,13 +265,23 @@ public static class Controller
|
|||
|
||||
return false;
|
||||
|
||||
// => 6
|
||||
// => 13
|
||||
}
|
||||
|
||||
private static Boolean State24(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Inverter are on waiting for k3 to close";
|
||||
|
||||
s.DcDc.Enable();
|
||||
s.AcDc.Enable();
|
||||
s.AcDc.EnableIslandMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 28
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static Boolean State101(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Relay device is not available";
|
||||
|
@ -324,24 +294,22 @@ public static class Controller
|
|||
return s.EnableSafeDefaults();
|
||||
}
|
||||
|
||||
|
||||
private static Boolean State103(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Panic: ACDCs have unequal grid types";
|
||||
s.StateMachine.Message = "Panic: ACDCs have unequal grid types or PowerStage";
|
||||
return s.EnableSafeDefaults();
|
||||
}
|
||||
|
||||
private static Boolean State104(StatusRecord s)
|
||||
{
|
||||
s.StateMachine.Message = "Panic: DCDCs not available";
|
||||
return s.EnableSafeDefaults();
|
||||
}
|
||||
// private static Boolean State104(StatusRecord s)
|
||||
// {
|
||||
// s.StateMachine.Message = "Panic: DCDCs not available";
|
||||
// return s.EnableSafeDefaults();
|
||||
// }
|
||||
|
||||
|
||||
private static Boolean UnknownState(StatusRecord s)
|
||||
{
|
||||
// "Unknown System State"
|
||||
|
||||
return s.EnableSafeDefaults();
|
||||
}
|
||||
|
||||
|
@ -351,7 +319,21 @@ public static class Controller
|
|||
{
|
||||
return acDcs.Devices.All(d => !d.Control.PowerStageEnable);
|
||||
}
|
||||
|
||||
private static Boolean AllEnabled(this AcDcDevicesRecord acDcs)
|
||||
{
|
||||
return acDcs.Devices.All(d => d.Control.PowerStageEnable);
|
||||
}
|
||||
|
||||
|
||||
private static Boolean AllTheSame(this AcDcDevicesRecord acDcs)
|
||||
{
|
||||
return acDcs.Devices
|
||||
.Select(d => d.Control.PowerStageEnable)
|
||||
.Distinct()
|
||||
.Count() == 1;
|
||||
}
|
||||
|
||||
private static Boolean AllGridTied(this AcDcDevicesRecord acDcs)
|
||||
{
|
||||
return acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied380V60Hz)
|
||||
|
@ -381,9 +363,12 @@ public static class Controller
|
|||
|
||||
private static void Disable(this DcDcDevicesRecord dcDc)
|
||||
{
|
||||
dcDc.Devices
|
||||
.Select(d => d.Control)
|
||||
.ForAll(c => c.PowerStageEnable = false);
|
||||
// For Test purpose, The transition from island mode to grid tier and vis versa , may not need to disable Dc/Dc.
|
||||
// This will keep the Dc link powered.
|
||||
|
||||
// dcDc.Devices
|
||||
// .Select(d => d.Control)
|
||||
// .ForAll(c => c.PowerStageEnable = false);
|
||||
}
|
||||
|
||||
private static void Enable(this AcDcDevicesRecord acDc)
|
||||
|
@ -393,7 +378,6 @@ public static class Controller
|
|||
.ForAll(c => c.PowerStageEnable = true);
|
||||
}
|
||||
|
||||
|
||||
private static void Enable(this DcDcDevicesRecord dcDc)
|
||||
{
|
||||
dcDc.Devices
|
||||
|
@ -402,7 +386,6 @@ public static class Controller
|
|||
}
|
||||
|
||||
|
||||
|
||||
private static void EnableGridTieMode(this AcDcDevicesRecord acDc)
|
||||
{
|
||||
acDc.Devices
|
||||
|
@ -417,7 +400,34 @@ public static class Controller
|
|||
.Select(d => d.Control)
|
||||
.ForAll(c => c.Ac.GridType = Island400V50Hz); // TODO: config grid type
|
||||
}
|
||||
|
||||
private static void EnableDcLinkIslandMode(this StatusRecord s)
|
||||
{
|
||||
// Dc Link Windows on AcDc +- 60
|
||||
s.Config.ReferenceDcLinkVoltageFromAcDc = 750;
|
||||
s.Config.MinDcLinkVoltageFromAcDc = 690;
|
||||
s.Config.MaxDcLinkVoltageFromAcDc = 810;
|
||||
|
||||
// Dc Link Windows on DcDc +-55
|
||||
s.Config.ReferenceDcLinkVoltageFromDc = 750;
|
||||
s.Config.UpperDcLinkVoltageFromDc = 55;
|
||||
s.Config.LowerDcLinkVoltageFromDc = 55;
|
||||
}
|
||||
|
||||
private static void EnableDcLinkGridTie(this StatusRecord s)
|
||||
{
|
||||
// Dc Link Windows on DcDc +-30
|
||||
|
||||
s.Config.ReferenceDcLinkVoltageFromAcDc = 750;
|
||||
s.Config.MinDcLinkVoltageFromAcDc = 720;
|
||||
s.Config.MaxDcLinkVoltageFromAcDc = 780;
|
||||
|
||||
// Dc Link Windows on DcDc +-20
|
||||
s.Config.ReferenceDcLinkVoltageFromDc = 750;
|
||||
s.Config.UpperDcLinkVoltageFromDc = 20;
|
||||
s.Config.LowerDcLinkVoltageFromDc = 20;
|
||||
}
|
||||
|
||||
private static void DisconnectIslandBusFromGrid(this RelaysRecord? relays)
|
||||
{
|
||||
if (relays is not null)
|
||||
|
@ -433,15 +443,16 @@ public static class Controller
|
|||
|
||||
private static Boolean EnableSafeDefaults(this StatusRecord s)
|
||||
{
|
||||
s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
s.AcDc.EnableGridTieMode();
|
||||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
// After some tests, the safe state is switch off inverter and keep the last state of K2 , Dc/Dc and Grid type to avoid conflict.
|
||||
|
||||
// s.DcDc.Disable();
|
||||
s.AcDc.Disable();
|
||||
// s.AcDc.EnableGridTieMode();
|
||||
// s.Relays.DisconnectIslandBusFromGrid();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static DcDcDevicesRecord ResetAlarms(this DcDcDevicesRecord dcDcStatus)
|
||||
public static DcDcDevicesRecord ResetAlarms(this DcDcDevicesRecord dcDcStatus)
|
||||
{
|
||||
var sc = dcDcStatus.SystemControl;
|
||||
|
||||
|
@ -454,7 +465,7 @@ public static class Controller
|
|||
return dcDcStatus;
|
||||
}
|
||||
|
||||
private static AcDcDevicesRecord ResetAlarms(this AcDcDevicesRecord acDcStatus)
|
||||
public static AcDcDevicesRecord ResetAlarms(this AcDcDevicesRecord acDcStatus)
|
||||
{
|
||||
var sc = acDcStatus.SystemControl;
|
||||
|
||||
|
|
|
@ -14,48 +14,52 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
|||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
||||
|
||||
public required Double MinSoc { get; set; }
|
||||
public required UnixTime LastEoc { get; set; }
|
||||
public required Double PConstant { get; set; }
|
||||
public required Double GridSetPoint { get; set; }
|
||||
public required Double BatterySelfDischargePower { get; set; }
|
||||
public required Double HoldSocZone { get; set; }
|
||||
public required Double MinSoc { get; set; }
|
||||
public required UnixTime LastEoc { get; set; }
|
||||
public required Double PConstant { get; set; }
|
||||
public required Double GridSetPoint { get; set; }
|
||||
public required Double BatterySelfDischargePower { get; set; }
|
||||
public required Double HoldSocZone { get; set; }
|
||||
|
||||
public required Double MaxDcLinkVoltageFromAcDc { get; set; }
|
||||
public required Double MinDcLinkVoltageFromAcDc { get; set; }
|
||||
public required Double ReferenceDcLinkVoltageFromAcDc { get; set; }
|
||||
public required Double MaxDcLinkVoltageFromAcDc { get; set; }
|
||||
public required Double MinDcLinkVoltageFromAcDc { get; set; }
|
||||
public required Double ReferenceDcLinkVoltageFromAcDc { get; set; }
|
||||
|
||||
public required Double LowerDcLinkVoltageFromDc { get; set; }
|
||||
public required Double ReferenceDcLinkVoltageFromDc { get; set; }
|
||||
public required Double UpperDcLinkVoltageFromDc { get; set; }
|
||||
public required Double LowerDcLinkVoltageFromDc { get; set; }
|
||||
public required Double ReferenceDcLinkVoltageFromDc { get; set; }
|
||||
public required Double UpperDcLinkVoltageFromDc { get; set; }
|
||||
|
||||
public required Double MaxBatteryChargingCurrent { get; set; }
|
||||
public required Double MaxBatteryDischargingCurrent { get; set; }
|
||||
public required Double MaxBatteryChargingCurrent { get; set; }
|
||||
public required Double MaxBatteryDischargingCurrent { get; set; }
|
||||
|
||||
public required Double MaxChargeBatteryVoltage { get; set; }
|
||||
public required Double MinDischargeBatteryVoltage { get; set; }
|
||||
public required Double MaxChargeBatteryVoltage { get; set; }
|
||||
public required Double MinDischargeBatteryVoltage { get; set; }
|
||||
|
||||
public required DeviceConfig Devices { get; set; }
|
||||
public required S3Config? S3 { get; set; }
|
||||
public required DeviceConfig Devices { get; set; }
|
||||
public required S3Config? S3 { get; set; }
|
||||
|
||||
|
||||
|
||||
#if DEBUG
|
||||
public static Config Default => new()
|
||||
{
|
||||
MinSoc = 20,
|
||||
LastEoc = UnixTime.Epoch, // TODO: remove, use new LastEoc feature from BMS
|
||||
PConstant = .5,
|
||||
GridSetPoint = 0,
|
||||
BatterySelfDischargePower = 200,
|
||||
HoldSocZone = 1, // TODO: find better name,
|
||||
MinDcBusVoltage = 690,
|
||||
ReferenceDcBusVoltage = 750,
|
||||
MaxDcBusVoltage = 810,
|
||||
LowerDcBusVoltageWindow = 50,
|
||||
ReferenceDcBusVoltageWindow = 750,
|
||||
UpperDcBusVoltageWindow = 50,
|
||||
Devices = new ()
|
||||
MinSoc = 20,
|
||||
LastEoc = UnixTime.Epoch, // TODO: remove, use new LastEoc feature from BMS
|
||||
PConstant = .5,
|
||||
GridSetPoint = 0,
|
||||
BatterySelfDischargePower = 200,
|
||||
HoldSocZone = 1, // TODO: find better name,
|
||||
MinDcLinkVoltageFromAcDc = 690,
|
||||
ReferenceDcLinkVoltageFromAcDc = 750,
|
||||
MaxDcLinkVoltageFromAcDc = 810,
|
||||
LowerDcLinkVoltageFromDc = 50,
|
||||
ReferenceDcLinkVoltageFromDc = 750,
|
||||
UpperDcLinkVoltageFromDc = 50,
|
||||
MaxBatteryChargingCurrent = 210,
|
||||
MaxBatteryDischargingCurrent = 210,
|
||||
MaxChargeBatteryVoltage = 57,
|
||||
MinDischargeBatteryVoltage = 0,
|
||||
Devices = new ()
|
||||
{
|
||||
TruConvertAcIp = new() { Host = "localhost", Port = 5001},
|
||||
TruConvertDcIp = new() { Host = "localhost", Port = 5002},
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using InnovEnergy.App.SaliMax.Ess;
|
||||
using InnovEnergy.Lib.Devices.Battery48TL;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Units.Power;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using Ac3Bus = InnovEnergy.Lib.Units.Composite.Ac3Bus;
|
||||
|
||||
namespace InnovEnergy.App.SaliMax;
|
||||
|
||||
public static class Topology
|
||||
{
|
||||
public static TextBlock From(this StatusRecord s)
|
||||
{
|
||||
// Topology is built up from right to left
|
||||
|
||||
// Power Measurement Values
|
||||
|
||||
var inverterPower = s.AcDc.Ac.Power.Active;
|
||||
var islandLoadPower = s.LoadOnAcIsland is not null
|
||||
? s.LoadOnAcIsland.Ac.Power.Active
|
||||
: 0; // TODO
|
||||
|
||||
var islandTopology = CreateIslandTopology(s, islandLoadPower, inverterPower);
|
||||
|
||||
if (s.GridMeter is null) // no grid meter?
|
||||
return islandTopology; // we're done
|
||||
|
||||
var gridBusColumn = GridBusColumn(s);
|
||||
var gridBox = CreateGridBox(s);
|
||||
|
||||
ActivePower islandToGridBusPower = inverterPower + islandLoadPower;
|
||||
|
||||
// return TextBlock
|
||||
// .AlignCenterVertical
|
||||
// (
|
||||
// gridBox , Flow.Horizontal(s.GridMeter.Ac.Power.Active),
|
||||
// gridBusColumn, Flow.Horizontal(islandToGridBusPower),
|
||||
// islandTopology
|
||||
// );
|
||||
|
||||
var gridTopology = TextBlock
|
||||
.AlignCenterVertical
|
||||
(
|
||||
gridBox,
|
||||
Flow.Horizontal(s.GridMeter.Ac.Power.Active),
|
||||
gridBusColumn
|
||||
);
|
||||
|
||||
return TextBlock.AlignCenterVertical
|
||||
(
|
||||
gridTopology,
|
||||
Flow.Horizontal(islandToGridBusPower),
|
||||
islandTopology
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateIslandTopology(StatusRecord s, ActivePower islandLoadPower, ActivePower inverterPower)
|
||||
{
|
||||
var dcBatteryPower = s.DcDc.Dc.Battery.Power;
|
||||
var dcdcPower = s.DcDc.Dc.Link.Power;
|
||||
|
||||
var batteries = CreateBatteryColumn(s);
|
||||
var dcBusColumn = CreateDcBusColumn(s);
|
||||
var islandBusColumn = CreateIslandBusColumn(s, islandLoadPower);
|
||||
var inverterBox = CreateInverterBox(s);
|
||||
var dcDcBox = CreateDcDcBox(s);
|
||||
|
||||
return TextBlock
|
||||
.AlignCenterVertical
|
||||
(
|
||||
islandBusColumn, Flow.Horizontal(inverterPower),
|
||||
inverterBox , Flow.Horizontal(inverterPower),
|
||||
dcBusColumn , Flow.Horizontal(dcdcPower),
|
||||
dcDcBox , Flow.Horizontal(dcBatteryPower),
|
||||
batteries
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateGridBox(StatusRecord statusRecord)
|
||||
{
|
||||
return statusRecord
|
||||
.GridMeter!
|
||||
.Ac
|
||||
.PhasePowersActive()
|
||||
.TitleBox("Grid");
|
||||
}
|
||||
|
||||
private static TextBlock CreateDcDcBox(StatusRecord s)
|
||||
{
|
||||
var dc48Voltage = s.DcDc.Dc.Battery.Voltage.ToDisplayString();
|
||||
|
||||
return TextBlock
|
||||
.AlignLeft(dc48Voltage)
|
||||
.TitleBox("DC/DC");
|
||||
}
|
||||
|
||||
private static TextBlock CreateInverterBox(StatusRecord s)
|
||||
{
|
||||
var inverterAcPhases = s
|
||||
.AcDc
|
||||
.Devices
|
||||
.Select(d => d.Status.Ac.Power)
|
||||
.ToReadOnlyList();
|
||||
|
||||
return TextBlock
|
||||
.AlignLeft(inverterAcPhases)
|
||||
.TitleBox("AC/DC");
|
||||
}
|
||||
|
||||
private static TextBlock CreateIslandBusColumn(StatusRecord s, ActivePower islandLoadPower)
|
||||
{
|
||||
var islandBusPv = 0.W(); // TODO
|
||||
|
||||
return ColumnBox
|
||||
(
|
||||
"Pv", islandBusPv,
|
||||
"Island Bus", s.AcDc.Ac.PhasePowersActive(),
|
||||
"Load", islandLoadPower
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateDcBusColumn(StatusRecord s)
|
||||
{
|
||||
var dcBusLoad = 0.W(); // TODO
|
||||
var pvOnDcPower = s.PvOnDc.Dc!.Power; // TODO !
|
||||
var dcLinkVoltage = s.DcDc.Dc.Link.Voltage.ToDisplayString();
|
||||
|
||||
return ColumnBox
|
||||
(
|
||||
"Pv" , pvOnDcPower,
|
||||
"Dc Bus", dcLinkVoltage,
|
||||
"Load" , dcBusLoad
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateBatteryColumn(StatusRecord s)
|
||||
{
|
||||
var bat = s.Battery;
|
||||
var batteryAvgBox = CreateAveragedBatteryBox(bat);
|
||||
|
||||
var batteryBoxes = bat
|
||||
.Devices
|
||||
.Select(CreateIndividualBattery)
|
||||
.ToReadOnlyList();
|
||||
|
||||
var individualBatteries = batteryBoxes.Any()
|
||||
? TextBlock.AlignLeft(batteryBoxes)
|
||||
: TextBlock.Empty;
|
||||
|
||||
return TextBlock
|
||||
.AlignCenterVertical
|
||||
(
|
||||
batteryAvgBox //,
|
||||
//individualBatteries // TODO
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords bat)
|
||||
{
|
||||
var batteryVoltage = bat.Dc.Voltage.ToDisplayString();
|
||||
var batterySoc = bat.Devices.Any() ? bat.Devices.Average(b => b.Soc).Percent().ToDisplayString() : "0";
|
||||
var batteryCurrent = bat.Dc.Current.ToDisplayString();
|
||||
var batteryTemp = bat.Temperature.ToDisplayString();
|
||||
var batteryHeatingCurrent = bat.HeatingCurrent.ToDisplayString();
|
||||
var alarms = bat.Alarms.Count + " Alarms";
|
||||
var warnings = bat.Warnings.Count + " Warnings";
|
||||
|
||||
return TextBlock
|
||||
.AlignLeft
|
||||
(
|
||||
batteryVoltage,
|
||||
batterySoc,
|
||||
batteryCurrent,
|
||||
batteryTemp,
|
||||
batteryHeatingCurrent,
|
||||
warnings,
|
||||
alarms
|
||||
)
|
||||
.TitleBox("Battery");
|
||||
}
|
||||
|
||||
private static TextBlock GridBusColumn(StatusRecord s)
|
||||
{
|
||||
var gridLoadPower = s.LoadOnAcGrid is not null
|
||||
? s.LoadOnAcGrid.Power.Active
|
||||
: 0; // TODO: show that LoadOnAcGrid is actually not available and not 0
|
||||
|
||||
return ColumnBox
|
||||
(
|
||||
"Pv", 0,
|
||||
"Grid Bus", s.GridMeter!.Ac.PhaseVoltages(),
|
||||
"Load", gridLoadPower
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock PhaseVoltages(this Ac3Bus ac)
|
||||
{
|
||||
return TextBlock.AlignLeft
|
||||
(
|
||||
ac.L1.Voltage.ToDisplayString(),
|
||||
ac.L2.Voltage.ToDisplayString(),
|
||||
ac.L3.Voltage.ToDisplayString()
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock PhasePowersActive(this Ac3Bus ac)
|
||||
{
|
||||
return TextBlock.AlignLeft
|
||||
(
|
||||
ac.L1.Power.Active.ToDisplayString(),
|
||||
ac.L2.Power.Active.ToDisplayString(),
|
||||
ac.L3.Power.Active.ToDisplayString()
|
||||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateIndividualBattery(Battery48TlRecord battery, Int32 i)
|
||||
{
|
||||
var batteryWarnings = battery.Warnings.Any();
|
||||
var batteryAlarms = battery.Alarms.Any();
|
||||
|
||||
var content = TextBlock.AlignLeft
|
||||
(
|
||||
battery.Dc.Voltage.ToDisplayString(),
|
||||
battery.Soc.ToDisplayString(),
|
||||
battery.Dc.Current.ToDisplayString() + " C/D",
|
||||
battery.Temperatures.Cells.Average.ToDisplayString(),
|
||||
battery.BusCurrent.ToDisplayString() + " T",
|
||||
batteryWarnings,
|
||||
batteryAlarms,
|
||||
battery.HeatingCurrent.ToDisplayString() + " H"
|
||||
);
|
||||
|
||||
var box = content.TitleBox($"Battery {i + 1}");
|
||||
var flow = Flow.Horizontal(battery.Dc.Power);
|
||||
|
||||
return TextBlock.AlignCenterVertical(flow, box);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")]
|
||||
|
||||
private static TextBlock ColumnBox(String pvTitle , ActivePower pvPower,
|
||||
String busTitle , Object busData,
|
||||
String loadTitle, ActivePower loadPower)
|
||||
{
|
||||
var pvBox = TextBlock.FromString(pvTitle).Box();
|
||||
var pvToBus = Flow.Vertical(pvPower);
|
||||
var busBox = TextBlock.AlignLeft(busData).TitleBox(busTitle);
|
||||
var busToLoad = Flow.Vertical(loadPower);
|
||||
var loadBox = TextBlock.FromString(loadTitle).Box();
|
||||
|
||||
return TextBlock.AlignCenterHorizontal(pvBox, pvToBus, busBox, busToLoad, loadBox);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace InnovEnergy.App.SaliMax;
|
||||
|
||||
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
|
||||
public static class Watchdog
|
||||
{
|
||||
// "it is generally recommended to ignore the return value of this call. "
|
||||
[DllImport("libsystemd.so.0")]
|
||||
private static extern Int32 sd_notify(Int32 unsetEnvironment, String state);
|
||||
|
||||
public static void Ready() => _ = sd_notify(0, "READY=1");
|
||||
public static void Alive() => _ = sd_notify(0, "WATCHDOG=1");
|
||||
}
|
|
@ -8,7 +8,7 @@ tunnel() {
|
|||
rPort=$3
|
||||
lPort=$4
|
||||
|
||||
echo -n "localhost:$lPort $name "
|
||||
echo -n "$name @ $ip mapped to localhost:$lPort "
|
||||
ssh -nNTL "$lPort:$ip:$rPort" "$host" 2> /dev/null &
|
||||
|
||||
until nc -vz 127.0.0.1 $lPort 2> /dev/null
|
||||
|
@ -22,23 +22,23 @@ tunnel() {
|
|||
|
||||
echo ""
|
||||
|
||||
tunnel "Trumpf Inverter (http) " 10.0.2.1 80 7001
|
||||
tunnel "Trumpf DCDC (http) " 10.0.3.1 80 7002
|
||||
tunnel "Ext Emu Meter (http) " 10.0.4.1 80 7003
|
||||
tunnel "Int Emu Meter (http) " 10.0.4.2 80 7004
|
||||
tunnel "AMPT (http) " 10.0.5.1 8080 7005
|
||||
tunnel "Doepke (http) " 10.0.6.1 80 7006
|
||||
tunnel "Trumpf Inverter (http) " 10.0.2.1 80 8001
|
||||
tunnel "Trumpf DCDC (http) " 10.0.3.1 80 8002
|
||||
tunnel "Ext Emu Meter (http) " 10.0.4.1 80 8003
|
||||
tunnel "Int Emu Meter (http) " 10.0.4.2 80 8004
|
||||
tunnel "AMPT (http) " 10.0.5.1 8080 8005
|
||||
|
||||
tunnel "Trumpf Inverter (modbus)" 10.0.2.1 502 5001
|
||||
tunnel "Trumpf DCDC (modbus) " 10.0.3.1 502 5002
|
||||
tunnel "Ext Emu Meter (modbus) " 10.0.4.1 502 5003
|
||||
tunnel "Int Emu Meter " 10.0.4.2 502 5004
|
||||
tunnel "AMPT (modbus) " 10.0.5.1 502 5005
|
||||
tunnel "Batteries " 127.0.0.1 6855 5007
|
||||
|
||||
tunnel "Adam " 10.0.1.1 502 5006
|
||||
tunnel "Batteries " 127.0.0.1 6855 5007
|
||||
|
||||
echo
|
||||
echo "press any key to close the tunnels ..."
|
||||
read -r -n 1 -s
|
||||
kill $(jobs -p)
|
||||
echo "done"
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public static class Program
|
|||
app.MapControllers();
|
||||
// app.MapGet("/", () => Controller.Index());
|
||||
var webTask = app.RunAsync();
|
||||
await Task.WhenAll(webTask);
|
||||
await Task.WhenAll(webTask, updateTask);
|
||||
}
|
||||
|
||||
private static OpenApiInfo OpenApiInfo { get; } = new OpenApiInfo
|
||||
|
|
|
@ -3,7 +3,7 @@ using InnovEnergy.Lib.Utils;
|
|||
namespace InnovEnergy.Lib.Channels.Framed;
|
||||
|
||||
|
||||
public class Channel<Tx, Rx> : Connection
|
||||
public class Channel<Tx, Rx> : Connection
|
||||
{
|
||||
private readonly AsyncAction<Tx> _Transmit;
|
||||
private readonly Async<Rx> _Receive;
|
||||
|
|
|
@ -19,11 +19,10 @@ public class AmptDevices
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
public AmptDevices(ModbusClient modbusClient)
|
||||
{
|
||||
_CommunicationUnit = new ModbusDevice<CommunicationUnitRegisters>(modbusClient);
|
||||
_StringOptimizers = StringOptimizers(modbusClient);
|
||||
_StringOptimizers = StringOptimizers(modbusClient);
|
||||
}
|
||||
|
||||
public AmptStatus Read()
|
||||
|
@ -36,7 +35,7 @@ public class AmptDevices
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine( "Failed to read Ampt data \n"+ e.Message );
|
||||
Console.WriteLine("Failed to read Ampt data \n" + e.Message);
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ using static System.IO.Ports.Parity;
|
|||
|
||||
namespace InnovEnergy.Lib.Devices.Battery48TL;
|
||||
|
||||
public class Battery48TlDevice: ModbusDevice<Battery48TlRecord>
|
||||
public class Battery48TlDevice : ModbusDevice<Battery48TlRecord>
|
||||
{
|
||||
public const Parity Parity = Odd;
|
||||
public const Int32 StopBits = 1;
|
||||
|
|
|
@ -20,7 +20,7 @@ public class Battery48TlDevices
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine( "Failed to read Battery data \n"+ e.Message );
|
||||
Console.WriteLine("Failed to read Battery data \n" + e.Message);
|
||||
// TODO: log
|
||||
|
||||
return Battery48TlRecords.Null;
|
||||
|
|
|
@ -94,24 +94,23 @@ public partial class Battery48TlRecord
|
|||
if (HasBit(14)) yield return "FUSE : Main fuse blown";
|
||||
if (HasBit(15)) yield return "HTRE : Battery failed to warm up";
|
||||
if (HasBit(16)) yield return "TCPE : Temperature sensor failure";
|
||||
if (HasBit(17)) yield return "STRE :";
|
||||
if (HasBit(17)) yield return "STRE : Voltage measurement circuit fails";
|
||||
if (HasBit(18)) yield return "CME : Current sensor failure";
|
||||
if (HasBit(19)) yield return "HWFL : BMS hardware failure";
|
||||
if (HasBit(20)) yield return "HWEM : Hardware protection tripped";
|
||||
if (HasBit(21)) yield return "ThM : Heatsink temperature too high";
|
||||
if (HasBit(22)) yield return "vsm1 : String voltage too low";
|
||||
if (HasBit(23)) yield return "vsm2 : Low string voltage failure";
|
||||
if (HasBit(25)) yield return "vsM2 : String voltage too high";
|
||||
if (HasBit(27)) yield return "iCM2 : Charge current too high";
|
||||
if (HasBit(29)) yield return "iDM2 : Discharge current too high";
|
||||
if (HasBit(31)) yield return "MID2 : String voltage unbalance too high";
|
||||
if (HasBit(33)) yield return "CCBF : Internal charger hardware failure";
|
||||
if (HasBit(34)) yield return "AhFL :";
|
||||
if (HasBit(36)) yield return "TbCM :";
|
||||
if (HasBit(37)) yield return "BRNF :";
|
||||
// if (HasBit(34)) yield return "AhFL :"; // This is doesn't exist in the manual
|
||||
// if (HasBit(36)) yield return "TbCM :"; // This is doesn't exist in the manual
|
||||
// if (HasBit(37)) yield return "BRNF :"; // This is doesn't exist in the manual
|
||||
if (HasBit(42)) yield return "HTFS : Heater Fuse Blown";
|
||||
if (HasBit(43)) yield return "DATA : Parameters out of range";
|
||||
if (HasBit(45)) yield return "CELL2:";
|
||||
if (HasBit(45)) yield return "CELL2: Unbalance string voltages";
|
||||
if (HasBit(46)) yield return "HEBT : Loss of heartbeat";
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
|
@ -124,18 +123,20 @@ public partial class Battery48TlRecord
|
|||
if (HasBit(6) ) yield return "VBm1: Bus voltage low";
|
||||
if (HasBit(8) ) yield return "VBM1: Bus voltage high";
|
||||
if (HasBit(10)) yield return "IDM1: Discharge current high";
|
||||
if (HasBit(22)) yield return "vsm1: String voltage too low";
|
||||
if (HasBit(24)) yield return "vsM1: String voltage high";
|
||||
if (HasBit(26)) yield return "iCM1: Charge current high";
|
||||
if (HasBit(28)) yield return "iDM1: Discharge current high";
|
||||
if (HasBit(30)) yield return "MID1: String voltages unbalanced";
|
||||
if (HasBit(32)) yield return "BLPW: Not enough charging power on bus";
|
||||
if (HasBit(33)) yield return "CCBF : Internal charger hardware failure";
|
||||
if (HasBit(35)) yield return "Ah_W: String SOC low";
|
||||
if (HasBit(38)) yield return "MPMM: Midpoint wiring problem";
|
||||
if (HasBit(39)) yield return "TCMM:";
|
||||
// if (HasBit(39)) yield return "TCMM:"; // This is doesn't exist in the manual
|
||||
if (HasBit(40)) yield return "TCdi: Temperature difference between strings high";
|
||||
if (HasBit(41)) yield return "WMTO:";
|
||||
if (HasBit(44)) yield return "bit44:";
|
||||
if (HasBit(46)) yield return "CELL1:";
|
||||
// if (HasBit(41)) yield return "WMTO:"; // This is doesn't exist in the manual
|
||||
if (HasBit(44)) yield return "LMPW : String voltages unbalance warning";
|
||||
if (HasBit(47)) yield return "TOCW : ";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,16 @@ public partial class Battery48TlRecord
|
|||
[InputRegister(1017, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsRight;
|
||||
[InputRegister(1003, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsAverage;
|
||||
|
||||
|
||||
[InputRegister(1054)] private Double _FwVersion;
|
||||
[InputRegister(1055)] private Double _SerialNum1;
|
||||
[InputRegister(1056)] private Double _SerialNum2;
|
||||
[InputRegister(1057)] private Double _SerialNum3;
|
||||
[InputRegister(1058)] private Double _SerialNum4;
|
||||
[InputRegister(1059)] private Double _LimpBitMap;
|
||||
[InputRegister(1060)] private Double _BatteryState1;
|
||||
[InputRegister(1061)] private Double _BatteryState2;
|
||||
|
||||
private LedState ParseLed(LedColor led) => (LedState)((_LedStates >> (Int32)led) & 3);
|
||||
|
||||
// public Decimal CellsVoltage { get; init; }
|
||||
|
|
|
@ -19,7 +19,7 @@ public class Battery48TlRecords
|
|||
HeatingCurrent = records.Any() ? records.Sum(b => b.HeatingCurrent) : 0;
|
||||
|
||||
Dc = empty
|
||||
? DcBus.FromVoltageCurrent(0, 0)
|
||||
? DcBus.Null
|
||||
: DcBus.FromVoltageCurrent
|
||||
(
|
||||
records.Average(r => r.Dc.Voltage),
|
||||
|
|
|
@ -36,8 +36,12 @@ public class DcControl
|
|||
}
|
||||
}
|
||||
|
||||
public DcPrechargeConfig PrechargeConfig => _Self.DcPrechargeConfig;
|
||||
|
||||
public DcPrechargeConfig PrechargeConfig
|
||||
{
|
||||
get { return _Self.DcPrechargeConfig; }
|
||||
set { _Self.DcPrechargeConfig = value; }
|
||||
}
|
||||
|
||||
private Boolean Is480V => _Self.GridType is GridType.GridTied480V60Hz or GridType.Island480V60Hz;
|
||||
|
||||
internal DcControl(AcDcRecord self) => _Self = self;
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
|||
public enum DcPrechargeConfig : UInt16
|
||||
{
|
||||
WaitForExternalPrecharge = 0,
|
||||
PrechargeDcWithSystemCtl = 1,
|
||||
PrechargeDcWithInternal = 1,
|
||||
PrechargeDcWithDcDcs = 2,
|
||||
PrechargeDcWithSystemCtlAndWait = 3,
|
||||
}
|
|
@ -15,6 +15,19 @@ public class CurrentControl
|
|||
get => _Self.MaxCurrentChangePerMs;
|
||||
set => _Self.MaxCurrentChangePerMs = value.Value;
|
||||
}
|
||||
|
||||
public Current MaxBatteryChargingCurrent
|
||||
{
|
||||
get => _Self.MaxBatteryChargingCurrent;
|
||||
set => _Self.MaxBatteryChargingCurrent = value.Value;
|
||||
}
|
||||
|
||||
public Current MaxBatteryDischargingCurrent
|
||||
{
|
||||
get => _Self.MaxBatteryDischargingCurrent;
|
||||
set => _Self.MaxBatteryDischargingCurrent = value.Value;
|
||||
}
|
||||
|
||||
|
||||
private readonly DcDcRecord _Self;
|
||||
internal CurrentControl(DcDcRecord self) => _Self = self;
|
||||
|
|
|
@ -20,11 +20,14 @@ public partial class DcDcRecord
|
|||
[HoldingRegister(4100, Scale = .01)] internal Double MaxBatteryVoltage ;
|
||||
[HoldingRegister(4101, Scale = .01)] internal Double MinBatteryVoltage ;
|
||||
|
||||
[HoldingRegister(4106, Scale = .1)] internal Double MaxBatteryChargingCurrent ;
|
||||
[HoldingRegister(4109, Scale = .1)] internal Double MaxBatteryDischargingCurrent ;
|
||||
|
||||
[HoldingRegister(4112, Scale = .1)] internal Double VccEndPointVoltage ;
|
||||
[HoldingRegister(4115)] internal Double VccEndPointCurrent ;
|
||||
[HoldingRegister(4118)] internal Double VccStartPointCurrent ;
|
||||
|
||||
[HoldingRegister(4118)] internal Double MaxDcPower ;
|
||||
[HoldingRegister(4121)] internal Double MaxDcPower ;
|
||||
|
||||
[HoldingRegister(4124, Scale = .1)] internal Double MaxVoltageAlarm ;
|
||||
[HoldingRegister(4127, Scale = .1)] internal Double MinVoltageAlarm ;
|
||||
|
|
|
@ -35,11 +35,11 @@ public class ModbusDevice<[DynamicallyAccessedMembers(All)] R> where R : notnull
|
|||
return Read(r);
|
||||
}
|
||||
|
||||
public R Read(R record)
|
||||
public R Read(R record)
|
||||
{
|
||||
foreach (var batch in _Batches)
|
||||
batch.Read(record);
|
||||
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ public static class UnixTimeSpanExtensions
|
|||
public static UnixTimeSpan Weeks (this Int32 w) => UnixTimeSpan.FromWeeks (w);
|
||||
|
||||
public static UnixTimeSpan Seconds(this UInt32 s) => UnixTimeSpan.FromSeconds(s);
|
||||
public static UnixTimeSpan Minutes(this UInt32 m) => UnixTimeSpan.FromSeconds(m);
|
||||
public static UnixTimeSpan Hours (this UInt32 h) => UnixTimeSpan.FromMinutes(h);
|
||||
public static UnixTimeSpan Days (this UInt32 d) => UnixTimeSpan.FromHours (d);
|
||||
public static UnixTimeSpan Weeks (this UInt32 w) => UnixTimeSpan.FromDays (w);
|
||||
public static UnixTimeSpan Minutes(this UInt32 m) => UnixTimeSpan.FromMinutes(m);
|
||||
public static UnixTimeSpan Hours (this UInt32 h) => UnixTimeSpan.FromHours (h);
|
||||
public static UnixTimeSpan Days (this UInt32 d) => UnixTimeSpan.FromDays (d);
|
||||
public static UnixTimeSpan Weeks (this UInt32 w) => UnixTimeSpan.FromWeeks (w);
|
||||
}
|
|
@ -9,6 +9,11 @@ public abstract class Unit
|
|||
|
||||
public override String ToString() => $"{Value} {Symbol}";
|
||||
|
||||
private static readonly IReadOnlyList<String> Prefix = new[] { "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Y" };
|
||||
|
||||
private static Int32 MaxPrefix { get; } = Prefix.Count - 1;
|
||||
private static Int32 DefaultIndex { get; } = Prefix.TakeWhile(e => e != "").Count();
|
||||
|
||||
public String ToDisplayString()
|
||||
{
|
||||
if (Value == 0)
|
||||
|
@ -17,14 +22,14 @@ public abstract class Unit
|
|||
var a = Math.Abs(Value);
|
||||
var s = Math.Sign(Value);
|
||||
|
||||
var i = 8;
|
||||
var i = DefaultIndex;
|
||||
|
||||
while (a >= 10000)
|
||||
while (a >= 10000 && i < MaxPrefix)
|
||||
{
|
||||
a /= 1000;
|
||||
i++;
|
||||
}
|
||||
while (a < 10)
|
||||
while (a < 10 && i > 0)
|
||||
{
|
||||
a *= 1000;
|
||||
i--;
|
||||
|
@ -37,6 +42,6 @@ public abstract class Unit
|
|||
return $"{r * s} {Prefix[i]}{Symbol}";
|
||||
}
|
||||
|
||||
private static readonly IReadOnlyList<String> Prefix = new[] { "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Y" };
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,19 @@ public static class Units
|
|||
public static Energy Wh (this Double value) => value;
|
||||
public static Percent Percent(this Double value) => value;
|
||||
|
||||
public static Current A (this Int32 value) => value;
|
||||
public static Voltage V (this Int32 value) => value;
|
||||
public static ActivePower W (this Int32 value) => value;
|
||||
public static ReactivePower Var (this Int32 value) => value;
|
||||
public static ApparentPower Va (this Int32 value) => value;
|
||||
public static Resistance Ohm (this Int32 value) => value;
|
||||
public static Frequency Hz (this Int32 value) => value;
|
||||
public static Angle Rad (this Int32 value) => value;
|
||||
public static Temperature Celsius(this Int32 value) => value;
|
||||
public static Energy KWh (this Int32 value) => value * 1000;
|
||||
public static Energy Wh (this Int32 value) => value;
|
||||
public static Percent Percent(this Int32 value) => value;
|
||||
|
||||
public static String ToCsv(this Object thing)
|
||||
{
|
||||
var csvLines = new List<String>();
|
||||
|
|
|
@ -13,4 +13,6 @@ public static class ArrayExtensions
|
|||
Array.Fill(ts, element);
|
||||
return ts;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<T> AsReadOnlyList<T>(this T[] ts) => ts;
|
||||
}
|
|
@ -38,7 +38,6 @@ public static class ConsoleUtils
|
|||
return t;
|
||||
}
|
||||
|
||||
|
||||
public static T Write<T>(this T t, ConsoleColor color)
|
||||
{
|
||||
var c = Console.ForegroundColor;
|
||||
|
|
|
@ -277,6 +277,9 @@ public static class EnumerableUtils
|
|||
|
||||
public static T[] ToArray<T>(this IEnumerable<T> ts, Int32 n)
|
||||
{
|
||||
if (ts is T[] ta)
|
||||
return ta;
|
||||
|
||||
var array = new T[n];
|
||||
var i = 0;
|
||||
|
||||
|
@ -296,6 +299,8 @@ public static class EnumerableUtils
|
|||
return ts as T[] ?? ts.ToArray(ts.Count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static IEnumerable<T> Concat<T>(this IEnumerable<T> ts, T last)
|
||||
{
|
||||
foreach (var t in ts)
|
||||
|
|
|
@ -132,9 +132,11 @@ public static class StringUtils
|
|||
.SideBySideWith(text, "");
|
||||
}
|
||||
|
||||
public static IReadOnlyList<String> SplitLines(this String s)
|
||||
public static IReadOnlyList<String> SplitLines(this String? s)
|
||||
{
|
||||
return s.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
return s is null
|
||||
? Array.Empty<String>()
|
||||
: s.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,13 +8,19 @@ public class TextBlock
|
|||
|
||||
public override String ToString() => _Lines.JoinLines();
|
||||
|
||||
public static TextBlock AlignLeft(IReadOnlyList<Object> things)
|
||||
public static TextBlock Empty { get; } = new TextBlock();
|
||||
|
||||
public static TextBlock AlignLeft(IEnumerable<Object> things)
|
||||
{
|
||||
var lines = things
|
||||
.SelectMany(GetLines)
|
||||
.Unless(String.IsNullOrEmpty)
|
||||
.ToList();
|
||||
|
||||
var width = lines.Max(l => l.Length);
|
||||
if (!lines.Any())
|
||||
return Empty;
|
||||
|
||||
var width = lines.Max(l => l.Length);
|
||||
|
||||
var alignedLines = lines
|
||||
.Select(l => l.PadRight(width))
|
||||
|
@ -27,8 +33,12 @@ public class TextBlock
|
|||
{
|
||||
var lines = things
|
||||
.SelectMany(GetLines)
|
||||
.Unless(String.IsNullOrEmpty)
|
||||
.ToList();
|
||||
|
||||
if (!lines.Any())
|
||||
return Empty;
|
||||
|
||||
var width = lines.Max(l => l.Length);
|
||||
|
||||
var alignedLines = lines
|
||||
|
@ -42,8 +52,12 @@ public class TextBlock
|
|||
{
|
||||
var lines = things
|
||||
.SelectMany(GetLines)
|
||||
.Where(l => !String.IsNullOrEmpty(l))
|
||||
.ToList();
|
||||
|
||||
if (!lines.Any())
|
||||
return Empty;
|
||||
|
||||
var width = lines.Max(l => l.Length);
|
||||
|
||||
var alignedLines = lines
|
||||
|
@ -52,15 +66,17 @@ public class TextBlock
|
|||
|
||||
return new TextBlock(alignedLines);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static TextBlock AlignTop(IReadOnlyList<Object> things)
|
||||
{
|
||||
var columns = things
|
||||
.Select(GetLines)
|
||||
.Where(c => c.Count > 0)
|
||||
.ToList();
|
||||
|
||||
if (!columns.Any())
|
||||
return Empty;
|
||||
|
||||
var height = columns.Max(l => l.Count);
|
||||
|
||||
var alignedLines = Enumerable
|
||||
|
@ -76,8 +92,12 @@ public class TextBlock
|
|||
{
|
||||
var columns = things
|
||||
.Select(GetLines)
|
||||
.Where(c => c.Count > 0)
|
||||
.ToList();
|
||||
|
||||
if (!columns.Any())
|
||||
return Empty;
|
||||
|
||||
var height = columns.Max(l => l.Count);
|
||||
|
||||
var alignedLines = Enumerable
|
||||
|
@ -93,8 +113,12 @@ public class TextBlock
|
|||
{
|
||||
var columns = things
|
||||
.Select(GetLines)
|
||||
.Where(c => c.Count > 0)
|
||||
.ToList();
|
||||
|
||||
if (!columns.Any())
|
||||
return Empty;
|
||||
|
||||
var height = columns.Max(l => l.Count);
|
||||
|
||||
var alignedLines = Enumerable
|
||||
|
@ -105,18 +129,18 @@ public class TextBlock
|
|||
return new TextBlock(alignedLines);
|
||||
}
|
||||
|
||||
public static TextBlock AlignLeft (params Object[] things) => AlignLeft ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignRight (params Object[] things) => AlignRight ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignTop (params Object[] things) => AlignTop ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignBottom (params Object[] things) => AlignBottom ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignCenterVertical (params Object[] things) => AlignCenterVertical ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignCenterHorizontal(params Object[] things) => AlignCenterHorizontal((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignLeft (params Object?[] things) => AlignLeft ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignRight (params Object?[] things) => AlignRight ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignTop (params Object?[] things) => AlignTop ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignBottom (params Object?[] things) => AlignBottom ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignCenterVertical (params Object?[] things) => AlignCenterVertical ((IReadOnlyList<Object>) things);
|
||||
public static TextBlock AlignCenterHorizontal(params Object?[] things) => AlignCenterHorizontal((IReadOnlyList<Object>) things);
|
||||
|
||||
public static TextBlock FromString(String thing) => AlignLeft(thing);
|
||||
|
||||
public TextBlock Box()
|
||||
{
|
||||
var width = _Lines.Max(l => l.Length);
|
||||
var width = _Lines.Any() ? _Lines.Max(l => l.Length) : 0;
|
||||
|
||||
var hLine = "".PadRight(width + 2, '─');
|
||||
var top = "┌" + hLine + "┐";
|
||||
|
@ -134,7 +158,7 @@ public class TextBlock
|
|||
|
||||
public TextBlock TitleBox(String title)
|
||||
{
|
||||
var linesWidth = _Lines.Max(l => l.Length);
|
||||
var linesWidth = _Lines.Any() ? _Lines.Max(l => l.Length) : 0;
|
||||
var titleWidth = title.Length;
|
||||
|
||||
var width = Math.Max(linesWidth, titleWidth);
|
||||
|
@ -175,15 +199,18 @@ public class TextBlock
|
|||
}
|
||||
|
||||
|
||||
private static IReadOnlyList<String> GetLines(Object t)
|
||||
private static IReadOnlyList<String> GetLines(Object? t)
|
||||
{
|
||||
return t is TextBlock tb
|
||||
? tb._Lines
|
||||
: t.ToString()!.SplitLines();
|
||||
return t switch
|
||||
{
|
||||
TextBlock tb => tb._Lines,
|
||||
null => Array.Empty<String>(),
|
||||
_ => t.ToString()!.SplitLines()
|
||||
};
|
||||
}
|
||||
|
||||
private static String Space(Int32 totalWidth)
|
||||
{
|
||||
return "".PadRight(totalWidth);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,9 +60,15 @@ public static class Utils
|
|||
return t;
|
||||
}
|
||||
|
||||
// Below does not work ;(
|
||||
// [DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||||
// public static R Apply<T, S, R>(this T t, Func<S, R> f) where T : S
|
||||
// {
|
||||
// return f(t);
|
||||
// }
|
||||
|
||||
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||||
public static R Apply<T, R>(this T t, Func<T, R> f) => f(t);
|
||||
|
||||
|
||||
[DebuggerStepThrough][MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||||
public static R Apply<T1, T2, R>(this (T1 p1, T2 p2) t, Func<T1, T2, R> f) => f(t.p1, t.p2);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "VrmGrabberOxidised"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rocket = "=0.5.0-rc.3"
|
||||
reqwest = "0.11.18"
|
||||
openssl = { version = "0.10", features = ["vendored"]}
|
||||
serde = {version = "1.0.173", features = ["derive"]}
|
||||
serde_json = "1.0.103"
|
||||
handlebars = "5.0.0-beta.1"
|
||||
urlencoding = "2.1.2"
|
|
@ -0,0 +1,11 @@
|
|||
pub struct Installation {
|
||||
name: String,
|
||||
vrm: i64,
|
||||
ip: String,
|
||||
identifier: String,
|
||||
serial: String,
|
||||
online: String,
|
||||
last_seen: String,
|
||||
number_of_batteries: String,
|
||||
batter_firmware_version: String
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
use rocket::serde;
|
||||
use handlebars::Handlebars;
|
||||
// use rocket::serde::__private::de::TagContentOtherField::Content;
|
||||
|
||||
use urlencoding::encode;
|
||||
|
||||
mod installation;
|
||||
mod vrm_account;
|
||||
|
||||
|
||||
struct InstallationToHtmlInterface<'a> {
|
||||
Name: &'a str,
|
||||
Ip: i64,
|
||||
Vrm: &'a str,
|
||||
Identifier: &'a str,
|
||||
Serial: &'a str,
|
||||
EscapedName: &'a str,
|
||||
Online: &'a str,
|
||||
LastSeen: &'a str,
|
||||
NumBatteries: &'a str,
|
||||
BatteryVersion: &'a str,
|
||||
ServerIp : &'a str,
|
||||
FirmwareVersion: &'a str,
|
||||
}
|
||||
|
||||
// impl Default for InstallationToHtmlInterface{
|
||||
// fn default() -> Self {
|
||||
// Self{
|
||||
// Name: "",
|
||||
// Ip: 0,
|
||||
// Vrm: "",
|
||||
// Identifier: "",
|
||||
// Serial: "",
|
||||
// EscapedName: "",
|
||||
// Online: "",
|
||||
// LastSeen: "",
|
||||
// NumBatteries: "",
|
||||
// BatteryVersion: "",
|
||||
// ServerIp : "10.2.0.1",
|
||||
// FirmwareVersion: "AF09",
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
#[get("/")]
|
||||
async fn index() -> String{
|
||||
let res = vrm_account::all_installations_request().await;
|
||||
let json = rocket::serde::Deserialize(res.unwrap().text().await.unwrap());
|
||||
let source = "<head>
|
||||
<style>
|
||||
tbody {
|
||||
background-color: #e4f0f5;
|
||||
}
|
||||
|
||||
|
||||
tbody tr:nth-child(odd) {
|
||||
background-color: #ECE9E9;
|
||||
}
|
||||
|
||||
th, td { /* cell */
|
||||
padding: 0.75rem;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
th { /* header cell */
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
color: #272838;
|
||||
border-bottom: 2px solid #EB9486;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #F9F8F8;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
border: 2px solid rgb(200, 200, 200);
|
||||
letter-spacing: 1px;
|
||||
font-family: sans-serif;
|
||||
font-size: 0.8rem;
|
||||
position: absolute; top: 0; bottom: 0; left: 0; right: 0;
|
||||
}
|
||||
|
||||
thead th {
|
||||
border: 1px solid rgb(190, 190, 190);
|
||||
padding: 5px 10px;
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 0px;
|
||||
background: white;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: left;
|
||||
}
|
||||
#managerTable {
|
||||
overflow: hidden;
|
||||
}</style></head>
|
||||
|
||||
<div id='managerTable'>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Gui</th>
|
||||
<th>VRM</th>
|
||||
<th>Grafana</th>
|
||||
<th>Identifier</th>
|
||||
<th>Last Seen</th>
|
||||
<th>Serial</th>
|
||||
<th>#Batteries</th>
|
||||
<th>Firmware-Version</th>
|
||||
<th>Update</th>
|
||||
</tr>
|
||||
{{#inst}}
|
||||
{{> installations}}
|
||||
{{/inst}}
|
||||
</tbody>
|
||||
</table>
|
||||
<div id='managerTable'>";
|
||||
|
||||
let partialSource= "<tr><td>{{Name}}</td>
|
||||
<td><a target='_blank' href=http://{{Ip}}>{{online}} {{Ip}}</a></td>
|
||||
<td><a target='_blank' href=https://vrm.victronenergy.com/installation/{{Vrm}}/dashboard>VRM</a></td>
|
||||
<td><a target='_blank' href='https://salidomo.innovenergy.ch/d/ENkNRQXmk/installation?refresh=5s&orgId=1&var-Installation={{EscapedName}}&kiosk=tv'>Grafana</a></td>
|
||||
<td>{{Identifier}}</td>
|
||||
<td>{{LastSeen}}</td>
|
||||
<td>{{Serial}}</td>
|
||||
<td>{{NumBatteries}}</td>
|
||||
<td>{{BatteryVersion}}</td>
|
||||
<td><a target='_blank' href=https://{{ServerIp}}/UpdateBatteryFirmware/{{Ip}}/{{NumBatteries}}>⬆️{{FirmwareVersion}}</a></td>
|
||||
</tr>";
|
||||
|
||||
let mut handlebars = Handlebars::new();
|
||||
handlebars.register_template_string("installations", partialSource);
|
||||
|
||||
let mut installsForHtml = Vec::<InstallationToHtmlInterface>::new();
|
||||
for inst in json["records"] {
|
||||
let mut installation = InstallationToHtmlInterface {
|
||||
Name: inst["name"],
|
||||
Ip: 0, // TODO
|
||||
Vrm: inst["idSite"].parse::<i64>(),
|
||||
Identifier: inst["identifier"],
|
||||
Serial: "", //Todo Grab and parse Details
|
||||
EscapedName: &encode(inst["name"]).to_string(),
|
||||
Online: "",
|
||||
LastSeen: "",
|
||||
NumBatteries: "",
|
||||
BatteryVersion: "",
|
||||
ServerIp : "10.2.0.1",
|
||||
FirmwareVersion: "AF09",
|
||||
};
|
||||
installsForHtml.push(installation)
|
||||
}
|
||||
let mut data = installsForHtml;
|
||||
|
||||
let result = handlebars.render(source, &data);
|
||||
return result.unwrap();
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build().mount("/", routes![index])
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
use std::ops::Add;
|
||||
use reqwest::{Error, Response};
|
||||
// use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
const API_ROOT:&str ="https://vrmapi.victronenergy.com/v2";
|
||||
const USER_ID:&str = "55450";
|
||||
const TOKEN:&str = "88b36e7226ff7fa7bf231d0f9f98e916f661923c84e494cd27b6bc795ec0074b";
|
||||
|
||||
pub async fn all_installations_request() -> Result<Response, Error> {
|
||||
// use reqwest::header::AUTHORIZATION;
|
||||
let client = reqwest::Client::new();
|
||||
let res = client
|
||||
.get(API_ROOT.to_owned().add("/users/").add(USER_ID).add("/installations"))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("x-authorization","Token ".to_owned()+TOKEN)
|
||||
.send()
|
||||
.await;
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const axiosConfigWithoutToken = axios.create({
|
||||
baseURL: "http://localhost:5000/api",
|
||||
baseURL: "https://localhost:7087",
|
||||
});
|
||||
|
||||
const axiosConfig = axios.create({
|
||||
baseURL: "http://localhost:5000/api",
|
||||
baseURL: "https://localhost:7087",
|
||||
});
|
||||
|
||||
axiosConfig.defaults.params = {};
|
||||
|
|
Loading…
Reference in New Issue