Install
$ agentstack add skill-wirenboard-wb-ai-skills-wb-mod-slots ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
wb-mod-slots
Operate the per-slot hardware configuration on WB6/WB7/WB8 controllers — MOD1..MOD4 (internal WBE2 slots) and rs485-1..rs485-2. The slot's mode (RS-485, raw UART, bit-banged I2C, CAN, ...) is selected at runtime by loading a device-tree overlay through wb-hwconf-helper. Sister skill to wb-serial, which handles Modbus on top of the default RS-485 mode.
CRITICAL RULES
> Don't write /etc/wb-hardware.conf blindly. The file is the persistent config consumed at boot. A bad JSON or a wrong slot-id locks the slot into a non-working state on every reboot. For testing, prefer the runtime init/deinit path — it doesn't touch the conf file.
> init and deinit need the FULL board-prefixed slot-id (e.g. wb85-mod3, not mod3). The short mod3 form only works through config-apply against /etc/wb-hardware.conf. If wb-hwconf-helper complains "Slot definition file …/slots/mod3.def not found", you forgot the prefix.
> After init, expect a brief glitch on the slot's lines. Don't switch modes while another MCU on the wire is mid-transaction — pinmux flips can clock random bits and corrupt the peer's state.
> **` in examples** means wirenboard-.local` (substitute the controller's mDNS name).
When to load this skill
- User wants to expose raw UART or I2C on a MOD slot for a custom device, MCU programming, GPIO bit-bang, or one-off bench work.
stty -F /dev/ttyMOD3returnsInput/output erroreven though the device file exists (= pinmux not applied yet).wb-mqtt-serialis configured to use/dev/ttyMODxbut the port refuses to open.- User mentions
wb-hwconf-helper,/etc/wb-hardware.conf,wbe2x-generic-uart,wbe2x-generic-i2c,i2c-gpio, MOD slot mode, repurpose MOD3 / MOD4. - User asks where
/dev/i2c-modNcame from or how to make one appear.
Stay out and hand off when:
- It's actually a Modbus/RS-485 diagnostics question on the default mode →
wb-serial. - Network adapters / WiFi / 4G →
wb-network.
Architecture — what a MOD slot is
A MOD slot is an internal WBE2 connector on the controller. The CPU exposes a UART (or alternate functions: I2C, SPI, GPIO) on the slot's pins. What runs on those pins is decided at boot by an applied device-tree overlay. No overlay → pins are bare GPIOs in input mode → /dev/ttyMODx exists as a udev symlink but the underlying 8250 UART driver fails to talk to dead pinmux.
Layout on disk:
/etc/wb-hardware.conf # persistent user config (JSON)
/var/lib/wirenboard/hardware.state # current slot→module mapping (runtime)
/usr/share/wb-hwconf-manager/
├── boards/.conf # default modules per slot for this board
├── slots/-.def # slot pin map (e.g. wb85-mod3.def)
└── modules/.dtso + .sh # overlay sources + add/remove hooks
/sys/firmware/devicetree/base/model # current board hint
Board hint examples: Wiren Board rev. 8.5.1 (T507) → boards/wb85xm.conf. The mapping from DT compatible to boards/*.conf is in wb-hwconf-manager/config.py.
Tool: wb-hwconf-helper
wb-hwconf-helper init # apply overlay now (non-persistent)
wb-hwconf-helper deinit # roll back the active overlay on a slot
wb-hwconf-helper config-apply # diff /etc/wb-hardware.conf vs current, apply
wb-hwconf-helper load-overlay # apply a standalone DTS overlay
wb-hwconf-helper unload-overlay # remove one
wb-hwconf-helper confed-tojson # for the web editor
wb-hwconf-helper confed-fromjson # for the web editor
` for init/deinit is the **full** id from boards/.conf (wb85-mod3, wb84-rs485-1, wb67-w1, …). The web editor uses the short form (mod3`) and resolves it through the board file; the CLI does not.
Workflow: switch a MOD slot's mode (runtime, recommended)
Switch MOD3 from default RS-485 to raw UART:
ssh root@ sudo wb-hwconf-helper init wb85-mod3 wbe2x-generic-uart
ssh root@ stty -F /dev/ttyMOD3 # should succeed now
Switch the same slot to bit-banged I2C:
ssh root@ sudo wb-hwconf-helper deinit wb85-mod3
ssh root@ sudo wb-hwconf-helper init wb85-mod3 wbe2x-generic-i2c
ssh root@ ls /dev/i2c-mod3 /dev/i2c-* # the slot now appears as an i2c-gpio adapter
This path does not write to /etc/wb-hardware.conf. On the next reboot the slot reverts to the board default — desirable for bench tests, not for production use.
Workflow: persistent change (production)
Edit /etc/wb-hardware.conf:
{
"slots": [
{ "slot_id": "mod3", "module": "wbe2x-generic-uart" }
]
}
Note: short slot_id here ("mod3"), not the board-prefixed form. The board file resolves it.
Apply:
ssh root@ sudo wb-hwconf-helper config-apply
config-apply diffs the new config vs /var/lib/wirenboard/hardware.state, calls deinit+init for each changed slot, and runs module add/remove hooks. Survives reboot.
Module catalogue (most common)
Names match files in /usr/share/wb-hwconf-manager/modules/. List the full set per board with ls /usr/share/wb-hwconf-manager/modules/ on the controller.
| Module | Exposes | Notes | | ----------------------- | -------------------------------------------------------- | ----- | | wbe2x-generic-uart | /dev/ttyMODn — raw UART on the slot's TX/RX | CPU UART, 3.3 V LVCMOS on T507. Check schematic for older boards. | | wbe2x-generic-i2c | /dev/i2c-modN — bit-banged i2c-gpio | TX→SDA, RX→SCL per wbe2-i2c.dtsi. ~100 kHz, no internal pull-ups. | | wb67-can-rs485 | RS-485 on rs485-1/2 slots | Default for rs485-* slots. | | wbe2-i-rs485-iso | Isolated RS-485 via WBE2-I-RS-485-ISO | For external WBE2 ISO modules. | | wbe2-i-rs232 | RS-232 | | | wbe2-i-can | CAN | Slot must be wbe2-i-can compatible (check boards/.conf). | | wbe2-i-knx | KNX | | | wb6-wx-1wire | 1-Wire on w1/w2 terminal mode | | | wbe2-i-w1 / -w1-gpio| 1-Wire on MOD slot | | | wbe2-i-opentherm | OpenTherm | |
If init fails with a DTS parse error, the slot likely doesn't match the module's compatible-slots — see the capability check below.
Slot capabilities — what fits where
Slots on the same board are NOT all equivalent. Each slot has a compatible: [...] list of tags; each module declares a single compatible-slots = "" string. A module loads on a slot iff the module's tag is in the slot's list.
Example on wb8.5 (/usr/share/wb-hwconf-manager/boards/wb85x.conf):
| Slot | Compat tags | I2C? | UART? | | ----------------- | --------------------------------------------------------------------------------- | :--: | :---: | | mod1 / mod2 | wbe2, wbe2-gpio, wbe3-reduced-uart, wbe3-wbec-only, wbe2-i-can | ✗ | ✓ | | mod3 / mod4 | wbe2, wbe2-gpio, wbe2-i2c, wbe3-reduced, wbe3-reduced-uart, wbe2-i-can | ✓ | ✓ | | rs485-1 / -2 | wb67-rs485 | ✗ | RS-485 only |
So wbe2x-generic-i2c (compatible-slots = wbe3-reduced) loads on mod3/mod4 but fails on mod1/mod2 — the agent must check capability before suggesting a slot. Same for analog modules (wbe2-ai-cm-1, wbe2-ao-10v-2) and RTC.
Run this on the controller to print the per-slot compatibility matrix for the current board:
ssh root@ python3 {', '.join(fitting) or '(none)'}")
PY
get_board_config_path() from wb-hwconf-manager/config.py resolves the right boards/.conf for whatever board you're on — don't hardcode the path. The CLI's ` is the value of the id field (e.g. wb85-mod3); the persistent-config short form is the slot_id field (mod3`).
Connector pinout (paste to user when they ask where to wire something)
Top view of the controller PCB. Pin 1 of the UART/I2C/GPIO block is the top-left of that block (3.3 V); odd numbers on the left column, even on the right.
MOD1..MOD3 on WB6.7–6.9 / WB7.x, MOD1..MOD4 on WB8.x:
OUT1 ● ● OUT2
● ● OUT3
── 1 ─── 2 ──
3.3V ● ● 5V
TX/SDA ● ● RTS
RX/SCL ● ● GND
═══ UART / I2C / GPIO ═══
MOD4 on WB6.7–6.9 / WB7.x (extra SPI block instead of OUTs):
── 1 ── SPI ── 2 ──
MISO ● ● MOSI
SCK ● ● CS
───────────────────
3.3V ● ● 5V
TX/SDA ● ● RTS
RX/SCL ● ● GND
═══ UART / I2C / GPIO ═══
Pin function depends on the loaded module:
wbe2x-generic-uart→ TX (controller out), RX (controller in), RTS.wbe2x-generic-i2c→ TX→SDA, RX→SCL (perwbe2-i2c.dtsi; remember external pull-ups, ~4.7 kΩ to 3.3 V).- GPIO modules → bare digital lines.
OUT1..OUT3are passive contacts on the slot connector — they're routed to the controller's external (front-panel / terminal-block) connector. The installed WBE2 module decides what flows through them (e.g. relay contacts on awbe2-do-*module). When you loadwbe2x-generic-uart/-i2cthere's nothing on them from the SoC side.SPIblock (MOD4 on WB6.7–6.9 / WB7.x only) is a separate hardware SPI — wbe2-i-* SPI modules tap it.
Power rails per module (from the wiki): 3.3 V up to 0.5 A, 5 V up to 1 A. Wiki doesn't clarify whether the budget is per slot or shared across all four — assume shared and don't push it.
Signal lines are 0–3.3 V CMOS without overvoltage protection. Driving them from 5 V logic damages the controller — use a level shifter for any external 5 V peripheral.
Verify the switch worked
ssh root@ stty -F /dev/ttyMOD3 # OK = pinmux applied; Input/output error = no overlay
ssh root@ ls -l /dev/i2c-* /dev/ttyMOD* # check expected device files exist
ssh root@ cat /sys/class/i2c-adapter/i2c-*/name | grep -i mod # find which i2c-N is i2c-gpio
ssh root@ gpioinfo | grep -i "MOD3" # if "unused input" — pinmux NOT applied
ssh root@ udevadm info -q all -n /dev/ttyMOD3 # which raw device backs the symlink
ssh root@ cat /var/lib/wirenboard/hardware.state # what wb-hwconf-helper thinks is active
gpioinfo will keep showing MOD3 TX / MOD3 RX labels regardless of mode — the labels are static. Look at the third column: unused input means no overlay; an active overlay shows the pin as used by the kernel driver.
Pitfalls
stty: Input/output erroron a fresh/dev/ttyMODx— pinmux not applied. Runinitfor the slot or check/etc/wb-hardware.conf.wb-mqtt-serialconfig has the port with"enabled": false— the daemon does NOT set up pinmux for disabled ports. The port is "released" only in the wb-mqtt-serial sense; the kernel UART is still unmuxed until an overlay loads.Slot definition file …/slots/mod3.def not foundoninit— using short slot-id; needs the board-prefixed form (wb85-mod3).initerrors with a DTS overlay parse error — the module'scompatible-slotsdoesn't match the slot'scompatiblelist. Run the capability matrix above to see which slots accept the module. Classic case on wb8.5:wbe2x-generic-i2cworks on mod3/mod4 but fails on mod1/mod2.initsucceeds butgpioinfostill saysunused input—gpioinfoonly sees pins that the kernel exposed as GPIOs. Pinmuxed pins (UART/I2C/...) leave the GPIO subsystem; the static labels stay. Checkstty//dev/i2c-*instead.wbe2x-generic-i2cisi2c-gpio(bit-banged), not hardware I2C. ~100 kHz max, no clock stretching support beyond what the kernel emulates. For real I2C performance use the SoC's hardware bus (/dev/i2c-1etc.) on the side connector instead of MOD.- No internal pull-ups on
i2c-gpio. Add external pull-ups (4.7 kΩ to 3.3 V typical) on SDA and SCL. - Switching modes while a device is connected can clock garbage during the brief transition between
deinitandinit. Power down the peer (or disconnect) before mode-switching if it's stateful. /etc/wb-hardware.conf = {}is normal — defaults fromboards/.confapply. The conf file only stores deviations from defaults.- After
deinit,/dev/ttyMODxsymlink stays, butsttyfails again. The symlink is created by udev based on the platform UART regardless of pinmux.
What the agent does NOT do
- Don't edit
/etc/wb-hardware.conffor a one-off test. Use the runtimeinit/deinitpath so a reboot returns to the board default. - Don't replace an active
rs485-1/rs485-2module without checking what's on the bus. Existing Modbus devices will disconnect. - Don't load an arbitrary
.dtsoviaload-overlayfrom the internet. Only ship overlays from/usr/share/wb-hwconf-manager/modules/or vetted local files; the kernel device-tree subsystem will happily activate dangerous configs. - Don't claim that
init+deinitcycle preserves bus signals. It doesn't — pins glitch.
When to ask the user
- The board model is uncertain (no
/sys/firmware/devicetree/base/modelor it doesn't map to a knownboards/*.conf) — confirm the controller model before guessing the slot-id prefix. - The target slot is currently
rs485-*running production Modbus traffic — confirm beforedeinit(will breakwb-mqtt-serial). - The new mode requires extra hardware (pull-ups for I2C, isolation, level shifters) — surface that before flipping the mode and finding out the hard way.
- About to write
/etc/wb-hardware.conf(persistent change) — confirm it should survive a reboot, not just one bench session.
Documentation
- WB hwconf-manager source:
- WB extension modules + pinouts + power specs (canonical):
- Linux
i2c-gpiobinding: kernelDocumentation/devicetree/bindings/i2c/i2c-gpio.yaml - Sister skill:
wb-serial(Modbus/RTU on the default RS-485 mode).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wirenboard
- Source: wirenboard/wb-ai-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.