Command line and automation API
FlowState can be driven without the mouse in two ways:
flowstate-cli, a command-line tool installed with the app, which reads and writes.flowfiles;- a local HTTP JSON API, served either by
flowstate-cli serveor by the desktop app itself, which Excel, Power Query, Python or any HTTP client can call.
Both use the same variable paths to address any input or result.
Variable paths
A path names an element by its name (or index) inside a list. A procedure can also be named by its equipment tag.
| Path | Value |
|---|---|
procedures/P-1/operations/REACT-1/duration/process | Process time of an operation, h |
procedures/P-1/operations/REACT-1/kind/reactions/0/extent | An operation parameter |
procedures/R-101/equipment/size | Equipment size |
streams/S-102/spec/A | Feed amount of component A, kg/batch |
components/A/price | Purchase price, $/kg |
resources/agents/Steam/cost_per_t | Utility price |
economics/tax_rate, cycle_time, batches_per_year | Plant and economic settings |
results/schedule/batch_time, results/economics/npv | Results (read-only) |
results/streams/Cake/composition/C | Stream contents, kg/batch |
List the available paths with flowstate-cli vars my.flow [prefix], for example
flowstate-cli vars my.flow results/economics. Values are checked before they are saved: a value of
the wrong type, or an unknown field, is rejected and the file is left unchanged. In URLs,
percent-encode names with spaces (Cooling%20Water).
flowstate-cli
flowstate-cli <command> [options]
| Command | Purpose |
|---|---|
simulate FILE [--json PATH] [--summary] | Simulate and print batch time, cycle time, batches/year, unit cost, NPV and messages. --summary prints the key results as JSON; --json writes the full results. Exit code 0 = OK, 2 = simulation errors, 1 = usage or I/O error |
get FILE PATH | Read a variable |
set FILE PATH VALUE [-o OUT] | Write a variable (value in JSON; bare words are strings) and save |
vars FILE [PREFIX] | List variable paths |
sweep FILE --var PATH --from X --to Y [--steps 5] [--out CSV] [--metric a,b] | One-variable sensitivity sweep to CSV |
monte-carlo FILE --var SPEC … [--runs 100] [--seed 42] [--out CSV] [--summary-out CSV] [--metric …] | Monte Carlo study; SPEC is path:uniform:min,max, path:normal:mean,sd or path:triangular:min,mode,max |
report FILE -o OUT [--docx | --rtf] | Process report (HTML, Word or RTF) |
batch-sheet FILE -o OUT [--markdown | --docx | --rtf] | Electronic batch record |
export-xlsx FILE -o OUT | Results workbook (9 sheets) |
chart FILE --kind gantt|occupancy|resources|cashflow -o OUT [--batches N] [--csv] | Chart as SVG, or its data as CSV |
templates FILE [--kind LABEL] | Show batch-sheet templates and placeholders (JSON) |
import FILE.spf -o OUT.flow [--check] | Import an .spf project (see Importing .spf project files) |
lca FILE [--simapro CSV] [--json] [--per-fu] | LCA inventory and impacts; optionally write the SimaPro CSV |
lca-import FILE CSV [-o OUT] | Import a SimaPro process CSV into the LCA settings |
serve FILE [--port 8765] [--allow-origin ORIGIN]… | Serve the HTTP API for a file |
excel-link SOURCE -o OUT [--port 8765] [--table NAME] | Write Excel web-query (.iqy) files and Power Query code |
samples DIR | Write the four built-in sample processes as .flow files |
Metrics for sweep and monte-carlo are batch_time, cycle_time, min_cycle_time,
batches_per_year, unit_production_cost, unit_revenue, npv, irr, roi, payback_years,
gross_margin, net_profit, total_investment, annual_operating_cost, revenues,
main_product_kg_per_year, e_factor, total_waste_kg, gwp and pmi, or any results/… path.
Examples
flowstate-cli samples samples/
flowstate-cli simulate samples/getting-started.flow
flowstate-cli set samples/getting-started.flow procedures/P-1/operations/REACT-1/duration/process 8 -o react8.flow
flowstate-cli sweep samples/getting-started.flow --var streams/S-102/spec/A --from 40 --to 60 --steps 5 \
--out sweep.csv --metric unit_production_cost,npv,batch_time
flowstate-cli monte-carlo samples/getting-started.flow \
--var components/A/price:triangular:8,10,14 --var economics/tax_rate:uniform:0.3,0.5 \
--runs 500 --seed 1 --out mc.csv --summary-out mc-summary.csv
flowstate-cli export-xlsx samples/getting-started.flow -o results.xlsx
The HTTP API
Start it in one of two ways:
- From the desktop app: Tools ▸ Start automation server. The API serves the document open in the window. The menu then shows Stop automation server (…) and Copy server URL. Changes made through the API appear in the window at once, re-simulate as usual, and can be undone with Ctrl+Z.
- Headless:
flowstate-cli serve my.flow.
The server listens on http://127.0.0.1:8765 and nowhere else. It rejects requests whose Host
is not a loopback address, and it refuses cross-origin browser requests unless you allow their exact
origin (see Office Scripts).
| Request | Purpose |
|---|---|
GET / | Endpoint index, with mode (file or desktop) and a revision counter |
GET /vars?prefix=… | List variable paths |
GET /var/<path> | Read a variable: {"path", "value"} |
PUT /var/<path> (JSON body) | Set a variable |
POST /vars with {"path": value, …} | Atomic batch update |
POST /simulate | Simulate and return {"summary", "results"} |
GET /summary, GET /results | Key results, or full results |
GET /report.html, /report.docx, /report.rtf | Process report |
GET /batch-sheet.html, .md, .docx, .rtf | Batch record |
GET /export.xlsx | Results workbook |
GET /table, GET /table/<name>?format=csv|html | Live tables: summary, streams, equipment, schedule, economics, cashflow, utilities, profiles, environment |
GET /chart/<kind>.svg or .csv (?batches=3) | gantt, occupancy, resources, cashflow |
GET /templates | Batch-sheet templates and placeholders |
GET /lca, GET /lca.csv | LCA results, or the SimaPro CSV |
GET /project, PUT /project | The whole .flow JSON |
POST /save | Save to the open file |
curl -s localhost:8765/var/economics/tax_rate
curl -s -X PUT localhost:8765/var/economics/tax_rate -d 0.35
curl -s -X POST localhost:8765/simulate
Excel and Power Query
The /table/… endpoints are plain web tables that spreadsheets can pull and refresh. Numbers use
. as the decimal separator and have no thousands separators.
- Start the API (desktop app or
flowstate-cli serve). - Run
flowstate-cli excel-link http://127.0.0.1:8765 -o FlowState.iqy. This writes oneFlowState-<table>.iqyper table andFlowState.pqwith Power Query (M) code. Add--table cashflowto write a single.iqyfile. - Then, in Excel, do one of the following:
- Web query: go to Data ▸ Get Data ▸ Existing Connections ▸ Browse for More… and pick an
.iqyfile. - Power Query: go to Data ▸ Get Data ▸ From Other Sources ▸ From Web and enter
http://127.0.0.1:8765/table/streams?format=csv. Alternatively, paste the queries fromFlowState.pqinto Blank Query ▸ Advanced Editor. Power BI Desktop uses the same code.
- Web query: go to Data ▸ Get Data ▸ Existing Connections ▸ Browse for More… and pick an
- In the query Properties, tick Refresh every N minutes or Refresh data when opening the file. With the desktop app’s server, every refresh shows what the window currently shows.
Writing values back from VBA:
Sub SetTaxRateAndRefresh()
Dim http As Object, v As String
v = Replace(CStr(Range("B2").Value), ",", ".")
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "PUT", "http://127.0.0.1:8765/var/economics/tax_rate", False
http.setRequestHeader "Content-Type", "application/json"
http.send v
If http.Status <> 200 Then MsgBox http.responseText: Exit Sub
ThisWorkbook.RefreshAll
End Sub
Office Scripts
Office Scripts run in a web page whose origin is not local. The API refuses such requests by default, so that no web page can drive your simulator. To allow them, add the exact origin:
- with
flowstate-cli serve my.flow --allow-origin https://…, or - in the app, under Tools ▸ Allowed web origins.
Wildcards are not accepted. When a request is refused, the app offers Allow …? in the Tools
menu, and flowstate-cli prints the origin it refused. Allow an origin only while you need it.
Python
The API needs nothing beyond the Python standard library:
import json, urllib.request
BASE = "http://127.0.0.1:8765"
def call(method, path, body=None):
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(BASE + path, data=data, method=method,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req) as r:
return json.loads(r.read())
path = "procedures/P-1/operations/REACT-1/duration/process"
original = call("GET", "/var/" + path)["value"]
for hours in (4, 6, 8):
call("PUT", "/var/" + path, hours)
s = call("POST", "/simulate")["summary"]
print(hours, s)
call("PUT", "/var/" + path, original) # restore
The example changes the reaction time of the Getting Started process, re-simulates and prints the key results. Against the desktop app’s server, you can watch the changes in the window as they happen.