1 Getting Started
Welcome to the Whisker IDE — the design environment for the D6 Labs Nexus.io family of automation controllers. This chapter takes you from download to a first look at the workspace, introduces the handful of concepts the rest of the manual builds on, and points you to the hands-on walkthroughs.
1.1 About this manual
The Whisker IDE ships in two editions built from the same code:
- Cloud edition. Signs in to a Whisker.io account. Adds the Cloud Explorer, cloud provisioning of controllers, Publish to Cloud and the Account section of the Security dialog. It also has a Continue Offline button on the sign-in screen for days without a connection.
- Offline edition. No account and no cloud features. It installs as Whisker PLC IDE Standalone. Its Security dialog holds the site certificate authority and the local keystore, so a plant can run its own managed controllers without a cloud account.
This one manual covers both. Where a feature needs an account, the chapter says so; everything else — tags, ladder, HMI, alerts, Python, emulation, deploying — works the same in both editions.
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 | 1 GB free | 2 GB free (projects, HMI runtime bundles) |
| Display | 1280 × 720 | 1920 × 1080 or larger |
| Network | Ethernet or Wi-Fi on the same LAN as your controller | Same, plus internet access for the Cloud edition |
The IDE itself runs without an internet connection. You need the LAN to reach your controllers, and the Cloud edition needs internet access to sign in and to talk to Whisker.io.
1.3 Downloading the IDE
D6 Labs supplies the IDE as a single zip file per edition, named
whiskeride_v<version>_cloud_windows.zip or
whiskeride_v<version>_standalone_windows.zip. Ask
your D6 Labs contact for the edition you have licensed. The zip contains
the installer plus four short text files (README, LICENSE, CHANGELOG,
THIRD-PARTY-NOTICES) and the Quick Start PDF.
When the download completes, locate the file in your Downloads folder (or wherever your browser saves downloads).
Note. If your browser warns that the file might be dangerous, choose Keep. Windows SmartScreen can flag any installer it has not seen many times before. Check that the file came from D6 Labs, then continue.
1.4 Installing the IDE
1.4.1 Step 1 — Extract the zip
- Right-click the downloaded zip file.
- Choose Extract All…
- Accept the default destination and click Extract.
The extracted folder contains:
| File | What it is |
|---|---|
WhiskerIDE-Cloud-<version>-Setup.exe or
WhiskerIDE-Standalone-<version>-Setup.exe |
The installer |
README.txt |
Quick reference matching this chapter |
LICENSE.txt |
End-user licence agreement |
CHANGELOG.txt |
Notable changes in this release |
THIRD-PARTY-NOTICES.txt |
Open-source component attributions |
WhiskerIDE-QuickStart-v<version>.pdf |
The Quick Start guide |
1.4.2 Step 2 — Run the installer
Double-click the
Setup.exefile.Note. Windows may show a “Windows protected your PC” warning because the installer was downloaded from the internet. Click More info → Run anyway. This appears before the User Account Control prompt in the next step.
Windows asks for permission to make changes. Click Yes.
The setup wizard appears. The defaults suit almost everyone:
Screen What to do License Agreement Read it, choose I accept, click Next Select Additional Tasks Tick Create a desktop icon if you want one. Click Next Ready to Install Click Install Completing Setup Leave Launch Whisker IDE ticked. Click Finish When installation finishes the IDE launches.
1.4.3 Step 3 — Confirm the install
You should now have a Start menu entry named Whisker PLC IDE (Cloud edition) or Whisker PLC IDE Standalone (Offline edition), a desktop shortcut if you chose one, and an entry under Settings → Apps. The IDE is installed under Program Files in a folder of the same name. You can delete the zip and the extracted folder.
The installer also places the HMI runtime, the I/O scanner service and the PLC compiler alongside the IDE; you do not install those separately.
1.5 First launch
1.5.1 Cloud edition — sign in
The Cloud edition opens on a sign-in screen with Email, Password, a Remember me box, Sign In, and below a divider, Continue Offline.
Sign In does two things. It authenticates you with Whisker.io, and it fetches your IDE certificate — the credential a managed controller checks before it accepts your connection or your deploy. You do not set up certificates by hand; signing in once per PC is enough. If your account uses two-factor authentication, a Two-Factor Authentication screen asks for the Verification Code from your authenticator app.
Continue Offline skips the account. You get the same workspace with the cloud features hidden; you can still emulate, connect to a standalone controller (or a managed one you hold a site identity for) and deploy. Sign in later from the Cloud indicator in the status bar.
Note. Remember me keeps your e-mail address and password in Windows-protected storage, encrypted for your Windows user account, so the IDE can sign you in next time. Another Windows account on the same PC cannot read them, but anyone using your account can open the IDE signed in — do not tick it on a shared login. (Earlier releases kept them in plain files in Documents; the first start of this release moves them into protected storage and deletes the files.)
1.5.2 Offline edition
The Offline edition has no sign-in screen; it opens straight to the workspace.
1.5.3 The first workspace
Either way, you arrive at an empty workspace with two buttons in the editor area: New Application and Open Application.
On first launch the IDE also creates your default project folder,
DocumentsProjects, and copies two finished sample
projects into it: walkthrough_ladder.widez (the Quick
Start’s motor scenario in ladder logic) and
walkthrough_py.widez (the same scenario in Python).
Open Application starts in that folder, so opening a
sample is a two-click way to see a complete project.
The window title tells you which edition you are running:
Whisker PLC IDE or Whisker PLC IDE
Standalone. When an Application is open, the title shows its
file name; a leading * means there are unsaved changes.
1.6 Core concepts
Application — the file you open and save. An
Application is a .widez archive that holds one or more
Projects plus an Application-level Design Spec and a little metadata
(customer, site, notes). A single-controller installation is an
Application with one Project; a controller with an operator PC is an
Application with two.
Project — one program for one controller (or one PC application). A Project has a Target, a Tag Database, and — depending on the Target — ladder programs and tasks, I/O configuration, HMI screens, alerts and Python files. Projects live inside the Application archive; they are not separate files on disk. See Projects and Applications.
Target — the kind of hardware a Project runs on. The Target Hardware dropdown offers three:
Nexus.io AC— the Nexus.io Automation Controller, a panel PLC with a 10-inch touchscreen. The HMI screens you draw in the IDE are shown on that touchscreen; there is no separate HMI box.SmartController Classic— the SmartController (Classic), D6 Labs’ earlier MicroPython controller, programmed over USB serial with the Python editor. No display.WhiskerHMI— a Windows application, not hardware. The IDE builds your screens into a program you install on any Windows PC; it reads live tags from a Nexus.io controller over the network and shows the same screens the controller’s own touchscreen can show. Install it on as many PCs as you need.
Target Hardware in the IDE describes each in detail.
Tag — a named variable. Tags have a type — BOOL, INT
(16-bit), DINT (32-bit) or REAL — and an address in controller memory:
%MX for BOOL, %MW for INT, %MD
for DINT, %MF for REAL; physical inputs are
%I… and outputs %Q…. Ladder logic, HMI
widgets, alerts, the Modbus map and Python all refer to tags by name.
See Tag Database.
Task — the schedule a ladder program runs on. There
are three kinds: Cyclic (every N milliseconds — the
Main task every new project starts with is cyclic at 10
ms), Event (once, when a chosen memory bit changes on a
rising, falling or either edge) and Freewheel (as fast
as the controller allows, for logic that paces itself). Tasks appear
under Tasks in the Project Tree. See Function
Blocks, Faceplates and Tasks.
Device — a piece of external I/O the controller talks to: a Modbus RTU module on RS-485, a Modbus TCP device, another Nexus.io controller (ArenaTCP) or an EtherNet/IP PLC. Adding a device creates its tags for you. See I/O Configuration and Devices.
Design Spec — a Markdown document attached to every Application and Project, with sections for overview, I/O, tags, control logic, screens and alarms. The IDE keeps its tag and Modbus tables up to date; the AI Designer reads it. See Projects and Applications.
1.6.1 I/O acronyms used in this manual
| Acronym | Meaning | Example |
|---|---|---|
| DI | Digital input — on/off signal into the controller | float switch, push button, limit switch |
| DO (or DQ) | Digital output — on/off signal out of the controller | contactor coil, relay, indicator lamp |
| AI | Analog input — continuously variable signal in | 4–20 mA pressure transmitter, 0–10 V level sensor |
| AO (or AQ) | Analog output — continuously variable signal out | 4–20 mA valve command, 0–10 V speed reference |
The IDE assigns the %I / %Q /
%IW / %QW addresses when you add a device; you
never type them by hand.
1.6.2 Arena memory
The arena is the controller’s shared in-memory tag
store: one block of RAM holding the current value of every tag. The
ladder runtime writes it every scan; the HMI, the Modbus server, the
Python task, the historian and the cloud agent all read and write the
same block, which is why every part of the controller sees the same
values. Day to day you can think of it as “where tag values live”. The
name shows up in Tag Monitor, in
ArenaTCP (one controller or PC reading another
controller’s arena) and in the Python ctx.read_tag()
call.
1.7 A tour of the workspace
- Toolbar — file operations, Build, Build & Emulate, Connect, the controller’s run/stop/debug modes and monitoring. The row changes with the active project’s Target.
- Project tree — the open Application and everything in its Projects. In the Cloud edition a Cloud tab beside it is the Cloud Explorer.
- Editor area — the Tag Database, ladder programs, HMI screens and other editors, each in a tab.
- Properties panel — click anything (a tag, a ladder element, a widget, the project itself) and edit it here. This is how all editing of existing items works; dialogs are only for creating and deleting.
- Toolbox — what you can add to the active editor.
- Bottom panel — Output (build and deploy messages), Statistics, Tag Monitor (live values), Python Log, and the others described in The Workspace.
- Status bar — project name, cloud sign-in state and controller connection state.
The Workspace covers every region in detail.
1.8 Three ways to run a program
- Build & Emulate — compiles the open project and runs it on your PC. No controller needed; monitoring works against the emulator. This is the path to take if you are working without hardware.
- Build (F5) — for a Nexus.io project the button is enabled only while you are connected to a controller: press it and the IDE compiles and downloads the program to the connected controller in one action. Building for a SmartController (Classic) or a WhiskerHMI project needs no connection.
- Run — for a WhiskerHMI project, starts the PC application on this machine with the screens you just built.
Before any build, the IDE checks that every tag your logic refers to exists in the Tag Database and offers to create the missing ones.
1.9 What’s next
The Quick Start walks you through one physical scenario — a motor, three float switches, an Off/Hand/Auto selector and a latched high-level alarm — three times over:
- The Walkthrough scenario sets up the hardware, wiring and tag names the walkthroughs share, and explains the two ways to start with a new controller: enrol it into your Whisker.io account, or simply connect to it as the standalone unit it ships as (with a site certificate authority you run yourself as the optional way to manage it without the cloud).
- Your First PLC Project — Ladder builds the control logic as ladder networks on a Nexus.io controller.
- Your First PLC Project — Python builds the same logic in Python on the same controller.
- Your First WhiskerHMI Project builds a Windows operator panel that connects to the controller over the network.
If you have a controller on your bench, start with The Walkthrough scenario. If you do not, the ladder and Python walkthroughs can be completed against the emulator with Build & Emulate; only the deploy and the physical test need hardware.
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 separate HMI panel on a PC — 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 exercise by toggling float switches and watching the system respond.
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. Four inputs (three floats plus an operator mode selection), one output, one latched alarm, one operator panel.
The diagram above shows the physical setup. The three float switches
(Start, Stop, High) sit at three heights inside the tank. The pump
drives the tank’s discharge. All four field signals wire into the
mSmart Universal IO module on inputs DI1,
DI2, DI3 and output DO1 — those
module channels become the tags float_start,
float_stop, float_alarm, and
motor_run after you rename them in Step 3 of each
walkthrough. The Nexus.io Automation Controller talks to the mSmart
module over Modbus RTU on its RS-485 port; the wiring
map below spells out which DI/DO maps to which tag.
2.2 Choose your path
A new Nexus.io controller arrives ready to use: plug it into your LAN and the IDE finds it as a Standalone controller that accepts a plain connection and takes whatever program you build. How you work with it from there depends on one question — is this controller going to be connected to the Whisker.io cloud? Every walkthrough step that depends on the answer is marked Path A or Path B. Everything else — tags, logic, screens, testing — is the same.
Path A — Cloud. You use the Cloud edition of the IDE and have a Whisker.io account. In the Cloud Explorer you provision the controller as a device in your account; the IDE hands it its enrolment bootstrap and the controller fetches its own certificate from your account’s certificate authority, then restarts in managed mode. From then on the IDE connects to it securely with the certificate the cloud issued to you at login, only signed programs from your account are accepted, and its data flows to your account. A cloud-connected controller is always managed — enrolment does that for you. See Security, Provisioning and Enrolment for the full story.
Path B — No cloud. You run the IDE without an account. Connect to the controller by discovery or by address and deploy; nothing else is required. Whether the controller should also be managed — every engineer with their own identity, only signed programs accepted, revocation when someone leaves — is your call. If you want that without a cloud account, one PC at your site becomes the site’s certificate authority (Security dialog → Site section → Make this keystore a site…) and provisions the controller with Provision unit (site); engineers import an identity package from that PC. You own that certificate authority; D6 keeps no copy of it. See Security, Provisioning and Enrolment. None of the walkthroughs needs it.
Tip. If you have an account, do Path A’s provisioning before Step 8 of the first walkthrough — it is one dialog. On Path B there is nothing to do in advance. {.tip}
Steps 1–7 (creating the project, tags, logic and screen) need no controller at all — and if you have no controller yet, Build & Emulate runs the finished project on your PC: the IO Stimulus tab lets you flip the float switches by hand and the HMI Preview tab shows the screen (see Connecting, Deploying and Emulating).
2.3 The hardware
You need three things:
- A Nexus.io Automation Controller on your LAN, powered on (provisioned into your account first if you are on Path A).
- 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.3.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.3.2 RS-485 settings
The demo mSmart module talks Modbus RTU at the following settings. Both ends of the RS-485 link must agree, or no data flows.
| Setting | Value |
|---|---|
| Baud rate | 9600 |
| Data bits | 8 |
| Parity | None |
| Stop bits | 1 |
| Slave ID | 1 |
| Controller serial port | rs485 (UART 1) |
Set the baud rate to 9600 on the controller. The demo module runs at 9600, not the 19200 some controllers ship with — if the rate is wrong you’ll add the device fine but read all zeros. The controller’s RS-485 settings are described in Setting Up Your Nexus.io Automation Controller. The IDE-side device picks up its rate from the same
rs485port, so the two stay in sync once the controller is set.
2.4 Tags — where they come from
The walkthroughs use the twelve tags below — four
I/O tags and eight memory tags. (The Python walkthrough
skips const_hand, so it uses eleven.) 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 eight 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 the Tag Database chapter of the full 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.5 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 the Ladder Walkthrough and a matching few lines of
app.py in the Python Walkthrough:
(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 compares. The Whisker IDE has single comparison contacts (EQ, NE, GT and so on) and also a CMP block that emits LT / EQ / GT outputs from one comparison. The block fits this problem perfectly: one CMP network 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.6 The alarm
A single alert definition in each project:
| Field | Value |
|---|---|
| Name | HighLevelAlarm |
| Condition | float_alarm = TRUE |
| Latched | No (unchecked) |
| Output tag | (blank — leave it empty) |
Name, condition, latch flag, and output tag are the only configurable fields — there is no separate severity or message.
The alert is deliberately non-latched. Each time
float_alarm goes TRUE it records a FIRED entry
in the alert history, and each time it goes FALSE it records a
CLEARED — so every occurrence shows up, not just the first.
(A latched alert fires once and stays active until an explicit reset,
which would give you a single stuck entry instead of an event log.)
Latching lives in the ladder, not the alert. The
motor interlock is held by the Set/Reset coils that drive
alarm_latched (the control logic above), and the
Clear Alarms button clears that latch. The alert sits
alongside it purely to record occurrences for the history and the HMI
alert table.
2.7 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.8 Watching the live data — Tag Monitor
Before you start a walkthrough, it helps to know where you’ll watch the controller think. The Whisker IDE has three live-data views, and you’ll lean on all of them during testing:
- Tag Monitor — bottom-panel tab, table view of every
addressed tag and its current value, refreshed every poll cycle. This is
the fastest way to confirm an input is wired correctly: wiggle a float
switch, watch the
float_*row flip0→1in well under a second. Filter box narrows the list (float,motor, etc.); the eye icon toggles system tags (Comm OK, Cell health) in or out of view; the copy icon dumps the whole visible table to the clipboard as TSV. You’ll use the Tag Monitor in Step 9 of each walkthrough. - Ladder editor’s Debug Mode (Walkthrough 1 only) — colors every contact and coil green/grey based on its live state. Best for “is the rung firing?” questions.
- Python Log — the controller’s
ctx.log.info(...)output streamed live, every entry selectable and copyable for pasting into chat or a bug report.
If you only remember one: the Tag Monitor is the one you’ll open first when something doesn’t behave the way you expect.
Note. Live values appear only after the IDE knows the controller is running the project you have open — in practice, after you press Build in Step 8 of a walkthrough. Until then the Tag Monitor stays empty on purpose, so you never read a stale program’s memory under your project’s tag names.
2.9 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 Automation 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 (see Getting Started).
- A Nexus.io controller powered on, on the same LAN as your PC (provisioned into your account first if you are on Path A — see Choose your path in the scenario chapter), with the mSmart Universal IO module wired per the wiring map. Steps 1–7 need no controller; Step 8 does.
- 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 New Project. A New Project sub-dialog opens. Fill it in:
- Project name:
Motor - Target hardware:
Nexus.io AC
Click Add to attach the Project to the new Application — you’ll return to the outer Application dialog with
Motorlisted.- Project name:
Back in the outer Application dialog, click Create.
The IDE automatically opens a Save dialog for the new Application. Pick somewhere convenient (your Documents folder is fine) and accept the filename
Walkthrough-Ladder.widez. No need to press Ctrl+S — the Create button saves for you.
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 → Setup → IO Config. The IO Configuration editor opens.
Click Add Device in the toolbar. The Add Device dialog opens.
Configure the device:
- Device Kind: select Modbus / EtherNet-IP device (from IODF). This is the first choice in the dialog and it determines which fields appear below.
- Device Type: 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 device type:
- Port:
rs485(the RS-485 port on the Nexus.io controller) - Slave ID:
1
- Port:
Click Add Device. The new device appears in the Configured Devices panel with a cable-style RTU icon to its left.
Look at the Digital Inputs, Digital Outputs, Analog Inputs, and Analog Outputs panels below the Configured Devices panel. The IDE has auto-created roughly 30 tags — one for every channel on the module — and distributed them into the right panel by type. Each tag is named
uio_<channel>(souio_DI1,uio_DI2, …,uio_DO1, …) and has an auto-assigned IEC address.Disable the IO points you won’t use. Each row in the Digital Inputs / Digital Outputs / Analog Inputs / Analog Outputs panels has a checkbox at its left edge. When enabled (the default) the IO scanner polls that channel every scan cycle. The walkthrough uses only four channels —
DI1,DI2,DI3, andDO1. Enable those and disable everything else:- Digital Inputs: keep
DI1,DI2,DI3; uncheckDI4,DI5,DI6. - Digital Outputs: keep
DO1(it’s the only one). - Analog Inputs: uncheck all of them —
AI1–AI5, every… Filter Window, every… Total Count, every… Events Per Min, andSolar Voltage. (The per-channel counters and filter windows are word values, so the IDE files them under Analog Inputs, not Digital Inputs.) - Analog Outputs: uncheck
AO1(uio_AO1).
Disabled rows dim out and stay in your project — flip the checkbox back on if you want them later.
Why this matters. The IO scanner does one Modbus transaction per enabled point per scan cycle. With all ~30 points enabled you’re spending most of the bus’s time reading values you never look at, and any one of those transactions can time out and slow the next scan. Trimming to the four you use takes wire traffic from ~30 transactions/scan down to ~2 (one coalesced read of DI1-3 plus one write to DO1) and makes the end-to-end response feel instant.
- Digital Inputs: keep
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.Double-click the
uio_DI1row’s name cell to edit it in place. Typefloat_startand press Enter. There is no “Rename” button or menu — name editing is just an in-place edit on the name cell.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
Eight 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 Class Memory Area Address (auto) Initial value Description const_handINT CONST Memory Word (16-bit) %MW11Constant used as IN2 of the CMP block — the AHO “Hand” value motor_offBOOL VAR Memory Bit %MX0Mode-decode output: TRUE when aho_mode = 0 motor_handBOOL VAR Memory Bit %MX1Mode-decode output: TRUE when aho_mode = 1 motor_autoBOOL VAR Memory Bit %MX2Mode-decode output: TRUE when aho_mode = 2 call_motorBOOL VAR Memory Bit %MX3Auto-mode seal-in: set by start float, reset by stop float alarm_latchedBOOL VAR Memory Bit %MX4Latched high-alarm clear_alarmsBOOL VAR Memory Bit %MX5Operator clear-alarms pulse Set the Class column carefully. Every tag here is
VAR(the default, likeaho_mode) exceptconst_hand, which must beCONST. The Class field is in the Tag properties panel.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 ClassCONSTand an initial value of1, and use it as the comparison operand. As aCONSTit never changes at runtime; it’s just how you spell “the integer 1” to the CMP block. (Leaving itVARlets the logic overwrite it, which breaks the comparison.)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 → Tasks and click Main. (Main is a task, not a folder, so it doesn’t expand — a single click on the task opens its ladder program directly; a double-click works too.) The Ladder Editor opens with five empty networks — what other PLC platforms call rungs. The sub-steps below add more networks as you need them using the + button at the top of the editor.
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 right 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
Two conventions for the networks below. (1) You don’t need to click a network to “select” it first — just drag the instruction onto the target network’s segment. (2) In the element dialogs a contact asks for a Tag Name and a coil asks for an Output Tag; the steps use those labels.
3.6.1 Network 1 — Decode the operator mode (CMP)
The IDE has single comparison contacts (EQ, NE, GT and so on — see
the Ladder Instruction Reference), but it also ships a
CMP function block that performs one comparison and
writes three BOOL output tags directly — one each for “less than”,
“equal”, and “greater than”. That’s exactly what we want for AHO — one
network gives us motor_off, motor_hand,
motor_auto all at once.
CMP is a sink instruction (like a coil). It has no right-hand output pin; instead its three outputs are set as properties in the property dialog and written to tag values directly. You drop one CMP in the terminal slot of a network and the network is complete.
From the Toolbox, drag a CMP block (under Compare) onto the terminal slot at the right end of network 1. A dialog appears. Give the block an Instance name (e.g.
cmp_mode), then set the properties in the order the dialog lists them — IN1, IN2, then GT, EQ, LT:- 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) - GT output:
motor_auto(Rationale: aho_mode > 1 means aho_mode = 2, which is Auto.) - EQ output:
motor_hand(Rationale: aho_mode = 1 is Hand.) - LT output:
motor_off(Rationale: aho_mode < 1 means aho_mode = 0, which is Off.)
Click OK. The CMP block sits in the terminal slot with the four bound tag names labelled on it. There is no coil to wire — the CMP block writes the three output tags itself every scan.
- IN1:
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 to compareaho_modeto the value 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 Set Coil (
(S)) — the coil marked with ansin the toolbox — to the terminal slot. There is no “mode” to choose: the popup asks only for the output tag. Enteralarm_latched.
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 the + button to add network 7.
Drag a Normally Open Contact onto the first segment. Tag Name:
motor_hand.Drag a Simple Output coil to the terminal slot (that’s the label in the toolbox tooltip). Output 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.
With the last contact (
alarm_latched) selected, press Ctrl + Up to reconnect the sub-branch back to the parent rung so the two branches feed the samemotor_runcoil. (The branch does not auto-reconnect; you have to ask for it explicitly.)- Normally Open Contact, tag
Press Ctrl+S.
Tip: read the network out loud. “Motor runs when (Hand) or (Auto AND call_motor 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. The dialog asks only for a Name — enter
HighLevelAlarmand confirm. The new alert appears in the Alerts list; select it and configure the rest in the Properties panel on the right:- Condition: build
float_alarm == True. Pickfloat_alarmfrom the left dropdown; because it’s a BOOL tag the value field becomes a True / False picker — choose==and True. (The condition editor adapts to the tag’s type: BOOL gives a True/False picker, INT/DINT a whole-number field, and REAL a decimal field.) - Latched: leave unchecked. A
non-latched alert tracks the condition — it logs a
FIREDeach timefloat_alarmgoes true and aCLEAREDwhen it goes false, so every occurrence shows up in the alarm history. (A latched alert fires once and stays active until an explicit reset — not what you want for an event log.) - Output tag: leave blank. The motor interlock is latched separately by the ladder Set/Reset coils in Networks 2–3; this alert just reports occurrences for the history and alert table.
The Alert system does not currently have severity or per-alert message fields; the only configurable pieces are name, condition, latch flag, and output tag.
- Condition: build
Press Ctrl+S.
Latching lives in the ladder, not the alert. The motor interlock latches via the Set/Reset coils in Networks 2–3 (
alarm_latched), and the Clear Alarms button clears it. The alert is deliberately non-latched so the alarm history logs every high/low of the float instead of one stuck entry. Two separate jobs: the ladder holds the interlock; the alert records events.
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.Place the widgets on the canvas. Widgets aren’t dragged in from the Toolbox — single-click a widget in the Toolbox and the IDE autoplaces it on the canvas; then drag it from the canvas into the position you want. Place these widgets:
- selectorSwitch at the top — for AHO mode.
- pump below it — for motor run status.
- text above the pump — label for the motor.
- led × 3 in a row below the pump — for the three float inputs.
- pushButton at the bottom right — for Clear Alarms.
- alertTable along the bottom — for the alarm display.
Configure each widget by clicking it and editing the Properties panel.
Tag bindings live at the bottom of the Properties panel. For each widget below, click it on the canvas and scroll the Properties panel to its Bindings section at the bottom. That’s where every “Bind X → tag” instruction below is set; the upper parts of the Properties panel cover label, colors, and other look-and-feel options.
selectorSwitch (the properties appear in this top-to-bottom order in the panel):
- Positions: 3
- Labels:
OFF, HAND, AUTO - Bind
position→aho_mode(in the Bindings section at the bottom of the panel)
pump (motor run):
- Bind Running →
motor_run. The pump has no single “state” binding — it exposes separate Running and Faulted bindings. - Faulted: leave unbound — this walkthrough has no motor-fault tag.
- Active color: green (shown while Running is true).
- Fault color: red (shown when Faulted is true). It never shows here since Faulted is unbound, but in a real project a motor overload bit would bind to Faulted and operators rely on the red/green distinction for quick “is something wrong?” reads.
- Body color: dark gray (the static housing of the pump icon).
- Bind Running →
text (motor label):
- Text:
Motor(the text widget’s field is Text, not Label)
- Text:
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. Each controller it finds is listed with its posture: a new controller shows as Standalone; one you have provisioned into your account shows as Managed.
Awaiting enrolment? That posture only appears on a controller ordered with management required; it accepts nothing until it is provisioned (Path A, or the site CA). See Security, Provisioning and Enrolment.
When your controller appears in the list, click it and click Connect. If it does not appear — mDNS discovery is blocked on many corporate networks and never crosses a VPN — click Enter address manually and type the controller’s IP address.
- Path A: the controller is managed, so the IDE connects securely using the certificate your account issued to you when you logged in. Nothing to configure.
- Path B: the IDE connects plainly. (If you have made the controller managed through a site CA, it connects with your site identity instead; with more than one site imported, pick the right one under Project Properties → Security → Site identity first.)
A confirmation notification appears at the bottom of the IDE and the status bar shows the connection. The first time you connect with this project the IDE also compares it with whatever the controller already holds. A brand-new controller holds nothing, so nothing happens; if you later connect to a controller that runs a different project, a dialog offers to Download from target — choose it only if you want to edit that project instead of yours.
Press F5 (or click Build). Build is only enabled while you are connected, because for a Nexus.io project one press does both jobs: the IDE compiles, then downloads the program to the connected controller (signing it first when the controller is managed). The Output panel shows the sequence:
Building project: Motor... Build succeeded: 12 files generated Uploading program to target... Reloading program... Starting VM...On a managed controller (Path A) you will also see
Signed by …andUploading signed bundle to target....If the build stops with a list of undefined tags, a name you typed somewhere (a contact, a coil, a widget binding) does not exist in the Tag Database. The dialog offers to create them; check the types it proposes and try again.
The controller loads the new program and starts it; the touchscreen switches to your Main screen within a few seconds.
Note. From this point on the IDE knows the controller is running exactly this project, and the Tag Monitor and Debug Mode come alive. If you edit the project afterwards, they switch off again until your next Build — that is deliberate, so you never watch live values under tag names the running program does not have.
3.10 Step 9 — Test it
If your hardware is wired and your float switches are accessible, this is the fun part.
Open the Tag Monitor first. Click the Tag
Monitor tab in the bottom panel. With the controller connected
you’ll see live values for every addressed tag. Type float
in the filter box to keep float_start,
float_stop, float_alarm (and
motor_run) on screen. As you exercise each switch in the
steps below, watch these values flip in real time — if a switch doesn’t
move its tag, the issue is wiring or slave config, not your ladder
logic.
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, and the motor turns off (if it was on in Auto). Now open the float again: the LED and alert table clear (they track the live float), but the motor stays off — the ladder’s Set-coil latch (Network 2) holds the interlock until you clear it. Each high/low of the float adds aFIRED/CLEAREDpair to the alarm history.Hand override — While alarmed, tap HAND. Motor turns back on (the safety override). Tap back to AUTO — motor turns off again.
Clear the interlock — Tap Clear Alarms. This resets the ladder’s
alarm_latched(Network 3), releasing the motor interlock so the motor can run again in Auto. (The alert table already cleared when you opened the float — it tracks the live 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 (see Monitoring and Debugging in the full 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 controller, 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 controller on your LAN (provisioned into your account first on Path A), 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 → Setup → IO
Config, click Add Device, set Device
Kind to Modbus / EtherNet-IP device (from
IODF), pick mSmart-Universal-IO as the
Device Type, 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.
Don’t forget the Disable the IO points you won’t use
sub-step from the Ladder Walkthrough Step 2 — uncheck everything except
DI1, DI2, DI3, and
DO1. Same reasoning as the ladder walkthrough: the IO
scanner does one Modbus transaction per enabled point per scan, so
trimming to the four channels you actually read makes the controller’s
response to a float change feel instant.
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
Add the seven memory tags below — the same set as Walkthrough 1
minus const_hand. The ladder version
needed const_hand only because the CMP block can’t take a
literal operand; in Python you compare aho_mode == 1
directly, so there’s no constant tag to create. The Python code in Step
5 still 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 click
app.py. The Python Editor opens (a single click is enough; there’s no separate “open” step).Editor tips. Tab and Shift-Tab indent/outdent the currently-selected lines (no selection = insert 4 spaces / outdent the current line). Pasting code from another editor, chat, or the web normalizes tab characters to 4 spaces automatically — no need to reformat first.
Replace the entire contents of the file with the script below.
Don’t retype it — and don’t copy it out of this PDF. Copying Python from a PDF mangles the indentation (and PDFs may split the block across a page), which breaks the code because indentation is significant. The complete script already ships with the IDE: open the
Walkthrough-Pysample (File → Open →Documents\Whisker Projects) and copy therun(ctx)body from its Python editor, where the indentation is intact. The listing here is for reading along."""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 controller). 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 the Ladder Walkthrough Step 6. Name
HighLevelAlarm, condition float_alarm == True
— float_alarm is a BOOL, so the value field is a
True / False picker (choose == and
True) — Latched unchecked (the alert
tracks the condition so every occurrence is logged; your Python code
handles the motor-interlock latch), output tag blank. The Alert system
has no severity or message field — name, condition, latch, and output
tag are the only knobs.
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, you can copy the screen across rather than rebuilding it. The clipboard isn’t shared between two IDE windows, so do it within a single window by switching projects:
- Save this Python project (Ctrl+S), then open the
Ladder walkthrough’s
Walkthrough-Ladder.widez(File → Open) in the same window. - In its Project Tree, right-click Motor → HMI Screens → Main and choose Copy.
- Re-open your Python project (File → Open), right-click its HMI Screens node, and 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 (Path A or Path B), then press F5 — one press compiles and downloads (signing first on a managed controller).
This time the build output mentions the Python bundle:
Building project: Motor...
Build succeeded: 11 files generated
Uploading program to target...
Reloading program...
Starting VM...
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.
The Python walkthrough doesn’t have a Debug Mode (Python isn’t a
graph that lights up), so the Tag Monitor is your
primary window into what the controller is doing — open it in the bottom
panel and filter on float, motor, or
alarm to keep the relevant tags on screen while you
exercise the floats. If a tag doesn’t move when you expect it to, you
can check the Python Log to see what your
run() loop saw.
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. Because the two are different projects, the IDE asks you to confirm replacing the one already on the controller — that’s expected; confirm it. 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 Python log. The IDE’s Python Log panel (bottom of the workspace, next to the Output and Tag Monitor tabs) streams that log live — each entry selectable and copyable for pasting into chat or a bug report. The Python Log panel is all you need to watch your code run.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 (see Monitoring and Debugging in the full 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 and reports the total with
ctx.log.info(...). It streams live to the IDE’s Python Log panel, so you can read and copy it without pulling a file off the controller. See Python on the Controller in the full manual for the fullctxAPI — and for Python function blocks, which let a ladder network call your Python.
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 self-contained 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).
Path A or Path B? On Path B (a controller that is not managed, which is how a new controller arrives) the panel connects plainly and this walkthrough is complete as written. On Path A (a managed controller — cloud-enrolled, or provisioned through a site CA) the controller accepts only secure connections on its data port, so the panel PC needs a panel identity: in Step 3 tick Secure connection, and after installing the panel in Step 8 issue an identity for that PC from the Security dialog and import it from the panel’s Panel ▸ Import panel identity… menu. The procedure is in The WhiskerHMI PC Application.
5.1 Before you start
- Walkthrough 1 (or 2) is complete and the Motor PLC project is running on a Nexus.io controller.
- You know the controller’s IP address (the one you connected to in the Ladder Walkthrough 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 New Project (the same button you used in the Ladder Walkthrough 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 Create. The Project Tree now shows two siblings under Walkthrough-Ladder: Motor (the PLC project from the Ladder Walkthrough) 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 Tasks branch (it runs no ladder or Python) and no Functions — it has Tags, IO Configuration, Alerts, and HMI. The IDE knows the target type runs no control logic and hides the branches that don’t apply.
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 → Setup → IO Config → click 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 the Ladder Walkthrough if you have any RTU devices wired in).
Fill in the ArenaTCP form:
- Instance name:
controller - IP address: the Nexus.io controller’s address from
Walkthrough
- (If you started from a shipped sample Panel project rather than
building it here, its
controllerdevice may carry a placeholder address — set it to your controller’s actual one.)
- (If you started from a shipped sample Panel project rather than
building it here, its
- TCP port:
5000(the controller’s data port, not the 9000 port the IDE uses to program it). - Secure connection: unticked on Path B; ticked on Path A (see the box at the top of the chapter).
- Instance name:
Click Add Device. 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 six 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 — click the Pick .widez/.wapp button instead and browse to the file.)The dialog lists every tag from the Motor project with its type and address. Tick the six HMI-facing tags:
Tag Type float_startBOOL float_stopBOOL float_alarmBOOL motor_runBOOL aho_modeINT clear_alarmsBOOL Leave the five tags the HMI doesn’t display unticked: the four internal scratch tags (
motor_off,motor_hand,motor_auto,call_motor) plusalarm_latched. None of them is bound to a widget —alarm_latchedis the ladder interlock latch,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
6 tags importedand closes.Open Panel → Tags → Tag Database to verify. All six 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 the Ladder Walkthrough 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 (6 tags) [INFO] Generating io_scanner_config.json (1 ArenaTCP source) [INFO] Generating app_config.json [OK] Build succeeded: 4 files generatedThese four files are written to a temporary build folder, not inside your Application directory — you don’t need to find or manage them. The next step (Generate Installer) bundles them into the installer automatically.
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, shortcuts, Install, Finish. The path shown on the Destination Folder page is informational only in the current installer layout — the app is always installed under the system Program Files area:
C:\Program Files\Walkthrough Motor Panel\. (If you need to verify after install, that’s where to look — not at whatever was shown on the wizard page.)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 (the controller’s data port) isn’t blocked by a firewall between them.
- On Path A, the panel PC has a panel identity imported and the device has Secure connection ticked; a managed controller refuses a panel without a matching identity (see the box at the top of the chapter).
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
- Read The WhiskerHMI PC Application in the full manual for what the panel can do beyond this screen: several windows, the Trends dialog against the controller’s historian, CSV export, and operator login with roles.
- 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 Security, Provisioning and Enrolment and The WhiskerHMI PC Application in the full manual before shipping a panel into production — in particular what a secure panel connection needs.
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 the controller and the PC panel. 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, which ships as HTML and PDF alongside this guide. The full manual covers both editions of the IDE — Cloud and Offline — and says in each chapter what needs an account.
| Chapter | What it adds to what you did here |
|---|---|
| The Workspace | every panel, toolbar button and bottom-panel tab (Output, Python Log, Tag Monitor) |
| Projects and Applications | multi-project Applications, what is stored where, projects stored on the controller |
| Setting Up Your Nexus.io Automation Controller | the touchscreen settings, network, serial ports, the controller’s security postures |
| Target Hardware in the IDE | the Nexus.io Automation Controller, the SmartController, WhiskerHMI |
| Tag Database | the full address map, classes, initial values, process variables, retained values that survive a program update, system tags |
| I/O Configuration and Devices | every device kind — Modbus TCP/RTU, ArenaTCP (another controller’s tags), EtherNet/IP PLCs |
| Ladder Logic Editor | the editor itself: networks, wiring, properties, tags from the Properties panel |
| Function Blocks, Faceplates and Tasks | reusable logic, faceplates, periodic / event / freewheel tasks |
| HMI Designer | every widget, PIN login at the panel, trend charts, alert tables |
| Alerts Editor | conditions, latching, output tags, the alert table |
| Modbus Server and Map Viewer | exposing tags, renumbering, the four CSV export formats |
| Python on the Controller | the full ctx API, Python function blocks called from
ladder, the SmartController’s MicroPython |
| Connecting, Deploying and Emulating | discovery, the three controller postures, Build & Emulate with the IO Stimulus and HMI Preview tabs, what a signed deploy is |
| Monitoring and Debugging | Tag Monitor, Debug Mode, the Output panel, diagnosing a device that will not talk |
| Security, Provisioning and Enrolment | Path A and Path B in full, the Security dialog, certificates, revocation |
| Generating HMI Installers | packaging a WhiskerHMI panel for other PCs |
| Project Properties Reference | every project setting in one place |
| Ladder Instruction Reference | every instruction — timers, counters, compare, math, process blocks (PID, totalizer, filter…), motor and valve blocks, sequencer, scheduler |
| Historian and Trends | the controller’s 60-day historian, trend widgets, CSV export |
| The WhiskerHMI PC Application | several windows, Trends, operator login and roles |
6.2 Exposing tags to Modbus
The controller always runs a Modbus TCP server (slave) on port 502 — there’s no switch to turn it on. Instead you choose which tags it exposes, one tag at a time, so a SCADA system, BMS, or any Modbus master can read and write them.
Expose a tag
- Open the Tag Database and select the tag you want to expose.
- In the Properties panel, check Expose via Modbus.
- The IDE auto-assigns a Modbus address. To override it, type a different address in the Properties panel — a tag whose address you edit by hand is flagged as manually assigned, which the renumber tool (below) can leave untouched.
How tags map to registers
- BOOL tags are exposed twice — as a Coil and as a single-bit Holding Register — so every bool has two addresses.
- INT takes one Holding Register; DINT and REAL take two consecutive Holding Registers. The IDE allocates the registers for you.
Renumbering the map
To re-pack the addresses, select the Project node, and in its properties click Renumber all auto-assigned tags. In the dialog:
- Leave Keep manually-assigned addresses checked to renumber only the auto-assigned tags and leave your hand-edited addresses where they are; uncheck it to renumber everything.
- You can give each data type its own address range — for example, in
the Holding Register space,
0–999for bools,1000–1999for ints, and2000–2999for reals — so the map stays organized.
The Modbus Map
As soon as at least one tag is exposed, a Modbus Map node appears under the Project in the tree. It’s generated automatically (you don’t edit it directly) and shows two tables — Holding Registers and Coils — listing every mapped tag with its address, type, and access.
The Export button writes the map out as Generic CSV, Ignition CSV, KEPServerEX CSV, or AVEVA System Platform CSV — a big time-saver when you’re pulling these tags into an existing SCADA system.
See Modbus Server and Map Viewer for the full address conventions and read-only vs. read-write rules.
6.3 The Design Spec
Every project has a Design Spec — a living document under the Project in the tree. It starts from a template with sections for Overview, IO Configuration, Control Logic, HMI Screens, Alarms, and Notes that you fill in as you design the system.
Two parts are generated for you and kept up to date automatically:
- Tag Database — tables of your tags, split into
IO Tags (anything with a physical address),
Setpoints (
sp_…), Internal Variables (state_…,var_…), Process Variables (cmd_…,call_…), and a Misc Tags catch-all for everything else. - Modbus Registers — Holding Register and Coil tables of every tag you exposed via Modbus (above), refreshed whenever the Modbus map changes.
These tables live inside marked blocks in the document. The IDE refreshes only what’s inside the markers, so everything you write around them — your design narrative, control strategy, commissioning notes — is left untouched. Edit your tags in the Tag Database and the tables follow along.
6.4 Connecting to a controller
Click Connect in the toolbar, then pick the controller from the discovered list or enter its address. You don’t need a project open to connect.
When you connect, the IDE reconciles the project you have open against the project stored on the controller:
- No project open, controller has one — the IDE offers to download the project from the controller and open it. Decline, and the connection is cancelled (there’d be nothing to work with).
- Your open project matches the controller’s — it simply connects.
- They differ — the IDE asks whether to Download from target (this closes your open project, prompting you to save first) or keep the one you have. If you keep yours, live monitoring stays off until you Build, because the tag addresses wouldn’t line up with what’s actually running.
- Deploying a project to a controller that already holds a different project prompts you to confirm before it’s replaced.
Because the controller stores the editable project source, you can pull a project straight off a device even without a local copy. For IP-sensitive deployments, turn this off per project under Project Properties → Deployment → Store editable source on target.
See Connecting, Deploying and Emulating for discovery details, the three controller postures and Build & Emulate, and Security, Provisioning and Enrolment for Path A and Path B in full.
6.5 Sample projects
The IDE ships with the two completed walkthrough projects. On first
launch it copies them into your default project folder —
Documents\Whisker Projects — which is also
where File → Open and Save As
start:
- walkthrough_ladder.widez — the completed ladder version of this walkthrough’s pump-station scenario.
- walkthrough_py.widez — the same scenario built in Python instead of ladder.
Open either with File → Open; it opens straight to
Documents\Whisker Projects.
6.6 When you get stuck
- A build that fails names the program and network of each error in the Output panel; Troubleshooting lists the common causes.
- The Output, Tag Monitor and Python Log tabs are
your live view into the controller, right inside the IDE.
Output shows build results and runtime messages;
Tag Monitor shows every tag’s current value;
Python Log streams
ctx.logoutput from your Python code as it runs. All update live while you’re connected, and every entry is selectable and copyable for pasting into a bug report. - Troubleshooting in the full manual’s appendices is organized by symptom (the controller refuses to connect, the deploy was refused, the Tag Monitor is empty, the motor doesn’t run…).
6.7 Support
- Email support:
support@d6labs.com - Phone (US business hours): 1-844-365-8647
6.8 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.