Commit c66f34cf authored by Jürg Rast's avatar Jürg Rast Committed by GitHub

New Documentation (#1007)

* Initial new documentation

* Update server-minimal example which is used in the docs

* Better API Structure

* Added RTD Config

* Added documentation for 'a minimal opc-ua client'

* More about nodes and nodeids

* More usage guide

* Combined Node & NodeId Docu, updated links in index

* A little more documentation
parent 0499120c
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.10"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
\ No newline at end of file
# Makefile for Sphinx documentation
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
# Put it first so that "make" without argument is like "make help".
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonOPC-UA.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonOPC-UA.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/PythonOPC-UA"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonOPC-UA"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: help Makefile
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
=========================
asyncua.client.ha package
=========================
Submodules
==========
asyncua.client.ha.common module
-------------------------------
.. automodule:: asyncua.client.ha.common
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ha.ha\_client module
-----------------------------------
.. automodule:: asyncua.client.ha.ha_client
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ha.reconciliator module
--------------------------------------
.. automodule:: asyncua.client.ha.reconciliator
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ha.virtual\_subscription module
----------------------------------------------
.. automodule:: asyncua.client.ha.virtual_subscription
:members:
:undoc-members:
:show-inheritance:
======================
asyncua.client package
======================
Subpackages
===========
.. toctree::
:maxdepth: 4
asyncua.client.ha
Submodules
===========
asyncua.client.client module
----------------------------
.. automodule:: asyncua.client.client
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ua\_client module
--------------------------------
.. automodule:: asyncua.client.ua_client
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ua\_file module
------------------------------
.. automodule:: asyncua.client.ua_file
:members:
:undoc-members:
:show-inheritance:
asyncua.client.ua\_file\_transfer module
----------------------------------------
.. automodule:: asyncua.client.ua_file_transfer
:members:
:undoc-members:
:show-inheritance:
======================
asyncua.common package
======================
Submodules
==========
asyncua.common.callback module
------------------------------
.. automodule:: asyncua.common.callback
:members:
:undoc-members:
:show-inheritance:
asyncua.common.connection module
--------------------------------
.. automodule:: asyncua.common.connection
:members:
:undoc-members:
:show-inheritance:
asyncua.common.copy\_node\_util module
--------------------------------------
.. automodule:: asyncua.common.copy_node_util
:members:
:undoc-members:
:show-inheritance:
asyncua.common.event\_objects module
------------------------------------
.. automodule:: asyncua.common.event_objects
:members:
:undoc-members:
:show-inheritance:
asyncua.common.events module
----------------------------
.. automodule:: asyncua.common.events
:members:
:undoc-members:
:show-inheritance:
asyncua.common.instantiate\_util module
---------------------------------------
.. automodule:: asyncua.common.instantiate_util
:members:
:undoc-members:
:show-inheritance:
asyncua.common.manage\_nodes module
-----------------------------------
.. automodule:: asyncua.common.manage_nodes
:members:
:undoc-members:
:show-inheritance:
asyncua.common.methods module
-----------------------------
.. automodule:: asyncua.common.methods
:members:
:undoc-members:
:show-inheritance:
asyncua.common.node module
--------------------------
.. automodule:: asyncua.common.node
:members:
:undoc-members:
:show-inheritance:
asyncua.common.node\_factory module
-----------------------------------
.. automodule:: asyncua.common.node_factory
:members:
:undoc-members:
:show-inheritance:
asyncua.common.shortcuts module
-------------------------------
.. automodule:: asyncua.common.shortcuts
:members:
:undoc-members:
:show-inheritance:
asyncua.common.statemachine module
----------------------------------
.. automodule:: asyncua.common.statemachine
:members:
:undoc-members:
:show-inheritance:
asyncua.common.structures module
--------------------------------
.. automodule:: asyncua.common.structures
:members:
:undoc-members:
:show-inheritance:
asyncua.common.structures104 module
-----------------------------------
.. automodule:: asyncua.common.structures104
:members:
:undoc-members:
:show-inheritance:
asyncua.common.subscription module
----------------------------------
.. automodule:: asyncua.common.subscription
:members:
:undoc-members:
:show-inheritance:
asyncua.common.type\_dictionary\_builder module
-----------------------------------------------
.. automodule:: asyncua.common.type_dictionary_builder
:members:
:undoc-members:
:show-inheritance:
asyncua.common.ua\_utils module
-------------------------------
.. automodule:: asyncua.common.ua_utils
:members:
:undoc-members:
:show-inheritance:
asyncua.common.utils module
---------------------------
.. automodule:: asyncua.common.utils
:members:
:undoc-members:
:show-inheritance:
asyncua.common.xmlexporter module
---------------------------------
.. automodule:: asyncua.common.xmlexporter
:members:
:undoc-members:
:show-inheritance:
asyncua.common.xmlimporter module
---------------------------------
.. automodule:: asyncua.common.xmlimporter
:members:
:undoc-members:
:show-inheritance:
asyncua.common.xmlparser module
-------------------------------
.. automodule:: asyncua.common.xmlparser
:members:
:undoc-members:
:show-inheritance:
asyncua.crypto package
======================
asyncua.crypto.permission\_rules module
---------------------------------------
.. automodule:: asyncua.crypto.permission_rules
:members:
:undoc-members:
:show-inheritance:
asyncua.crypto.security\_policies module
----------------------------------------
.. automodule:: asyncua.crypto.security_policies
:members:
:undoc-members:
:show-inheritance:
asyncua.crypto.uacrypto module
------------------------------
.. automodule:: asyncua.crypto.uacrypto
:members:
:undoc-members:
:show-inheritance:
===============
asyncua package
===============
Subpackages
===========
.. toctree::
:maxdepth: 2
asyncua.client
asyncua.common
asyncua.crypto
asyncua.server
asyncua.ua
Submodules
==========
asyncua.sync module
-------------------
.. automodule:: asyncua.sync
:members:
:undoc-members:
:show-inheritance:
asyncua.tools module
--------------------
.. automodule:: asyncua.tools
:members:
:undoc-members:
:show-inheritance:
======================
asyncua.server package
======================
Subpackages
===========
.. toctree::
:maxdepth: 4
asyncua.server.standard_address_space
Submodules
==========
asyncua.server.address\_space module
------------------------------------
.. automodule:: asyncua.server.address_space
:members:
:undoc-members:
:show-inheritance:
asyncua.server.binary\_server\_asyncio module
---------------------------------------------
.. automodule:: asyncua.server.binary_server_asyncio
:members:
:undoc-members:
:show-inheritance:
asyncua.server.event\_generator module
--------------------------------------
.. automodule:: asyncua.server.event_generator
:members:
:undoc-members:
:show-inheritance:
asyncua.server.history module
-----------------------------
.. automodule:: asyncua.server.history
:members:
:undoc-members:
:show-inheritance:
asyncua.server.history\_sql module
----------------------------------
.. automodule:: asyncua.server.history_sql
:members:
:undoc-members:
:show-inheritance:
asyncua.server.internal\_server module
--------------------------------------
.. automodule:: asyncua.server.internal_server
:members:
:undoc-members:
:show-inheritance:
asyncua.server.internal\_session module
---------------------------------------
.. automodule:: asyncua.server.internal_session
:members:
:undoc-members:
:show-inheritance:
asyncua.server.internal\_subscription module
--------------------------------------------
.. automodule:: asyncua.server.internal_subscription
:members:
:undoc-members:
:show-inheritance:
asyncua.server.monitored\_item\_service module
----------------------------------------------
.. automodule:: asyncua.server.monitored_item_service
:members:
:undoc-members:
:show-inheritance:
asyncua.server.server module
----------------------------
.. automodule:: asyncua.server.server
:members:
:undoc-members:
:show-inheritance:
asyncua.server.subscription\_service module
-------------------------------------------
.. automodule:: asyncua.server.subscription_service
:members:
:undoc-members:
:show-inheritance:
asyncua.server.uaprocessor module
---------------------------------
.. automodule:: asyncua.server.uaprocessor
:members:
:undoc-members:
:show-inheritance:
asyncua.server.user\_managers module
------------------------------------
.. automodule:: asyncua.server.user_managers
:members:
:undoc-members:
:show-inheritance:
asyncua.server.users module
---------------------------
.. automodule:: asyncua.server.users
:members:
:undoc-members:
:show-inheritance:
===============================================
asyncua.server.standard\_address\_space package
===============================================
Submodules
==========
asyncua.server.standard\_address\_space.standard\_address\_space module
-----------------------------------------------------------------------
.. automodule:: asyncua.server.standard_address_space.standard_address_space
:members:
:undoc-members:
:show-inheritance:
asyncua.server.standard\_address\_space.standard\_address\_space\_services module
---------------------------------------------------------------------------------
.. automodule:: asyncua.server.standard_address_space.standard_address_space_services
:members:
:undoc-members:
:show-inheritance:
==================
asyncua.ua package
==================
Subpackages
===========
.. toctree::
:maxdepth: 4
asyncua.ua.uaerrors
Submodules
==========
asyncua.ua.attribute\_ids module
--------------------------------
.. automodule:: asyncua.ua.attribute_ids
:members:
:undoc-members:
:show-inheritance:
asyncua.ua.object\_ids module
-----------------------------
.. note:: This module is very large and currently excluded from the API documentation
.. .. automodule:: asyncua.ua.object_ids
.. :members:
.. :undoc-members:
.. :show-inheritance:
asyncua.ua.status\_codes module
-------------------------------
.. note:: This module is very large and currently excluded from the API documentation
.. .. automodule:: asyncua.ua.status_codes
.. :members:
.. :undoc-members:
.. :show-inheritance:
asyncua.ua.ua\_binary module
----------------------------
.. automodule:: asyncua.ua.ua_binary
:members:
:undoc-members:
:show-inheritance:
asyncua.ua.uaprotocol\_auto module
----------------------------------
.. note:: This module is very large and currently excluded from the API documentation
.. .. automodule:: asyncua.ua.uaprotocol_auto
.. :members:
.. :undoc-members:
.. :show-inheritance:
asyncua.ua.uaprotocol\_hand module
----------------------------------
.. automodule:: asyncua.ua.uaprotocol_hand
:members:
:undoc-members:
:show-inheritance:
asyncua.ua.uatypes module
-------------------------
.. automodule:: asyncua.ua.uatypes
:members:
:undoc-members:
:show-inheritance:
asyncua.ua.uaerrors package
===========================
.. automodule:: asyncua.ua.uaerrors._base
:members:
:undoc-members:
:show-inheritance:
.. automodule:: asyncua.ua.uaerrors._auto
:members:
:undoc-members:
:show-inheritance:
opcua
=====
.. toctree::
:maxdepth: 4
opcua
=============
API Reference
=============
.. toctree::
:maxdepth: 4
asyncua
\ No newline at end of file
OPC-UA Client Class
=========================================
.. autoclass:: opcua.client.client.Client
:members:
:undoc-members:
.. autoclass:: opcua.client.ua_client.UaClient
:members:
:undoc-members:
This diff is collapsed.
.. Python OPC-UA documentation master file, created by
sphinx-quickstart on Sun May 3 10:13:43 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Python OPC-UA Documentation
=========================================
Pure Python OPC-UA / IEC 62541 Client and Server Python 2, 3 and pypy .
http://freeopcua.github.io/, https://github.com/FreeOpcUa/python-opcua
OPC-UA implementation is quasi complete and has been tested against many different OPC-UA stacks. API offers both a low level interface to send and receive all UA defined structures and high level classes allowing to write a server or a client in a few lines. It is easy to mix high level objects and low level UA calls in one application.
Most code is autogenerated from xml specification using same code as the one that is used for freeopcua C++ client and server, thus adding missing functionnality to client and server shoud be trivial.
Some documentation is available at http://python-opcua.readthedocs.org/en/latest/
A simple GUI client is available: https://github.com/FreeOpcUa/opcua-client-gui
Examples: https://github.com/FreeOpcUa/python-opcua/tree/master/examples
Minimal client example: https://github.com/FreeOpcUa/python-opcua/blob/master/examples/client-minimal.py
Minimal server example: https://github.com/FreeOpcUa/python-opcua/blob/master/examples/server-minimal.py
Contents:
.. toctree::
:maxdepth: 2
server
client
node
subscription
opcua
All:
modules
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
==================================
Python opcua-asyncio Documentation
==================================
Pure Python OPC-UA / IEC 62541 Client and Server for Python 3.7+ and pypy.
.. note:: This documentation is a work in progress. Documenting a project takes time, effort
and loads of coffee. We are more than happy to get feedback and merge requests relating
the documentation.
OPC-UA implementation is quasi complete and has been tested against many different OPC-UA stacks. API offers both a low level interface to send and receive all UA defined structures and high level classes allowing to write a server or a client in a few lines. It is easy to mix high level objects and low level UA calls in one application.
Most code is autogenerated from xml specification using same code as the one that is used for freeopcua C++ client and server, thus adding missing functionnality to client and server shoud be trivial.
- Some documentation is available at http://opcua-asyncio.readthedocs.org/en/latest/
- A simple GUI client is available: https://github.com/FreeOpcUa/opcua-client-gui
- Examples: https://github.com/FreeOpcUa/opcua-asyncio/tree/master/examples
- Source Code: https://github.com/FreeOpcUa/opcua-asyncio
.. toctree::
:maxdepth: 2
:caption: Contents:
:hidden:
usage/index
api/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
High level Functions and Node Class
=========================================
.. automodule:: opcua.common.node
:member-order: bysource
:members:
:undoc-members:
.. automodule:: opcua.common.manage_nodes
:members:
:undoc-members:
.. automodule:: opcua.common.methods
:members:
:undoc-members:
.. automodule:: opcua.common.event
:members:
:undoc-members:
opcua.client package
====================
Submodules
----------
opcua.client.client module
--------------------------
.. automodule:: opcua.client.client
:members:
:undoc-members:
:show-inheritance:
opcua.client.ua_client module
-----------------------------
.. automodule:: opcua.client.ua_client
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.client
:members:
:undoc-members:
:show-inheritance:
opcua.common package
====================
Submodules
----------
opcua.common.event module
-------------------------
.. automodule:: opcua.common.event
:members:
:undoc-members:
:show-inheritance:
opcua.common.instanciate module
-------------------------------
.. automodule:: opcua.common.instanciate
:members:
:undoc-members:
:show-inheritance:
opcua.common.manage_nodes module
--------------------------------
.. automodule:: opcua.common.manage_nodes
:members:
:undoc-members:
:show-inheritance:
opcua.common.methods module
---------------------------
.. automodule:: opcua.common.methods
:members:
:undoc-members:
:show-inheritance:
opcua.common.node module
------------------------
.. automodule:: opcua.common.node
:members:
:undoc-members:
:show-inheritance:
opcua.common.subscription module
--------------------------------
.. automodule:: opcua.common.subscription
:members:
:undoc-members:
:show-inheritance:
opcua.common.uaerrors module
----------------------------
.. automodule:: opcua.common.uaerrors
:members:
:undoc-members:
:show-inheritance:
opcua.common.utils module
-------------------------
.. automodule:: opcua.common.utils
:members:
:undoc-members:
:show-inheritance:
opcua.common.xmlimporter module
-------------------------------
.. automodule:: opcua.common.xmlimporter
:members:
:undoc-members:
:show-inheritance:
opcua.common.xmlparser module
-----------------------------
.. automodule:: opcua.common.xmlparser
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.common
:members:
:undoc-members:
:show-inheritance:
opcua.crypto package
====================
Submodules
----------
opcua.crypto.security_policies module
-------------------------------------
.. automodule:: opcua.crypto.security_policies
:members:
:undoc-members:
:show-inheritance:
opcua.crypto.uacrypto module
----------------------------
.. automodule:: opcua.crypto.uacrypto
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.crypto
:members:
:undoc-members:
:show-inheritance:
opcua package
=============
Subpackages
-----------
.. toctree::
opcua.client
opcua.common
opcua.crypto
opcua.server
opcua.ua
Submodules
----------
opcua.tools module
------------------
.. automodule:: opcua.tools
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua
:members:
:undoc-members:
:show-inheritance:
opcua.server package
====================
Subpackages
-----------
.. toctree::
opcua.server.standard_address_space
Submodules
----------
opcua.server.address_space module
---------------------------------
.. automodule:: opcua.server.address_space
:members:
:undoc-members:
:show-inheritance:
opcua.server.binary_server module
---------------------------------
.. automodule:: opcua.server.binary_server
:members:
:undoc-members:
:show-inheritance:
opcua.server.binary_server_asyncio module
-----------------------------------------
.. automodule:: opcua.server.binary_server_asyncio
:members:
:undoc-members:
:show-inheritance:
opcua.server.internal_server module
-----------------------------------
.. automodule:: opcua.server.internal_server
:members:
:undoc-members:
:show-inheritance:
opcua.server.internal_subscription module
-----------------------------------------
.. automodule:: opcua.server.internal_subscription
:members:
:undoc-members:
:show-inheritance:
opcua.server.server module
--------------------------
.. automodule:: opcua.server.server
:members:
:undoc-members:
:show-inheritance:
opcua.server.subscription_service module
----------------------------------------
.. automodule:: opcua.server.subscription_service
:members:
:undoc-members:
:show-inheritance:
opcua.server.uaprocessor module
-------------------------------
.. automodule:: opcua.server.uaprocessor
:members:
:undoc-members:
:show-inheritance:
opcua.server.users module
-------------------------
.. automodule:: opcua.server.users
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.server
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space package
===========================================
Submodules
----------
opcua.server.standard_address_space.standard_address_space module
-----------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part10 module
------------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part10
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part11 module
------------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part11
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part13 module
------------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part13
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part3 module
-----------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part3
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part4 module
-----------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part4
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part5 module
-----------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part5
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part8 module
-----------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part8
:members:
:undoc-members:
:show-inheritance:
opcua.server.standard_address_space.standard_address_space_part9 module
-----------------------------------------------------------------------
.. automodule:: opcua.server.standard_address_space.standard_address_space_part9
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.server.standard_address_space
:members:
:undoc-members:
:show-inheritance:
opcua.ua package
================
Submodules
----------
opcua.ua.attribute_ids module
-----------------------------
.. automodule:: opcua.ua.attribute_ids
:members:
:undoc-members:
:show-inheritance:
opcua.ua.extension_objects module
---------------------------------
.. automodule:: opcua.ua.extension_objects
:members:
:undoc-members:
:show-inheritance:
opcua.ua.object_ids module
--------------------------
.. automodule:: opcua.ua.object_ids
:members:
:undoc-members:
:show-inheritance:
opcua.ua.status_codes module
----------------------------
.. automodule:: opcua.ua.status_codes
:members:
:undoc-members:
:show-inheritance:
opcua.ua.uaprotocol_auto module
-------------------------------
.. automodule:: opcua.ua.uaprotocol_auto
:members:
:undoc-members:
:show-inheritance:
opcua.ua.uaprotocol_hand module
-------------------------------
.. automodule:: opcua.ua.uaprotocol_hand
:members:
:undoc-members:
:show-inheritance:
opcua.ua.uatypes module
-----------------------
.. automodule:: opcua.ua.uatypes
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: opcua.ua
:members:
:undoc-members:
:show-inheritance:
sphinx
sphinxcontrib-napoleon
futures
cryptography
Sphinx>=5.1.0
pydata-sphinx-theme>=0.9.0
# sphinx-copybutton>=0.5.0
# Optional Dependencies
sphinx-autobuild>=2021.3.14
\ No newline at end of file
OPC-UA Server Class
=========================================
.. autoclass:: opcua.server.server.Server
:members:
:undoc-members:
.. autoattribute:
.. autoclass:: opcua.server.internal_server.InternalServer
:members:
:undoc-members:
.. autoclass:: opcua.server.internal_server.InternalSession
:members:
:undoc-members:
.. autoclass:: opcua.server.binary_server_asyncio.BinaryServer
:members:
:undoc-members:
Subscription Class
=========================================
.. autoclass:: opcua.common.subscription.Subscription
:members:
:undoc-members:
===============
Client Overview
===============
Creating a client
=================
There is not much to it: Create a :class:`asyncua.client.client.Client` and your
ready to go. The url is usually something like ``opc.tcp:\\<server>:4840``, but you
might check your server documentation to make sure your server runs actually on this port.
Connecting to a server
======================
.. todo:: Show different examples, with / without security, ...
Learn more about the server
===========================
.. todo:: Things to show here: Namespaces, loading data type definitions, ...
Browsing and accessing nodes
============================
.. todo:: Usage of shortcut objects (root, objects, ...)
==================
NodeId's and Nodes
==================
The NodeId Class
================
:class:`asyncua.ua.uatypes.NodeId` objects are used as unique ids for :class:`~asyncua.common.node.Node`'s
and are therefore used on the server and client side to access specific nodes. The two classes
:class:`~asyncua.ua.uatypes.NodeId` and :class:`~asyncua.common.node.Node` should not
be confused: The NodeId is the unique identiefier of an actual Node. While the NodeId is used to identify
a specific node, the Node object can be used to access the underlaying data.
To learn more about the Node class, head over to :ref:`usage/common/node-nodeid:the node class`.
A NodeId contains two main informations which allow a unique mapping in the opc-ua address space:
The :attr:`~asyncua.ua.uatypes.NodeId.Identifier` and the :attr:`~asyncua.ua.uatypes.NodeId.NamespaceIndex`.
In addition there is the :attr:`~asyncua.ua.uatypes.NodeId.NodeIdType` attribute which is used
to specify which opc-ua type is used for the Identifier. In addition to the :class:`~asyncua.ua.uatypes.NodeId`
class, there is also the a :class:`~asyncua.ua.uatypes.ExpandedNodeId` which adds the
:attr:`~asyncua.ua.uatypes.ExpandedNodeId.NamespaceUri` and :attr:`~asyncua.ua.uatypes.ExpandedNodeId.ServerIndex`
attributes to make the ID unique accross different servers and namespaces.
Creating NodeId's
-----------------
As allready mentioned above, the NodeId class supports different types for the Identifier.
The type is handled automatically on class instanciation and there is usually no need
to set the type manually. Creating new NodeIds usually looks like this:
.. code-block:: python
>>> from asyncua import ua
>>> ua.NodeId(1, 2) # Integer Identifier
NodeId(Identifier=1, NamespaceIndex=2, NodeIdType=<NodeIdType.FourByte: 1>)
>>> ua.NodeId('Test', 2) # String Identifier
NodeId(Identifier='Test', NamespaceIndex=2, NodeIdType=<NodeIdType.String: 3>)
>>> ua.NodeId(b'Test', 2) # Bytes Identifier
NodeId(Identifier=b'Test', NamespaceIndex=2, NodeIdType=<NodeIdType.ByteString: 5>)
A NodeId can also be built from a single string:
.. code-block:: python
>>> ua.NodeId.from_string('ns=2;i=4')
NodeId(Identifier=4, NamespaceIndex=2, NodeIdType=<NodeIdType.Numeric: 2>)
>>> ua.NodeId.from_string('ns=2;s=Test')
NodeId(Identifier='Test', NamespaceIndex=2, NodeIdType=<NodeIdType.String: 3>)
The input string must be in the format :code:`<key>=<val>;[<key>=<val>]`, or in words:
it must be a list of key-value pairs, separated by semicolons.
The following keys are supported:
ns
The ns key will map to the Namespace of the NodeId
i, s, g, b
These keys will map to the Identifier of the NodeId. The character specifies the
type: Numeric, String, Guid or Bytes.
srv, nsu:
If one of this keys is set, a :class:`~asyncua.ua.uatypes.ExpandedNodeId` will be returned
and the ServerIndex and NamespaceUri will be set.
What else?
----------
The :class:`~asyncua.ua.uatypes.NodeId` class is actually just a normal UA data-type like
other objects as :class:`~asyncua.ua.uatypes.QualifiedName` or :class:`~asyncua.ua.uatypes.Variant`
are. The asyncua package models all datatypes as :mod:`dataclasses`, for some types, like
the NodeId some additional logic is implemented to make it easier to work with them.
The Node Class
==============
The :class:`~asyncua.common.node.Node` class is a central part used on the server and client.
On the server side nodes are created and configured as well as read and written. On the client
side we can browser through the nodes and access and manipulate their values. Nodes should not
be confused with :class:`~asyncua.ua.uatypes.NodeId`: Each node has a NodeId an can be access
by it, so the NodeId is a unique identiefier within the server to reference a Node.
The Node class exposes a wide range of the OPC-UA protocol for easy access, however, to fully
optimize your code you will need to use lower level functions. Beside that, for many usecases
the Node class might be the right thing to use for simpler usecases and makes it certainly
easier to get started with OPC-UA.
Accessing Nodes
---------------
As mentioned above, the Node class provides access to a lot of functionality, on the server
and client side. Therefore, both, the server and client, provide a :code:`get_node` method:
:meth:`asyncua.client.client.Client.get_node` & :meth:`asyncua.server.server.Server.get_node`.
These functions can be used to get a node by it's NodeId, for example:
.. code-block::
>>> client.get_node("ns=2;i=2")
Node(NodeId(Identifier=2, NamespaceIndex=2, NodeIdType=<NodeIdType.Numeric: 2>))
Note that using :code:`get_node` does not check if the node actually exists! The method
just creates a new node which later can be used to query data.
.. note:: As a rule of thumb: If the method is synchronous, there is no communication between
server and client. In such cases only input validation is performed.
The node now can be used to read / write / ... data from the server:
.. code-block::
>>> node = client.get_node("ns=2;i=2")
>>> name = (await node.read_browse_name()).Name
>>> value = (await node.read_value())
>>> print(f"{name} = {value}")
MyVariable = 16.59999
>>> await node.write_value(5.0) # Must use 5.0, see note below
>>> value = (await node.read_value())
>>> print(f"{name} = {value}")
MyVariable = 5.1
Writing values using :meth:`~asyncua.common.node.Node.write_value` can be tricky in some cases
as the method converts the python type to a OPC-UA datatype. In the example above we explicitly
need to pass in a :code:`float` to enforce a conversion to a :attr:`~asyncua.ua.uatypes.VariantType.Double`.
If :code:`5` is passed in, the value will be sent as a :attr:`VariantType.Int64`, which would
result in a error as the sent datatype does not match the expected type on the server side.
.. todo:: If there is ever a section which goes into more detail, add a link!
The node object can also be used to browse to other nodes. There are several methods available
as shown in the following short example:
.. code-block::
>>> # Get the parent of a node
>>> parent = await node.get_parent()
>>> print(parent)
Node(NodeId(Identifier=1, NamespaceIndex=2, NodeIdType=<NodeIdType.FourByte: 1>))
>>> # Get all children of a node
>>> await parent.get_children()
[Node(NodeId(Identifier=2, NamespaceIndex=2, NodeIdType=<NodeIdType.FourByte: 1>))]
>>> # Get a specific child (by NodeId) of a node
>>> await parent.get_child("2:MyVariable")
Node(NodeId(Identifier=2, NamespaceIndex=2, NodeIdType=<NodeIdType.FourByte: 1>))
Note that in the last example we use the browse path of child as argument to
:meth:`~asyncua.common.node.Node.get_child`. With the same method it's also possible
to access a child several levels deeper than the current node:
.. code-block::
>>> await c.nodes.objects.get_child(['2:MyObject', '2:MyVariable'])
Node(NodeId(Identifier=2, NamespaceIndex=2, NodeIdType=<NodeIdType.FourByte: 1>))
Here we start at the objects node an traverse via MyObject to MyVariable. Allways keep in
mind that browsing through the nodes will create network traffic and server load. If
you allready know the NodeId using :meth:`~asyncua.client.client.Client.get_node` should
be prefered. You might also consider caching NodeIds which you found through browsing
to reduce the traffic.
\ No newline at end of file
===============
Common Overview
===============
OPC-UA is built around the concept of namespaces and nodes. This concept is
present in the server and the client and therefore much of the code is shared
by both. In this section we take a look at the shared part of the library.
The shared code lives in the :mod:`asyncua.common`, :mod:`asyncua.ua`
and :mod:`asyncua.crypto` packages and the most important classes and methods
from these packages will be discussed in the following sections.
asyncua.common package
======================
The :mod:`asyncua.common` package is provides the core functionality of the library.
Several important parts life in this subpackage, for example the :class:`~asyncua.common.node.Node`
class and the :mod:`~asyncua.common.subscription` module. You can find usage exampels
of these classes and functionalities in the following sections.
asyncua.ua package
==================
The :mod:`asyncua.ua` package contains mostly autogenerated code which reflects the standard
objects, attributes and status codes provided by the OPC-UA standard.
asyncua.crypto package
======================
Code related to permissions, security and encryption is located in the :mod:`asyncua.crypto`
package.
========================
Installation & CLI Tools
========================
Package Installation
====================
The opcua-asyncio package is available `PyPi <https://pypi.org/project/asyncua/>`_ as :code:`asyncua` package.
To install the package execute
.. code-block:: console
pip install asyncua
As the package is still under very active development you might also consider to install the package from the
source repository
.. code-block:: console
pip install git+https://github.com/FreeOpcUa/opcua-asyncio.git#egg=asyncua
# or, if git is not available
pip install https://github.com/FreeOpcUa/opcua-asyncio/archive/refs/heads/master.zip#egg=asyncua
Once the installation is completed, the package is ready to be used. To verify the installation,
or the report the version if you create a bugreport, the following code can be run in a python interpreter:
.. code-block:: python
import asyncua
print(asyncua.__version__)
Command Line Tools
==================
Alongside the package some utility command line tools are installed:
:code:`uabrowse`:
Browse OPC-UA node and print result
:code:`uacall`:
Call method of a node
:code:`uaclient`:
Connect to server and start python shell. root and objects nodes are available.Node specificed in command line is available as mynode variable.
:code:`uadiscover`:
Performs OPC UA discovery and prints information on servers and endpoints.
:code:`uageneratestructs`:
Generate a Python module from the xml structure definition (.bsd), the node argument is typically a children of i=93.
:code:`uahistoryread`:
Read history of a node.
:code:`uals`:
Browse OPC-UA node and print result.
:code:`uaread` / :code:`uawrite`:
Read / Write attribute of a node, per default reads value of a node.
:code:`uaserver`:
Run an example OPC-UA server. By importing xml definition and using uawrite command line, it is even possible to expose real data using this server.
:code:`uasubscribe`:
Subscribe to a node and print results
These command line tools can be used from within the environment in which the package was installed. To get more information run:
.. code-block:: console
<ua-tool> --help
# For example
uaread --help
More Tools for Development
==========================
.. todo:: Create a list of additional tools which are nice to have during development
Possible Tools:
- opcua-client (https://github.com/FreeOpcUa/opcua-client-gui)
- UaModeler (https://www.unified-automation.com/products/development-tools/uamodeler.html)
\ No newline at end of file
=======================
A Minimal OPC-UA Client
=======================
In this section we will build a client which reads / writes data from the server
created in the last section and calls the method which the server provides.
Running the client code will require a running server of course, so open a new
terminal and run :code:`python server-minimal.py` to start the server.
Like in the server section, we will first look at the complete code of the client
before diving into the details:
.. literalinclude:: ../../../examples/client-minimal.py
:caption: client-minimal.py
:linenos:
Connecting to the server
========================
To connect to the server a new :class:`~asyncua.client.client.Client` instance is created.
The client supports the same async context manager construct as we have already seen in
the server, which can be used to handle the opening / closing of the connection for us.
Getting the namespace
=====================
As all our custom objects life in a custom namespace, we need to get the namespace
index to address our objects. This is done with the :meth:`~asyncua.client.client.Client.get_namespace_index`
method. If you are connecting to a unknown server and want to find out which namespaces
are available the :meth:`~asyncua.client.client.Client.get_namespace_array` method can be used to
fetch a list of all namespaces of the server.
Read / Write Variables
======================
To read or write a variable of an object, we first need to get the :class:`~asyncua.common.node.Node`
of the variable. The :meth:`~asyncua.common.node.Node.get_child` method of the root node
(which is just a regular node) is used to transform the known path to a Node.
.. note:: Using :meth:`~asyncua.common.node.Node.get_child` will perform a server request
in the background to resolve the path to a node. Extensive usage of this method can
create a lot of network traffic which is not strictly required if the node id is knwon.
If you know the node id it's better to use the :meth:`~asyncua.client.client.Client.get_node`
method of the client. For example :code:`client.get_node("ns=2;i=2")` or
:code:`client.get_node(ua.NodeId(2, 2))` could be used in the example.
Note that the call is not :code:`async`!
Once we have our node object, the variable value can directly be read or written using
the :meth:`~asyncua.common.node.Node.read_value` and :meth:`~asyncua.common.node.Node.write_value`
methods. The read method automatically transforms the opc-ua type to a python type but the
:meth:`~asyncua.common.node.Node.read_data_value` method can be used if the original type of
the variable is of interest. The write interface is built flexible and a :class:`~asyncua.ua.uatypes.Variant`
is also accepted to specify the exact type to be used.
Calling Methods
===============
The method interface is similar to the interface of variables. In the example the special
node :code:`client.nodes.objects`, wich is in fact just a shortcut to the :code:`0:Objects`
node, is used to call the `2:ServerMethod` on it. The :meth:`~asyncua.common.node.Node.call_method`
must be called on the parent node of the actuall method node.
\ No newline at end of file
=======================
A Minimal OPC-UA Server
=======================
Let's start exploring the :code:`asyncua` package by building a minimal runnable server.
Most of the hard work will be hidden behind the scene and we only need to implement the
application specific code.
The complete code will look like the code below. In the next sections we will look at
the different parts of the code, so don't be overhelmed by the code snippet!
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py
:linenos:
Before we even look at the code in detail, let's try out what our server can do.
Start the server in a terminal with :code:`python server-minimal.py` and open a new console.
In the new console you now can use the CLI tools (see :ref:`usage/get-started/installation:command line tools`) provided by the package to explore
the server. The following session gives you an idea how the tools can be used.
.. code-block:: console
$ uals --url=opc.tcp://127.0.0.1:4840 # List root node
Browsing node i=84 at opc.tcp://127.0.0.1:4840
DisplayName NodeId BrowseName Value
LocalizedText(Locale=None, Text='Objects') i=85 0:Objects
LocalizedText(Locale=None, Text='Types') i=86 0:Types
LocalizedText(Locale=None, Text='Views') i=87 0:Views
$ uals --url=opc.tcp://127.0.0.1:4840 --nodeid i=85 # List 0:Objects
Browsing node i=85 at opc.tcp://127.0.0.1:4840
DisplayName NodeId BrowseName Value
LocalizedText(Locale=None, Text='Server') i=2253 0:Server
LocalizedText(Locale=None, Text='Aliases') i=23470 0:Aliases
LocalizedText(Locale=None, Text='MyObject') ns=2;i=1 2:MyObject
LocalizedText(Locale=None, Text='ServerMethod') ns=2;s=ServerMethod 2:ServerMethod
$ # In the last two lines we can see our own MyObject and ServerMethod
$ # Lets read a value!
$ uaread --url=opc.tcp://127.0.0.1:4840 --nodeid "ns=2;i=2" # By NodeId
7.599999999999997
$ uaread --url=opc.tcp://127.0.0.1:4840 --path "0:Objects,2:MyObject,2:MyVariable" # By BrowsePath
12.199999999999996
Seems like our server is working and we can browse through the nodes, read values, ...
So let's start working through the code!
Imports, Basic Setup & Configuration
====================================
In the first few lines the relevant packages, classes and methods are imported.
While the :mod:`logging` module is optional (just remove all calls to the logging module),
:mod:`asyncio` is required to actually run our main function. From the :mod:`asyncua`
package we need the :class:`~asyncua.server.server.Server`, the :mod:`asyncua.ua`
module and the :meth:`~asyncua.common.methods.uamethod` decorator.
Ignore the :code:`@uamethod ...` part for the moment and jump straight into the
:code:`async def main()` function:
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py, Line 13 - 22
:lines: 13-22
.. todo:: The :meth:`~asyncua.server.server.Server.init` and :meth:`~asyncua.server.server.Server.set_endpoint`
methods have no docstrings but are referenced in the next section.
Here the server is created and initialized (:meth:`~asyncua.server.server.Server.init`).
The endpoint is configured (:meth:`~asyncua.server.server.Server.set_endpoint`) and a custom namespace
is registered (:meth:`~asyncua.server.server.Server.register_namespace`). It's recommended (:emphasis:`required??`)
that all custom objects, variables and methods life in a separate namespace. As we later need the
namespace index to our objects to it, the index is stored as :code:`idx`.
Creating Objects and Variables
==============================
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py, Line 26 - 29
:lines: 26-29
In the next lines, the custom object "MyObject" is created and a variable is added to this object.
Note that by default all variables are read-only, so we need to be explicit and make it writable.
The :meth:`~asyncua.common.node.Node.add_object` / :meth:`~asyncua.common.node.Node.add_object` calls
are actually just calling :meth:`~asyncua.common.manage_nodes.create_object`, respectively
:meth:`~asyncua.common.manage_nodes.create_variable` internally. You can find more information on
how nodes and variables are created in the API docs of these methods.
Adding Methods
==============
With the code we have written so far, we would already have a server which can be run and
exposes some custom data. But to complete the example, we also add a method which is callable
by clients:
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py, Line 8 - 11
:lines: 8 - 11
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py, Line 30 - 36
:lines: 30 - 36
To do this, a function, decorated with the :meth:`~asyncua.common.methods.uamethod` decorator,
is created and, similar to the objects and variables, registered on the server. It would
also be possible to register a undecorated function on the server, but in this case the
coversion from and to UA Variant types would be up to us.
Starting the Server
===================
.. literalinclude:: ../../../examples/server-minimal.py
:caption: server-minimal.py, Line 37 -
:lines: 37 -
Using the server as a context manager with :code:`async with server: ...` allows us to
hide starting and shutting down the server nicely. In order to keep the server alive
a endless loop must be present. In the this example the loop is also used to periodically
update the variable on our custom object.
Now that we have a working server, let's go on and write :ref:`usage/get-started/minimal-client:a minimal opc-ua client`!
\ No newline at end of file
=============
OPC-UA Basics
=============
.. todo:: How much should be in this chapter?
Are we only going to link to external references and skip explaining the OPC-UA basics?
The `open62541 documentation <http://www.open62541.org/doc/master/>`_ for example
contains a lot of information about how OPC-UA works but in many chapters it also
assumes the reader is interested how the library works. Where do we need to start
such that new users can later understand how the concepts of OPC-UA are represented
by this library?
External References
===================
.. note:: We are open to sugguestions for this section!
You know good tutorials, help pages, blogs or other resources? Share them with us!
https://reference.opcfoundation.org
Luckily the complete documentation about OPC-UA is available for free. As this is
the official reference documentation, you will find links to this page in the
source code of this package and also in this documentation where necesary.
https://www.open62541.org
Open Source (MPL v2.0) OPC UA stack implemented in C. If you need a library which
runs on your embedded device have a look at it! Also the documentation is great
and contains a lot of details about the architecture and datamodeling in OPC-UA.
https://www.unified-automation.com
Unified Automation provides different products for the OPC-UA ecosystem. Most of the
tools are avialable as a free download with a evaluation license (non commercial use).
===========
Usage Guide
===========
.. toctree::
:maxdepth: 2
:caption: Get started
get-started/installation
get-started/opc-ua-basics
get-started/minimal-server
get-started/minimal-client
.. toctree::
:maxdepth: 2
:caption: Common
common/overview
common/node-nodeid
.. toctree::
:maxdepth: 2
:caption: Client
client/overview
.. toctree::
:maxdepth: 2
:caption: Server
server/overview
.. toctree::
:maxdepth: 2
:caption: Sync Interface
sync/overview
Server Overview
===============
\ No newline at end of file
=====================
Synchronous Interface
=====================
You don't like to work with ``asyncio`` and ``async`` / ``await`` or you need to integrate
the package in code wich is not using ``asyncio``? The :mod:`asyncua.sync` module provides
a convinient wrapper around the client and server and provides synchronous versions of
the node and subscription classes. This allows direct usage of the package, using the same
interface as for ``async`` code, without writing custom wrappers.
\ No newline at end of file
# User Management
## Overview
Currently user management on OPC-UA servers here is done exclusively through certificates, though there is the potential to create new user management objects.
How this works in practice is that every user generates a certificate/private key pair, and then the certificate is given
to the OPC-UA server. The administrator of the OPC-UA server enters the certificate into the `certificate_user_manager` with a `UserRole`
and a `name`. When a user connects with this certificate, every action they do will be associated with their name in the logs,
and the `permission_ruleset` will determine whether a user with that role can carry out that action.
## Usage
an example of usage is in `examples/server-with-encryption.py`:
```python
user_manager = CertificateUserManager()
await user_manager.add_user("certificates/peer-certificate-example-1.der", name='user1')
server = Server(user_manager=user_manager)
await server.init()
server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
server.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt],
permission_ruleset=SimpleRoleRuleset())
```
We can see here that a certificate user manager object is made, and told to assign peer-certificate-example-1 with User credentials.
When the client wants to actually carry out some actions, the user manager `CertificateUserManager` will use the
certificate handler to associate a user to the certificate, and then the `permission_ruleset` will determine if they are
allowed to do the action.
## Custom permission rules
The permission ruleset object has been designed in a way to allow new rulesets to be made easily. For example, lets look
at the implementation of `SimpleRoleRuleset`:
```python
class SimpleRoleRuleset(PermissionRuleset):
"""
Standard simple role-based ruleset.
Admins alone can write, admins and users can read, and anonymous users can't do anything.
"""
def __init__(self):
write_ids = list(map(ua.NodeId, WRITE_TYPES))
read_ids = list(map(ua.NodeId, READ_TYPES))
self._permission_dict = {
UserRole.Admin: set().union(write_ids, read_ids),
UserRole.User: set().union(read_ids),
UserRole.Anonymous: set()
}
def check_validity(self, user, action_type_id, body):
if action_type_id in self._permission_dict[user.role]:
return True
else:
return False
```
all that is needed to create a permission ruleset is to create a function `check_validity` which takes information about
the user and the action type, and returns `True` if it is allowed, or `False` if it isn't. In this case, we simply take the
user role and compare the action it wants to do with a list of actions stored in a dictionary. A more complex ruleset could use the body
of the request to determine some users as being able to write some variables, but not others. Another potential option is
having more user roles than those we have set here.
\ No newline at end of file
import asyncio
import sys
# sys.path.insert(0, "..")
import logging
from asyncua import Client, Node, ua
logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger('asyncua')
from asyncua import Client
url = "opc.tcp://localhost:4840/freeopcua/server/"
namespace = "http://examples.freeopcua.github.io"
async def main():
url = 'opc.tcp://localhost:4840/freeopcua/server/'
# url = 'opc.tcp://commsvr.com:51234/UA/CAS_UA_Server'
print(f"Connecting to {url} ...")
async with Client(url=url) as client:
# Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
# Node objects have methods to read and write node attributes as well as browse or populate address space
_logger.info('Children of root are: %r', await client.nodes.root.get_children())
uri = 'http://examples.freeopcua.github.io'
idx = await client.get_namespace_index(uri)
# get a specific node knowing its node id
# var = client.get_node(ua.NodeId(1002, 2))
# var = client.get_node("ns=3;i=2002")
var = await client.nodes.root.get_child(["0:Objects", f"{idx}:MyObject", f"{idx}:MyVariable"])
print("My variable", var, await var.read_value())
# print(var)
# await var.read_data_value() # get value of node as a DataValue object
# await var.read_value() # get value of node as a python builtin
# await var.write_value(ua.Variant([23], ua.VariantType.Int64)) #set node value using explicit data type
# await var.write_value(3.9) # set node value using implicit data type
if __name__ == '__main__':
# Find the namespace index
nsidx = await client.get_namespace_index(namespace)
print(f"Namespace Index for '{namespace}': {nsidx}")
# Get the variable node for read / write
var = await client.nodes.root.get_child(
["0:Objects", f"{nsidx}:MyObject", f"{nsidx}:MyVariable"]
)
value = await var.read_value()
print(f"Value of MyVariable ({var}): {value}")
new_value = value - 50
print(f"Setting value of MyVariable to {new_value} ...")
await var.write_value(new_value)
# Calling a method
res = await client.nodes.objects.call_method(f"{nsidx}:ServerMethod", 5)
print(f"Calling ServerMethod returned {res}")
if __name__ == "__main__":
asyncio.run(main())
import logging
import asyncio
import sys
sys.path.insert(0, "..")
import logging
from asyncua import ua, Server
from asyncua import Server, ua
from asyncua.common.methods import uamethod
@uamethod
def func(parent, value):
return value * 2
async def main():
_logger = logging.getLogger('asyncua')
_logger = logging.getLogger("asyncua")
# setup our server
server = Server()
await server.init()
server.set_endpoint('opc.tcp://0.0.0.0:4840/freeopcua/server/')
server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
# setup our own namespace, not really necessary but should as spec
uri = 'http://examples.freeopcua.github.io'
uri = "http://examples.freeopcua.github.io"
idx = await server.register_namespace(uri)
# populating our address space
# server.nodes, contains links to very common nodes like objects and root
myobj = await server.nodes.objects.add_object(idx, 'MyObject')
myvar = await myobj.add_variable(idx, 'MyVariable', 6.7)
myobj = await server.nodes.objects.add_object(idx, "MyObject")
myvar = await myobj.add_variable(idx, "MyVariable", 6.7)
# Set MyVariable to be writable by clients
await myvar.set_writable()
await server.nodes.objects.add_method(ua.NodeId('ServerMethod', 2), ua.QualifiedName('ServerMethod', 2), func, [ua.VariantType.Int64], [ua.VariantType.Int64])
_logger.info('Starting server!')
await server.nodes.objects.add_method(
ua.NodeId("ServerMethod", idx),
ua.QualifiedName("ServerMethod", idx),
func,
[ua.VariantType.Int64],
[ua.VariantType.Int64],
)
_logger.info("Starting server!")
async with server:
while True:
await asyncio.sleep(1)
new_val = await myvar.get_value() + 0.1
_logger.info('Set value of %s to %.1f', myvar, new_val)
_logger.info("Set value of %s to %.1f", myvar, new_val)
await myvar.write_value(new_val)
if __name__ == '__main__':
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
asyncio.run(main(), debug=True)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment