Skip to content

Commit

Permalink
feat: New layout config option
Browse files Browse the repository at this point in the history
Offer more control over how sensors are rendered. Right now two features
are added:
1. Remove all labels
2. Choose to render as "table" (current) or list. Expect more options to
   come here in order to support a truly compact card that can easily be
   used in lists.

BREAKING CHANGE: step_layout is moved under layout.step
  • Loading branch information
nervetattoo committed Apr 4, 2021
1 parent e1000b9 commit e0f461c
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 34 deletions.
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ Hide everything but sensors and temperature control:
```yaml
type: custom:simple-thermostat
entity: climate.hvac
step_layout: row
show_header: false
layout:
step: row
header: false
control: false
```
## Note about 1.0 release
## Note about 2.0 release
The 1.0 release only includes a rewrite to Typescript and a change of release management.
It does not include bug fixes or new features, in fact, due to the Typescript release I expect the 1.0 package to be less stable than 0.42.
The 2.0 release is most likely a breaking change for the majority of users.
Make sure you read the release notes and inspect the new configuration format.
It offers more flexibility and features as well as a number of bug fixes.
## Requirements
Expand Down Expand Up @@ -60,6 +62,11 @@ resources:
- `entity` _string_: The thermostat entity id **required**
- `header` _false|Header object_: See section about header config
- `setpoints` _false|Setpoints object_: See section about header config
- `layout` _Layout object_:
- `step` _row|column_: Where to render the setpoint up/down buttons
- `sensors`: _object_
- `type`: _list|table_: How to render the sensors
- `labels`: _boolean_: Whether to show labels/headings or not. Hiding here overrides hiding under root level `sensors` config
- `service` _object_: Must specify both domain+service if overriding
- `domain` _string_: Override the service call domain
- `service` _string_: Override the service call name
Expand All @@ -68,7 +75,6 @@ resources:
- `decimals` _number_: Specify number of decimals to use: 1 or 0
- `fallback` _string_: Specify a text to display if a valid set point can't be determined. Defaults to `N/A`
- `step_size` _number_: Override the default 0.5 step size for increasing/decreasing the temperature
- `step_layout` _string_: `row` or `column` (default). Using `row` will make the card more compact
- `label` _object_: Override untranslated labels
- `temperature`: _string_ Override Temperature label
- `state`: _string_ Override State label
Expand Down
6 changes: 5 additions & 1 deletion src/components/infoItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { html } from 'lit-html'
import { LooseObject } from '../types'

interface InfoItemDetails extends LooseObject {
heading?: string
heading?: string | false
icon?: string
unit?: string
}
Expand Down Expand Up @@ -52,6 +52,10 @@ export default function renderInfoItem({
valueCell = html` <div class="sensor-value">${state}</div> `
}

if (heading === false) {
return valueCell
}

const headingResult = icon
? html` <ha-icon icon="${icon}"></ha-icon> `
: html` ${heading}: `
Expand Down
33 changes: 24 additions & 9 deletions src/components/sensors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, nothing } from 'lit-html'
import { html } from 'lit-html'
import formatNumber from '../formatNumber'
import renderInfoItem from './infoItem'

Expand All @@ -14,22 +14,29 @@ export default function renderSensors({
const {
attributes: { hvac_action: action, current_temperature: current },
} = entity

const { type, labels: showLabels } = config?.layout?.sensors ?? {
type: 'table',
labels: true,
}
const sensorHtml = [
renderInfoItem({
hide: _hide.temperature,
state: `${formatNumber(current, config)}${unit || nothing}`,
state: `${formatNumber(current, config)}${unit || ''}`,
details: {
heading:
config?.label?.temperature ?? localize('ui.card.climate.currently'),
heading: showLabels
? config?.label?.temperature ?? localize('ui.card.climate.currently')
: false,
},
}),
renderInfoItem({
hide: _hide.state,
state: localize(action, 'state_attributes.climate.hvac_action.'),
details: {
heading:
config?.label?.state ??
localize('ui.panel.lovelace.editor.card.generic.state'),
heading: showLabels
? config?.label?.state ??
localize('ui.panel.lovelace.editor.card.generic.state')
: false,
},
}),
...(sensors.map(({ name, icon, state, unit }) => {
Expand All @@ -40,11 +47,19 @@ export default function renderSensors({
state,
localize,
openEntityPopover,
details: { heading: name, icon, unit },
details: {
heading: showLabels && name,
icon,
unit,
},
})
)
}) || null),
].filter((it) => it !== null)

return html` <div class="sensors">${sensorHtml}</div> `
const classes = [
showLabels ? 'with-labels' : 'without-labels',
type === 'list' ? 'as-list' : 'as-table',
]
return html` <div class="sensors ${classes.join(' ')}">${sensorHtml}</div> `
}
3 changes: 2 additions & 1 deletion src/config/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export interface CardConfig {
step_layout?: 'row' | 'column'
layout?: {
sensors: {
type: 'table'
type: 'table' | 'list'
labels: boolean
}
step: 'row' | 'column'
}
Expand Down
38 changes: 22 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ type ModeIcons = {
[key: string]: string
}

interface ModeOptions {
names: boolean
icons: boolean
headings: boolean
}

const DEFAULT_HIDE = {
temperature: false,
state: false,
Expand All @@ -70,14 +76,18 @@ function isIncluded(key: string, values: any) {
return true
}

function getModeList(type: string, attributes: any, config: any = {}) {
function getModeList(
type: string,
attributes: LooseObject,
config: LooseObject = {}
) {
return attributes[`${type}_modes`]
.filter((name: string) => isIncluded(name, config))
.map((name: string) => {
.filter((name) => isIncluded(name, config))
.map((name) => {
// Grab all values sans the possible include prop
// and stuff it into an object
const { include, ...values } =
typeof config[name] === 'object' ? config[name] : ({} as any)
const values = typeof config[name] === 'object' ? config[name] : {}
delete values.include
return {
icon: MODE_ICONS[name],
value: name,
Expand Down Expand Up @@ -118,11 +128,11 @@ export default class SimpleThermostat extends LitElement {
@property()
_values: Values
@property()
_updatingValues = false
_updatingValues: boolean = false
@property()
_hide = DEFAULT_HIDE
@property()
modeOptions = {
modeOptions: ModeOptions = {
names: true,
icons: true,
headings: true,
Expand Down Expand Up @@ -150,14 +160,14 @@ export default class SimpleThermostat extends LitElement {
if (!config.entity) {
throw new Error('You need to define an entity')
}
this.config = <CardConfig>{
this.config = {
decimals: DECIMALS,
...config,
}
}

set hass(hass: any) {
const entity = hass.states[this.config.entity as string]
const entity = hass.states[this.config.entity]
if (typeof entity === undefined) {
return
}
Expand Down Expand Up @@ -216,12 +226,8 @@ export default class SimpleThermostat extends LitElement {
if (entries.length > 0) {
controlModes = entries
.filter(([type]) => supportedModeType(type))
.map(([type, definition]) => {
const {
_name,
_hide_when_off,
...config
} = definition as ControlField
.map(([type, definition]: [string, ControlField]) => {
const { _name, _hide_when_off, ...config } = definition
return {
type,
hide_when_off: _hide_when_off,
Expand Down Expand Up @@ -319,7 +325,7 @@ export default class SimpleThermostat extends LitElement {

const unit = this.getUnit()

const stepLayout = this.config.step_layout || 'column'
const stepLayout = this.config?.layout?.step ?? 'column'
const row = stepLayout === 'row'

const classes = [!this.header && 'no-header', action].filter((cx) => !!cx)
Expand Down
17 changes: 16 additions & 1 deletion src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,28 @@ ha-card.no-header {

.sensors {
display: grid;
grid: auto-flow / auto auto;
grid-gap: var(--st-spacing, var(--st-default-spacing));
font-size: var(
--st-font-size-sensors,
var(--paper-font-subhead_-_font-size, 16px)
);
}
.sensors.as-list {
grid-auto-flow: column;
grid-template-columns: min-content;
}

.sensors.as-table {
&.without-labels {
grid: auto-flow / 100%;
place-items: start;
}
&.with-labels {
grid: auto-flow / auto auto;
place-items: start;
}
}

.sensor-value {
display: flex;
align-items: center;
Expand Down

0 comments on commit e0f461c

Please sign in to comment.