This is probably a drop-in-replacement for the Node-RED implementation of Dynamic ess using the VRM-API node and the “original flow”.
I used some code from dynamic-ess/src/nodes/victron-dynamic-ess.js at main · victronenergy/dynamic-ess · GitHub for this.
It is probably not yet 15-minutes compatible but I think this will be easy to add in the near future using the dess.is_half_hour_schedule variable (or similar).
[
{
"id": "ddb754a848a5437c",
"type": "group",
"z": "d457e88372dcd44a",
"name": "Dynamic ESS",
"style": {
"label": true
},
"nodes": [
"1857e6dc9a194fec",
"7049b7140944117e",
"76a5b63506d3a697",
"8533359282a12955",
"756103b9698a27ff",
"d81811500e0ae9f8",
"484523849a6134a7",
"780ff00a1393a6fe",
"70fcd76ccd733faf"
],
"x": 974,
"y": 264,
"w": 432,
"h": 317
},
{
"id": "1857e6dc9a194fec",
"type": "link out",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "schedule 0 - current hour",
"mode": "link",
"links": [
"da28729197a836c4",
"36f3c65014ac2767"
],
"x": 1305,
"y": 420,
"wires": []
},
{
"id": "7049b7140944117e",
"type": "link out",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "schedule 1 - current hour +1",
"mode": "link",
"links": [
"9072b4ed90c3d650"
],
"x": 1305,
"y": 460,
"wires": []
},
{
"id": "76a5b63506d3a697",
"type": "link out",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "schedule 2 - current hour +2",
"mode": "link",
"links": [
"7677870734c617e4"
],
"x": 1305,
"y": 500,
"wires": []
},
{
"id": "8533359282a12955",
"type": "link out",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "schedule 3 - current hour +3",
"mode": "link",
"links": [
"163da36509915168"
],
"x": 1305,
"y": 540,
"wires": []
},
{
"id": "756103b9698a27ff",
"type": "inject",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "300",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 1090,
"y": 320,
"wires": [
[
"70fcd76ccd733faf"
]
]
},
{
"id": "d81811500e0ae9f8",
"type": "function",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "VRM DESS compatibility",
"func": "let dess = msg.payload\n\n/**\nconst currentDateTime = new Date()\ncurrentDateTime.setMinutes(0, 0, 0)\n\nconst unixTimestamp = Math.floor(currentDateTime.getTime() / 1000)\n\n\nlet currentHour = currentDateTime.getHours()\nif (currentHour > Object.keys(dess.schedule).length) {\n currentHour -= 24\n}\n**/\nconst output = []\nif (dess.output) {\n const currentDateTime = new Date()\n currentDateTime.setMinutes(0, 0, 0)\n const unixTimestamp = Math.floor(currentDateTime.getTime() / 1000)\n const currentHour = currentDateTime.getHours()\n for (let schedule = 0; schedule <= 3; schedule++) {\n let schedulePick = currentHour + schedule\n if (dess.is_half_hour_schedule) {\n schedulePick = (currentHour * 2) + schedule\n if (schedulePick > Object.keys(dess.output.SOC).length) {\n schedulePick -= 48\n }\n if (currentHour === 0 && Object.keys(dess.output.SOC).length > 48) {\n schedulePick += 48\n }\n } else {\n if (schedulePick > Object.keys(dess.output.SOC).length) {\n schedulePick -= 24\n }\n if (currentHour === 0 && Object.keys(dess.output.SOC).length > 24) {\n schedulePick += 24\n }\n }\n output.push({\n topic: `Schedule ${schedule}`,\n soc: Number((dess.output.SOC[schedulePick])),\n feed_in: dess.options.feed_in_possible ? 1 : 0,\n duration: dess.is_half_hour_schedule ? 1800 : 3600,\n start: unixTimestamp + (schedule * (dess.is_half_hour_schedule ? 1800 : 3600)),\n restrictions: Number((dess.output.restrictions[schedulePick] || 0)),\n strategy: dess.output.coping_strategy[schedulePick]\n })\n }\n}\n\nreturn output\n\n/**\nreturn [\n {\n soc: dess.output.SOC[currentHour],\n feed_in: dess.output.feed_in[currentHour],\n start: unixTimestamp,\n duration: 3600,\n restrictions: dess.output.restrictions[currentHour],\n strategy: dess.output.coping_strategy[currentHour],\n },\n {\n soc: dess.output.SOC[currentHour+1],\n feed_in: dess.output.feed_in[currentHour+1],\n start: new Date(dess.output.timestamps[currentHour+1]),\n duration: 3600,\n restrictions: dess.output.restrictions[currentHour+1],\n strategy: dess.output.coping_strategy[currentHour+1],\n },\n {\n soc: dess.output.SOC[currentHour+2],\n feed_in: dess.output.feed_in[currentHour+2],\n start: new Date(dess.output.timestamps[currentHour+2]),\n duration: 3600,\n restrictions: dess.output.restrictions[currentHour+2],\n strategy: dess.output.coping_strategy[currentHour+2],\n },\n {\n soc: dess.output.SOC[currentHour+3],\n feed_in: dess.output.feed_in[currentHour+3],\n start: new Date(dess.output.timestamps[currentHour+3]),\n duration: 3600,\n restrictions: dess.output.restrictions[currentHour+3],\n strategy: dess.output.coping_strategy[currentHour+3],\n }\n];\n**/",
"outputs": 4,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1110,
"y": 520,
"wires": [
[
"1857e6dc9a194fec"
],
[
"7049b7140944117e"
],
[
"76a5b63506d3a697"
],
[
"8533359282a12955"
]
]
},
{
"id": "484523849a6134a7",
"type": "change",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "",
"rules": [
{
"t": "set",
"p": "dess",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1070,
"y": 460,
"wires": [
[
"d81811500e0ae9f8"
]
]
},
{
"id": "780ff00a1393a6fe",
"type": "victron-dynamic-ess",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"name": "DEPRECATED",
"vrm_id": "",
"vrmtoken": "",
"country": "",
"contract_buy": "",
"contract_sell": "",
"b_max": 10,
"fb_max": 1.1,
"tb_max": 1.2,
"fg_max": 1,
"tg_max": 1,
"b_cycle_cost": 0,
"buy_price_formula": "p",
"sell_price_formula": "p",
"green_mode_on": true,
"b_goal_hour": 0,
"b_goal_SOC": 0,
"feed_in_possible": true,
"feed_in_control_on": true,
"verbose": false,
"x": 1300,
"y": 320,
"wires": [
[
"1857e6dc9a194fec"
],
[
"7049b7140944117e"
],
[
"76a5b63506d3a697"
],
[
"8533359282a12955"
]
]
},
{
"id": "70fcd76ccd733faf",
"type": "vrm-api",
"z": "d457e88372dcd44a",
"g": "ddb754a848a5437c",
"vrm": "",
"name": "",
"api_type": "dynamic-ess",
"idUser": "",
"users": "",
"idSite": "",
"installations": "",
"attribute": "",
"stats_interval": "",
"show_instance": false,
"stats_start": "",
"stats_end": "",
"use_utc": false,
"gps_start": "",
"gps_end": "",
"widgets": "",
"instance": "",
"vrm_id": "",
"country": "",
"b_max": "",
"tb_max": "",
"fb_max": "",
"tg_max": "",
"fg_max": "",
"b_cycle_cost": "",
"buy_price_formula": "",
"sell_price_formula": "",
"green_mode_on": "",
"feed_in_possible": "",
"feed_in_control_on": "",
"b_goal_hour": "",
"b_goal_SOC": "",
"store_in_global_context": false,
"verbose": false,
"x": 1080,
"y": 400,
"wires": [
[
"484523849a6134a7"
]
]
}
]