How to Create a Home Assistant Dashboard

Home Assistant is a really versatile smart home system that allows you to connect all your smart home devices. But to control them, or to get insight into your smart home, you probably want to great a Home Assistant Dashboard.

This is the 3rd article in a mini-series about creating my Smart Home dashboard with Home Assistant. In the first article, I explained how we can use and mount a FireHD tablet as a smart home dashboard. In the second article, we divide into setting up Home Assistant and MQTT. And in this article, we are going to create a Home Assistant Dashboard.

It’s good to know that I am using Homey as my Smart Home controller. Home Assistant is only used to display the interactive dashboard. For the dashboard, it doesn’t matter if HA is your controller or Homey.

Good to know

I am not a Home Assistant expert, I have seen dashboards that have really advanced (and nice) features, but are also complicated to make. My goal for this dashboard was to get insight into my smart home and allow my family members to easily change scenes in the house.

Home Assistant is configured in Yaml files, I have written pretty much everything into the ui-lovelace.yaml file to keep things clear and easy to follow. But it is better to separate it more into separate files with larger configurations.

With HA you can’t simply copy and paste configurations from other users. You really need to write your own configuration files for your environment. In this article, I will try to explain how buttons, functions, and layouts are created and how they interact. So that you can create them for your smart home devices.

I don’t have created any automations or scripts because Homey does pretty much everything automatically. We only need to turn the lights off at night with a single press on the button. But sometimes you want to switch lighting scenes, turning the lights a bit brighter when playing a board game for example, so this is where the tablet comes in.

Linking Homey to Home Assistant

I have linked Homey with Home Assistant through MQTT. This way all devices that I have in Homey are also available as entities in HA. I have created trigger variables in Homey with the help of the app Better Logic (Homey app).

These triggers can then be added as a button (device) in Homey, which is then available in HA as an entity. The button can start a flow in Homey, so this way we can start flows in Homey through Home Assistant.

Creating a Home Assistant Dashboard

I am going to take you step-by-step through the process of making the dashboard. If you have any questions, just drop a comment below. The layout and style of the dashboard are based on the design of Dejan Markovic.

We are going to use different Home Assistant plugins. I will name them where necessary again, but make sure you have installed the following plugins:

  • Weather Card
  • Button-Card
  • Config Template Card
  • Mini Media Player
  • Mini Graph Card
  • Kiosk Mode
  • Button Text Card
  • Card Mod
  • Layout Card
  • State Switch
  • Atomic Calendar Revive

It’s easiest to install the plugins through HACS (Home Assistant Community Store). So make sure you have installed this in your HA installation.

Creating the dashboard Grid

The first step is to create the grid of the dashboard. The grid determines where we can place the different buttons, charts, and other content on our home assistant dashboard. To create our custom grid we are going to need Layout-Card plugin.

Follow the installation instruction to install the plugin into your HA installation. I recommend that you use HACS for this.

I have created a grid of 5 columns and 3 rows. The basis is a cell of 160px width and 160px height. Only the first row is higher and the last column is wider than there rest.

dashboard grid

Open your ui-lovelace.yaml file, using the file editor in Home Assistant (see step 2 in this article) or directly through FTP.

We have our main view defined: home and set the type of the first card to the custom:grid-layout plugin.

# Background color
background: rgb(248,250,251)

# Views
views:
  - title: Home
    id: home
    type: 'custom:grid-layout'
    layout:
      max_cols: 5
      # Define the width of the columns
      grid-template-columns: 160px 160px 160px 160px 280px

      # Define the height of the rows
      grid-template-rows: 220px 160px 160px

I have defined a max of 5 columns, the width of each column, and the height of each row. I have also set the background color to an off-white/light grey color.

Adding buttons to our HA Dashboard

For the buttons, I have used the custom button card plugin which you can also install through HACS. The advantage of the custom button card is that it allows you to create a custom layout for the buttons and use custom templates for this.

We are also going to use the plugin Card Mod. This allows us to use custom styling on the cards.

The dashboard works with cards, so first we need to add a cards section in our view (dashboard) that we just created. Add cards below the layout section:

# Views
views:
  - title: Home
    id: home
    type: 'custom:grid-layout'
    layout:
      max_cols: 5
      # Define the width of the columns
      grid-template-columns: 160px 160px 160px 160px 280px

      # Define the height of the rows
      grid-template-rows: 220px 160px 160px
    # Cards (buttons) section
    cards:

With Yaml it’s important to keep an eye on your indents. They need to be 2 spaces. One more or less and your configuration won’t work.

We are going to start with a simple button that can switch an entity on or off. Add the following to create a button:

Note

YAML files can grow pretty big, to keep the article readable I will only show relevant parts. You can see where I left with the comment sections ( in this case # Cards (buttons) section )
    # Cards (buttons) section
    cards:
    # Simple button
    - type: 'custom:button-card'
      template:
        - base  # Used for styling of the card
        - quick-action  # Additional styling of the card
      entity: light.kitchen # entity to light
      name: Kitchen lights  # Name on the card
      icon:  mdi:lightbulb-outline # Icon on the card
      show_state: false  # Show state of the entity (true of false)
      show_header_toggle: false 
      view_layout:
        grid-column: 1  # column position, first column
        grid-row: 2 # row position, second row
      styles:
        icon:
        - color: rgb(255,213,113) # icon color

As you can see we have positioned the card in column 1 on the second row. If you want to create a card that is two rows width, you can simply set the grid-column to 1 / 3. It will start at position 1 and end before position 3.

For the icons, you can use most icons from materialdesignicons.com.

Button card templates

The button card plugin allows you to create templates for your buttons. This way you can easily style your button cards. I have created two templates, a base for all cards and a quick-action template for the buttons on the second row.

To use the templates add the following code in your ui-lovelace.yaml file, below the background color and above the views that we have created earlier.

# Templates
button_card_templates:
  base:
    styles:
      card:
        - height: 100%          
        - padding: 15px
        - background-color: rgba(255, 255, 255, 1);
      name:
        - color: rgb(24, 24, 24);
        - justify-self: start;
        - font-weight: 400
        - font-family: "LatoWeb"
      state:
        - color: rgb(117,124,136);
        - justify-self: start
        - font-weight: 400
        - font-family: "LatoWeb"
        - font-size: 14px
        - margin-top: -10px
    style: |
      ha-card {
        background-color: rgba(255, 255, 255, 1);
        border: 1px solid rgba(0, 0, 0, 0.05);
        border-radius: 3px;
        box-shadow: none !important;
        transition: width ease-in-out 0.5s,height ease-in-out 0.5s,border ease-in-out 0.2s,transform ease-in-out 0.2s !important;
      }
      #icon {
        width: 25px !important;
        margin-right: 8px;
        margin-top: -20px;
      }
      #container{
        margin: -10px 0;
      }
  quick-action:
    styles:
        card:
        - paddding: 15px;
        grid:
        - grid-template-areas: '"i" "n" "s"'
        - grid-template-columns: 1fr
        - grid-template-rows: 2fr 1fr 1fr
        img_cell:
        - align-self: start
        - text-align: start
        - justify-content: start
        name:
        - font-size: 17px
        - justify-self: start
        - color: #213953;
        - margin-top: 10px;
        state:
        - font-size: 13px
        - align-self: left
        - justify-self: start
        - color: rgb(170,171,175)

# Views

I am using the Lato web font. You will need to download this font here from Google Fonts and save them to your Home Assistant installation folder under /www/fonts

Upload the latofonts.css to the /www folder and create a style.css in the same location with the following content:

body, html {
    font-family: "LatoWeb", sans-serif;
}

Then the last step to use the custom font we need to edit the configuration.yaml file. Make sure that the last two lines are added to the resources list.

Keep in mind that you will need to restart Home Assistant to apply changes that you made in the configuration file.

lovelace:
  mode: yaml
  resources:
    [ { url: /hacsfiles/lovelace-card-mod/card-mod.js,                             type: module },
      { url: /hacsfiles/lovelace-layout-card/layout-card.js,                       type: module },
      { url: /hacsfiles/mini-graph-card/mini-graph-card-bundle.js,                 type: module },
      { url: /hacsfiles/mini-media-player/mini-media-player-bundle.js,             type: module },
      { url: /hacsfiles/atomic-calendar-revive/atomic-calendar-revive.js,          type: module },
      { url: /hacsfiles/weather-card/weather-card.js,                              type: module },
      { url: /hacsfiles/config-template-card/config-template-card.js,              type: module },
      { url: /hacsfiles/button-card/button-card.js,                                type: module },
      { url: /hacsfiles/lovelace-state-switch/state-switch.js,                     type: module },
      { url: /hacsfiles/kiosk-mode/kiosk-mode.js,                                  type: module },
      { url: /local/style.css,                                                     type: css },
      { url: /local/latofonts.css,                                                 type: css }]

If you have added the templates and configured the fonts then you should see a result similar to this:

creating home assistant dashboard

Switching button states

Now as you might notice, the state of the kitchen lights is on, but the icon doesn’t represent the on state. This is where the state switch plugin comes in. It allows you to replace cards based on the state of an entity.

The normal card button is also capable of showing different icons based on the state of the entity, but my buttons need to trigger a different entity (switch) on Homey. So I not only needed to change the layout of the button, but also the functionality.

I have replaced the type of custom-button card with custom:state-switch. For the entity, you will need to use an entity on which you want to change the state. In this case a group of lights.

    cards: 
    # Simple button
    - type: custom:state-switch # Set the card to custom:state-switch type
      entity: light.lampen_woonkamer  # Entity to base state on
      default: off
      view_layout:
        grid-column: 1
        grid-row: 2
      states:
        "on": # When the state of the entity light.lampen_woonkamer = on      
          # BUTTON WHEN LIGHTS ARE ON
          type: 'custom:button-card'  # Show our custom button card
          template:
          - base
          - quick-action
          entity: switch.lampen_uit_knop  # entity to trigger
          name: Room
          icon:  mdi:lightbulb-on # Icon
          show_state: true
          show_header_toggle: false
          state_display: "Turn off all lights"  # I like to display the action of the button
          styles: # Some custom styling
            icon:
            - color: rgb(255,213,113)
            style: |
                .button-card-main{
                    height:148px !important;
                    border: 1px solid rgba(0, 0, 0, 0.05);
                }
                #icon {
                    width: 25px !important;
                    margin-right: 8px;
                    margin-top: -20px;
                }
                #container{
                    margin: -10px 0;
                }
        "off":  # When the state of the entity light.lampen_woonkamer = off
          # BUTTON WHEN LIGHTS ARE OFF
          type: 'custom:button-card'
          template:
          - base
          - quick-action
          entity: switch.lampen_aan_knop
          name: Room
          icon:  mdi:lightbulb-outline
          show_state: true  
          show_header_toggle: false
          state_display: "Turn on all lights"
          styles:
            icon:
            - color: rgb(255,213,113)
            style: |
                .button-card-main{
                    height: 148px !important;
                    border: 1px solid rgba(0, 0, 0, 0.05);
                }
                #icon {
                    width: 25px !important;
                    margin-right: 8px;
                    margin-top: -20px;
                }
                #container{
                    margin: -10px 0;
                }

This state switch is pretty straightforward. If the state of the entity light.lampen_woonkamer is on, display the first button (# BUTTON WHEN LIGHTS ARE ON). Otherwise, display the other custom button card.

Custom button inHome Assistant

Entities are not always on or off, sometimes you want to change the button based on a value of an entity. To achieve this, we can use a state template for this:

    cards: 
    # Simple button
    - type: custom:state-switch # Set the card to custom:state-switch type
      entity: template
      template: >
         {% if state_attr('light.ks_6', 'brightness') != None %} 
           {% if state_attr('light.ks_6', 'brightness') > 45 %} 
             cooking 
           {% else %}
             dimmed
           {% endif %}
         {% else %}
           turnedOff
         {% endif %}
       states:
         "cooking":
           # Add your button card here

Home Assistant is using Jinja2 templating engine, which can be a bit hard to figure out. A good way to test your templates is to use the Developer Tools in Home Assistant. Open the developer tools (left menu, just above get settings icon) and select the Template tab.

Home Assistant Developer tools

Here you can try out your templates and see the results on the right side of the screen (in the grey area)

Creating Chart Cards

On the bottom row of the dashboard, I have 3 charts. These charts give some information about the house, like the temperature, humidity, and solar panels.

To create the charts we are going to use the mini graph chart plugin for Home Assistant. Again, download it through HACS.

        # Humidity
        - type: 'custom:mini-graph-card'  # mini graph card type
          name: Humidity
          icon: 'mdi:water'
          entities:
            - entity: sensor.tado_humidity  # Entity to display
              show_legend: false
              show_state: true
              show_fill: false # Set fill to false for line chart
          show_state: true
          show_header_toggle: true
          view_layout:  # position on the grid
            grid-column: 2
            grid-row: 3
          hours_to_show: 12  # Show only last 12 hours
          points_per_hour: 2 # Show 2 data points per hour
          line_width: 8 # line thickness
          height: 140 # height of the chart
          animate: true # animate on reload of the screen
          upper_bound: 80 # Set upper limit of the chart (height possible value)
          lower_bound: 40 # Set lower limit of the cart
          align_icon: left
          align_header: left
          color_thresholds:  # Colors of the line, based on the value
            - value: 50
              color: "#00B4DB"
            - value: 70
              color: "#0083B0"
          show:
            labels: false
          style: |  # Styling of the card
            ha-card, :host{
                font-family: "LatoWeb";
                background-color: rgba(255, 255, 255, 1) !important;
            }
            ha-card{
                border: 1px solid rgba(0, 0, 0, 0.05) !important;
                border-radius: 3px !important;
                box-shadow: none !important;
                transition: width ease-in-out 0.5s,height ease-in-out 0.5s,border ease-in-out 0.2s,transform ease-in-out 0.2s !important;
            }
            .name > span {
                color: rgb(170,171,175);
                font-weight: 400 !important;
                font-size: 13px !important;
                font-family: "LatoWeb";
                opacity: 1 !important;
                width: 100px !important;
            }
            .icon {
                margin-right: 0px !important;
                color: rgb(170,171,175) !important;
                margin-left: -5px !important;
            }
            .header.flex .icon {
                --mdc-icon-size: 20px;
              }
            .states{
                font-size: 16px !important;
                font-weight: 400;
                color: #213953;
                font-family: "LatoWeb"
            }
            .state__value{
                font-size: 24px !important;
                font-weight: 400;
                color: #213953;
                font-family: "LatoWeb"
            }
            .state__uom{
                color: rgb(117,125,135) !important;
                font-size: 14px !important;
                font-family: "LatoWeb";
                opacity: 1 !important;
            }
            .graph {
                padding: 0 15px !important;
                margin-top: -10px !important;
            }

A couple of settings that are important to display nice graphs is the timeline, amount of data points, and limits:

hours_to_show: 12
points_per_hour: 2
line_width: 8
height: 140
upper_bound: 80
lower_bound: 40

For temperature or humidity, a 12-hour timeline is maybe perfect with two points per hour. But for solar, you might want to use more points per hour.

Also, the upper and lower bounds really help with displaying a nice consistent graph. Take solar panels for example. One day you might generate 4000w at max, but the other day only 500w.

As you can see, without limits, it just looks like we hit the maximum performance today.

Media Player

For the media player, I have first connected Sonos directly to Home Assistant. Simply go to configuration > integrations and add your Sonos (or other media player) to HA.

The media player card is pretty straightforward, add Sonos system as an entity and in my case, I have set the artwork to Cover.

- type: 'custom:mini-media-player'
          noPadding: true
          entity: media_player.sonos  # Your media player entity (Sonos in my case)
          artwork: cover # Display artwork, cover the whole card
          icon: mdi:play
          view_layout: # Position on the grid
            grid-column: 5  
            grid-row: 3
          hide:  # Hide what we don't need
            icon: true
            volume: true
            power: true
            prev: true
            next: true
            source: false
            controls: false
            mute: false
          style: |
            :host{
                font-family: "LatoWeb";
                background-color: rgba(255, 255, 255, 1) !important;
                --mini-media-player-base-color: #213953;
                --mini-media-player-overlay-base-color: #213953;
                --mini-media-player-overlay-accent-color: #213953;
            }
            ha-card{
                height: 100%;
                padding: 15px;
                border: 1px solid rgba(0, 0, 0, 0.05) !important;
                border-radius: 3px !important;
                box-shadow: none !important;
                transition: width ease-in-out 0.5s,height ease-in-out 0.5s,border ease-in-out 0.2s,transform ease-in-out 0.2s !important;
            }
            .ratio {
                padding-bottom: 70%!important;
            }
            .title-controls { 
                width: 100%; 
                height: 100%; 
            }
            ha-card.--has-artwork .cover{
                opacity: 0.3 !important; # Change the artwork opacity
                filter: grayscale(80%);  # Change the artwork color
            }
            ha-icon-button{
                color: #333 !important;
            }
            .mmp__bg{
                -webkit-filter: invert(1);
                filter: invert(1);
            }
            .entity__info__name{
                color: rgb(117,125,135) !important;
                font-weight: 400 !important;
                font-size: 16px !important;
            }

The only change that I made is adding a custom style to blend in the artwork a bit more with the layout of the dashboard. By turning it to 80% grayscale and an opacity of 0.3.

HA Dashboard

Weather Card

With the bottom rows completed, we are now going to start with the biggest item on the home assistant dashboard, the weather card.

For this, I have modified the Weather Card plugin and used icons created by Lai Ming. You can download the custom icons and modified plugin here from my GitHub.

Home Assistant Weather Card

First, install the Weather Card plugin through HACS and then upload the files from my Github repository to the /www/community/weather-card folder in your Home Assistant installation.

I am using the Meteorologisk institutt (Met.no) integration to pull the weather data. But you can also use OpenWeather Map or DarkSky API. Just read the installation guide of the plugin.

        #
        # Weather card
        #
        - type: custom:weather-card
          entity: weather.home # Weather entity
          icons: "/local/community/weather-card/icons/"  # load custom icons
          current: true  # Show current weather
          details: false
          forecast: true
          hourly_forecast: false
          number_of_forecasts: 3 # 3 days for case
          view_layout:
            grid-column: 1 / 5  # Span over the 4 colums
            grid-row: 1
          style: |  # Custom styling
            ha-card, :host{
                font-family: "LatoWeb";
                background-color: rgba(255, 255, 255, 1) !important;
            }
            ha-card{
                border: 1px solid rgba(0, 0, 0, 0.05) !important;
                border-radius: 3px !important;
                box-shadow: none !important;
                transition: width ease-in-out 0.5s,height ease-in-out 0.5s,border ease-in-out 0.2s,transform ease-in-out 0.2s !important;
                grid-template-columns: 1fr 2fr;
                grid-template-rows: 1fr;
                display: grid;
            }
            .current{
                width: 200px;
                margin-bottom: 0 !important;
                grid-template-columns: 1fr 1fr 1fr;
                grid-template-rows: 50px 30px 30px;
                display: grid;
            }
            .current .icon.bigger, .current .temp, .current .tempc {
                position: inherit;
            }
            .currentWeather{
                font-size: 18px !important;
                grid-column-start: 2;
                grid-column-end: 2;
                grid-row-start: 2;
                margin-top: 15px;
                color: rgb(114,114,114);
                text-align: left;
            }
             .current .temp {
                color: #213953;;
                font-size: 40px;
                grid-column-start: 1;
                grid-row-start: 1;
                justify-self: right;
                margin-top: 15px;
                opacity: 0.8
            }
            .current .tempc {
                color: rgb(170,171,175);
                opacity: 0.6;
                font-size: 20px;
                grid-column-start: 2;
                justify-self: left;
                grid-row-start: 1;
                margin-top: 8px !important;               
            }
            .current .icon{
                grid-column-start: 1;
                grid-column-end: 3;
                grid-row-start: 2;
                width: 50px !important;
                height: 50px !important;
                margin-top: 0px !important;
                text-indent: 0 !important;

                text-align: right;
                line-height: 50px;
            }
            .forecast .highTemp{
                color: #213953;
            }
            .forecast .precipitation{
                color: rgb(170,171,175);
            }
            .forecast .dayname{
                color: #213953;
            }

Adding a calendar to the dashboard

The last element (card) that we are going to add is the calendar. For this, we are going to use the Atomic Calendar Revive plugin. You will need to have Google Calendar connected to your Home Assistant installation. To do this you can follow this official guide from HA.

I have added some custom styling to the calendar card and made the scrollbar hidden. So you can scroll through the upcoming events, without showing the scrollbar.

        #
        # Upcoming Events
        #
        - type: custom:atomic-calendar-revive
          entities:
          - entity: calendar.family  # Calendar name in Google
            titleColor: #213953;
            maxEventCount: 5  # Show max 5 events
          language: nl 
          europeanDate: true
          noEventsForNextDaysText: Geen afspraken komende dagen
          noEventsForTodayText: Geen afspraken vandaag
          untilText: tot
          fullDayEventText: Hele dag
          refreshInterval: 300
          dateFormat: LL
          locationLinkColor: rgb(170,171,175);
          showProgressBar: false
          view_layout:  # Position on the grid
            grid-column: 5 / 6
            grid-row: 1
          style: |
            ::-webkit-scrollbar {
                display: none;  # Remove the scrollbar
            }
            ha-card, :host{
                font-family: "LatoWeb";
                background-color: rgba(255, 255, 255, 1) !important;
            }
            ha-card{
                border: 1px solid rgba(0, 0, 0, 0.05) !important;
                border-radius: 3px !important;
                box-shadow: none !important;
                transition: width ease-in-out 0.5s,height ease-in-out 0.5s,border ease-in-out 0.2s,transform ease-in-out 0.2s !important;
            }
            .event-titleRunning {
                color: #213953;
            }
            .cal-card {
                padding: 0;
            }
            .cal-eventContainer{
                padding-top: 15px !important;
            }
            .event-title{
                color: #213953;
            }
            .daywrap {
                border-top: 10px solid rgb(248,250,251);
            }
            .hoursHTML, .relativeTime{
                color: rgb(170,171,175);
            }

Kiosk Mode

The last step is to remove the header and sidebar from Home Assistant when viewing the dashboard on the tablet. For this, we are using the Kiosk mode plugin. After you have installed the plugin, simply add the following code in your ui-lovelace.yaml, just above the views.

kiosk_mode:
  mobile_settings:
    hide_header: true
    hide_sidebar: true
    ignore_entity_settings: true
    custom_width: 1320 # Set this to the max width (or slightly higher) then the width of your tablet

# Views

We only want to remove the header and sidebar on the tablet. So we only apply it on mobile devices, with a screen size below 1320px.

Wrapping Up

Creating your own custom dashboard in Home Assistant can be quite challenging. There is a lot of information and tips on the HA community forums, but most assume you already have some knowledge of HA.

I hope this article helped you with creating your own dashboard in Home Assistant, if you have any questions, just drop a comment below.

12 thoughts on “How to Create a Home Assistant Dashboard”

  1. Hello,

    I want help for a project which I have. Can you send me ean email to discuss it further?
    I want to build a mediaplayer to control shell_command as a volume slider and sources are switches wich i send nc commands to the remote Device.
    I want the player because then i have to create from the ESPHome with esp8266,oled screen and Rotary Encoder a Menu to Control these entities. They told me from the community that with media player will be easier to control it From ESPHome. But i’m new at HA and i’m tryning very much to finish this project.

    I would be grateful if someone could help me!!

  2. This is great. Thanks a lot. Been using the default Lovelace generated UI and this finally helped me getting a nice looking dashboard.

    But I’m now a bit confused. How do Themes play into this? I noticed that the night mode for example does not work on this dashboard. Is there anything that needs to be considered?

  3. Just a quick thanks for this. I finally figured out how to use custom fonts in dashboard themes in large part thanks to your post.

  4. He,

    I really like this dashboard. Its simple and wife friendly! 🙂
    One thing I can’t figure out is the state-switch card. Its more squished together than like the normal light card.

    Can you help me out?

Leave a Comment

18 Shares
Tweet
Pin18
Share
Share