Repository navigation
The home dashboard
This page is made from docs/home.md on every change to
main; edit it there.
What build(home) draws for a Home, every tile and pop-up, and why. The templates that draw them are named in parentheses (Templates); src/home/slots.ts fills their slots from the home, src/home/plan.ts makes the home a plan of the panel's builder, and the builder places them (Stack). The demo home, demo/home.ts, draws every one of them. For the look, see Design.
- At a glance
- Stack
- Layout
- Items: the common row
- Lists
- Pop-up headers
- Rooms
- Lights
- Heating and AC
- Vacuum
- 3D printer
- More devices
- Media
- Garage
- People
- Infrastructure
- The integrations' words and shapes
- Names and icons
What the generator writes: one sections view with the Glances strip, four sections of tiles one under another (Layout), and an untitled section that holds every pop-up.
| Section | Tiles |
|---|---|
| Rooms | Per room: the icon, the temperature and humidity, chips for the window, door, lock, heating and AC, a Leak and a Batteries chip while there is a problem, and a Lights row with its controls |
| People | Per person: presence, and Driving and Do not disturb chips. |
| Garage | Per car: the fuel, and Doors, Windows, Alarm and Tyres chips |
| Infrastructure | Server (Proxmox): its CPU and memory, and Guests, Checks, Backups and Notifications chips. Network: the internet latency, and Devices and Firmware chips. Tailscale: Offline, Relayed and Update chips. AdGuard: the blocked share and the processing time, an Update chip and the protection toggle. Home Assistant: its memory and free disk, and Services, Updates and Firmware chips. Media: the streams playing, and Requests, Downloads, Health and Update chips |
A status icon on a tile is drawn only while something is wrong. A room's window and door icons while the sensor is not off, the car's Doors, Windows, Alarm and Tyres, the people's Driving and Do not disturb, and every status icon of Server, Network, AdGuard, Home Assistant and Media (the status and tyres controls are silent, the notifications icon has a show rule): a tile with nothing to report has no icon row. An icon whose entity is unavailable is drawn, in orange, since that is a problem too. Controls you press, such as a lock, the AC, a light's power or AdGuard's protection, stay. A pop-up is the details of its tile and keeps showing its state, so a room's header still shows a closed window.
| Pop-up | Shows |
|---|---|
#<room> |
Lights, Climate, Air, Covers, Cameras, Appliances, Pets, Plants, Media, Other (vacuum, 3D printer, outlets, diffuser), Batteries, Energy: each only when present; Plants, Batteries and Energy folded, Batteries open while one is low |
#energy |
The power now (home, solar, grid, EV charger, battery) and the energy today |
#batteries |
The batteries under 20 %, lowest first, with their level as a bar |
#<room>-3d-printer |
The camera, the print, the temperatures, the power outlet and its energy |
#<room>-lights |
The group's sliders, the scenes, every light (sub-groups expandable) |
#<room>-heating |
The target and preset, the valves, the thermostats' batteries |
#<room>-ac |
The target, fan, swing, horizontal swing, power saving, dehumidifier, energy |
#<room>-vacuum |
Routines, the map, details, settings, the dock, maintenance, totals |
#car-<key> |
The VIN, security, a plan of the car from above with its openings and tyres, details, its location |
#<room>-<speaker> |
The speaker's sound: volume, and the bass, treble, balance and loudness it has, then its TV, subwoofer and surround settings |
#person-<key> |
Devices, and location permissions that aren't "always" |
#person-<key>-<device> |
The battery, and the companion app's details |
#system |
Resources, services, updates, firmware (the system's, then one list per room) |
#proxmox |
Notifications, stopped guests, daily checks, the host, disks, storage, energy, the guests table, backups |
#proxmox-notifications |
Every message Proxmox sent, newest first, one card each with its title, its source (Proxmox VE, PBS or the guest) and a clear button; a tap shows the text; Clear all in the header |
#adguard |
Queries, the update; the protection toggle in the header |
#network |
Internet, devices, the router, the Wi-Fi networks, the clients per network, folded but for Other, firmware |
#tailscale |
A card per device, the essential ones under Infrastructure and the others under Devices: connected or last seen, a pending update, a key about to expire, and for the router and exit node how they connect |
#network-<key> |
A Wi-Fi network's QR code, while the network is on |
#media |
Watching, requests, downloads, the upcoming releases, the library, Plex's update |
How the pop-ups behave. They open as adaptive dialogs, 560 px wide on a desktop and a sheet on a phone, or as the home's popupOpen says for each kind of screen ({ tablet: 'unfold', desktop: 'unfold' } unfolds them out of their tile, in its place); second-level pop-ups have a back button. Every item follows one pattern: name, icon and state on the left, and flat buttons on the right, with the filled on / off last.
Colour.
- Red: water, an unlocked lock or car, a car alarm, a low tyre, a critical battery, a full container disk, blocklists that failed to download, a degraded pool or a failing disk, a server running hot, a bucket at its free limit.
- Orange: an open window or door, a low battery, a tyre that is dropping, a filling container disk, a link below 10 Gbps, a worn disk, a warm server, a bucket nearing the 20 GB it may hold.
- Amber: on. AdGuard's protection is the exception: on is how it should always be, so its chip is neutral while on and orange while off, as its pop-up's header is.
Every threshold has two stages, so a slow drift and a fault don't look alike. There are no graphs: history lives in HA's more-info dialogs.
-
Almost everything is a custom card. Everything the dashboard shows comes from
mnml-cards.js, the pop-up shell included. The few native HA cards are the vacuum map, the 3D printer's camera and the Wi-Fi QR codes (picture-entity), the car's location (map) and the routine buttons (grid). - No other HACS card. Everything is MNML's or native.
-
Template instances, every slot spelled. The dashboard is MNML template cards, one per tile, each with every slot written from the home and no
area, so nothing is discovered. Repetition is the templates' job (roomper room); spelling is the generator's. No decluttering card. -
One generator.
homePlan(home)is the home as a plan of the panel's builder (Building a dashboard): the Glances strip, each room, person and system tile spelled (spelled: true, its slots all of them), each car, the section titles, the order and the openings.build(home)is that plan drawn by the builder'sdashboardOf(), with no registries to discover from, so a home in code and a dashboard the panel builds are drawn by the same code. -
Where new things go:
- a read-only value: a row of a list card, or an entry of a state line;
- a control: a
Controlin a lane; - a new kind of thing: a new card, under
src/cards/with its configuration insrc/contract/cards.ts, and the template that draws it.
- Nothing hides behind more-info. No graphs, and no more-info dialog behind anything. History lives in HA's more-info dialogs, outside the dashboard.
-
One view. It is a
sectionsview withmax_columns: 3. The Glances strip comes first, across the whole width. Then four titled sections, eachcolumn_span: 3: Rooms, People, Garage, Infrastructure, or in the order of the home'sorder(a list ofrooms,people,garageandsystem, each once), whichproblems()checks. The titles aremnml-heading-cards withgrid_options.columns: full, from the home'ssections. A section with no tiles, the Garage of a home with no car, is left out with its heading. Last comes an untitled section holding the pop-up shell. -
Section headings. A heading has its title and icon at the left, and a trailing group (
.trail) at the right with a state line, controls, or both. A folding list's heading ends in a chevron after its summary, and the whole heading is the tap target; folded, the heading stands alone, with no surface under it. -
Tile width. Every tile writes
grid_options: { columns: 12 }over MNML's default of half a section, so each takes 12 grid columns. The Garage and the Infrastructure keep the rhythm of the Rooms: at three columns, three infrastructure tiles fill a row and the other two take the next.- Each view column is twelve grid columns, so a section is 36 wide when three columns fit and 24 when two do.
- Two tiles share a row only while twice the width fits, so 12 is a third of a row at three columns and half a row at two. No single value can be half at three columns and full at two.
| Window width (sidebar open) | Tiles per row |
|---|---|
| about 1360 px and up | 3 |
| below that | 2, so a 1280 px laptop gets 2 |
| about 500 px and down | 1 |
| 600 to 900 px | 1, a 500 px tile centred by HA's column cap; a 900 px tablet gets 1 until the sidebar collapses |
The sidebar costs roughly 250 px.
An item (mnml-entity-card) is every card in a pop-up that stands for an entity or a device: name, icon, state line, controls.
Where a tap goes.
-
The row opens the device's pop-up when it has one: lights, AC, heating, vacuum, a person's phone or tablet, a Wi-Fi network. A speaker's media card links the same way.
- Otherwise nothing opens: outlets, the diffuser, the dock's switches, the lights inside the lights pop-up.
- A linking row takes the
linkclass, with the hover and press wash. It prebuilds onpointerdownand stops the tap, so a row inside a tile doesn't also open the tile's pop-up.
-
The pill keeps
role="button", its label and the keyboard path. So what a pointer reaches anywhere along the row, a keyboard and a screen reader reach at one control, and no button is nested inside another.
The pill's icon is the entity's ha-state-icon, unless the item names an icon. The phone and tablet rows name one, because a device_tracker would draw a person rather than the thing it tracks.
An item may carry a name, which wins over the registry, for the one case the registry can't answer. A companion-app device whose entities are all unavailable has no friendly name, and would print its entity id.
Controls, with power last and filled on anything that toggles:
| On | Controls |
|---|---|
| A light | The scenes button (mdi:palette-swatch), then the brightness, white temperature and, in color rooms, hue slider buttons (light-item, light-controls), then power. The sliders show while the light is not off (show: { not: ['off'] }); the scenes button always shows, since a scene is how an off room is turned on |
| The heating | The target-temperature slider button while it runs, a preset select over preset_modes while it runs, then power (heating-item, heating-controls) |
| The AC | The target slider button while it runs, then a filled select over hvac_modes in place of a power button. It is blue while not off, and its icon is the current mode's (HVAC_ICONS; mdi:power while off). The tap that would switch the unit on asks which mode; hvac_modes contains off, so the same menu turns it off |
| The diffuser | The amount slider button, then power |
| The 3D printer | Its job buttons while a job runs, then the outlet's power button while none does (3d-printer-actions, 3d-printer-card) |
| The vacuum | Dock while not docked or Locate while docked, then Start while not cleaning or Stop (vacuum.stop) while cleaning (vacuum-actions) |
A slider button opens its slider as an overlay over the card; on a tile's Lights row, over that row alone, so the tile's own header stays.
Every read-only section is one mnml-list-card. The card's title is drawn above its surface, like any heading.
Layout.
-
Rows are a grid, 32 px each: the state icon, the name, a 72 px bar column when any row has
bar, and the value right-aligned in tabular figures. -
A long value is cut, not the name. A value takes at most half the row (
VALUE_SHARE, of the list's width), and what doesn't fit ends in an ellipsis, so a file name never squeezes the names beside it. A bar and a long value don't share a list: on a phone the two leave the names no room. -
With
headersthe list is a table. A 24 px header row sits in the secondary colour; the first header spans the icon and name columns, and the rest are right-aligned over theirs. Each row gives one cell per entity ofvalues, showing "—" where an entity has no value.headerstherefore has one entry more thanvalues. A row withofin a table shows its last value as a share of that entity, orange overhighand red overcritical_high. -
Hiding. A row is hidden while its entity has no value or its
showrule fails, and it leaves no gap. A card whose rows are all hidden renders nothing, title included, and takes no space: the pop-up leaves no gap for it. -
Lowest first (
lowest_first) orders the rows by their number, ascending, a row without one last; in the model's order otherwise. A table keeps its order.
Folding. A list with fold shows its heading alone, ending in a chevron, until it needs you:
-
It needs you while a row is orange or red: a threshold crossed, an orange or red
colorrule holding, a warning shown, or a value unavailable. Amber, such as an outlet that is on, doesn't count. So the rule is the colouring the list already does, and adds no threshold. - A tap on the heading folds or unfolds it, and holds until the page reloads, whatever the rows do; then each list starts from its rule again.
-
The summary sits at the heading's right, folded or not.
summary: 'lowest'or'highest'is that row's value as the row shows it, a share as a share: "Lowest 65%".summary: { sum: n }adds up a table's values columnnunder its header, "Today 0.1 kWh", and shows nothing when the column mixes units. - What folds: Batteries, in the rooms and the heating pop-ups; Energy, in the rooms, the ACs, the 3D printer and the server; the server's Storage; the vacuum's Maintenance and Totals; and the Network pop-up's clients, network by network. Everything that shows only while it needs you (Stopped, Updates, Firmware) and the short readings (Host, Internet, Queries) don't fold.
Row semantics. A row carries the section's meaning through the fields of ListRow and nothing else:
| Row | Written as |
|---|---|
| A battery |
{ entity, label: 'device', bar: true, low, critical }: orange under low, red under critical, the room's or the person's low and critical slots, 20 and 5 unless the home sets them |
| A share |
{ entity, label: 'device', bar: true, of, high, critical_high }: the entity's share of of, bar and value, in the same unit or a dash; orange over high, red over critical_high
|
| A consumable |
{ entity, strip: ' time left', reset }. reset draws a 28 px restart button that presses the button entity: the one action a list row carries |
| A warning | { entity, flag: true, color: 'orange', show: { is: ['on'] } } |
| A progress | { entity, bar: true, show: { entity: vacuum, is: ['cleaning'] } } |
| A daily total |
{ entity, zero_when_empty: true }: no value yet today reads "0 floors", in the entity's own unit and precision, uncoloured; any threshold applies to the 0 |
| A timestamp |
{ entity, relative: true }, shown as "6 hours ago" |
| A link |
link-row: a port's link speed, orange while it isn't 10 Gbps (its speed default) |
| A raw word | { entity, words: '[[lock_words]]', color: red, when: { is: ['[[unlocked]]'] } } |
batteries and energy-table (templates/common.yaml) draw the two lists every room shares. Both fold: Batteries lowest first, summed up by its lowest; Energy by today's total.
A pop-up template's card is its hash and its cards, a mnml-header-card first.
-
The header shows the pop-up's name and icon, and the entity it is about: its
color/whenfor the pill, and itsstatefor the line. - Controls are the same ones its item has.
-
Buttons. A back button appears when
backis set; a close button always does. Both are 40 px rounds.
Titles.
- A second-level pop-up is titled after what it is: Lights, Heating, AC, Vacuum, Phone, Tablet. A speaker's and a Wi-Fi network's take their entity's name, so the Sonos reads "Sonos" and a network its SSID.
- Its state line is the name of the pop-up it was opened from: a
textitem with the room's, or, for a device, anameitem on thepersonentity. It carries no state. So the title names the pop-up, the line says where it is, and the entity's state stays in the body, which is about it.
Sections. Every section has a heading, either a mnml-heading-card in front of the cards or the title of a list or of the car plan. Both are drawn alike.
room writes a mnml-tile-card in two rows.
First row.
- The pill. The room icon alone. Problems are chips, below.
-
The name, with the temperature and humidity under it (
room:statewithicon: true, so each value follows its sensor's icon, joined with•). -
Chips at the top right, icon-only on the pill colour, in this order (
room, thenroom):- the window and the door:
indicator, orange while open; - the lock:
toggle, red while unlocked, open or jammed. Tapping it locks or unlocks, without confirmation; - AC and Heating:
nav, the unit's own icon, blue or orange while not off. They open#<room>-acand#<room>-heating; - Leak and Batteries:
statuschips drawn only while there is a problem, hidden otherwise. The leak chip is red while a leak sensor is wet. The battery chip is red under 5 % and orange under 20 % (critical,low), and either chip turns orange while a sensor it watches is unavailable. Hovering a chip lists the sensors behind it, an offline device once.
- the window and the door:
Second row: the Lights item, across the whole tile.
- It is
light-item: the sameItemthe room pop-up's Lights section is built from, drawn by the sameitemRow(). - It is a 44 px strip in the pill colour. The group's icon sits in a 36 px pill in the card colour, amber while on. Then come the group's name with its brightness and, while it is on, the active scene ("80% • Relax"), the scenes button, the slider buttons and the power button, all filled in the card colour.
- Brightness is a button, like the other two values, not a strip to drag. So the tile and the pop-up offer the same controls in the same order, and one lights item in the model can't drift into two shapes.
-
Taps. Tapping the strip opens
#<room>-lightsand stops there. Its controls stop their own taps. Tapping anything else on the tile opens#<room>.
The tile shows vital state only: temperature, humidity, a window or door while it is open, lock, climate, lights, and a leak or a low battery while there is one. Every other device lives in the room pop-up.
The header (room-popup) has the room's name and icon and the same window, door and lock chips.
- The lock comes first, so that the chip that unlocks a door isn't next to the close button.
- The state line repeats the tile's vitals, so the temperature and humidity are in the same place in both. That line costs 19 px, which is what pushes the longest room pop-ups past the shell's height. A pop-up that clips by a hair is the first place to look when this changes.
Sections, in a fixed order, each only when non-empty:
| Section | Contents |
|---|---|
| Lights | The light group item, opening #<room>-lights, with the room's scenes in its lane |
| Climate | The AC and the Heating items, each with a line of Off, or the target and the action |
| Media |
media-card per player; a speaker's opens its pop-up |
| Air |
fan-card and humidifier-card per fan and humidifier: the state, a speed or target slider, a power button |
| Covers |
cover-card per cover: a position slider, and Open, Stop and Close buttons, each only while it applies |
| Cameras |
camera-card per camera, a live picture, then camera-activity: the doorbell, person and motion sensors, orange while on |
| Appliances |
appliance-card per appliance: the cycle state, the time left and the power, blue while a cycle runs |
| Pets |
pet-card per feeder: when it last ate, the food and litter levels, and a Feed button |
| Plants |
plants: soil moisture per plant, driest first, orange under 30 % and red under 15 % |
| Other |
room-popup: the vacuum, the 3D printer, outlets, the diffuser |
| Batteries |
batteries: one row per battery, labelled with its device, the level as a bar |
| Energy |
energy-table: headers Item / Now / Today / Total, one row per metered device (outlets, then the AC), labelled with the device. An outlet's power shows only here |
What has no card here.
- Leak sensors. They surface through the tile's Leak chip while wet, and through the batteries.
- The lock. Its chip is in the header.
- Anything generic. There is no general info section; a new read-only value needs its own place.
A device that needs a pop-up of its own gets a second-level one, #<room>-<device>, whose header has back: true.
Every battery is spelled once, next to its device:
- the thermostats' in
heating.thermostats; - the vacuum's in
vacuum.battery, a charge level in its state line rather than a battery to replace; - the room's other batteries in
batteries.
roomSlots()'s batteries (src/home/slots.ts) joins the room's and the thermostats' lists and sorts them by entity id. It is the one list the generator orders itself, since two lists of the home meet in it. The room pop-up's Batteries list and the tile's Batteries chip both read it. The list then shows them lowest first (lowest_first), so the entity ids only settle a tie.
The header has the room's name as its line, the group for its pill, and the power button.
The sections:
-
All lights. The group's slider cards (
lights-popup): brightness, where 0 turns the light off; white temperature in kelvin; and, incolorrooms, hue.- A card
visibilityhides all three, heading included, while the group is off: a brightness, a hue and a kelvin the light isn't showing aren't values. - With the group on but in the other colour mode, the attribute is absent while the card shows. That is the one state where the gradients desaturate and lose their marker.
- A card
-
Scenes. One
mnml-select-cardover the room'sscenes(lights-popup), and the one section with no heading: a single card that already names itself.- A scene's own state is when it was last activated, not whether it is showing. So the active scene comes from the room's
activeScene, the Hue select whose state is the active scene's name. The card's state line names it, and the menu checks the scene of that name. With no scene active, the select readsunknown, and the card has no state line and the menu marks nothing. - The Lights item takes the same name into its state line while the group is on (
light-item), so the tile reads "80% • Relax". - The match is by the name the menu shows. A scene renamed in HA but not in the Hue app is never checked.
- It comes before the lights because a room is set from its scenes, while a single bulb is rarely touched.
- A scene's own state is when it was last activated, not whether it is showing. So the active scene comes from the room's
-
Lights. Every other light of the room, as items with the slider and power controls of the room's Lights item, without its scenes button, and with no pop-up.
- Each is named without the word "Light" (
strip_word: Light), and they are listed in order of that name: "Countertop", "Top", "TV". - A
{ group, members }member becomes one card for the sub-group, with its bulbs as the card'sitems. It is collapsed by default; a chevron at the head of its lane expands the bulbs as rows indented by a pill's width, so a bulb's icon sits under its group's name. - The card keeps whether it is open on the element (
expanded), so a state update draws it open. - So the living room lists two rows, Top and TV, rather than ten bulbs.
- Each is named without the word "Light" (
Both pop-ups are built from the same cards:
-
The target slider (
heating-popup):slider: temperature,climate.set_temperature, and the unit'smin_temp,max_tempandtarget_temp_step.- On a unit with a power switch it carries
turn_on. The card then callsclimate.turn_onfirst when the unit is off, so one drag both starts it and sets the target. - That is why the heating's slider has no
visibilityand the AC's does: an AC is started by choosing a mode.
- On a unit with a power switch it carries
-
Mode cards (
ac-popup) aremnml-select-cards over a mode attribute.- A mode card shows the current option's icon:
HVAC_ICONSfor a mode,ha-attribute-iconfor a preset, for a swing mode only when HA has an icon for it, and none for a fan or horizontal swing mode, whose words are the unit's own (low-medium,far left). Its label is in the line, and its whole body opens the menu. - A
selectentity's card shows its options throughhass.formatEntityState(), with no icons.
- A mode card shows the current option's icon:
| Pop-up | Header | Sections |
|---|---|---|
#<room>-heating |
The room's name, the target button, the preset menu, power | Settings: the target slider, which stays whatever the unit reads, and a Preset card hidden while off. Valves: one row per thermostat, the valve position as a bar. Batteries: the thermostats' |
#<room>-ac |
The room's name, the target button, the HVAC mode button |
Temperature: the target slider, hidden with its heading while off. Settings: the Fan, Swing and Horizontal swing cards, the power saving select (select-card), the dehumidifier number (number-slider). Energy
|
- The HVAC mode has no card of its own. The header's mode button is where the unit is switched on, off or over.
-
Only what the unit has is written. The AC's settings are written only for the fields the model has (
fan,swing,horizontalSwing,powerSaving,dehumidifier,energy), and the Settings heading only when one of its cards is. The heating's Preset card and control needpreset.- Each flag is set only for a list the unit reports among its capabilities.
- A mode card whose attribute yields no options renders nothing, rather than an empty menu.
- Not shown: the AC's temperature source and error sensor.
The header has the room's name as its line, and Dock / Locate and Start / Stop next to it. The vacuum's line (vacuum-card: its error while it has one, the status, the current room while cleaning, the battery, then the dock's error while it is not Ok and the mop drying time left in minutes while drying) is the entity card's in the room pop-up, not the header's.
| Section | Contents |
|---|---|
| Routines | A grid of mnml-button-cards pressing the button. entities, two per row so that a routine's full name fits. A tap colours the pill for 600 ms |
| Map |
picture-entity on the vacuum's image entity |
| Details | The progress as a bar, the area and the time while cleaning; the last clean as a relative time while not; mop attached, and water box attached where the model has it |
| Settings | The settings selects as mnml-select-cards: cleaning mode, mop mode, mop intensity |
| Dock |
vacuum-popup: the dust emptying, mop drying and mop washing switches, one item each with a power button |
| Maintenance |
vacuum-popup: the consumables of the vacuum and of the dock together, labelled without " time left" and formatted by HA ("38h 5m"), then both sets of warnings as orange flags shown while on. It folds, and opens while a warning shows |
| Totals |
vacuum-popup: the lifetime cleaning count, area and time, where the model has totals. HA names the area and the time "Cleaning area (total)" and "Cleaning time (total)", apart from the current clean's; the rows strip " (total)", since the heading says it. It folds |
The dock has no pop-up and no item of its own. It isn't a thing you go to; it is part of the vacuum. So its switches are a section of the vacuum pop-up, and its consumables and warnings share the vacuum's list. The model's dock block still holds its entities, because which entity belongs where follows the HA device.
The 3D printer is an item of its room's Other section, like the vacuum. Its line is the 3D printer's state, then the progress while a job runs (printing, paused or needing attention). While the 3D printer's outlet is off, the line is the outlet's "Off" instead. A tap opens the pop-up.
The job's buttons each show only in the state where the 3D printer accepts it: Cancel while a job runs, Pause while printing, Resume while paused, and Continue while it asks for attention (3d-printer-actions). The header has them too. Its line is the room's name alone, as the vacuum's and the lights' are: the 3D printer's state and progress are in the item and in the Print rows.
The item adds the outlet's power button, filled and last, as on any item that toggles (3d-printer-card). It is hidden while a job runs, since cutting the power ends the print; Cancel is there instead.
A switched-off 3D printer reads orange. With its outlet off, PrusaLink can't reach the 3D printer and its entities are unavailable, so the item's pill takes the orange of an unavailable entity.
| Section | Contents |
|---|---|
| Camera |
picture-entity on the 3D printer's camera, streaming live (camera_view: live) while the pop-up is open |
| The loaded material, then, while a job runs, the progress, the file, the print speed, and the start and the finish as relative times | |
| Temperatures | A table of the nozzle and the heatbed, now and target, named without " temperature" |
| Power | The 3D printer's outlet, an item with a power button, then its meter in an Energy table |
Job rows wait for a job. PrusaLink reports the job's entities, and its buttons, as unavailable while the 3D printer is idle. Shown then, they would be orange dashes for a 3D printer that is fine. So they are shown only while a job runs.
The outlet belongs to the 3D printer, not the room. The room pop-up lists neither the outlet nor its meter; only the 3D printer's pop-up does. Its firmware stays in the room's firmware list, with the room's other devices.
The room's tile and pop-up take these from the room's cameras, covers, fans, humidifiers, appliances, pets and plants, each only when the room has them. A room placed by area finds its cameras, covers, fans and humidifiers itself. The home's security adds the alarm and the smoke detectors to the glances above Rooms; energy adds the power the home uses to them.
-
Cameras. The pop-up streams each camera live as long as it is open; the tile never loads a picture. A chip on the room's tile lights orange while a camera's
doorbellorpersonsensor is on, and all three sensors are rows of Activity, orange while on. -
Covers. A cover with a position has a slider; a garage door (
garage: true) has none, and its chip on the room's tile lights orange while it is open, opening or closing, and closes it when pressed. -
Air. A fan's slider sets its speed in percent, a humidifier's its target humidity; either has a power button.
-
Appliances. The entity is the status sensor of the washer, the dryer or the dishwasher; the item is blue while a cycle runs (running, washing, drying, rinsing, spinning, in use).
-
Pets and plants. The feeder's Feed button presses a
button. The plants' bars use the thresholds of the batteries, 30 % and 15 %. -
Glances. One strip across the top of the dashboard, a line high, each item a well. It has the weather (the temperature of
outside, the icon showing the conditions), the alarm panel as a button that arms it (away) or disarms it, and the vacation toggle (vacation), and the energy the home uses now (energy), which opens#energy. The alarm and vacation are red when they do not fit who is home: switched on with somebody home, or off with everybody away; the alarm is also red while triggered. Otherwise they read as normal, the alarm as its icon alone. Then what needs you, each drawn only while it does, and a tap opens where to deal with it:- failed checks and warnings of the server, failing disks and a backup problem:
#proxmox; - the server's notifications:
#proxmox-notifications; - services that are down and pending updates and firmware:
#system; - the power the home uses:
#energy, which lists the power now (home, solar, grid, EV charger, battery) and the energy today; - low batteries, a count of the room's, the heating's and the people's, orange under 20 % and red under 5 %:
#batteries, which lists those under 20 %, lowest first; - stopped guests:
#proxmox; - network devices that are down, in none of the network's up states (
device_up):#network; - essential Tailscale devices that are offline:
#tailscale; - the media server's health, while Radarr reports a problem:
#media; - a lock that is unlocked, open or jammed, one item per lock: its room's pop-up;
- a car that is unlocked or unarmed, one item per car, counting its lock and its arming state in the car template's words (
unlocked,disarmed):#car-<key>; - leaks and smoke, which open nothing: the room's tile has its Leak chip.
A strip with nothing to show is not drawn. An item is an icon and its value, with no title: the name is its tooltip, and a count's tooltip lists what it counts. The calm statuses sit on the left and what needs you on the right, behind a hairline, in wells that are louder than the calm ones. The vacation item is its dimmed icon alone until it is on. The weather is the temperature beside an icon that follows the conditions.
- failed checks and warnings of the server, failing disks and a backup problem:
mnml-media-card:
- The pill shows the player's picture while it is active (playing, paused, buffering, on), and its icon otherwise.
- The text is the name, then the title and artist (or the app and series) as the line. While idle, the line is HA's state.
-
The lanes follow
supported_features: previous, play / pause (filled,media_player.media_play_pause), next, then the volume slider button and the power toggle, amber while not off. - Under 480 px the previous and next buttons hide, so the name keeps its room.
-
A speaker's card links. A player the model spells as a
Speaker, rather than a bare id, has a pop-up of its own. Its row and its pill open it, while the transport, volume and power buttons keep their own taps.
The header is the player, with the room's name as its line and a back button. The transport stays on the media card in the room pop-up: this pop-up is for how the speaker sounds.
| Section | Contents |
|---|---|
| Sound | The volume, as a slider card on the player; the bass, the treble and the balance, as number sliders, and loudness, an item with power, each where the model has it |
| TV | The input format on the heading's line ("Dolby Atmos"), where the model has it; night sound and speech enhancement, items with power; the audio delay |
| Subwoofer | Whether the sub plays, and its gain, shown only while it does |
| Surround | Whether the surrounds play, and while they do, their level for TV and for music, and whether music plays through them at full volume |
-
Only what the speaker has is written. A
Speakerneeds only itskeyand its player (entity):bass,treble,balanceandloudnessare optional, for a speaker without those settings, andtv,subwooferandsurroundfor one that isn't a soundbar or has no sub or surrounds bonded. -
A level shows only while its part plays. The sub's gain and the surrounds' levels are hidden while the sub or the surrounds are off (
while-not-off), as a light's sliders are while it is off. - What Sonos reports besides (crossfade, the status light, touch controls, autoplay, the microphone) stays disabled in Home Assistant.
car shows the car's icon and its name, with the fuel under it (state with icon: true). The name is the metadata sensor's device's (entity: car.metadata with label: 'device'), so renaming the car in HA renames the tile. Four chips sit at the top right (car). Each always shows, coloured by the first of its rules that holds:
| Chip | Icon | Colour |
|---|---|---|
| Doors | mdi:car-door |
Red while the lock sensor reads one of unlocked; orange while a door, the hood or the tailgate is on
|
| Windows | mdi:car-windshield-outline |
Orange while a window or the sunroof is open or intermediate
|
| Alarm | mdi:shield-car |
Red while alarmActive is on or unavailable, or while the arming state is unarmed (disarmed) or unavailable; not drawn while the car is armed (doorsOnly, doorsTiltCabin) |
| Tyres | mdi:car-tire-alert |
Orange while a tyre is under tyre_warn_share of its target, red under tyre_low_share; titled "Tyre pressure dropping" or "Tyre pressure low" (the tyres control) |
A chip is drawn only while it is an issue, so a car with nothing wrong has none. Hovering a chip lists the entities behind its colour, with their states. The lock and arming states read through the same dictionaries as the Security list (words), so the tooltip says "Doors only", not doorsOnly.
The BMW states are raw words with no translation: SECURED / LOCKED / SELECTIVE-LOCKED / UNLOCKED, unarmed / doorsOnly / doorsTiltCabin, CLOSED / INTERMEDIATE / OPEN.
- The
cartemplate holds, as slot defaults, the state lists that the tile's rules and the pop-up's rows share (unlocked,disarmed,open_states). The plan takesopen_statesas its half open states, so a part in one of them is drawn at least half open. - It also holds the dictionaries the list card's
wordsrenders them with:lock_words("Locked", "Partly locked") andalarm_words("Doors only", "Armed"). - A word the dictionaries don't list comes out lower-cased, without hyphens and capitalised ("Unarmed").
The header has no controls. Its entity is the metadata sensor: the header takes that sensor's device's name (label: 'device'), shows the car's icon, and has the VIN as its line ({ serial: true }, the serial number of the sensor's device). The pill turns orange while the sensor is unavailable.
| Section | Contents |
|---|---|
| Security | The lock state, red while one of unlocked; the arming state, amber while not one of disarmed; the Alarm flag, red and shown while alarmActive is on |
| Status |
car-plan: the mnml-car-plan-card
|
| Details | The fuel level, then the remainingFuel in litres where the car has it, the remaining range (one is read from the other), the mileage, "Service in" when the car has service, then the 12 V batteryVoltage and the coolantTemperature where the car reports them |
| Location | HA's map card on location, aspect_ratio: 3:1
|
src/cards/car-plan.ts draws an SVG of the car seen from above, nose at the left and the car's left side at the bottom, in a 480 × 251 viewBox.
The silhouette is a trace, not a drawing. The outline, the windscreen, the rear screen, the cowl band, the four side-glass panes and the four lamp crescents are subpaths of a vector trace of a top-down photograph, kept in its 992 × 620 space.
- One group transform mirrors the trace's nose-right onto the project's nose-left, and fits its 966 × 490 silhouette to the box. So the geometry stays the trace's, and only the transform is the project's.
- The mirrors belong to the outline, as in the trace, and they set the drawing's height: the room the tyres protrude into.
- The outline is stroked, so that it reads against a card it is only a shade away from. It is also the clip for everything inside it.
What the trace can't give is built in the same space, aligned to what it can:
- The hood is everything forward of the cowl, and the boot lid everything aft of the rear screen. Each runs past the end of the car, so the clip gives it the body's own nose or tail rather than an edge of its own.
- A door is the shoulder band between two pillars, with its inboard edge on its own glass. So an open door and an open window stay regions you can tell apart.
At rest, the car draws almost nothing.
- A closed door, hood or boot draws nothing at all, neither outline nor fill. A region with nothing to report isn't on screen.
- The
seamclass is the outline redrawn above the fills at a fifth of the text colour. It isn't a seam of its own; it keeps an edge on the body, so an open part reads as a region inside it. - The roof runs from the rear screen to the windscreen, just inside the side glass. Its ends are set clear of both, so that a straight edge never crosses a curved one.
-
The sunroof, on a car that has one, sits inside the roof with a tighter radius and a stronger stroke, so the two don't read as one box.
- Its margin is even across the car (35 and 32 units) but not along it (129 units toward the tail, 52 toward the nose). That puts its centre 38.5 units forward of the roof's.
- The windscreen and the cowl are nudged toward the nose by
SCREEN_SHIFT, and the sunroof is inset from what was traced. Those are the two places the drawing departs from the trace.
Lamps and tyres.
- The lamps are filled against the card colour rather than tinted over the body. So they stay opaque, and read on top of an open hood or boot.
- The front pair has well over twice the contrast of the rear, so the nose is the end you can name at a glance.
- The tyres are footprints sized from a real tyre: the diameter along the car, the section width across it, on a wheelbase of three fifths of the length. They overlap the flank and protrude past it, which is the only way a wheel shows in a view this flat.
- Every stroke is
non-scaling-stroke, so a width is pixels on the card, not units of the trace.
What turns colour:
| Part | Colour |
|---|---|
A door, the hood, the tailgate on
|
Orange |
A window or the sunroof open
|
Orange |
A window intermediate
|
Half-transparent orange |
A tyre under tyre_warn_share of its target |
Orange |
A tyre under tyre_low_share of its target |
Red |
Pressures and caption.
- The tyre pressures are HTML labels in rows above and below the drawing, positioned at the axle centres in percent of the width. So they keep their 12 px size on a phone ("2.1 / 2.4 bar": current, then target). Each number takes its sensor's display precision from HA.
- A caption under the drawing lists the problems ("Front left door open • Rear right window half open • One tyre low") or reads "All closed".
- Hovering a part gives its state (
<title>).
A tile per person of the home's people (person):
-
The pill: the
personentity's icon. A Batteries chip, drawn only while a device battery is low or unavailable, sits with the status chips. -
The
personentity's name, with its state under it: Home, Away or a zone. -
Two
statuschips, inert, drawn only while they hold, and each titled with the entities behind its colour:- Driving (
mdi:steering), amber while any device'sactivityreadsautomotive; - Do not disturb (
mdi:moon-waning-crescent), amber while any device'sfocusis on.
- Driving (
And nothing else. A tile is the glance, and a phone's readings are not what you look at a person's card for.
-
The header is the
personentity: its name, icon and state, and nothing more precise. -
Devices. One item per device: the device's
iconandname, with its tracker state and battery as the line. Two values, because the row is a way in rather than a readout.- A device item renders whether or not its entities read anything, where a table row would hide. So a tablet that has gone quiet still appears, named, with an empty line: the honest picture.
-
Location access. A row per device, orange, shown only while its location permission is not
authorized always. It is a warning rather than a column nobody reads: a tracker on "while in use" only updates with the app open, which silently breaks every presence automation. -
Health, for a person with
health: steps, distance, flights climbed, active energy and resting energy, as the Health store reports them. They belong to the person rather than to the phone that reports them. Each is a daily total that the phone reports only once the day has a sample, so a row with no value reads 0 rather than an orange dash (zero_when_empty): a day without stairs is not a broken sensor.
Where a person is, is left out on purpose. The person entity's state says Home, Away or a zone. Neither the geocoded address nor a map is on the dashboard.
Health comes from one source. The Companion app reports steps and distance twice, from the phone's pedometer and from the Health store, and the tablet repeats the phone's store. So the model spells the Health store's five, from the phone, on each person, and HA has the pedometer's and the tablet's disabled. The heart rate, sleep, weight and the other Health readings are left out of the model.
- The header shows the device's icon and name, the person's name as its line, and a back button to the person. Neither the tracker's state nor the battery is repeated there: the first row below is the battery, and where the person is belongs to the person pop-up.
-
Battery. The level as a bar, orange under the person's
lowand red under theircritical, 20 % and 5 % unless the home sets them, then the charging state. -
Details. Free storage, connection type, network, activity, Focus (and its name where the device reports one), and the location permission, orange while it is not
authorized always.
Everything else the companion app reports lives here rather than on the row above it: a phone has a dozen readings, and none of them is what you open a person's card to see.
Six tiles, one per system the house runs on, each with its own pop-up, in this order, each before what depends on it: the server, the network, Tailscale, AdGuard, Home Assistant and the media server. They take the default width, so three share a row at three columns and the six fill two rows. The home's system holds all six; proxmox, network, tailscale, adguard and media are optional, and their tile and pop-up exist only when the model has them.
Each system reads its own entities. Proxmox owns the server and every guest on it, AdGuard its filtering, the network its devices, Tailscale the tailnet's devices, the media server Plex and Jellyfin, Seerr, Radarr and Sonarr, and Home Assistant its virtual machine, services, updates and firmware. The one entity two cards share is Home Assistant's own guest, whose CPU and memory are both the Home Assistant tile's and a row of the guests table, so it is one Guest constant.
The tile and its pop-up are named "Server" after the machine they show; Proxmox is what runs on it, and the hashes, the model field and the templates (proxmox-server) keep its name. The tile has the server's CPU and memory under it, and four chips, in the pop-up's order: Guests, red while a guest is not running; Checks, red while the server's last daily checks had a failure and orange while the last run is over 26 hours old, a timer that stopped included; Backups, red while the server's last backup reports a problem; and Notifications, amber while Proxmox has sent messages that are not cleared. Notifications is a nav chip: it opens #proxmox-notifications directly.
The server outlet has no power button anywhere. It feeds the machine the dashboard is served from, and a filled toggle there would be one tap from switching the house's brain off. So it lives in the pop-up, not on the tile.
| Section | Contents |
|---|---|
| Notifications |
proxmox-popup, with no heading, like the lights pop-up's Scenes: the number of messages, or "None", amber while there is one. It opens #proxmox-notifications, and comes first because a lit chip is why the pop-up was opened; Stopped and Daily checks follow, as what else needs you |
| Stopped | One red row per guest that is not running, named by its device (stopped-row) |
| Checks |
proxmox-popup, an item like Notifications: the name Checks with the last run, as a relative time, under it; a red icon while the failures are not 0 and an orange one while the warnings are not 0; and, while the home gives checks.actions, a Run button that becomes Stop while the checks run. It opens #checks, the daily checks: the failures, the warnings, the last run and an orange flag while it is overdue, then Check details, while there are any: each failed check in red and each warning in orange, with the details under it, from the failures sensor's details attribute. Its header has the same Run and Stop, and a back button |
| Host | The outlet's state, amber while on, then the server's CPU, its memory as a bar, its last boot, as a relative time, its link to the router (link-row), and the CPU's and the root disk's temperatures, pushed by the host: orange over cpu_hot and root_disk_hot, red over cpu_critical and root_disk_critical
|
| Disks |
proxmox-popup: the ZFS pool's health, red while not ONLINE; the disks failing SMART, red while not 0; and the lowest life left among the disks that report one, as a bar, orange under disk_life_low and red under disk_life_critical
|
| Storage | Each storage as a bar, named by its device. It folds, summed up by the fullest |
| Energy | The outlet's meter; its wattage and energy are here rather than in Host, so the reading is in one place. It sits with the host, whose outlet it meters |
| Guests |
proxmox-popup: every guest, named by its device, with its CPU, its memory and, for a container, its disk used as a share of its size: orange over disk_high, red over disk_full. Proxmox reports no disk use for a VM, which shows a dash. The row's icon is the guest's running state |
| Backups | The last backup, as a relative time, a red row while it reports a problem, and the off-site bucket's size: orange over bucket_high and red over bucket_full
|
What the server would mail to root, from the host and from every guest. The header reads "Notifications · Server", with Clear all while there is a message, and a back button to #proxmox. Under it, one mnml-messages-card lists the messages, newest first, each as an item on a card of its own, spaced like the pop-up's cards:
-
The row: an envelope in the pill, coloured by the message's severity (red for
error, orange forwarning, blue fornoticeandinfo, grey for any other), the title as the name, the source and the time on the state line, "PBS • 2 hours ago", and a clear button. -
The text is collapsed. Tapping the row shows it under the row, across the card's whole width so that a log table fits a phone; the title wraps rather than ending in an ellipsis, and the envelope opens. Tapping again hides it. The pill is the keyboard path, with
aria-expanded. A message stays open while the list updates, until it is cleared. - A message without text has nothing to expand: its row doesn't link and its pill is not a button.
The text is the sender's summary, a few lines, and for a failure the source's own text under it: a backup's failed guests' log lines, an update report, a disk's smartd warning. Those are plain-text tables and logs, so the text is monospace and keeps its line breaks. A line wider than the card wraps rather than scrolling sideways, because the end of a log line is usually the error.
Each message names its source. Proxmox VE and PBS run on the server, and a guest's mail reaches Home Assistant through it, so the host is always the server; each message carries a source instead. proxmox.notifications.sources names pve and pbs, "Proxmox VE" and "PBS", and every guest with a host adds itself, named by its device as in the Guests table (proxmoxSlots()'s message_sources, in src/home/slots.ts). A source the card doesn't know shows as sent, and a message without one shows its time alone. A guest renamed on the host needs its host to follow, or its messages show the bare host name.
Home Assistant keeps the list; the dashboard only reads it. proxmox.notifications names two entities:
| Field | Entity |
|---|---|
messages |
A trigger-based template sensor. Its state is the number of messages; its messages attribute lists them newest first, each { id, title, message, severity, source, time }: title, message, severity (info, notice, warning or error), source, and time in ISO 8601 |
clear |
A script, run through script.turn_on. With an id variable it removes that message; without one it removes them all |
Data gives the shape, and recipes/messages.yaml is a package that keeps such a list: an automation fires mnml_message with a title, a message, a severity and a source, and the script clears one message or all.
The tile has Home Assistant's memory percentage and free disk under it. Home Assistant runs as a virtual machine, so the memory is the machine's, and the disk is the one Home Assistant fills.
| Chip | Colour |
|---|---|
| Services | Red while the Matter server or the Thread border router is not running |
| Updates | Amber while any core, add-on or integration update entity is on |
| Firmware | Amber while any device update entity is on, the rooms' included |
| Section | Contents |
|---|---|
| Resources | The virtual machine's CPU, its memory as a bar, and the disk used and free |
| Backups | The last successful automatic backup, and the last one attempted, both as relative times: they differ while the latest backup failed; and a red row while problem is on. The section is drawn when backups is set |
| Services | One red row per services entry, named by its device and shown only while it is not running (stopped-row) |
| Updates | One flag row per update entity, shown while on (pending-row) |
| Firmware | The same for the devices outside any room; then one list per room, such as "Bedroom firmware", from the room's firmware
|
The tile takes its name from the protection switch's device, "AdGuard Home", and its icon from the switch, so the shield shows whether blocking is on. Under it are the share of queries blocked and the average processing time. Its chips are Update, amber while AdGuard has one, and the protection switch itself, neutral while on and orange while off, as the pop-up's header is: protection on is the normal state, so it reads calm.
Protection is the only control. It is for when a site breaks and blocking has to pause. It is a toggle chip on the tile and the power button of the pop-up's header, whose icon turns orange while protection is off.
| Section | Contents |
|---|---|
| Queries | The DNS queries, those blocked, the blocked share as a bar, and the average processing time |
| Blocklists | The rule count, red at 0: the lists failed to download, and nothing is blocked |
| Update | AdGuard's update entity, shown while on |
The tile has the first internet latency under it, and two chips: Devices, red while a network device is anything but connected, upgrading or provisioning (device_up); and Firmware, amber while a network device has an update.
| Section | Contents |
|---|---|
| Internet | Each latency: the gateway's average round trip to Cloudflare and to Google; then the WAN port's link speed (link-row) |
| Devices | The router, the switches and the AP, named by their devices, each red while it isn't up |
| Router | The gateway's CPU as a bar, and its temperature |
| Wi-Fi | One item per wifi network, named by its device, which is the SSID as UniFi names it, with On or Off as its line, and a power button on a switchable one. A tap opens the network's QR code |
| Clients |
mnml-clients-card: one section per network with a client connected, in the model's order, headed by the network's icon and name and the count, which a screen reader hears as "3 clients". Rows sort by IP: the connection type's icon (Wi-Fi, Ethernet, else a question mark, each labelled for a screen reader), the name with the FQDN under it, the IP. A client in no listed subnet, or without an IPv4 address, goes to Other, last. A client UniFi has no name for takes its FQDN, then its IP. While the clients sensor has no value or no list, the card draws nothing; while it is unavailable, a Clients heading over the orange dash. "No clients" means UniFi listed none. Each network folds to its heading and count; Other stays open, since a client outside every known network needs you. A tap opens or folds one, until the page reloads |
| Firmware | One flag row per network device's update entity, shown while on |
Clients come from two sensors. UniFi lists the clients connected now, with their names and IPs; AdGuard's reverse lookups give each IP its FQDN: its rDNS names count, and its etc/hosts names with a dot, since AdGuard knows its own host, dns.home.arpa, only from there. Undotted hosts entries such as ip6-allnodes, and ARP, DHCP and WHOIS names, don't. The card joins them by IP, so a row survives AdGuard being down, without its FQDN, and names is optional for a home without AdGuard. UniFi's networks carry no subnet, so clients.networks spells each network's name, icon and subnet, in the order the sections take; the first network whose subnet holds an IP takes it. A subnet that isn't an IPv4 range (octets 0-255, a prefix of 0-32) fails the card's configuration, and problems() checks every subnet of the home, so a typo can't quietly empty a network.
Only the Guests network can be switched. The Wi-Fi items take their name and their On or Off from UniFi's switch for the network. Only a network the model marks switchable gets a power button, on its item and its pop-up's header: Guests, which is on only while there are guests. The others have none, since turning off a network the dashboard is reached over would cut the dashboard off with it.
The latency is a reading, not an alarm. The sensor reports the gateway's average round trip to each target, and nothing in it says the line is down, so no chip watches it. Two targets tell a slow site from a slow line.
One tile and one pop-up for the tailnet, with the devices spelled in the model, each with the sensors Tailscale reports for it. A device marked essential, the router and the exit node, is one that must stay connected; the others, phones, a laptop, a tablet, come and go, so their being offline is not a problem. The tile has no line under its name, and three chips, each drawn only while it holds: Offline, red while an essential device is not connected to Tailscale's control server; Relayed, orange while the router or exit node, the devices that carry traffic, cannot connect directly (udp off); and Update, amber while an essential device has a newer client. A personal device's update shows only on its card in the pop-up, since a phone or a laptop updates when its owner gets to it. A tooltip lists the devices behind a chip, by their names.
The pop-up is a card per device (tailscale-device), in two sections: Infrastructure, the essential devices, and Devices, the others, each in the model's order. Either heading is drawn only while it has a device under it.
| Part | Contents |
|---|---|
| Title | The device's name, as Home Assistant has it, without its leading "Tailscale" ("Router", "Angie phone"); the icon follows its connection, and an essential device's turns red while it is not connected |
| Status | The device's IP address (ip_address), when it has one |
| Update | A red icon while the device has a newer client; not drawn otherwise |
| Key | A red icon while its key expires within soon_days (14) or has expired (within_days); not drawn while the key is further off, or does not expire |
| Connection | For a device with udp, always drawn: blue, Direct while it supports UDP; orange, Relayed, while it does not |
| Connected | Last, one icon in every state: blue, "Connected", while the device is connected; otherwise a grey clock whose tooltip is "Last seen" and when it was |
The QR code a phone scans to join one network: UniFi's image entity for it, as a picture-entity under "Scan to join". The header is the network's switch, named by its device, with "Network" as its line and a back button to #network. UniFi draws the code from the network's SSID and password, so a new password shows here without a change to the model.
An off network has no code. UniFi reports the image unavailable while its network is off, which a picture-entity draws as a spinner that never ends. So the heading and the code are hidden while the switch reads off (while-not-off), and the header's line reads "Network • Off".
The media server: Plex, and Jellyfin beside it, which stream, Seerr, where requests come in, and Radarr and Sonarr, which fetch them. The tile has the streams playing under it, one count for each server with its own icon, and up to four chips: Requests, amber while a request waits for approval; Downloads, amber while Radarr's or Sonarr's queue is not empty; Health, red while Radarr reports a problem; and Update, amber while Plex has one.
| Section | Contents |
|---|---|
| Watching | Each server's streams, named by its device |
| Requests | Those pending, amber while not 0, and those processing |
| Downloads | Radarr's and Sonarr's queues, named by their devices, amber while not 0; Sonarr's wanted episodes; Radarr's health, shown while it reports a problem |
| Upcoming |
mnml-agenda-card over Sonarr's and Radarr's calendars: the episodes and movies from today on, by week, only the weeks that have something: the first, then one more per Next, and Back to now to return |
| Library | The movies and the shows, named by their devices; Sonarr's upcoming episodes; the free space on Radarr's movies folder |
| Update | Plex's update entity, shown while on |
Upcoming reads the calendars, not a sensor. Home Assistant gives a calendar's events for any range, so the card asks for 13 weeks at a time, as far ahead as Next needs and a year past the last week shown at most, when the pop-up opens and again when a calendar's state changes; nothing is stored in Home Assistant. Weeks start on Monday, and days are the browser's.
Wanted is a reading. Sonarr counts every missing episode of a monitored show, aired before the show was added included, so the count stays high and colours nothing; the queue is what shows a download under way.
Every section that reports trouble is invisible while there is none: Services, Stopped, the Updates and Firmware lists, AdGuard's and Plex's Update. That is what makes the chips enough at a glance. The sections that report a reading (Resources, Host, Storage, Guests, Backups, Queries, Internet, Devices, Wi-Fi, VPN, Clients, Router, Watching, Requests, Downloads, Library) are always there, and colour a row only while something is wrong.
Named by device. The Storage, Stopped, Guests, Services, Devices, Updates and Firmware rows, the media server's queues, health and library counts, and the chips' tooltips, are labelled with the device (label: 'device'). Every update entity is named "Update" or "Firmware", every Proxmox guest's running state "Status", every storage's "Storage used", and every network device's "State", so the device is the only name that tells them apart. Device names are room-relative, so a device's firmware is spelled in its room, as its battery is, and the pop-up lists it under that room's name.
What the cards rely on that each integration decides, which only the live instance can confirm; the first suspects when something reported from it looks wrong.
-
BMW CarData states.
-
SELECTIVE-LOCKED,doorsOnly,doorsTiltCabinandINTERMEDIATEare the integration's words. A state it adds comes out capitalised as is, and on the alarm chip it counts as armed. - The car plan reads
on/openas open andINTERMEDIATEas half open. - Whether the door, hood and tailgate sensors have a device class decides whether their titles say Open / Closed or On / Off.
- The target tyre pressures are hidden entities (
hidden_by: user) whose states the cards still read.
-
-
Climate capabilities.
- The ACs report
fan_modes,swing_modesandswing_horizontal_modes, in words of their own that HA has no icons or translations for, and the Better Thermostat entitiespreset_modes(and HA has icons for the presets). - Better Thermostat supports
climate.turn_onandclimate.turn_off. The ACs are switched throughclimate.set_hvac_modeonly,offincluded. - The heating's target slider calls
climate.turn_onbeforeclimate.set_temperaturewhen the unit is off.
- The ACs report
-
The vacuum.
- Stop calls
vacuum.stop; a vacuum that can only pause would needvacuum.pause. - The dock's sensors:
dock_error, the water boxes, andmop_drying_remaining_timein seconds, shown in minutes. Alsomop_attached, and the map'simageentity. - The dock's toggles show whatever icons HA gives its switches.
- Stop calls
- The client list. The shapes of UniFi's and AdGuard's answers, which the two sensors pass on as they are (Data).
- The lights. A bulb that lacks the white or colour mode does nothing with that slider.
- Names and icons. The names and icons HA shows for every entity, and whether they fit their lanes. The room pop-up's light item carries five controls: scenes, brightness, white temperature, hue and power.
Anything with an entity takes its name and icon from Home Assistant. A card, row or control with an entity shows:
- the entity's own name from the registry (
entityName()); - its state icon (
ha-state-icon), which follows its state.
Rename or re-icon the entity in HA, and every place that shows it follows. A name that is too long is shortened in HA, not here. An icon-only control shows whatever icon HA has for its entity, so an entity without a meaningful icon gets one in HA (Settings → Entities).
Three options adjust a row's name without spelling it:
-
label: 'device'names a row after its device (name_by_user, thenname), where the entity's name would repeat the section: the battery rows, the valve rows, the Energy rows, the Storage, Stopped, Guests, Services and Devices rows, the Updates and Firmware rows, and a status chip's tooltip. The car's tile and header use it too, so the car is called by its device ("Sedan"), and so do the Wi-Fi items and headers, so a network is called by its SSID. -
stripremoves a literal suffix that every entry of a section shares, such as " time left" in Maintenance. -
strip_wordremoves a word with its optional plural and leading space, wherever it falls.strip_word: Lightturns "Top Lights" into "Top", "Top Light 1" into "Top 1" and "TV Left Light" into "TV Left". The card builds the pattern from the bare word, so the YAML carries no expression.
A literal name is written only where the label isn't the entity's own:
- the car's Alarm flag, whose entity gives it its visibility while the label names the problem;
- "Service in";
- the mode cards (Preset, Mode, Fan, Swing, Horizontal swing), which are attributes of one entity;
- the Location access rows, named after their device rather than after the permission sensor.
Names and icons are written for what has no entity, or stands for an action:
-
Tiles and headers: the room's
name, and the room's or car'sicon, from the model; "Lights", "Heating", "AC" and "Vacuum" on second-level headers. The car's tile and header take their name from HA: the metadata sensor's device, withlabel: 'device'. The person's take both from thepersonentity. - Headings, and the car plan's title.
-
Slider buttons and cards: the
light-controlstemplate's (Brightness, White temperature, Color), the heating's and the AC's target, Amount on the diffuser, Volume on a player. -
Service buttons: Dock, Locate, Start, Stop, the media transport; the power button (
mdi:power). -
The car's
statuschips (Doors, Windows, Alarm, Tyres), since each sums up several entities. - The Energy table's headers: Item, Now, Today, Total.
-
A
Device's name and icon: "Phone", "Tablet", on its item in the person pop-up and on its own header. A device whose companion-app entities are all unavailable has no name in the registry to be called by.