Table of Contents

Workflow: Coloring Steps by Condition over the HTTP API

Replay Acceptance over the HTTP API ends with a run that played the whole mission and was accepted on evidence. This page sorts that run's steps into categories by conditions on their step properties — a color tree — and reports each category's share of the steps and of the machining time, over the HTTP API, for a script or an agent with no canvas to look at. It is written for an instance other people may be watching: §1 to §4 change neither the project nor the colors anyone sees; §5 adds the tree without overwriting one someone else put; and the one step that changes the colors on every screen, §6, is optional and puts them back at its end, unless someone else has changed the color index meanwhile.

Sign-in, the reply envelope and the other conventions every route here follows are Driving the Web Service over HTTP. Every route, field and answer code used below is in Step Color Trees over HTTP, and how a tree sorts the steps and colors its leaves is Color Trees. The same tree built in the browser is Step Colors, where each node is numbered as it is added — Cut, the leaf a new tree starts with, as 1 — so the leaves' ids, and with them the automatic hues, differ from the ones here. Every body below is JSON, sent with Content-Type: application/json.

flowchart LR
    Look["Look<br>keep the color index"]
    Write["Write the tree"]
    Check["Check"]
    Preview["Preview<br>shares per leaf"]
    Put["Put, add only"]
    Show["Show it<br>only when asked"]
    Back["Put the color<br>index back"]
    Save["Save"]

    Look --> Write --> Check --> Preview --> Put --> Save
    Check -->|problems| Write
    Preview -->|409, send again| Preview
    Put -.->|on screen| Show --> Back --> Save

1. Look first, and keep the color index

Every request of this section reads and changes nothing. First the run:

GET /api/Execution/status

executionStatus is Finished. Keep the runId, the instanceId and the resetCount beside it: §4 reads them again, to know that the steps it counted are still this run's. Running or Paused is a play changing the steps under every request below — wait for it to end, and never stop or reset a run you cannot prove is yours. NoProject means no project is open.

GET /api/execution/cl-strip/range

count is the number of positions on the step strip, above 0; it is <count> below. Then the project's trees, the keys a tree can read, and the color index:

GET /api/execution/step-color-trees?lang=en

The answer is { success, generation, physicsShown, inspectingKey, trees, registeredAtRun, keyOptions }, or success: false with code NoProjectLoaded when no project is open.

  • inspectingKey is the color index: the step property the Color Index Time Chart plots and the 3D view colors the tool path and the cut faces by, a project setting every connected screen follows. Keep it exactly as it is, null included: §4 checks it, and §6 reads it again before it sets another. GET /api/execution/strip-chart-item-config without a key answers the same value as its inspectingKey. currentKey of GET /api/execution/step-properties is not it: while the physics keys are hidden and the color index is one of them, that field names the key shown in its place.
  • keyOptions are the step properties a term can name, each { key, name, unit, unitLabel, kind, isPhysics, source }. The keys of §2 are among them: IsRapid and IsTouched with kind bool, and, while physicsShown is true, the three ratios with kind quantity and isPhysics true.
  • physicsShown false — Show Physics Options off, or no physics licence — leaves the physics keys out of keyOptions, and check and the PUT then warn about each one the tree names; the tree reads them all the same. Leave the preference as it is: it is the instance's, shared by every user.
  • trees and registeredAtRun are the trees the project defines and the ones a mission script registered for the session. A tree there that already asks the question needs no copy when it is one of registeredAtRun or its state is registered, the trees a preview by key reads: preview it by its key (§4) and report from that.

Choose the tree's key before going on: one that no entry of trees, registeredAtRun or keyOptions has, and that is not inspectingKey itself — a removed tree leaves its key as the color index until someone sets another, and a tree added under that key would recolor every screen at once. A built-in step property's key, or one under MC., is refused (400 StepColorTreeKeyTaken); a project step variable's answers 409 in §5; a project tree under a key a script registered takes that key over for the session. This page uses LoadCheck.

2. Write the tree

A tree is a list of nodes tried from the top: the first leaf whose condition holds takes the step and gives it its color, and a leaf without a condition, "when": null, takes every step that reaches it. The categories here are four:

Leaf Takes a step when
Overload any of the yielding stress ratio, the max spindle torque ratio and the max spindle power ratio is above 1
Rapid it is a rapid move: IsRapid is yes
Air it touches nothing: IsTouched is no
Cut otherwise; the chart draws its max spindle power ratio inside its lane
{"key": "LoadCheck", "name": "Load check", "nodes": [
  {"kind": "leaf", "name": "Overload", "hue": 0, "when": {"join": "any", "terms": [
    {"key": "YieldingStressRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindleTorqueRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindlePowerRatio", "op": "gt", "threshold": 1}]}},
  {"kind": "leaf", "name": "Rapid", "when": {"join": "all", "terms": [{"key": "IsRapid", "op": "eq", "threshold": 1}]}},
  {"kind": "leaf", "name": "Air", "when": {"join": "all", "terms": [{"key": "IsTouched", "op": "eq", "threshold": 0}]}},
  {"kind": "leaf", "name": "Cut", "when": null, "valueKey": "MaxSpindlePowerRatio"}]}
  • The order is the meaning. An overload is an Overload on a rapid move too, a rapid move is a Rapid whether it touches anything or not, and Air takes the feed moves that touch nothing.
  • The ids are the server's. A tree being added leaves out id and nextId; the server numbers the nodes in the order written — Overload 1, Rapid 2, Air 3, Cut 4 — and a leaf's id is the tree's value on each of its steps.
  • Yes and no read as 1 and 0, so eq with 1 asks for yes and with 0 for no.
  • No value fails every comparison. The three ratios have a value only where the physics ran, and the two spindle ratios only where the project's spindle capability gives limits at the step's speed: a step without them is no Overload and goes on to the leaves below.
  • The threshold 1 — each ratio's 100 % — is this example's choice, not a limit HiNC sets. The thermal yield ratio is left out: under a toolmaker's recommended cutting data it usually reads above 100 % (Thermal Plastic Deformation of Cutting Edge), so a leaf on it would mark ordinary cuts.
  • hue is a leaf's hue in degrees, picked here for Overload alone; a leaf without one gets an automatic hue from its id. valueKey changes no color: it names the value the Color Index Time Chart draws inside the leaf's lane.

3. Check it

POST /api/execution/step-color-trees/check
Content-Type: application/json

{"key": "LoadCheck", "name": "Load check", "nodes": [
  {"kind": "leaf", "name": "Overload", "hue": 0, "when": {"join": "any", "terms": [
    {"key": "YieldingStressRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindleTorqueRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindlePowerRatio", "op": "gt", "threshold": 1}]}},
  {"kind": "leaf", "name": "Rapid", "when": {"join": "all", "terms": [{"key": "IsRapid", "op": "eq", "threshold": 1}]}},
  {"kind": "leaf", "name": "Air", "when": {"join": "all", "terms": [{"key": "IsTouched", "op": "eq", "threshold": 0}]}},
  {"kind": "leaf", "name": "Cut", "when": null, "valueKey": "MaxSpindlePowerRatio"}]}

The answer is { success, problems, messages, referencedKeys }. Accept the tree when:

  • problems is empty. A problem is { code, path, refuses }, path its place in the body, such as nodes[0].when.terms[2]: one with refuses: true keeps the tree from registering — fix it and check again; one with refuses: false is registered as it is, with a warning.
  • messages is empty, or holds three rows whose id is StepColorTree-Term--PhysicsHidden, one per ratio, while physicsShown is false. A row StepColorTree-Term--KeyUnresolved names a key no step property has: a misspelt key reads as no value on every step.
  • referencedKeys is ["YieldingStressRatio", "MaxSpindleTorqueRatio", "MaxSpindlePowerRatio", "IsRapid", "IsTouched"], each a key of keyOptions — the three ratios excepted while physicsShown is false.

A body that is not a tree as written answers 400 with a code and args: path, the place in the body, and for some codes a reason; Answers lists every code. check changes nothing.

4. Preview it over the whole run, and read the shares

POST /api/execution/step-color-trees/preview
Content-Type: application/json

{"tree": {"key": "LoadCheck", "name": "Load check", "nodes": [
  {"kind": "leaf", "name": "Overload", "hue": 0, "when": {"join": "any", "terms": [
    {"key": "YieldingStressRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindleTorqueRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindlePowerRatio", "op": "gt", "threshold": 1}]}},
  {"kind": "leaf", "name": "Rapid", "when": {"join": "all", "terms": [{"key": "IsRapid", "op": "eq", "threshold": 1}]}},
  {"kind": "leaf", "name": "Air", "when": {"join": "all", "terms": [{"key": "IsTouched", "op": "eq", "threshold": 0}]}},
  {"kind": "leaf", "name": "Cut", "when": null, "valueKey": "MaxSpindlePowerRatio"}]},
 "range": "all"}

The preview reads the played steps themselves and writes nothing. Its histogram is the answer to the question:

  • leaves lists every leaf in tree order, { id, name, steps, seconds, share, firstStepIndex }: the steps the leaf took; their simulated time summed, in seconds; share, that time's part of the time of every step scanned; and the first of them, −1 for none. A leaf's share of the steps is its steps over scannedSteps.
  • noValue, { steps, seconds, share }, is the steps no leaf took.

selectedStep explains the step selected on the instance, or is null; it is not needed yet. Accept the shares on evidence:

Check Where Pass
The whole run was read histogram range is all, begin 0 and end <count>; scannedSteps is <count>, less any position that holds no step (a step whose building failed, reported as Step-Task--Fault); skippedPositions is 0
Every step is in a category histogram the leaves' steps and noValue.steps add up to scannedSteps; with an otherwise leaf last, noValue.steps equals faultedSteps, the steps whose read failed, and is 0
The ratios were computed selectedStep of the request below Cut's first step reads numbers for the three ratios
The color index untouched inspectingKey of the answer the key kept in §1
Still the run of §1 GET /api/Execution/status runId, instanceId and resetCount as kept in §1

To see why a step is where it is, name it — here Cut's first step, the firstStepIndex of the leaf whose name is Cut (−1 when Cut took no step: name another leaf's first step). Find Cut by its name, not by a number: a tree previewed by its key keeps the ids it was built with, and the same tree built by the steps of Step Colors has Cut 1, Overload 2, Rapid 3 and Air 4:

POST /api/execution/step-color-trees/preview
Content-Type: application/json

{"tree": {"key": "LoadCheck", "name": "Load check", "nodes": [
  {"kind": "leaf", "name": "Overload", "hue": 0, "when": {"join": "any", "terms": [
    {"key": "YieldingStressRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindleTorqueRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindlePowerRatio", "op": "gt", "threshold": 1}]}},
  {"kind": "leaf", "name": "Rapid", "when": {"join": "all", "terms": [{"key": "IsRapid", "op": "eq", "threshold": 1}]}},
  {"kind": "leaf", "name": "Air", "when": {"join": "all", "terms": [{"key": "IsTouched", "op": "eq", "threshold": 0}]}},
  {"kind": "leaf", "name": "Cut", "when": null, "valueKey": "MaxSpindlePowerRatio"}]},
 "range": "all", "stepIndex": <Cut's firstStepIndex>}

selectedStep is { stepIndex, leafId, leafName, leafValue, values, trace, error }. On Cut's first step leafName is Cut and leafId Cut's id in the histogram; trace lists the nodes tried in order, each { id, name, kind, held } — Overload, Rapid and Air with held: false, Cut last with held: true; values holds the step's value under each key the tree reads, { key, value }, IsRapid 0 and IsTouched 1 among them; leafValue is its max spindle power ratio; error is null unless a read failed. The three ratios must be numbers there. A value that is not a number travels as the string "NaN": all three "NaN" on a cutting step means the play computed no physics there, and the two spindle ratios alone that the project's spindle capability gives no limits at the step's speed — either way no step without them can be an Overload, and Overload's share says nothing about the load of those steps. Named with Overload's firstStepIndex instead, the same request shows which ratio is above 1.

A 409 StepColorTreePreviewSuperseded is a preview stopped before its end: by another preview — one runs at a time on the instance, whoever sends it, a Preview in the browser included — or by a change to the steps under it, such as a reset, a recompute of the step physics, a key registered or set as the color index, or values written onto the steps. Send it again; a 409 that keeps coming back is someone else at work on the instance, so leave time between the tries. It works the other way too: a preview sent here stops one running in someone's browser, whose panel then says that its preview was stopped, so send a preview when its answer is needed, never in a loop. A stepIndex the strip holds no step at answers 400: StepColorTreeNoStep, or StepColorTreeStepNotBuiltYet for the index a play would build next.

The shares are the report, and getting them changed neither the project nor any screen. Report each leaf's name, steps, seconds and share, the noValue row when it is not empty, and the evidence above. An Overload share is a reading of the simulation before it is a finding about the program: check it against what the project assumes before calling it a risk (Simulation Report). Go on only when the tree is to stay with the project, to be shown on screen, or to give the step file a column.

5. Add it to the project, as an add only

PUT /api/execution/step-color-trees/LoadCheck
Content-Type: application/json
If-None-Match: *

{"key": "LoadCheck", "name": "Load check", "nodes": [
  {"kind": "leaf", "name": "Overload", "hue": 0, "when": {"join": "any", "terms": [
    {"key": "YieldingStressRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindleTorqueRatio", "op": "gt", "threshold": 1},
    {"key": "MaxSpindlePowerRatio", "op": "gt", "threshold": 1}]}},
  {"kind": "leaf", "name": "Rapid", "when": {"join": "all", "terms": [{"key": "IsRapid", "op": "eq", "threshold": 1}]}},
  {"kind": "leaf", "name": "Air", "when": {"join": "all", "terms": [{"key": "IsTouched", "op": "eq", "threshold": 0}]}},
  {"kind": "leaf", "name": "Cut", "when": null, "valueKey": "MaxSpindlePowerRatio"}]}

A 200, { success, item, appearanceOnly, renamedFrom, messages, generation }, is the tree added: item.state is registered and item.problems empty; item.tree is the tree numbered, ids 1 to 4 and nextId 5; item.leaves gives each leaf as { id, lane, name, hue, hueAuto, color, valueKey }, color the #RRGGBB the charts and the 3D view paint its steps; appearanceOnly is false and renamedFrom null. messages repeats what check said, followed by what the project's other step definitions report. The tree is in the open project's memory until §7 saves it. Adding it registers the project's step definitions again, which stops a preview running at that moment (409), and leaves every screen's colors as they are: those follow the color index alone.

  • 412 StepColorTreeKeyRepeated: the project has a tree under the key — another caller's, or one from an earlier try of this run whose answer was lost — and nothing changed. Read it with GET /api/execution/step-color-trees/LoadCheck and compare its item.tree with §2's node by node — names, hues, conditions, value keys; the ids are the server's. The same tree: preview it by its key, {"key": "LoadCheck", "range": "all"}, and go on. Another tree: choose another key and put again. Never send the PUT again without If-None-Match: without it the request replaces the tree someone else put.
  • 409 StepColorTreeKeyRepeated: the project has a step variable under the key, as the message says. Choose another key.
  • 400: the key refused, as §1 describes, or the body, as §3 does.

6. Only when it must be on screen: set it as the color index, then put the old one back

This is the one step that changes what other people see. The color index is a project setting: setting it repaints the Color Index Time Chart and the colors of the tool path and the cut faces on every screen connected to the instance — the chart in four lanes named Overload, Rapid, Air and Cut from the top, the run in the leaves' colors — and a save keeps it. Do it only when the tree is to be shown, and keep it short.

Read the color index once more, GET /api/execution/step-color-trees?lang=en, and keep its inspectingKey, null included, as the key to put back — not §1's: a key another user has set since §1 is theirs. Then make the tree the color index:

POST /api/execution/inspecting-key
Content-Type: application/json

{"inspectingKey": "LoadCheck"}

The answer is { success, currentKey, messages }, with currentKey LoadCheck. The field is inspectingKey and nothing else in the body is read: {"key": "LoadCheck"} clears the color index and still answers success: true, with currentKey: null.

The host then fills each step's cached value of the color index in the background. Read the chart over the whole run, again after a moment, until pending is false:

GET /api/execution/strip-chart?aspect=Individual&inspectingKey=LoadCheck&xValueCategory=IndexByStep&widthHint=1&dispBegin=0&dispEnd=<count>
  • items[0].colorTree.leafTotals holds one entry per leaf, { lane, id, steps, seconds }, over the steps the answer covers, and noValueTotals, { steps, seconds }, the steps in no leaf. Matched by id — the list is in tree order, so never index it by lane — each leaf's steps equal those of §4's histogram, or of §5's preview by key when the tree was already in the project, and its seconds agree with them.
  • dispBegin and dispEnd make the answer cover the run, not the window on display; widthHint=1 keeps it to two points, while the totals still count every step.
  • items empty with pending: true means LoadCheck is not the color index: another user has set another one since. Stop there, and leave theirs.

Then put the color index back, unless someone else has changed it meanwhile. Read it again:

GET /api/execution/step-color-trees?lang=en

While inspectingKey is still LoadCheck, post the key kept before LoadCheck was set — the JSON null, unquoted, when there was none — and accept on a currentKey equal to it:

POST /api/execution/inspecting-key
Content-Type: application/json

{"inspectingKey": "<the key kept before LoadCheck was set>"}

Any other inspectingKey is another user's choice since §6 began: leave it. Read GET /api/Execution/status once more as §4 does: the same runId, instanceId and resetCount say the totals counted the run of §1.

7. Save the project, and give the step file a column

POST /api/Project/save

A 200, { "success": true, "message": "Project saved successfully" }, is the project file written with the tree in it; a 409 is another project file operation in progress, so save again after it, and a 400 gives the reason in message, no project open among them. The save writes the open project as it stands: the tree, every other edit made to it since it was last saved, other users' included, and the color index as it is at that moment — which is why §6 puts the color index back first. A tree that is never saved is lost when the project is reloaded or another one is opened.

Per-step data comes from a step file, the CSV that a Post-Execution command's Step Files Output writes during a play (Writing out what the run produced). It has a column under every step property's key, so the tree's column, LoadCheck, holds each step's leaf id; item.leaves of GET /api/execution/step-color-trees/LoadCheck turns an id into its leaf's name. Only a file written while the tree was in the project has the column, and the run of §1 played before the tree was added. To have one, play the mission again as Replay Acceptance plays it — a reset and a start, which everyone on the instance sees — with a Post-Execution below the programs, the command enabled (PUT /api/Mission/commands/{path}/enabled with true as the body) and its step files on (PUT /api/Mission/commands/{path}/postexecution/enable-write-step-files with true), {path} the command's entry path as Project Construction writes it. Enabling the command runs every output switched on under it, not only the step files: read its entry in GET /api/Mission/list-command/entries first — the enable… fields of its command say which — and keep its isEnabled and command.enableWriteStepFiles. Both PUTs change the mission in memory after the save above, so once the replay has written the files, put both back as they were, or the next save, anyone's, keeps them. Each file is named by its StepFile-Create--Start row (Replay Acceptance §4). A file holds one program, and the writer opens it afresh each time the play returns to that program from another, so a program that calls another keeps only its rows after the last call, and counts taken from the files then fall short of §4's.

See Also