Most efficient way to read tags and insert into csv

I am running Ignition Edge 8.1.21.

I am trying to figure out the most efficient way to read in tag values and then use these values as my data for a script running the csv library.

For each digital input I have two tags within a data type I created that I want to read in, the first being name and the second being StateOnOff. I want my csv file to look like this as an example using the screenshot of my tag structure:

LSHH-100 OFF
LSH-200 ON

I know there is a way to read in these tags using code where you aren't reading in each individual tag within the script. And is it better to put the values into a dataset and then transfer this data set into a csv? Better to do it with a dictionary?

system.tag.readBlocking takes a list of tags paths. Use this.
Build the tags paths:

from itertools import chain
base_name = "[provider]DigitalO/InputSlot3In"
paths = list(chain(*(["{}/Name".format(base_name, i), "{}/StateOnOff".format(base_name, i)] for i in xrange(1, 5))))
values = [qval.value for qval in system.tags.readBlocking(paths)]

Then format and export to csv.
If you need help with that part too, I'll try and do my best.

interesting. I do want to get values from the following tag data types though:

InputSlot3In0, InputSlot3In2, InputSlot3In3, InputSlot3In4, InputSlot3In5, InputSlot4In0

As you can see they aren't in order

system.tag.readBlocking returns a list of qualified values in the order of the list of tag paths passed in. Note, it returns qualified values; not values. You have to handle those accordingly.

https://docs.inductiveautomation.com/display/DOC81/system.tag.readBlocking

that's easily fixable:

folders = [
    "InputSlot3In0",
    "InputSlot3In2",
    ... etc
]
paths = list(chain(*(["DigitalO/{}/Name".format(f), "DigitalO/{}/StateOnOff".format(f)] for f in folders)))

edit: note that if you have a lot of instances of this UDT, you can use system.tag.browse to build the list programmatically instead.

This is what I have for the script using your example above

def create_DI_file ():
	"""Create CSV file showing digital input status.
			
	Params: N/A
	
	Returns: N/A
	"""
			
	import csv
	from itertools import chain
									
	header = ['Digital Input', 'State']
	
	folders = ["InputSlot3In0", "InputSlot3In2", "InputSlot3In3", "InputSlot3In4", "InputSlot3In5", "InputSlot4In0"]
	paths = list(chain(*("[PLC]DigitalO/{}/Name".format(f), "[PLC]DigitalO/{}/StateOnOff".format(f)] for f in folders)))
	values = [qval.value for qval in system.tags.readBlocking(paths)]
							
	with open('C:\DailyCSVFiles\DIStatus.csv', 'w', newline='') as f:
			
		writer = csv.writer(f)
		
		writer.writerow(header)
		
		writer.writerow(values)

... I get this error when trying to run the script

you're missing a [:
paths = list(chain(*(["[PLC]DigitalO/{}/Name".format(f), "[PLC]DigitalO/{}/StateOnOff".format(f)] for f in folders)))

By the way, there are system functions to convert to csv and download a file. You should use those.
And you'll need to re-structure the data, as it is it's a simple list. You'll need a list of lists, with each inner list containing the name and state of that particular machine/whatever they are.

data_table = list(zip(values[::2], values[1::2]))
1 Like

Thanks. I did get it to work but like you said it just gave me a list as seen here:

Where would this other line of code go and what would it be replacing?
I tried putting this into the code as follows and got this:

def create_DI_file ():
	"""Create CSV file showing digital input status.
			
	Params: N/A
	
	Returns: N/A
	"""
			
	import csv
	from itertools import chain
									
	header = ['Digital Input', 'State']
	
	folders = ["InputSlot3In0", "InputSlot3In2", "InputSlot3In3", "InputSlot3In4", "InputSlot3In5", "InputSlot4In0"]
	
	paths = list(chain(*(["[PLC]DigitalO/{}/Name".format(f), "[PLC]DigitalO/{}/StateOnOff".format(f)] for f in folders)))
	values = [qval.value for qval in system.tag.readBlocking(paths)]
							
	data_table = list(zip(values[::2], values[1::2]))
	
	with open('C:\DailyCSVFiles\DIStatus.csv', 'w') as f:
			
		writer = csv.writer(f)
		
		writer.writerow(header)
		
		writer.writerow(data_table)

Because that's not how you use writerow.

But I'd repeat my suggestion: use the system functions.

dataset = system.dataset.toDataSet(header, data_table)
csv = system.dataset.toCSV(dataset, True, False, False)
system.perspective.download("filename", csv)

edit: wait, is this vision or perspective ?

perspective

Then if you piece together the little snippets in the posts above, it should do the trick.

If don't want to use a standard download, (maybe you're doing this in a gateway script) you'll need to dig in the csv writer doc to find how to write a table.
Or loop through it:

for row in data_table:
    writer.writerow(row) #might need formatting, I don't know how this function works

I am doing it through a button right now but eventually I want to create this csv file once a day through gateway scripting. I tried the method above using system.perspective.download but did not have luck. The file isn't changing at all. If I am doing it through gateway scripting would this perspective download function not work?

Did you not get a download prompt ? What do your logs say ?

Nope.
Read up on ignition's scopes, this will help you tremendously in using ignition.

Is the file supposed to go on the same machine as the gateway is running ?

Yes. Same machine. I want to create the file locally on same machine running Gateway and then send this file out in an email shortly after.

I am getting nothing in the logs, no errors or other indications when I press the button.

so seems like I would have to go the route of using the csv write instead is what you are saying if I intend to do this through a scheduled gateway event

There might be system functions for that but I never used them.
One of those should do:
https://docs.inductiveautomation.com/display/DOC81/system.file

Ok. Will check it out. Thanks for the help!