Skip to main content

Entity types

Every discovered component becomes an entity of a Kind. Twelve kinds are hand-written in Rust; every other component is described as data by a JSON type table, compiled into the hub. Components that are neither are reported under GET /api/v1/ignored. To add one, see Adding a device.

Kinds​

KindHome Assistant component
lightlight
switchswitch
covercover
climateclimate
sensorsensor
binary_sensorbinary_sensor
alarm_panelalarm_control_panel
numbernumber
selectselect
buttonbutton
vacuumvacuum
water_heaterwater_heater
genericany component the type table describes; the component name is in the entity's component

Only device (device-based discovery) is folded by routing: it expands into one entity per entry. Any other component that the hand-written kinds and the table do not describe is reported as ignored component <name> under GET /api/v1/ignored.

The type table​

crates/oikos-core/src/types/table.json is shaped {"version": 1, "types": {"<component>": {…}}}. Each entry says where the entity shows, which field is its primary state, which controls it offers, what puts it in alert style and how its history is charted.

Sixteen components are covered:

ComponentPlacementPrimary fieldControlsNotes
cameracardpicturenonePicture served by /api/v1/entities/{id}/picture.
device_automationsignallastnoneRemotes; several configs of one device fold into one entity.
device_trackercardstatenonestate required. History: home 1, not_home 0.
eventsignallastnonestate required.
fancardstatepower, percentage, preset, oscillation, directionMain: power. History: on 1, off 0.
humidifiercardstatepower, target, modeMain: power. History charts target.
imagecardpicturenonePicture served like a camera.
lawn_mowercardactivitystart, pause, dockMain: start. Alert style on error.
lockcardstatelocked, openstate required. Main: locked. Alert style on unlocked, jammed. History: locked 1, unlocked 0.
notifytargetnonemessageA target flows can send to.
scenecardnoneactivateMain: activate.
sirencardstatepower, tonestate required. Main: power. Alert style when on.
tagsignallastnoneTag scanners.
textcardvaluevalueMain: value.
updateupdatelatestnoneFields installed and latest feed the firmware marks.
valvecardstatevalve, stopstate required. Main: valve. History: open 1, closed 0.

Entry keys​

KeyMeaning
placementWhere the entity shows: card (Home), signal (a trigger for flows), target (something flows can send to) or update (a firmware mark).
iconA glyph name for the card.
primaryThe field name shown on the card, or null.
requires_stateWhen true, discovery is rejected without the primary field's topic.
fieldsA map of field_name to { shape, topic, template?, values?, options?, range?, on?, json_path? }. shape is on_off, number, choice, text, picture or version. topic is the config key holding the state topic, template the config key holding its value template. values lists the allowed values, each with the config key that may override its payload and the Home Assistant default. options names a list in the config (such as preset_modes). range is {min, max, step} with defaults and optional config keys. on is the value that counts as on. json_path, for a text or version field, reads one top-level key when the rendered template produces a JSON object (how a Zigbee2MQTT update entity exposes installed_version and latest_version from one template).
controlsA map of control_name to { shape, topic, template?, field?, press?, payload?, payload_on?, payload_off?, json_key?, requires?, labels? }. topic is the config key of the command topic. press: true makes a button, which has no state. payload is a word definition {value, default}, which may also carry a key. field ties the control to a field it changes. json_key sends {json_key: value} instead of the bare value. requires is an extra config key that must be present to announce the control. labels are the card's button words for an on/off control.
mainThe default main control, in preference order.
alerts[{field, any_of}]: field values that put the card in alert style.
history{field, map}. map turns the field's text values into numbers, such as {"on": 1.0, "off": 0.0}. An empty map keeps a number as it is.

Publication​

The hub publishes the whole table retained on <ui_prefix>/_types (default oikos/ui/_types) on every connection, next to oikos/ui/_areas and the per-entity oikos/ui/<id> overrides, so the Android app reads the same vocabulary. Its own echo is ignored.

Behaviours​

  • Secret text. A text entity with mode: password is masked as •••• on every state path out of the hub (REST, WebSocket, MCP) and is left out of history.
  • Remotes fold into one entity. Several device_automation configs for one device fold into a single remote entity, whose capabilities.generic.signals lists their payloads. Zigbee2MQTT announces an action only after it first sees it, so the hub also seeds each Zigbee2MQTT remote with every value of the action enum its device exposes in bridge/devices (in that order, marked "seeded": true): a double press is a signal before anyone double-presses, and a remote that was never pressed is listed. An announced action replaces its seeded twin. trigger.signal in a flow fires on those remotes, on events and on tags.
  • Main control. The override mainControl names one announced control, or "none" to hide the main control. Without it the card leads with the first announced entry of the type's main list.
  • Firmware marks. update entities feed the firmware marks (installed, latest, available) that the device view shows. A device with several update entities shows the first that reports a version.
  • Pictures. Camera and image entities carry their picture in the picture field.

Folding​

Some entities are folded into another entity's card (part_of). A folded entity is not primary, so list_entities hides it unless you pass include: "all". The rules are recomputed after every change, so the result does not depend on arrival order:

  • A device with exactly one light folds its number and select entities into that light (a strip's "Effect speed" belongs in the light's sheet). With two lights the owner is ambiguous: no fold.
  • Zigbee2MQTT publishes a cover and a separate "Moving" sensor off the same state payload. A sensor folds into the cover of its device when both read the same state_topic and the sensor's value_template reads exactly one JSON field that the cover's template also reads. A binary sensor with device_class: moving on a device with exactly one cover folds too. The cover rule wins a conflict.

An entity is primary (shown by default) when it has the primary category, is enabled by default, is not folded and is not hidden by its override. entity_category: diagnostic or config and enabled_by_default: false keep it out.

Overrides​

An override is a retained JSON document at <ui_prefix>/<entity id> that changes how one entity appears. Set it from the web device sheet, PATCH /api/v1/entities/{id}/override or MCP set_override; null clears a field. Unknown fields and invalid values are refused and nothing is written. These twenty fields are the app's, in its order:

FieldTypeMeaning
namestringDisplay name.
areastringRoom id (a raw room name is resolved).
hiddenboolHide the entity from the default lists.
orderintegerSort position.
cardStylestringCard style of a sensor's card in the app.
favoriteboolMark as favourite.
energyRolestringsolar, grid, grid_export, battery, house, consumer or water: puts the entity on the Energy tab.
energyInvertboolFlip the sign of an energy reading whose role is signed (a direction).
securityHiddenboolTake a sensor off the Security tab.
energyIconstringIcon of a consumer on the Energy diagram.
energyMeterstringThe energy counter paired with a power reading on the Energy tab.
homePinnedboolKeep the entity on Home although Energy or Security already shows it.
securityActionboolOffer a switch or button as an action on the Security tab.
securityAskbool (default true)Ask for confirmation before the Security action.
ungroupedboolKeep the entity out of the derived room groups used by the one-time group migration.
showAsstringlight, door, siren, chime or plug: what a switch drives. Only read on a switch. Absent is a plain switch.
lightOnPresetstringwhite, warm, red, green or blue: the colour a light takes when switched on.
lightOnBrightnessinteger1 to 255: the brightness a light takes when switched on.
climatePresetsstringPreset buttons of a climate entity's card in the app.
mainControlstringA generic entity's main control: one of its announced controls, or none.
invertboolA switch wired the other way round (relay on = device off). The hub swaps on and off in the state it decodes and the commands it sends, so the web UI, flows, ambiances, history and MCP all see the device's real state. Only read on a switch.

A newer app's unknown fields survive a read-modify-write. For compatibility with an app that only knows the retired asLight flag, the hub writes asLight: true next to showAs: "light", and reads a stored asLight as showAs: "light".

Home leaves out what Energy or Security already shows, unless homePinned is set: an entity with an energyRole, a security-class binary sensor or alarm panel (unless securityHidden), or an opted-in securityAction leaves Home.

Room priority for an entity: the override area, then the discovery suggested_area, then the room from the device name's / path, then Unassigned.