Function Working in Script Console and Not in Gateway Event Console

Title pretty much as follows. The code is as follows:

vfds = ["Pmp1","Pmp2","Pmp3"]

# Define the paths to the run hours memory tags for each VFD
run_hour_tags = ["[default]Simulation/Index Test/Pmp{}".format(i+1) for i in range(3)]

# Define the paths to the index tags for each VFD (these should store the index values)
index_tags = ["[default]Simulation/Index Test/Pmp{}Index".format(i+1) for i in range(3)]


# Function to retrieve run hours for each VFD
def get_vfd_run_hours():
    run_hours = {}
    
    for i, vfd in enumerate(vfds):
        # Read the run hours from the tag
	    run_hours_value = system.tag.readBlocking([run_hour_tags[i]])[0].value
	    run_hours[vfd] = run_hours_value
    
    return run_hours

# Function to assign VFDs to unique indices based on their run hours
def assign_vfd_indices():
    # Get run hours for all VFDs
    run_hours = get_vfd_run_hours()

    # Sort the VFDs by their run hours in descending order (most run hours last)
    sorted_vfds = sorted(run_hours.keys(), key=lambda vfd: run_hours[vfd], reverse=False)

    # Assign indices, starting at 1
    vfd_indices = {}
    for index, vfd in enumerate(sorted_vfds, start=1):
        vfd_indices[vfd] = index
    
    return vfd_indices


def write_vfd_indices_to_tags(vfd_indices):
    for i, vfd in enumerate(vfds):
        # Get the index for the current VFD
        index_value = vfd_indices.get(vfd)
        
        # Write the index value to the corresponding index tag
        system.tag.writeBlocking([index_tags[i]], [index_value])

# Print the indices for each VFD 
for vfd, index in vfd_indices.items():
   print({vfd},"is assigned to index", {index})

# Example usage
vfd_indices = assign_vfd_indices()

# Write the indices to the index tags
write_vfd_indices_to_tags(vfd_indices)

And I get the following error:

Traceback (most recent call last):
  File "<TimerScript:APLD/Index @5,000ms >", line 47, in <module>
NameError: name 'vfd_indices' is not defined

8.1.42 (b2024061810)
Azul Systems, Inc. 17.0.11

But this script works in the script console, but not in the gateway. I'm unsure of what the problem and the difference are? Same exact copy and paste between gateway and console. And yes I plan to when the gateway script works I will flush it out to the project library and just call on the functions :slight_smile:

It looks like you are referencing vfd_indices:

for vfd, index in vfd_indices.items():

before declaring it:

vfd_indices = assign_vfd_indices()

so I wouldn't expect this to work in either context.

1 Like

Many system.* functions work differently, or require different arguments, based on what scope they are called from.

The Designer Script Console is a derivative of Vision Scope, while Perspective events run in a derivative of Gateway Project Scope. Look at the documentation for differences in the functions you use.

(The designer script console is almost never the right tool for testing Perspective scripts. It is the right tool for testing Vision scripts.)

1 Like

I suppose I didn't know the difference between the two. Would you have any suggestions for this code then? I am running into a writer's block here

I think you need to indent properly:

def write_vfd_indices_to_tags(vfd_indices):
	for i, vfd in enumerate(vfds):
		# Get the index for the current VFD
		index_value = vfd_indices.get(vfd)

		# Write the index value to the corresponding index tag
		system.tag.writeBlocking([index_tags[i]], [index_value])

	# Print the indices for each VFD 
	for vfd, index in vfd_indices.items():
		print({vfd},"is assigned to index", {index})

When I copied your code it was all spaces, not tabs...

2 Likes

Spaces for indentation is ok, you just can't mix tab indents with space indents.

2 Likes

Really? So does one space equal one tab when Python measures indentation?

Either way, there's no space before:

for vfd, index in vfd_indices.items():

so it's evaluating before vfd_indices gets declared.

1 Like

The 'pythonic way' (per PEP8, if anyone wants to read it) is to indent with four spaces.

I always just use a single tab

But what you cannot do is indent 4 spaces on one line and use a tab on the next.

Whichever you decide to use, make it a habit to always use the same thing. :wink:

4 Likes

That said, you are right in that the print loop is in the wrong spot. Probably the assign_vfd_indices() function is the best place for it.

The reason it probably worked in the Script Console is that it does not clear values every time you run the script.

4 Likes

You sort of can, for different scopes. But maybe we shouldn't be telling people this.

So, it's been a while since I've refactored something, and that first post kinda awakened the itch. I believe this should do the same thing, assuming I understood what's going on.

from operator import itemgetter

vfds = ["Pmp1", "Pmp2", "Pmp3"]
run_hours_tags = ["[default]Simulation/Index Test/{}".format(vfd) for vfd in vfds]

vfds = sorted(
	(
		{
			'name': vfd,
			'hours': qval.value
		} for vfd, qval in zip(vfds, system.tag.readBlocking(run_hours_tags))
	),
	key = itemgetter('hours')
)

index_tags = ["[default]Simulation/Index Test/{}Index".format(vfd['name']) for vfd in vfds]
system.tag.writeBlocking(index_tags, range(1, len(vfds)+1))

Side note:

{} in python means set or dict, depending on what you put inside. here are some examples of how you could print that instead:

print (vfd, "is assigned to index", index)
print "{} is assigned to {}".format(vfd, index)
print "{vfd} is assigned to {index}".format(vfd=vfd, index=index)
print vfd + " is assigned to " + index
print "%s is assigned to %d" % (vfd, index)

Side note 2:
I'd recommend not putting spaces in your tags names. Stick to valid python identifiers, basically alphanumerical values + underscores.
I'd even push it to anything that's not meant for the eye of your application's users: view names, components, db columns, everything.

2 Likes

This quirk of the script console has caused headaches for me on more than one occasion.

2 Likes

I really appreciate everyone's input here. It looks like @pascal.fragnoud's genius is yet again unmatched and it works right out of the gate. I am taking scrupulous notes on your work from now on haha.

I was hoping the script console was going to be more useful for troubleshooting scripts so I wouldn't have to make edits to a script, then save, then wait for the script to run, then see if it fails and repeat as needed. Unless there is a way to clear values? But then it still doesn't have the same scope as a gateway event, right?

There is, on the right of the script console:
image

Nope, but nothing in this script uses "scope restricted" functions.
When you run into something that does have different behavior for different scopes, you can put the script in your library and call it from a button or something in your browser.
Use system.perspective.print to print to the dev tools console.

Or I believe you can call that script from a gateway event message handler, and send a message with system.util.sendMessage from the script console.

1 Like

Pssst!

Or use my Integration Toolkit's @system.util.runInGateway decorator. :grin:

4 Likes

I didn't think that button actually reset the values as well I figured it only reset the output screen or right side results for some reason. I suppose it still sort of makes sense my script above didn't work because it wasn't getting the proper defining it needed. I think I need to rewatch the python course again or find new material.

I'm gonna bring this up to my team they have been looking for some things like what's mentioned on the site there. Thanks!

The eraser button clears the screen, the reset button... resets the whole interpreter.

1 Like

I suppose some things should be obvious lol