Live points. Real control. Verified data.
Every project connected to a bridge, with its live link state as reported by the bridge itself. Pause takes one site out of its bridge without touching the others; the bridge restarts automatically both ways.
| Site | Bridge | Target | Mode | Last data | Link | Actions |
|---|
Select Log on a site to see its communication history.
How long a point held a value or stayed within a range: a fan's run time, a door's open time, or how long a setpoint or reading stayed above or below a threshold. Uses the From/To period and the Aggregate bucket set above; gaps longer than 6 hours (typically an outage) are not counted, so results reflect what was actually observed.
Select one or more points in the tree above first.
State breakdown with no step shows every exact value seen (right for a binary or multistate point); a step size instead auto-bins a continuous reading into that width and draws one bar chart. Set Aggregate above to hour, day, or similar first, and each bin draws its own bar chart over time instead of one chart of totals.
Define several ranges for the first point selected above and see how time split across them: a pie of totals for the whole period above, or one bar chart per range broken down using the Aggregate bucket set above (hour, day, or whichever suits). A sample matching none of the ranges counts as "other".
| At least | Below | Label (optional) |
|---|
For the first point selected above, how much time was spent at each step away from a target value over the period set above, centred on the target: for a target of 23 and a step of 0.5, bands run outward both ways, 22 to 22.5, 22.5 to 23, 23 to 23.5, 23.5 to 24, and so on. Bands are generated automatically to cover whatever the point actually reported.
Checks an operating pattern, e.g. a heating valve's position against outdoor temperature: if the points trace the expected curve, the control is behaving correctly, and outliers stand out. Uses the first two points selected above, in the order picked, first as X and second as Y, and the same From/To period as the chart above. With an Aggregate bucket set above (hour, day, ...), both points are averaged to that clock and joined exactly; with Aggregate left on raw, each x reading is instead paired with whichever y reading is genuinely closest to it in time (not the same instant, since the two are sampled independently), skipped if nothing within the tolerance below is close enough.
Select exactly two points above (order matters).
Visualises a longer period at a glance: each column is a day, each row an hour of the day (0 at top, 23 at bottom), coloured by that hour's average. Good for spotting patterns across weeks or months, weekday-versus-weekend behaviour, or transitional-season energy use. Uses the first point selected above and the period set above. Give a Reference value to colour by deviation from a target instead of the raw value, e.g. how far a room ran from its setpoint.
Shows how a quantity, typically energy, distributes from a source down through sub-meters: building electricity into floor 1 and floor 2, then into individual meters, for example. Uses whichever points are selected above as nodes (up to 16) and the period set above. For counter meters (kWh, Wh, m3) each node's value is its consumption over the period; for power points it is the integrated energy; for anything else it is the average. Give each node's parent below to build the tree; a node left with no parent starts its own tree, so more than one is fine.
Select 2 or more points above first.
Pick an equipment on the left to see its asset record, points, plans, documents, open work and maintenance history on one card.
| Task | Equipment | Origin | Assignee | Status | Proof |
|---|
| Equipment | Plan | Every | Last done | Next due |
|---|
| Equipment | File | Note | By | When |
|---|
Describe what to look into, e.g. "analyse the humidity in AHU-1" or "any issues with the chiller this week". Claude looks at the real historical data for this project (via time-in-range, aggregates, and state totals, the same tools the Trends tab uses) and builds a short dashboard from what it finds. For a point an admin has put into Approved automation mode (Points tab), it can also propose a specific action, e.g. starting an AHU or changing a setpoint; it never writes anything itself, a proposal is only a request that someone with operator access or higher must explicitly review and approve below before anything changes. Needs an Anthropic API key set up under Admin, AI first.
Every action the AI has proposed for this project and not yet decided, from any question, by anyone. Nothing here has been written; approving is the one moment that actually publishes the value, using the exact same path as the Adjust button on the Points tab.
How the alarm system itself is performing over the last seven days. The reference for a workable system is roughly 150 annunciations per operator per day (about one per ten minutes); sustained rates above that mean operators stop reading, which is how real faults get missed. Bad actors are the alarms that raised most: each one is a threshold, a debounce, or a broken sensor asking for attention.
The label factory. Twenty seconds on each closed alarm (what it was, what was done) and any field observation worth writing down. Every entry can bind to the exact alarm activation it closes, which is the join a real predictive model will need in two years; until then it is simply the equipment's memory, and the Explain button already reads it.
| When | Equipment | Cause | Note | Action taken | By |
|---|
The transition history drawn out: how many alarms raised each day by severity, how many hours of alarm each day accumulated (an episode counts on the day it started, still-open episodes count up to now), and the ten alarms that spent the most time active in the window. Shelving never splits an episode; the condition was still there, someone just silenced it.
| Alarm | Equipment | Rule | Episodes | Total time |
|---|
Threshold: one point against a fixed value. Deviation: a sensor against a paired setpoint, further apart than allowed. Mismatch: two points that should agree (a run command and its status, for example) but do not. Rules are evaluated continuously by the live alarm engine, every few seconds with raise and clear debounce; a new or deleted rule is picked up within a minute, or instantly on save. The Refresh button re-reads the live state on demand.
Basic alarms have no rule row, so the opt in lives on the project. Ticked checks queue a diagnosis on every raise, under the same cooldown and concurrency policy.
| Name | Category | Severity | Type |
|---|
Schedule and Calendar objects the project's EDE import declared, filled in by the bridge when it can reach the live device. One that has never been reached by a live scan shows its name only, not yet a pattern; give it time, or check the bridge is running for this site. Read-only mirror of the device: to propose a change, put a specific schedule into Approved automation below, then ask the AI tab, the same discipline as a point write, a human must approve before anything is sent.
Point a Modbus bridge at an authorized TCP target and survey it, no project required. Discovery is read-only and always bounded: every request counts against a budget, so a scan can never flood a gateway, and it can be cancelled between requests. What a survey produces is evidence, not configuration. Nothing reaches a building until a reviewer approves it and it is exported as a unified bundle.
An open TCP port is not a Modbus device. This tells apart a valid response, a Modbus exception, an open port that speaks something else, a malformed reply, a reply carrying the wrong transaction id, a timeout and a refused connection. Each one sends an engineer to a different panel.
The protocol range is 1 to 247, and Unit ID 0 is the broadcast address, so it is never swept: an answer there identifies nothing. Behind a gateway a responding Unit ID is a downstream routing candidate, not proof of a physical device, and it is labelled that way. FC43/14 identification is read where the device supports it.
Blocks of up to 125 registers (the protocol PDU ceiling), subdividing on exceptions to isolate exactly what exists. The coverage report says which addresses the device denied and which the scan never reached, because those are different facts. Detected float32 candidates are suggestions carrying every plausible word order, never guesses.
Every discovered register is a proposal. Give the ones you want a system, an equipment and a point name (the four segment riza1 path this platform keys a point by), then approve them. Approving a candidate whose datasheet disagrees with the wire needs a written rationale. Nothing you leave pending can reach the export.
The operational export is a unified miniBMS bundle built from approved configuration and nothing else, and it is the only operational format this platform emits. The evidence report is a separate download, labelled non-operational, that records what the survey saw; it cannot be imported as configuration.
A standalone Modbus map is migration input, never an operational artifact. Upload one and this transforms it into the unified schema and reports exactly what had no destination there. The result still needs approval before any operational use.
The live stream of every topic this platform hears on the broker, newest first, with the retained flag as the broker sent it. Scoped like everything else: a tenant admin sees only their own projects' topics. The stream holds the last 400 messages; filter matches topic and payload.
The latest meta payload per topic as received from the broker: the retained set replayed at connect, plus every fresh meta published since, bounded to the newest 6000.
The logical view of one project's points with how each value actually travels: verified COV, plain polling, or an honest fallback. States, provenance and timestamps come straight from the serving bridge's health snapshot (written every ten seconds while it runs). Read now fetches one fresh value through the bridge on demand; Subscribe test asks the controller for a sixty second COV subscription and reports whether a notification really arrives.
Always-on and nearly free: every broker message is counted into per-second buckets, five minutes deep. A steady baseline is COV traffic and worker chatter; short spikes on the minute are polling cadences; a sustained plateau far above the baseline is a COV storm (a too-tight COV increment somewhere) or a runaway poller, and the top-talkers row names the suspect. Healthy systems are boring here.
A live window onto the platform's own conversations: every broker message (MQTT) and every BACnet request, response and COV notification the selected bridge exchanges, mirrored only while this page is watching. Everything stays in memory; Stop ends the mirror and keeps what was seen for saving, Clear forgets it, and an abandoned capture expires by itself. Nothing is ever written to disk on the server.
| Target | Telegrams | Failed |
|---|
| Point | Messages |
|---|
| Time | Bus | Dir | Target / topic | Service | Object / point | ms | OK | Info |
|---|
Discovery and browsing through the platform's own bridges, from the server's network vantage: Who-Is sweeps, device identity, object lists, on-demand reads, and a full EDE 2.3 export that imports straight back as a project. A bridge with no projects connected now starts fine as a pure discovery bridge (Admin, Bridges), which is exactly how a brand-new site is onboarded.
| Device | Address | Name | Vendor | Model |
|---|
| Object | Name | Value | Unit |
|---|
| Property | Value | Tag |
|---|
| Slot | Value |
|---|
Five comma separated fields per line: device ID, object type (AI, AO, AV, BI, BO, BV, MSI, MSO, MSV or numeric), object instance, priority (p1 to p16 or 1 to 16), value (NULL releases the slot). Comments with # and blank lines are fine. Parsing is strict and completes before any write; a malformed line aborts the whole run untouched. Every row is read back after it is written and reported as written, refused (the device ignored it) or unverified, so a row that did not land says so.
This writes to live equipment at the stated priorities. The typed count must match the list, which is the same inline confirmation the other destructive actions use; it is inline rather than a browser modal because modals are suppressed in some embedded and automation contexts, and a suppressed confirmation is no confirmation at all.
beez-BACnetBrowser is the desktop field instrument: one portable exe that runs from a USB stick, binds the field laptop's own network cards and COM ports, discovers controllers with repeated Who-Is sweeps, browses and writes every object property, and exports EDE 2.3 for a device or an entire network in one file. The live browser above works through the platform's bridges from the server's network; this exe is the complementary field instrument for a laptop on a strange subnet or an RS-485 segment, and both export the same EDE 2.3 that feeds straight into project onboarding here.
Field notes: Windows Firewall prompts on the first Who-Is (allow Private and Public, UDP 47808). Never run it on the same machine as a soft BACnet server; both bind 47808 and unicast replies land on one socket only. Devices on routed subnets are added by IP (right-click the interface); MS/TP attaches through a USB RS-485 adapter.
Build with publish.cmd on Windows, then upload the single-file exe here. It is stored in tools-dist/ beside the app, untouched by platform updates, content-checked for a Windows executable header, checksummed, and the upload is audited.
| Room | Link | QR |
|---|
QR codes encode the address of this browser session unless guest.public_base_url is set in config.json (for example https://bms.projects.beez-fm.com), which is the right setting whenever the platform is published under a public name. Set it once, restart, and every QR and printed sheet carries the public address regardless of where Admin is opened.
One zip from the Claude Project onboards a whole site: points (EDE or MQTT list), graphics, and the historical logging selection. Pick the customer tenant, or create one.
Change what unit a project shows values in, for example Celsius instead of a raw Fahrenheit reading, without touching what is stored or how anything is calculated. A project default applies to every point in a family (temperature, volume, flow, pressure, energy, power, ratio); an equipment pattern rule overrides the default for matching equipment (the common case: a chiller plant where everything is discussed in Celsius except the chillers themselves, which run in Fahrenheit); a single point can be overridden further from the Points tab. The most specific setting always wins.
| Family | Pattern | Unit |
|---|
Channels ship dormant until configured: SMTP lives in config.json on the server; the Telegram bot token is write only and never leaves the server. FAULTs bypass the digest window and the rate cap.
The main engineer and the main technical support receive every controls and system fault alarm of their projects; FAULT transitions reach them immediately, never digested. Both must be admin users.
Per project filters: no categories ticked means every category; the minimum severity gates the rest.
Superadmin only. Deleting a project removes its points, history, graphics, project-scoped users, and the retained broker topics; copy the project folder first if you need a backup. Tenants delete only when empty. You will be asked to type the slug to confirm.
Point at an old miniBMS folder; its projects are listed with
their slugs, points, samples and dates. Pick a target project here and
import; points match by site, equipment and point, duplicates are ignored,
and the platform keeps running. For a full replace (projects, users,
settings) use beez tools\manage.py restore instead.
One bridge is one subprocess speaking one field bus. Pick the bus when you create it: BACnet/IP, Modbus TCP or REST/JSON. A bridge needs no project to run, and started empty it idles as a survey instrument, which is what the BACnet browser and the Modbus survey both drive. Only BACnet binds a local UDP port, so only BACnet bridges contend for one; two of them may share a port when they bind different local IPs, while the same IP needs distinct ports.
| Name | Bus | Projects | Local port | Device instance | State | Actions |
|---|
What a bridge carries is defined by the projects connected to it below; one bridge can serve many buildings. A running bridge applies changes on its next restart.
The project's own EDE (from its bundle) defines the points; the target is the BACnet server to read them from. Pick "(none)" to disconnect a project.
Give these settings to any gateway or device that should send data to this platform.
By default a topic's first segment is the project slug
(slug/site/equipment/point/value). To read points from
topics that do not follow that, map a topic prefix to a project here.
Values arriving under the prefix are routed to the project; the rest of
the topic is read as site/equipment/point.
| Topic prefix | Project | Tenant |
|---|
Topic roots the broker has delivered lately. "unmapped" means no project is picking them up yet; click to pre-fill the prefix.
| Topic | Last seen | Status |
|---|
| Username | Role | Tenant | Project | Rules |
|---|
A flagged point counts as an active device alarm in the basic check whenever its value reads 1. Candidates (names containing alarm, alm, fault, fail, or trip) are flagged by default at import and by the one-time upgrade backfill; anything can be toggled here, and a deliberate unflag is never overridden.
| Flagged | Equipment | Point | Name | Unit | Candidate |
|---|
The contradiction checks (heating against cooling, commanded with no status, running on zero amps, saturated valve with the setpoint unmet, low water delta-T at load) need to know which point plays which part on each equipment. The platform guesses from names, conservatively: anything ambiguous stays unassigned, because a wrong guess makes a false contradiction. Every slot here can be pinned to a point or set to none (this equipment has no such point, stop guessing); manual decisions are never overridden and the live engine picks changes up instantly.
| Role | Point | Source |
|---|
The machine passports: every equipment with its Brick class, every point with its Brick class, endpoints, role map, confirmed relationships, and the monitors this platform actually runs on it. Classes are guessed conservatively (ambiguity walks up to an honest parent class, never sideways to a wrong leaf) and every tag is overridable here; manual decisions are never overridden. Export the whole twin as Brick Turtle, or import a model in the same simple dialect to seed classes and feeds relationships.
| Equipment | Brick class | Source | Points | Monitors |
|---|
| Point | Name | Brick class | Source |
|---|
The CTRLont layer, proposed by logic: every loop whose members the role map can prove (the controlled sensor, its setpoint, the actuator) is proposed with its evidence and confidence; the loop's internal logic (gains, deadbands, sequencing) is honestly marked unknown until a sequence document says otherwise. Confirm what matches the plant, dismiss what does not; dismissed loops leave the graph and the exports. Confirmed and proposed loops are SPARQL-queryable as ctrl:ControlActor and ride the Turtle export.
| Loop | Type | Members | Confidence | Status |
|---|
Trim and Respond, advisory only. For every supervisory reset loop the review kept, the advisor counts which member loops are requesting (actuators at 90 percent or more, fresh values only), applies the G36 arithmetic (2 ignores, 0.2 K trim, 0.3 K respond per excess request), and clamps every target inside the setpoint's own observed 30 day operating range, so it can never recommend a value the plant has not already lived at. The platform never writes a setpoint; acting on a recommendation stays a human decision on the existing write path.
| Supervisory setpoint | Current | Requests | Advice | Target | Why |
|---|
The same graph the AI tab grounds itself in: equipment typed with Brick classes, brick:hasPoint to typed points carrying beez:dbId, brick:feeds topology, and sites. The built-in engine answers basic graph patterns; install rdflib on the server for full SPARQL, and the result says which engine answered.
What the project was told to do, imported with the bundle (schema 3): the setpoints that should be in force and the schedules that should be running. This is intent, not live values. Where a plan and the building disagree, that difference is the commissioning question worth asking.
| Equipment | Kind | State | Value | Unit | Tolerance | Status | Effective | Writable | Source |
|---|
| Equipment | BACnet object | Week | Exceptions | Status |
|---|
Sweeps every device on a bridge's panel for Schedule and Calendar objects and reads what each one actually holds, so the plan above can be compared with the wire. Clearing writes seven empty days, which stops the object commanding anything; the object itself remains, because BACnet object deletion is optional and most controllers refuse it.
| Device | Object | Name | Week | Present value |
|---|
Your equipment as draggable nodes, confirmed relationships as typed, colour coded edges. Drag from a node's right port to another node's left port to confirm a relationship of the selected type; delete an edge to dismiss the pair (it will not be re-proposed). Positions save with the project, so a backup carries the drawing.
Five picks and a whole floor is wired: the medium, the supplier (a machine or a loop), the floors it serves, the equipment on them, done. Loops are created here too; in most buildings one chilled water loop supplies everything, so make the loop once and connect it everywhere.
These are statistics, not topology: pairs whose alarms fire together far more often than chance. "Raises first" means exactly that, which equipment's alarm tends to come first and by how many seconds; it is evidence for a physical relationship, never proof of one. Draw the real plumbing on the canvas above or with Quick connect; use this list as a hint, confirm what you know is real, dismiss the accidents, and either way the pair stops being suggested.
| Raises first | Raises after | Times together | Typical gap |
|---|
Every change to the graph (an edge confirmed or dismissed, a layout saved) snapshots edges and positions here, newest thirty kept, stored in the project's own folder. Restore replaces the current graph with a snapshot and demands the typed project slug, because it is destructive; the state before the restore is itself snapshotted first, so a restore is always reversible.
| Version | When | By | Edges | Nodes |
|---|
Security and configuration events: sign-ins, user and rule changes, deletions, and MQTT mapping changes. Search covers the action, actor, target, detail and IP; the export honours the current search.
| When | Actor | Action | Target | Detail | IP |
|---|
| When | User | Point | New value | Previous |
|---|
Upload a beez-minibms package zip. The platform checks
it, then applies it by itself: it stops the services, replaces the
code (your data, tenants and settings are untouched), and restarts.
This page reconnects when the new version is live. The manual
update.bat in the install folder remains available as a
fallback. Every update saves the code being replaced first, so it
can be undone with Roll back below.
Stops and starts the platform in place: no code change, no data change. Loops are stored, not lost, and pick back up once the engine is back online. Use this if the console feels stuck or the Control page reports the engine offline for no reason you can fix from here.
Restore the platform code from a snapshot saved before an earlier update (or a previous rollback). Data, tenants, and settings are never touched, either in the snapshot or by restoring it. The version being replaced is itself saved first, so a rollback can always be undone the same way. Only the 3 most recent snapshots are kept.
The AI tab turns a plain-language question into a dashboard by having Claude call the platform's own analysis functions (time in range, aggregates, state totals) on real data and choose what to show. This needs an Anthropic API key, created at console.anthropic.com. Once saved, the key is never displayed again, anywhere, by anyone, not even masked; this page can only tell you whether one is currently configured. Superadmin only.
Checking...
Only for a provider not in the dedicated lines above. Pick the wire format (anthropic or openai), paste its base URL and key.
One Telegram bot, two directions: it pushes alarms out to whoever is subscribed or is a project contact, and it takes actions and questions back, grounded strictly in this platform's own live data. Setup runs top to bottom: configure and trust the bot once, then connect each user with a pairing code. No chat id is ever typed by hand.
Create a bot with
@BotFather
on Telegram (/newbot), paste the token it
gives you, validate it, save it, then enable Trusted bot.
The token is write only: once saved it is never shown
again, anywhere, by anyone.
Checking...
Trusted means the platform continuously monitors the bot's own message stream (Telegram's getUpdates): pairing codes complete automatically the moment they arrive, and the deterministic alarm commands (Explain, Acknowledge, Assign, Close, Shelve) are taken. Until the bot is trusted it only pushes alerts out.
If this network inspects TLS (a corporate firewall or antivirus re-signing traffic), the platform will refuse to talk to Telegram until that authority is trusted. The delivery log names this failure as a certificate verify error mentioning a self-signed certificate. Export the authority's root certificate in PEM form, put it on this server, and give its full path here.
The automatic route tries the server's own certificate store first, which is the same trust the browsers on this machine already use and therefore the usual answer on an inspected network; it falls back to the certificate actually presented. Nothing is saved unless a real call to Telegram succeeds with it, and verification stays on either way.
Pick a platform user, tick the project(s) they belong to, and generate a pairing code. They send the code to the bot from their own phone; the platform reads the sender's chat id from that one message and links it automatically, which is also what proves they hold that phone. Codes are single use and expire after 15 minutes.
Everyone Telegram can reach, with their chat id, projects and permissions. Edit a row and press Save; Regenerate mints a fresh pairing code for that user (for a new phone, or a code that expired); Disconnect cuts the link at any time without touching the platform account.
| User | Chat id | Projects | Two-way | Pairing | Actions |
|---|
Two independent paths deliver alarms. Project contacts receive every fault and control event immediately, never folded into a digest. Subscriptions are per user and per project, folded into a digest at the interval below. Both are configured here.
Alarm routing for the chosen project, decided here rather than by asking each person to subscribe themselves. Tick the categories a user should receive, pick the minimum severity and the channels, and save on their row. A user without a Telegram pairing or an email cannot receive on that channel, and the row says so.
| User | Reachable | Categories | Min severity | Channels |
|---|
When this is on, a two-way user can message the bot a free question, for example what alarms do I have or is CH-01 running, and receive an answer built from exactly three read only functions over this platform's own live alarms and point values: nothing here gives any model access to the server, a file, or a shell, and a question the tools cannot answer is met with that fact rather than a guess. The deterministic alarm commands never depend on this switch and never spend a token; they come with Trusted bot in step 1. A message from a chat id no user has paired receives no reply at all.
Everything Telegram has for this bot, read with the token stored here, so the bot can be debugged without ever pasting a token into a browser address bar. Telegram hands each message over once per bot, so while the bot is trusted the platform's own monitor consumes them and this shows the monitor's record instead; untrust the bot to watch the raw stream.
| When | Chat id | Type | From | Message | Paired to |
|---|
What the platform actually tried to send, and what came back. A message that never arrived on your phone shows its real reason here rather than failing silently.
| When | Channel | Recipient | Subject | Status | Detail |
|---|
The Control Engine, phase C1. Loops are authored in IEC 61131-3 Structured Text, evaluated against a first order plant model, and executed by the engine process. An active loop writes to the field through the signed /set priority extension; the TEST freeze, the holds ledger and the typed confirmations below are the guardrails.
Pick a strategy from the beez-fm control doctrine, map its variables to real points, and instantiate: setpoints and loops arrive pre-filled, source labelled, in off mode, fully editable. Every template names its doctrine section and its ASHRAE Guideline 36-2021 clause where one exists.
Reset curves and schedules computed by the engine and published as calculated points under ctl/ctl-setpoints, ready to serve as any loop's existing setpoint reference. The curve is piecewise linear on the source variable; schedule windows override it (value, offset, or hold, the protected window that freezes the reset through a peak block).
| Name | Source | Curve | Schedule | Unit | Enabled | Live point |
|---|
Boost pushes the AUTO members of a definition toward the boost setpoint until the aggregate enters the comfort band, then stops itself; the hard time limit is mandatory. TEST freezes are respected and FAULT is never overridden.
| Name | Target | Band | Authority | Limit | Live |
|---|
Every AI review lands here. Nothing applies itself; a group verdict is information, never an action.
| Loop | Kind | Status | Reasoning | Proposal |
|---|
| Name | Equipment | Class | Scan s | Mode | Cascade of | Health | Active sensor | PV | SP | OUT cmd | OUT actual |
|---|
This loop is running (TEST or AUTO). Everything below is read only until it is set to OFF; nothing edited here is saved while it runs.
Shows this loop's own live PV, SP and OUT as the engine is computing them right now. Read only: this panel only reads the engine's state, it never writes to the field, in any mode.
Last 24 hours of this loop's own PV, SP and OUT, whatever mode it ran in, so OFF and TEST leave a full record behind even though neither ever writes to the field.
An ordered failover list for the loop PV. When any candidate exists the list owns PV and the single PV point above is ignored. Offsets are calibrations; a mounting height offset is an estimate and is labelled as one. Order is preference; the aggregation runs over the currently valid candidates only.
| Point (site/equipment/point) | Offset | Min | Max | Max rate /s | Stale s | Mount m | Pin |
|---|
Declare an additional named input the program reads as IN.<alias>, each with its own ordered failover candidate list, same rules as the PV candidates above. The alias must match what the program uses exactly; it is case sensitive.
First order plant: PV relaxes toward ambient - gain x OUT with time constant tau. Positive gain models a cooling process from ambient.
| t s | PV | SP | OUT |
|---|