[APP][Pro] IcalCalendar

I have released a new version to test (it needs review by Athom before its live on the App Store).

You can try the test version here: IcalCalendar | Homey

Tested with this option.

msedge_rskhiIzTQy

Now it doesnā€™t match the event ā€œGarageā€ anymore, and it does match the event ā€œRAā€ā€™ so this is perfect!

You have my eternal gratitude! show me the way to donate and Iā€™ll buy you a couple of beers!

1 Like

Thats awesome :+1:

If you want to donate (which iā€™ll really appreciate), you can do so from: GitHub - thanks

Hello everybody, I just installed the app an connected it with my gmail calendar.
If I import the events, all events I created direct in the calendar are imported.
Is there a possibility to also import shown events like birthdays, comming from the phone contacts, and holdays, comming from a conneted holiday calendar? They are all displayd in the gmail calendar.
Otherwise I have to create them all again in the gmail calendar.

Thereā€™s no other way to import events than importing them via a public secret iCal link. If these birthdays and holidays isnā€™t in such a shareable calendar, IcalCalendar canā€™t import them!

Happy to donate for your time, enjoy the beers! (or whatever you like to drink :slight_smile: )

1 Like

I dont know how it is managed internally. I synchronised my laptop with my mobile and the mobwith my tablet. On the tablet I also integrated another calendar with holidays. Everything is merged on the tablet in one calendar, but imported are only the events wich i make direkt in the gmail calendar on the tablet.
If I canā€™t import all of that, Iā€™m sorry, then your app doesnā€™t work for me.
I appreciate your work, but it doesnā€™t fit my needs.

Hi guys,

First off, thanks Runely for your awesome work with this great app.

I want to create a morning routine flow thatā€™ll tell me my upcoming lectures when activted (via the cast to text on google-app). The problem currently is that there is a character limit at 200 words on the cast to text app. I then tried to do the same but via notification to the Homey app, and there seems to be a limit there as well. Would it be possible to segmentize my events for the given day so that I in some way can divide them in several ā€œthenā€-cards? Maybe via IDs that is assigned via a loop to all events the given day or similar?

Thanks once again!

All the best

That sounds like a job for HomeyScript

Also, this must be a limit on the app (as you said) and not in homey.

I use Sonos to say my events for the day and it has a higher limit

The birthday calendar available on Gmail has no iCal link possibility. Gmail only allows to integrate that calendar through a calendar view. So unless Gmail changes that behavior, IcalCalendar canā€™t import that calendar Iā€™m afraid.

The holiday calendar on Gmail however does have a publicly availble iCal link and can be imported to IcalCalendar.

Your laptop, mobile and/or tablet is probably merging all these calendars for you through an API. IcalCalendar just reads publicly available .ics files.

Thank you for your answer. I thought it is like that. But to transfr all birthdays from the mobile contacts and other merged events to gmail calendar by hand is too much effort for the moment.
Keep on your good work. Maybe I do that if I have more free time.

I made a HomeyScript that can be used to divide the Todays events, title and time and call a flow to speak out a tag divided up into 200 character chunks!

This approach needs to be done in mulitple steps

  1. Make sure you have installed HomeyScript on your Homey
  2. Create an advanced flow, with a run button and a HomeyScript flow card Run code with Argument
    1. Make sure the trigger button is connected to the flow card
    2. For the argument, remove the MyArg text and insert the tag Todays events, title and time tag
    3. For the code, insert the code found in the HomeyScript code section below and change the tagName if you want to name it something else.
    4. Run the code once by clicking the blue run button in the code window, this is to create the tag so you can use it in the next section. The output will show that the flow wasnā€™t found, but this is OK and will be fixed later.
    5. Save the advanced flow
  3. Create a flow like this one, or use a similar one: Shared Flow | Homey
    1. For the ?, insert the tag created in step 2
    2. If you donā€™t have Sonos, but use Google TTS or something else, change the flow card
    3. Save the flow
    4. Copy the name you gave this flow
  4. Open the advanced flow created in step 2
    1. Open the code section
    2. Insert the flow name created in step 3 in the flowName variable
    3. Run the code again, this time (if the flow is found) it will output the id of the flow. Copy the id
    4. Insert the copied id in the flowId variable
    5. Comment out the section called Comment out this code after youā€™ve found the id of the flow to trigger
    6. Uncomment the section called Uncomment this code to parse, divide and trigger the speak flow
    7. Run the code by clicking the blue run button to test that things is working
    8. Save the flow
  5. Call the advanced flow (created in step 2) from your morning routine flow to have it say Todays events, title and time divided into 200 character chunks!

HomeyScript code

// input the tag 'Todays events, title and time' in the Arguments section above
var tokenValue = args[0];
// how many characters to save in tagName each trip
var charLength = 200;
// time to wait between each flow call (milliseconds)
var waitTime = 35000;
// add the name of the flow created earlier (it's case sensitive)
var flowName = '';
// fill out the flowId found in the section below
var flowId = '';
// this tag will be created if it doesn't exist and updated if it exists
// call it what ever you want. After creation you will find it in the tag list on a flow card
// use this tag in a flow with Google TTS or Sonos etc. or push message or whatever
var tagName = 'Calendar Speak Var'
await tag(tagName, '');


// Comment out this code after you've found the id of the flow to trigger
var flows = await Homey.flow.getFlows();
if (!flows) {
  console.error('No flows found');
  return;
}
var flow = Object.values(flows).find(f => f.name === flowName);
if (!flow) {
  console.error(`Flow with name '${flowName}' not found`);
  return;
}
// this will log out the id to use in the next steps
console.log(flow.id);
return;
// end of flow id section


// Uncomment this code to parse, divide and trigger the speak flow
/*var trips = Math.ceil(tokenValue.length / charLength); // how many times the speak flow will be called
console.log(`Flow with name '${flowName}' (${flowId}) will be called ${trips} time(s)`);

for (var i = 0; i < trips; i++) {
  var start = charLength * i;
  var end = charLength + (charLength * i);
  var tokenVal = tokenValue.substring(start, end).trim();
  
  await tag(tagName, tokenVal);

  await Homey.flow.triggerFlow({ id: flowId });

  console.log(`${i + 1} / ${trips} : Flow triggered with ${tokenVal.length} characters`);

  if (i < (trips - 1)) {
    console.log(`Waiting ${waitTime / 1000} seconds before next trip`);
    await wait(waitTime);
  }
}
console.log('Finished');*/
2 Likes

Runely, you are awesome! I sent you a donation for a beer (or fancy fizzy drink?) to show some appreciation. :slight_smile:

Iā€™ll try your approach soon. After your post about testing Homey-script i set out on a journey, and boy have a learned a lot!

My approach needless to say not as sophisticated as yours, but for inspiration i guess I can share it:

Homey Script code:

const variableValue = await Homey.logic.getVariable({ id: '322534e2-05ba-4b2b-8a0a-1472f70c633e' });
let data = await variableValue.value;

// Define the maximum number of anticipated events
const MAX_EVENTS = 10;

// First, delete all potential old tags up to MAX_EVENTS
for (let i = 1; i <= MAX_EVENTS; i++) {
    let tagName = "Event " + i;
    log('Deleting ' + tagName + '...');
    await tag(tagName, null);
}

// Split the data into major segments based on ';;'
let segments = data.split(';;');

segments = segments.map(segment => {
    // Remove "Kronox: Kurs.grp:"
    segment = segment.replace('Kronox:  Kurs.grp:', '');

    // Remove everything from "Program:" up to the next ";"
    segment = segment.replace(/Program:.*?;/, '');

    // Trim any extra spaces
    return segment.trim();
});

// Split each segment further by ';'
let subSegments = segments[0].split(';').map(s => s.trim());

let processedSegments = [ ];

for(let i = 0; i < subSegments.length; i++) {
    let current = subSegments[i];
    // If current segment looks like a time range, append it to the previous segment
    if(current.match(/^\d{2}:\d{2} till \d{2}:\d{2}/) || current.match(/^\d{2}-\d{2} \d{2}:\d{2} till \d{2}-\d{2} \d{2}:\d{2}/)) {
        processedSegments[processedSegments.length - 1] = processedSegments[processedSegments.length - 1] + '; ' + current + ';';
    } else {
        processedSegments.push(current + ';');
    }
}

processedSegments = processedSegments.map(segment => {
    return segment.replace(/;;/g, ' ').replace(/;/g, ''); // remove extra semicolons
});

processedSegments = processedSegments.map(segment => {
    segment = segment.replace(/;;/g, ' ').replace(/;/g, ''); // remove extra semicolons
    return segment.replace(/\s+/g, ' ').trim(); // replace multiple spaces with a single space and trim
});

// Join the processed segments with a newline for the desired output format
let output = processedSegments.join('\n');

console.log(output);

let variables = {};
processedSegments.forEach((segment, index) => {
    variables["variable" + (index + 1)] = segment;
});

console.log(variables.variable1); 
console.log(variables.variable2); 
// And so on...

// Then, create tags for the current day's events
for (let i = 0; i < processedSegments.length; i++) {
    let tagName = "Event " + (i + 1); 
    let tagValue = processedSegments[i];
    
    log('Creating ' + tagName + '...');
    await tag(tagName, tagValue);
}

The problem with this approach is that, as you said, I need to in my flow figure out how many events i have the said day, and then add delays based upon logic of the amount of events.

One problem that I still have not figured out though, Is how I can get the information regarding the ā€œmomentā€ from my schedule, because as it seems right now, when the data from my Ical file is parsed via the app, this segment (moment) seems to be removed.

Example:

Today I have this event in my calender:

But the only data that I get when i set a variable based upon todays events is:
ā€œTesta 1212; 15:30 till 16:00ā€

Maybe I should try your approach and come back?

Regardless, thanks a lot for all the help!

First of all, thank you so much for the donation. Iā€™ll really appreciate it :beer:

The flow tag you are using, ( and all the flow tags starting with Todays events or Tomorrows events ) only contains the title of the event + the start and stop times.

This is because these flow tags have always been intended to be used for TTS, such as for example Google TTS or Sonos. And having the description in there aswell would make it way too long for TTS.

Ah I see the point. I donā€™t think I really need the description so all good. :slight_smile:

One last thing, I tried to integrate your awesome solution to my problem together with my own script (that I posted above), but there seems to be a problem, because I get an error when the HomeyScript-card includes events that is not defined:

This works when i remove the ā€œnot availableā€ ones, but the problem is that in my script I have defined a maximum of 10 events, so I would like to have all 10 events there in caseā€¦ Would this be easily solvable?

I think it would work if you set the tag as ā€˜ā€™ (empty string) instead of null when you delete the tag on startup of your script.

Then the next script should treat them as just empty strings and ignore them

1 Like

Iā€™ve released a new version, v2.3.0, with trigger hit count :tada:

3 Likes

Is there a solution for the problem of the @Eternity topic starter? Iā€™ve got exactly the same problem. When I create a flow with ā€˜event has startedā€™ after a few seconds card is unavailable and app crashes.

Hmm, today my calender stopped syncing events, anyone else experiencing this? Has worked flawlessly until today. I sent in a diagnostic report.