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.

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.
1. # Background color 2. background: rgb(248,250,251) 3. 4. # Views 5. views: 6. - title: Home 7. id: home 8. type: 'custom:grid-layout' 9. layout: 10. max_cols: 5 11. # Define the width of the columns 12. grid-template-columns: 160px 160px 160px 160px 280px 13. 14. # Define the height of the rows 15. 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:
1. # Views 2. views: 3. - title: Home 4. id: home 5. type: 'custom:grid-layout' 6. layout: 7. max_cols: 5 8. # Define the width of the columns 9. grid-template-columns: 160px 160px 160px 160px 280px 10. 11. # Define the height of the rows 12. grid-template-rows: 220px 160px 160px 13. # Cards (buttons) section 14. 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
)
1. # Cards (buttons) section 2. cards: 3. # Simple button 4. - type: 'custom:button-card' 5. template: 6. - base # Used for styling of the card 7. - quick-action # Additional styling of the card 8. entity: light.kitchen # entity to light 9. name: Kitchen lights # Name on the card 10. icon: mdi:lightbulb-outline # Icon on the card 11. show_state: false # Show state of the entity (true of false) 12. show_header_toggle: false 13. view_layout: 14. grid-column: 1 # column position, first column 15. grid-row: 2 # row position, second row 16. styles: 17. icon: 18. - 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.
1. # Templates 2. button_card_templates: 3. base: 4. styles: 5. card: 6. - height: 100% 7. - padding: 15px 8. - background-color: rgba(255, 255, 255, 1); 9. name: 10. - color: rgb(24, 24, 24); 11. - justify-self: start; 12. - font-weight: 400 13. - font-family: "LatoWeb" 14. state: 15. - color: rgb(117,124,136); 16. - justify-self: start 17. - font-weight: 400 18. - font-family: "LatoWeb" 19. - font-size: 14px 20. - margin-top: -10px 21. style: | 22. ha-card { 23. background-color: rgba(255, 255, 255, 1); 24. border: 1px solid rgba(0, 0, 0, 0.05); 25. border-radius: 3px; 26. box-shadow: none !important; 27. 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; 28. } 29. #icon { 30. width: 25px !important; 31. margin-right: 8px; 32. margin-top: -20px; 33. } 34. #container{ 35. margin: -10px 0; 36. } 37. quick-action: 38. styles: 39. card: 40. - paddding: 15px; 41. grid: 42. - grid-template-areas: '"i" "n" "s"' 43. - grid-template-columns: 1fr 44. - grid-template-rows: 2fr 1fr 1fr 45. img_cell: 46. - align-self: start 47. - text-align: start 48. - justify-content: start 49. name: 5o. - font-size: 17px 51. - justify-self: start 52. - color: #213953; 53. - margin-top: 10px; 54. state: 55. - font-size: 13px 56. - align-self: left 57. - justify-self: start 58. - color: rgb(170,171,175) 59. 60. # 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:
1. body, html { 2. font-family: "LatoWeb", sans-serif; 3. }
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.
1. lovelace: 2. mode: yaml 3. resources: 4. [ { url: /hacsfiles/lovelace-card-mod/card-mod.js, 5. type: module }, 6. { url: /hacsfiles/lovelace-layout-card/layout-card.js, 7. type: module }, 8. { url: /hacsfiles/mini-graph-card/mini-graph-card-bundle.js, 9. type: module }, 10. { url: /hacsfiles/mini-media-player/mini-media-player-bundle.js, 11. type: module }, 12. { url: /hacsfiles/atomic-calendar-revive/atomic-calendar-revive.js, 13.type: module }, 14. { url: /hacsfiles/weather-card/weather-card.js, 15.type: module }, 16. { url: /hacsfiles/config-template-card/config-template-card.js, 17.type: module }, 18. { url: /hacsfiles/button-card/button-card.js, 19.type: module }, 20. { url: /hacsfiles/lovelace-state-switch/state-switch.js, 21.type: module }, 22. { url: /hacsfiles/kiosk-mode/kiosk-mode.js, 23.type: module }, 24. { url: /local/style.css, 25.type: css }, 26. { url: /local/latofonts.css, 27.type: css }]
If you have added the templates and configured the fonts then you should see a result similar to this:

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.
1. cards: 2. # Simple button 3. - type: custom:state-switch # Set the card to custom:state-switch type 4. entity: light.lampen_woonkamer # Entity to base state on 5. default: off 6. view_layout: 7. grid-column: 1 8. grid-row: 2 9. states: 10. "on": # When the state of the entity light.lampen_woonkamer = on 11. # BUTTON WHEN LIGHTS ARE ON 12. type: 'custom:button-card' # Show our custom button card 13. template: 14. - base 15. - quick-action 16. entity: switch.lampen_uit_knop # entity to trigger 17. name: Room 18. icon: mdi:lightbulb-on # Icon 19. show_state: true 20. show_header_toggle: false 21. state_display: "Turn off all lights" # I like to display the action of the button 22. styles: # Some custom styling 23. icon: 24. - color: rgb(255,213,113) 25. style: | 26. .button-card-main{ 27. height:148px !important; 28. border: 1px solid rgba(0, 0, 0, 0.05); 29. } 30. #icon { 31. width: 25px !important; 32. margin-right: 8px; 33. margin-top: -20px; 34. } 35. #container{ 36. margin: -10px 0; 37. } 38. "off": # When the state of the entity light.lampen_woonkamer = off 39. # BUTTON WHEN LIGHTS ARE OFF 40. type: 'custom:button-card' 41. template: 42. - base 43. - quick-action 44. entity: switch.lampen_aan_knop 45. name: Room 46. icon: mdi:lightbulb-outline 47. show_state: true 48. show_header_toggle: false 49. state_display: "Turn on all lights" 50. styles: 51. icon: 52. - color: rgb(255,213,113) 53. style: | 54. .button-card-main{ 55. height: 148px !important; 56. border: 1px solid rgba(0, 0, 0, 0.05); 57. } 58. #icon { 59. width: 25px !important; 60. margin-right: 8px; 61. margin-top: -20px; 62. } 63. #container{ 64. margin: -10px 0; 65. }
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.

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:
1. cards: 2. # Simple button 3. - type: custom:state-switch # Set the card to custom:state-switch type 4. entity: template 5. template: > 6. {% if state_attr('light.ks_6', 'brightness') != None %} 7. {% if state_attr('light.ks_6', 'brightness') > 45 %} 8. cooking 9. {% else %} 10. dimmed 11. {% endif %} 12. {% else %} 13. turnedOff 14. {% endif %} 15. states: 16. "cooking": 17. # 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.

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.
1. # Humidity 2. - type: 'custom:mini-graph-card' # mini graph card type 3. name: Humidity 4. icon: 'mdi:water' 5. entities: 6. - entity: sensor.tado_humidity # Entity to display 7. show_legend: false 8. show_state: true 9. show_fill: false # Set fill to false for line chart 10. show_state: true 11. show_header_toggle: true 12. view_layout: # position on the grid 13. grid-column: 2 14. grid-row: 3 15. hours_to_show: 12 # Show only last 12 hours 16. points_per_hour: 2 # Show 2 data points per hour 17. line_width: 8 # line thickness 18. height: 140 # height of the chart 19. animate: true # animate on reload of the screen 20. upper_bound: 80 # Set upper limit of the chart (height possible value) 21. lower_bound: 40 # Set lower limit of the cart 22. align_icon: left 23. align_header: left 24. color_thresholds: # Colors of the line, based on the value 25. - value: 50 26. color: "#00B4DB" 27. - value: 70 28. color: "#0083B0" 29. show: 30. labels: false 31. style: | # Styling of the card 32. ha-card, :host{ 33. font-family: "LatoWeb"; 34. background-color: rgba(255, 255, 255, 1) !important; 35. } 36. ha-card{ 37. border: 1px solid rgba(0, 0, 0, 0.05) !important; 38. border-radius: 3px !important; 39. box-shadow: none !important; 40. 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; 41. } 42. .name > span { 43. color: rgb(170,171,175); 44. font-weight: 400 !important; 45. font-size: 13px !important; 46. font-family: "LatoWeb"; 47. opacity: 1 !important; 48. width: 100px !important; 49. } 50. .icon { 51. margin-right: 0px !important; 52. color: rgb(170,171,175) !important; 53. margin-left: -5px !important; 54. } 55. .header.flex .icon { 56. --mdc-icon-size: 20px; 57. } 58. .states{ 59. font-size: 16px !important; 60. font-weight: 400; 61. color: #213953; 62. font-family: "LatoWeb" 63. } 64. .state__value{ 65. font-size: 24px !important; 66. font-weight: 400; 67. color: #213953; 68. font-family: "LatoWeb" 69. } 70. .state__uom{ 71. color: rgb(117,125,135) !important; 72. font-size: 14px !important; 73. font-family: "LatoWeb"; 74. opacity: 1 !important; 75. } 76. .graph { 77. padding: 0 15px !important; 78. margin-top: -10px !important; 79. }
A couple of settings that are important to display nice graphs is the timeline, amount of data points, and limits:
1. hours_to_show: 12 2. points_per_hour: 2 3. line_width: 8 4. height: 140 5. upper_bound: 80 6. 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.

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.
1. - type: 'custom:mini-media-player' 2. noPadding: true 3. entity: media_player.sonos # Your media player entity (Sonos in my case) 4. artwork: cover # Display artwork, cover the whole card 5. icon: mdi:play 6. view_layout: # Position on the grid 7. grid-column: 5 8. grid-row: 3 9. hide: # Hide what we don't need 10. icon: true 11. volume: true 12. power: true 13. prev: true 14. next: true 15. source: false 16. controls: false 17. mute: false 18. style: | 19. :host{ 20. font-family: "LatoWeb"; 21. background-color: rgba(255, 255, 255, 1) !important; 22. --mini-media-player-base-color: #213953; 23. --mini-media-player-overlay-base-color: #213953; 24. --mini-media-player-overlay-accent-color: #213953; 25. } 26. ha-card{ 27. height: 100%; 28. padding: 15px; 29. border: 1px solid rgba(0, 0, 0, 0.05) !important; 30. border-radius: 3px !important; 31. box-shadow: none !important; 32. 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; 33. } 34. .ratio { 35. padding-bottom: 70%!important; 36. } 37. .title-controls { 38. width: 100%; 39. height: 100%; 40. } 41. ha-card.--has-artwork .cover{ 42. opacity: 0.3 !important; # Change the artwork opacity 43. filter: grayscale(80%); # Change the artwork color 44. } 45. ha-icon-button{ 46. color: #333 !important; 47. } 48. .mmp__bg{ 49. -webkit-filter: invert(1); 50. filter: invert(1); 51. } 52. .entity__info__name{ 53. color: rgb(117,125,135) !important; 54. font-weight: 400 !important; 55. font-size: 16px !important; 56. }
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.

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.

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.
1. # 2. # Weather card 3. # 4. - type: custom:weather-card 5. entity: weather.home # Weather entity 6. icons: "/local/community/weather-card/icons/" # load custom icons 7. current: true # Show current weather 8. details: false 9. forecast: true 10. hourly_forecast: false 11. number_of_forecasts: 3 # 3 days for case 12. view_layout: 13. grid-column: 1 / 5 # Span over the 4 colums 14. grid-row: 1 15. style: | # Custom styling 16. ha-card, :host{ 17. font-family: "LatoWeb"; 18. background-color: rgba(255, 255, 255, 1) !important; 19. } 20. ha-card{ 21. border: 1px solid rgba(0, 0, 0, 0.05) !important; 22. border-radius: 3px !important; 23. box-shadow: none !important; 24. 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; 25. grid-template-columns: 1fr 2fr; 26. grid-template-rows: 1fr; 27. display: grid; 28. } 29. .current{ 30. width: 200px; 31. margin-bottom: 0 !important; 32. grid-template-columns: 1fr 1fr 1fr; 33. grid-template-rows: 50px 30px 30px; 34. display: grid; 35. } 36. .current .icon.bigger, .current .temp, .current .tempc { 37. position: inherit; 38. } 39. .currentWeather{ 40. font-size: 18px !important; 41. grid-column-start: 2; 42. grid-column-end: 2; 43. grid-row-start: 2; 44. margin-top: 15px; 45. color: rgb(114,114,114); 46. text-align: left; 47. } 48. .current .temp { 49. color: #213953;; 50. font-size: 40px; 51. grid-column-start: 1; 52. grid-row-start: 1; 53. justify-self: right; 54. margin-top: 15px; 55. opacity: 0.8 56. } 57. .current .tempc { 58. color: rgb(170,171,175); 59. opacity: 0.6; 60. font-size: 20px; 61. grid-column-start: 2; 62. justify-self: left; 63. grid-row-start: 1; 64. margin-top: 8px !important; 65. } 66. .current .icon{ 67. grid-column-start: 1; 68. grid-column-end: 3; 69. grid-row-start: 2; 70. width: 50px !important; 71. height: 50px !important; 72. margin-top: 0px !important; 73. text-indent: 0 !important; 74. 75. text-align: right; 76. line-height: 50px; 77. } 78. .forecast .highTemp{ 79. color: #213953; 80. } 81. .forecast .precipitation{ 82. color: rgb(170,171,175); 83. } 84. .forecast .dayname{ 85. color: #213953; 86. }
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.
1. # 2. # Upcoming Events 3. # 4. - type: custom:atomic-calendar-revive 5. entities: 6. - entity: calendar.family # Calendar name in Google 7. titleColor: #213953; 8. maxEventCount: 5 # Show max 5 events 9. language: nl 10. europeanDate: true 11. noEventsForNextDaysText: Geen afspraken komende dagen 12. noEventsForTodayText: Geen afspraken vandaag 13. untilText: tot 14. fullDayEventText: Hele dag 15. refreshInterval: 300 16. dateFormat: LL 17. locationLinkColor: rgb(170,171,175); 18. showProgressBar: false 19. view_layout: # Position on the grid 20. grid-column: 5 / 6 21. grid-row: 1 22. style: | 23. ::-webkit-scrollbar { 24. display: none; # Remove the scrollbar 25. } 26. ha-card, :host{ 27. font-family: "LatoWeb"; 28. background-color: rgba(255, 255, 255, 1) !importan.t; 29. } 30. ha-card{ 31. border: 1px solid rgba(0, 0, 0, 0.05) !important; 32. border-radius: 3px !important; 33. box-shadow: none !important; 34. 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; 35. } 36. .event-titleRunning { 37. color: #213953; 38. } 39. .cal-card { 40. padding: 0; 41. } 42. .cal-eventContainer{ 43. padding-top: 15px !important; 44. } 45. .event-title{ 46. color: #213953; 47. } 48. .daywrap { 49. border-top: 10px solid rgb(248,250,251); 50. } 51. .hoursHTML, .relativeTime{ 52. color: rgb(170,171,175); 53. }
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.
1. kiosk_mode: 2. mobile_settings: 3. hide_header: true 4. hide_sidebar: true 5. ignore_entity_settings: true 6. custom_width: 1320 # Set this to the max width (or slightly higher) then the width of your tablet 7. 8. # 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.