Skip to content

Commit 0e4391a

Browse files
feat: describe LDevice
1 parent 7ef0dd8 commit 0e4391a

File tree

5 files changed

+376
-28
lines changed

5 files changed

+376
-28
lines changed

describe.spec.ts

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ const testScl = new DOMParser().parseFromString(
1414
<LDevice inst="ldInst1">
1515
<LN0 lnClass="LLN0" inst="" lnType="baseLLN0"/>
1616
<LN lnClass="XCBR" inst="1" lnType="baseXCBR"/>
17-
<LN lnClass="XCBR" inst="1" lnType="equalXCBR"/>
18-
<LN lnClass="XCBR" inst="1" lnType="diffXCBR"/>
1917
</LDevice>
2018
<LDevice inst="ldInst2">
2119
<LN0 lnClass="LLN0" inst="" lnType="equalLLN0"/>
22-
</LDevice>
20+
<LN lnClass="XCBR" inst="1" lnType="equalXCBR"/>
21+
</LDevice>
2322
<LDevice inst="ldInst3">
2423
<LN0 lnClass="LLN0" inst="" lnType="diffLLN0"/>
25-
</LDevice>
24+
<LN lnClass="XCBR" inst="1" lnType="diffXCBR"/>
25+
</LDevice>
2626
</Server>
2727
</AccessPoint>
2828
</IED>
@@ -114,13 +114,9 @@ const baseEnumType = testScl.querySelector("#someID")!;
114114
const diffEnumType = testScl.querySelector("#someDiffID")!;
115115
const equalEnumType = testScl.querySelector("#someOtherID")!;
116116

117-
const baseLN = testScl.querySelector(`LN[lnType="baseXCBR"]`)!;
118-
const equalLN = testScl.querySelector(`LN[lnType="equalXCBR"]`)!;
119-
const diffLN = testScl.querySelector(`LN[lnType="diffXCBR"]`)!;
120-
121-
const baseLN0 = testScl.querySelector(`LDevice[inst="ldInst1"]>LN0`)!;
122-
const equalLN0 = testScl.querySelector(`LDevice[inst="ldInst2"]>LN0`)!;
123-
const diffLN0 = testScl.querySelector(`LDevice[inst="ldInst3"]>LN0`)!;
117+
const baseLDevice = testScl.querySelector(`LDevice[inst="ldInst1"]`)!;
118+
const equalLDevice = testScl.querySelector(`LDevice[inst="ldInst2"]`)!;
119+
const diffLDevice = testScl.querySelector(`LDevice[inst="ldInst3"]`)!;
124120

125121
describe("Describe SCL elements function", () => {
126122
it("returns undefined with missing describe function", () =>
@@ -139,23 +135,13 @@ describe("Describe SCL elements function", () => {
139135
JSON.stringify(describeSclElement(equalEnumType)),
140136
));
141137

142-
it("returns same description with semantically equal LN0's", () =>
143-
expect(JSON.stringify(describeSclElement(baseLN0))).to.equal(
144-
JSON.stringify(describeSclElement(equalLN0)),
145-
));
146-
147-
it("returns different description with unequal LN0 elements", () =>
148-
expect(JSON.stringify(describeSclElement(baseLN0))).to.not.equal(
149-
JSON.stringify(describeSclElement(diffLN0)),
150-
));
151-
152-
it("returns same description with semantically equal LN's", () =>
153-
expect(JSON.stringify(describeSclElement(baseLN))).to.equal(
154-
JSON.stringify(describeSclElement(equalLN)),
138+
it("returns same description with semantically equal LDevice's", () =>
139+
expect(JSON.stringify(describeSclElement(baseLDevice))).to.equal(
140+
JSON.stringify(describeSclElement(equalLDevice)),
155141
));
156142

157-
it("returns different description with unequal LN elements", () =>
158-
expect(JSON.stringify(describeSclElement(baseLN))).to.not.equal(
159-
JSON.stringify(describeSclElement(diffLN)),
143+
it("returns different description with unequal LDevice elements", () =>
144+
expect(JSON.stringify(describeSclElement(baseLDevice))).to.not.equal(
145+
JSON.stringify(describeSclElement(diffLDevice)),
160146
));
161147
});

describe.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Text, TextDescription } from "./describe/Text.js";
33
import { EnumType, EnumTypeDescription } from "./describe/EnumType.js";
44
import { DAType, DATypeDescription } from "./describe/DAType.js";
55
import { DOType, DOTypeDescription } from "./describe/DOType.js";
6+
import { LDevice, LDeviceDescription } from "./describe/LDevice.js";
67
import { LNodeType, LNodeTypeDescription } from "./describe/LNodeType.js";
78
import { LN, LNDescription } from "./describe/LN.js";
89
import { LN0, LN0Description } from "./describe/LN0.js";
@@ -16,7 +17,8 @@ export type Description =
1617
| DOTypeDescription
1718
| LNodeTypeDescription
1819
| LNDescription
19-
| LN0Description;
20+
| LN0Description
21+
| LDeviceDescription;
2022
const sclElementDescriptors: Partial<
2123
Record<string, (element: Element) => Description | undefined>
2224
> = {
@@ -28,6 +30,7 @@ const sclElementDescriptors: Partial<
2830
LNodeType,
2931
LN,
3032
LN0,
33+
LDevice,
3134
};
3235

3336
export function describe(element: Element): Description | undefined {

describe/LDevice.spec.ts

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
import { expect } from "chai";
2+
import { LDevice } from "./LDevice.js";
3+
4+
const scl = new DOMParser().parseFromString(
5+
`<SCL xmlns="http://www.iec.ch/61850/2003/SCL" >
6+
<IED name="IED1">
7+
<AccessPoint name="AP1">
8+
<Server>
9+
<LDevice inst="lDevice1">
10+
<LN0 lnClass="LLN0" inst="" lnType="LLN0">
11+
<DataSet name="baseDataSet" >
12+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal" fc="ST" />
13+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="q" fc="ST" />
14+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="LLN0" doName="Beh" daName="stVal" fc="ST" />
15+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="LLN0" lnInst="" doName="Beh" fc="ST" />
16+
</DataSet>
17+
<DOI name="Beh" >
18+
<DAI name="stVal">
19+
<Val>on</Val>
20+
</DAI>
21+
</DOI>
22+
<GSEControl name="gse1" datSet="baseDataSet" />
23+
<GSEControl name="gse2" />
24+
<SampledValueControl name="smv1" datSet="baseDataSet" smpRate="80" nofASDU="1" >
25+
<SmvOpts />
26+
</SampledValueControl>
27+
<SampledValueControl name="smv2" smpRate="80" nofASDU="1" >
28+
<SmvOpts />
29+
</SampledValueControl>
30+
<Log name="someLog" />
31+
<Log name="someOtherLog" />
32+
<Inputs>
33+
<ExtRef intAddr="Beh.t" pLN="LLN0" pDO="Beh" pDA="t" pServT="GOOSE" />
34+
</Inputs>
35+
</LN0>
36+
<LN prefix="Meas" lnClass="MMXU" inst="1" lnType="MMXU" >
37+
<DataSet name="baseDataSet" >
38+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal" fc="ST" />
39+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="q" fc="ST" />
40+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="LLN0" doName="Beh" daName="stVal" fc="ST" />
41+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="LLN0" lnInst="" doName="Beh" fc="ST" />
42+
</DataSet>
43+
<DOI name="A" >
44+
<SDI name="phsA" >
45+
<SDI name="cVal" >
46+
<SDI name="mag" >
47+
<DAI name="f" >
48+
<Val sGroup="1">10.10</Val>
49+
<Val sGroup="3">30.30</Val>
50+
<Val sGroup="2">20.20</Val>
51+
</DAI>
52+
</SDI>
53+
</SDI>
54+
</SDI>
55+
</DOI>
56+
<LogControl name="anotherLog" logName="logName" />
57+
<LogControl name="log" dataSet="baseDataSet" logName="logName" reasonCode="true" logEna="true" intgPd="0" bufTime="0" >
58+
<TrgOps dchg="false" qchg="false" dupd="false" period="false" gi="false" />
59+
</LogControl>
60+
<ReportControl name="report" datSet="baseDataSet" intgPd="0" indexed="true" buffered="true" bufTime="0" confRev="0" >
61+
<TrgOps dchg="false" qchg="false" dupd="false" period="false" gi="false" />
62+
<OptFields seqNum="false" timeStamp="false" dataSet="false" reasonCode="false" dataRef="false" entryID="false" configRef="false" bufOvfl="false"/>
63+
<RptEnabled max="0" />
64+
</ReportControl>
65+
<ReportControl name="anotherReport" />
66+
</LN>
67+
<LN lnClass="MMXU" inst="2" lnType="MMXU" />
68+
</LDevice>
69+
<LDevice inst="lDevice2">
70+
<LN0 lnClass="LLN0" inst="" lnType="LLN02" >
71+
<DataSet name="equalDataSet" >
72+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal" fc="ST" />
73+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="XCBR" lnInst="1" doName="Pos" daName="q" fc="ST" />
74+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="LLN0" lnInst="" doName="Beh" daName="stVal" fc="ST" />
75+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="LLN0" doName="Beh" fc="ST" />
76+
</DataSet>
77+
<GSEControl name="gse2" />
78+
<GSEControl name="gse1" datSet="equalDataSet" />
79+
<SampledValueControl name="smv2" smpRate="80" nofASDU="1" >
80+
<SmvOpts />
81+
</SampledValueControl>
82+
<SampledValueControl name="smv1" datSet="equalDataSet" smpRate="80" nofASDU="1" >
83+
<SmvOpts />
84+
</SampledValueControl>
85+
<Log name="someOtherLog" />
86+
<Log name="someLog" />
87+
<Inputs>
88+
<ExtRef intAddr="Beh.t" pLN="LLN0" pDO="Beh" pDA="t" pServT="GOOSE" />
89+
</Inputs>
90+
</LN0>
91+
<LN lnClass="MMXU" inst="2" lnType="MMXU" />
92+
<LN prefix="Meas" lnClass="MMXU" inst="1" lnType="MMXU2" >
93+
<DataSet name="equalDataSet" >
94+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal" fc="ST" />
95+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="XCBR" lnInst="1" doName="Pos" daName="q" fc="ST" />
96+
<FCDA iedName="IED1" ldInst="lDevice" prefix="" lnClass="LLN0" lnInst="" doName="Beh" daName="stVal" fc="ST" />
97+
<FCDA iedName="IED1" ldInst="lDevice" lnClass="LLN0" doName="Beh" fc="ST" />
98+
</DataSet>
99+
<LogControl name="log" dataSet="equalDataSet" logName="logName" />
100+
<LogControl name="anotherLog" logName="logName" />
101+
<ReportControl name="anotherReport" />
102+
<ReportControl name="report" datSet="equalDataSet" />
103+
</LN>
104+
</LDevice>
105+
<LDevice inst="lDevice3" ldName="ldName" >
106+
<LN0 lnClass="LLN0" inst="" lnType="LLN0" >
107+
<DOI name="Beh" >
108+
<DAI name="stVal">
109+
<Val>test</Val>
110+
</DAI>
111+
</DOI>
112+
<Inputs>
113+
<ExtRef intAddr="A.phsA" pLN="MMXU" pDO="A.phsA" pDA="cVal.mag.f" pServT="SMV" />
114+
</Inputs>
115+
</LN0>
116+
<LN prefix="Meas" lnClass="MMXU" inst="1" lnType="MMXU" >
117+
<DOI name="A" >
118+
<SDI >
119+
<Val sGroup="1">10.10</Val>
120+
<Val sGroup="3">30.30</Val>
121+
<Val sGroup="2">20.20</Val>
122+
</SDI>
123+
</DOI>
124+
</LN>
125+
<AccessControl>Some AccessControl Own Namespace thingy!</AccessControl>
126+
</LDevice>
127+
<LDevice inst="lDevice4" >
128+
</LDevice>
129+
<LDevice inst="lDevice5" >
130+
<LN0 lnClass="LLN0" inst="" />
131+
</LDevice>
132+
<LDevice inst="lDevice6" >
133+
<LN0 lnClass="LLN0" inst="LLN0" />
134+
<LN lnClass="PTOC" inst="1" lnType="invalidPTOC" />
135+
</LDevice>
136+
<LDevice inst="lDevice7" >
137+
<LN0 lnClass="LLN0" inst="" lnType="LLN0" />
138+
<LN lnClass="MMXU" inst="1" lnType="MMXU" />
139+
<LN lnClass="MMXU" inst="2" lnType="MMXU" />
140+
<LN lnType="MMXU" />
141+
</LDevice>
142+
<LDevice inst="lDevice8" >
143+
<LN0 lnClass="LLN0" inst="" lnType="LLN0" />
144+
<LN lnClass="MMXU" inst="1" lnType="MMXU" />
145+
<LN lnClass="MMXU" inst="2" lnType="MMXU3" />
146+
<LN lnType="MMXU" />
147+
</LDevice>
148+
</Server>
149+
</AccessPoint>
150+
</IED>
151+
<DataTypeTemplates>
152+
<LNodeType id="invalidPTOC" desc="desc" lnType="lnType" />
153+
<LNodeType id="LLN0" desc="desc" lnClass="LLN0">
154+
<DO name="Beh" type="BehENS"/>
155+
</LNodeType>
156+
<LNodeType id="LLN02" desc="desc" lnClass="LLN0">
157+
<DO name="Beh" type="BehENS2"/>
158+
</LNodeType>
159+
<LNodeType id="diffLLN0" desc="desc" lnClass="LLN0">
160+
<DO name="Beh" type="diffBehENS"/>
161+
</LNodeType>
162+
<LNodeType id="MMXU" desc="desc" lnClass="MMXU">
163+
<DO name="A" type="WYE"/>
164+
</LNodeType>
165+
<LNodeType id="MMXU2" desc="desc" lnClass="MMXU">
166+
<DO name="A" type="WYE2"/>
167+
</LNodeType>
168+
<LNodeType id="diffMMXU" desc="desc" lnClass="MMXU">
169+
<DO name="A" type="diffWYE"/>
170+
</LNodeType>
171+
<DOType cdc="ENS" id="BehENS" >
172+
<DA name="stVal" bType="Enum" type="BehModKind" fc="ST" >
173+
<Val>off</Val>
174+
</DA>
175+
</DOType>
176+
<DOType cdc="ENS" id="BehENS2" >
177+
<DA name="stVal" bType="Enum" type="BehModKind" fc="ST" >
178+
<Val>on</Val>
179+
</DA>
180+
</DOType>
181+
<DOType id="diffBehENS" cdc="ENS" >
182+
<DA name="stVal" bType="Enum" type="BehModKind" fc="ST" >
183+
<Val>on</Val>
184+
</DA>
185+
<DA name="q" bType="Quality" fc="ST" />
186+
</DOType>
187+
<DOType id="WYE" cdc="WYE">
188+
<SDO name="phsA" type="CMV" />
189+
</DOType>
190+
<DOType id="WYE2" cdc="WYE">
191+
<SDO name="phsA" type="CMV2" />
192+
</DOType>
193+
<DOType id="diffWYE" cdc="WYE">
194+
<SDO name="phsA" type="diffCMV" />
195+
<SDO name="phsB" type="CMV" />
196+
</DOType>
197+
<DOType id="CMV" cdc="CMV" >
198+
<DA name="cVal" bType="Struct" fc="MX" type="Vector"/>
199+
</DOType>
200+
<DOType id="CMV2" cdc="CMV" >
201+
<DA name="cVal" bType="Struct" fc="MX" type="Vector2"/>
202+
</DOType>
203+
<DOType id="diffCMV" cdc="CMV" >
204+
<DA name="cVal" bType="Struct" fc="MX" type="diffVector"/>
205+
<DA name="q" bType="Quality" fc="MX" />
206+
</DOType>
207+
<DAType id="Vector" >
208+
<BDA name="mag" bType="Struct" type="AnalogueValue" />
209+
</DAType>
210+
<DAType id="Vector2" >
211+
<BDA name="mag" bType="Struct" type="AnalogueValue2" />
212+
</DAType>
213+
<DAType id="diffVector" >
214+
<BDA name="mag" bType="Struct" type="AnalogueValue" />
215+
<BDA name="ang" bType="Struct" type="AnalogueValue" />
216+
</DAType>
217+
<DAType id="AnalogueValue" >
218+
<BDA name="f" bType="FLOAT32" >
219+
<Val sGroup="3">60.60</Val>
220+
<Val sGroup="1">10.10</Val>
221+
<Val sGroup="2">40.10</Val>
222+
</BDA>
223+
</DAType>
224+
<DAType id="AnalogueValue2" >
225+
<BDA name="f" bType="FLOAT32" >
226+
<Val sGroup="3">30.30</Val>
227+
<Val sGroup="1">10.10</Val>
228+
<Val sGroup="2">20.20</Val>
229+
</BDA>
230+
</DAType>
231+
<EnumType id="BehModKind" >
232+
<EnumVal ord="1">on</EnumVal>
233+
<EnumVal ord="3">test</EnumVal>
234+
<EnumVal ord="5">off</EnumVal>
235+
</EnumType>
236+
<EnumType id="diffBehModKind" >
237+
<EnumVal ord="1">on</EnumVal>
238+
<EnumVal ord="3">test</EnumVal>
239+
</EnumType>
240+
</DataTypeTemplates>
241+
</SCL>`,
242+
"application/xml",
243+
);
244+
245+
/*
246+
const missingLnType = scl.querySelector('*[desc="missingLnType"]')!;
247+
const invalidLnType = scl.querySelector('*[desc="invalidLnType"]')!;
248+
const invalidLnTypeDescription = scl.querySelector(
249+
'*[desc="invalidLnTypeDescription"]'
250+
)!; */
251+
252+
const baseLDevice = scl.querySelector(`LDevice[inst="lDevice1"]`)!;
253+
const equalLDevice = scl.querySelector('LDevice[inst="lDevice2"]')!;
254+
const diffLDevice = scl.querySelector('LDevice[inst="lDevice3"]')!;
255+
const missingLLN0 = scl.querySelector('LDevice[inst="lDevice4"]')!;
256+
const missingLnType = scl.querySelector('LDevice[inst="lDevice5"]')!;
257+
const invalidLnType = scl.querySelector('LDevice[inst="lDevice6"]')!;
258+
const missingInst = scl.querySelector('LDevice[inst="lDevice7"]')!;
259+
const undefinedLN = scl.querySelector('LDevice[inst="lDevice8"]')!;
260+
261+
describe("Description for SCL schema type LDevice", () => {
262+
it("returns undefined with missing lnType attribute", () =>
263+
expect(LDevice(missingLLN0)).to.be.undefined);
264+
265+
it("returns undefined with missing lnType attribute", () =>
266+
expect(LDevice(missingLnType)).to.be.undefined);
267+
268+
it("returns undefined with invalid lnType attribute", () =>
269+
expect(LDevice(invalidLnType)).to.be.undefined);
270+
271+
it("returns undefined with missing lnType attribute", () =>
272+
expect(LDevice(missingInst)).to.be.undefined);
273+
274+
it("returns undefined with at least one undefined LNDescription", () =>
275+
expect(LDevice(undefinedLN)).to.be.undefined);
276+
277+
it("return ldName attribute if present", () =>
278+
expect(LDevice(diffLDevice)?.ldName).to.equal("ldName"));
279+
280+
it("return AccessControl child as a string if present", () =>
281+
expect(LDevice(diffLDevice)?.accessControl).to.equal(
282+
`<AccessControl xmlns="http://www.iec.ch/61850/2003/SCL">Some AccessControl Own Namespace thingy!</AccessControl>`,
283+
));
284+
285+
it("returns same description with semantically equal LDevice's", () =>
286+
expect(JSON.stringify(LDevice(baseLDevice))).to.equal(
287+
JSON.stringify(LDevice(equalLDevice)),
288+
));
289+
290+
it("returns different description with unequal LDevice elements", () =>
291+
expect(JSON.stringify(LDevice(baseLDevice))).to.not.equal(
292+
JSON.stringify(LDevice(diffLDevice)),
293+
));
294+
});

0 commit comments

Comments
 (0)