My Node-Red and FarmOS project

Figured I’ll try to share my progress for my Node-Red and FarmOS integration.
I’ve got a limited set of skills for this, but it’s for sure quite fun trying…

Until now I’ve tried to get familiar with FarmOS itself, and what possibilities I have with NodeRed.
I’ve learnt a lot from @Farmer-Ed’s flows here on the forum. You made me believe I could do this…

I did some dashboard buttons to help me add certain logs to FarmOS. Push the button, and the log is created. Nothing fancy, but quite handy.

I also made a work agenda for my pig business. It takes events from -7 days to +21 days of today, and list it up with the number of days till due.


(Pardon my french… The first entry is Farrowing, 6 days ago.

The flow was quite easy. Big challenge was formatting the dates.

3 Likes

Later on, I intend to

  1. make some csv field task import from my FieldBee tractor GPS (if not via API. Not verified yet)
  2. try to get info from my locally installed Pig management software (EliteHerd)
  3. do some sensor monitoring

But for now, I decided my first bigger project is to make use of the animal asset.

Use case:
Every 7 week I wean a batch of piglets, and I intend to weigh a couple pens every week to track average daily growth.

At weaning day, I create 2 animals. One for each pen I intend to weigh.

I name them with the date, and pen number. I also set the review flag.

I intend to add the weights from the dashboard.
So I came up with a flow to let me select animals from a dropdown listbox. It only shows animals with the review flag set.

bilde
Picture show the dropdown with the 2 animals with review flag.

The flow… I tried to make it with no function nodes, but hey… that was hard.

Well it works so far… Need to study to figure out how to proceed when I select from the dropdown list…

In debug node 69 I have this object.
bilde

The dropdown takes its items from the options part. But when I select one, the object has lost the FarmOS ID for the animal asset.
bilde

1 Like

You could try this:

[
    {
        "id": "d4384525475d2051",
        "type": "sf:949541c9b70110d5",
        "z": "9761e3d04587c4ce",
        "name": "",
        "API": "asset/animal",
        "Method": "GET",
        "x": 110,
        "y": 500,
        "wires": [
            [
                "2c0bde5aa867661a"
            ]
        ]
    },
    {
        "id": "1b4ed8658d016049",
        "type": "inject",
        "z": "9761e3d04587c4ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 120,
        "y": 420,
        "wires": [
            [
                "4ac6156a5531d2af"
            ]
        ]
    },
    {
        "id": "d67c9a1d34d1445f",
        "type": "split",
        "z": "9761e3d04587c4ce",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 430,
        "y": 500,
        "wires": [
            [
                "8a54399e21d1a83c"
            ]
        ]
    },
    {
        "id": "8a54399e21d1a83c",
        "type": "split",
        "z": "9761e3d04587c4ce",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 550,
        "y": 500,
        "wires": [
            [
                "db0df28a61ba1df9"
            ]
        ]
    },
    {
        "id": "db0df28a61ba1df9",
        "type": "switch",
        "z": "9761e3d04587c4ce",
        "name": "Filter animals",
        "property": "payload.attributes.flag",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "monitor",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 700,
        "y": 500,
        "wires": [
            [
                "9e0fa6fb5b7dc62b"
            ]
        ]
    },
    {
        "id": "9e0fa6fb5b7dc62b",
        "type": "change",
        "z": "9761e3d04587c4ce",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "options",
                "pt": "msg",
                "to": "payload.attributes.name",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.payload.id",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 880,
        "y": 500,
        "wires": [
            [
                "cf287a9f2c469279"
            ]
        ]
    },
    {
        "id": "2f8b34fa993266d9",
        "type": "debug",
        "z": "9761e3d04587c4ce",
        "name": "debug 68",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1020,
        "y": 440,
        "wires": []
    },
    {
        "id": "e0ae85f360f9fdc2",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "function 18",
        "func": "msg.options = [msg.payload.options];\nvar aID = flow.get(\"animalID\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n    msg.options[i] = msg.payload[i].options\n    msg.payload[i] = msg.payload[i].payload.id\n    aID[i] = msg.payload[i];\n}\nflow.set(\"animalID\", aID)\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1190,
        "y": 500,
        "wires": [
            [
                "c2a87e3565e05dbd",
                "8207a9ac9358fec7"
            ]
        ]
    },
    {
        "id": "c2a87e3565e05dbd",
        "type": "debug",
        "z": "9761e3d04587c4ce",
        "name": "debug 69",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1220,
        "y": 440,
        "wires": []
    },
    {
        "id": "8207a9ac9358fec7",
        "type": "ui_dropdown",
        "z": "9761e3d04587c4ce",
        "name": "",
        "label": "",
        "tooltip": "",
        "place": "",
        "group": "e396e7e9f5db9aaa",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": false,
        "multiple": false,
        "options": [],
        "payload": "",
        "topic": "",
        "topicType": "str",
        "className": "",
        "x": 400,
        "y": 580,
        "wires": [
            [
                "5e424d5b6f44d789",
                "c41ba247bce535b3"
            ]
        ]
    },
    {
        "id": "5e424d5b6f44d789",
        "type": "debug",
        "z": "9761e3d04587c4ce",
        "name": "debug 70",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 560,
        "y": 580,
        "wires": []
    },
    {
        "id": "cf287a9f2c469279",
        "type": "merge",
        "z": "9761e3d04587c4ce",
        "name": "",
        "timeout": "0",
        "x": 1030,
        "y": 500,
        "wires": [
            [
                "2f8b34fa993266d9",
                "e0ae85f360f9fdc2"
            ]
        ]
    },
    {
        "id": "2c0bde5aa867661a",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "Save id's",
        "func": "var array = flow.get('Animals') || [];\nvar name;\nvar id;\n\nmsg.payload.data.forEach(data => {\nname = data.attributes.name;\nid = data.id;\narray.push({id:id,name:name});\n})\n\nflow.set(\"Animals\", array);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 280,
        "y": 500,
        "wires": [
            [
                "d67c9a1d34d1445f"
            ]
        ]
    },
    {
        "id": "4ac6156a5531d2af",
        "type": "change",
        "z": "9761e3d04587c4ce",
        "name": "",
        "rules": [
            {
                "t": "delete",
                "p": "Animals",
                "pt": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 290,
        "y": 420,
        "wires": [
            [
                "d4384525475d2051"
            ]
        ]
    },
    {
        "id": "c41ba247bce535b3",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "",
        "func": "var animals = flow.get(\"Animals\");\nvar name = msg.payload;\nvar array = [];\nvar id;\n\nanimals.forEach(data => {\n    if (data.name == name) {\n        id = data.id;\n        }\n   })\n\narray.push({id:id,name:name});\n\nmsg.payload = array;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 560,
        "y": 640,
        "wires": [
            [
                "4b5de9c569fa3567"
            ]
        ]
    },
    {
        "id": "4b5de9c569fa3567",
        "type": "debug",
        "z": "9761e3d04587c4ce",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 770,
        "y": 640,
        "wires": []
    },
    {
        "id": "e396e7e9f5db9aaa",
        "type": "ui_group",
        "name": "Farmos",
        "tab": "169f5145902ec68e",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "169f5145902ec68e",
        "type": "ui_tab",
        "name": "FarmOS div",
        "icon": "fa-leaf",
        "order": 4,
        "disabled": false,
        "hidden": false
    }
]


1 Like

or this:

[
    {
        "id": "d4384525475d2051",
        "type": "sf:949541c9b70110d5",
        "z": "9761e3d04587c4ce",
        "name": "",
        "API": "asset/animal?filter[flag]=monitor",
        "Method": "GET",
        "x": 370,
        "y": 500,
        "wires": [
            [
                "2c0bde5aa867661a"
            ]
        ]
    },
    {
        "id": "1b4ed8658d016049",
        "type": "inject",
        "z": "9761e3d04587c4ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 380,
        "y": 420,
        "wires": [
            [
                "4ac6156a5531d2af"
            ]
        ]
    },
    {
        "id": "e0ae85f360f9fdc2",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "options list",
        "func": "var animals = flow.get(\"Animals\");\nvar array = [];\nvar name;\n\nanimals.forEach(data => {\n    name = data.name\n    array.push(name);\n   })\n\nmsg.options = array;\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 710,
        "y": 500,
        "wires": [
            [
                "8207a9ac9358fec7"
            ]
        ]
    },
    {
        "id": "8207a9ac9358fec7",
        "type": "ui_dropdown",
        "z": "9761e3d04587c4ce",
        "name": "",
        "label": "",
        "tooltip": "",
        "place": "",
        "group": "e396e7e9f5db9aaa",
        "order": 0,
        "width": 0,
        "height": 0,
        "passthru": false,
        "multiple": false,
        "options": [],
        "payload": "",
        "topic": "",
        "topicType": "str",
        "className": "",
        "x": 880,
        "y": 500,
        "wires": [
            [
                "c41ba247bce535b3"
            ]
        ]
    },
    {
        "id": "2c0bde5aa867661a",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "Save id's",
        "func": "var array = flow.get('Animals') || [];\nvar name;\nvar id;\n\nmsg.payload.data.forEach(data => {\nname = data.attributes.name;\nid = data.id;\narray.push({id:id,name:name});\n})\n\nflow.set(\"Animals\", array);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 540,
        "y": 500,
        "wires": [
            [
                "e0ae85f360f9fdc2"
            ]
        ]
    },
    {
        "id": "4ac6156a5531d2af",
        "type": "change",
        "z": "9761e3d04587c4ce",
        "name": "",
        "rules": [
            {
                "t": "delete",
                "p": "Animals",
                "pt": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 420,
        "wires": [
            [
                "d4384525475d2051"
            ]
        ]
    },
    {
        "id": "c41ba247bce535b3",
        "type": "function",
        "z": "9761e3d04587c4ce",
        "name": "Load Id's",
        "func": "var animals = flow.get(\"Animals\");\nvar name = msg.payload;\nvar array = [];\nvar id;\n\nanimals.forEach(data => {\n    if (data.name == name) {\n        id = data.id;\n        }\n   })\n\narray.push({id:id,name:name});\n\nmsg.payload = array;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 500,
        "wires": [
            [
                "4b5de9c569fa3567"
            ]
        ]
    },
    {
        "id": "4b5de9c569fa3567",
        "type": "debug",
        "z": "9761e3d04587c4ce",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1210,
        "y": 500,
        "wires": []
    },
    {
        "id": "e396e7e9f5db9aaa",
        "type": "ui_group",
        "name": "Farmos",
        "tab": "169f5145902ec68e",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "169f5145902ec68e",
        "type": "ui_tab",
        "name": "FarmOS div",
        "icon": "fa-leaf",
        "order": 4,
        "disabled": false,
        "hidden": false
    }
]

Save id's and options list can be combined into a single function, but I left them separate for ease of following.

Probably can’t avoid using some function nodes, but if we come up with a few that are flexible and reusable then they can be packaged up.

1 Like

Ah, cool. I’ll look at it later on…

Yesterday I understood that NodeRed has a project functionality. Making use of git and github. So, more to learn…
I tried to connect NodeRed to my github today and got version control in NodeRed but could not sync with github yet…

@Farmer-Ed, have you set this up for you?

1 Like

I couldn’t resist a quick peek on the last of your flows…
I had no idea that the FarmOS API node could filter that way. Awesome :+1:
bilde

The functions looked quite nice and clear too.
Maybe I’ve gotten some javascript under my fingernails after all… :thinking:

1 Like

No I don’t, but that is very interesting must have a good look at it.

Well it just uses the farmOS API API Changes | farmOS
I guess the nodes could do with a bit of documentation too.

If you get enough thrown at you after a while it starts to stick :rofl:
I think you need to learn a bit if you want to get the most out of Node-Red.

1 Like

Yep. Most guides I found told me to add a setting in config.js. But the setting was already there. Just had to change it from false to true. Just search for “projects” in the file.

I’m strugglig to authenticate between NodeRed and GitHub.
I followed How to Use Deploy Keys on Github (with Pictures) - wikiHow but GitHub gives me the following error:

Key is invalid. You must supply a key in OpenSSH public key format

Let me know if you find a working guide.

1 Like

Did some quick and dirty hacking tonight…
No coding was involved. Just a pile of nodes and some glue.

@Farmer-Ed, you made me aware of ntfy.sh, so I figured I could try it out.
Also, I kept checking for the beta7 update on Farmier, and I suddenly got an ida.
No coding involved. Just a few nodes and some glue.

I now get the FarmOS version printed on my dashbard, and also get notified if it’s updated.
(Only checks for the text “beta7” for the moment)

Thanks @mstenta for holding back the update :innocent:

[
    {
        "id": "88c23616cce2b95e",
        "type": "comment",
        "z": "ae72b941.c54948",
        "name": "FarmOS version",
        "info": "",
        "x": 120,
        "y": 900,
        "wires": []
    },
    {
        "id": "35eebc580ddd20fc",
        "type": "inject",
        "z": "ae72b941.c54948",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 940,
        "wires": [
            [
                "8f95d30c1d55f879"
            ]
        ]
    },
    {
        "id": "8f95d30c1d55f879",
        "type": "sf:949541c9b70110d5",
        "z": "ae72b941.c54948",
        "name": "",
        "API": "",
        "Method": "GET",
        "credentials": {},
        "x": 310,
        "y": 940,
        "wires": [
            [
                "39e7804a7613a6c7"
            ]
        ]
    },
    {
        "id": "d4cc55cbd0f88975",
        "type": "ui_template",
        "z": "ae72b941.c54948",
        "group": "3129ab11879b0c59",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "FarmOS version : <div ng-bind-html=\"msg.payload\"></div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 640,
        "y": 940,
        "wires": [
            [
                "8c726ef60a9cafcf"
            ]
        ]
    },
    {
        "id": "39e7804a7613a6c7",
        "type": "change",
        "z": "ae72b941.c54948",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.meta.farm.version",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 480,
        "y": 940,
        "wires": [
            [
                "d4cc55cbd0f88975"
            ]
        ]
    },
    {
        "id": "a1ed6d010d510879",
        "type": "http request",
        "z": "ae72b941.c54948",
        "name": "ntfy",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "https://ntfy.sh/NTFY-TOPIC-GOES-HERE",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 890,
        "y": 940,
        "wires": [
            []
        ]
    },
    {
        "id": "8c726ef60a9cafcf",
        "type": "switch",
        "z": "ae72b941.c54948",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "2.0.0-beta7",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 770,
        "y": 940,
        "wires": [
            [
                "a1ed6d010d510879"
            ]
        ]
    },
    {
        "id": "3129ab11879b0c59",
        "type": "ui_group",
        "name": "Diverse",
        "tab": "aa4e56286fd1b949",
        "order": 3,
        "disp": true,
        "width": "10",
        "collapse": false,
        "className": ""
    },
    {
        "id": "aa4e56286fd1b949",
        "type": "ui_tab",
        "name": "Dagen idag",
        "icon": "developer_dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]
2 Likes

Cool @pat
I’ve some suggestions if you don’t mind. :slightly_smiling_face:

  1. Store the version as a flow variable, then compare, so if the version changes you get a notification.
    (you will get a notification on first run, then on every update “beta7/8/9” etc, if your node red instance is not always on then you may need to set flow variables to be saved to file in node-red config file to persist through restarts)

  2. Use your first change node to suppress msg.url and msg.method will stop the warnings on the http request node. These are coming from the API node, I think I should suppress them internally on the next version.

[
    {
        "id": "88c23616cce2b95e",
        "type": "comment",
        "z": "18fa260c2dd21518",
        "name": "FarmOS version",
        "info": "",
        "x": 220,
        "y": 160,
        "wires": []
    },
    {
        "id": "8f95d30c1d55f879",
        "type": "sf:949541c9b70110d5",
        "z": "18fa260c2dd21518",
        "name": "",
        "API": "",
        "Method": "GET",
        "x": 390,
        "y": 200,
        "wires": [
            [
                "39e7804a7613a6c7"
            ]
        ]
    },
    {
        "id": "d4cc55cbd0f88975",
        "type": "ui_template",
        "z": "18fa260c2dd21518",
        "group": "3129ab11879b0c59",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "FarmOS version : <div ng-bind-html=\"msg.payload\"></div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 760,
        "y": 200,
        "wires": [
            [
                "8c726ef60a9cafcf"
            ]
        ]
    },
    {
        "id": "39e7804a7613a6c7",
        "type": "change",
        "z": "18fa260c2dd21518",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.meta.farm.version",
                "tot": "msg"
            },
            {
                "t": "delete",
                "p": "url",
                "pt": "msg"
            },
            {
                "t": "delete",
                "p": "method",
                "pt": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 580,
        "y": 200,
        "wires": [
            [
                "d4cc55cbd0f88975"
            ]
        ]
    },
    {
        "id": "a1ed6d010d510879",
        "type": "http request",
        "z": "18fa260c2dd21518",
        "name": "ntfy",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://192.168.1.22:90/farmos",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 1050,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "8c726ef60a9cafcf",
        "type": "switch",
        "z": "18fa260c2dd21518",
        "name": "",
        "property": "version",
        "propertyType": "flow",
        "rules": [
            {
                "t": "neq",
                "v": "payload",
                "vt": "msg"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 910,
        "y": 200,
        "wires": [
            [
                "5fe30ea54706669c",
                "a1ed6d010d510879"
            ]
        ]
    },
    {
        "id": "5fe30ea54706669c",
        "type": "change",
        "z": "18fa260c2dd21518",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "version",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1080,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "51b09b06acec5fd0",
        "type": "inject",
        "z": "18fa260c2dd21518",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 210,
        "y": 200,
        "wires": [
            [
                "8f95d30c1d55f879"
            ]
        ]
    },
    {
        "id": "3129ab11879b0c59",
        "type": "ui_group",
        "name": "Diverse",
        "tab": "aa4e56286fd1b949",
        "order": 3,
        "disp": true,
        "width": "10",
        "collapse": false,
        "className": ""
    },
    {
        "id": "aa4e56286fd1b949",
        "type": "ui_tab",
        "name": "Dagen idag",
        "icon": "developer_dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]
1 Like

Suggestions are indeed welcome…

I was actually thinking of this, but did not have time to explore it at the time. :ok_hand:

1 Like

Sorry @pat - the whole family has Covid here, so things are moving slow. :face_with_diagonal_mouth:

2 Likes

Oh no…
Hope you are all OK.
Had the same here a few weeks ago, but nobody too sick thankfully.

2 Likes

No problemo :slightly_smiling_face:
Take the time you need. I can wait.

Uninstall covid first…

1 Like

sudo apt-get purge covid-19

2 Likes

Updated my flow now @Farmer-Ed
Nice touch.

Think I’ll install ntfy on my rpi3 along with node-red.
Looked lik an easy process.

1 Like

yes @pat, I just included it with the same docker-compose as farmOS not much configuration beyond that.

Did you get the notification @pat?? :wink:

2 Likes

I did :innocent:
I planned on commenting it tonight. Thanks.

2 Likes

Hacking-time:

I have this button in my dashboard to log an activity of filling salt to my water purifyer.
bilde

It logs the event associated to it’s asset. There are some error-checking and if success I get this dialog with a link to the log.

bilde

Latest addition is a countdown timer that notifies me via ntfy when it’s time to refill.

It works fine so far.
:sunglasses:

1 Like