The Home Assistant Plasmoid displays entities with a flexible, adaptive interface that shows relevant state information, attributes, and visual indicators.
Display Representations
Compact Representation
When the plasmoid is collapsed in the panel, it shows a simple Home Assistant icon:
MouseArea {
onClicked: root.expanded = !root.expanded
MdiIcon {
name: "home-assistant"
anchors.fill: parent
anchors.centerIn: parent
}
}
Clicking the compact representation toggles the expanded full view.
Full Representation
The full representation displays all configured entities in a responsive grid layout:
GridView {
readonly property int dynamicColumnNumber: Math.min(Math.max(width / minItemWidth, 1), count)
readonly property int dynamicCellWidth: Math.max(width / dynamicColumnNumber, minItemWidth)
readonly property int minItemWidth: Kirigami.Units.iconSizes.enormous
cellWidth: dynamicCellWidth
cellHeight: minItemWidth / 2
model: itemModel
delegate: Entity {
width: GridView.view.cellWidth - Kirigami.Units.smallSpacing
height: GridView.view.cellHeight - Kirigami.Units.smallSpacing
contentItem: EntityDelegateTile {}
}
}
The grid automatically adjusts the number of columns based on available width, with a minimum item width constraint.
Entity Tiles
Each entity is displayed as a tile with the following components:
Layout Structure
The EntityDelegateTile.qml uses a 2-column grid layout:
GridLayout {
columns: 2
rows: model.value ? 2 : 1
columnSpacing: Kirigami.Units.smallSpacing
rowSpacing: 0
DynamicIcon {
name: model.icon
Layout.rowSpan: model.value ? 2 : 1
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
}
PlasmaExtras.Heading {
level: 4
text: model.value
visible: !!text
font.weight: Font.Bold
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
}
PlasmaComponents3.Label {
text: name
Layout.alignment: model.value ? Qt.AlignTop : 0
Layout.fillWidth: true
}
}
Components:
- Icon (left): Dynamic icon spanning 1-2 rows depending on whether a value is shown
- Value (top-right): Bold heading showing the current state or attribute value
- Name (bottom-right): Entity friendly name
When an entity has no display value, the tile shows only the icon and name in a single row.
Display Value Logic
The plasmoid uses sophisticated logic to determine what value to display for each entity. This is implemented in model.mjs:
function getDisplayValue({ state, attribute, attributes, unit }) {
if (attribute && attributes[attribute]) return attributes[attribute].toString()
if (state && state !== 'unknown') return state + (unit === '%' ? unit : ' ' + unit)
return ''
}
Display Priority
- Custom Attribute: If an
attribute is configured and exists, display its value
- State with Unit: If state is not ‘unknown’, display state with unit of measurement
- Empty: Return empty string if neither condition is met
Entity Model Construction
When entity data is received from Home Assistant, it’s processed into a display model:
export function Entity({
entity_id = '',
name,
icon,
state,
attribute = '',
attributes,
unit,
default_action = {},
scroll_action = {}
} = {}, data = {}) {
this.entity_id = entity_id
this.attributes = Object.assign({}, attributes, data.a)
this.state = data.s || state || ''
this.name = name || this.attributes.friendly_name || ''
this.icon = icon || this.attributes.icon || ''
this.unit = unit || this.attributes.unit_of_measurement || ''
this.attribute = attribute
this.default_action = default_action
this.scroll_action = scroll_action
this.active = activeStates.includes(this.state)
this.domain = entity_id.substring(0, entity_id.indexOf('.'))
this.value = getDisplayValue(this)
}
Fallback Hierarchy:
- Name: Configured name →
friendly_name attribute → empty string
- Icon: Configured icon → entity’s
icon attribute → empty string
- Unit: Configured unit →
unit_of_measurement attribute → empty string
Active State
Entities are considered “active” if their state is one of:
const activeStates = ['on', 'open', 'idle'];
Active entities are displayed with the button in a “down” state:
PlasmaComponents3.Button {
down: model.active
}
Dynamic Icons
The plasmoid supports two icon systems through the DynamicIcon component:
Loader {
property string name
property string type
property string id
sourceComponent: {
switch(type) {
case 'mdi': return mdi
case 'plasma': return plasma
}
}
onNameChanged: () => {
if (!name || !~name.indexOf(':')) return
[type, id] = name.split(':')
}
Component {
id: mdi
MdiIcon { name: id }
}
Component {
id: plasma
Kirigami.Icon { source: id }
}
}
- MDI icons:
mdi:icon-name (e.g., mdi:lightbulb)
- Plasma icons:
plasma:icon-name (e.g., plasma:preferences-desktop)
The component automatically parses the icon string and loads the appropriate icon type.
Units are displayed with special handling for percentage:
return state + (unit === '%' ? unit : ' ' + unit)
Examples:
"50%" - No space for percentage
"23.5 °C" - Space before unit
"125 W" - Space before unit
To display a specific attribute instead of the entity state, configure the attribute field in your entity configuration. For example, set attribute: "brightness" for a light to show brightness level instead of on/off.
Real-Time Updates
Entity displays update in real-time when Home Assistant sends state changes:
function updateState(state) {
for(let id in state) {
const itemIdx = items.findIndex(i => i.entity_id === id)
const change = state[id]['+'] // Only changed fields
const item = itemModel.get(itemIdx)
const newItem = new Model.Entity(item, change)
itemModel.set(itemIdx, newItem)
}
}
The plasmoid subscribes to entity state changes and efficiently updates only the changed properties in the model, triggering automatic UI refresh.