
Der findes et fantastisk system, der er gratis som hedder Mealie.
Dette er også lavet, som et tilføjelses program til Home Assistant.
Jeg bruger integrationen via Node Red og det fungere helt perfekt.

Her er Mealie som Node Red
[
{
"id": "0fabd94e3d75037c",
"type": "tab",
"label": "Mealie",
"disabled": false,
"info": "",
"env": []
},
{
"id": "24698eb5a34a6e6c",
"type": "ha-entity",
"z": "0fabd94e3d75037c",
"name": "Weekly recipe sensor",
"server": "49e64ea71c5ef4d9",
"version": 1,
"debugenabled": false,
"outputs": 1,
"entityType": "sensor",
"config": [
{
"property": "name",
"value": "weekly_recipes"
},
{
"property": "device_class",
"value": ""
},
{
"property": "icon",
"value": "mdi:silverware"
},
{
"property": "unit_of_measurement",
"value": ""
}
],
"state": "payload[0].recipe_name",
"stateType": "msg",
"attributes": [
{
"property": "recipes",
"value": "payload",
"valueType": "msg"
}
],
"resend": true,
"outputLocation": "",
"outputLocationType": "none",
"inputOverride": "allow",
"x": 1070,
"y": 160,
"wires": [
[]
]
},
{
"id": "ad8f9fac9b2818dc",
"type": "comment",
"z": "0fabd94e3d75037c",
"name": "Get recipes for next 7 days from Mealie",
"info": "",
"x": 200,
"y": 60,
"wires": []
},
{
"id": "5b89f7168b70378c",
"type": "inject",
"z": "0fabd94e3d75037c",
"name": "Hourly update",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "3600",
"crontab": "",
"once": false,
"onceDelay": "1",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 150,
"y": 110,
"wires": [
[
"72d53960a104a7cb"
]
]
},
{
"id": "f38dac9ded497b2f",
"type": "server-state-changed",
"z": "0fabd94e3d75037c",
"name": "Manuel update?",
"server": "49e64ea71c5ef4d9",
"version": 1,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityidfilter": "input_boolean.recipe_reload",
"entityidfiltertype": "exact",
"outputinitially": false,
"state_type": "str",
"haltifstate": "",
"halt_if_type": "str",
"halt_if_compare": "is",
"outputs": 1,
"output_only_on_state_change": true,
"for": "",
"forType": "num",
"forUnits": "minutes",
"ignorePrevStateNull": false,
"ignorePrevStateUnknown": false,
"ignorePrevStateUnavailable": false,
"ignoreCurrentStateUnknown": false,
"ignoreCurrentStateUnavailable": false,
"x": 150,
"y": 160,
"wires": [
[
"72d53960a104a7cb"
]
]
},
{
"id": "a4b38c28628774c2",
"type": "http request",
"z": "0fabd94e3d75037c",
"name": "Get mealplan from Mealie",
"method": "GET",
"ret": "obj",
"paytoqs": "query",
"url": "http://[MEALIE_IP]:9925/api/groups/mealplans",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "bearer",
"senderr": false,
"headers": [],
"x": 620,
"y": 160,
"wires": [
[
"43cc5010da45aee8",
"544c565b5b967113"
]
]
},
{
"id": "72d53960a104a7cb",
"type": "function",
"z": "0fabd94e3d75037c",
"name": "Limit to next 7 days",
"func": "msg.topic=\"\";\nlet today = new Date();\nlet next7days = new Date();\nnext7days.setDate(today.getDate() + 6);\n\nfunction padTo2Digits(num) {\n return num.toString().padStart(2, '0');\n}\n\nfunction formatDate(date) {\n return [\n date.getFullYear(),\n padTo2Digits(date.getMonth() + 1),\n padTo2Digits(date.getDate()),\n ].join('-');\n}\n\nlet NewMsg = {\n \"topic\": \"\",\n \"payload\" : {\n \"start\": formatDate(today),\n \"limit\": formatDate(next7days)\n}};\nreturn NewMsg;\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 160,
"wires": [
[
"a4b38c28628774c2"
]
]
},
{
"id": "43cc5010da45aee8",
"type": "function",
"z": "0fabd94e3d75037c",
"name": "Process plan",
"func": "msg.topic=\"\";\nlet today = new Date();\nlet weekday = new Date();\nconst plan = [];\nlet recipes=msg.payload;\n\nfor (let i = 0; i < 7; i++) {\n //weekday.setDate(today.getDate() + i);\n weekday = new Date(new Date().getTime() + (i * 24 * 60 * 60 * 1000));\n var recipe = recipes.find(obj => {\n return obj.date === formatDate(weekday)\n })\n let id = null;\n let rname = '(Intet planlagt)';\n let url = '';\n let image = '/local/assets/no_recipe.jpg';\n if (typeof (recipe) != \"undefined\") { \n id = recipe.recipe.id;\n rname = recipe.recipe.name;\n url = 'http://[MEALIE_IP]:9925/recipe/' + recipe.recipe.slug;\n image = 'http://[MEALIE_IP]:9925/api/media/recipes/'+id +'/images/min-original.webp';\n }\n plan.push(\n {\n \"Weekday\": capitalizeFirst(weekday.toLocaleDateString('da-DK', { weekday: 'long', })),\n \"Date\": formatDate(weekday),\n \"recipe_name\": rname,\n \"recipe_url\": url,\n \"recipe_image\": image,\n \"mealieID\": id\n });\n}\n\nmsg.payload=plan;\nreturn msg;\n\n// Functions\n\nfunction padTo2Digits(num) {\n return num.toString().padStart(2, '0');\n}\n\nfunction formatDate(date) {\n return [\n date.getFullYear(),\n padTo2Digits(date.getMonth()+1 ),\n padTo2Digits(date.getDate()),\n ].join('-');\n}\n\nfunction capitalizeFirst(word) {\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 850,
"y": 160,
"wires": [
[
"24698eb5a34a6e6c"
]
]
},
{
"id": "544c565b5b967113",
"type": "debug",
"z": "0fabd94e3d75037c",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 830,
"y": 220,
"wires": []
}
]