Environments, devices and vehicles
The lab is made of physical things: a bench, a device under test, a car on a rig, a manufacturer. DK Studio keeps those things as inventory records so that a team can find the rig it needs and say what is on it. This page introduces the asset model, what an environment is, how a device is described, and how naming and tagging let you find a rig in a large lab.
The asset model
Six tables describe the world a test bench lives in. The setup wizard creates them in the
initialize step, identically on SQLite, PostgreSQL and MySQL.
| Table | Key columns | Points at |
|---|---|---|
projects | id, name, description, status | β |
products | id, name, description, project_id | projects |
environments | id, name, type, config, project_id | projects |
devices | id, kind_id, device_id, serial, display_name, status | device_kinds |
vehicles | id, name, make, model, year, vin, status | β |
oems | id, name, code, description | β |
A project is the top of the tree. Products and environments hang off it through project_id;
devices, vehicles and OEMs are the free-standing inventory of the lab that those projects draw
on.
| Screen | What it lists |
|---|---|
/projects | The programmes the lab is working on, with their status. |
/products | The products under test inside each project. |
/environments | The rigs, labs and campaigns. |
/devices | The devices under test. |
/vehicles | The vehicles on the rigs. |
/oems | The manufacturers. |
Environments
An environment is a named, typed context for work: a lab, a bench, a vehicle, or a test campaign.
| Column | Type | Meaning |
|---|---|---|
id | text | Primary key. |
name | text, not null | The human handle. Not unique. |
type | text, not null | What kind of environment: a lab, a bench, a vehicle, a campaign. |
config | text | The configuration of the rig, as JSON. |
project_id | text | Foreign key to projects. |
config is where the rig is described: the benches it contains, the device addresses on them, the
serial ports, and the vehicles it carries. It is the one place where the composition of an
environment is written down, so it is also the place to look when you want to know what is
physically in front of you.
The environment record describes the rig β its name, its type and its configuration. The agent
record describes the machine that is actually connected to the studio and can be commanded. Name
them after each other β environment bench-01, agent bench-01 β and the two views line up.
Devices under test
A device is the piece of hardware under test. It is observed, not registered: the studio learns a device exists when a bench reports it, and keeps one registry row for that device from then on.
The registry is split from the catalogue of what a device can be.
The kinds
device_kinds is the catalogue of device classes. Each row describes a kind of hardware β the
model that every phone of that kind shares, the transport the bench talks to it over, and the
capabilities it offers.
| Column | Type | Meaning |
|---|---|---|
id | text | Primary key. ios, android, harmonyos, and later sbm, sam, robot_arm. |
name | text, not null | The human name of the kind. |
category | text, not null | mobile, module or robot. |
vendor | text | Who makes it. |
model | text | Which model this kind is. |
transport | text | How the bench reaches it: usbmux, adb, hdc, serial, can, tcp. |
capabilities | text | JSON array of what the kind can do. |
spec | text | JSON, the fields specific to this kind. |
Adding a new kind of device is adding a row here.
The registry
devices holds one row per physical unit.
| Column | Type | Meaning |
|---|---|---|
id | text | Primary key. Studio-assigned, stable, and the key that history rows point at. |
kind_id | text | Which kind it is. |
device_id | text | The address the bench uses: a UDID, a serial, a target id. |
serial | text | The nameplate serial. May be empty. |
display_name | text | The human handle. |
status | text | in_service, repair or retired. |
firmware | text | The firmware it runs. |
notes | text | Free text. |
first_seen_at | text | When the studio first saw it. |
last_seen_at | text | When the studio last heard about it. |
retired_at | text | When it left service. |
The pair (kind_id, device_id) is unique. That is what makes the registry a registry: when a bench
reports a device the studio has seen before, it claims the existing row rather than creating a
second one. Moving a phone from one bench to another does not change its identity β only where it
sits.
status is the device's own lifecycle, and it says nothing about whether the device is plugged in
right now. A retired device keeps its row, because reports and history still refer to it.
The per-unit details
device_details_phone holds the columns that belong to one machine rather than to the kind.
| Column | Type | Meaning |
|---|---|---|
device_id | text | The device it describes. |
product_type | text | The product type string the platform reports. |
product_version | text | The product version. |
os_version | text | The OS version it is running. |
connection_type | text | How it is connected. |
The model belongs to the kind, but the OS version belongs to this unit β a machine gets upgraded. Each kind has its own details table of this shape.
Where it is
device_sessions records where a device has been, one row per stretch of time it was on a bench.
| Column | Type | Meaning |
|---|---|---|
id | text | Primary key. |
device_id | text | The device. |
agent_id | text | The bench it is on. |
slot | text | The position on the bench. |
role | text | dut, companion or monitor. |
status | text | attached, detached or closed. |
attached_at | text | When it was reported. |
detached_at | text | When the bench reported it gone. |
closed_at | text | When the stretch truly ended. |
end_reason | text | moved, replaced, disconnected, lost or retired. |
driver_state | text | JSON snapshot of the driver state. |
A disconnect is not the end of the stretch. A bench that loses its socket reports the device as
detached and the studio holds that row open for a grace period; if the device comes back inside
the window it is the same row, with detached_at cleared. Only when the window passes does the
stretch close, and the reason says which kind of ending it was β the device moved to another
bench, the bench lost the device, or the bench itself went away and took the device with it.
The device page reads that history three ways, and the choice is remembered: a list of stretches with the time each one ran, a timeline that lays the stretches on a time axis so the gaps between them show β each stretch marked with the point it connected and the point it dropped β and a stream of the connect and disconnect events themselves.
agent_sessions is the same idea for benches: when an agent connected, when it went away, when
the stretch truly ended, and the machine identity it reported at handshake time.
The agent page reads that history the same way the device page does β a list of stretches, a timeline of the gaps between them, and a stream of the connect and disconnect events β and adds the two numbers that matter at a glance: how long the agent has been connected in total, and how many times it has dropped. Each stretch carries the machine identity the agent reported when it connected, so a bench that was moved to another machine says so.
The screens
| Screen | What it is for |
|---|---|
/devices | The inventory, open to everyone. Every device the studio knows, with its kind, model, OS version, current bench and service state, filterable by kind, state and bench. |
/devices/<id> | One device in full: its record, and the timeline of every stretch it has spent on a bench, with the reason each one ended. |
/admin/devices | The registry, for admins. The same list plus the lifecycle actions β send a unit to repair, return it to service, retire it. |
Every row and card carries two states side by side: presence β on a bench, reported gone, or not on a bench β and the device's own service state, in service, in repair, or retired. Presence is whether the bench reports the device plugged in right now; service state is whether it can be used at all. A retired device can still be sitting on a bench, and a device in repair is not on any bench.
The inventory keeps itself current: when a bench reports a device plugged in or unplugged, the row follows without a reload.
Both lists read either way: a table for scanning and comparing, a grid of cards for one device at a time. The choice is remembered, so the list looks the same the next time you open it.
A device opens its own record from wherever you meet it: the name is a link, and so is the row it sits in. On a bench page the click lands on the same record, with the same presence history.
The inventory answers "what do we have and where is it right now". The registry answers "is it still fit to be used", and it is the one screen that changes a device's life. A device that has been sent to repair keeps its row and its history; it simply stops being counted as in service.
Vehicles
A vehicle is a car on a rig.
| Column | Type | Meaning |
|---|---|---|
name | text, not null | The human handle. Not unique. |
make | text, not null | Manufacturer name. |
model | text, not null | Model name. |
year | text | Model year. |
vin | text | Vehicle identification number β the handle you quote when you mean one specific car. |
A vehicle is attached to an environment through the environment's config: record the vin of the
car that sits in that rig, and the environment carries it. The same convention applies to a
vehicle-only environment β an environment of type vehicle describes the car it is built around,
and the vehicle record carries the details.
OEMs
An OEM is a manufacturer: name, a unique code, and an optional description.
| Column | Type | Meaning |
|---|---|---|
name | text, not null | The manufacturer name, matching the make on its vehicles. |
code | text | Short key, unique across the table. |
description | text | Optional notes. |
code is the short handle to use when you name things and when you write configuration β it is
the one field in the asset model that is guaranteed to be unique, so it is the one you can key on.
Naming and tagging
name is the handle on every asset table, and it is the first thing your team sees in a list. Put
the same information in it every time, in the same order, so that a name can be read at a glance
and searched for without opening a record.
A convention that works across a lab:
| Part | Example | Why |
|---|---|---|
| Location | bench-02 | Which bench in the room. |
| Role | -dut, -rig, -hmi | What the asset is for: device under test, rig, head unit. |
| Tag | -icc, -ccc, -fleet-b | The protocol, the campaign, or the variant being tested. |
So bench-02-dut-icc is the ICC device under test on bench 02, and bench-02-rig-ccc is the CCC
rig on the same bench. The same convention applied to environments, devices and agents means that
a search for bench-02 returns everything that lives on that bench, and a search for -icc
returns every ICC asset in the lab.
Because the tag lives in the name, it is only a tag if everyone writes it the same way. Agree the suffixes before the lab grows, and keep to them β renaming half the inventory later costs more than the convention did.
How to verify
- Open
/environmentsand check that each rig has atypethat says what it is and aconfigthat lists what is on it. - Open
/devicesand look for the unit on your bench: its kind, itsdevice_id, its OS version and which bench it is sitting on. - Open the unit itself and read its presence history β every stretch it has spent on a bench, and why each one ended.
- Open
/admin/devicesas an admin, send a unit to repair, and watch it counted as out of service in/devices. - Move a device to another bench and back β it keeps one registry row and gains a new stretch in its history.
- Compare the inventory with the live pool:
GET /api/agentsshows which benches are actually connected, and the agent name should match the environment name.
Related pages
- The Agent Pool β the live inventory of connected benches.
- Device Topology and Physical Connection β how benches, devices and ports are wired.
- Glossary β the vocabulary the platform uses for these objects.