forked from openscd/open-scd
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(104/values): Added List of IEDs and 104-related DAI to values sc…
…reen.
- Loading branch information
Dennis Labordus
authored
May 19, 2022
1 parent
3364eab
commit adbc4a4
Showing
21 changed files
with
2,126 additions
and
226 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { | ||
css, | ||
html, | ||
LitElement, | ||
property, | ||
query, | ||
TemplateResult | ||
} from "lit-element"; | ||
import {translate} from "lit-translate"; | ||
|
||
import '@material/mwc-fab'; | ||
import '@material/mwc-radio'; | ||
import '@material/mwc-formfield'; | ||
|
||
import {RadioListItem} from "@material/mwc-list/mwc-radio-list-item"; | ||
|
||
import './protocol104/network-container.js' | ||
import './protocol104/values-container.js' | ||
|
||
import { | ||
newViewEvent, | ||
View, | ||
VIEW_EVENT_NAME, | ||
ViewEvent | ||
} from "./protocol104/foundation/foundation.js"; | ||
|
||
/** Defining view outside the class, which makes it persistent. */ | ||
let selectedViewProtocol104Plugin: View = View.VALUES; | ||
|
||
export default class Communication104Plugin extends LitElement { | ||
@property() | ||
doc!: XMLDocument; | ||
|
||
@query('#byValuesRadio') | ||
byValuesRadio!: RadioListItem; | ||
|
||
@query('#byNetworkRadio') | ||
byNetworkRadio!: RadioListItem; | ||
|
||
@query('div#containers') | ||
listDiv!: Element; | ||
|
||
constructor() { | ||
super(); | ||
|
||
this.addEventListener(VIEW_EVENT_NAME, (evt: ViewEvent) => { | ||
selectedViewProtocol104Plugin = evt.detail.view; | ||
this.requestUpdate(); | ||
}); | ||
} | ||
|
||
firstUpdated(): void { | ||
selectedViewProtocol104Plugin == View.VALUES | ||
? this.byValuesRadio.setAttribute('checked', '') | ||
: this.byNetworkRadio.setAttribute('checked', '') | ||
} | ||
|
||
render(): TemplateResult { | ||
return html ` | ||
<section> | ||
<div> | ||
<mwc-formfield label="${translate('protocol104.view.valuesView')}"> | ||
<mwc-radio | ||
id="byValuesRadio" | ||
name="view" | ||
value="values" | ||
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.VALUES))} | ||
></mwc-radio> | ||
</mwc-formfield> | ||
<mwc-formfield label="${translate('protocol104.view.networkView')}"> | ||
<mwc-radio | ||
id="byNetworkRadio" | ||
name="view" | ||
value="network" | ||
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.NETWORK))} | ||
></mwc-radio> | ||
</mwc-formfield> | ||
<div id="containers"> | ||
${selectedViewProtocol104Plugin == View.VALUES | ||
? html `<values-104-container .doc=${this.doc}></values-104-container>` | ||
: html `<network-104-container .doc=${this.doc}></network-104-container>` | ||
} | ||
</div> | ||
</div> | ||
</section>`; | ||
} | ||
|
||
static styles = css` | ||
:host { | ||
width: 100vw; | ||
} | ||
section { | ||
padding: 8px 12px 16px; | ||
} | ||
`; | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
getInstanceAttribute, | ||
getNameAttribute | ||
} from "../../../foundation.js"; | ||
|
||
export const PRIVATE_TYPE_104 = "IEC_60870_5_104"; | ||
|
||
/** | ||
* Retrieve the full path as wanted for the IED Container in the 104 Plugin, meaning we go higher in the | ||
* hierarchy until the parent found is the IED, this element is excluded, because the containers are group per | ||
* IED. | ||
* From all parent between the DAI and IED the name or likely attributes are used to define a unique name. | ||
* | ||
* @param daiElement - The DAI Element for which the full path needs to be defined. | ||
* @returns The full path shown to the user for a DAI Element. | ||
*/ | ||
export function getFullPath(daiElement: Element): string { | ||
let path = daiElement.getAttribute('name') ?? ''; | ||
let parent = daiElement.parentElement; | ||
|
||
while (parent && parent.tagName != 'IED') { | ||
let value: string | undefined; | ||
switch (parent.tagName) { | ||
case 'LN': | ||
case 'LN0': { | ||
const prefix = parent.getAttribute('prefix'); | ||
const inst = getInstanceAttribute(parent); | ||
value = `${prefix ? prefix + '-' : ''}${parent.getAttribute('lnClass')}${inst ? '-' + inst : ''}`; | ||
break; | ||
} | ||
case 'LDevice': { | ||
value = getNameAttribute(parent) ?? getInstanceAttribute(parent); | ||
break; | ||
} | ||
default: { | ||
// Just add the name to the list | ||
value = getNameAttribute(parent); | ||
} | ||
} | ||
path = (value ? value + ' / ' : '') + path; | ||
parent = parent.parentElement; | ||
} | ||
return path; | ||
} | ||
|
||
/** | ||
* Retrieve the CDC Value that belongs to a DAI Element, meaning, using the DOI/LN Elements to | ||
* search for a DO Element, which is again used to find the DO/DOType Element. The DOType Element | ||
* finally holds the attribute 'cdc'. | ||
* | ||
* @param daiElement - The DAI Element to start the search for the CDC Value. | ||
* @returns The CDC Value from the DOType Element. | ||
*/ | ||
export function getCdcValue(daiElement: Element): string | null { | ||
const lnElement = daiElement.closest('LN0, LN'); | ||
const doiElement = daiElement.closest('DOI'); | ||
if (lnElement && doiElement) { | ||
const lnType = lnElement.getAttribute('lnType'); | ||
const doName = doiElement.getAttribute('name'); | ||
|
||
const doElement = daiElement.ownerDocument.querySelector(`LNodeType[id="${lnType}"] > DO[name="${doName}"]`) | ||
if (doElement) { | ||
const doType = doElement.getAttribute('type'); | ||
const doTypeElement = daiElement.ownerDocument.querySelector(`DOType[id="${doType}"]`) | ||
return (doTypeElement ? doTypeElement.getAttribute('cdc') : null); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Enumeration stating the active view of the 104 plugin. | ||
*/ | ||
export enum View { | ||
VALUES, | ||
NETWORK | ||
} | ||
|
||
export const VIEW_EVENT_NAME = 'view-change-104-plugin'; | ||
|
||
// Objects needed to register and fire the change of a view within the Communication 104 Plugin | ||
export interface ViewDetail { | ||
view: View; | ||
} | ||
export type ViewEvent = CustomEvent<ViewDetail>; | ||
export function newViewEvent( | ||
view: View, | ||
): ViewEvent { | ||
return new CustomEvent<ViewDetail>(VIEW_EVENT_NAME, { | ||
bubbles: true, | ||
composed: true, | ||
detail: { view }, | ||
}); | ||
} | ||
|
||
declare global { | ||
interface ElementEventMap { | ||
[VIEW_EVENT_NAME]: ViewEvent; | ||
} | ||
} |
Oops, something went wrong.