I’ve currently solved it using Node-RED, and it works very well. It is controlled mainly via the charging voltage; the charging current has been adjusted for my seven Pylontech batteries and serves as a reserve. If something like this could be implemented, I think it would help everyone, regardless of whether they use US2000C, US3000C or US5000C. Here, the system simply reacts when a cell rises too quickly. You can take a look at it and decide for yourselves; perhaps it can even be improved further. [
{
"id": "tab_pylon_dyn_cell_protect",
"type": "tab",
"label": "Pylontech Dyn. Zellschutz",
"disabled": false,
"info": "",
"env": \[\]
},
{
"id": "set_topic_soc",
"type": "change",
"z": "tab_pylon_dyn_cell_protect",
"name": "topic = soc",
"rules": \[
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "soc",
"tot": "str"
}
\],
"x": 590,
"y": 140,
"wires": \[
\[
"logic_dyn_cell_protect"
\]
\]
},
{
"id": "set_topic_cell",
"type": "change",
"z": "tab_pylon_dyn_cell_protect",
"name": "topic = cell_volt",
"rules": \[
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "cell_volt",
"tot": "str"
}
\],
"x": 600,
"y": 200,
"wires": \[
\[
"logic_dyn_cell_protect"
\]
\]
},
{
"id": "set_topic_bat",
"type": "change",
"z": "tab_pylon_dyn_cell_protect",
"name": "topic = bat_volt",
"rules": \[
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "bat_volt",
"tot": "str"
}
\],
"x": 600,
"y": 260,
"wires": \[
\[
"logic_dyn_cell_protect"
\]
\]
},
{
"id": "logic_dyn_cell_protect",
"type": "function",
"z": "tab_pylon_dyn_cell_protect",
"name": "SOC-Rampe & Dyn. Zellschutz (Ist-Spannung)",
"func": "if (msg.topic === 'soc') {\\n let raw = (typeof msg.payload === 'object' && msg.payload !== null) ? msg.payload.value : msg.payload;\\n if (!isNaN(Number(raw))) {\\n context.set('currentSOC', Number(raw));\\n }\\n} else if (msg.topic === 'cell_volt') {\\n let raw = (typeof msg.payload === 'object' && msg.payload !== null) ? msg.payload.value : msg.payload;\\n if (!isNaN(Number(raw))) {\\n context.set('maxCellVolt', Number(raw));\\n }\\n} else if (msg.topic === 'bat_volt') {\\n let raw = (typeof msg.payload === 'object' && msg.payload !== null) ? msg.payload.value : msg.payload;\\n if (!isNaN(Number(raw))) {\\n context.set('batVolt', Number(raw));\\n }\\n}\\n\\nlet soc = context.get('currentSOC');\\nlet maxCellVolt = context.get('maxCellVolt') || 0;\\nlet batVolt = context.get('batVolt');\\n\\nif (soc === undefined || isNaN(soc)) {\\n return null;\\n}\\n\\nlet state = context.get('state') || 'UNKNOWN';\\n\\nif (soc >= 95) {\\n context.set('state', 'LIMITED');\\n\\n let boundedSoc = Math.min(100, soc);\\n let targetVoltage = 51.30 + ((boundedSoc - 95) \* 0.26);\\n\\n let targetCurrent = 50;\\n if (soc >= 98) {\\n targetCurrent = 10;\\n } else if (soc >= 97) {\\n targetCurrent = 25;\\n }\\n\\n if (maxCellVolt >= 3.55 && batVolt !== undefined && !isNaN(batVolt)) {\\n targetVoltage = Math.min(targetVoltage, batVolt - 0.10);\\n }\\n\\n targetVoltage = Math.max(51.00, Math.round(targetVoltage \* 100) / 100);\\n\\n return \[\\n { payload: targetCurrent },\\n { payload: targetVoltage }\\n \];\\n} else if (soc < 92) {\\n if (state !== 'NORMAL') {\\n context.set('state', 'NORMAL');\\n \\n return \[\\n { payload: 256 },\\n { payload: 52.50 }\\n \];\\n }\\n}\\n\\nreturn null;",
"outputs": 2,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": \[\],
"x": 900,
"y": 200,
"wires": \[
\[
"c0446d57e9897113"
\],
\[
"26265e3945cea9bc"
\]
\]
},
{
"id": "4d0ad8730f7884d4",
"type": "victron-input-battery",
"z": "tab_pylon_dyn_cell_protect",
"service": "com.victronenergy.battery/512",
"path": "/System/MaxCellVoltage",
"serviceObj": {
"service": "com.victronenergy.battery/512",
"name": "Pylontech battery",
"communityTag": "battery"
},
"pathObj": {
"path": "/System/MaxCellVoltage",
"type": "float",
"name": "System; maximum cell voltage (V DC)"
},
"name": "",
"onlyChanges": false,
"roundValues": "no",
"rateLimit": 0,
"conditionalMode": false,
"condition1HysteresisEnabled": false,
"condition1HysteresisThreshold": "",
"outputTrue": "true",
"outputFalse": "false",
"debounce": "2000",
"x": 210,
"y": 200,
"wires": \[
\[
"set_topic_cell"
\]
\]
},
{
"id": "ee9b01cb0bc4025a",
"type": "victron-input-battery",
"z": "tab_pylon_dyn_cell_protect",
"service": "com.victronenergy.battery/512",
"path": "/Dc/0/Voltage",
"serviceObj": {
"service": "com.victronenergy.battery/512",
"name": "Pylontech battery",
"communityTag": "battery"
},
"pathObj": {
"path": "/Dc/0/Voltage",
"type": "float",
"name": "Battery voltage (V)"
},
"name": "",
"onlyChanges": false,
"roundValues": "no",
"rateLimit": 0,
"conditionalMode": false,
"condition1HysteresisEnabled": false,
"condition1HysteresisThreshold": "",
"outputTrue": "true",
"outputFalse": "false",
"debounce": "2000",
"x": 150,
"y": 260,
"wires": \[
\[
"set_topic_bat"
\]
\]
},
{
"id": "0470b3957b684ae8",
"type": "victron-input-battery",
"z": "tab_pylon_dyn_cell_protect",
"service": "com.victronenergy.battery/512",
"path": "/Soc",
"serviceObj": {
"service": "com.victronenergy.battery/512",
"name": "Pylontech battery",
"communityTag": "battery"
},
"pathObj": {
"path": "/Soc",
"type": "float",
"name": "State of charge (%)"
},
"name": "",
"onlyChanges": false,
"roundValues": "no",
"rateLimit": 0,
"conditionalMode": false,
"condition1HysteresisEnabled": false,
"condition1HysteresisThreshold": "",
"outputTrue": "true",
"outputFalse": "false",
"debounce": "2000",
"x": 150,
"y": 140,
"wires": \[
\[
"set_topic_soc"
\]
\]
},
{
"id": "c0446d57e9897113",
"type": "victron-output-ess",
"z": "tab_pylon_dyn_cell_protect",
"service": "com.victronenergy.settings",
"path": "/Settings/SystemSetup/MaxChargeCurrent",
"serviceObj": {
"service": "com.victronenergy.settings",
"name": "Venus settings",
"communityTag": "ess"
},
"pathObj": {
"path": "/Settings/SystemSetup/MaxChargeCurrent",
"type": "float",
"name": "DVCC Charge current limit (A)",
"mode": "both"
},
"name": "DVCC Charge Current (A)",
"onlyChanges": true,
"conditionalMode": false,
"condition1HysteresisEnabled": false,
"condition1HysteresisThreshold": "",
"outputTrue": "",
"outputFalse": "",
"debounce": "",
"x": 1170,
"y": 140,
"wires": \[\]
},
{
"id": "26265e3945cea9bc",
"type": "victron-output-ess",
"z": "tab_pylon_dyn_cell_protect",
"service": "com.victronenergy.settings",
"path": "/Settings/SystemSetup/MaxChargeVoltage",
"serviceObj": {
"service": "com.victronenergy.settings",
"name": "Venus settings",
"communityTag": "ess"
},
"pathObj": {
"path": "/Settings/SystemSetup/MaxChargeVoltage",
"type": "float",
"name": "DVCC Maximum charge voltage (V)",
"mode": "both"
},
"name": "DVCC Max Charge Voltage ESS (V)",
"onlyChanges": true,
"conditionalMode": false,
"condition1HysteresisEnabled": false,
"condition1HysteresisThreshold": "",
"outputTrue": "",
"outputFalse": "",
"debounce": "",
"x": 1210,
"y": 260,
"wires": \[\]
},
{
"id": "c7bb500a958ef4d5",
"type": "global-config",
"env": \[\],
"modules": {
"@victronenergy/node-red-contrib-victron": "1.7.23"
}
}
]
Pylontech Dyn. Zellschutz.zip (1.7 KB)