Commit ba62172e authored by Gino Tosti's avatar Gino Tosti
Browse files

minor changes based on the removal of the blank row on the ICD files and...

minor changes based on the removal of the blank row on the ICD files and addition of a python opcuaserver generator for fast check and development of complex Device simulations
parent 1d22239b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
from GenDevice.acsUtils import *
import shutil
import os
managerxml="""<?xml version="1.0" encoding="ISO-8859-1"?>
<Manager   xmlns:cdb="urn:schemas-cosylab-com:CDB:1.0" 
           xmlns="urn:schemas-cosylab-com:Manager:1.0" 
@@ -69,8 +70,7 @@ def setCDBEnvVar(dirname):
	pwd = os.getcwd()
	os.chdir(dirname)
	f=open("setCDB.sh","w")
	f.write("ACS_CDB="+dirname+"\n")
	f.write("export ACS_CDB\n")
	f.write("export ACS_CDB="+os.path.abspath(dirname)+"\n")
	f.close()
	os.chdir(pwd)
	return
+59 −0
Original line number Diff line number Diff line
@@ -37,3 +37,62 @@ $>cd $PYGEN/test

$>python runGenDeviceGUI.py

<NEWS - 01/07/21>

An experimental simulation OPC-UA server written in python can be also generatedwith this version of pyGen. Arrays are not supported at present, then to play with it use ICD that do not include arrays.

Before to use it you need to install some libraries:

———Python OPCUA support libraries —-
the ACS environment  must be active
library needed by Qt
from root /sudo 
yum install libxcb
yum install xcb-util-wm
yum install xcb-util-image
yum install xcb-util-keysyms
yum install xcb-util-renderutil

from user account:
Install pyQT
 pip3 install --user PyQt5
 pip3 install --user pyqtgraph

Install python opcua https://github.com/FreeOpcUa/python-opcua

 pip3 install --user opcua
 pip3 install --user opcua-client

The documentation on python opcua is here:
https://github.com/FreeOpcUa/python-opcua

--------Simulation server generation----------
$>cd $PYGEN/test
$>python makeTestOPCUAServer.py -f <your ICD file .xls/xlsx> -o <ServerOutputDir> 
the input ICD file  shall be the same used to generate the ACS component.The default output dir is "./SimulationOPCUAserver"
in the output you have someting like:
....
....
Working on: ['MyDevice']
File: /home/astrisw/pyGen/test/SimulationOPCUAserver/MyDeviceServerModel.xml  created
File: /home/astrisw/pyGen/test/SimulationOPCUAserver/MyDevice_opcuaServer.py  created
The Simulation server can be reached at: opc.tcp://127.0.0.1:52523/OPCUA/hwSimulator

$>cd ServerOutputDir
$>python <DeviceName>_upcuaServer.py

you should see something like this output:

Server Started!
Python 3.6.9 (default, Sep  3 2020, 15:28:31) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.8.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

Insert exit at the In[1] prompt above.

To check the server open another terminal and insert the command:
$>opcua-client
Insert for example:"opc.tcp://127.0.0.1:52523/OPCUA/hwSimulator" in the input box on top left of the client and click on the "Connect button". You can play with the servers nodes now.
+92 −0
Original line number Diff line number Diff line
import uuid
from threading import Thread
import copy
import logging
from datetime import datetime
import time
from math import sin
import sys
import random

from opcua.ua import NodeId, NodeIdType

sys.path.insert(0, "..")

try:
    from IPython import embed
except ImportError:
    import code

    def embed():
        myvars = globals()
        myvars.update(locals())
        shell = code.InteractiveConsole(myvars)
        shell.interact()

from opcua import ua, uamethod, Server


class SubHandler(object):
    """
    Subscription Handler. To receive events from server for a subscription
    """

    def datachange_notification(self, node, val, data):
        print("Python: New data change event", node, val)

    def event_notification(self, event):
        print("Python: New event", event)

class VarUpdater(Thread):
    def __init__(self, var):
        Thread.__init__(self)
        self._stopev = False
        self.var = var

    def stop(self):
        self._stopev = True
    def run(self):
        while not self._stopev:
            for v in self.var:
                ty=v.get_data_type_as_variant_type()
                if ty!=ua.VariantType.String and ty!=ua.VariantType.Boolean: 
                    v.set_value(v.get_value()+random.uniform(-5,5))
            time.sleep(2)



if __name__ == "__main__":
    # optional: setup logging
    logging.basicConfig(level=logging.ERROR)

    server = Server()
    #server.disable_clock()
    #server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
    server.set_endpoint("$Url")
    server.set_server_name("$Assembly Simulation Server")
    # set all possible endpoint policies for clients to connect through
    server.set_security_policy([
                ua.SecurityPolicyType.NoSecurity,
                ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
                ua.SecurityPolicyType.Basic256Sha256_Sign])

    uri = "http://localhost/$Assembly/"
    idx = server.register_namespace(uri)
    # import some nodes from xml
    server.import_xml("$Model")

    root = server.get_root_node()
    obj=root.get_children()[0].get_children()
    get=obj[2].get_children()

    # starting Server
    server.start()
    vup = VarUpdater(get)  # update a monitoring variables only Numeric variables
    vup.start() 
    print("Server Started!")
    try:
        embed()
    finally:
        vup.stop()
        server.stop()
        print("Server Stopped!")
+165 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.02"          LastModified="2013-03-06T05:36:44.0862658Z" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd">
<!-- *  Generated by: $Author
 *  Date: $Date
 *  Description: $Description !-->
<NamespaceUris>
          <Uri>http://localhost/$Assembly/</Uri>
</NamespaceUris>

<Aliases> <Alias Alias="Boolean">i=1</Alias> 
<Alias Alias="SByte">i=2</Alias>
<Alias Alias="Byte">i=3</Alias> 
<Alias Alias="Int16">i=4</Alias> 
<Alias Alias="UInt16">i=5</Alias> 
<Alias Alias="Int32">i=6</Alias> 
<Alias Alias="UInt32">i=7</Alias> 
<Alias Alias="Int64">i=8</Alias> 
<Alias Alias="UInt64">i=9</Alias> 
<Alias Alias="Float">i=10</Alias> 
<Alias Alias="Double">i=11</Alias> 
<Alias Alias="DateTime">i=13</Alias> 
<Alias Alias="String">i=12</Alias> 
<Alias Alias="ByteString">i=15</Alias> 
<Alias Alias="Guid">i=14</Alias> 
<Alias Alias="XmlElement">i=16</Alias> 
<Alias Alias="NodeId">i=17</Alias> 
<Alias Alias="ExpandedNodeId">i=18</Alias> 
<Alias Alias="QualifiedName">i=20</Alias> 
<Alias Alias="LocalizedText">i=21</Alias> 
<Alias Alias="StatusCode">i=19</Alias> 
<Alias Alias="Structure">i=22</Alias> 
<Alias Alias="Number">i=26</Alias> 
<Alias Alias="Integer">i=27</Alias> 
<Alias Alias="UInteger">i=28</Alias> 
<Alias Alias="HasComponent">i=47</Alias> 
<Alias Alias="HasProperty">i=46</Alias> 
<Alias Alias="Organizes">i=35</Alias> 
<Alias Alias="HasEventSource">i=36</Alias> 
<Alias Alias="HasNotifier">i=48</Alias> 
<Alias Alias="HasSubtype">i=45</Alias> 
<Alias Alias="HasTypeDefinition">i=40</Alias> 
<Alias Alias="HasModellingRule">i=37</Alias> 
<Alias Alias="HasEncoding">i=38</Alias> 
<Alias Alias="HasDescription">i=39</Alias> 
<Alias Alias="Range">i=884</Alias>
</Aliases>


<UAObject NodeId="ns=4;i=1" BrowseName="2:${Assembly}Folder">
  <DisplayName>${Assembly}</DisplayName>
  <Description>The folder of the Assembly</Description>
  <References>
      <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
      <Reference ReferenceType="HasTypeDefinition">i=61</Reference>
  </References>
</UAObject>
<UAObject NodeId="ns=4;i=2" BrowseName="3:${Assembly}_Get_Points" ParentNodeId="ns=4;i=1">
  <DisplayName>${Assembly} Monitoring Variables</DisplayName>
  <Description>The folder of the Assembly Monitoring Variables</Description>
  <References>
      <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
      <Reference ReferenceType="HasTypeDefinition">ns=4;i=1</Reference>
  </References>
</UAObject>
<UAObject NodeId="ns=4;i=3" BrowseName="3:${Assembly}_Set_Points" ParentNodeId="ns=4;i=1">
  <DisplayName>${Assembly} Setting Variables</DisplayName>
  <Description>The folder of the Assembly Setting Variables</Description>
  <References>
      <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
      <Reference ReferenceType="HasTypeDefinition">ns=4;i=1</Reference>
  </References>
</UAObject>
<UAObject NodeId="ns=4;i=4" BrowseName="3:${Assembly}_Mode_cmd" ParentNodeId="ns=4;i=1">
  <DisplayName>${Assembly} Mode Variables</DisplayName>
  <Description>The folder of the Assembly Setting Variables</Description>
  <References>
      <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
      <Reference ReferenceType="HasTypeDefinition">ns=4;i=1</Reference>
  </References>
</UAObject>
<UAObject NodeId="ns=4;i=5" BrowseName="3:${Assembly}_Commands" ParentNodeId="ns=4;i=1">
  <DisplayName>${Assembly} Command Variables</DisplayName>
  <Description>The folder of the Assembly Monitoring Variables</Description>
  <References>
      <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
      <Reference ReferenceType="HasTypeDefinition">ns=4;i=1</Reference>
  </References>
</UAObject>
#silent L=[]
#for $idx in $range(0,$x["NRows"])
#silent L.append($x["Short name"][$idx])
#if ($x["OPC UA Data type"][$idx]).upper()[-1]==']' ## test for arrays
 #set $type=($x["OPC UA Data type"][$idx].upper()).split("[")[0].capitalize()
#else
  #set $type=$x["OPC UA Data type"][$idx].capitalize()
<UAVariable NodeId="$x['OPC_UA node'][$idx]" BrowseName="4:$x['Name of command'][$idx]" DataType="$type" ParentNodeId="ns=4;i=2">
  <DisplayName>$x['Name of command'][$idx]</DisplayName>
  <Description>$x['Description'][$idx]</Description>
  <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasProperty" IsForward="false">ns=4;i=2</Reference>
  </References>
      <Value>
      <uax:$type>$x['Default value'][$idx]</uax:$type>
  </Value>
</UAVariable>
#end if
#end for
#for $idx in $range(0,$y["NRows"])
#silent L.append($y["Short name"][$idx])
#if ($y["OPC UA Data type"][$idx]).upper()[-1]==']' ## test for arrays
  #set $type=($y["OPC UA Data type"][$idx].upper()).split("[")[0].capitalize()
#else
  #set $type=$y["OPC UA Data type"][$idx].capitalize()
#end if
  <UAVariable NodeId="$y['OPC_UA node'][$idx]" BrowseName="4:$y['Name of command'][$idx]" DataType="$type" ParentNodeId="ns=4;i=3" UserAccessLevel="3" AccessLevel="3">
  <DisplayName>$y['Name of command'][$idx]</DisplayName>
  <Description>$y['Description'][$idx]</Description>
  <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasProperty" IsForward="false">ns=4;i=3</Reference>
  </References>
      <Value>
      <uax:$type>$y['Default value'][$idx]</uax:$type>
  </Value>
</UAVariable>  
#end for
#for $idx in $range(0,$m["NRows"])
#set $name=($m["OPC_UA node"][$idx].split(";")[1]).split("=")[1].replace(".","_")
#if not $name in L
    #set $type=$m["OPC UA Data type"][$idx].capitalize()
   <UAVariable NodeId="$m['OPC_UA node'][$idx]" BrowseName="4:$name" DataType="$type" ParentNodeId="ns=4;i=4" UserAccessLevel="3" AccessLevel="3">
  <DisplayName>$name</DisplayName>
  <Description>$m['Description'][$idx]</Description>
  <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasProperty" IsForward="false">ns=4;i=4</Reference>
  </References>
      <Value>
      <uax:$type>$m['Default value'][$idx]</uax:$type>
  </Value>
</UAVariable> 
#silent L.append($name)
#end if
#end for
#for $idx in $range(0,$c["NRows"])
#set $name=($c["OPC_UA node"][$idx].split(";")[1]).split("=")[1].replace(".","_")
#if not $name in L
    #set $type=$c["OPC UA Data type"][$idx].capitalize()
   <UAVariable NodeId="$c['OPC_UA node'][$idx]" BrowseName="4:$c['Name of command'][$idx]" DataType="$type" ParentNodeId="ns=4;i=5" UserAccessLevel="3" AccessLevel="3">
  <DisplayName>$c['Name of command'][$idx]</DisplayName>
  <Description>$c['Description'][$idx]</Description>
  <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasProperty" IsForward="false">ns=4;i=5</Reference>
  </References>
      <Value>
      <uax:$type>$c['Default value'][$idx]</uax:$type>
  </Value>
</UAVariable> 
#silent L.append($name)
#end if
#end for

</UANodeSet>
+8 −8
Original line number Diff line number Diff line
@@ -15,9 +15,9 @@ import glob

outdir="/tmp/"

def manageICDFiles(dev,outdir,smain,wb):
def manageICDFiles(dev,outdir,wb):
	query="`Device Name` =="+ "'"+dev+"'"
	main=smain.query(query)
	main=(wb.book.parse("Main")).query(query)
	get=(wb.book.parse("GET")).query(query)
	sett=(wb.book.parse("SET")).query(query)
	cmd=(wb.book.parse("CMD")).query(query)
@@ -78,10 +78,10 @@ if __name__ =="__main__":
	pwd=os.getcwd()
	excel_file =options.bookfile
	wb=excelIcd(excel_file)
	tmp=wb.book.parse("Main")
	smain=pd.DataFrame(data=tmp.loc[1:,tmp.columns].values,columns=tmp.loc[0,tmp.columns])
	print (smain)
	#devs= wb.MainSheet['Device Name']
	#tmp=wb.book.parse("Main")
	#smain=pd.DataFrame(data=tmp.loc[1:,tmp.columns].values,columns=tmp.loc[0,tmp.columns])
	#print (smain)
	smain= wb.book.parse("Main")
	devs= smain['Device Name']
	comp=smain['Component Name']
	assembly=smain['Assembly']
@@ -90,7 +90,7 @@ if __name__ =="__main__":
		print ("the Assembly:"+assembly[0]+" includes more than one device\n",devs)
		for dev in devs:
			print("working On device:", dev)
			outf=manageICDFiles(dev,outdir,smain,wb)
			outf=manageICDFiles(dev,outdir,wb)
			outfile.append(outf)
			print("Working on files:",dev)
			mygen=genFromTemplates(outfile[-1],options.prefix,options.module,options.basedir)
@@ -101,7 +101,7 @@ if __name__ =="__main__":
			
	else:
		print ("the Assembly:"+assembly[0]+" includes one device\n",devs)
		outf=manageICDFiles(devs[0],outdir,smain,wb)
		outf=manageICDFiles(devs[0],outdir,wb)
		mygen=genFromTemplates(outf,options.prefix,options.module,options.basedir)
		mygen.generateFileInDir()
		if options.install :
Loading