Schedule Operations
In this section we'll start scheduling activities on our assets.
-
Navigate to Ops → Scheduling → Operations.
-
Select the
Machine 1asset. -
Schedule a non-production event such as:
Mode: EngineeringAsset: Machine 1Time Window: Choose a short training window -
You can make it recurring if you'd like.
Generic production scheduling is useful when no formal work order exists yet, when a customer wants to schedule by item only, or when the schedule is an operational plan rather than an ERP order plan.
- Select the time window on the calendar and click the add button to create a new schedule block.
- Select
Spray Line 1and the Production mode, and the itemSC-2024-STD. Leave the work order blank. - Set the start and end times and save the schedule.
- Select
Machine 1and click the order selector button in the top bar to show the production orders that can run on this asset. - Drag production order
260526-001onto the schedule. - Kanoa uses the item-asset scheduled rate (or the standard rate, if no scheduled rate is set) to estimate the duration.
- Save the schedule.
Events that have a production order associated with them can't be recurring.
Enforcing Shift Schedules
By default, operations can be scheduled at any time. If you want to ensure that production schedules are only scheduled during active shifts, you can configure the asset model to use
Shift Time Only. When enabled, scheduled operations are forced to fit within the asset's shift times, which are shown as the white sections of the calendar.
- Navigate to Configuration → Ops → Assets.
- Select
Philadelphiaand enable 'Shift Time Only'.
By setting Shift time Only at the site level, all assets beneath the site will inherit this setting. If you have a particular area or line that doesn't need to adhere to shifts,
you can set their Shift Time Only setting to False. The concept of inheritance is to set what is most common for your plant and then place overrides on just the exceptions.
- Navigate to Ops → Scheduling → Operations.
- Select the
Machine 1asset. - Delete the currently scheduled production order
260526-001. - Drag production order
260526-001ontoMachine 1again, starting just before the end of the Evening Shift. - Notice that the operation is split into multiple events, each scheduled at the earliest available shift time.
Copy this script into the Ignition Designer Script Console (Tools → Script Console) and run it. It lists what's scheduled on Machine 1, Spray Line 1 and Manual Pack 1 (in the site's time zone), then ticks off each scheduling step from this lesson that it can see. It doesn't change anything.
Show the check script
# Kanoa Ops Training - check "Schedule Operations" (Scheduling, lesson 3)
#
# Run in the Ignition Designer Script Console (Tools > Script Console), in the
# project that inherits KANOA_SCRIPTS. It only reads; it changes nothing.
# Lists what is scheduled on each line, then notes which of the lesson's
# schedule entries it can see.
from java.text import SimpleDateFormat
from java.util import TimeZone, Date
SITE = 'CoreForge\\Philadelphia'
LINES = [
SITE + '\\Machining\\Machine 1',
SITE + '\\Coating\\Spray Line 1',
SITE + '\\Finishing\\Manual Pack 1',
]
WINDOWS_TZ = {
'eastern standard time': 'America/New_York', 'central standard time': 'America/Chicago',
'mountain standard time': 'America/Denver', 'pacific standard time': 'America/Los_Angeles',
}
def field(row, *names):
for n in names:
if n in row and row[n] is not None:
return row[n]
return None
def text(v):
return '' if v is None else unicode(v).strip()
def rows(fn, params):
# Kanoa returns a dataset, a list, or None when there's nothing to return
data = fn(params)
if data is None:
return []
if hasattr(data, 'getRowCount'):
cols = list(data.getColumnNames())
return [dict((c, data.getValueAt(i, c)) for c in cols) for i in range(data.getRowCount())]
return [dict(r) for r in data]
site = rows(system.kanoa.asset.getAssets, {'assetPath': SITE})
tzName = text(field(site[0], 'timeZone')) if site else ''
tz = TimeZone.getTimeZone(WINDOWS_TZ.get(tzName.lower(), tzName)) if tzName else TimeZone.getDefault()
fmt = SimpleDateFormat('EEE yyyy-MM-dd HH:mm')
fmt.setTimeZone(tz)
def when(v):
if v is None:
return '-'
if hasattr(v, 'getTime'):
return fmt.format(Date(v.getTime()))
return text(v)
def repeat(rule):
# 'FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=MO,TU' -> 'weekly MO,TU'
rule = text(rule)
if not rule:
return ''
parts = dict(kv.split('=', 1) for kv in rule.split(';') if '=' in kv)
days = parts.get('BYWEEKDAY', parts.get('BYDAY', ''))
out = parts.get('FREQ', 'repeats').lower()
if days:
out += ' ' + days
if parts.get('UNTIL'):
out += ' until ' + parts['UNTIL'][:8]
return out
print '=' * 78
print 'Kanoa Ops Training - Schedule Operations check'
print '=' * 78
print 'Times are shown in %s (%s).' % (tzName or "this computer's time zone", tz.getID())
allBlocks = []
for path in LINES:
line = path.split('\\')[-1]
blocks = rows(system.kanoa.schedule.getScheduleBlocks, {'assetPath': path})
blocks.sort(key=lambda r: field(r, 'startDate').getTime() if hasattr(field(r, 'startDate'), 'getTime') else 0)
print '\n-- %s: %d scheduled' % (line, len(blocks))
for r in blocks:
mode = text(field(r, 'modeName')) or '?'
item = text(field(r, 'itemName'))
order = text(field(r, 'workOrderName'))
what = mode
if item:
what += ', item ' + item
if order:
what += ', order ' + order
qty = field(r, 'scheduledQty')
if qty is not None:
what += ', qty %s' % qty
rule = repeat(field(r, 'rruleStr'))
start, end = when(field(r, 'startDate')), when(field(r, 'endDate'))
if start[:14] == end[:14]:
end = end[15:] # same day: just the time
msg = ' %s -> %s %s' % (start, end, what)
print msg + ((' [' + rule + ']') if rule else '')
allBlocks.append((line, mode, item, order, r))
# What the lesson asked for (informational)
print '\n-- Lesson steps'
def found(label, test):
hits = [b for b in allBlocks if test(*b[:4])]
print ' %s %s%s' % ('[x]' if hits else '[ ]', label, (' (%d)' % len(hits)) if len(hits) > 1 else '')
found('Non-production event on Machine 1 (e.g. Engineering)',
lambda l, m, i, o: l == 'Machine 1' and m and m.lower() != 'production' and not o)
found('Generic production on Spray Line 1: Production, item SC-2024-STD, no order',
lambda l, m, i, o: l == 'Spray Line 1' and m == 'Production' and i == 'SC-2024-STD' and not o)
found('Production order 260526-001 on Machine 1',
lambda l, m, i, o: l == 'Machine 1' and o == '260526-001')
split = [b for b in allBlocks if b[0] == 'Machine 1' and b[3] == '260526-001']
print ' %s 260526-001 split across shifts after enabling Shift Time Only' % ('[x]' if len(split) > 1 else '[ ]')
shiftOnly = field(site[0], 'shiftTimeOnly', 'scheduleShiftTimeOnly') if site else None
if shiftOnly is not None:
print ' %s Shift Time Only enabled on Philadelphia' % ('[x]' if str(shiftOnly).lower() in ('true', '1') else '[ ]')
print '=' * 78









