Skip to main content

Configure Performance Reasons

Performance reasons are organized like the other Kanoa reason codes:

  • Performance state classes act as folders for related reasons, for example by area or by cause (equipment, material, labor, process).
  • Performance states are the reasons themselves, each with a name and a color used in reports.
  • Links to assets (and optionally items) control where each reason can be selected, so an operator on Machine 1 only sees reasons that make sense for a machining center.
Create the Machining performance reasons
  1. Navigate to Configuration → Ops → Performance Reasons.

  2. Create a performance state class named Machining.

  3. Under Machining, create these performance reasons, giving each a distinct color:

    ReasonTypical cause
    Tool WearFeed rate reduced to protect a worn cutting tool
    Coolant Flow LowSpindle speed reduced while coolant pressure recovers
    Material Hardness VariationHarder bar stock forcing slower cuts
    Operator PacingManual load/unload slower than the cycle allows
  4. Open each reason with the edit button and confirm its class, color, and that it is enabled.

Link the reasons to Machine 1
  1. On the same screen, click on the Performance state Links tab and select the Machining class so all four reasons are included.
  2. In the asset section, find Machine 1 (CoreForge\Philadelphia\Machining\Machine 1).
  3. Click the link button to link the reasons to the asset.
Linking matters

Reasons that aren't linked to an asset don't appear when someone codes a performance event on that asset. A reason for a jammed tape applicator on a packaging line shouldn't be selectable on a machining center.

Check your work

Copy this script into the Ignition Designer Script Console (Tools → Script Console) and run it. It checks the Machining class, the four reasons (name, class, enabled, distinct colours) and that each one is linked to Machine 1. It doesn't change anything.

Show the check script
checkLesson-performanceReasons.py
# Kanoa Ops Training - check "Configure Performance Reasons" (Performance events, lesson 1)
#
# Run in the Ignition Designer Script Console (Tools > Script Console). It only
# reads; it changes nothing. Every check prints PASS or FAIL with what to fix.

CLASS = 'Machining'
REASONS = ['Tool Wear', 'Coolant Flow Low', 'Material Hardness Variation', 'Operator Pacing']
ASSET = 'CoreForge\\Philadelphia\\Machining\\Machine 1'
ps = system.kanoa.performanceState

results = []

def check(ok, what, fix=None):
results.append(bool(ok))
if ok:
print 'PASS %s' % what
else:
print 'FAIL %s' % what
if fix:
print ' -> %s' % fix

def field(row, *names):
for n in names:
if row.get(n) is not None:
return row[n]
return None

def text(v):
return '' if v is None else unicode(v).strip()

def key(v):
return ' '.join(text(v).lower().split())

def truthy(v):
return str(v).lower() in ('true', '1')

def rows(data):
return system.kanoa.utilities.convertDatasetToJSON(data) if data is not None else []

print '=' * 70
print 'Kanoa Ops Training - Configure Performance Reasons check'
print '=' * 70

# 1. The performance state class
print '\n-- Performance reason class'
classes = rows(ps.getPerformanceStateClasses({}))
classPaths = dict((key(field(c, 'performanceStateClassPath', 'path')), text(field(c, 'performanceStateClassPath', 'path'))) for c in classes)
if CLASS in classPaths.values():
check(True, 'Class %s exists' % CLASS)
elif key(CLASS) in classPaths:
check(False, 'Class %s exists' % CLASS, "Found '%s'. Rename it to %s." % (classPaths[key(CLASS)], CLASS))
else:
check(False, 'Class %s exists' % CLASS, 'In Configuration > Ops > Performance Reasons, create a class named %s.' % CLASS)

# 2. The four reasons
print '\n-- Performance reasons'
states = rows(ps.getPerformanceStates({}))
byName = {}
for s in states:
byName.setdefault(key(field(s, 'performanceStateName')), []).append(s)
found = {}
for reason in REASONS:
matches = byName.get(key(reason), [])
if not matches:
check(False, '%s exists' % reason, 'Under %s, add a performance reason named %s.' % (CLASS, reason))
continue
s = matches[0]
found[reason] = s
actual = text(field(s, 'performanceStateName'))
check(actual == reason, '%s exists' % reason, "Found '%s'. Rename it to %s." % (actual, reason))
classPath = text(field(s, 'performanceStateClassPath'))
if classPath:
check(key(classPath) == key(CLASS), '%s is in the %s class' % (reason, CLASS),
"It's in '%s'. Edit it and set its class to %s." % (classPath, CLASS))
if field(s, 'enabled') is not None:
check(truthy(field(s, 'enabled')), '%s is enabled' % reason, 'Edit it and tick Enabled.')

colours = [key(field(s, 'performanceStateColor', 'color')) for s in found.values()]
colours = [c for c in colours if c]
if len(colours) == len(found) and found:
check(len(set(colours)) == len(colours), 'Each reason has its own colour',
'Some reasons share a colour (%s). Give each one a distinct colour so they can be told apart in reports.' % ', '.join(sorted(colours)))

# 3. Linked to Machine 1
print '\n-- Linked to Machine 1'
linked = set(key(field(r, 'performanceStateName')) for r in rows(ps.getAssetPerformanceStates({'assetPath': ASSET})))
for reason in REASONS:
check(key(reason) in linked, '%s is linked to Machine 1' % reason,
'On the Performance state Links tab, select the %s class and Machine 1, then click the link button.' % CLASS)

passed = results.count(True)
print '\n' + '=' * 70
print 'Result: %d of %d checks passed' % (passed, len(results))
if passed == len(results):
print 'All good. Your performance reasons are set up.'
else:
print 'Fix the FAIL items above, then run this again.'
print '=' * 70