Hello,
I am having total n00b trouble creating a dataset:
I have few integer tags originating from a PLC through OPC which I need to display in a table (retention is done on the PLC side) and enable editing for some of the cells. To do this I need to create a dataset which will include those tags (or rather their values) in the correct order, which is where I'm having trouble.
I watched the IU video on arrays and datasets which I learned nothing from, I also found this but I don't know where to put this code (modified to my needs) to get it to work, and clearly I couldn't find a step by step tutorial explaining this.
I know I should have been able to google my way through this but for some reason I'm unable to.
In the meantime I managed to define the table with tags manually, but that generated another question: When I set the row to be editable, I am able to type values into a cell but on focus loss the tag isn't updated and the value displayed returns to the live tag value (the tags are editable in the designer's tag manager, so this isn't a problem with the tags themselves) how do I make the editable value update the tag?
For something like this, for lack of a better way at the moment, I'd setup a folder for the table, and then a sub folder, with a number, for each row and then in each folder have a tag that is named via the column. Then you will have a folder for each row and a tag for each column.
Using scripting, or @pturmel Toolkit function, generate the dataset.
Now... updating that data is going to be tricky since you are hitting tags and not a table in a database or a dataset specifically.
I set the tags in the structure you described, now I'm trying to create the dataset.
Copying the code from the first example here into the scripting console seems to work in the sense that I get no error messages back, however I do have 2 problems:
One is I can't find where that new dataset was created, searching the tag browser gives no results. Manually creating a dataset tag with the same name and then running the script doesn't populate the dataset tag with the content of the script.
Two is I can enter the data as it appears in the example i.e. numbers and strings, but I can't figure out the syntax for it to include data from tags, every attempt at entering a tag path results in a syntax error.
Those examples are snippets, not complete solutions. You need to tailor your own code to retrieve your own raw data, and deliver the result where you wish.
If you are using runScript to bind a dataset property, the delivery part is to simply return the dataset from your function.
However, you will struggle getting both live values and editability into a Vision table--the live dataset will keep replacing your edits.
Consider using a template repeater, where the repeater dataset supplies descriptions and tag paths to a row-like template. (Or omit the description if you will obtain it from the tag.)
The row-like template would have multiple indirect tag bindings to not only obtain the live value, but also obtain formatting, units, and descriptive information to make the "row" useful. The numeric editing field placed in this template would be set to ignore updates while focused, and use a property change script to write back to the tag (when the new value doesn't match the current live value).
Of course there must be modifications to suit my needs, I didn't mention it as it seemed trivial.
The editability shouldn't just remain in the table, the new values were supposed to actually update the tag.
I've actually got some of this to work by running the code in the table's propertyChange event based on this thread. However, since I couldn't get tag data to appear in there I don't know if this would have created live values or a single data pull.
I tried to read tag values this based on this thread here, modified to a single tag for the test, but my project refuses to read the path and I can't understand what it is that I'm doing wrong.
The reason I'm trying to get a table to work is that I initially tried just placing numeric text fields side by side to get the "table look", but when I open the project on a different size screen it looks bad with out of alignment cells etc. and I'm not sure how a row of those fields set as a template (and stacked vertically via the template repeater) will look.
Nowhere in this topic have you posted your actual code, so the rest of us have to guess at the possible common mistakes you might be making. Post your code (as code, using the "preformatted text" button in the forum comment editor). Adjusting examples to suit a particular case is not trivial.
Ironically, neither can we as long as you don't show us your code.
Here are the basic steps to achieve what you are trying to do.
#read the tags to get the values.
tagPaths = ["tagPath1", "tagPath2", "tagPath3"]
tagValues = [tag.value for tag in system.tag.readBlocking(tagPaths)]
#Assemble those values into a dataset
#As the values are already in a list, all we need is a header
tagValueDataset = system.dataset.toDataSet(['tagValueHeaer'], tagValues)
Then you just set the tables data property to your dataset.
To go the other way, you would use writeBlocking in a similar way.
I tried the list way described in the thread I linked (editing the path and reducing the lists to just 1 item) but as it didn't work for me I was trying to get a more basic version to run and build from there.
Will do! but that doesn't mean I'm giving up on learning to use tables.
But for live tag data, you should give it up. At least, if reading tags via script. Scripts don't cause leased tags to be leased, like bindings do, and readBlocking has much greater overhead than a binding.
Using a template that takes a tagpath and does an indirect binding will make a tag reference, not a simple read, and works properly with the rest of Ignition's tag machinery. Templates add slight overhead on the client UI side, where readBlocking burdens both gateway and client.
The only tool I'd recommend to let you avoid the template would be to use my Integration Toolkit's tags() expression function.
In the spirit of teaching, I will explain what is wrong with the script you've posted, but seriously, use a repeater as Phil has advised.
This is wrong, readBlocking expects either a single string tag path or a list of strings. What you have provided is an undefined identifier, at least as far as the interpreter is concerned, because you didn't surround it with single or double quotes to identify it as a string. I would recommend always using a list, even if you are only reading a single path, this way the function signature in your scripts always looks the same.
value = system.tag.readBlocking(['[default]Room_Temp_SP'])
system.tag.readBlocking() returns a List of QualifiedValue objects. So you can not use them as is in a dataset the way that you are trying. In this case, we need to get the value attribute of the first QualifiedValue item in the list.
value = system.tag.readBlocking('[defalut]Room_Temp_SP')[0].value
So, if your code looked like this, it should work to populate your table:
if event.propertyName == 'componentRunning':
headers = ['Stage', 'Temperature', 'Humidity']
data = [[1,20,'Test'],[70,15,'Worm']]
value = system.tag.readBlocking(['[default]Room_Temp_SP'])[0].value
data.append([99,value,'Book'])
event.source.data = system.dataset.toDataSet(headers,data)
I think @Omer_Oren may have skipped over this solution too quickly.
You can easily make an editable pseudo-table by making a single row in a template with indirection and then use a template repeater to make the table. I've done this many times - it's a great solution with very little complexity.