I am extracting data from an OPC-UA server that only supports read. I have no control over the format of the value from the OPC-UA server.
The format of the value is a variant array of size 2 (see example in picture). The only way I am able to not get a "TypeConversion" error in Ignition is to use datatype equal to string array for the OPC-tag.
My goal is to have a tag where the value is only the float inside the first element of the array, while the quality and timestamp is unchanged.
What I have tried to to:
By creating an Expression tag with the expression below, I am able to isolate the value that I am interested in: toFloat(replace(replace({[default]tag_name[0]}, "Variant{value=", ""), "}", ""))
However, using the expression it also impacts the timestamp, thus I thereby losses the time of sampling of the sensor. It is also very cumbersome as I have to do this for about 1000 sensors.
Unfortunately, the replace() expression doesn't support regex. (The split() function does.)
A simpler expression that seems to work is toFloat(substring({this.custom.variant}, 14))
You could create a UDT with two internal tags and a tagpath parameter. The first tag would get your Array[2] using the tagpath parameter and the second one would return the float.
This will be a bit ugly because Variant (and Variant array) is basically an unsupported type in Ignition. I think it'll be a little better in 8.3, but still not great.
Create a UDT. Create 3 tags:
OpcVariantArray
V0
V1
In the OpcVariantArray, add a value changed event script:
import re
from com.inductiveautomation.ignition.common.model.values import BasicQualifiedValue
from com.inductiveautomation.ignition.common.model.values import QualityCode
ts = currentValue.timestamp
v0 = currentValue.value[0]
v1 = currentValue.value[1]
match0 = re.search(r'value=([^}]+)', v0)
match1 = re.search(r'value=([^}]+)', v1)
if match0:
value = BasicQualifiedValue(match0.group(1), QualityCode.Good, ts)
system.tag.writeBlocking(["[.]V0"], [value])
if match1:
value = BasicQualifiedValue(match1.group(1), QualityCode.Good, ts)
system.tag.writeBlocking(["[.]V1"], [value])
you'll probably need to do some casting to int/float on the desired type on the values you pull out of the regex (match0.group(1) etc...) and generally clean this script up a but, but the basic idea is there...
Parameterize the UDT as needed so that you just instantiate 1000 of them or whatever.