I ended up with this as a test. It calculates whether or not supplemental charging would be required to complete a full charge of my off-grid battery.
Basic logic is to estimate out how much PV output is expected from the off-grid PV array for the remainder of the day (a bit convoluted due to the available entities I have to work with, plus some allowances for error/inefficiencies), and compare that with how much energy is currently required to charge the battery to 100%.
[{"id":"4e91b577f9dc2162","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - Today's Combined Array Total","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_forecast_today","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecasttoday","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":380,"y":820,"wires":[["cd43495a2e709e6a"]]},{"id":"845e2d4da2a88c34","type":"inject","z":"eafe579046581a4e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":820,"wires":[["4e91b577f9dc2162"]]},{"id":"cd43495a2e709e6a","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - Remaining Today","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_forecast_remaining_today","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecastremaining","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":340,"y":880,"wires":[["12182a3aba5abe7b"]]},{"id":"12182a3aba5abe7b","type":"api-current-state","z":"eafe579046581a4e","name":"PV Forecast - OffGrid Array","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.solcast_wattmatters_garage","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"forecastgarage","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":320,"y":940,"wires":[["59e291b3ef1668c1"]]},{"id":"59e291b3ef1668c1","type":"api-current-state","z":"eafe579046581a4e","name":"Battery SOC","server":"58a17342.ac5f9c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_state_of_charge","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"batterySOC","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":270,"y":1000,"wires":[["a611421366c0e28a"]]},{"id":"a611421366c0e28a","type":"function","z":"eafe579046581a4e","name":"Calculate PV Surplus/Deficit","func":"msg.payload = 0.8 * ((msg.forecastremaining / msg.forecasttoday) * msg.forecastgarage) - ((100 - msg.batterySOC) / 10);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":1060,"wires":[["284967eb18418534","2bb7a68b48da92b4"]]},{"id":"284967eb18418534","type":"debug","z":"eafe579046581a4e","name":"Expected PV Surplus/Deficit","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":1060,"wires":[]},{"id":"2bb7a68b48da92b4","type":"switch","z":"eafe579046581a4e","name":"Supplemental Charging Required?","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"0","vt":"str"},{"t":"gte","v":"0","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":350,"y":1140,"wires":[["95a6279f5440517c"],["4a1c403cf26b20b9"]]},{"id":"95a6279f5440517c","type":"change","z":"eafe579046581a4e","name":"Supplemental charge IS required","rules":[{"t":"set","p":"payload","pt":"msg","to":"Yes","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":1120,"wires":[["e7cda27faa7a98fb"]]},{"id":"4a1c403cf26b20b9","type":"change","z":"eafe579046581a4e","name":"Supplemental charge IS NOT required","rules":[{"t":"set","p":"payload","pt":"msg","to":"No","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":1160,"wires":[["e7cda27faa7a98fb"]]},{"id":"e7cda27faa7a98fb","type":"debug","z":"eafe579046581a4e","name":"Is Supplemental Charging Required?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1070,"y":1120,"wires":[]},{"id":"58a17342.ac5f9c","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]
No doubt there are far more efficient ways of doing it but it’s a start.
With this I can choose whether to set my system to turn on/off supplemental charging from the grid-tied PV array.
That will be determined by whether the grid-tied PV array has sufficient excess energy available, i.e. is exporting enough power to the grid to supply supplemental charging. This avoid grid imports but also unnecessary use of supplemental charging which otherwise could earn export credits.