├── README.md ├── client.PNG ├── client.py ├── data.png ├── server.PNG └── server.py /README.md: -------------------------------------------------------------------------------- 1 | # pyiec61850 2 | Server and Client of PyIEC61850 based on mz-automation 3 | 4 | # A. Requirements 5 | a. Python 2.7 or higher 6 | 7 | b. CMake 3.7.2 or higher 8 | 1. wget https://cmake.org/files/v3.7/cmake-3.7.2.tar.gz 9 | 2. tar zxvf cmake-3.7.2.tar.gz 10 | 3. cd cmake-3.7.2 11 | 4. ./bootstrap && make 12 | 5. sudo make install 13 | 14 | c. SWIG 4.0.0 or higher 15 | 1. wget http://prdownloads.sourceforge.net/swig/swig-4.0.0.tar.gz 16 | 2. tar xzf swig-4.0.0.tar.gz 17 | 3. cd swig-4.0.0 18 | 4. ./configure 19 | 5. make 20 | 6. sudo make install 21 | 22 | # B. Installation 23 | 1. cd ~ 24 | 2. sudo apt update && upgrade 25 | 3. git clone https://github.com/keyvdir/pyiec61850.git 26 | 4. cd pyiec61850 27 | 5. git clone https://github.com/mz-automation/libiec61850.git 28 | 6. wget https://tls.mbed.org/download/mbedtls-2.16.0-apache.tgz 29 | 7. tar zxvf mbedtls-2.16.0-apache.tgz 30 | 8. mv mbedtls-2.16.0 libiec61850/third_party/mbedtls/mbedtls-2.16 31 | 9. cd libiec61850 32 | 10. cmake -DBUILD_PYTHON_BINDINGS=ON -DPYTHON_EXECUTABLE=/usr/bin/python3 . 33 | 11. make WITH_MBEDTLS=1 34 | 12. cd .. 35 | 13. python3 server.py and python3 client.py (different terminal window) 36 | 37 | ![Server example](server.PNG) 38 | ![Client example](client.PNG) 39 | 40 | # C. IEC 61850 Information Model 41 | ![IEC 61850 Information Model](data.png) 42 | 43 | # D. Write and Read Data 44 | Data type for write, read, and other complete functions can be found in “libiec61850/pyiec61850/iec61850.py”. Please refer to the original website of IEC61850 for further information of the data types. https://libiec61850.com/api/modules.html 45 | -------------------------------------------------------------------------------- /client.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyvdir/pyiec61850/cc0736dfec94d1b072fadcc81cb805cff15a78bf/client.PNG -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import time 4 | import threading 5 | import traceback 6 | import signal 7 | import sys 8 | sys.path.insert(0, "libiec61850/pyiec61850") 9 | import iec61850 10 | from datetime import datetime 11 | 12 | def signal_handler(signal, frame): 13 | global running 14 | running =0 15 | print('You pressed Ctrl+C!') 16 | 17 | if __name__=="__main__": 18 | now = datetime.now(); 19 | current_time = now.strftime("%H:%M:%S"); 20 | print("Starting Client At Time %s" % current_time); 21 | 22 | #Create Client Connection 23 | con = iec61850.IedConnection_create() 24 | error = iec61850.IedConnection_connect(con, "localhost", 8102); 25 | 26 | if (error == iec61850.IED_ERROR_OK): 27 | [deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(con) 28 | device = iec61850.LinkedList_getNext(deviceList) 29 | 30 | print("Connected to Server.\n") 31 | 32 | #Show Logical Node, Logical Device and Data Object inside the Server 33 | while device: 34 | LD_name=iec61850.toCharP(device.data) 35 | print("LD: %s" % LD_name) 36 | [logicalNodes, error] = iec61850.IedConnection_getLogicalDeviceDirectory(con, LD_name) 37 | logicalNode = iec61850.LinkedList_getNext(logicalNodes) 38 | while logicalNode: 39 | LN_name=iec61850.toCharP(logicalNode.data) 40 | print(" LN: %s" % LN_name) 41 | [LNobjects, error] = iec61850.IedConnection_getLogicalNodeVariables(con, LD_name+"/"+LN_name) 42 | LNobject = iec61850.LinkedList_getNext(LNobjects) 43 | while LNobject: 44 | print(" DO: %s" % iec61850.toCharP(LNobject.data)) 45 | LNobject = iec61850.LinkedList_getNext(LNobject) 46 | iec61850.LinkedList_destroy(LNobjects) 47 | logicalNode = iec61850.LinkedList_getNext(logicalNode) 48 | iec61850.LinkedList_destroy(logicalNodes) 49 | device = iec61850.LinkedList_getNext(device) 50 | iec61850.LinkedList_destroy(deviceList) 51 | 52 | running = 1; 53 | 54 | signal.signal(signal.SIGINT, signal_handler); 55 | 56 | while (running): 57 | #Read Data Object 58 | theVal = "testmodelSENSORS/TTMP1.Temp1.float" 59 | theValType = iec61850.IEC61850_FC_MX 60 | value = iec61850.IedConnection_readFloatValue(con, theVal, theValType); 61 | print("\n Read Value of TTMP1.Temp1.float: %s" % value[0]); 62 | 63 | assert(value[1]==0) 64 | newValue= value[0] 65 | err = iec61850.IedConnection_writeFloatValue(con, theVal, theValType, newValue) 66 | assert(err==25) 67 | 68 | # Accessing to ASG values 69 | theVal = "testmodelSENSORS/TTMP1.TmpSp.setMag.f" 70 | theValType = iec61850.IEC61850_FC_SP 71 | setpoint = iec61850.IedConnection_readFloatValue(con, theVal, theValType) 72 | assert(value[1]==0) 73 | newValue= 50 74 | err = iec61850.IedConnection_writeFloatValue(con, theVal, theValType, newValue) 75 | assert(err==0) 76 | #Write Data Object with new value 77 | setpoint = iec61850.IedConnection_readFloatValue(con, theVal, theValType) 78 | print(" Write Value of TTMP1.Temp1.float: %s" % setpoint[0]) 79 | assert(setpoint[0]==newValue) 80 | 81 | #Read Data Object 82 | theVal1 = "testmodelSENSORS/TTMP1.Temp1.string" 83 | theValType1 = iec61850.IEC61850_FC_DC 84 | value1 = iec61850.IedConnection_readStringValue(con, theVal1, theValType1); 85 | print(" Read Value of TTMP1.Temp1.string: %s" % value1[0]); 86 | 87 | assert(value1[1]==0) 88 | newValue1= value1[0] 89 | err1 = iec61850.IedConnection_writeVisibleStringValue(con, theVal1, theValType1, newValue1) 90 | assert(err1==21) 91 | 92 | # Accessing to VSG values 93 | theVal1 = "testmodelSENSORS/TTMP1.TmpSt.setVal" 94 | theValType1 = iec61850.IEC61850_FC_SP 95 | setpoint1 = iec61850.IedConnection_readStringValue(con, theVal1, theValType1) 96 | assert(value1[1]==0) 97 | newValue1= "Networked System Lab" 98 | err1 = iec61850.IedConnection_writeVisibleStringValue(con, theVal1, theValType1, newValue1) 99 | assert(err1==0) 100 | #Write Data Object with new value 101 | setpoint1 = iec61850.IedConnection_readStringValue(con, theVal1, theValType1) 102 | print(" Write Value of TTMP1.Temp1.string: %s" % setpoint1[0]) 103 | assert(setpoint1[0]==newValue1) 104 | 105 | time.sleep(5) 106 | 107 | else: 108 | print("Connection error") 109 | sys.exit(-1) 110 | 111 | iec61850.IedConnection_close(con) 112 | iec61850.IedConnection_destroy(con) 113 | print("\n Client Disconnected.") 114 | -------------------------------------------------------------------------------- /data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyvdir/pyiec61850/cc0736dfec94d1b072fadcc81cb805cff15a78bf/data.png -------------------------------------------------------------------------------- /server.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyvdir/pyiec61850/cc0736dfec94d1b072fadcc81cb805cff15a78bf/server.PNG -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import time 4 | import threading 5 | import traceback 6 | import signal 7 | import Adafruit_DHT 8 | import sys 9 | sys.path.insert(0, "libiec61850/pyiec61850") 10 | import iec61850 11 | from datetime import datetime 12 | 13 | def signal_handler(signal, frame): 14 | global running 15 | running =0 16 | print('You pressed Ctrl+C!') 17 | 18 | 19 | if __name__=="__main__": 20 | now = datetime.now(); 21 | current_time = now.strftime("%H:%M:%S"); 22 | print("Starting MMS Server At Time %s" % current_time); 23 | 24 | #Create Model IED 25 | myModel = iec61850.IedModel_create("testmodel"); 26 | #Create Logical Device 27 | lDevice1 = iec61850.LogicalDevice_create("SENSORS", myModel); 28 | #Create Logical Node 29 | ttmp1 = iec61850.LogicalNode_create("TTMP1", lDevice1); 30 | #Create Model Node 31 | iec61850.CDC_ASG_create("TmpSp", iec61850.toModelNode(ttmp1), 0, False); 32 | iec61850.CDC_VSG_create("TmpSt", iec61850.toModelNode(ttmp1), 0); 33 | #Create Data Object 34 | do1 = iec61850.DataObject_create("Temp1", iec61850.toModelNode(ttmp1), 0); 35 | #Create Data Attribute 36 | fl = iec61850.DataAttribute_create("float", iec61850.toModelNode(do1), iec61850.IEC61850_FLOAT64, iec61850.IEC61850_FC_MX, 0, 0, 0); 37 | st = iec61850.DataAttribute_create("string", iec61850.toModelNode(do1), iec61850.IEC61850_VISIBLE_STRING_255, iec61850.IEC61850_FC_DC, 0, 0, 0); 38 | 39 | #Create Server Connection 40 | iedServer = iec61850.IedServer_create(myModel); 41 | iec61850.IedServer_start(iedServer, 8102); 42 | print("Waiting for connection...\n"); 43 | 44 | 45 | if not(iec61850.IedServer_isRunning(iedServer)) : 46 | print("Starting server failed! Exit.\n"); 47 | iec61850.IedServer_destroy(iedServer); 48 | sys.exit(-1); 49 | 50 | running = 1; 51 | 52 | signal.signal(signal.SIGINT, signal_handler); 53 | 54 | #Main loop 55 | while (running): 56 | #Sensing humidity and temperature value using DHT11 57 | humidity, temperature = Adafruit_DHT.read_retry(11, 4); 58 | #Add the value to the specific Data Attribute 59 | val1 = iec61850.IedServer_updateFloatAttributeValue(iedServer, fl, temperature); 60 | val2 = iec61850.IedServer_updateVisibleStringAttributeValue(iedServer, st, 'This is'); 61 | time.sleep(1); 62 | 63 | iec61850.IedServer_stop(iedServer); 64 | iec61850.IedServer_destroy(iedServer); 65 | --------------------------------------------------------------------------------