Skip to content

Examples

I originally wrote a plugin for my air conditioner implementation using esphome if interested, you can source esphome-mqtt-climate the following is a configuration example for my air conditioner

type: custom:mini-climate
entity: climate.dahatsu
name: Кондиционер
fan_mode:
  source:
    auto: Авто
    low: Слабый
    medium: Средний
    high: Сильный
    # for my implementation fan_modes_al is an array of available fan modes of the selected hvac mode
    __filter: >
      (source, state, entity) => entity.attributes
        .fan_modes_al.map(fan_mode => source.find(s => s.id === fan_mode))
        .filter(fan_mode => fan_mode)
buttons:
  swing_mode:
    type: dropdown
    icon: mdi:approximately-equal
    state:
      attribute: swing_mode
    # the drop-down list will remain active until swing_mode is off
    active: state => state !== 'off'
    source:
      'off': Выкл
      horizontal: Вкл
    change_action: >
      (selected, state, entity) => this.call_service('climate', 'set_swing_mode', { entity_id: entity.entity_id, swing_mode: selected })
  # turbo air conditioning button
  turbo:
    icon: mdi:weather-hurricane
    # control topic
    topic: 'dahatsu/turbo/set'
    state:
      attribute: turbo
      # for my device, the turbo attribute returns boolean type, convert it to on or off
      mapper: "(state, entity) => state ? 'on': 'off'"
    # turbo button is not available for all modes, block it when it is not available
    disabled: (state, entity) => !entity.attributes.turbo_al
    # when you click on the button, send the event to mqtt
    toggle_action: >
      (state) => this.call_service('mqtt', 'publish', { payload: this.toggle_state(state), topic: this.topic, retain: false, qos: 1 })
  # eco button configuration is the same as for turbo button
  eco:
    icon: mdi:leaf
    topic: 'dahatsu/eco/set'
    state:
      attribute: eco
      mapper: "(state, entity) => state ? 'on': 'off'"
    disabled: (state, entity) => !entity.attributes.eco_al
    toggle_action: >
      (state) => this.call_service('mqtt', 'publish', { payload: this.toggle_state(state), topic: this.topic, retain: false, qos: 1 })
  # health button configuration is the same as for turbo button
  health:
    icon: mdi:emoticon-happy-outline
    topic: 'dahatsu/health/set'
    state:
      attribute: health
      mapper: "(state, entity) => state ? 'on': 'off'"
    disabled: (state, entity) => !entity.attributes.health_al
    toggle_action: >
      (state) => this.call_service('mqtt', 'publish', { payload: this.toggle_state(state), topic: this.topic, retain: false, qos: 1  })
  # power off button
  power_switch:
    icon: mdi:power-plug
    state:
      entity: switch.air_conditioner_kitchen_switch_l1
indicators:
  # humidity indicator
  humidity:
    icon: mdi:water
    unit: '%'
    round: 1
    source:
      entity: sensor.sensor_temp_hum_pre_kitchen_humidity
  # power consumption indicator
  power_consumption:
    icon: mdi:flash
    unit: 'W'
    round: 1
    source:
      entity: sensor.dahatsu_power
  # power indicator
  power:
    icon: mdi:power-plug
    source:
      entity: switch.air_conditioner_kitchen_switch_l1
      values:
        'on': 'вкл'
        'off': 'выкл'
    # localization of values
    mapper: value => this.source.values[value]

Recipes

Five things this tracker has been asked for more than once, with the answer and what it looks like.

Each is also a card in the bench's manifest and an assertion in test/e2e/answers.test.mjs, so an answer that stops being true fails a run rather than sitting here reading well.

A card with nothing but the temperature

Everything that can be hidden, hidden - the icon, the name, the fan mode, the secondary info line and the toggle. What is left is the temperature and the buttons that change it.

type: custom:mini-climate
entity: climate.bedroom
name: ' '
hide_icon: true
toggle:
  hide: true
fan_mode:
  hide: true
secondary_info:
  hide: '() => true'

a card showing only the temperature and its buttons

An indicator with an icon and no value

There is no option for this, and none is needed: the value carries a style, and a style can hide it. The unit goes with it.

indicators:
  window:
    source:
      entity: binary_sensor.bedroom_window
    icon:
      template: "(value) => (value === 'on' ? 'mdi:window-open' : 'mdi:window-closed')"
      style: "(value) => (value === 'on' ? { color: 'orange' } : {})"
    value:
      style: "() => ({ display: 'none' })"

an indicator drawn as an icon alone

A shortened value

A mapper runs on every value the indicator reads, so anything that is a string can be cut, rounded or relabelled on the way to the card.

indicators:
  clock:
    icon: mdi:clock-outline
    source:
      entity: sensor.bedroom_clock
      mapper: "value => (typeof value === 'string' ? value.slice(0, 5) : value)"

an indicator showing hh:mm out of hh:mm:ss

The mode icon coloured by what the unit is doing

hvac_action is what the unit is doing now - heating, cooling, idle - as against state, which is what it was asked to do. The style template is handed the entity, so both are available.

hvac_mode:
  style: >
    (value, entity) => ({
      color: entity.attributes.hvac_action === 'cooling'
        ? 'blue'
        : entity.attributes.hvac_action === 'heating'
          ? 'red'
          : 'grey',
    })

the mode icon drawn in blue while the unit is cooling

An indicator coloured by the mode

The third argument every template gets is the climate entity, whatever entity the indicator itself is reading. That is what to reach for here: an indicator on a floor sensor has no hvac_action of its own.

indicators:
  floor:
    source:
      entity: binary_sensor.floor_demand
    unit: '%'
    icon:
      template: "() => 'mdi:heating-coil'"
      style: >
        (value, entity, climate_entity) => ({
          color: climate_entity.state === 'cool' ? 'blue' : 'red',
        })

an indicator icon drawn red while the climate entity is not cooling

A row of preset buttons

One climate entity holds one preset at a time, so a row of preset buttons is a set of switches rather than a list. Each button maps the attribute to on/off and sends the chosen value on press; active decides which one is lit.

type: custom:mini-climate
entity: climate.pass_actuator_3
buttons:
  eco:
    icon: mdi:leaf
    state:
      attribute: preset_mode
      mapper: state => state === 'eco' ? 'on' : 'off'
    active: state => state === 'on'
    toggle_action: >
      (state, entity) => this.call_service('climate', 'set_preset_mode', { entity_id: entity.entity_id, preset_mode: state === 'on' ? 'none' : 'eco' })
  boost:
    icon: mdi:weather-hurricane
    state:
      attribute: preset_mode
      mapper: state => state === 'boost' ? 'on' : 'off'
    active: state => state === 'on'
    toggle_action: >
      (state, entity) => this.call_service('climate', 'set_preset_mode', { entity_id: entity.entity_id, preset_mode: state === 'on' ? 'none' : 'boost' })

Two things worth knowing:

  • the buttons sit behind the toggle, like every other button;
  • after pressing one there is a moment where no button is lit - the old preset goes out before the new one comes in. On a slow connection that is visible; it settles.

To show the selected preset's name as well, add an indicator reading attribute: preset_mode - that is A shortened value's values + mapper, applied to preset_mode.

a row of preset buttons with the active one lit