1 Getting Started
Welcome to the Whisker IDE — the design environment for the D6 Labs Nexus.io family of industrial automation controllers. This chapter walks you through downloading and installing the IDE, gives you a tour of the workspace, and ends with a five-minute walkthrough that gets you to a saved project ready to deploy.
1.1 About this manual
This manual covers the Standalone edition of the Whisker IDE on Windows. The Standalone edition is fully offline: it does not require an account, an internet connection, or any cloud subscription. Everything you do — designing programs, configuring I/O, deploying to a controller — happens between your PC and the controller on your local network.
A separate manual covers the Cloud edition of the Whisker IDE for users who want fleet management, cloud-staged deployments, and role-based access control through Whisker.io.
1.2 System requirements
| Minimum | Recommended | |
|---|---|---|
| Operating system | Windows 10 (64-bit), version 1809 or later | Windows 11 |
| Processor | 64-bit dual-core | Quad-core or better |
| Memory | 4 GB RAM | 8 GB RAM |
| Disk space | 200 MB free | 1 GB free (for projects and HMI runtime bundles) |
| Display | 1280 × 720 | 1920 × 1080 or larger |
| Network | Ethernet or Wi-Fi on the same LAN as your controller | Same |
The Whisker IDE itself does not need an internet connection. You only need network connectivity to reach your Nexus.io controllers during deployment.
1.3 Downloading the IDE
Open your web browser and go to:
www.d6labs.com/downloads/whiskeride_v1_2_standalone_windows.zipThis downloads a single zip file (~13 MB) containing the installer plus three short text files.
Note on versioning. The download URL uses a two-component version (
v1_2) for stability — minor bumps within the v1.2.x series reuse the same URL. The installer inside the zip carries the full three-component version (e.g.,1.2.0).When the download completes, locate the file in your Downloads folder (or wherever your browser saves downloads).
Note. If your browser warns “this file might be dangerous,” choose Keep or Keep anyway. Until D6 Labs’s installer is signed by a commercial code-signing certificate, Windows SmartScreen may flag any new download from us. This is normal and the file is safe.
1.4 Installing the IDE
The download is a zip file, not the installer itself. You need to extract it first.
1.4.1 Step 1 — Extract the zip
Right-click the downloaded
whiskeride_v1_2_standalone_windows.zipfile.Choose Extract All…
Pick a destination (the default — a folder with the same name in Downloads — is fine).
Click Extract.
When extraction finishes, you’ll have a folder containing:
| File | What it is |
|---|---|
WhiskerIDE-Offline-1.2.0-Setup.exe |
The installer you’ll run next |
README.txt |
Quick reference matching this chapter |
LICENSE.txt |
End-user license agreement |
CHANGELOG.txt |
Notable changes in this release |
1.4.2 Step 2 — Run the installer
Double-click
WhiskerIDE-Offline-1.2.0-Setup.exe.Windows shows a User Account Control prompt asking permission to make changes. Click Yes.
The setup wizard appears. The default values are correct for almost everyone — you can click Next through each screen.
Screen What to do License Agreement Read it, choose I accept, click Next Select Additional Tasks Check Create a desktop icon if you want one. Click Next Ready to Install Click Install Completing Setup Leave Launch Whisker IDE checked. Click Finish Installation takes 10–20 seconds. When it finishes, the IDE launches automatically.
1.4.3 Step 3 — Confirm the install
After the installer finishes, you should see:
- A Whisker PLC IDE Offline entry in your Start menu.
- A desktop shortcut (if you chose that option).
- A new program registered under Settings → Apps & features.
You can safely delete the extracted folder and the original zip — the
IDE is now installed in
C:\Program Files\Whisker PLC IDE Offline\.
1.5 First launch
When the IDE opens for the first time, you see an empty workspace. No login, no account setup, no first-run wizard — the Standalone edition is ready to use immediately.
Take a moment to find the window title in the title bar: it should read Whisker PLC IDE Offline. That’s how you tell at a glance which edition you’re running.
1.6 Core concepts
Before you build anything, it helps to understand the four nouns the IDE revolves around.
Application — A container that groups one or more related Projects. For a single-controller installation, your Application will contain one Project. For a system with several controllers and an operator panel, your Application might contain three or four Projects that share tags and design specs.
Project — A single program for a single controller.
A Project knows which kind of controller it targets (its Target).
Projects are saved as .widez files (a single-file zip
archive containing ladder logic, tags, I/O configuration, HMI screens,
and alerts).
Target — The type of controller the Project runs on. The Standalone edition supports three Targets:
- Nexus.io AC — D6 Labs’s flagship automation controller. Full PLC with ladder logic, I/O, tasks, HMI, and Modbus server.
- SmartControllerClassic — D6 Labs’s earlier MicroPython-based controller. Uses the Python editor instead of ladder logic.
- WhiskerHMI — A standalone HMI panel that runs alongside (not on) a Nexus.io AC controller. No ladder logic; only the HMI Designer.
Tag — A named variable in your program. Tags have a
data type (BOOL, INT, DINT, REAL) and an address in controller memory
(%M0, %MW10, %MD4,
%MF12). You reference tags from ladder logic, HMI bindings,
alerts, and the Modbus map.
1.7 A tour of the IDE workspace
The Whisker IDE workspace is divided into seven main areas. The arrangement is shown below, and each area is described in detail in the chapter The Workspace.
- Toolbar — file operations, build, connect, run, deploy. The set of visible buttons depends on the active project’s Target type.
- Project Tree — the structure of the open Application and all its Projects.
- Editor area — open editors for tags, ladder programs, HMI screens, etc. Multiple editors stack as tabs.
- Properties panel — when you click an element in the project tree or the active editor, its editable properties appear here.
- Toolbox — context-sensitive palette for the active editor (ladder elements, HMI widgets, etc.).
- Output panel — build results, deploy progress, errors and warnings.
- Status bar — connection state, current target, dirty/clean indicator.
1.8 What’s next
You now know enough about the IDE to build something real. The next three chapters walk you through three end-to-end projects against the same physical scenario — a single motor controlled by float switches, with an Auto/Hand/Off operator panel and a latched high-level alarm. Each walkthrough uses the same controller, the same I/O module, and the same HMI screen, so you can see how Ladder, Python, and a standalone WhiskerHMI panel each express the same control intent:
- Chapter 2 — The Walkthrough scenario sets up the shared hardware, I/O wiring, and tag conventions that the three walkthroughs reuse.
- Chapter 3 — Your First PLC Project (Ladder) builds the motor control logic as ladder rungs on a Nexus.io AC controller.
- Chapter 4 — Your First PLC Project (Python) builds the same logic as Python code on the same controller.
- Chapter 5 — Your First WhiskerHMI Project builds a standalone Windows HMI panel that connects to the Nexus.io AC over Modbus TCP.
If you already have a controller on your LAN, start with Chapter 2. If you’re working without hardware for now, the Ladder and Python walkthroughs (chapters 3 and 4) cover the design steps you can do offline; the Build step requires a connected controller because Build compiles and uploads in a single operation.
2 The Walkthrough scenario
The next three chapters walk you through three end-to-end projects that share one physical setup. Building the same control system three different ways — once in ladder logic, once in Python, once as a standalone HMI panel — is the fastest way to see what each editor in the Whisker IDE actually does and how the pieces fit together. The shared scenario also gives you something concrete to keep on your bench: at the end of the three walkthroughs, you’ll have one running controller and one running HMI panel that you can prod with float switches and watch react.
This chapter sets up everything the walkthroughs assume — the hardware, the field wiring, the tag names, the control intent, and the HMI layout. Read it once. Each walkthrough then refers back here for setup details rather than repeating them.
2.1 What you’re building
A single motor controlled by three float switches and an operator selector. The operator chooses one of three modes — Off, Hand, or Auto — using an AHO selector switch on the HMI. In Auto mode, the motor runs when the start float closes and stops when the stop float opens, like a classic seal-in. In Hand mode, the motor runs unconditionally; the operator owns it. In Off mode, the motor is off.
A separate high-alarm float acts as a safety. When it closes, the controller latches an alarm and refuses to run the motor in Auto until the operator presses a Clear Alarms button on the HMI. In Hand mode the operator can still run the motor through the alarm — that lets them pump down or service the system without fighting the alarm latch. Off still means off, alarm or no alarm.
That’s the whole scenario. Five inputs, one output, one latched alarm, one operator panel.
2.2 The hardware
You need three things:
- A Nexus.io AC controller on your LAN, powered on, reachable from your PC by IP or mDNS hostname.
- An mSmart Universal IO module wired to one of the controller’s RS-485 ports as a Modbus RTU slave.
- Field wiring: three float switches on three digital inputs, one motor contactor (or a stand-in like an indicator lamp) on one digital output.
If you don’t have a real motor handy, a 24 V relay or a single LED on the DO will do — you just need to see something react when the logic turns the output on.
2.2.1 Wiring map
| Field signal | Module channel | Modbus register | Tag name (after rename) |
|---|---|---|---|
| Start float | DI1 | Holding reg 0 | float_start |
| Stop float | DI2 | Holding reg 1 | float_stop |
| High-alarm float | DI3 | Holding reg 2 | float_alarm |
| Motor contactor | DO1 | Holding reg 99 | motor_run |
The mSmart Universal IO module exposes a lot more than this — six DIs, five AIs, an AO, plus counters and event-rate readbacks — but the walkthroughs only use four channels. Anything you don’t reference in the project stays unmapped and ignored.
2.2.2 RS-485 settings
The mSmart module talks Modbus RTU at the following defaults. The IDE will let you change all of these from the Add Device dialog if your hardware is configured differently.
| Setting | Value |
|---|---|
| Baud rate | 19200 |
| Data bits | 8 |
| Parity | None |
| Stop bits | 1 |
| Slave ID | 1 |
| Controller serial port | rs485 (UART 1) |
2.3 Tags — where they come from
The walkthroughs use seven tags. They come from two different places in the IDE, and getting the order right matters:
- I/O tags are created automatically by the IO
Configuration editor when you add a hardware module. You don’t (and
can’t) type a
%Ior%Qaddress into the Tag Database — those addresses belong to physical I/O channels and the IDE assigns them based on which device they belong to. - Memory tags are created in the Tag Database. These are the internal bits and words your logic uses to remember state — modes, latches, button pulses — that don’t correspond to a physical wire.
So the setup sequence in each walkthrough is:
- Add the mSmart Universal IO module in the IO Configuration editor.
- The IDE auto-creates one tag per channel on the module
(
uio_DI1,uio_DI2, …,uio_DO1, …). Rename the four you care about to friendlier names. - Open the Tag Database and add the three memory tags that have no physical counterpart.
| Name | Type | Address | Origin | What it is |
|---|---|---|---|---|
float_start |
BOOL | %I0 |
auto from uio device, renamed from
uio_DI1 |
Start float input |
float_stop |
BOOL | %I1 |
auto from uio device, renamed from
uio_DI2 |
Stop float input |
float_alarm |
BOOL | %I2 |
auto from uio device, renamed from
uio_DI3 |
High-alarm float input |
motor_run |
BOOL | %Q0 |
auto from uio device, renamed from
uio_DO1 |
Motor output |
aho_mode |
INT | %MW0 |
added in Tag Database | Operator mode: 0=Off, 1=Hand, 2=Auto |
const_hand |
INT | %MW1 |
added in Tag Database (initial value 1) |
Constant 1, used as IN2 of the CMP block. The CMP
inputs require tag references — this is how you spell the constant
“Hand” |
motor_off |
BOOL | %MX0 |
added in Tag Database | True when aho_mode = 0; set by the CMP block |
motor_hand |
BOOL | %MX1 |
added in Tag Database | True when aho_mode = 1; set by the CMP block |
motor_auto |
BOOL | %MX2 |
added in Tag Database | True when aho_mode = 2; set by the CMP block |
call_motor |
BOOL | %MX3 |
added in Tag Database | “Tank needs the motor” — set by start float, reset by stop float |
alarm_latched |
BOOL | %MX4 |
added in Tag Database | High-alarm latch (set by start-of-alarm float, cleared by button) |
clear_alarms |
BOOL | %MX5 |
added in Tag Database | Clear-alarms button (one-shot, set by HMI, cleared by logic) |
A few conventions to know:
%Iand%Qaddresses map directly to physical I/O channels —%I0is the first input bit,%Q0is the first output bit. The I/O scanner fills%Ifrom the module each scan and writes%Qback out. The exact address numbering depends on how many devices and channels precede this one; the IDE handles the bookkeeping.%MXaddresses are internal memory bits. They have no physical counterpart; they’re storage that lives in arena memory and survives between scans.%MW0is a 16-bit internal word, used here to hold the AHO mode as a small integer (0, 1, or 2).
The Whisker IDE uses these IEC-61131 address conventions for all PLC-style projects. The full address map is in Appendix AB of the main manual.
The other auto-created tags. When you add the mSmart Universal IO module the IDE creates one tag for every channel on the device — roughly 30 tags. You only rename four. The rest stay in your project as untouched
uio_*tags. They don’t hurt anything; the I/O scanner reads them every scan whether you use them or not. If you want a tidier Tag Database, the IO Configuration editor lets you remove individual unused points.
2.4 The control logic — what it does
All three walkthroughs implement the same behavior. Reading this specification before diving into a walkthrough makes the editors a lot easier to follow.
The logic factors into five small steps. Each step is one ladder rung
in W1 and a matching few lines of app.py in W2:
(1) Mode decode — one CMP block compares aho_mode against const_hand (=1):
motor_off := aho_mode < const_hand # LT output (aho_mode = 0 → Off)
motor_hand := aho_mode == const_hand # EQ output (aho_mode = 1 → Hand)
motor_auto := aho_mode > const_hand # GT output (aho_mode = 2 → Auto)
(2) Alarm latch:
if float_alarm: alarm_latched := TRUE
(3) Clear alarms (one-shot):
if clear_alarms:
alarm_latched := FALSE
clear_alarms := FALSE # auto-release the button
(4) call_motor latch (Auto-mode seal-in):
if float_start: call_motor := TRUE # tank wants the motor
if float_stop: call_motor := FALSE # tank doesn't anymore
(5) Motor output:
motor_run := motor_hand
OR (motor_auto AND call_motor AND NOT alarm_latched)
A few points worth flagging because they catch people out:
Why a CMP block instead of three separate equals. The Whisker IDE doesn’t have a standalone EQ instruction — it has a single CMP block that emits LT / EQ / GT outputs from one comparison. That fits this problem perfectly: one CMP rung produces all three mode flags at once, and the rest of the logic reads them like ordinary BOOLs. The same approach scales nicely if you ever add a fourth mode (just add another CMP).
Hand overrides the alarm. Step (5) is just
motor_handORed with the Auto branch — no alarm check on the Hand side. This is a deliberate safety choice (operator on Hand needs to be able to pump down a flooded tank). If your site needs the opposite, drop aNOT alarm_latchedcontact in series withmotor_handand you’re done.The seal-in lives on its own. Pulling the start/stop latch out of the motor rung into dedicated
call_motornetworks makes both cleaner. The motor rung becomes a one-line summary of intent (“Hand, or Auto + call + no alarm”), and the seal-in is two small networks (set on start float, reset on stop float) you can debug in isolation. The split into two networks is because the Whisker IDE allows only one coil per network — the Set and the Reset have to live on separate networks.clear_alarmsis a one-shot, not a level. HMI button writes TRUE; logic clears the latch and immediately writes FALSE back toclear_alarms. If it weren’t one-shot, holding the button down while the alarm condition was still active would re-latch every scan and you’d never see it clear.
2.5 The alarm
A single alert definition in each project:
| Field | Value |
|---|---|
| Name | HighLevelAlarm |
| Condition | float_alarm = TRUE |
| Latched | Yes |
| Output tag | alarm_latched |
| Severity | Warning |
| Message | High-level float is wet |
When float_alarm goes TRUE the alert system sets
alarm_latched and records an entry in the alert history.
The latch stays set until clear_alarms clears it through
the control logic above.
2.6 The HMI screen
One screen, identical across the three walkthroughs. Walkthrough 3’s WhiskerHMI screen is literally a copy of the Walkthrough 1 embedded HMI screen with the controller IP filled in.
Five widget types do all the work:
selectorSwitch— the AHO mode selector. Configured with three positions (OFF=0, HAND=1, AUTO=2) and bound toaho_mode. Writable — the operator’s choice goes back to the controller every time they tap.led— three of them for the float inputs. Read-only indicators. Green when TRUE.pump- formotor_run. Turns green and animates when motor is running.pushButton— the Clear Alarms button. Configured as momentary, bound toclear_alarms. Writes TRUE while held; the controller’s one-shot logic immediately writes it back to FALSE.alertTable— a pre-built widget that shows current and historical alerts. No tag binding; it reads from the alert system’s internal state. You don’t have to wire anything up — drop it on the screen and it Just Works.
2.7 What’s next
You’re ready to build. Pick a walkthrough:
- Walkthrough 1 — Ladder if you want to start with the most visual / most PLC-traditional approach. Recommended if you’re new to the Whisker IDE.
- Walkthrough 2 — Python if you prefer code, or want to see how the same logic shapes up when you can use variables, conditionals, and the full Python standard library.
- Walkthrough 3 — WhiskerHMI if you’ve completed Walkthrough 1 or 2 and now want to put an operator panel in front of it.
The walkthroughs are independent. You don’t have to do all three, and you can do them in any order — though Walkthrough 3 assumes the controller from Walkthrough 1 or 2 is already running so it has something to connect to.
3 Your First PLC Project — Ladder
This walkthrough builds the scenario from The Walkthrough scenario as a ladder-logic PLC project running on a Nexus.io AC controller. By the end you’ll have a working motor controller with a latched alarm, an Auto/Hand/Off selector, and a touchscreen HMI on the controller’s display.
Allow about 45 minutes the first time through. Each subsequent walkthrough will go faster because you’ll already know the IDE’s mechanics.
3.1 Before you start
You need:
- The Whisker IDE installed (Chapter 1).
- A Nexus.io AC controller powered on, on the same LAN as your PC, with the mSmart Universal IO module wired per the wiring map.
- The Walkthrough scenario chapter read (or at least skimmed) — this walkthrough doesn’t re-explain the tags, wiring, or control intent.
3.2 Step 1 — Create the Application and Project
Launch the Whisker IDE.
From the toolbar, click the New Application icon (the leftmost icon, a small workspace symbol).
The New Application dialog appears. Fill it in:
- Application name:
Walkthrough-Ladder - Description: leave blank (or type something brief like “Motor control demo”)
- Application name:
Click Add Project. A New Project sub-dialog opens. Fill it in:
- Project name:
Motor - Target hardware:
Nexus.io AC
- Project name:
Click Add, then Create in the outer Application dialog.
Press Ctrl+S. The IDE prompts for a location to save the Application. Pick somewhere convenient (your Documents folder is fine) and accept the filename
Walkthrough-Ladder.widez.
When the dialog closes you should see:
A new Application named Walkthrough-Ladder in the title bar.
A single project named Motor in the Project Tree on the left.
An empty editor area in the middle.
The Motor project comes pre-populated with a Main task and a Main ladder program — that’s the file you’ll write the logic in. We’ll get there in a few steps.
3.3 Step 2 — Add the mSmart Universal IO module
In the Project Tree, click Motor → IO Config. The IO Configuration editor opens.
Click Add Device in the toolbar. The Add Device dialog opens.
Configure the device:
- IODF: pick
mSmart-Universal-IOfrom the dropdown. (If it’s not there, the IDE hasn’t seeded its default IODFs yet — re-open this dialog and it should appear.) - Instance name:
uio(short for “universal IO” — you’ll reference this name later when mapping points). - Connection settings auto-fill from the IODF:
- Port:
rs485(the only RS-485 port on the Nexus.io AC) - Slave ID:
1
- Port:
- Leave baud rate, parity, data bits, and stop bits at the defaults (19200 / N / 8 / 1) unless your hardware is configured differently.
- IODF: pick
Click Add. The device appears in the IO Configuration table with a cable-style RTU icon to its left.
Click the IO Points tabs below the device table. You should see roughly 30 entries the IDE created automatically — one for every channel on the module. Each tag is named
uio_<channel>(souio_DI1,uio_DI2, …,uio_DO1, …) and has an auto-assigned IEC address.Press Ctrl+S.
Why this is the right place to create I/O tags. Tags that map to physical I/O don’t make sense without a module behind them — the address
%I0only exists because there’s an input channel on a device somewhere. The IDE enforces this: you can’t type a%Ior%Qaddress into the Tag Database directly. You add the device, the IDE creates the tags, you rename them.
3.4 Step 3 — Rename the I/O tags you’ll use
The 30 auto-created tags include analog readings, pulse counters, event rates, and config registers. The walkthrough only uses four of them. Renaming those four to friendlier names makes the ladder and HMI easier to read.
In the Project Tree, expand Motor → Tags and click Tag Database. The Tag Database editor opens. You’ll see the
uio_*tags the IO module created.Click on the
uio_DI1row, then click again on its name to enter edit mode (or use the Rename action in the Properties panel on the right). Change the name tofloat_start.Repeat for the other three:
From To Why uio_DI1float_startStart float input uio_DI2float_stopStop float input uio_DI3float_alarmHigh-alarm float input uio_DO1motor_runMotor contactor output The addresses (
%I0,%I1,%I2,%Q0) don’t change — only the names do. Anywhere else in the project that referenced the old names is updated automatically.Press Ctrl+S.
3.5 Step 4 — Add the memory tags
Seven more tags don’t correspond to any physical wire — they’re internal state the logic uses to remember things between scans, plus the mode flags the CMP block in Step 5 will produce. All of them go in the Tag Database directly.
Still in the Tag Database editor, click Add Tag.
First tag — the operator mode:
- Name:
aho_mode - Type:
INT - Class:
VAR - Memory Area:
Memory Word (16-bit)→ address auto-fills%MW0 - Description:
Operator mode (0=Off, 1=Hand, 2=Auto)
Click Add.
- Name:
Repeat for the remaining seven:
Name Type Memory Area Address (auto) Initial value Description const_handINT Memory Word (16-bit) %MW11Constant used as IN2 of the CMP block — the AHO “Hand” value motor_offBOOL Memory Bit %MX0Mode-decode output: TRUE when aho_mode = 0 motor_handBOOL Memory Bit %MX1Mode-decode output: TRUE when aho_mode = 1 motor_autoBOOL Memory Bit %MX2Mode-decode output: TRUE when aho_mode = 2 call_motorBOOL Memory Bit %MX3Auto-mode seal-in: set by start float, reset by stop float alarm_latchedBOOL Memory Bit %MX4Latched high-alarm clear_alarmsBOOL Memory Bit %MX5Operator clear-alarms pulse Why a tag for a constant? The CMP block’s IN1 and IN2 inputs both expect tag references — the IDE doesn’t let you type a literal number into IN2. So we make one tag,
const_hand, with an initial value of1, and use it as the comparison operand. The tag never changes at runtime; it’s just how you spell “the integer 1” to the CMP block.Press Ctrl+S.
About address prefixes.
%Iand%Qwere assigned to your I/O tags by the module.%MXis the prefix for internal memory bits,%MWfor 16-bit words,%MDfor 32-bit double-words, and%MFfor 32-bit floats. The Memory Area dropdown lets you pick the right one; the IDE fills the address number automatically based on which slots are already taken.
3.6 Step 5 — Write the ladder logic
In the Project Tree, expand Motor → Programs → Main and double-click the ladder file. The Ladder Editor opens with five empty networks — what other PLC platforms call rungs. You’ll need seven for this walkthrough, so click the + button at the top of the editor twice to add two more empty networks at the bottom before you start.
One coil per network. The Whisker IDE enforces a single terminal (coil, timer, counter, FB, etc.) per network. If two outputs need to be driven from the same condition — for example, “when
clear_alarmsis pressed, resetalarm_latchedAND resetclear_alarms” — you spell that as two networks that share the same contact pattern, not as two parallel branches inside one network. That’s why the walkthrough uses seven networks rather than five.
Ladder editor shortcuts you’ll use in this step. The IDE leans on keyboard shortcuts more than drag-and-drop for branch wiring. Worth learning early:
Shortcut What it does drag from Toolbox drop an instruction onto the selected segment Ctrl + Down create a parallel branch below the current branch Ctrl + Up reconnect the current branch back up to its parent Ctrl + Right extend a wire to the left on the current branch Del delete the selected instruction Ctrl + Del delete the entire current network + (toolbar) add a new empty network at the bottom
3.6.1 Network 1 — Decode the operator mode (CMP)
The IDE doesn’t ship a standalone EQ instruction. It ships a
CMP function block that performs one comparison and
produces three outputs (LT, EQ, GT) on a single call. That’s exactly
what we want for AHO — one network gives us motor_off,
motor_hand, motor_auto all at once.
Click into network 1 to select it.
From the Toolbox, drag a CMP block (under Compare) onto the first segment. Click it; in the Properties panel set:
- IN1:
aho_mode - IN2:
const_hand(the constant tag you added in Step 4 — the CMP block expects a tag reference here, not a literal number)
- IN1:
The CMP block exposes three output pins on its right side: LT, EQ, GT. Each is a BOOL. Wire each to a coil:
- LT → drag a Coil (mode
Simple) to the terminal slot, tagmotor_off. Rationale: aho_mode < 1 means aho_mode = 0, which is Off. - EQ → drag a second Coil, tag
motor_hand. Rationale: aho_mode = 1 is Hand. - GT → drag a third Coil, tag
motor_auto. Rationale: aho_mode > 1 means aho_mode = 2, which is Auto.
- LT → drag a Coil (mode
What’s nice about this pattern. Three BOOL flags fall out of one CMP network. The rest of the program reads them like any other contact; nobody downstream needs to know
aho_modeis an integer or what its values mean. That separation makes it easy to add a fourth mode later (e.g. a Maintenance mode ataho_mode = 3) — add a second CMP against 2 and you have four mode flags from two networks.
3.6.2 Network 2 — Latch the alarm
When the high-alarm float closes, latch alarm_latched
with a Set coil so the bit stays on after the float
opens.
- Click into network 2.
- Drag a Normally Open Contact onto the first
segment. Tag:
float_alarm. - Drag a Coil to the terminal slot. Set:
- Tag:
alarm_latched - Mode:
Set/Latch
- Tag:
3.6.3 Network 3 — Clear the alarm latch
When the operator presses Clear Alarms, reset
alarm_latched.
Click into network 3.
Drag a Normally Open Contact onto the first segment. Tag:
clear_alarms.Drag a Reset Coil (
(R)) to the terminal slot. Tag:alarm_latched.
3.6.4 Network 4 — Auto-release the Clear Alarms button (one-shot)
clear_alarms is driven by the HMI button. The HMI writes
TRUE while the button is pressed; we want the controller to
immediately write it back to FALSE so the next scan sees a fresh edge if
the operator presses again. This network resets
clear_alarms using its own value as the trigger — that’s
what makes the button behave as a one-shot pulse even though the HMI
widget writes a level.
Click into network 4.
Drag a Normally Open Contact onto the first segment. Tag:
clear_alarms.Drag a Reset Coil (
(R)) to the terminal slot. Tag:clear_alarms.
Why two networks instead of one? Networks 3 and 4 fire from the same condition (
clear_alarms = TRUE) but drive different coils, and the IDE allows only one coil per network. So we spell the “reset both” intent as two networks with identical contact patterns. They execute in the same scan, so the behavior is equivalent to “reset both at once”.
3.6.5 Network 5 — call_motor SET (start float closes the tank’s request)
Pulling the Auto-mode seal-in out into its own pair of networks keeps
the motor output readable. call_motor represents “the tank
is asking for the motor to run” — it goes TRUE when the start float
closes and stays TRUE (latched) until the stop float clears it in the
next network.
Click into network 5.
Drag a Normally Open Contact onto the first segment. Tag:
float_start.Drag a Set Coil (
(S)) to the terminal slot. Tag:call_motor.
3.6.6 Network 6 — call_motor RESET (stop float clears the request)
Click the ‘+’ button to add a new network - creates network 6.
Drag a Normally Open Contact onto the first segment. Tag:
float_stop.Drag a Reset Coil (
(R)) to the terminal slot. Tag:call_motor.
3.6.7 Network 7 — Drive
motor_run
The payoff network. With all the state already decoded above, this one reads like a one-line sentence:
“Motor runs in Hand, or in Auto when the tank is calling and the alarm isn’t latched.”
Two parallel branches feed one Simple coil:
- Top branch: NO contact
motor_hand. That’s it. - Bottom branch: NO
motor_auto→ NOcall_motor→ NCalarm_latched, all in series.
Click into network 7.
Drag a Normally Open Contact onto the first segment. Tag:
motor_hand.Drag a Coil (mode
Simple) to the terminal slot. Tag:motor_run.With the
motor_handcontact selected, press Ctrl + Down to add a parallel branch below.On the new branch, drag in series:
- Normally Open Contact, tag
motor_auto. - Normally Open Contact, tag
call_motor. - Normally Closed Contact, tag
alarm_latched.
The bottom branch will automatically reconnect to the terminal coil at the right.
- Normally Open Contact, tag
Press Ctrl+S.
Tip: read the network out loud. “Motor runs when (Hand) or (Auto AND tank-calling AND no alarm).” If that sentence matches the behavior you want, the network is correct. If you ever need to change which conditions inhibit the motor, this is the only network you’ll touch — the seal-in (networks 5–6) and mode decode (network 1) stay as-is.
3.7 Step 6 — Define the HighLevelAlarm alert
In the Project Tree, click Motor → Alerts. The Alerts editor opens.
Click Add Alert. Fill it in:
- Name:
HighLevelAlarm - Condition:
float_alarm = TRUE(the condition builder lets you pick the tag and operator from dropdowns) - Latched: ✓ checked
- Severity: Warning
- Message:
High-level float is wet - Output tag: leave blank — the ladder logic already does the latching in Network 2 using a Set coil.
- Name:
Press Ctrl+S.
Two ways to latch — pick one. The alert system can latch on its own and write the result into an output tag. The ladder Set coil in Network 2 also latches. We’re using the ladder version (output tag blank) so the latch logic is visible in one place. If you’d rather let the alert system own the latch, delete Network 2 and set the alert’s output tag to
alarm_latched— but then the Reset coil in Network 3 needs to clear it through the alert’s own reset mechanism instead. The walkthrough sticks with the ladder approach because it’s easier to follow when you’re reading networks.
3.8 Step 7 — Build the HMI screen
In the Project Tree, click Motor → HMI → Screens. Click Add Screen in the toolbar and name it
Main. The HMI Designer opens with an empty canvas.From the Toolbox on the left, drag the widgets onto the canvas in roughly this layout (precise positions don’t matter):
- selectorSwitch at the top — for AHO mode.
- pump below it — for motor run status.
- led × 3 in a row below that — for the three float inputs.
- pushButton at the bottom right — for Clear Alarms.
- alertTable along the bottom — for the alarm display.
- text above the pump - label for Motor
Configure each widget by clicking it and editing the Properties panel:
selectorSwitch:
- Bind
position→aho_mode - Positions: 3
- Labels:
OFF, HAND, AUTO
- Bind
pump (motor run):
- Bind
state→motor_run - Label:
Motor running - On color: green, Off color: dark gray
- Bind
text (motor label):
- Label:
Motor
- Label:
led × 3 (floats): bind each one to
float_start,float_stop,float_alarmrespectively. Labels:Start Float,Stop Float,High Alarm.pushButton:
- Bind
output→clear_alarms - Mode:
momentary - Label:
Clear Alarms
- Bind
alertTable: no binding needed; just drop it on the canvas. It reads alarm state from the alert system on its own.
Press Ctrl+S.
3.9 Step 8 — Connect and Build
Click the Connect icon in the toolbar (the plug icon to the right of Build). The Connect dialog opens and starts scanning the LAN.
When your controller appears in the list, click it and click Connect. If mDNS is blocked on your network, click Enter address manually and type the controller’s IP address.
A confirmation snackbar appears at the bottom of the IDE. The status bar now shows the connection.
Press F5 (or click the Build icon). The Output panel at the bottom shows the compile, then the upload to the controller:
[INFO] Building project: Motor... [INFO] Compiling ladder programs (1)... [INFO] Compiling alerts (1)... [INFO] Generating app.io for I/O scanner... [OK] Build succeeded: 5 files generated [INFO] Uploading to 192.168.1.244... [OK] Upload complete (32 KB)The controller restarts the runtime services automatically and begins executing the new program.
3.10 Step 9 — Test it
If your hardware is wired and your float switches are accessible, this is the fun part.
Verify the HMI — Walk over to the controller’s touchscreen. The Main screen should be showing the layout you designed. The mode selector starts at OFF, all LEDs are dark.
Hand mode — Tap HAND on the selector. The Motor LED turns green and DO1 energizes on the I/O module. Confirm by looking at the module’s DO1 LED.
Off mode — Tap OFF. Motor LED goes dark, DO1 de-energizes.
Auto mode without floats — Tap AUTO. With both floats open, motor stays off (no start signal yet).
Auto seal-in — Briefly close the start float. The Motor LED should turn on and stay on after the float opens again.
Auto stop — Close the stop float. Motor LED goes off.
High alarm — Close the high-alarm float. The Alarm LED lights, the alert table shows
HighLevelAlarm — High-level float is wet, and the motor turns off (if it was on in Auto). Confirm the alarm latches by opening the float — the indicators should stay on.Hand override — While alarmed, tap HAND. Motor turns back on (the safety override). Tap back to AUTO — motor turns off again.
Clear the alarm — Tap Clear Alarms. The alert table clears, the Alarm LED goes dark, and if you’re in Auto with the start float open, the motor stays off until you re-trigger the start condition.
If all nine steps behave as described, you’re done with the Ladder walkthrough. The controller is now running a complete motor-control program with an alarm system and an operator panel.
3.11 What’s next
- Continue to Walkthrough 2 — Python to see the same project written in Python. The contrast between the two approaches is the most educational part of doing both.
- Continue to Walkthrough 3 — WhiskerHMI to add a Windows HMI panel that mirrors the controller’s embedded screen.
- Or stop here and explore. Open the Tag Monitor (Chapter 15 of the main manual) to watch tag values change in real time. Experiment with adding a runtime timer to the alarm latch so it auto-clears after 5 minutes. The ladder logic is yours now.
4 Your First PLC Project — Python
This walkthrough builds the same scenario as the Ladder walkthrough,
on the same Nexus.io AC hardware, with the same I/O module and the same
HMI screen — but the control logic lives in app.py instead
of in ladder networks (rungs). If you’ve already finished the Ladder
walkthrough, most of the setup steps will be familiar.
Reading both walkthroughs side by side is the fastest way to understand when ladder is the right tool and when Python is. Short version: ladder is unmatched for boolean interlock logic the way a maintenance electrician will read it; Python is unmatched when you need arithmetic, data structures, conditionals more than two levels deep, or a library call. The motor scenario fits both, which is exactly why it’s a useful comparison.
Allow about 30 minutes if you’ve already done the Ladder walkthrough, or 45 minutes if this is your first.
4.1 Before you start
Same prerequisites as the Ladder walkthrough — a Nexus.io AC on your LAN, the mSmart Universal IO wired up, and the Walkthrough scenario chapter read.
4.2 Step 1 — Create the Application and Project
Same procedure as Walkthrough 1, Step 1. The only difference is the
naming: call the Application Walkthrough-Py and the Project
Motor (target Nexus.io AC). Save as
Walkthrough-Py.widez. We use a different filename so it can
coexist with the Ladder walkthrough project on your disk.
(If you skipped Walkthrough 1, see its Step 1 for screenshots of the dialogs.)
4.3 Step 2 — Add the mSmart Universal IO module
Same as Walkthrough 1 Step 2 — open Motor → IO
Configuration, click Add Device, pick the
mSmart-Universal-IO IODF, instance name uio,
port rs485, slave ID 1, defaults for the rest.
The IDE auto-creates ~30 uio_* tags, one per channel on the
module.
4.4 Step 3 — Rename the I/O tags
Same as Walkthrough 1 Step 3 — in the Tag Database, rename the four tags the walkthrough uses:
| From | To |
|---|---|
uio_DI1 |
float_start |
uio_DI2 |
float_stop |
uio_DI3 |
float_alarm |
uio_DO1 |
motor_run |
The tag names are what the Python code references — that’s
why they have to match. The addresses
(%I0/%I1/%I2/%Q0)
are unaffected by the rename.
4.5 Step 4 — Add the memory tags
Same as Walkthrough 1 Step 4 — same seven memory tags. The Python
code in Step 5 writes the four intermediate tags (motor_off
/ motor_hand / motor_auto /
call_motor) just like the ladder version does, so you can
see the same intent expressed two ways.
| Name | Type | Memory Area | Address |
|---|---|---|---|
aho_mode |
INT | Memory Word (16-bit) | %MW0 |
motor_off |
BOOL | Memory Bit | %MX0 |
motor_hand |
BOOL | Memory Bit | %MX1 |
motor_auto |
BOOL | Memory Bit | %MX2 |
call_motor |
BOOL | Memory Bit | %MX3 |
alarm_latched |
BOOL | Memory Bit | %MX4 |
clear_alarms |
BOOL | Memory Bit | %MX5 |
4.6 Step 5 — Write the Python application
This is the part that differs. The Motor project comes with a default
app.py containing a stub run(ctx) function and
a brief comment explaining the available API. You’ll replace the stub
with the motor control logic.
In the Project Tree, expand Motor → Python and double-click
app.py. The Python Editor opens.Replace the entire contents of the file with:
"""Motor controller — Walkthrough 2 Implements the AHO state machine, alarm latching, and one-shot Clear Alarms behavior described in the Walkthrough scenario. Equivalent in behavior to the ladder version in Walkthrough 1 — the five sections below mirror Networks 1–5 of the ladder program. """ SCAN_PERIOD_S = 0.05 # 50 ms — matches the I/O scanner cadence def run(ctx): ctx.log.info("Motor controller started") while not ctx.shutdown_requested: # --- Read inputs ---------------------------------------------- float_start = ctx.read_tag("float_start") float_stop = ctx.read_tag("float_stop") float_alarm = ctx.read_tag("float_alarm") clear_alarms = ctx.read_tag("clear_alarms") aho_mode = ctx.read_tag("aho_mode") alarm_latched = ctx.read_tag("alarm_latched") call_motor = ctx.read_tag("call_motor") # previous scan # (1) Mode decode — CMP equivalent ---------------------------- motor_off = aho_mode < 1 # LT (aho_mode = 0 → Off) motor_hand = aho_mode == 1 # EQ (aho_mode = 1 → Hand) motor_auto = aho_mode > 1 # GT (aho_mode = 2 → Auto) # (2) Latch the alarm ----------------------------------------- if float_alarm: alarm_latched = True # (3) One-shot clear ------------------------------------------ if clear_alarms: alarm_latched = False ctx.write_tag("clear_alarms", False) # auto-release # (4) call_motor seal-in -------------------------------------- if float_start: call_motor = True if float_stop: call_motor = False # (5) Motor output -------------------------------------------- motor_run = motor_hand or ( motor_auto and call_motor and not alarm_latched) # --- Write outputs ------------------------------------------- ctx.write_tag("motor_off", motor_off) ctx.write_tag("motor_hand", motor_hand) ctx.write_tag("motor_auto", motor_auto) ctx.write_tag("call_motor", call_motor) ctx.write_tag("alarm_latched", alarm_latched) ctx.write_tag("motor_run", motor_run) ctx.wait(SCAN_PERIOD_S) ctx.log.info("Motor controller stopped")Press Ctrl+S.
A few things worth understanding before you move on:
ctxis the controller’s API surface. Thectxobject is passed intorun(ctx)by the Python runtime on the controller. It gives youread_tag/write_tagfor named tags, lower-leveldi_read/dq_write/mw_read/mw_writefor direct arena access, andwait(seconds)for sleeping in a shutdown-aware way. Don’t usetime.sleep()— it won’t notice when the controller’s service is being shut down for an update.while not ctx.shutdown_requestedis the standard outer loop. When the controller’s smartcontroller service receives a stop or an update, it setsshutdown_requested = Trueandctx.wait()returns immediately so your loop can finish its scan and exit cleanly. Thectx.log.info("...stopped")line confirms you exited normally.The scan period is yours to choose. Ladder is fixed at the task’s configured rate (typically 10 ms on the Nexus.io AC). Python runs in its own thread; you decide how often it loops. 50 ms is a reasonable default for HMI-driven logic — fast enough that the operator doesn’t see latency, slow enough that the controller has headroom for everything else. Drop it to 10 ms if you need ladder- comparable response; raise it to 500 ms if you’re doing heavy calculations between scans.
“Previous scan” semantics for
call_motor. The linecall_motor = ctx.read_tag("call_motor")reads the latch’s previous state into a local variable. If neitherfloat_startnorfloat_stopfires this scan, the local variable still holds the previous value and gets written back unchanged at the bottom. That’s the same pattern as a ladder network where a coil tag is referenced as a contact in the same network — the value being read is whatever was written by the previous scan. In Python you have to do it explicitly; in ladder the editor does it implicitly.No need to update
clear_alarmson the HMI. When you callctx.write_tag("clear_alarms", False), the change goes into arena memory immediately. The HMI runtime polls arena and sees the change on its next refresh, so the button visually de-activates within a few hundred milliseconds.Why write motor_off / motor_hand / motor_auto at all? Strictly, the Python code could just use the local booleans in the motor_run expression and never write them to tags. But writing them gives the Tag Monitor (and the HMI, if you add indicator LEDs) visibility into the controller’s mode decode, matching exactly what the ladder version exposes. It’s a couple of microseconds per scan and it makes the two implementations directly comparable.
4.7 Step 6 — Define the HighLevelAlarm alert
Same as Walkthrough 1 Step 6. Name HighLevelAlarm,
condition float_alarm = TRUE, latched, message
High-level float is wet, output tag blank (the Python code
handles the latch).
4.8 Step 7 — Build the HMI screen
Same as Walkthrough 1 Step 7 — same five widgets, same bindings, same layout. If you’ve already built it in your Ladder project, the fastest path is:
- Open the Ladder walkthrough’s
Walkthrough-Ladder.widezin a second IDE window (File → Open). - In its Project Tree, right-click Motor → HMI → Screens → Main and choose Copy.
- Switch back to this walkthrough’s window, right-click your project’s HMI → Screens node, choose Paste.
Otherwise build it from scratch following Walkthrough 1’s HMI step.
4.9 Step 8 — Connect and Build
Same as Walkthrough 1 Step 8. Connect to the controller, press F5.
This time the build output mentions Python:
[INFO] Building project: Motor...
[INFO] Compiling alerts (1)...
[INFO] Bundling Python application (app.py, 1.2 KB)...
[INFO] Generating app.io for I/O scanner...
[OK] Build succeeded: 4 files generated
[INFO] Uploading to 192.168.1.244...
[OK] Upload complete (28 KB)
The controller’s smartcontroller service detects the new
python_app.json bundle within a couple of seconds, stops
the previous run(ctx) thread (if any), unpacks the new
bundle, and starts the new one. You don’t have to restart anything
manually.
4.10 Step 9 — Test it
Same nine test steps as Walkthrough 1 Step 9 — Hand, Off, Auto seal-in, Auto stop, alarm latches, Hand overrides alarm, Clear Alarms releases. The behavior should be indistinguishable from the ladder version.
If you have both walkthrough projects on hand, try this: deploy the Ladder project, run through the tests, then deploy the Python project and run through them again. You won’t be able to tell which is running just by watching the HMI — which is the whole point.
4.11 What Python gives you that ladder doesn’t
The motor scenario is intentionally simple, so this walkthrough doesn’t show off what Python is genuinely good for. Some things you could try next, that would be painful or impossible in ladder:
Runtime configuration. Read a YAML file shipped with the project, change setpoints without recompiling.
HTTP calls. Fetch a setpoint from a remote service every minute. Push status to a webhook. Pull a weather forecast and adjust based on rain probability.
State machines beyond two levels. AHO is shallow; some processes have nested states (sequencing through a startup procedure, for instance) that get unreadable in ladder fast but stay clean in Python.
Logging and debugging.
ctx.log.info(...)writes to the controller’s system journal. You can tail it from your PC withjournalctl -u smartcontroller -fand watch what your code is doing.Standard library.
datetime,statistics,json,re,collections— all available, all the same Python you know from your laptop.
4.12 What’s next
- Continue to Walkthrough 3 — WhiskerHMI to put a Windows HMI panel in front of the controller you just programmed (whether by ladder or Python).
- Open the Tag Monitor (Chapter 15 of the main manual) and watch the values change as you exercise the floats and selector.
- Try extending the Python code: add a runtime counter that records
motor starts, log it to a file the controller writes nightly. See
Chapter 13 of the main manual for the full
ctxAPI.
5 Your First WhiskerHMI Project
This walkthrough adds a Windows HMI panel to the Application you
built in Walkthrough 1. Instead of creating a new Application from
scratch, you’ll open Walkthrough-Ladder.widez and add a
second Project to it — a WhiskerHMI project — that runs on a Windows PC
and shows the same operator screen the controller’s built-in touchscreen
shows.
WhiskerHMI is a viewer + interactor. It has no I/O, no ladder, no Python, no alerts of its own. It reads tags directly from the controller’s arena agent over TCP and writes operator input back. All control intent still lives in the Motor PLC project from Walkthrough 1. WhiskerHMI just shows it.
The result is a standalone Windows installer (.exe) you can run on a desktop PC, a panel PC on the plant floor, or several PCs at once — every panel sees the same live state from the same controller.
Allow about 15 minutes. You need to have completed Walkthrough 1 first (or Walkthrough 2; the WhiskerHMI side is identical either way).
5.1 Before you start
- Walkthrough 1 (or 2) is complete and the Motor PLC project is running on a Nexus.io AC controller.
- You know the controller’s IP address (the one you connected to in W1 Step 8).
- The PC where the WhiskerHMI panel will run is on the same LAN as the controller. (You can build and test on your dev PC; the installer copies to any other Windows PC.)
5.2 Step 1 — Reopen the Walkthrough-Ladder Application
- File → Open Application, pick
Walkthrough-Ladder.widez. The IDE loads the Application; the Project Tree shows the Motor project from Walkthrough 1.
Why no Modbus setup this time. Earlier versions of WhiskerHMI required you to expose tags via the controller’s Modbus server and manually map them on the panel side. With ArenaTCP the panel reads the controller’s arena agent directly — every tag is automatically readable, no expose step, no Modbus address bookkeeping. The Modbus server is still there if you need it for third-party SCADA, but WhiskerHMI doesn’t use it.
5.3 Step 2 — Add a WhiskerHMI project to the Application
You already have an Application — Walkthrough. You’re going to add a second project to it.
In the Project Tree, click the Application root node (Walkthrough-Ladder) to select it.
From the toolbar, click Add Project to Application (the same button you used in W1 to add the Motor project, but now you’re adding a sibling).
In the New Project dialog:
- Project name:
Panel - Target hardware:
WhiskerHMI
- Project name:
Click Add. The Project Tree now shows two siblings under Walkthrough-Ladder: Motor (the PLC project from W1) and Panel (the new WhiskerHMI project, currently empty).
Press Ctrl+S to save the Application.
What WhiskerHMI looks like in the tree. A WhiskerHMI project has no Programs branch (no ladder), no Functions, no Alerts — only Tags, IO Configuration, and HMI. The IDE knows the target type doesn’t support those features and hides the irrelevant branches.
5.4 Step 3 — Add an ArenaTCP device pointing at the controller
The Panel needs to know which controller to read tags from. ArenaTCP is a direct connection to the controller’s arena agent on TCP port 5000 — no Modbus translation in between.
Panel → IO Configuration → Add Device.
At the top of the dialog, choose ArenaTCP for the device kind (the alternative is IODF-backed Modbus, which is what you used in W1 if you have any RTU devices wired in).
Fill in the ArenaTCP form:
- Instance name:
controller - IP address: the Nexus.io AC’s IP from Walkthrough 1.
- TCP port:
5000(the arena agent default).
- Instance name:
Click Add. The Configured Devices table shows the new
controllerrow with a download icon (Import Tags) next to the delete icon.
Why ArenaTCP and not Modbus. Modbus is the right answer when the remote endpoint is a third-party device that doesn’t speak anything else. Talking from one Whisker controller (or HMI) to another, the arena agent is the native protocol — it carries tag names, data types, and qualities, so the panel doesn’t need a hand-maintained Modbus address table to know what each register means.
5.5 Step 4 — Import tags from the Motor project
Now bring the seven HMI-facing tags from the Motor project into the Panel. Doing this through the import flow keeps the names, types, and controller addresses in sync — no retyping, no transcription errors.
On the
controllerrow in the Configured Devices table, click the download icon (Import Tags).The Import Tags dialog opens. The source list at the top shows sibling projects in the current Application. Pick Motor.
(If your source PLC lives in a separate
.widezfile — say, you’re building a panel for a controller whose project you don’t have open — switch to From file and browse to the.widezor.wapp.)The dialog lists every tag from the Motor project with its type and address. Tick the seven HMI-facing tags:
Tag Type float_startBOOL float_stopBOOL float_alarmBOOL motor_runBOOL aho_modeINT alarm_latchedBOOL clear_alarmsBOOL Leave the four internal scratch tags (
motor_off,motor_hand,motor_auto,call_motor) unticked. The HMI doesn’t need them —motor_runis the actual outcome, andaho_modealready reflects the operator’s mode selection.The Prefix field defaults to
Motor(the source project name). For this walkthrough there’s only one controller so collisions aren’t an issue — clear the prefix field to keep the original tag names. Step 5 imports the screen from Motor and the bindings reference the bare names (motor_run, notMotor_motor_run).Click Import. The dialog reports
7 tags importedand closes.Open Panel → Tags → Tag Database to verify. All seven tags appear with the addresses they had in Motor (
%I0,%Q0,%MW0, etc.). The Panel project records thecontrollerdevice as each tag’s source internally; at build time the IO scanner uses that link to read each tag from the controller’s arena rather than from the panel’s own (empty) local arena.
Why the prefix matters. When a single panel reads from multiple controllers — say three pump stations all running the same Motor app — every controller has its own
motor_run,aho_mode, etc. Without a prefix the second import would collide with the first by name. The convention is to prefix each import with the controller’s identity (PS1_,PS2_,PS3_orStation1_, etc.) so all 21 tags coexist in one panel.Behind the scenes the IDE allocates each imported tag a unique slot in the panel’s local arena. When you import a tag from PS2, the IDE finds the next free local address in that area — so
PS1_motor_runandPS2_motor_runend up at different local slots even though both map to%Q0on their source controllers. At build time the compile-service emits a per-tag mapping (remote%Q0→ local%Q<whatever>); the panel’s IO scanner reads each remote arena and copies each tag’s value into its mapped local slot. For a single-controller panel like this one, no prefix is fine — the imported tags get the same local addresses they had on the source.
5.6 Step 5 — Copy the HMI screen from Motor
The HMI screen you built in W1 Step 7 already exists in the Motor project; you don’t need to rebuild it.
In the Project Tree, right-click Motor → HMI Screens → Main and choose Copy. A notification confirms the screen is on the clipboard.
Right-click Panel → HMI Screens and choose Paste. The Main screen appears under the Panel project with all five widgets and their bindings intact.
The paste also auto-remaps bindings to whatever prefix you chose in Step 4: if you imported with prefix
Motor_, the binding that readaho_modeon Motor’s screen is rewritten toMotor_aho_modeon the Panel’s copy. A notification at the bottom confirms how many bindings were remapped. If multiple ArenaTCP devices in the Panel import from the same source project, the paste asks which controller the screen is for.If you haven’t imported the source tags yet, the paste is refused with a dialog listing what’s missing. Import first, then paste again.
Under Panel → HMI → Windows, confirm that
Mainis the primary window — pasted screens inherit their source’s window role, so this should be the case automatically.
5.7 Step 6 — Build the Panel runtime
Click anywhere inside the Panel project (e.g., select Panel → HMI → Screens → Main in the tree) so the IDE knows which project you want to build.
Press F5. The Output panel shows:
[INFO] Building project: Panel... [INFO] Generating screens.hmi (1 screen) [INFO] Generating symbols.json (7 tags) [INFO] Generating io_scanner_config.json (1 ArenaTCP source) [INFO] Generating app_config.json [OK] Build succeeded: 4 files generatedThe IDE puts the build output in a
build/Panel/folder under your Application directory. The Motor project’s build is inbuild/Motor/— they don’t interfere.
Build vs Generate Installer. Build produces the runtime configuration files. To run the panel on another PC, you generate a Windows installer that bundles the WhiskerHMI runtime executable together with the Panel build output — that’s the next step.
5.8 Step 7 — Generate the Windows installer
Click the Generate Installer icon in the toolbar (a small package / box icon). Make sure the Panel project is selected; the button is only enabled for WhiskerHMI projects.
The Installer dialog opens. Fill in:
- App name:
Walkthrough Motor Panel - App version:
1.0.0 - Publisher: your name or company
- Output folder: somewhere convenient
- App name:
Click Generate. The IDE invokes Inno Setup; after a few seconds the Output panel reports:
[INFO] Bundling WhiskerHMI runtime... [INFO] Bundling project config (Panel)... [INFO] Running Inno Setup... [OK] Installer created: WalkthroughMotorPanel-Setup-1.0.0.exe (24.7 MB)The installer .exe lands in the output folder. That’s the whole deliverable — a single file you can copy to any Windows PC.
5.9 Step 8 — Install and run on a PC
Copy the .exe to the PC where the panel will live (your laptop works for testing). Double-click it:
User Account Control prompts for permission — click Yes.
The installer wizard runs through License, Destination Folder (
C:\Program Files\Walkthrough Motor Panel\by default), shortcuts, Install, Finish.The HMI panel launches automatically. The window opens, fills with the Main screen layout, and starts polling the controller’s arena agent.
If the screen comes up blank or shows “Connecting…” for more than a few seconds, the panel can’t reach the controller. Check:
- The PC and controller are on the same subnet.
- The IP address in Step 3 matches the controller’s current address (DHCP can move it).
- Port 5000 (arena agent) isn’t blocked by a firewall between them.
5.10 Step 9 — Test it
Tap the AHO selector switch from OFF → HAND on the Windows HMI panel. The motor LED in the Windows panel turns green — and at the same moment, the controller’s built-in touchscreen shows the same change because both panels are reading the same controller state.
Trigger the high-alarm float (physically or via tag forcing). The alarm latches on both panels. Press Clear Alarms on either panel and both clear.
That’s the point of WhiskerHMI: as many panels as you want, each showing the same live state, all writing back through the same arena agent. Run the panel on three workstations and each operator sees the same thing.
5.11 What’s next
- Set the WhiskerHMI runtime to auto-launch on the panel PC’s boot (Chapter 17 of the main manual).
- Add a second screen to the Panel project (e.g., a trends screen showing motor run-time history) using the same Generate Installer flow — one installer, multiple screens.
- Build a multi-controller panel by adding a second ArenaTCP
device pointing at a different controller and importing tags from that
controller’s project with a distinct prefix (e.g.
PS2_). The same Panel can display state from any number of controllers side by side. - Read about WhiskerHMI’s security model (PIN-gated settings, signed configuration bundles) in Chapter 16 of the main manual before shipping a panel into production.
6 Where to go next
You’ve built three projects that touch every major editor in the Whisker IDE — Tag Database, IO Configuration, Ladder, Python, Alerts, HMI Designer, and the Modbus server — plus the deploy pipeline for both PLC and HMI targets. You know enough now to build real things.
The rest of this section points at where to deepen each piece.
6.1 The full user manual
The Quick Start Guide you just finished is an extract from the full Whisker IDE user manual. The full manual covers:
| Chapter | Topic |
|---|---|
| 2 | The Workspace — every panel, every toolbar button, every keyboard shortcut |
| 3 | Projects and Applications — multi-project layouts, sharing tags |
| 4 | Controller setup — first-time provisioning, network, time |
| 5 | Target hardware — every supported HDL, ports, expansion |
| 6 | Tag Database — full address map, classes, types, PVs |
| 7 | IO Configuration — every supported IODF, polling, error handling |
| 8 | Ladder editor — every element, function blocks, custom FBs |
| 9 | Functions and tasks — periodic, event-driven, freewheel |
| 10 | HMI Designer — every widget, themes, layout, multi-screen flow |
| 11 | Alerts editor — conditions, severity, output tags, latch policies |
| 12 | Modbus server — address allocation, range customization |
| 13 | Python editor — the full ctx API, threading,
dependencies |
| 14 | Connecting and deploying — security modes, discovery, OTA |
| 15 | Monitoring and debugging — Tag Monitor, journalctl, AI Fix |
| 16 | Security — PKI, signed bundles, RBAC |
| 17 | Generating installers — WhiskerHMI panel deployment in detail |
The full manual lives at
d6labs.com/docs/whisker-ide-manual and ships as an HTML and
PDF alongside this Quick Start Guide.
6.2 In-IDE help
- Help → User Manual opens the local copy of the full manual.
- Help → Quick Start Guide opens this document.
- Help → Keyboard Shortcuts opens a quick reference.
- Hovering most toolbar icons shows a tooltip with the shortcut (F5 for Build, etc.).
6.3 Sample projects
The IDE ships with a handful of reference projects you can open and inspect:
- lift_station.widez — Three-pump duplex lift station with alternation, runtime balancing, and a SCADA-ready Modbus map.
- sample_pump_station.widez — Single-pump system similar to this walkthrough but with analog pressure feedback instead of float switches.
- whisker_hmi_demo.widez — A multi-screen WhiskerHMI panel showing trend charts, alarm history, and recipe selection.
Open them with File → Open Sample Project.
6.4 When you get stuck
- Output panel errors usually have an AI Fix button next to them — clicking it sends the error context to the Whisker IDE’s built-in AI helper, which suggests a one-rung, one-line, or one-config-field fix you can apply with one click.
- The journalctl on the controller is your friend.
SSH in and run
journalctl -u smartcontroller -ffor Python logs,journalctl -u arena_agent -ffor I/O scanner activity, andjournalctl -u ladder_vm -ffor ladder execution. - Appendix AC of the full manual is a troubleshooting guide organized by symptom (motor doesn’t run, HMI shows blank, Build fails, etc.).
6.5 Community and support
- Documentation site:
d6labs.com/docs - Sample projects + reference designs:
d6labs.com/library - Issue tracker:
github.com/d6labs/whisker-ide/issues - Email support:
info@d6labs.com - Phone (US business hours): 1-844-365-8647
6.6 What we’d love to hear about
D6 Labs prioritizes new IDE features based on what users actually build. If you’ve extended this walkthrough into something interesting — a real production lift station, a hybrid Python/ladder scheme, an unusual WhiskerHMI deployment — drop us a note. Screenshots and brief descriptions go a long way.
Happy building.