Merge pull request #480 from mbourhis/mbourhis/feature/update-python-wrapper-cmakelist

Python wrapper: update CMakeLists, and rename the module to 'pyiec61850'
pull/494/head
Michael Zillgith 2 years ago committed by GitHub
commit 5aaa7a1475
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,18 +1,22 @@
# The SWIG functions/macros used in this module, swig_add_module and swig_add_library cmake_minimum_required(VERSION 3.12)
# are not available in CMake versions earlier than 3.8
# cmake_minimum_required(VERSION 3.8) cmake_policy(SET CMP0078 NEW)
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0")
cmake_policy(SET CMP0086 NEW)
endif()
find_package(SWIG REQUIRED) find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE}) include(${SWIG_USE_FILE})
find_package(PythonInterp ${BUILD_PYTHON_VERSION} REQUIRED) find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED)
include_directories(${PYTHON_INCLUDE_PATH}) include_directories(${Python_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_SWIG_FLAGS "") set(CMAKE_SWIG_FLAGS "")
set_property(SOURCE iec61850.i PROPERTY CPLUSPLUS ON) set_property(SOURCE iec61850.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE iec61850.i PROPERTY SWIG_MODULE_NAME pyiec61850)
if(WIN32) if(WIN32)
set(LIBS iec61850 ws2_32) set(LIBS iec61850 ws2_32)
@ -20,25 +24,21 @@ else()
set(LIBS iec61850-shared) set(LIBS iec61850-shared)
endif() endif()
if(${CMAKE_VERSION} VERSION_LESS 3.8) swig_add_library(pyiec61850
swig_add_module(iec61850 python iec61850.i) LANGUAGE python
else() SOURCES iec61850.i
swig_add_library(iec61850 )
LANGUAGE python
SOURCES iec61850.i
)
endif()
swig_link_libraries(iec61850 ${PYTHON_LIBRARIES} ${LIBS}) swig_link_libraries(pyiec61850 ${LIBS})
# Finding python modules install path # Finding python modules install path
execute_process( execute_process(
COMMAND ${PYTHON_EXECUTABLE} -c COMMAND ${Python_EXECUTABLE} -c
"from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib())" "from sysconfig import get_path; import sys; sys.stdout.write(get_path('platlib'))"
OUTPUT_VARIABLE PYTHON_SITE_DIR OUTPUT_VARIABLE PYTHON_SITE_DIR
) )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/iec61850.py DESTINATION ${PYTHON_SITE_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pyiec61850.py DESTINATION ${PYTHON_SITE_DIR})
install(TARGETS _iec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR}) install(TARGETS pyiec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR})
add_test(test_pyiec61850 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/test_pyiec61850.py) add_test(test_pyiec61850 ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/test_pyiec61850.py)

@ -0,0 +1,95 @@
# Python wrapper for libIEC61850
## Building
Before building you should install SWIG and Python
(see the '[Setup development environment on Linux](#setup-development-environment-on-linux-ubuntu)' section for help).
To build the Python bindings you have to turn on the BUILD\_PYTHON\_BINDINGS flag in CMake from cmake-gui or in command line:
```sh
$ mkdir build && cd build
$ cmake -DBUILD_PYTHON_BINDINGS=ON ..
```
Then compile the library and install it:
```sh
$ make
$ sudo make install
```
(Eventually, update your ld cache with: `sudo ldconfig`)
CMake and SWIG will automatically detect your Python version and install the Python library in Python library directories.
For running the integrated tests:
```sh
$ make test
```
pyiec61850 library is to be imported calling:
```python
import pyiec61850 as iec61850
```
## Client tutorial
The Python bindings works similarly to the basic C library. However there are some differences:
* a specific function is to be called to cast variables from one type to another
* arguments passed by pointer are to be removed from arguments and append to the return list
For example to create a connection, call:
```python
con = iec61850.IedConnection_create()
error = iec61850.IedConnection_connect(con, "localhost", 102)
if (error == iec61850.IED_ERROR_OK):
# Do some work
iec61850.IedConnection_close(con)
iec61850.IedConnection_destroy(con)
```
To iterate over a list of logical devices, the code becomes:
```python
[deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(con)
device = iec61850.LinkedList_getNext(deviceList)
while device:
print("LD: %s" % iec61850.toCharP(device.data))
[logicalNodes, error] = iec61850.IedConnection_getLogicalDeviceDirectory(
con, iec61850.toCharP(device.data))
device = iec61850.LinkedList_getNext(device)
iec61850.LinkedList_destroy(deviceList)
```
Reading and writing operations can be performed using this syntax:
```python
[floatValue, error] = iec61850.IedConnection_readFloatValue(con,
"simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX)
err = iec61850.IedConnection_writeFloatValue(con,
"simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX, 10.0)
```
## Appendix
## Setup development environment on Linux Ubuntu
_[Tested on Ubuntu 20.04 LTS, Ubuntu 22.04 LTS, Ubuntu 23.10]_
Here the minimum required packages for compiling libiec61850 and the Python
wrapper (without TLS, SQlite, ...):
```sh
$ sudo apt-get update
$ sudo apt-get install g++ cmake swig git python3 python3-all-dev
```
## Setup development environment on Linux Alpine
_[Tested on Alpine 3.18]_
Here the minimum required packages for compiling libiec61850 and the Python
wrapper (without TLS, SQlite, ...):
```sh
$ apk update
$ apk add git g++ swig make cmake python3 python3-dev linux-headers
```

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
import os,sys import os,sys
import iec61850 import pyiec61850 as iec61850
if __name__=="__main__": if __name__=="__main__":
hostname = "localhost"; hostname = "localhost";
tcpPort = 102 tcpPort = 102

@ -27,7 +27,7 @@ The user needs to:
import time import time
import sys import sys
import iec61850 import pyiec61850 as iec61850
def open_connection(ip_address, mms_port): def open_connection(ip_address, mms_port):

@ -1,5 +1,5 @@
/* File : iec61850.i */ /* File : iec61850.i */
%module(directors="1") iec61850 %module(directors="1") pyiec61850
%ignore ControlObjectClient_setTestMode(ControlObjectClient self); %ignore ControlObjectClient_setTestMode(ControlObjectClient self);
%ignore CDA_OperBoolean(ModelNode* parent, bool isTImeActivated); %ignore CDA_OperBoolean(ModelNode* parent, bool isTImeActivated);
%ignore LogicalNode_hasBufferedReports(LogicalNode* node); %ignore LogicalNode_hasBufferedReports(LogicalNode* node);

@ -6,7 +6,7 @@ import traceback
import signal import signal
import sys import sys
sys.path.append('.') sys.path.append('.')
import iec61850 import pyiec61850 as iec61850
def signal_handler(signal, frame): def signal_handler(signal, frame):
global running global running
running =0 running =0

@ -1,50 +0,0 @@
# Building
Before building you should install swig and python.
To build python bindings you have to turn on the BUILD\_PYTHON\_BINDINGS flag in CMake from cmake-gui or in command line:
```sh
$ cmake -DBUILD_PYTHON_BINDINGS=ON .
```
Then compile the library and install it. CMake and swig will automatically detect your python version and install the python library in python library directories.
pyiec61850 library is to be imported calling
```python
import iec61850
```
# Client tutorial
The python bindings works similarly to the basic C library. However there are some differences:
* a specific function is to be called to cast variables from one type to another
* arguments passed by pointer are to be removed from arguments and append to the return list
For example to create a connection, call:
```python
con = iec61850.IedConnection_create()
error = iec61850.IedConnection_connect(con, "localhost", 102)
if (error == iec61850.IED_ERROR_OK):
# Do some work
iec61850.IedConnection_close(con)
iec61850.IedConnection_destroy(con)
```
To iterate over a list of logical devices, the code becomes:
```python
[deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(con)
device = iec61850.LinkedList_getNext(deviceList)
while device:
print("LD: %s" % iec61850.toCharP(device.data))
[logicalNodes, error] = iec61850.IedConnection_getLogicalDeviceDirectory(
con, iec61850.toCharP(device.data))
device = iec61850.LinkedList_getNext(device)
iec61850.LinkedList_destroy(deviceList)
```
Reading and writing operations can be performed using this syntax:
```python
[floatValue, error] = iec61850.IedConnection_readFloatValue(con,
"simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX)
err = iec61850.IedConnection_writeFloatValue(con,
"simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX, 10.0)
```
Loading…
Cancel
Save