There is no byte array type for custom properties in vision, so dumping the tag's value into a string and parsing the values from it was the best I could do. It is a lot easier in perspective where you can do a script transform on the binding to convert the byte array to the proper format.
In Vision, I would avoid converting the byteArray to a string.
I would instead use an expression binding with the following expression:
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(" + {[default]New Tag} + ")])",0)
This will work in either Vision or Perspective, you can put the binding directly on the power table, or on a Custom Dataset Property depending on what you are trying to with the table (If you are wanting to edit the values).
This can be made more performant with the Integration Toolkit Module if you can install it:
unionAll( \\returns a dataset give columnInfo, and row data
asList(
asList("Slave","Integer"), \\Column 1 Header, Type
asList("Value","Byte") \\Column 2 Header, Type
),
forEach( \\results in a list of items from the iteration
{[default]New Tag}, \\Data to loop over
asList(
idx(), \\item index each trip through the loop
it() \\item value each trip through the loop
)
)
)
Also works in vison or perspective, and will be more performant than a script transform in perspective as well.
Well that's a little more complicated, as you can not parametrize a tag path in an expression, and you should not use the tag() expression binding in this instance. (You will kill your performance, there are many threads on the forum about this).
Nothing however, prevents you from building the tagPath and then using that in the script.
What I would do for vision is create a custom string property called tagPath, with an expression binding that you use to build the path with. Use other custom properties to hold the dynamic values of the path. So, for instance say your path varies by machine number, then I would create a custom property to hold the machine number and build the path in an expression:
"[default]" + {MachineNumber} + "/ByteArray"
Then I would use that path in the runScript expression and change the script to this:
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(system.tag.readBlocking(" + {event.source.tagPath} + ")[0].value)])",0)
To only return those values which are greater than 0 you can add a conditional to the comprehension. That would look like this:
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(system.tag.readBlocking(" + {event.source.tagPath} + ")[0].value) if value > 0])",0)
Below is the my expression for reading indirect tag to update the array value in power table.
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(system.tag.readBlocking(" + {DirectTag.tagPath} + ")[0].value) if value > 0])",0)
I am using template that having power table with custom property of template parameter string to read tag.
The problem is you are not providing a valid TagPath.
Either you need to provide quotes around the supplied path in the expression for your template property, or you need to add them into the script for the runScript expression.
TableTag does not point at the data that you are interested in. Your tag path needs to look like this:
[default]TableTag/AMag
The quotes are required so even if you have the correct path, without the quotes it still won’t work, as it will see the path as an undefined identifier.
Thanks for the reply.
Adjusted the code now no error, but tables are not updating until I save. whereas table are updating if I use direct tag in expression.
below is the indirect tag expression.
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(system.tag.readBlocking('" +{IndirectTag.Power Table.tTagPath}+ "/PLCUDTArray')[0].value) if value > 0])",0)
The 0 at the end of the runScript expression is the pollRate. If that is set to 0 then it only executes at load. Set it to some amount of ms that you wish for it to update. Beware, the lower the number the higher the load you will put on the client and the gateway.
Hi
How can I add another column in same power table using runscript.
same tag path but different array as below.
(system.tag.readBlocking('" +{IndirectTag.Power Table.TagPath}+ "/Faultnode')
Below is the current runscript I have. In this script I have to add another column.
runScript("system.dataset.toDataSet(['Slave', 'Value'], [[i,value] for i,value in enumerate(system.tag.readBlocking('" +{IndirectTag.Power Table.TagPath}+ "/PLCUDTArray')[0].value) if value > 0])",3000)
This run script is starting to get convoluted, and it seems to be doing to much work. I would abstract this out to a function, put the driving value into a bound custom property, and call the function from the custom property's propertyChange change event.
There is really no "good" and clean way to do this as a string in a runScript expression. Instead, you should create the script in the project library script, then use runScript() to call that instead.
For instance you could write this script:
def getDataSet(values, faultNodes):
headers = ['Slave', 'Value', 'Node']
data = [[i, value, node] for i, (value, node) in enumerate(zip(values, falutNodes))]
return system.dataset.toDataSet(headers, data)
Next create custom properties to hold your arrays, and use Indirect Tag Bindings to bind them to the tags.
I have implemented the script in project library as ReadingArray. Then created custom properties in the name of FaultNodes and PLCUDTArray as string data type and bind them with array value as you can see in the pic.
I can able to read the value on the table but two digit values are reading as single digit including comma.
Is there a way that only reading value please. Thanks in Advance.
Ahh, yes, I forgot the limitation that custom properties cant have an array type. Hopefully, that gets fixed in 8.3
Anyway, we will need to force the script to see the string as a list of integer values instead of a list of characters.
def getDataSet(values, faultNodes):
headers = ['Slave', 'Value', 'Node']
cnvValues = [int(iVal) for iVal in values[1:-1].split(',')]
cnvNodes = [int(iVal) for iVal in falutNodes[1:-1].split(',')]
data = [[i, value, node] for i, (value, node) in enumerate(zip(cnvValues, cnvNodes))]
return system.dataset.toDataSet(headers, data)
I don't know what this means, nor do I know how you would get the wrong tag name.
Yep, just add the conditional back in to the comprehension.
def getDataSet(values, faultNodes):
headers = ['Slave', 'Value', 'Node']
cnvValues = [int(iVal) for iVal in values[1:-1].split(',')]
cnvNodes = [int(iVal) for iVal in falutNodes[1:-1].split(',')]
data = [[i, value, node] for i, (value, node) in enumerate(zip(cnvValues, cnvNodes)) if value > 0]
return system.dataset.toDataSet(headers, data)
cnvValues = [int(iVal) for iVal in values[1:-1].split(',')]
cnvNodes = [int(iVal) for iVal in falutNodes[1:-1].split(',')]
data = [[i, value, node] for i, (value, node) in enumerate(zip(cnvValues, cnvNodes)) if value > 0]
return system.dataset.toDataSet(headers, data)