Define a Custom Entity Type

Hands-on: create a new entity type and fields with the Schema Editor.

In this tutorial you will use the Schema Editor to define a brand-new entity type from scratch, give it a parent to inherit from, and add a handful of fields with the correct data kinds and storage scopes. By the end you will have a persisted entity type with both inherited and direct fields, ready to hold real entity instances. We will model a simple Pump type as the running example, but the same steps apply to any type you want to define.

Looking for full details?

This is a hands-on tutorial. For the complete reference (every field, option, and edge case), see the Schema Editor reference.

What you'll need

  • Access to the ControlBird platform UI with the schema.edit permission and the Debug responsibility. The Schema Editor will not open without both.
  • A desktop browser. The editor opens in a two-panel layout.
  • A name in mind for your new type and a short list of fields you want it to carry. For this walkthrough we will create a Pump type with a setpoint, an enabled flag, and a live status.

Decide on scope before you start

The most important decision for each field is its storage scope. Configuration-scoped fields are saved persistently and survive restarts, while Runtime-scoped fields live only in memory. Sketch out which of your fields are persistent settings and which are live, derived values before you begin: it makes every step below faster.

Step by step

  1. Open the Schema Editor. Launch it from the platform UI. The editor shows the list of entity types and loads each type's schema when you select it.

    Expected result: a two-panel layout, with a searchable, paginated tree of entity types on the left (25, 50, or 100 root types per page) and an empty detail panel on the right.

  2. Create the new entity type. Click New Entity Type (or press Ctrl+N) to open the create form. Enter the type name Pump, and in the parent selector choose Object so your type inherits the base structural fields.

    Expected result: the create form shows Pump with Object listed as its parent.

  3. Create the type. Click Create. ControlBird registers the new type with Object as its parent, and the type appears in the tree nested under Object.

    Expected result: Pump is visible in the type tree. Selecting it shows an entity header with its name, type ID, parent name (Object), and field counts.

  4. Review what you inherited. With Pump selected, look at the read-only Inherited Fields table. Because Pump inherits from Object, you will see Description and Faceplates contributed by the parent. The Direct Fields table is still empty: that is what you fill in next.

    Inherited fields are read-only here

    You cannot edit Description or Faceplates from the Pump view. To change an inherited field, edit the parent type (Object) directly. The structural fields Name, Parent, and Children are handled separately and never appear in the schema tables.

  5. Add a persistent setpoint field. In the Add Field section, enter the field name Setpoint, select the kind Float, set the rank to 1, and set the storage scope to Configuration. Optionally enter a default value such as 0.0. Click Add Field.

    Expected result: Setpoint appears immediately in the Direct Fields table, sorted by its rank.

  6. Add an enabled flag. Add another field named Enabled with kind Boolean, rank 2, and storage scope Configuration. Click Add Field. A Bool field defaults to false unless you set a default.

    Expected result: Enabled joins the Direct Fields table below Setpoint.

  7. Add a live status as a Choice field. Add a field named Status with kind Choice. For a Choice field, enter the options as a comma-separated list (Idle,Running,Fault) and pick the default index 0 (which selects Idle). Set the rank to 3 and the storage scope to Runtime, because status is a live, derived value rather than a saved setting. Click Add Field.

    Expected result: Status appears with its three options listed and Idle selected by default.

    Choice fields have strict rules

    A Choice field must have at least one option, and the default index must fall within the valid range of options, here that means 0 to 2. An out-of-range default or an empty options list will be rejected when you save.

  8. Tidy up ranks if needed. You can edit field properties inline. If two fields share the same rank, they are sorted alphabetically by name as a tie-breaker, which can produce an order you did not intend. Adjust the rank values so the fields display in the order you want.

  9. Save your changes. Click Save Changes. The editor saves your Configuration-scoped fields persistently and updates the live schema so the tree and field counts stay accurate. To throw away unsaved edits instead, click Reset to reload from the server.

    Expected result: the entity header's field counts update, and your two Configuration-scoped fields (Setpoint, Enabled) are now saved persistently on the Pump type. The Runtime-scoped Status field exists only in memory.

What you built

After saving, your Pump type has the shape below. Configuration-scoped fields are stored persistently and survive restarts, while the Runtime-scoped field lives only in memory:

FieldKindScopeWhere it lives
SetpointFloatConfigurationSaved persistently
EnabledBoolConfigurationSaved persistently
StatusChoiceRuntimeIn memory only

Two things you cannot undo easily

Removing a direct field takes effect immediately, with no confirmation dialog, so double-check before removing anything, especially Configuration-scoped fields whose data is saved persistently. And once a type or field is created, it cannot be renamed. Choose names deliberately.

Next steps

Now that Pump exists, create and lay out instances of it in the Model Builder, then inspect the resulting rows in the Database Browser. To understand how field writes propagate to other services, read Notifications & Reactivity. When you need every option and edge case, return to the Schema Editor reference.