Best Practice for dataset storage for gateway scripting and perspective use

OK so let me set the stage. I’m not very versed with programming and there are still a lot of things I don’t understand. What I’m trying to do is link Ignition with AssetEssentials with their API to send meter readings from PLC tags to Assets in AssetEssentials.

I could hardcode AssetIds and tags into my gateway timer script and loop through my list. I’d rather keep the asset ids and tag association elsewhere so that I can also make an Ignition perspective screen that allows for appending to the data.

My best guess is to use a dataset in a memory tag but I’m really struggling with pointing scripts at a tag based dataset. Is there a better place to keep this type of data which allows iterating through in a gateway script and appending in a perspective session?

I would store the IDs in a database table and retrieve/update via queries. Share your script for a better understanding of what you are doing and how we can help.

My script so far is a basic API login to get a token.

Then from the AssetEssentials documentation, I would FOR loop through my data and do a series of POST operations with different asset id and meter readings(from plc tags).

Request URI: POST /v2/assets/1/meterreadings

Request Body

{
    "DateRead": "2021-03-30T11:09:00",
    "ValueRead": 8,
    "AssetId": 1,
    "MeterTitleId": 2
}

So if I understand you correctly, I should go strait to making a table in my database and working with the data that way.

For my understanding, why not use a dataset memory tag and/or what is a better use for a dataset memory tag?

If you want to edit and maintain your data, databases have many features to help you do that. It's easy to add data constraints, such as preventing duplicate values, and provides concurrent access managment, etc for data integrity.

Databases are made for this kind of thing, in other words. Of course, you could use a dataset tag if you wanted.

Make sure to use Ignition's httpClient for the api calls.

Here is what I have so far.

client = system.net.httpClient()

address = "https://assetessentials.dudesolutions.com/Redacted/api"

mydata = {
"LoginName": "Redacted",
"Password": "Redacted",
"CultureCode": "en-US",
"Expires": 1
}

authTolken = client.post(url=address+"/login", data=mydata).text

Looks reasonable so far.

If this is called often, I like to hold the client in a variable at the top level of a project script (not inside a function). HttpClient objects are heavy weight, don't create it every time you need to use it.

I’m thinking to login, iterate, then logout. I’d run the script every 15 minutes. My guess is that even if I post1000 meter readings, it wouldn’t take more than a minute to run the script and close the httpClient.

They don't close by themselves. They are cached, and are expensive to create. Just write your code in a project library script function, and place the assignment to client outside the function.

OK, so I write the script in the project library, and it creates the httpClient, logs in, iterates through the post functions to add meter readings, and then logs out. Then I invoke that script from the gateway timer scripts? If so how does one invoke a project library script from the gateway?

The gateway timer event would have the one line:

scriptName.functionName()

In the project library:

client = system.net.httpClient()

def doYourApiCall(parameters):
    # do your API call here
    response = client.get()
    return response.json

In the gateway timer script, what Phil said.

Let's go back to this, though, because maybe there's a better fundamental architecture.

Can you describe in a bit more detail what you're trying to do?
If you ultimately need this data to live in a particular Perspective session, then tags and gateway timer scripts are (probably) not the right choice.

If you need this data to live globally, totally independent of any Perspective session, then carry on.

I do want this data to live independent of the perspective session. The use of perspective would be to edit what the script is looking at without needing to launch perspective designer.

Thank you for the example code, that helps a lot.