Power Chart Pen Instances

Question: is there a way to dynamically generate pens and allow my operators to add more pens/edit their settings?

Scenario: I have 18 lift stations for a wastewater collections system I'm developing an HMI for. The lift stations are pretty similar, but have a different number of devices at each site that I want to make pens for in my power chart. I have a power chart in a view that has a parameter "LocationID". Each location has a 5 character ID, which is the name of the folder in the tag browser that the site's tags live in. It is easy to look up how many of each kind of device is at each site with a quick script:

def DeviceLookup(LocationID, Device):
	tags = system.tag.browse("[default]"+LocationID)

	TagList = [tag["fullPath"] for tag in tags.getResults()]

	NumberOfDevices = 0
	for i in TagList:
		if Device in str(i):
			NumberOfDevices+=1
	
	return NumberOfDevices

Calling the function Equipment.DeviceLookup("LS124", "PMP") returns 5, which tells me how pens I need for pumps. For another site, LS122 for example, it will return 2.

My problem is that if I dynamically generate the pens it eliminates the operator's ability to add or change the pens without the binding overwriting their changes immediately.

Maybe there's something I'm missing, but is there a way to dynamically generate pens and allow my operators to add more pens/edit their settings?

Right now, my working solution is to generate the pen instances by binding the pens property of the PowerChart to my parameter and then use a script transform to look up how many of each device I need a pen for, and use a for loop to generate the pen instance. Here's my script to generate my pens:


    pumps = Equipment.DeviceLookup(value, "PMP")   #Look up number of pumps
    flows = Equipment.DeviceLookup(value, "FIT")  #Look up number of flow transmitters
    levels = Equipment.DeviceLookup(value, "LIT")  #Look up number of level transmitters
    instances = []  #initialize an empty list to be returned with all pen instances
	
	for i in range(pumps):
		instances.append({})  #JSON removed for readability
		
	for i in range(flows):
		instances.append({})  #JSON removed for readability
	
	for i in range(levels):
		instances.append({})  #JSON removed for readability
	
	return 	instances

Here's a screenshot of the system.tag.browse for good measure.

Don't generate the pens on a binding, do it on either a value change script (on location ID change) or with a button (let operator decide when it should auto fill) or both. After the script dumps the new pens in, operators can edit as they please without their changes being overwritten.

2 Likes

Or move the original binding to a custom property, and make sure it references just what is needed to reset the chart. Then unidirectionally bind from the chart to the custom property, so it propagates on reset. Then you are free to manipulate the chart without disruption.

1 Like

I'm not sure I understand. Can you elaborate?

UI bindings execute once at setup, and thereafter only when something they reference (curly braces) changes. You can write to their target with scripting after that and the scripted write will be undisturbed until the original binding's references change. Arrange to not have any reference changes after chart setup, and then your users' changes won't be broken.

Using a separate property for the original pens binding gives you the option to copy that back to the chart later (reset) without having to re-execute the binding. Or to refer to the information there.