šŸ“… Calendar Add-On + some calendar designs

Hi!

I have a question and a request if someone can help me!

Let me first clarify that I have no programming knowledge and I understand yaml somewhat! I would like the data from the google calendar add-on as shown in the image:

Inserted into the SVG text field, which is made on the floor plan:

Previously, I had done it with the help of add-on cards, but the display on all devices (PC, tablet, phone) gave me problems.

Now the view works satisfactorily for me on all devices, after I changed the display to just the SVG file (I donā€™t use any other cards except the floor plan card)!

Since I donā€™t have programming skills, I donā€™t know how to solve the issue of giving me selected (not only my events! Also data such as the next F1 race, Moto GP, waste collection, national holidays, etc.) data from the google calendar add-on!

Can I help myself with this add-on?

Link to my floor plan view and zip of both card views : My floor plan example: Ā· ExperienceLovelace/ha-floorplan Ā· Discussion #411 Ā· GitHub

I donā€™t think youā€™re in the right thread, as your question is more about how to set up lovelace cards than using my calendar add-on. It also looks like youā€™re not using the add-on right now but the standard calendar integration. Regardless of what calendar integration method you use your issue is about how to get the data displayed in a certain card.

I suggest you ask around in threads about the floorplan card. One tip I can give is to look at custom button card too, you could create different zones/templates inside a custom button card, one of which could be the svg floorplan. Thereā€™s an extensive thread about custom button card and it has rich documentation.

Hi.
Thanks for the reply.

I use the google calendar add-on, which works with any calendar card without a problem and in the settings (day, week, month) and just the way I want it.
As I have already written, it presents a problem (for me, because I somehow solved it with a grid card) of the display on the mobile phone, because it did not want to display nicely on the screen.

When I tried to use only the SVG file, everything was displayed nicely even on a mobile phone. Otherwise, I struggled at first with the placement of the weather card in the SVG file, but somehow I succeeded. The display of persons or data was also not a problem.

The only thing I donā€™t know is to use javascript code. Unless I find an example and then start trying/fixing it, as I did in the case of the code below, which I can use for several calendars but only to display the first event.

{{as_timestamp(strptime(state_attr("calendar.f1","start_time"),"%Y-%m-%d %H:%M:%S")) | timestamp_custom("%d %B %Y %H:%M")}}-{{as_timestamp(strptime(state_attr("calendar.f1","end_time"),"%Y-%m-%d %H: %M:%S")) | timestamp_custom("%H:%M")}} {{state_attr("calendar.f1","message")}}, {{state_attr("calendar.f1","location")}} {{state_attr(" calendar.f1","description")}} {{state_attr("calendar.f1","summary")}}

Which shows me only the first event in the calendar/calendars, which can be several months apart in time, but in the same calendar there can be several events on the same day, and until the first one passes, it doesnā€™t show me the second one.

An example is this weekend when there are several events in Formula1 and Moto GP in one day and it shows me only the first one that will be on the line and not all of them for this weekend or say within 7 days as you can specify in the add-on card.

I couldnā€™t find anywhere that next.state_attr or something like that could be used to get more events.

I have the following configuration:

locale: it-IT
timeZone: ā€œā€
fetchDays: 365
fetchDaysPast: 7
fetchCRON: ā€œ30ā€
calendarList:

  • calName: famiglia
    calType: google
    username: username
    password: password
    caldavUrl: http://something (only for caldav)
    calId: [email protected]
    googleServiceAccountKeyfile: >-
    xxxxxxxxx.json

Anyway with button-card copied from yours, I have the following in dashboard:

Screenshot 2024-04-22 000531

Reading the log I get the following:

s6-rc: info: service base-addon-banner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service base-addon-log-level: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service base-addon-log-level successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
System locale: en-US
Luxon locale set to: it-IT
System timeZone: Europe/Rome
Number of calendars: 1
/app/node_modules/node-cron/src/convert-expression/month-names-conversion.js:10
            expression = expression.replace(new RegExp(items[i], 'gi'), parseInt(i, 10) + 1);
                                    ^

TypeError: Cannot read properties of undefined (reading 'replace')
    at convertMonthName (/app/node_modules/node-cron/src/convert-expression/month-names-conversion.js:10:37)
    at interprete (/app/node_modules/node-cron/src/convert-expression/month-names-conversion.js:16:27)
    at interprete (/app/node_modules/node-cron/src/convert-expression/index.js:54:26)
    at validate (/app/node_modules/node-cron/src/pattern-validation.js:117:32)
    at new TimeMatcher (/app/node_modules/node-cron/src/time-matcher.js:14:9)
    at new Scheduler (/app/node_modules/node-cron/src/scheduler.js:9:28)
    at new ScheduledTask (/app/node_modules/node-cron/src/scheduled-task.js:22:27)
    at createTask (/app/node_modules/node-cron/src/node-cron.js:36:12)
    at Object.schedule (/app/node_modules/node-cron/src/node-cron.js:25:18)
    at Object.<anonymous> (/app/index.js:493:6)

Node.js v18.19.1
s6-rc: info: service legacy-services: stopping
s6-rc: info: service legacy-services successfully stopped
s6-rc: info: service legacy-cont-init: stopping
s6-rc: info: service legacy-cont-init successfully stopped
s6-rc: info: service fix-attrs: stopping
s6-rc: info: service base-addon-log-level: stopping
s6-rc: info: service fix-attrs successfully stopped
s6-rc: info: service base-addon-log-level successfully stopped
s6-rc: info: service base-addon-banner: stopping
s6-rc: info: service base-addon-banner successfully stopped
s6-rc: info: service s6rc-oneshot-runner: stopping
s6-rc: info: service s6rc-oneshot-runner successfully stopped

Your value in fetchCRON is not a valid cron pattern. The error message is one from node-cron as you can see, which could have given you a clue. I have linked to a cron pattern generator in the docs, just use that tool to get a valid pattern (also have a look at the examples via the examples-link on that website).

thanks you for your support, I fixed all the errors coming from the addon and now it works very well.
Now I think I have some issue from the button-card code in the dashboard.
I used the hass-addon-calendar/card-examples/onePersonNext4.yaml example but I get this card:

Which is the issue now?
I read previous posts and in the solution you suggested I have both fixed, that is card-mod (that I installed) and the link to the image (that I put into /config/www)

config\www is the right folder for the image. I guess thereā€™s a mistake in the img path in your card code still. It should be somehting like <img src="/local/filename.png"/>

And the blown up icons suggest that you donā€™t have card-mod installed which is used for the styling. If you have never used card-mod, take some time to read its documentation: GitHub - thomasloven/lovelace-card-mod: šŸ”¹ Add CSS styles to (almost) any lovelace card

Well, I solved about image, now I can see it in the card.
But card-mod seems to be installed:

But it doesnā€™t work, even if I followed the configuration steps.

this is my button card code. does this work.

type: custom:button-card
name: Simon
show_icon: false
show_name: false
entity: sensor.simoncal
custom_fields:
  person: '[[[ return `` ]]]'
  calendar: |
    [[[ let calSnippet = '';
    for (let i = 0; i < entity.state; i++) {
      if (i > 3) {};
      if (i <= 3 ) {
      let start_month = entity.attributes.data[i].startMonth;
      let start_day = entity.attributes.data[i].startDay;
      let start_time = entity.attributes.data[i].startTime;
      let end_month = entity.attributes.data[i].endMonth;
      let end_day = entity.attributes.data[i].endDay;
      let end_time = entity.attributes.data[i].endTime;
      let time = start_time;
      let wholeDay = entity.attributes.data[i].wholeDay;
      if (end_day != null && start_day !== end_day) {time = "meerdaags, tot " + end_day + " " + end_month};
      if (wholeDay === true) {time = "all day"};
      let event = entity.attributes.data[i].summary;
      let location = entity.attributes.data[i].location;
      if (location === "" || location === undefined) {location = "-"}

    calSnippet += 
      `<table><tr>
          <td class="date month">${start_month}</td><td class="event"><div class="event-title">${event}</div></td>
        </tr>
        <tr>
          <td class="date day">${start_day}</td><td class="event"><span class="location"><ha-icon class="icon" icon="mdi:map-marker"></ha-icon>${location}</span><span class="time"><ha-icon class="icon" icon="mdi:clock-outline"></ha-icon>${time}</span></td>
        </tr></table>`
        }
    }
      
    return calSnippet; ]]]
styles:
  card:
    - color: null
    - margin-top: 1em
    - box-shadow: none
  grid:
    - grid-template-areas: '"person" "calendar"'
    - grid-template-columns: 1fr
    - grid-template-rows: 1fr min-content
  person:
    - align-self: middle
card_mod:
  style: |
    img {
      border-radius: 50%;
      width: 120px;
      margin-bottom: 1em;
    }
    .icon {
      margin-right: 5%;
      text-align: center;
      float: left;
      width: 16px;
    }
    table {
      margin-left: 10px;
      box-sizing: border-box;
      border-spacing: 0;
      margin-bottom: 1.25em;
      width: 100%;
    }
    td {
      white-space: -o-pre-wrap; 
      word-wrap: break-word;
      white-space: pre-wrap; 
      white-space: -moz-pre-wrap; 
      white-space: -pre-wrap; 
    }
    .date {
      border-right: 2px solid #008000;
      width: 20%;
      text-align: center;
    }
    .event, .task {
      padding-left: 10px;
      width: 80%;
    }
    .month {
      text-transform: uppercase;
      vertical-align: bottom;
    }
    .day {
      font-size: 1.8em;
      vertical-align: top;
    }
    .event-title {
      margin-top: 0;
      font-size: 1.1em;
      font-weight: 400;
      text-align: left;
      vertical-align: top;
      word-wrap: break-word;
      overflow-wrap: break-word;
    }
    .time, .location {
      display: block;
      text-align: left;
      font-size: 0.9em;
      padding-top: 5px;
    }
    .time {
      padding-bottom: 1em;
    }
1 Like

Ok, thank you Frosty.
I compared your code with developer one and I missed ā€œcard_mod:ā€ at row 51.
The example onePersonNext4.yaml lacks this reference. If you add ā€œcard_mod:ā€ between ā€œperson:ā€ entry and ā€œstyle:ā€ entry at that row, it works.

Now I can enjoy with characters dimensions and colors etc. etc.
Thank you again!!

2 Likes

Thatā€™s due to my example code being old and card-mod having changed its syntax since a recent release.

1 Like

Iā€™m trying to use in a button-card the other script also, the family planner, I guess if thereā€™s something to change due to card-mod new version.
For example, using this part of the code:

let calFabioState = states['sensor.fabio'].state;
      let calFabioData = states['sensor.fabio'].attributes.data;
      for (let i = 0; i < calFabioState; i++) {
        if (calFabioData[i].start_month == currentMonth) {
          let day = calFabioData[i].start_day;
          let summary = calFabioData[i].summary.replace(/'/g,'&apos;');
          let label = '';
          let startTime = calFabioData[i].start_time;
          if (calFabioData[i].whole_day) {startTime = 'Tutto il giorno';}
          if (calFabioData[i].label !== undefined) {label = '<span class="label">'+calFabioData[i].label+'</span>';}
          
          calendar = calendar.replace(`<div style="grid-area: c1_${day}" id="c1_${day}" class="event"></div>`, `<div style="grid-area: c1_${day}" id="c1_${day}" class="event"><span>${startTime} - ${summary}</span>${label}</div>`);
        }
      }

I canā€™t see the calendar events in the grid, i.e.:

PS: please note that Iā€™m changing the calendar grid as I like :wink:

I really havenā€™t put any effort into that family planner design since my original post in this thread. Probably the entity atributes donā€™t match any more.
Iā€™d advise you to look at this thread instead, that user has made a really beautiful family calendar solution.

1 Like

I cant figure out whats going wrongā€¦ as far as I can tell no sensors were created


Add-on: Hass Calendar Addon
Addon to consume caldav and google calendars and make calendar events available as sensordata in Home Assistant.

Add-on version: 0.500
You are running the latest version of this add-on.
System: Home Assistant OS 12.3 (amd64 / qemux86-64)
Home Assistant Core: 2024.5.4
Home Assistant Supervisor: 2024.05.1

Please, share the above information when looking for help
or support in, e.g., GitHub, forums or the Discord chat.

s6-rc: info: service base-addon-banner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service base-addon-log-level: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service base-addon-log-level successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
s6-rc: info: service legacy-services successfully started
System locale: en-US
Luxon locale set to: nl-BE
System timeZone: Europe/Amsterdam
Luxon timezone set to: Europe/Brussels
Number of calendars: 1
No previously stored events found
Error in getEvents: Error: ENOENT: no such file or directory, open ā€˜/config/366492799286-nmj0cqgp0umpe72luh596k90fgimgv3g.apps.googleusercontent.comā€™
at Object.openSync (node:fs:596:3)
at Object.readFileSync (node:fs:464:35)
at /app/index.js:320:37
at new Promise ()
at getEvents (/app/index.js:65:10)
at Task._execution (/app/index.js:495:27)
at Task.execute (/app/node_modules/node-cron/src/task.js:17:25)
at ScheduledTask.now (/app/node_modules/node-cron/src/scheduled-task.js:38:33)
at Scheduler. (/app/node_modules/node-cron/src/scheduled-task.js:25:18)
at Scheduler.emit (node:events:517:28) {
errno: -2,
syscall: ā€˜openā€™,
code: ā€˜ENOENTā€™,
path: ā€˜/config/366492799286-nmj0cqgp0umpe72luh596k90fgimgv3g.apps.googleusercontent.comā€™
}
Error posting events to sensor(s) at: Sat May 18 2024 22:30:00 GMT+0200 (Central European Summer Time)
Error: ENOENT: no such file or directory, open ā€˜/config/366492799286-nmj0cqgp0umpe72luh596k90fgimgv3g.apps.googleusercontent.comā€™
at Object.openSync (node:fs:596:3)
at Object.readFileSync (node:fs:464:35)
at /app/index.js:320:37
at new Promise ()
at getEvents (/app/index.js:65:10)
at Task._execution (/app/index.js:495:27)
at Task.execute (/app/node_modules/node-cron/src/task.js:17:25)
at ScheduledTask.now (/app/node_modules/node-cron/src/scheduled-task.js:38:33)
at Scheduler. (/app/node_modules/node-cron/src/scheduled-task.js:25:18)
at Scheduler.emit (node:events:517:28) {
errno: -2,
syscall: ā€˜openā€™,
code: ā€˜ENOENTā€™,
path: ā€˜/config/366492799286-nmj0cqgp0umpe72luh596k90fgimgv3g.apps.googleusercontent.comā€™
}

The error is quite readable here:

So youā€™re trying to work with a google calendar but have made an error with the service account keyfile. That filename looks odd and should be ending in .json.
And it also looks like you didnā€™t place the file in the right folder. Regarding the location I did notice on my own system that Home Assistant added a prefix to the addon config folder, so watch out for that.

Please read all instructions in the docs and the linked tutorials regarding obtaining and configuring the keyfile carefully and you should be able to get it working then.

Any idea how to share calendar with service account? Because when I try to share calendar it requeires other invited email to accept invite.

I just tested and for me the sharing option under google calendar settings still looks and behaves the same as in the screenshot in this post. I didnā€™t get the invitation expires text when I added another e-mail address.

I juat figured it out. The problem was I was trying to share family calendar which must be accepted by the invited side. Switched to non family calendar and it works.

Thanks for reply

Are you able to add events with your add-on?
My biggest gripe with the CalDav integration is I canā€™t add events on the calendar.

No, event creation is not supported.
You could probably create a REST command to achieve this. Did some quick research: this is the PUT method for caldav to create events: Calendaring Extensions to WebDAV (CalDAV).
Authentication is probably basicauth with your username/password

1 Like