Пример #1
0
 def __init__(self, _scl, TR):  ## Constructor for Server
     self.scl = _scl  ## Pointer to the SCL as provided by 'minidom'.
     self.TR = TR  ## Instance of the TRACE service.
     self.pLN = Parse_LN(
         TR
     )  ## Invoking the constructor of ParseLN, to initialize TRACE service.
     self.Dyn = DynImport()
Пример #2
0
 def __init__(self, _scl, _TR):
     self.scl = _scl  #
     self.TRX = _TR  #
     self.Dyn = DynImport(
     )  ## Create an instance of DynImpot for private TAG
Пример #3
0
class ParseCommunication:
    def __init__(self, _scl, _TR):
        self.scl = _scl  #
        self.TRX = _TR  #
        self.Dyn = DynImport(
        )  ## Create an instance of DynImpot for private TAG

    ##
    # \b ParseCommSection handle the SubNetwork section of the SCL
    #
    #  Parsing all the instance of SubNetwork
    # < Communication
    #    < SubNetwork
    #       <BitRate
    #       <ConnectedAP
    # ...
    # @param    pNetwork    pointer to 'SubNetwork' tag in the SCL
    def ParseCommSection(self, pNetWork):
        # Analyse d'un IED
        #
        #

        # ...
        tNetWork = []
        pSubNet = pNetWork[0].firstChild.nextSibling

        if pSubNet.localName != "SubNetwork":
            self.TRX.Trace(("Error: Tag SubNetwork not found"), TL.ERROR)

        while pSubNet:
            if pSubNet is None:
                break

            _name = pSubNet.getAttribute(
                "name"
            )  ##_name : A name identifying this bus; unique within this SCL file
            _type = pSubNet.getAttribute(
                "type"
            )  ## # @param _type : The SubNetwork protocol type; protocol types are defined by the SCSMs. In the
            ## examples, 8-MMS is used for the protocol defined in IEC 61850-8-1; IP should be used
            ## for all IP based protocols except those explicitly standardized. PHYSICAL should be
            ## used, if only physical connections shall be modeled, e.g. at a hub.

            _desc = pSubNet.getAttribute(
                "desc"
            )  ## @param _desc : Some descriptive text to this SubNetwork

            iSubNet = Comm.SubNetwork(_name, _type, _desc, 'text', 'bitrate',
                                      None)  # None: reservé for ConnectedAP
            self.TRX.Trace(("SubNetWork: name:" + _name + " type:" + _type +
                            " desc:" + _desc), TL.DETAIL)
            iSubNet = self.ParseSubNet(pSubNet, iSubNet)
            tNetWork.append(iSubNet)
            if pSubNet.firstChild is None:
                self.TRX.Trace(("Error: SubNet.firstChild is None"), TL.ERROR)
            if pSubNet.localName is None:
                pSubNet = pSubNet.nextSibling
                continue

            pSubNet = pSubNet.nextSibling
            if pSubNet is not None:
                pSubNet = pSubNet.nextSibling

        return (tNetWork)

    ##
    # \b ParseCommSection handle the SubNetwork section of the SCL
    #
    # Parse the subsequent TAG to 'subNetwork':
    #       <Text ...
    #       <BitRate ...
    #       <ConnectedAP ..
    #
    # @param    pSubNet    pointer to 'SubNetwork' tag in the SCL
    # @param    iSubNet    instance of SubNetwork class

    def ParseSubNet(self, pSubNet, iSubNet):
        pSubNet = pSubNet.firstChild

        tAP = []  # Tableau des accès point pour un 'subNetWork'.

        while pSubNet is not None:
            if pSubNet is not None:
                pSubNet = pSubNet.nextSibling

            if pSubNet is None:
                break
            if pSubNet.localName is None:
                continue

            if pSubNet.localName == 'Private':
                self.TRX.Trace(("Private in SubNetworkSubNetwork"), TL.ERROR)
                self.Dyn.PrivateDynImport(type, pSubNet, iSubNet)
                continue

            if pSubNet.localName == "Text":
                if pSubNet.firstChild is not None:
                    localText = pSubNet.firstChild.data
                else:
                    localText = "pas de texte !"
                self.TRX.Trace(("SubNetWork" + localText), TL.GENERAL)
                iSubNet.text = localText

            if pSubNet.localName == "BitRate":
                Unit = pSubNet.getAttribute("unit")
                Value = pSubNet.firstChild.data
                _BitRate = Comm.SubNetwork.BitRate(Unit, Value)
                iSubNet.bitRate = _BitRate
                self.TRX.Trace(
                    ("BitRate:     Unit:" + Unit + "Value:" + Value),
                    TL.DETAIL)

            if pSubNet.localName == "ConnectedAP":  # def __init__(self,_iedName,_apName,_desc,_Address,_SMV,_PhysConn):
                pAP = pSubNet
                _iedName = pAP.getAttribute("iedName")
                _apName = pAP.getAttribute("apName")
                _desc = pAP.getAttribute("desc")
                _redProt = pAP.getAttribute("redProt")
                self.TRX.Trace(("        ConnectedAP: iedName:" + _iedName +
                                " apName:" + _apName + " desc: " + _desc),
                               TL.DETAIL)
                iCnxAP = Comm.SubNetwork.ConnectedAP(_iedName, _apName, _desc,
                                                     _redProt)
                iCnxAP = self.ParseConnectedAP(pAP, iCnxAP, self.TRX)
                tAP.append(iCnxAP)
                continue

        iSubNet.tConnectedAP = tAP
        return iSubNet

    def ParseConnectedAP(self, SubNet, CnxAP, TRX):
        # Partie Address de connected pAP.
        #            <Address >
        #               < P  type = "IP-SUBNET" > 255.255.255.0 < / P >
        #               ...
        #               < P  type = "OSI-SSEL" > 01 < / P >
        #            </ Address >
        tAddress = []
        if SubNet.firstChild is None:  # cas de: <ConnectedAP iedName="L2_MU_SCU_VIZ_MGU" apName="ETH_2" />
            return CnxAP
        pAP = SubNet.firstChild.nextSibling  # CnxAP
        tGSE = []
        tSMV = []
        while pAP:  # Pour tout les "ConnectedAP"...
            if pAP.localName is None:
                pAP = pAP.nextSibling
                if pAP is None:
                    break
                continue
            if pAP.localName == "Private":
                self.TRX.Trace(("Private in SubNetworkSubNetwork"), TL.ERROR)
                self.Dyn.PrivateDynImport(type, pAP, CnxAP)
                pAP = pAP.nextSibling
                continue

            if pAP.localName == "Address":
                tAddress = self.ParseAddress(pAP.firstChild.nextSibling,
                                             "Address")  #<Adress>
                #                tAddress.append(iAddress)
                CnxAP.tAddress = tAddress

            if pAP.localName == "PhysConn":
                _type = pAP.getAttribute("type")
                iPhysConn = Comm.SubNetwork.ConnectedAP.PhysConn(_type, None)
                iPhysConn.tPhysAddress = self.ParseAddress(
                    pAP.firstChild.nextSibling, "PhysConn")
                CnxAP.PhysConn.append(iPhysConn)

            if pAP.localName == "SMV":  # <SMV ldInst="MU01" cbName="MSVCB01" desc="bla...bla>
                _ldInst = pAP.getAttribute("ldInst")  #   <Address> ....
                _cbName = pAP.getAttribute("cbName")
                _desc = pAP.getAttribute("desc")
                iSMV = Comm.SubNetwork.ConnectedAP.SMV(_ldInst, _cbName, _desc)
                #                self.TRX.Trace(("     SMV:         ldInst:"+_ldInst+" cbName:"+_cbName+" desc:"+_desc),TL.DETAIL)

                iAddressSMV = pAP.firstChild.nextSibling  #	<Address>
                if (iAddressSMV.localName == "Address"
                    ):  #		<P type="MAC-Address">01-0C-CD-04-00-00</P>
                    iAddressSMV = self.ParseAddress(
                        iAddressSMV.firstChild.nextSibling,
                        "SMV Address:")  #		...
                    iSMV.tSMVAddress = iAddressSMV  #		<P type="VLAN-PRIORITY">4</P>
                    #                tSMV.append(iSMV)                       #	</Address>
                    CnxAP.tSMV.append(iSMV)

            if pAP.localName == "GSE":  #<GSE ldInst="PIGO" cbName="GoCB1">
                _ldInst = pAP.getAttribute("ldInst")  #   <Address>
                _cbName = pAP.getAttribute(
                    "cbName"
                )  #     <P type="MAC-Address">01-01-19-01-11-01</P>
                _desc = pAP.getAttribute(
                    "desc")  #     <P type="VLAN-ID">00B</P>
                iGSE = Comm.SubNetwork.ConnectedAP.GSE(
                    _ldInst, _cbName, _desc)  #     <P type="APPID">1911</P>
                #                self.TRX.Trace(("     GSE: ldInst:" + _ldInst + " cbName:" + _cbName + " desc:" + _desc), TL.DETAIL)

                pGSE = pAP.firstChild.nextSibling  #     <P type="VLAN-PRIORITY">4</P>
                while pGSE is not None:
                    if pAP.localName == "Private":
                        self.TRX.Trace(("Private in GSE"), TL.ERROR)
                        self.Dyn.PrivateDynImport(type, pGSE, iGSE)
                        pAP = pAP.nextSibling
                        continue
                    if (pGSE.localName == "Address"):  #    </Address>
                        _Adr = self.ParseAddress(pGSE.firstChild.nextSibling,
                                                 "GSE Address:")
                        iGSE.tGSEAddress = _Adr
                        pGSE = pGSE.nextSibling
                    if (
                            pGSE.localName == "MinTime"
                    ):  # <MinTime unit="s" multiplier="m">2</MinTime></GSE>
                        _unit = pGSE.getAttribute("unit")
                        _multiplier = pGSE.getAttribute("multiplier")
                        _MinTime = pGSE.firstChild.nodeValue
                        minTime = Comm.SubNetwork.ConnectedAP.GSE.MinTime(
                            _unit, _multiplier, _MinTime)
                        iGSE.minTime = minTime
                        self.TRX.Trace(
                            ("     GSE: MinTime.unit:" + _unit + " multi:" +
                             _multiplier + " MinTime=" + _MinTime), TL.DETAIL)
                        pGSE = pGSE.nextSibling
                    if (pGSE.localName == "MaxTime"
                        ):  # <MaxTime unit="s" multiplier="m">5000</MaxTime>
                        _unit = pGSE.getAttribute("unit")
                        _multiplier = pGSE.getAttribute("multiplier")
                        _MaxTime = pGSE.firstChild.nodeValue
                        maxTime = Comm.SubNetwork.ConnectedAP.GSE.MaxTime(
                            _unit, _multiplier, _MaxTime)
                        iGSE.maxTime = maxTime
                        self.TRX.Trace(
                            ("     GSE: MaxTime.unit:" + _unit + " multi:" +
                             _multiplier + " MaxTime=" + _MaxTime), TL.DETAIL)
                        pGSE = pGSE.nextSibling
                    pGSE = pGSE.nextSibling
                    CnxAP.tGSE.append(iGSE)
            pAP = pAP.nextSibling
            continue
        return CnxAP

    ##
    # \b ParseAddress handle the Address section of the SCL
    #
    # @description
    #
    # Parse the list <P Type ... from the SCL
    #       <Text ...
    #       <BitRate ...
    #       <ConnectedAP ..
    #
    # Nota: the validity of the 'P Type' is not checked.
    #
    # @param    pAP    pointer to 'SubNetwork' tag in the SCL
    # @param    Titre   instance of SubNetwork class
    def ParseAddress(self, pAP, Titre):
        self.TRX.Trace(("     " + Titre + ":"), TL.DETAIL)  #
        tAdress = []
        pAdr = pAP  # Adresse IP Connected AP
        while pAdr.nextSibling:  # <Address>
            if pAdr.localName is None:  #   <P type="OSI-AP-Title">1,3,9999,23</P>
                pAdr = pAdr.nextSibling  #   <P type="OSI-AE-Qualifier">23</P>
                continue  #   <P type="OSI-PSEL">00000001</P>
            type = pAdr.getAttribute("type")  # <P type="OSI-SSEL">0001</P>
            value = pAdr.firstChild.data  # <P type="OSI-TSEL">0001</P>
            self.TRX.Trace(("         " + type + "='" + value + "'"),
                           TL.DETAIL)  # </Address>
            iPtype = Comm.SubNetwork.ConnectedAP.PhysConn.PType(type, value)

            tAdress.append(iPtype)
            pAdr = pAdr.nextSibling
            continue
        return (tAdress)
Пример #4
0
 def __init__(self, _TR):
     self.TRX = _TR  ## Instance of the TRACE service.
     self.Dyn = DynImport(
     )  ## Create an instance of DynImpot for private TAG
Пример #5
0
class Parse_LN:
    ##
    # __init__(self , _TR)
    #
    # Constructor for LN parsing, initialieze the DynImport class
    #
    # @param _TR    Trace system

    def __init__(self, _TR):
        self.TRX = _TR  ## Instance of the TRACE service.
        self.Dyn = DynImport(
        )  ## Create an instance of DynImpot for private TAG

    ##
    # \b Parse_LN:
    #
    # Main function of this class
    #
    # The function hierarchy is as follow
    #
    # Parse_LN
    #   - private:   <private>  .... </Private>
    #       - Dyn.Import (from IEC_PrivateSupport)
    #   - inputs:
    #           - invoke the method Parse_ExtRef() from this class
    #   - DOI:
    #       - invoke the methode Parse_DOI() from this class
    #           - ParseDAI_VAL() invoked by Parse_DOI()
    #           - Parse_SDI() invoked by Parse_DOI()
    #   - Log (not parsed)             \b #TODO not supported
    #   - SettingControl (not parsed)  \b #TODO not supported
    #   - GSEControl (local to this method)
    #   - LogControl (local to this method)
    #   - SampledValueControl (local to this method)
    #   - DataSet:
    #        - invoke the method Parse_DataSet() from this class
    #   - ReportControl:
    #        - invoke the method Parse_ReportControl() from this class
    #
    # @param pLN        : is the result of scl.getElementsByTagName("DataTypeTemplates")
    # @param IEDname    : Use to create the full IEC oath to the data
    # @param AP_Name    : Use to create the full IEC oath to the data
    # @param tDAI       : table of DAi
    #
    # @return iLN       : The logical node with all its sub-classes.

    def Parse_LN(self, pLN, IEDname, AP_Name, tDAI):
        #
        # LN contains DataSet, ReportControl, GooseControl and DOI/SDI.../SDI/DAI sections (up to 3 levels of SDI
        #
        _lnPrefix = pLN.getAttribute(
            "prefix")  ## The LN prefix part (none for LN0)
        _lnClass = pLN.getAttribute(
            "lnClass"
        )  ## The LN class according to IEC 61850-7-x or other domain specific standards (LLN0 for LN0)
        _inst = pLN.getAttribute(
            "inst"
        )  ## The LN instance number identifying this LN – an unsigned integer; leading zeros are
        ## not recommended, as they formally lead to another instance identification (Not presnet for LN0)
        _lnType = pLN.getAttribute(
            "lnType"
        )  ## The instantiable type definition of this logical node, reference to a LNodeType definition
        _desc = pLN.getAttribute(
            "desc")  ## The description text for the logical node

        iLN = IED.AccessPoint.Server.LN(_lnPrefix, _lnType, _inst, _lnClass,
                                        _desc)

        if pLN.firstChild is not None:  # pLN is used to browse the XML tree
            pLN = pLN.firstChild.nextSibling  #
        else:
            return iLN  # LN0 is empty, usually the case for ICD IID file

        tiRCB = []  # Tableau des instances des RCB du LN0
        tiSVC = []  # Tableau des instances des SVC du LN0
        tiGCB = []  # Tableau des instances des GCB du LN0
        tiLCB = []  # Tableau des instances des LCB du LN0
        tExtRef = []  # Tableau des ExtRef (Inputs)
        tDS = [
        ]  # Tableau des instances des DatatSet du LN0 (l'objet DA contient la liste des FCDA)

        while pLN:
            if pLN.localName is None:
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "Private":
                type = pLN.getAttribute("type")
                self.Dyn.PrivateDynImport(type, pLN,
                                          iLN)  # Dynamic import for private
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "Inputs":  # < Inputs >
                #  < ExtRef doName = "SPCSO3" daName = "q" serviceType = "GOOSE"...
                self.TRX.Trace(("      *** Inputs"), TL.DETAIL)
                iLN.tInputs = self.Parse_ExtRef(pLN)
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "DOI":  ### DOI et DAI à TRAITER DANS LE DATA MODEL.
                self.TRX.Trace(("      *** DOI"), TL.DETAIL)
                LN_id = iLN.lnPrefix + iLN.lnClass + iLN.lnInst
                DoName = IEDname + AP_Name + '/' + LN_id  # Use for collecting DAI
                iDOI, iLN = self.Parse_DOI(iLN, pLN, DoName)

                pLN = pLN.nextSibling
                continue

            # TODO ???gérer les balises Log, et SettingControl? .

            if pLN.localName == "Log":  # Non utilisé dans R#Space
                self.TRX.Trace(("      Log: NON TRAITE"), TL.ERROR)
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "LogControl":  # Non utilisé dans R#Space
                self.TRX.Trace(("      LogControl"), TL.DETAIL)
                tiLCB = self.Parse_LogControl(pLN, tiLCB)
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "SettingControl":  # Non utilisé dans R#Space
                self.TRX.Trace(
                    ("      SettingControl: NON TRAITE"),
                    TL.ERROR)  ## TODO handle the SettingControl class
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "GSEControl":
                self.TRX.Trace(("      GSEControl"), TL.DETAIL)
                _name = pLN.getAttribute(
                    "name")  ## The name identifying this GOOSE control block
                _desc = pLN.getAttribute("desc")  ## A description text
                _datSet = pLN.getAttribute(
                    "datSet"
                )  ## The name of the data set to be sent by the GSE control block.
                _confRev = pLN.getAttribute(
                    "confRev"
                )  ## The configuration revision number of this control block.
                _type = pLN.getAttribute(
                    "type"
                )  ## The default type value is GOOSE (GSSE is deprecated)
                _appID = pLN.getAttribute(
                    "appID"
                )  ## A system wide unique identification of the application to which the GOOSE message belong
                _fixedOffs = pLN.getAttribute(
                    "fixedOffs"
                )  ## Default value false. If set to true it shows all receivers, that the values GOOSE message have fixed offset.
                _securityEnabled = pLN.getAttribute(
                    "securityEnabled"
                )  ## Default: None. Allows to configure the security options per control block instance.
                GOOSE = IED.AccessPoint.Server.LN.GSEControl(
                    _name, _desc, _datSet, _confRev, _type, _appID, _fixedOffs,
                    _securityEnabled)
                # TODO LISTE DES IEDs à accrocjer GSECONTROL

                tiGCB.append(GOOSE)
                self.TRX.Trace(
                    ("     GSEControl, name: " + _name + " datSet:" + _datSet),
                    TL.DETAIL)
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "SampledValueControl":
                self.TRX.Trace(("      SampledValueControl"), TL.DETAIL)
                _name = pLN.getAttribute(
                    "name"
                )  ## name	        A name identifying this SMV control block
                _desc = pLN.getAttribute(
                    "desc")  ## desc	        The description text
                _datSet = pLN.getAttribute(
                    "datSet"
                )  ## datSet       The name of the data set whose values shall be sent.
                _confRev = pLN.getAttribute(
                    "confRev"
                )  ## confRev	    The configuration revision number of this control block; mandatory.
                _smvID = pLN.getAttribute(
                    "smvID"
                )  ## smvID	    Multicast CB: the MsvID for the sampled value definition as defined (Unicast: deprecated)
                _multicast = pLN.getAttribute(
                    "multicast"
                )  ## multicast    Indicates Unicast SMV services only meaning that smvID = UsvI
                _smpRate = pLN.getAttribute(
                    "smpRate"
                )  ## smpRate	    Sample rate as defined in IEC 61850-7-2. If no smpMod is defined, i
                _nofASDU = pLN.getAttribute(
                    "nofASDU"
                )  ## nofASDU	    Number of ASDU (Application service data unit) – see IEC 61850-9-2
                _smpMod = pLN.getAttribute(
                    "smpMod"
                )  ## smpMod	    The sampling mode as defined in IEC 61850-7-2; default: SmpPerPeriod; i
                _securityEnabled = pLN.getAttribute(
                    "securityEnabled"
                )  ## securityEnabled Default: None. Allows to configure the security options per control block instance

                SVC = IED.AccessPoint.Server.LN.SampledValueControl(
                    _name, _desc, _datSet, _confRev, _smvID, _multicast,
                    _smpRate, _nofASDU, _smpMod, _securityEnabled)
                tiSVC.append(SVC)
                self.TRX.Trace(("     SampledValueControl, name:" + _name +
                                " smvID:" + _smvID + " datSet:" + _datSet),
                               TL.DETAIL)

                #TODO Parse smvOptions
                ##
                # \b smvOption
                #
                #  param refreshTime       The meaning of the options is described in IEC 61850-7-2.
                #  param sampleRate        If any of the attributes is set to true, the appropriate values shall be included into the SMV telegram
                #  param dataSet           If the attribute is set to true, the dataset name shall be included into the SMV telegram
                #  param security          See IEC61850-9-2...
                #  param synchSourceId     if true, the SV message contains the identity of the synchronizing master clock according to IEC 61850-9-3; default = false

                pLN = pLN.nextSibling
                continue

            # Extraction of data Set:
            #   <DataSet name = "DS_TAXD" desc = "Data Set..." >
            #       <FCDA  ldInst = "LD_all" prefix = "" lnInst = "1" lnClass = "TAXD" doName = "EEName"   fc = "DC" />
            #       <FCDA  ldInst = "LD_all" prefix = "" lnInst = "1" lnClass = "TAXD" doName = "EEHealth" fc = "ST" />
            #       <FCDA  ldInst = "LD_all" prefix = "" lnInst = "1" lnClass = "TAXD" doName = "AxDspSv"  fc = "MX" / >
            #       <FCDA  ldInst = "LD_all" prefix = "" lnInst = "1" lnClass = "TAXD" doName = "SmpRte"   fc = "SP" />
            #   </DataSet >

            if pLN.localName == "DataSet":
                _name = pLN.getAttribute("name")  ##
                _desc = pLN.getAttribute("desc")  ##
                self.TRX.Trace(
                    ("     DataSet, dsName:" + _name + " desc:" + _desc),
                    TL.DETAIL)
                DS = IED.AccessPoint.Server.LN.DataSet(
                    _name, _desc)  # "" Tableau des  FCDA
                DS = self.Parse_DataSet(pLN, DS)
                tDS.append(DS)
                pLN = pLN.nextSibling
                continue

            if pLN.localName == "ReportControl":
                self.TRX.Trace(("      ReportControl"), TL.DETAIL)
                iRCB = self.Parse_ReportControl(pLN)
                tiRCB.append(iRCB)
                pLN = pLN.nextSibling
                continue
            continue
        iLN.tSVCtrl = tiSVC
        iLN.tDataSet = tDS
        iLN.tGSECtrl = tiGCB
        iLN.tRptCtrl = tiRCB
        iLN.tLogCtrl = tiLCB
        return iLN

    ##
    # \b Parse_DataSet:
    #
    # Parsing the dataset and its list of FCDA
    #
    # @param    pLN : pointer to SCL DataSet section
    # @param    DS  : DataSet object, the tFCDA table is used to collect the list of  FCDA for the DataSet
    #
    # @return  DS: table of FCDA

    def Parse_DataSet(self, pLN, DS):

        FCDAi = pLN.firstChild
        while FCDAi:
            if FCDAi.localName is None:
                FCDAi = FCDAi.nextSibling
                continue
            _ldInst = FCDAi.getAttribute(
                "ldInst")  ## The LD where the DO resides
            _prefix = FCDAi.getAttribute(
                "prefix"
            )  ## Prefix identifying together with lnInst and lnClass the LN where the DO resides
            _lnClass = FCDAi.getAttribute(
                "lnClass")  ##  LN class of the LN where the DO resides;
            _lnInst = FCDAi.getAttribute(
                "lnInst")  ## Instance number of the LN where the DO resides
            _doName = FCDAi.getAttribute(
                "doName"
            )  ## A name identifying the DO (within the LN). A name standardized in IEC 61850-7-4.
            _daName = FCDAi.getAttribute(
                "daName"
            )  ## The attribute name – if missing, all attributes with functional characteristic given by fc are selected
            _cf = FCDAi.getAttribute(
                "fc"
            )  ## All attributes of this functional constraint are selected. See IEC 61850-7-2 or the fc definition in 9.5
            _ix = FCDAi.getAttribute(
                "ix"
            )  ## An index to select an array element in case that one of the data elements is an array.
            iFCDA = IED.AccessPoint.Server.LN.DataSet.FCDA(
                _ldInst, _prefix, _lnClass, _lnInst, _doName, _daName, _cf,
                _ix)
            DS.tFCDA.append(iFCDA)
            FCDAi = FCDAi.nextSibling

        return DS

    ##
    # \b Parse_ReportControl
    #
    # Parsing the Report Control structures: RCB, TrgOps, RptEnabled
    #
    # @param    pLN : pointer to SCL ReportControl section
    #
    # @return  DS: table of FCDA

    def Parse_ReportControl(self, pLN):

        _name = pLN.getAttribute(
            "name")  ##  name	    Name of the report control block.
        _desc = pLN.getAttribute("desc")  ##  desc	    The description text
        _rptID = pLN.getAttribute(
            "rptID"
        )  ##  datSet	    The name of the data set to be sent by the report control block
        _datSet = pLN.getAttribute(
            "datSet"
        )  ##  intgPd	    Integrity period in milliseconds – see IEC 61850-7-2. Only relev
        _intgPd = pLN.getAttribute(
            "intgPD"
        )  ##  rptID	    Identifier for the report control block, optional.
        _confRev = pLN.getAttribute(
            "confRev"
        )  ##  confRev	    The configuration revision number of this report control block.
        _buffered = pLN.getAttribute(
            "buffered"
        )  ##  buffered	Specifies if reports are buffered or not – see IEC 61850-7-2; de
        _bufTime = pLN.getAttribute(
            "bufTime"
        )  ##  bufTime	    Buffer time – see IEC 61850-7-2; default: 0
        _indexed = pLN.getAttribute(
            "indexed"
        )  ##  indexed	    If true, the report control block instance names are built from supplied name, followed by an index number from 01 up to maximum 99.

        #    _Opt      = LN.getAttribute("optFields")
        iRCB = IED.AccessPoint.Server.LN.ReportControl(_name, _desc, _datSet,
                                                       _intgPd, _rptID,
                                                       _confRev, _buffered,
                                                       _bufTime, _indexed)
        self.TRX.Trace(("ReportControl: " + _rptID + " name:" + _name +
                        " datSet" + _datSet), TL.DETAIL)
        # Récupération des attribues des sous-sections: TrgOps, OptFields et RptEnabled
        rptCtrl = pLN.firstChild
        while rptCtrl:
            if rptCtrl.localName is None:
                rptCtrl = rptCtrl.nextSibling
                continue
            if rptCtrl.localName == "Private":
                rptCtrl = rptCtrl.nextSibling
                continue
            if rptCtrl.localName == "TrgOps":
                self.TRX.Trace(("ReportControl: TrgOps"), TL.DETAIL)
                _qchg = rptCtrl.getAttribute("qchg")
                _dchg = rptCtrl.getAttribute("dchg")
                _dupd = rptCtrl.getAttribute("dupd")
                _period = rptCtrl.getAttribute("period")
                _gi = rptCtrl.getAttribute("gi")
                iRCB.TrgOps = IED.AccessPoint.Server.LN.TrgOps(
                    _qchg, _dchg, _dupd, _period, _gi)

                rptCtrl = rptCtrl.nextSibling
                continue

            if rptCtrl.localName == "OptFields":
                _seqNum = rptCtrl.getAttribute("seqNum")
                _timeStamp = rptCtrl.getAttribute("timeStamp")
                _reasonCode = rptCtrl.getAttribute("reasonCode")
                _dataSet = rptCtrl.getAttribute("dataSet")
                _dataRef = rptCtrl.getAttribute("dataRef")
                _entryID = rptCtrl.getAttribute("entryID")
                _configRef = rptCtrl.getAttribute("configRef")
                _bufOvfl = rptCtrl.getAttribute("bufOvfl")
                iRCB.OptField = IED.AccessPoint.Server.LN.ReportControl.OptFields(
                    _seqNum, _timeStamp, _reasonCode, _dataSet, _dataRef,
                    _entryID, _configRef, _bufOvfl)
                rptCtrl = rptCtrl.nextSibling
                continue

            if rptCtrl.localName == "RptEnabled":
                self.TRX.Trace(("ReportControl: RptEnabled"), TL.DETAIL)
                _max = rptCtrl.getAttribute("max")
                iRCB.RptEnable = IED.AccessPoint.Server.LN.ReportControl.RptEnabled(
                    _max)

                pClientLN = rptCtrl.firstChild
                if pClientLN is not None:
                    pClientLN = pClientLN.nextSibling

                    while pClientLN is not None:
                        if pClientLN.localName == "ClientLN":
                            self.TRX.Trace(("ReportControl: ClientLN"),
                                           TL.DETAIL)
                            #iedName, _ldInst, _lnPrefix, _lnClass, _lnInst, _desc, _apRef):
                            _iedName = pClientLN.getAttribute(
                                "iedName"
                            )  ## The name of the IED where the LN resides
                            _ldInst = pClientLN.getAttribute(
                                "ldInst"
                            )  ## The instance identification of the LD where the LN resides
                            _prefix = pClientLN.getAttribute(
                                "prefix")  ## The LN prefix
                            _lnClass = pClientLN.getAttribute(
                                "lnClass"
                            )  ## The LN class according to IEC 61850-7-4
                            _lnInst = pClientLN.getAttribute(
                                "lnInst"
                            )  ## The instance id of this LN instance of below LN class in the IED
                            _desc = pClientLN.getAttribute(
                                "desc"
                            )  ## optional descriptive text, e.g. about purpose of the client
                            _apRef = pClientLN.getAttribute(
                                "apRef")  ## Application reference

                            iClientLN = IED.AccessPoint.Server.LN.ReportControl.RptEnabled.ClientLN(
                                _iedName, _ldInst, _prefix, _lnClass, _lnInst,
                                _desc, _apRef)
                            iRCB.RptEnable.tClientLN.append(iClientLN)
                        pClientLN = pClientLN.nextSibling
                        continue

                rptCtrl = rptCtrl.nextSibling
                continue
        return iRCB

    ##
    # \b Parse_LogControl
    #
    # Parsing the LogControl section
    # @param   pLN   : pointer to SCL ReportControl section
    # @param   tiLCB : Table of instance of Log Control Block (empty)
    #
    # @return  tiLCB : Table of instance of Log Control Block completed

    def Parse_LogControl(self, pLN, tiLCB):
        _name = pLN.getAttribute(
            "name")  ## name the name of the log control block
        _desc = pLN.getAttribute("desc")  ## A description text
        _datSet = pLN.getAttribute(
            "datSet"
        )  ## The name of the data set whose values shall be logged; datSet should only be
        _intgPd = pLN.getAttribute(
            "intgPd"
        )  ## Integrity scan period in milliseconds – see IEC 61850-7-2.
        _ldInst = pLN.getAttribute(
            "ldInst"
        )  ## The identification of the LD where the log resides; if missing, the same LD
        _prefix = pLN.getAttribute(
            "prefix"
        )  ## Prefix of LN where the log resides; if missing, empty string
        _lnClass = pLN.getAttribute(
            "lnClass"
        )  ## Class of the LN where the log resides; if missing, LLN0
        _lnInst = pLN.getAttribute(
            "lnInst"
        )  ## Instance number of LN, where the log resides; missing for LLN0
        _logName = pLN.getAttribute(
            "logName"
        )  ## Relative name of the log within its hosting LN; name of the log element
        _logEna = pLN.getAttribute(
            "logEna"
        )  ## TRUE enables immediate logging; FALSE prohibits logging until enabled online
        _reasonCode = pLN.getAttribute(
            "reasonCode"
        )  ## If true, the reason code for the event trigger is also stored into the log –

        iLogControl = IED.AccessPoint.Server.LN.LogControl(
            _name, _desc, _datSet, _intgPd, _ldInst, _prefix, _lnClass,
            _lnInst, _logName, _logEna, _reasonCode)

        self.TRX.Trace(("      LogControl: name:" + _name + " datSet: " +
                        _datSet + " logName:" + _logName), TL.DETAIL)
        logCtrl = pLN.firstChild
        while logCtrl:
            if logCtrl.localName is None:
                logCtrl = logCtrl.nextSibling
                continue
            if logCtrl.localName == "Private":
                self.TRX.Trace(("      LogControl: Private"), TL.DETAIL)
                logCtrl = logCtrl.nextSibling
                continue
            if logCtrl.localName == "TrgOps":
                self.TRX.Trace(("      LogControl: TrgOps"), TL.DETAIL)
                _qchg = logCtrl.getAttribute("qchg")
                _dchg = logCtrl.getAttribute("dchg")
                _dupd = logCtrl.getAttribute("dupd")
                _period = logCtrl.getAttribute("period")
                _gi = logCtrl.getAttribute("gi")

                iTrgOps = IED.AccessPoint.Server.LN.TrgOps(
                    _qchg, _dchg, _dupd, _period, _gi)
                self.TRX.Trace(("        TrgOps qchg" + _qchg + " dchg:" + _dchg + " dupd:" + _dupd + \
                                " period+" + _period + "_gi" + _gi), TL.DETAIL)
                iLogControl.TrgOps = iTrgOps
                logCtrl = logCtrl.nextSibling
                continue
        tiLCB.append(iLogControl)
        return tiLCB

    ##
    # \b Parse_ExtRef
    #
    # Parse the tInputs sections of a LN0 declaration
    #
    # Features:
    #   - Create instance of an 'ExtRef' object by getting the attributes froml the SCL IED defined without any Server part.
    #   - Dynamically calling Private support class/method if a private is encountered.
    #
    # @return  tInputs: the table of ExtRef objects
    def Parse_ExtRef(self, pLN):
        _tInputs = IED.AccessPoint.Server.LN.Inputs([])

        pExtRef = pLN.firstChild.nextSibling
        while pExtRef:
            if pExtRef.localName is None:
                pExtRef = pExtRef.nextSibling
                continue
            if pExtRef.localName == 'Private':
                type = pExtRef.getAttribute("type")
                self.Dyn.PrivateDynImport(type, pExtRef,
                                          IED.AccessPoint.Server.LN.Inputs)

            if pExtRef.localName == 'ExtRef':
                _iedName = pExtRef.getAttribute("iedName")
                _ldInst = pExtRef.getAttribute("ldInst")
                _prefix = pExtRef.getAttribute("prefix")
                _lnClass = pExtRef.getAttribute("lnClass")
                _lnInst = pExtRef.getAttribute("lnInst")

                _doName = pExtRef.getAttribute("doName")
                _daName = pExtRef.getAttribute("daName")
                _intAddr = pExtRef.getAttribute("intAddr")

                _desc = pExtRef.getAttribute("desc")

                _serviceType = pExtRef.getAttribute("serviceType")

                _srcLDInst = pExtRef.getAttribute("srcLDInst")
                _srcPrefix = pExtRef.getAttribute("srcPrefix")
                _srcLNClass = pExtRef.getAttribute("srcLNClass")
                _srcLNInst = pExtRef.getAttribute("srcLNInst")
                _srcCBName = pExtRef.getAttribute("srcCBName")

                _pServT = pExtRef.getAttribute("pServT")
                _pLN = pExtRef.getAttribute("pLN")
                _pDO = pExtRef.getAttribute("pDO")
                _pDA = pExtRef.getAttribute("pDA")

                iExtRef = IED.AccessPoint.Server.LN.Inputs.ExtRef(
                    _iedName, _ldInst, _prefix, _lnClass, _lnInst, _doName,
                    _daName, _intAddr, _desc, _serviceType, _srcLDInst,
                    _srcPrefix, _srcLNClass, _srcLNInst, _srcCBName, _pDO,
                    _pLN, _pDA, _pServT)

                _tInputs.tExtRef.append(iExtRef)

            pExtRef = pExtRef.nextSibling
        return _tInputs

    ##
    # \b Parse_DOI
    #
    # Features:
    #   - Create instance of an 'DAI' and collected sub-sequent value
    #
    # The code of Parse_SDI(pDAI1, iDOI, n, TRX)is used to collect the
    # value of DO/DA looking like this:
    #         <DAI name="SIUnit" valKind="RO">
    #==>        <Val>cos(phi)</Val>           <===
    #          </DAI>
    #
    # @return  pDAI    new value of the pointer to SCL
    # @return  _value   _value found (or None)
    # @return  iDOI     modified instance DOI.

    def Parse_DOI(self, iLN, pDOI,
                  DoName):  # Instance of LN  & DOI is scl pointto DOI tag
        _name = pDOI.getAttribute(
            "name")  ## The name identifying this GOOSE control block
        _desc = pDOI.getAttribute("desc")  ## A description text
        _ix = pDOI.getAttribute(
            "ix"
        )  ## The name of the data set to be sent by the GSE control block.
        _accessControl = pDOI.getAttribute(
            "accessControl"
        )  ## The configuration revision number of this control block.
        self.TRX.Trace(("DOI: name:" + _name + " desc:" + _desc), TL.DETAIL)
        iDOI = IED.AccessPoint.Server.LN.DOI(
            _desc, _name, _ix,
            _accessControl)  #, None, None, None)  # None for RTE private Type
        setattr(iLN, iDOI.name, iDOI)
        pDAI = pDOI.firstChild  # Pointeur DAI ou SDI

        while pDAI:  # USE CASE:
            if pDAI.localName is None:  # <DOI name="LEDRs" desc="RstOper">
                pDAI = pDAI.nextSibling  # <SDI name="Oper">
                continue  # <SDI name="origin">
            if pDAI.localName == "Private":  # <DAI name="orCat" sAddr="96.1.3.10.4" />
                type = pDAI.getAttribute("type")
                # WG10 PRIVATE
                if type == "eTr-IEC61850-90-2":
                    pI90_2 = pDAI.firstChild.nextSibling
                    if (pI90_2.nodeName == "eTr-IEC61850-90-2:ProxyOf"):
                        _externalScl = pI90_2.getAttribute("externalScl")
                        _iedName = pI90_2.getAttribute("iedName")
                        _ldInst = pI90_2.getAttribute("ldInst")
                        _prefix = pI90_2.getAttribute("prefix")
                        _lnClass = pI90_2.getAttribute("lnClass")
                        _lnInst = pI90_2.getAttribute("lnInst")
                        _doName = pI90_2.getAttribute("doName")
                        iDOI.IEC_90_2 = IED.AccessPoint.Server.LN.DOI.IEC_90_2(
                            _externalScl, _iedName, _ldInst, _prefix, _lnClass,
                            _lnInst, _doName)
# WG10 PRIVATE
                elif type == "IEC_60870_5_104":
                    p104 = pDAI.firstChild
                    if p104 is not None:
                        p104 = p104.nextSibling

                        if (p104.localName == "Address") and (
                                p104.nodeName == "'IEC_60870_5_104:Address'"):
                            _casdu = p104.getAttribute("casdu")
                            _ioa = p104.getAttribute("ioa")
                            _ti = p104.getAttribute("ti")
                            _usedBy = p104.getAttribute("usedBy")
                            _inverted = p104.getAttribute("inverted")
                            iDOI.IEC104 = IED.AccessPoint.Server.LN.DOI.IEC104(
                                _casdu, _ioa, _ti, _usedBy, _inverted)
                else:
                    self.Dyn.PrivateDynImport(type, pDAI, iDOI)

                pDAI = pDAI.nextSibling  # </SDI>
                continue  # <DAI name="ctlVal" sAddr="96.1.3.10.3" />
            if pDAI.localName == "DAI":  # <DAI name="ctlNum" sAddr="96.1.3.10.6" />
                pX, value, iDAI = self.Parse_DAI_VAL(
                    pDAI, iDOI)  # <DAI name="T" sAddr="96.1.3.10.7" />
                #            tDAI.append(iDOI)
                pDAI = pDAI.nextSibling
                continue  #     <DAI name="Test" sAddr="96.1.3.10.8" />

            if pDAI.localName == "SDI":  # <DAI name="Check" sAddr="96.1.3.10.9" />
                self.Parse_SDI(pDAI, iDOI, DoName)
                pDAI = pDAI.nextSibling
                continue

            pDAI = pDAI.nextSibling

        return iDOI, iLN

    ##
    # \b Parse_DAI_VAL
    #
    # @param pDAI         The SCL pointer to DAI
    # @param iDOI	      The current instance of a DOI
    #
    # @return   pDAI      pDAI is pointing to the next Tag
    # @return  _value
    # @return  iDOI             The meaning of the value from the engineering phases. If missing, the valKind from the type definition applies for any attached value.

    def Parse_DAI_VAL(self, pDAI, iDOI):
        _value = None
        if pDAI.localName == "DAI":
            _desc = pDAI.getAttribute(
                "desc"
            )  ## desc	        The description text for the DAI element
            _name = pDAI.getAttribute(
                "name"
            )  ## name	        The name of the Data attribute whose value is given.
            _sAddr = pDAI.getAttribute(
                "sAddr")  ## sAddr	    Short address of this Data attribute
            _valKind = pDAI.getAttribute(
                "valKind"
            )  ## valKind	    The meaning of the value from the engineering phases. If missing, the va
            _ix = pDAI.getAttribute(
                "ix"
            )  ## ix	        Index of the DAI element in case of an array type
            _valImport = pDAI.getAttribute(
                "valImport"
            )  ## valImport	if true, an IED / IED configurator can import values modified by another
            ## value        implementation artefact, the declared value is stored here.

            iDAI = IED.AccessPoint.Server.LN.DOI.DAI(_desc, _name, _sAddr,
                                                     _valKind, _ix, _valImport,
                                                     _value)  # _value !
            setattr(iDOI, _name, iDAI)

            # Is there a value ?
            p1 = pDAI.firstChild
            if p1 is not None:  # The SCL may contains empty tag like </xxxx> <xxxx/>
                p1 = p1.nextSibling
                if (p1.firstChild is not None):

                    if p1.localName == "Val":
                        _value = p1.firstChild.data
                        iDAI.value = _value
                        self.TRX.Trace(("    Balise1 <VAL/>: " + _value),
                                       TL.DETAIL)
                        p1 = p1.firstChild.nextSibling

                    if p1 is not None and p1.localName == "Private":
                        pType = pDAI.firstChild.nextSibling
                        _type = pType.getAttribute("type")
                        self.Dyn.PrivateDynImport(_type, pType, iDAI)

                    setattr(iDOI, _name,
                            iDAI)  # I add the iDAI named '_name' to iDOI
                else:
                    setattr(iDOI, _name, iDAI)
                    _value = None
                    self.TRX.Trace(("    Balise2 <VAL/> vide"), TL.DETAIL)
            else:
                pDAI = pDAI.nextSibling
        return pDAI, _value, iDOI

    """
    The code of Parse_SDI(pDAI1, iDOI, n, TRX)is used to collect the
     value of DO/DA looking like this:
                </DOI>
                <DOI name="CosPhi">
                    <SDI name="phsA">
                        <SDI name="cVal">
                            <SDI name="mag">
                                <DAI name="f" sAddr="MX:0;0x070F2800;DB=0:P;MIN=0;MAX=0"/>
                            </SDI>
                        </SDI>
                        <SDI name="units">
                            <DAI name="SIUnit" valKind="RO">
    ==>                           <Val>cos(phi)</Val>           <=== 
                            </DAI>
                        </SDI>
                    </SDI>
    """

    ##
    # \b Parse_SDI
    # @param   pDAI     : the SCL pointer to a SDI
    # @param   iDOI     : an instance of DO, which may have SDI value to add
    # @param   DoName:
    # @return  sdi_name : the name of the instance
    #
    # \b Principle
    #
    # The instances of SDI is added to the DOI by dynamic creation of an attribute (setattr)
    # The code assume that there is a maximum of three levels of SDI.
    #
    def Parse_SDI(self, pDAI, iDOI, DoName):
        pDAI1 = pDAI
        BaseName = DoName + '.' + iDOI.name
        t_IX = [None, None, None, None]
        while pDAI1 is not None:
            if pDAI1.localName is None:
                pDAI1 = pDAI1.nextSibling
                continue
            iSDI1, sdi_name = self.Parse_SDI_Val(pDAI1, iDOI, BaseName, 0,
                                                 t_IX, '')
            if pDAI1.firstChild is None:  # No value found by Parse_SDI_Val
                pDAI1 = pDAI1.nextSibling
                continue
            pDAI2 = pDAI1.firstChild.nextSibling  # Prochaine balise DAI ou à SDI cas 'origin'.

            if pDAI2.localName == "SDI":  # SDI imbriqué
                while pDAI2 is not None:
                    if pDAI2.localName == "SDI":  # SDI imbriqué
                        iSDI2, sdi_name = self.Parse_SDI_Val(
                            pDAI2, iSDI1, BaseName, 1, t_IX, sdi_name)
                        if pDAI2.firstChild is None:
                            pDAI2 = pDAI2.nextSibling
                            continue
                        pDAI3 = pDAI2.firstChild.nextSibling  # Prochaine balise DAI ou à SDI cas 'origin'.

                        if pDAI3.localName == "SDI":  # SDI imbriqué
                            while pDAI3 is not None:
                                if pDAI3.localName == "SDI":  # SDI imbriqué
                                    iSDI3, sdi_name = self.Parse_SDI_Val(
                                        pDAI3, iSDI2, BaseName, 2, t_IX,
                                        sdi_name)
                                pDAI3 = pDAI3.nextSibling

                    pDAI2 = pDAI2.nextSibling

            pDAI1 = pDAI1.nextSibling
        return  # tDAI #.nextSibling,

    ##
    # \b Parse_SDI_Val
    #
    # @param   pDAI_v   : the SCL pointer to a SDI
    # @param   iDOI     : an instance of DO, which may have SDI value to add
    # @param   BaseName : used to build the name of the attribute DO.SDO.DA.BDA...
    # @param   n        : SDI1 or SDI2 ou SDI3  (for trace only)
    # @param   t_IX     : Table of value, if the DO is an array.
    # @param   sdi_name : Building the string DA_name.SDA_name.XX_name
    #
    # @return  iSDI: an instance od SDI object with value (if found)
    # @return  sdi_name: tha name of the instance.
    #
    # \b Principle
    # The instances of SDI is added to the DOI by dynamic creation of an attribute (setattr)

    def Parse_SDI_Val(self, pDAI_v, iDOI, BaseName, n, t_IX, sdi_name):
        _desc = pDAI_v.getAttribute("desc")
        _name = pDAI_v.getAttribute("name")
        _sdi_ix = pDAI_v.getAttribute("ix")
        _sAddr = pDAI_v.getAttribute("sAddr")
        _sdi_name = sdi_name + '.' + _name  # </SDI>
        iSDI = IED.AccessPoint.Server.LN.DOI.DAI.SDI(_desc, _name, _sdi_ix,
                                                     _sAddr)

        # Is it a table of SDI ?
        if len(_sdi_ix) > 0:
            t_IX[n] = _sdi_ix

        # Adding the attribute to iDOI dynamically.
        if _sdi_ix is not None and len(_sdi_ix) > 0:
            setattr(iDOI, _name + _sdi_ix, iSDI)
        else:
            setattr(iDOI, _name, iSDI)

        if pDAI_v.firstChild is None:
            self.TRX.Trace(("DAI without value:" + _name + "sAddr:" + _sAddr),
                           TL.DETAIL)
            return iSDI, sdi_name

        # Reading the Value
        pVAL = pDAI_v.firstChild.nextSibling
        pVAL, value, iSDI = self.Parse_DAI_VAL(pVAL, iSDI)
        if value is not None:
            found = False
            for i in range(0, 2):
                if t_IX[i] is not None:
                    self.TRX.Trace(
                        ("Value for SDI[idx]: " + str(n) + BaseName +
                         sdi_name + '_' + str(t_IX[i]) + '\t:' + value),
                        TL.DETAIL)
                    found = True
                    break
            if not found:
                self.TRX.Trace(("Value for SDI: " + str(n) + BaseName +
                                sdi_name + '\t:' + value), TL.DETAIL)
        return iSDI, sdi_name
Пример #6
0
 def __init__(self, _scl, _TR):
     self.scl            = _scl                  ##  scl
     self.TRX            = _TR                   ##  TRX instance of Trace System
     self.Dyn            = DynImport()           ## Dyn instance of DynImport to handle private section if any/
Пример #7
0
class ParseSubStation:

    ## \b Description
    #   Constructor is used to keep the dictionary of DOType available.
    #
    # @param _scl: pointer to the SCL structure created by miniDOM
    # @param _TRX: Trace function
    def __init__(self, _scl, _TR):
        self.scl            = _scl                  ##  scl
        self.TRX            = _TR                   ##  TRX instance of Trace System
        self.Dyn            = DynImport()           ## Dyn instance of DynImport to handle private section if any/

    ## \b Description
    #   Constructor is used to keep the dictionary of DOType available.
    #
    # @param _pTal      - pointer to the SCL structure, 'Terminal' TAG
    # @param pCNXNode   - Pointer to the data model at pConnectionNode level

    def ParseTerminal(self, pTal, pCNXNode):
        idxTal = 0
        while (pTal is not None) and (pTal.localName is not None):
            if pTal.localName == "Terminal":
                _name               = pTal.getAttribute("name")                ## _name             The optional relative name of the terminal at this Equipment. The default is the empty
                _desc               = pTal.getAttribute("desc")                ## _desc             Descriptive text to the terminal
                _connectivityNode   = pTal.getAttribute("connectivityNode")    ## _connectivityNode The pathname of the connectivity node to which this terminal connects.
                _substationName     = pTal.getAttribute("substationName")      ## _substationName   The name of the substation containing the connectivityNode
                _voltageLevelName   = pTal.getAttribute("voltageLevelName")    ## _voltageLevelName The name of the voltage level containing the connectivityNode
                _bayName            = pTal.getAttribute("bayName")             ## _bayName           The name of the bay containing the connectivityNode
                _cNodeName          = pTal.getAttribute("cNodeName")           ##  _cNodeName        (relative) name of the connectivityNode within its bay
                _lineName           = pTal.getAttribute("lineName")            ## _lineName         Ed 2    ??
                _neutralPoint       = pTal.getAttribute("neutralPoint")        ## _neutralPoint     Ed 2.1 ???

                iTerminal = SubStation.SubEquipement.Terminal(_name, _desc, _connectivityNode,_substationName,_voltageLevelName, _bayName,_cNodeName,_lineName, _neutralPoint)
                pCNXNode.tTerminal.append(iTerminal)
                idxTal = idxTal + 1

            pTal = pTal.nextSibling
            if pTal is not None:
                pTal = pTal.nextSibling

    ## \b Description
    #
    # Parse the VoltageLevel class
    #
    # @param Substation - the global daa model structure for subStation section of SCL
    # @param pCNXNode   - Pointer to the data model at pConnectionNode level

    def ParseVoltageLevelSection(self, Substation):
        # Analyse d'un IED
        #
        # <IED..
        #
        #    < Communication >
        #       < SubNetwork
        tVoltage = []
        _name = Substation[0].getAttribute("name")      # SubStation name
        _desc = Substation[0].getAttribute("desc")      # Description text
        poste=SubStation(_name,_desc)

        pVoltageLevel = Substation[0].firstChild.nextSibling

        while pVoltageLevel:

            _name       = pVoltageLevel.getAttribute("name")
#            _nomFreq    = pVoltageLevel.getAttribute("nomFreq")
#            _numpPhases = pVoltageLevel.getAttribute("numPhases")
            _desc       = pVoltageLevel.getAttribute("desc")

            Tension = poste.VoltageLevel(_name,_desc)
            poste.tVoltage.append(Tension)
            pVolt = pVoltageLevel.firstChild
            if pVolt is not None:
                pVolt=pVolt.nextSibling
            idxVolt = len(poste.tVoltage)-1
            while (pVolt is not None) and (pVolt.localName is not None):
                if pVolt.localName == "PowerTransformer":
                    _name    = pVolt.getAttribute("name")
                    _desc    = pVolt.getAttribute("desc")
                    _type    = pVolt.getAttribute("type")
                    _virtual = pVolt.getAttribute("virtual")
                    iTransfo = poste.VoltageLevel.PowerTransformer(_name,_desc, _type, _virtual )
                    poste.tVoltage[idxVolt].tPwrTfo.append(iTransfo)
                    self.TRX.Trace(('Substation/Transformer.name:' + _name  + ' desc:' + _desc + " type:"  + _type),TL.DETAIL)

                if pVolt.localName == "Voltage":
                    _unit       = pVolt.getAttribute("unit")
                    _multiplier = pVolt.getAttribute("multiplier")
                    _value      = pVolt.getAttribute("value")
                    iVolt       = poste.VoltageLevel.Voltage(_unit, _multiplier, _value)
                    poste.tVoltage[idxVolt].Voltage=iVolt
                    self.TRX.Trace(('Substation/Voltage.unit:' + _unit  + ' mul:' + _multiplier + " value:"  + _value ),TL.DETAIL)

                if pVolt.localName == "Bay":
                    _name    = pVolt.getAttribute("name")
                    _desc    = pVolt.getAttribute("desc")
                    _sx_y    = pVolt.getAttribute("sxy:y")
                    _sx_x    = pVolt.getAttribute("sxy:x")
                    iBay     = poste.Bay(_name, _desc, _sx_x, _sx_y)
                    poste.tVoltage[idxVolt].tBay.append(iBay)
                    self.TRX.Trace(('Substation/Bay.name:' + _name + ' desc:' + _desc + " sxy:y:" + _sx_y + " sxy:x:" + _sx_x), TL.DETAIL)

                    pBay = pVolt.firstChild
                    if pBay is not None:
                        pBay = pBay.nextSibling
                    idxConEqt  = 0
                    idxConMode = 0
                    idxBay = len(poste.tVoltage[idxVolt].tBay)-1
                    while(pBay is not None) and (pBay.localName is not None):
                        if pBay.localName == "ConductingEquipment":
                            _name    = pBay.getAttribute("name")
                            _desc    = pBay.getAttribute("desc")
                            _virtual = pBay.getAttribute("virtual")
                            _sx_y    = pBay.getAttribute("sxy:y")
                            _sx_x    = pBay.getAttribute("sxy:x")
                            _sx_dir  = pBay.getAttribute("sxy:dir")
                            iCondEqt = SubStation.ConductingEquipment(_name, _desc, _virtual, _sx_y, _sx_x, _sx_dir )
                            poste.tVoltage[idxVolt].tBay[idxBay].tConductingEquipment.append(iCondEqt)
                            self.TRX.Trace(('Substation/Bay/ConductEqt.name:' + _name + ' desc:' + _desc + ' virtual:' + _virtual +\
                                                                " sxy:y:" + _sx_y + " sxy:x:" + _sx_x), TL.DETAIL)

                            pTal  = pBay.firstChild
                            if pTal is not None:
                                pTal=pTal.nextSibling
                            self.ParseTerminal(pTal, poste.tVoltage[idxVolt].tBay[idxBay].tConductingEquipment[idxConEqt])
                            idxConEqt = idxConEqt+1

                        elif pBay.localName == "ConnectivityNode":
                            _name     = pBay.getAttribute("name")
                            _desc     = pBay.getAttribute("desc")
                            _pathName = pBay.getAttribute("pathName")
                            _sx_y     = pBay.getAttribute("sxy:y")
                            _sx_x     = pBay.getAttribute("sxy:x")
                            iConnNode = SubStation.SubEquipement.Terminal.ConnectivityNode(_name, _desc, _pathName, _sx_y, _sx_x)
                            poste.tVoltage[idxVolt].tBay[idxBay].tConnectivityNode.append(iConnNode)
                            self.TRX.Trace(('Substation/Bay/ConnnectNode.name:' + _name + ' desc:' + _desc + ' pathName:' + _pathName +\
                                                                " sxy:y:" + _sx_y + " sxy:x:" + _sx_x), TL.DETAIL)
                            pTal  = pBay.firstChild
                            if pTal is not None:
                                pTal=pTal.nextSibling
                            self.ParseTerminal(pTal, poste.tVoltage[idxVolt].tBay[idxBay].tConnectivityNode[idxConMode])
                            idxConMode = idxConMode + 1

                        elif pBay.localName == "Function":
                            _name     = pBay.getAttribute("name")
                            _desc     = pBay.getAttribute("desc")
                            iFunction = poste.Function(_name, _desc)
                            poste.tVoltage[idxVolt].tBay[idxBay].tFunction.append(iFunction)
                            self.TRX.Trace(('Substation/Bay/Function.name: ' + _name + ' desc:' + _desc), TL.DETAIL)

                            pPrivate = pBay.firstChild
                            if pPrivate is not None:
                                pPrivate = pPrivate.nextSibling
                                if pPrivate.localName == "Private":
                                    type = pPrivate.getAttribute("type")
                                    pDataModel = poste.tVoltage[idxVolt].tBay[idxBay].tFunction[0]
                                    self.Dyn.DynImport(type, pPrivate, pDataModel)


                        elif pBay.localName == "LNode":
                            _iedName  = pBay.getAttribute("iedName")
                            _lnClass  = pBay.getAttribute("lnClass")
                            _lnType   = pBay.getAttribute("lnType")
                            _lnInst   = pBay.getAttribute("lnInst")
                            iLNode    = poste.Bay.LNode(_iedName,_lnClass, _lnType, _lnInst)
                            poste.tVoltage[idxVolt].tBay[idxBay].tLNode.append(iLNode)
                            self.TRX.Trace(('Substation/Bay/Lnode.iedName: '+ _iedName + " lnClass:" + _lnClass + \
                                       " lnType:" + _lnType + " lnInst:" + _lnInst), TL.DETAIL)
                        pBay = pBay.nextSibling
                        if pBay is not None:
                            pBay = pBay.nextSibling
                pVolt = pVolt.nextSibling
                if pVolt is not None:
                    pVolt = pVolt.nextSibling

            pVoltageLevel = pVoltageLevel.nextSibling
            if pVoltageLevel is not None:
                pVoltageLevel = pVoltageLevel.nextSibling
        return pVoltageLevel
Пример #8
0
class Parse_Server:
    ## \b Description
    #   Constructor is used to keep initialize the Parse_LN class (forwarding TRACE class).
    # @param _scl: pointer to the SCL structure created by miniDOM
    # @param _TRX: Trace function
    def __init__(self, _scl, TR):  ## Constructor for Server
        self.scl = _scl  ## Pointer to the SCL as provided by 'minidom'.
        self.TR = TR  ## Instance of the TRACE service.
        self.pLN = Parse_LN(
            TR
        )  ## Invoking the constructor of ParseLN, to initialize TRACE service.
        self.Dyn = DynImport()

    ##
    # Parse the IED list created by  a  self.scl.getElementsByTagName("IED"
    #
    # Features:
    #   - Detects IED defined without any Server part.
    #   - Parse the AccessPoints and the Servers:
    #       - Created nested tables AccessPoint and tables of servers
    #   - Once the Server level is reached, the parsing continue with:
    #       - Parse_LD_LN
    #           - Parse LN (from IEC_LN class
    #
    # @param  iIED_array: the trace Object type to look up.
    # @param  pServer    pointer to the SCL structure
    # @param  idxAP         index to access a an instance of AccessPoint
    # @param  idxServer     index to access a an instance of Server
    #
    # @return
    #
    # \bThe DataModel is build dynamically by 'setAttr'

    def Parse_LD_LN(self, iIED_array, pServer, idxAP, idxServer):

        tLDevice = []
        LDi = pServer
        inst = LDi.getAttribute(
            "inst"
        )  ## Identification of the LDevice within the IED. Identification of the LDevice within the IED. Its value cannot be the empty string.
        ldName = LDi.getAttribute(
            "ldName"
        )  ## The explicitly specified name of the logical device according to IEC 61850-7-1  and 7-2 within the communication.
        desc = LDi.getAttribute("desc")  ## The description text
        trLDevice = "     LDevice: " + ldName + ' inst:' + inst + ' desc:' + desc
        self.TR.Trace(trLDevice, TL.GENERAL)
        iDeviceInstance = IED.AccessPoint.Server.LDevice(
            inst, desc, ldName)  # LN0 et les LN sont ajoutés après

        iIED_array.tAccessPoint[idxAP].tServer[idxServer].tLDevice.append(
            iDeviceInstance)

        LDeviceName = ldName + inst
        tLN = [
        ]  # Table of LN0 and LNs instanciation in the current Logical Device.
        LN_index = 0  # Index to this array
        pLNi = LDi.firstChild.nextSibling
        lnClass1 = ""
        LNtxt = ""
        while pLNi is not None:
            if pLNi.localName is None:
                pLNi = pLNi.nextSibling
                continue

            if pLNi.localName == 'Private':
                pLNi = pLNi.nextSibling
                continue

            iLN = self.pLN.Parse_LN(pLNi, iIED_array.name,
                                    iIED_array.tAccessPoint[idxAP].name,
                                    iIED_array.tDAI)
            tLN.append(iLN)

            LNtxt = ("       LN: " + iLN.lnPrefix + '_' + iLN.lnType + '_' + iLN.lnInst + \
                     " Class:" + iLN.lnClass + ' Desc:' + iLN.lnDesc)
            self.TR.Trace((LNtxt), TL.DETAIL)
            # The tree of nested level of DO / SDO / DA / SDA ishnadled in IEC_ParcoursDataModel
            LN_id = iLN.lnPrefix + iLN.lnClass + iLN.lnInst
            #                        tLN.append(iLN)
            LN_index = LN_index + 1
            setattr(iDeviceInstance, LN_id, iLN)  # = LDeviceInstance
            if (pLNi.nextSibling) is not None:
                pLNi = pLNi.nextSibling
                continue

        LDi = LDi.nextSibling
        iDeviceInstance.LN = tLN
        #        Name = iDeviceInstance.inst
        return iDeviceInstance, iDeviceInstance.inst

    ##
    # Parse the IED list created by  a  self.scl.getElementsByTagName("IED"
    #
    # Features:
    #   - Detects IED defined without any Server part.
    #   - Parse the AccessPoints and the Servers:
    #       - Created nested tables AccessPoint and tables of servers
    #   - Once the Server level is reached, the parsing continue with:
    #       - Parse_LD_LN
    #           - Parse LN (from IEC_LN class
    #
    # @param   TR: the trace Object type to look up.
    # @return  tIED_array: the table of IED and their full data model

    def Parse_IED(self, TR):
        LD_index = 0
        tIED_array = [
        ]  ## Iterative version of the Data Model: Table of LN, Table of DO....
        tIED_struct = [
        ]  ## Named based version of the Data Model:  MEASURE.MMXU.X.X

        IEDlst = self.scl.getElementsByTagName("IED")
        for ied in IEDlst:
            IEDname = ied.getAttribute(
                "name"
            )  ## The identification of the IED, 'Template' in ICD, unique in SCD.
            _desc = ied.getAttribute("desc")  ## The description text
            _type = ied.getAttribute(
                "type")  ## The (manufacturer specific) IED product type
            _manufacturer = ied.getAttribute(
                "manufacturer")  ## The manufacturer's name
            _configVersion = ied.getAttribute(
                "configVersion"
            )  ## The basic configuration version of this IED configuration
            _originalSclVersion = ied.getAttribute(
                "originalSclVersion"
            )  ## The original SCL schema version of the IEDs ICD file; optional
            _originalSclRevision = ied.getAttribute(
                "originalSclRevision"
            )  ## The original SCL schema revision of the IEDs ICD file; optional
            _engRight = ied.getAttribute(
                "engRight")  ## The engineering right transferred by a SED file
            _owner = ied.getAttribute(
                "owner")  ## The owner project of this IED,
            self.TR.Trace(
                ("IED:" + IEDname + ' type:' + _type + ' desc:' + _desc),
                TL.DETAIL)

            iIED_array = IED(IEDname, _desc, _type, _manufacturer,
                             _configVersion, _originalSclVersion,
                             _originalSclRevision, _engRight, _owner)

            iIED_struct = IED(IEDname, _desc, _type, _manufacturer,
                              _configVersion, _originalSclVersion,
                              _originalSclRevision, _engRight, _owner)

            Services = ied.firstChild.nextSibling
            # Skip any Private...
            while (Services.localName is None):
                Services = Services.nextSibling
                continue

    # Skip Service section (Parsed in a different section)

            while Services.localName == "Private":
                type = Services.getAttribute("type")
                self.Dyn.PrivateDynImport(type, Services, iIED_array)
                self.Dyn.PrivateDynImport(type, Services, iIED_struct)
                Services = Services.nextSibling
                Services = Services.nextSibling

            if Services.localName == "Services":
                Services = Services.nextSibling
                Services = Services.nextSibling
            ## AccessPoint.localName: is the key to the ConnectedAP related to this access point
            if Services.localName == "AccessPoint":
                pAcccess = Services

                _name = pAcccess.getAttribute("name")  ## The description text
                _desc = pAcccess.getAttribute(
                    "desc"
                )  ## Reference identifying this access point within the IED
                _router = pAcccess.getAttribute(
                    "router"
                )  ## The presence and setting to true defines this IED to have a router function.
                _clock = pAcccess.getAttribute(
                    "clock"
                )  ## The presence and setting to true defines this IED to be a master clock at this bus.
                _AccessPoint = IED.AccessPoint(_name, _desc, _router, _clock)
                iIED_array.tAccessPoint.append(_AccessPoint)
                idxAccessPoint = len(iIED_array.tAccessPoint) - 1

                if Services.firstChild is None:
                    ### In case of a strict client application, the access Point is only declared
                    self.TR.Trace(("AccessPoint: no firstChild"), TL.DETAIL)
                    continue
                else:
                    ServerSection = Services.firstChild.nextSibling

                    if (ServerSection is
                            None):  #Pas de Server, application client pure
                        self.TR.Trace(('Application client:', IEDname, desc),
                                      TL.DETAIL)
                        continue
                    if (ServerSection.firstChild is
                            None):  # Pas de Server, application client pure
                        TR.Trace(('Application client:', IEDname, desc),
                                 TL.DETAIL)
                        if (len(iIED_struct.tAccessPoint)) > 0:
                            iIED_struct.tAccessPoint[
                                idxAccessPoint].tServer = None
                        else:
                            iIED_struct.tAccessPoint = None
                            iIED_array.Server = None
                            iIED_struct.Server = None
                        iIED_array.tLDevice = None
                        iIED_struct.tLDevice = None
                        continue
                    else:
                        while ServerSection.localName == "Server":
                            _desc = ServerSection.getAttribute(
                                "desc")  ## A descriptive text
                            _timeout = ServerSection.getAttribute(
                                "timeout"
                            )  ## Time out in seconds: if a started transaction isnot completed within this time, it is cancelled and reset
                            iServer = IED.AccessPoint.Server(_desc, _timeout)
                            iIED_array.tAccessPoint[
                                idxAccessPoint].tServer.append(iServer)

                            idxServer = 0

                            pServer = ServerSection.firstChild.nextSibling
                            while pServer.nextSibling:
                                if pServer.localName is None:
                                    pServer = pServer.nextSibling
                                    continue

                                if pServer.localName == "Authentication":
                                    none = pServer.getAttribute(
                                        "none")  ## IEC  No authentication
                                    password = pServer.getAttribute(
                                        "password"
                                    )  ## Defined in the stack mappings (SCSMs)
                                    weak = pServer.getAttribute(
                                        "weak"
                                    )  ## Defined in the stack mappings (SCSMs)
                                    strong = pServer.getAttribute(
                                        "strong"
                                    )  ## Defined in the stack mappings (SCSMs)
                                    certificate = pServer.getAttribute(
                                        "certificate"
                                    )  ## Defined in the stack mappings (SCSMs)
                                    # TODO eventually AccesPoint without server
                                    iAuthentication = IED.AccessPoint.Server.Authentication(
                                        none, password, weak, strong,
                                        certificate)
                                    iIED_array.tAccessPoint[
                                        idxAccessPoint].tServer[
                                            idxServer].authentication = iAuthentication

                                    pServer = pServer.nextSibling
                                    continue

                                if pServer.localName == "Private":  # TODO est-ce qu'il y a des balises privées RTE ?
                                    pServer = pServer.nextSibling
                                    continue

                                if pServer.localName == "LDevice":
                                    iDeviceInstance, Name = self.Parse_LD_LN(
                                        iIED_array, pServer, idxAccessPoint,
                                        idxServer)
                                    setattr(
                                        iIED_array.tAccessPoint[idxAccessPoint]
                                        .tServer[idxServer], Name,
                                        iDeviceInstance)  # = LDeviceInstance
                                    pServer = pServer.nextSibling
                                    continue

                            ServerSection = ServerSection.nextSibling
                            if ServerSection is None:
                                break
# Version itérative
            tIED_array.append(iIED_array)

            # Version structurée
            #            iIED_struct.Server   = tServer
            #            tIED_struct.append(iIED_struct)
            continue
            self.TR.Trace(("FIN SERVER"), TL.DETAIL)

        self.TR.Trace(("FIN IED"), TL.DETAIL)
        return tIED_array