Day view of calendar doesn't display any tasks

Nothing at all or just no results?
There should be no results but under links a long list of API end points

Weird your previous picture shows timestamp?? but that one looks good.

Here is a quick flow I threw together, modify the API for your log types and enter your calendar ID in the credentials node. It’s just a rough example and needs a little more work, it will create duplicate calendar entries if it is run more than once. There is a few possible solutions, but try it and see if it works first. Probably a good idea to have a “Test” calendar.

[
    {
        "id": "bd36b327375f5e3f",
        "type": "inject",
        "z": "03ce168ba8e7e926",
        "name": "",
        "props": [],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 90,
        "y": 180,
        "wires": [
            [
                "5ec60f1ab3da0cc2"
            ]
        ]
    },
    {
        "id": "5ec60f1ab3da0cc2",
        "type": "sf:949541c9b70110d5",
        "z": "03ce168ba8e7e926",
        "name": "",
        "API": "log/observation?filter[status]=pending",
        "Method": "GET",
        "x": 250,
        "y": 180,
        "wires": [
            [
                "53819989470988cf"
            ]
        ]
    },
    {
        "id": "05c03b2077ab988b",
        "type": "function",
        "z": "03ce168ba8e7e926",
        "name": "POST Calendars",
        "func": "var token = global.get('Google_token');\nvar name = msg.payload.name\nvar notes = msg.payload.notes\nvar timestamp = msg.payload.timestamp\nvar date = timestamp.substring(0, 10);\n\nmsg.headers = {};\nmsg.headers['Authorization'] = \"Bearer \"+token;\nmsg.headers['Accept'] = \"application/json\";\nmsg.headers['Cache-Control'] = 'no-cache';\n\nmsg.url = \"https://www.googleapis.com/calendar/v3/calendars/\" + msg.calendar + \"/events\";\nmsg.method = \"POST\";\n\nmsg.payload = {\n  \"end\": {\n    \"date\": date\n  },\n  \"start\": {\n    \"date\": date\n  },\n  \"description\": notes,\n  \"summary\": name\n};\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 390,
        "y": 260,
        "wires": [
            [
                "f6e125f66b856ce7"
            ]
        ]
    },
    {
        "id": "f6e125f66b856ce7",
        "type": "http request",
        "z": "03ce168ba8e7e926",
        "name": "",
        "method": "use",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 590,
        "y": 260,
        "wires": [
            [
                "ee884d093860e958"
            ]
        ]
    },
    {
        "id": "ee884d093860e958",
        "type": "debug",
        "z": "03ce168ba8e7e926",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 770,
        "y": 260,
        "wires": []
    },
    {
        "id": "ff355d077cdaa495",
        "type": "credentials",
        "z": "03ce168ba8e7e926",
        "name": "Calendar ID",
        "props": [
            {
                "value": "calendar",
                "type": "msg"
            }
        ],
        "x": 190,
        "y": 260,
        "wires": [
            [
                "05c03b2077ab988b"
            ]
        ]
    },
    {
        "id": "53819989470988cf",
        "type": "function",
        "z": "03ce168ba8e7e926",
        "name": "",
        "func": "msg.payload.data.forEach(data => {\n    msg.payload.name = data.attributes.name;\n    msg.payload.timestamp = data.attributes.timestamp;\n    msg.payload.notes = data.attributes.notes;\n    node.send(msg)\n    })\n\nreturn;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 420,
        "y": 180,
        "wires": [
            [
                "ff355d077cdaa495"
            ]
        ]
    }
]

Very cool…yes, I see the list now that I get into the links section. Alrighty, I’ve add your flow to my Node-Red. I’m pretty clear on how I would add that to my authentication. However, I’m unclear on how I get credentials for a calendar. Sorry, I know I’m leaning on you a ton! Do I go into my Google Platform with the Node-Red project to do this? Will I be putting in a similar client_id and secret? Would I create a test calendar under my personal email or is it associated on the developer side?

Go to your personal calendars and add other calendar, create new calendar.
then click the 3 dots on the calendar, choose settings then scroll down to Integrate calendar and get the calendar ID.

You don’t strictly need to link your authentication to the flows, your authentication nodes save the access tokens as Global variables and the flows can retrieve those tokens from global variables. It may make sense some times to link the flows to authenticate and then complete the API requests but if you are making a lot of requests at once you can authenticate once then do all of the requests together. The authentication flows and API flows don’t even need to be on the same tabs.

If the tokens expire then you need to refresh them I think they a valid in farmOS for an hour and google a 1/2 hour

Oh, that’s easy! I was expecting something more complicated. Thanks! Ok, I think I’m super-close. I’m getting an error cod (401). It says I’m getting an invalid authentication credential. I copied the calendar ID. Not sure if that is the problem…

1 Like

you just need to refresh the Google Token in this case. Either add a google refresh node at the beginning of the flow or refresh it first elsewhere.

Holy &%$^##(@(@ I see work activity on a calendar! If you were nearby, I’d buy you a beer…a few of em. Wahoo. Ok, this gives me a template to work from. I REALLY appreciate the time you gave. . . and make sure you let me know when the module for FarmOS can be integrated in…very helpful stuff.

2 Likes

Good stuff @kyle
You’ll have to work out how to avoid the duplicate entries now.

you could:

  • use an unused data field in the logs to write something to mark it added to calendar, then any log with that data field used are ignored by your flow.
  • Change the node-red settings file to allow context data be stored to disk instead of just memory so it is persistent through reboots, then you could keep a list of logs already sent to calendar in an array, but you’d also need to prune that list when logs are no longer in pending state.
  • Read the calendar date for the entry about to be saved for an existing entry with the same name.

There are pro’s and cons to all of these approaches but the last one is probably the safest bet.

Anyway good luck!

Can you explain option number three? I’m not sure what you mean by “read the calendar date”…

So after reading the log entry from farmOS, the flow should get the log name and date, then read the calendar for that same date and check there is not already entry there with the same name as the log, if there is the flow should do nothing with this log and if there isn’t then it should create a new calendar event.

But there may be an even easier solution depending on how many logs you create and how you create them. For instance if you are the only one creating logs (or know when the last logs are created on any given day) you could just use the creation date and only add logs to the calendar that were created on that same day. This method would require running the flow only once and at the end of everyday that logs are created. It may be possible to add a few checks with this method to prevent duplicates too.

Hope that helps, sometimes things sound simpler in my head :upside_down_face:

Ok, the last option makes the most sense for my situation. I like the ability to update the calendar based on a creation date. I would probably want two flows. One flow would go ahead and populate the calendar with everything that already exists in the season. The second flow would then populate new tasks on the create date.

1 Like

As in a once off flow just to get you up to date, then the flow that you will use going forward?

That could work.

Yeah, that’s what I’m thinking…

1 Like

@Farmer-Ed Any tips on how I would set up a weekly update flow? Maybe something I could run that would capture the last 4-7 days of new logs?

Have you looked at using the Node-red dashboard yet?
I think a simple GUI where you can select a date range might be useful. Perhaps even load the logs into a table and click which ones you want to send to the calendar? Really depends on how many logs you generate per week as to how useful that might be.

Here is an example I’m working on for synchronizing my farmOS herd with another database. Nothing to do with calendars but a similar interface might suite what you are doing.
chrome_p9I8UG3D8Q

It really depends on the time of season. (We are an orchard of cherry, peach, pear.) My main purpose in calendar integration is for work flow. There are plenty of logs I make as completed logs for data purposes. However, there will be at least two folks who will make logs (events, inputs, activities, etc) throughout the season. A simply way for me to add to the calendar by choosing a date range would be ideal. In the end, I’m not opposed to having–as clunky as it may sound–workers subscribing to a weekly calendar if I need to renew and inject once a week. I went ahead and installed the Dashboard, but I’ve got to admit, I have no idea how to proceed with a date-based update. Would I copy my already existing flow and add Date Picker button? Thanks!

This is the clunky solution.

Replace the filter you have with this one, but change the epoch timestamp.

?filter[recent][condition][path]=created&filter[recent][condition][operator]=%3E&filter[recent][condition][value]=1641363784&filter[status]=pending

Unfortunately time and date filtering is done with epoch time, so you need to do some conversion here (eg. 1641363784 is Wednesday, January 5, 2022 6:23:04 AM ). Also the traditional operators need to be encoded as URL friendly versions (eg. %3E is greater than).

Relevant reading and converters:
See filtering API Changes | farmOS
See last example https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/filtering
How to convert time/dates https://www.epochconverter.com/
How to convert operators URL escape codes

Looking at this, I may update my farmOS nodes in the near future to make filtering a little easier.

More or less, some things can be directly replaced or even connected in conjunction with, like the inject button and dashboard button, admittedly a date picker and tables can be a little more head scratching but a button for “Last X no of days” might be a bit easier. You can always build the GUI’s later and maybe some safeguards against duplication, you’ll know after using it for a while where it needs tweaking.

@kyle
I’ve put together a simple GUI using the dashboard.

image

http://127.0.0.1:1880/ui to access the dashboard

Evening! I haven’t had a chance to delve into the dashboard. For now, I’m trying to see if there are simple ways form me to update and share with the rest of my crew. However, I’ve come into a snag. I’m not getting an error when I inject the node. Any idea what this is?

Possibly.
Has your Google Token expired? The tokens expire in developer mode every 7 days so you need to do a full Sign in/Authenticate with you google username/password every 7days not just the refresh.

In production mode this doesn’t happen but you need to provide Google with a registered domain name for the redirect URL and possibly SSL setup too, which may not be practical with running Node-Red on your laptop only a few times a week. Would be worth considering if you properly host Node Red on a server later.

The flows I provided you are not fully developed in the sense that they don’t fully capture every error and return to you a detailed explanation of what just failed. This is something I may get back to in the future but it’s a busy time on the farm here at the moment.

The debug nodes are really useful in finding issues, they can be connected after any other node to display its output which is usually msg.payload but can be anything like msg.url or msg.any_thing_else changing the output option of a debug node to complete msg object will show all available output messages.

No worries, I know it’s a busy time, and I think I may just find a workaround until there is integration into FarmOS itself. I managed to move a few things around and started getting integration back into a calendar. However it’s spotty. I get a mixture of successful integrations mixed with this error code. I’ve looked it up, and I’m wondering how to resolve. Don’t feel the need to reply if your too busy. I’m at least getting some integration back after injecting the Google Oauth2 and then injecting the calendar node.