NetBox plugin: DIN rails, subracks, mounting plates and busbars with SVG visualization of cabinet interiors, including chassis/parent-child devices and modular PLC chassis.
Project description
netbox-cabinet-view
A NetBox plugin that models physical mounting that doesn't fit a 19″ rack — DIN rails, Eurocard subracks, mounting plates, and busbars — and renders each cabinet as an SVG drawing with real device images.
(Above: three of the 16 demo scenarios seeded by manage.py cabinetview_seed. Every drawing is a live SVG rendered from the plugin's own endpoint — they flip to a dark palette automatically when your browser is in dark mode.)
Compatibility
| NetBox version | Supported | Tested | Notes |
|---|---|---|---|
| 4.5.x | ✅ | ✅ | Actively developed against 4.5.7 — this is the version all screenshots and smoke tests run against |
| 4.4.x | ✅ | ⚠️ | Untested but all APIs used (NetBoxModel, ViewTab, register_model_view, get_model_urls, PluginTemplateExtension.models) are present in 4.4.0; no code changes expected |
| 4.3.x and older | ❌ | ❌ | Not supported — some helpers we rely on may not exist or have different signatures |
| 4.6.x (when released) | ❓ | ❓ | To be verified when released |
Python 3.10+ required (matches NetBox 4.4 / 4.5's own Python support).
What it adds
Three models:
- DeviceTypeProfile — per-DeviceType declaration of whether the device hosts carriers (i.e. it's a cabinet or enclosure) and/or mounts on carriers (it's a DIN-mounted relay, a 4-HP Eurocard, a clip-on MCB). Internal dimensions and footprints live here.
- Carrier — a geometric mounting structure attached to a host
Device. Four types ship in v1:din_rail,subrack,mounting_plate,busbar. Each has offset, orientation, length (1D) or width/height (2D), and a unit (mm, DIN module 17.5 mm, Eurocard HP 5.08 mm). - Mount — a placement on a carrier. Points at exactly one of:
- a standalone
dcim.Device(bare DIN rail mounts) - a
dcim.DeviceBay(chassis with child devices — e.g. a WDM shelf with two filter modules) - a
dcim.ModuleBay(modular PLC / line-card chassis)
- a standalone
And three views:
- A Layout tab on every
dcim.Devicedetail page. Renders the host's carriers and their mounts as an SVG viasvgwrite, reusingDeviceType.front_imageandModuleType.front_imagefrom core NetBox. Falls back to colored rectangles with labels when no image is available. - A Cabinet Layouts panel on every
dcim.Rackdetail page, listing all carrier-host devices in the rack and embedding each one's layout SVG inline. - Rack elevation integration (v0.2.0+): the plugin monkey-patches
dcim.svg.racks.RackElevationSVG.draw_device_frontat startup so that ≥2U devices withhosts_carriers=Truerender their cabinet layout inside the rack elevation at their U slot, instead of the stockDeviceType.front_image. Letterboxed withxMidYMid meetso the layout keeps its natural aspect ratio. Falls back to the stock front image for 1U devices (a 230×22 px slot is too narrow for a useful layout). Cache-busted by a content hash of the host's carriers and mounts, so edits invalidate the browser cache. Opt out withPLUGINS_CONFIG['netbox_cabinet_view']['PATCH_RACK_ELEVATION'] = False.
Schema
Plugin models are in bold, core NetBox models are shown as context. The three dashed relationships from Mount form an XOR constraint — exactly one of them must be populated on any given mount, enforced in Mount.clean().
erDiagram
Device }o--o| Rack : "rack / position / face"
Device }o--|| DeviceType : "device_type"
Module }o--|| ModuleType : "module_type"
DeviceBay }o--|| Device : "parent device"
DeviceBay |o--o| Device : "installed_device (child)"
ModuleBay }o--|| Device : "parent device"
ModuleBay |o--o| Module : "installed_module"
DeviceType ||--o| DeviceTypeProfile : "cabinet_profile (1:1)"
Device ||--o{ Carrier : "cabinet_carriers (host)"
Carrier ||--o{ Mount : "mounts"
Device |o..o{ Mount : "device (XOR)"
DeviceBay |o..o{ Mount : "device_bay (XOR)"
ModuleBay |o..o{ Mount : "module_bay (XOR)"
DeviceTypeProfile {
OneToOne device_type
bool hosts_carriers
int internal_width_mm
int internal_height_mm
int internal_depth_mm
enum mountable_on
enum mountable_subtype
int footprint_primary
int footprint_secondary
}
Carrier {
FK host_device
str name
enum carrier_type
enum subtype
enum orientation
enum unit
int offset_x_mm
int offset_y_mm
int length_mm
int width_mm
int height_mm
}
Mount {
FK carrier
FK device "nullable"
FK device_bay "nullable"
FK module_bay "nullable"
int position "1D"
int size "1D (auto from profile footprint_primary)"
int position_x "2D"
int position_y "2D"
int size_x "2D"
int size_y "2D"
}
Why a Mount can target three different things: NetBox already represents three different parent/child relationships — direct device placement, DeviceBay-backed child devices (WDM shelves, blade chassis), and ModuleBay-backed modules (modular PLCs, line cards). The cabinet-view model treats each as a valid "thing that occupies a carrier position", so its geometry layer works uniformly across all three.
OT/ICS coverage
v1 covers the common OT/ICS cabinet types:
| Cabinet kind | Carrier type used |
|---|---|
| PLC cabinets, marshalling/junction boxes, field I/O, IS cabinets, relay panels, small LV distribution | din_rail |
| Rittal/Hoffman enclosures with back-mounted VSDs, UPS, contactors, IPCs | mounting_plate |
| VME/cPCI/MTCA measurement and controller racks, 3U/6U industrial computing | subrack |
| MCCs, LV panelboards, withdrawable switchgear spines (RiLine, 8US, SMISSLINE) | busbar |
| Modular PLCs, OLT/WDM line cards, modular router/switch chassis | subrack + ModuleBay mounts |
| MCC withdrawable buckets, switchgear compartments | nested Device-in-Device-on-Carrier (no new model) |
Install
pip install -e /path/to/netbox-cabinet-view
Add to your NetBox configuration.py:
PLUGINS = ['netbox_cabinet_view']
Then run migrations:
DEVELOPER=1 python manage.py makemigrations netbox_cabinet_view
python manage.py migrate netbox_cabinet_view
python manage.py collectstatic --no-input
Restart NetBox. A Cabinet View entry appears in the sidebar, and every dcim.Device detail page grows a Layout tab (hidden when the device has no carriers).
Using it
- Create a
DeviceTypeProfilefor any DeviceType that hosts carriers (sethosts_carriers=Trueand the internal dimensions in mm). - Create a
DeviceTypeProfilefor any DeviceType that mounts on carriers (setmountable_on,mountable_subtype, andfootprint_primaryin carrier units). Mountsizeis optional — if left blank it defaults to the profile'sfootprint_primary(slots are fixed-width; only carriers stretch). - Create a
Deviceof the host type, place it in a Location or a Rack as normal. - Add one or more
Carrierrecords to the host device — DIN rail at offset (x, y) with a length, or a mounting plate with width×height, etc. - Add
Mountrecords to place devices (or device bays, or module bays) on the carriers at specific positions. - Visit the host device's detail page → Layout tab.
Demo data
The plugin ships a management command that creates a realistic OT/ICS demo dataset for visually testing every feature. It is not run automatically on install. To use it:
python manage.py cabinetview_seed
The command is idempotent — safe to re-run, updates drifted fields back to the canonical values, and re-layouts rack positions cleanly. It creates one Site (OT Test Site), one Location, one Manufacturer (Generic), nine DeviceRoles, around 25 DeviceTypes with matching DeviceTypeProfiles, one Rack (Test Rack A, 24U), and the sixteen scenarios below:
Core scenarios (9)
| # | Scenario | Host device | Carrier(s) | Mount target | Demonstrates |
|---|---|---|---|---|---|
| 1 | Standalone DIN rail | DIN Rail #1 |
1× DIN rail (480 mm) | 2× Phoenix REL-MR (Device) | Bare rail with no enclosing cabinet |
| 2 | 2D mounting plate | Enclosure #1 |
1× mounting plate (760×1960 mm) | 1× Industrial PC (Device, 220×90 mm) | Back-plate with (x, y) mm placement |
| 3 | Chassis with child devices | WDM Shelf #1 |
1× subrack (HP 3U, 406 mm) | 2× WDM Mux/Demux (DeviceBay, slots 1 and 5) | DeviceBay-backed mounts, parent/child visualization |
| 4 | Small chassis | WDM Shelf 2-slot #1 |
1× subrack (HP 3U, 440 mm, full width) | 2× WDM Mux/Demux (DeviceBay, 20 HP each) | Fixed-width slots in a wider carrier |
| 5 | LV panelboard | LV Panel Busbar |
1× busbar (1000 mm) | 3× MCB 1P 45 mm (Device, at mm positions) | Copper busbar with clip-on modules |
| 6 | Modular PLC | PLC Backplane #1 |
1× subrack (HP 3U, 400 mm) | 2× DI 16×24 VDC (ModuleBay) | ModuleBay-backed mounts, modular chassis |
| 7 | Rack-mounted DIN shelf (2U) | DIN Shelf 2U #1 |
1× DIN rail (420 mm, centered) | 3× Phoenix REL-MR (Device) | Realistic 2U DIN shelf for rack-elevation testing |
| 8 | Rack-mounted DIN shelf (4U, two rails) | DIN Shelf 4U #1 |
2× stacked DIN rails (upper + lower) | 2× Relay + 3× MCB (Device) | Multi-carrier host, stacked rails |
| 9 | ISP-style 4U DIN shelf (single rail) | DIN Shelf 4U ISP #1 |
1× DIN rail (420 mm, centered vertically) | 5× Phoenix REL-MR (Device) | Single rail with wire-management headroom |
Classic OT/ICS scenarios (7 extras, v0.1.1+)
| # | Scenario | Host device | Carrier(s) | Mount target | Demonstrates |
|---|---|---|---|---|---|
| A | Marshalling cabinet | Marshalling Cabinet #1 (4U) |
1× DIN rail (mm unit, 420 mm) | 20× Phoenix UT 2.5 terminal block at 6 mm pitch | Dense narrow-slot rendering; label fitting under pressure |
| B | MCC with withdrawable buckets | MCC Cabinet #1 (standalone) |
1× vertical busbar (1800 mm) + nested DIN rails per bucket | 3× MCC Bucket devices (each also a carrier host), each with a motor contactor + auxiliary relay |
Device-in-Device recursion on a busbar; vertical-orientation carrier |
| C | VFD control cabinet | VFD Cabinet #1 (Rittal 600×1800) |
1× mounting plate + nested aux DIN strip | 1× Schneider ATV630 + aux DIN strip device holding a 24 V PSU and 2 motor contactors |
Mixed plate + DIN; rail-on-plate nesting |
| D | Wago remote I/O station | Wago Remote I/O #1 (2U) |
1× DIN rail (mm unit) | 1× Wago 750-362 coupler + 4× 750-430 DI + 3× 750-530 DO chained along the rail | Bus-coupler-plus-modules pattern on DIN |
| E | Industrial Ethernet switch panel | Industrial Switch Shelf #1 (2U) |
1× DIN rail | 1× Hirschmann MACH1000 (90 mm, wider than 1 module) | Single wider-footprint device on a rail |
| F | Safety relay panel | Safety Panel #1 (600×800 enclosure) |
1× mounting plate | 4× Pilz PNOZ X3 (45×100 mm each) | Multiple fixed-size devices on a 2D plate |
| G | Substation protection panel | Protection Panel #1 (800×2200 cabinet) |
1× mounting plate + nested test block rail | 2× Siemens SIPROTEC 7SJ82 + 1× ABB REL670 + nested test rail with 4× ABB RTXF test blocks | Protective relays / IEDs in a realistic utility protection cabinet; rail-on-plate nesting with its own mounts |
Test Rack A (24U) holds the 1U / 2U / 4U rack-mounted scenarios (3, 4, 7, 8, 9, A, D, E) at consecutive U positions. The standalone scenarios (1, 2, 5, 6, B, C, F, G) live in OT Test Site / Control Room without a rack.
Rendered scenario gallery
The SVGs below are committed at docs/screenshots/*.svg and embedded live — every stroke, fill and label you see is exactly what the plugin's /dcim/devices/<pk>/cabinet-layout/svg/ endpoint returns for that device.
| Scenario | Rendering |
|---|---|
| 1. Standalone DIN rail | |
| 2. Mounting plate + IPC | |
| 3. WDM 8-slot shelf (DeviceBay) | |
| 4. WDM 2-slot shelf | |
| 5. LV panelboard busbar | |
| 6. Modular PLC (ModuleBay) | |
| 7. 2U rack DIN shelf | |
| 8. 4U rack DIN shelf — two stacked rails | |
| 9. 4U rack DIN shelf — ISP single-rail | |
| A. Marshalling cabinet (20 terminal blocks) | |
| B. MCC with withdrawable buckets | |
| C. VFD control cabinet | |
| D. Wago remote I/O station | |
| E. Industrial Ethernet switch | |
| F. Safety relay panel | |
| G. Substation protection panel |
Security & supply chain
Every release ships with machine-readable supply-chain documents under security/:
security/sbom.cdx.json— CycloneDX 1.6 Software Bill of Materials enumerating every direct and transitive runtime dependency, with purl identifiers so it drops straight into Dependency-Track,grype,trivy,osv-scanner, or GitHub's dependency graph.security/openvex.json— OpenVEX 0.2.0 Vulnerability Exploitability eXchange document telling downstream consumers which CVEs actually affect the running code. At v0.1.2 there are no known CVEs affecting the plugin or its sole runtime dependencysvgwrite.
Both files are regenerated on every tagged release. See security/README.md for regeneration commands and a summary of current contents.
Reporting a vulnerability: please open a private Security Advisory on GitHub rather than a public issue.
Not in v1
Strut channel, keystone frames, Krone LSA/110-block frames, fiber cassettes, HMI panel cutouts, pneumatic manifolds, auto-provisioning carriers from existing bay templates, drag-to-place UI, REST API, GraphQL.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file netbox_cabinet_view-0.2.0.tar.gz.
File metadata
- Download URL: netbox_cabinet_view-0.2.0.tar.gz
- Upload date:
- Size: 50.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c903e162388cc3ff2c8d66c913181792577d2e9cd8a9a03ff93a788b75ebd06
|
|
| MD5 |
d9d5b4dac99dbab928c19ba1401e9288
|
|
| BLAKE2b-256 |
92cb3d24798672412679ae3f31fc6ffd73ede8e34c5ccbf0080d167df872b534
|
File details
Details for the file netbox_cabinet_view-0.2.0-py3-none-any.whl.
File metadata
- Download URL: netbox_cabinet_view-0.2.0-py3-none-any.whl
- Upload date:
- Size: 52.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed13890b3071a8f33c84bf29f9ef941d3e2ec2a7e227a6ca7c79cbca4960e887
|
|
| MD5 |
d4184631f71c90b6f098c245b9fc72b4
|
|
| BLAKE2b-256 |
9eae5fbda4fc85a1c5fabb1a144a37a3de2efecf8794d98c520340c6ce686a04
|