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
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
......
......@@ -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.
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!")
<?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>
......@@ -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 :
......
from Cheetah.Template import Template
from datetime import date
import sys,os
from optparse import OptionParser
from GenDevice.excelIcd import excelIcd
from shutil import copyfile
# Read the ICD excel file
DEF_DEST ="."
gen_dir=os.environ["PYGEN"]
if gen_dir==None:
print("PYGEN variable is not set")
os.exit(0)
def createOPCUModel(book,dest):
excel_file =book
wb=excelIcd(excel_file)
Main=wb.getSheet("Main")
Get=wb.getSheet("GET")
Set=wb.getSheet("SET")
Cmd=wb.getSheet("CMD")
Mode=wb.getSheet("MODE")
print("Working on:",Main['Assembly'])
outfile=dest+"/"+Main['Assembly'][0]+'_ServerModel.xml'
scriptfile=dest+"/"+Main['Assembly'][0]+'_opcuaServer.py'
name_space = {'Author': "Gino Tosti", "Date":today.strftime("%y/%m/%d"),
'Description':Main["Description"][0],
'Assembly': Main['Assembly'][0], 'Url':Main['OPC UA address'][0],'Model':os.path.abspath(outfile),
'x': Get,'y':Set,'z':Main,'c':Cmd,'m':Mode}
template_file=gen_dir+"/templates/simpleServerModel.tmpl"
t1 = Template(file=template_file, searchList=[name_space])
ff=open(outfile,"w")
ff.write(str(t1))
#print(t1)
print("File:",outfile," created")
template_file=gen_dir+"/templates/minserver.tmpl"
t2 = Template(file=template_file, searchList=[name_space])
ff=open(scriptfile,"w")
ff.write(str(t2))
#print(t2)
print("File:",scriptfile," created")
print("The Simulation server can be reached at:",name_space['Url'])
if __name__=="__main__":
defdest=DEF_DEST
parser = OptionParser(usage='usage: %prog [options] arguments')
today = date.today()
parser.add_option("-f", "--file", dest="book_file", default=None,
help="ICD Exel File ", metavar="FILE")
parser.add_option("-o", "--outdir", dest="outdir", default="./SimulationOPCUAserver",
help="outputdir will be /SimulationOPCUAserver/ ", metavar="OUTDIR")
(options, args) = parser.parse_args()
if not options.book_file: # if filename is not given
parser.error('ICD file not given')
if options.outdir!=None :
defdest=options.outdir
if not os.path.exists(defdest):
os.mkdir(defdest)
print("Directory " , defdest , " Created ")
else:
print("Directory " , defdest , " already exists")
#gen_dir=os.environ["PYGEN"]
createOPCUModel(options.book_file,os.path.abspath(defdest))
Supports Markdown
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