Google Calendar custom widget

The Google Calendar integration in Home Assistant is only the next single event in each subscribed calendar, which is fine for automation, but not much use for an on-wall calendar of upcoming events. I’ve seen various solutions suggested such as putting it in an iframe, but that’s unstylable and so pretty ugly.

Instead, I made a custom widget to display my calendar (shown here below a clock widget):

Features are:

  • Any number of subscribed Google Calendars
  • All-day and timed events
  • Scrolling area (that ugly scrollbar isn’t there on a mobile device)
  • Configurable colors/css for each calendar and for past vs upcoming events
  • Configurable update interval
  • Configurable number of days forward
  • Tap events to see details (end time, description, location)

Note that you need to set up your own Google Calendar API key and ClientID. Go to the Credentials Section of the Google API Console, and create an APIKEY and an OAuth Client ID for a Web Application, then ensure that the Authorised JavaScript Origins includes your HASSIO, noting that it can’t be an IP address or hostname (but note that you can use to make an IP address look like a hostname).

Also note that the Google Calendar API complains if it considers your web browsers is a “WebView” and will not let you authorized. If you’re using such a browser (and trust it), you’ll probably find it has the ability to use different User Agent strings. The Fully Kiosk Browser that I use for displaying this calendar needs this for example.



very nice.

i think you would please people if you would share it.
2 options:

  1. paste the code from the files here and let people copy/paste
  2. create a github and let people download the files.

Interested in the code as well

Also interested.

I’m in the process of cleaning up my config so it can be published.


I have posted the code to:

I’m very keen to clean this up into a form acceptable for contribution, if that’s appropriate, but I’m also fully aware that my JavaScript is very rusty, to say nothing of my css, html, and indeed, knowledge of, AppDaemon, and HADashboard, which I’ve been using (and loving) for all of a month.

Issues I see:

  • How am I supposed to integrate with skins?
  • I’ve had to hard-code 400px in the css, I couldn’t work out how to make a scrolling area that grew with widget size.
  • It sucks that everyone has to make their own API KEY etc.
  • Is this the right pattern: (function (self, a, b) { return function(a,b){ DoStuff(self, a, b) }}(self)?

you get a scrollbar when the inner html part is bigger then the outer part.
now that you have set it to 400 you wouldnt get a scrollbar when the widget is bigger then 400 px
so i think it would be better to set it to 101%. in that case its always bigger.

How am I supposed to integrate with skins?

in your gcal.yaml file you now connect like this:

  icon_on: $group_icon_on
  icon_off: $group_icon_off
static_icons: []
  title_style: $group_title_style
  title2_style: $group_title2_style
  slider_style: $group_slider_style
  widget_style: $group_widget_style
  icon_style_active: $group_icon_style_active
  icon_style_inactive: $group_icon_style_inactive

on the left are variables you use in the javascript.
on the right are variables that are set in the skins variables.yaml, and those can be overwritten in the dashboard.

so now you pick up the style from the group widget.
you need to change group to gcal and then create those variables in the variables.yaml from the skin you use.

It sucks that everyone has to make their own API KEY etc.

that cant be helped. you need a google api key and that is connected to you account.

Is this the right pattern: (function (self, a, b) { return function(a,b){ DoStuff(self, a, b) }}(self)?

i am sorry but i dont understand your question here.

Doesn’t work - the surrounding widget just grows when I tried this. It seems HADashboard doesn’t force fixed sizes on the widgets (which would seem to be a bug).

Ah, so this is what the docs mean by saying every widget needs a corresponding patch for all the skins. I’ll cross that bridge then if I end up contributing it as a patch. For now, I just want it to be something people can independently download and install, and the “group” widget css seems fine for that.

Not to your google account. I could publish the API_KEY and CLIENTID I’m using and let everyone else use it - it can sign in to whatever account the user chooses (and has authorization to). The problem is, if it becomes too popular, or if someone takes those and abuses them, then it’ll hit quota limits and stop working for everyone. One solution would be to collect them from an online source that can be updated if the keys become abused, and somehow funded if they become too popular.

Hmm, perhaps that means it’s not the right pattern. Frequently I needed to pass a function to a Google API call, but since I wanted access to “self” in that function, I used that quoted pattern to generate such a function. I’ve never used OO in JS and the information in the HADashboard custom widget docs didn’t really explain it, just said “use self everywhere”.

it would be almost impossible.
a widget has sub html and to force everything to stay inside the widget size, you would need to compare every css command with the widget max size.
and all sizes are customisable, so that would really be impossible to check.
i know you should also be able to set the scrollbar with css, but i dont know the commands for that.

arent the api key and clientid connected to the autorisation?
i know that when i use the python api a file is created that is connected to the authorisation (or i really misunderstood that)

about your pattern: i am just not familair enough with js to say if it is wrong or right what you do there.
i always think: if it works it must be right :wink:

Hi Waz,

Widget looks, great !

Thing is I’ve been trying to setup it up in my dashboard and wasn’t able to get it to work.

I followed the steps here in order to create the apikey and clientid. I also added to the oauth configuration in the Authorized Javascript Origins section.

I also tried being signed in and out of my google account in case it made any difference, but the only thing I see is the widget saying “Login to see calendar…” with three buttons (Back, Signout, Authorize), and the only one that works is Back.

If I go to the console I see a 400 error when it tries to access the following URL:

Error is:

{“error”:{“errors”:[{“domain”:“usageLimits”,“reason”:“keyInvalid”,“message”:“Bad Request”}],“code”:400,“message”:“Bad Request”}}

Note: MY_KEY is the same that I setup on example.dash in the field apikey and is the same key that works without any problems in HA integration.

I believe this maybe just a configuration issue but I am not getting to the root of it.

Thoughts / Tips ?


I tried to install this widget, but am getting a

500 Internal Server Error
Server got itself in trouble

when loading the config.

My calendar’s are loaded fine in HA, but not sure what is up with the HADashboard side. My config is,

    widget_type: gcal
    colorpast: "#555555"
    calendars:[email protected]:
        color: "#dddddd"
    updateinterval: 120000
    apikey: !secret google_clientid
    clientid: !secret google_clientsecret
    days: 7

I have just changed it to the holidays calendar to try it out.

Copied the gcal.yaml to the custom_widgets folder, and then the basecalendar folder with the css js and html files inside it too.

Any help would be much appreciated.

in most cases that is a yaml problem.
for example the use of a tab in stead of spaces, or a : in a string

Thank you for the reply Rene, I am still all a bit new to this, and trying my best to work my way through without bothering people too much. It got late, and I got lost last night in a world of code. Was just messing around with it again today when you replied. I had just started using multi-dashboard navigation, and it was that, that was causing a problem. I got past that error now, and have now come across this one,

Excuse the messy navigation, just using this as a test to get it setup.

I can’t click on Authorise, it doesn’t do anything, neither does sign out, just back works, but it just takes me to a screen with just the Authorise on it, which I still cant click on.

Sorry to bother you, but any clues. Have I missed something obvious again.

its not my widget, but that to me seems to be an authorisation problem.
and with that i see 2 things:

  1. you did set your apikey and clientid in secrets. it might be that that isnt working out as expected, so to test you better first set it in the dashboard, until you know everything is working
  2. apikey or clientid is wrong or wrongly interpreted by the yaml. sometimes placing things between quotes can help.

also it can be that the browser you use doesnt support everything (i always advice to test with google chrome, it seems to be working with all dashboard parts)

i looked at the code and there is some console logging, so in google chrome you can look at the console for more info what is happening ( CTRL + SHIFT + I )

The widget logs (blathers) to the console, so if you browse on a desktop, you can open the debug javascript console (Shift-Ctrl-K in Chrome) and see what it’s saying.

Note that you’ll need to allow your HASSIO device’s URL (NOT ip address, NOT just the hostname) in your Google API dashboard where you got the credentials. I’ll add more to the first post.

That won’t work. The Restrictions insist on a hostname. You could use instead though.

Hi Waz,

I added to to the authorized Javascript origins and it still gives the same error:

{“error”:{“errors”:[{“domain”:“usageLimits”,“reason”:“keyInvalid”,“message”:“Bad Request”}],“code”:400,“message”:“Bad Request”}}

request is the same:

I get the same behavior as @Cee above


The HA Google Calendar integration documentation gives instructions for creating an “Other” credentials. I’m not certain that’s the same as required for this widget. I used the “Web Application” credentials, where the APIKEY is a value of the form [AIza… 20 base64 chars]-[10 base64 chars] and the ClientID is a string of the form [base 10 number]-[base64 stuff]

Yes, i have both: “Other” and “Web Application” and doesn’t work with either of them. Both gives me the same error.

And also as said by @Cee the Authorize or Sign Out buttons don’t work.

Thanks again,

What does the Javascript Console show?