Table of Part Numbers with attributed run rate (PPM)

Hey everyone,

I am completely new to this environment but have already enjoyed the features I have utilized so far. However, I ran into an issue. I am attempting to script a property change event that executes when the user changes the PPM/run rate of the machine. This run rate is also to update a Power table where the part numbers and their attributed PPM’s are stored, but does not update the table, only the UPC. I get an error as follows:
Error executing script for event: propertyChange
on component: Run Rate
Details:
File “event:propertyChange”, line 3, in
AttributeError: ‘NoneType’ object has no attribute ‘replace’

The script in the numeric text field:

if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number")
	ATMSettings.setRunRateFromPartNumber(int(partNumber.replace(",","")), int(event.newValue))

I also want to point out that in the tree, the ‘Run Rate’ is in Templates-> Data-> Run Rate. and the power table is under Windows-> Standard Run Rates-> Root Container-> Power Table SRR.

Thanks for looking at my issue if you have a second!

partNumber references a component directly.

So partNumber.replace() doesn’t exist - I assuming an you are trying to do this to a get rid of commas out of an integer string? This is unnecessary if you grab the .intValue from the component directly.

Here is the rest of the code that is within the project library



def getRunRateFromPartNumber(partNumber):
	settings = system.tag.readBlocking(["[default]Concentrator PLC/ATM_Settings"])
	settingsDataset = settings[0].value
	return datasetFindValue(settingsDataset, "PartNumber", partNumber, "RunRate")

def setRunRateFromPartNumber(partNumber, newRunRate):
	settings = system.tag.readBlocking(["[default]Concentrator PLC/ATM_Settings"])
	settingsDataset = settings[0].value
	newDataset = datasetFindReplace(settingsDataset, "PartNumber", partNumber, "RunRate", newRunRate)
	system.tag.writeBlocking(["[default]Concentrator PLC/ATM_Settings"], [newDataset])
	addHistoryEntry(partNumber, newRunRate)
	
def addHistoryEntry(partNumber, newRunRate):
	historyDataset = system.tag.readBlocking(["[default]Concentrator PLC/History"])[0].value
	newDataset = system.dataset.addRow(historyDataset, historyDataset.getRowCount(), [system.date.now(), partNumber, newRunRate, system.security.getUsername()])
	system.tag.writeBlocking(["[default]Concentrator PLC/History"], [newDataset])

def datasetFindValue(dataset, searchColName, searchValue, returnColName):
	for row in system.dataset.toPyDataSet(dataset):
		if row[searchColName] == searchValue:
			try:
				return row[returnColName]
			except:
				raise Exception("Column name doesn't exist: " + returnColName)
				return ""
	
	return ""
	
def datasetFindReplace(dataset, searchColName, searchValue, replaceColumn, replaceValue):
	rowCt = 0
	for row in system.dataset.toPyDataSet(dataset):
		if row[searchColName] == searchValue:
			return system.dataset.setValue(dataset, rowCt, replaceColumn, replaceValue)
		
		rowCt += 1
	
	raise Exception("Couldn't find column " + searchColName + " with value " + str(searchValue) + " in the dataset, returning original dataset")
	return dataset

Is this a text field? You probably want partNumber = event.source.parent.getComponent("Part Number").text if this is something you need to get an int out of.

Alternatively and probably better is to use a numeric text field, you can make your number masking to have commas (or not) and then you can grab partNumber = event.source.parent.getComponent("Part Number").intValue and not have to worry about manually getting rid of commas out of an integer.

Thanks for the suggestion. You make a really good point and it was originally set up as a text field and I changed it to a numeric text field, and wasn’t aware I could remove the commas under this type of field. I made these changes and the script looks better but is still throwing a similar error.

File “event:propertyChange”, line 2, in
AttributeError: ‘NoneType’ object has no attribute ‘intvalue’

In advance, sorry if I miss something I currently have the flu and am working :laughing:

Think it should be .intValue, everything is camelCased in Ignition.

However, I don’t even trust myself to type component relationships correctly by hand - I just always use the property selector to find and pick what property I need.

3 Likes

Oops, good catch. I corrected the notation but got the same error. Rookie mistake ha.

if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(int(partNumber.replace()), int(event.newValue))

Did you use the property selector? If not, delete what you have and use the property selector like @bkarabinchak.psi mentioned.

Well now partNumber has type of int so it will not have a .replace() function, nor do you need to typecast it as it is already an int.

An AttributeError means you are calling a property or method on something that does not exist, and an integer does not have a replace method.

1 Like

I did and got a whole new error.
Traceback (most recent call last):
File “event:propertyChange”, line 2, in
AttributeError: ‘NoneType’ object has no attribute ‘event’

You’re making some great points. How would you structure it since I have literally chopped it to death and am clearly leaving behind unnecessary functions?

I would think this is enough

if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(partNumber), int(event.newValue))

Though since you are looking for the propertyName intValue, the event.newValue\event.oldValue will be of int type, so you can probably do it as

if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(partNumber), event.newValue)
2 Likes

Okay, I made the changes to remove anything not needed and I still get the ‘intValue’ in line 2. Could the issue be that because the ‘intValue’ I am trying to use is inside the power table and I am stuck in the Data under Templates. Do I need to drill out and then back down into the windows to use the correct property?

When I use the ‘Insert Property Reference’ I cannot get to the Part Number because it is in the Power Table under Windows.

For anyone who may need this information in the future within the community, the solution to my issue was as follows:

if event.source.parent.txtPartNumber:
	partNumber = event.source.parent.txtPartNumber
	ATMSettings.setRunRateFromPartNumber(partNumber, event.newValue)

There were a few problems found throughout the troubleshooting, but after some cleaning up and pointing to the correct data “txtPartNumber”, the issue was resolved. Hopefully this will help someone else.