Follow sunset/sunrise in VRM DESS Trade mode
This Node-RED flow automates setting battery discharge restrictions for a Victron Energy system based on sunrise and sunset times for a given location. Here's a breakdown of the flow:
Daily Injection (426f5b74668d1a6b): This node triggers the flow daily at 22:00 (10 PM) in your local timezone. It injects a timestamp, but the payload isn't actually used later in the flow. The important part is the scheduled time.
Sun Position Calculation (37c9a6df5ed98310): This
suncron
node calculates sunrise and sunset times based on the provided latitude (48.9147167) and longitude (24.6682185). Important: You should change these coordinates to your actual location for accurate sunrise/sunset times. The node outputs an object containing these times.Function Node - Schedule Creation (e0b6c70677569798): This is the core logic of the flow. It takes the output from the
suncron
node and creates a battery discharge schedule.- It extracts the sunrise and sunset times from the
suncron
output. - It constructs a schedule array with three entries:
00:00
tosunrise
: Restrict discharge (presumably to prioritize charging from solar).sunrise
tosunset
: Allow discharge (to use stored energy when solar is unavailable).sunset
to00:00
: Restrict discharge again.
- It formats this schedule into the structure required by the Victron VRM API. Specifically, it creates a JSON string representing an array containing a single object with
days
(0-6 for all days of the week) and theschedule
as defined above. - Crucially, it clears the entire
msg
object before setting the new payload. This is essential to prevent unintended data from previous nodes from interfering with the VRM API call. - If the
suncron
data is invalid or missing, it logs a warning and sets an empty array as the payload to avoid errors.
- It extracts the sunrise and sunset times from the
VRM API Call (1d4ac16e0acc5e6a): This node sends the generated schedule to the Victron VRM API.
vrm
(33cf008ea8e9d911): This configuration node stores your VRM API credentials. You'll need to configure this with your actual VRM portal ID, access token, etc.idSite
: THIS IS THE MOST IMPORTANT PART TO CHANGE. TheidSite
field is set to000000
. You MUST replace000000
with the actual ID of your VRM site. This ID identifies the specific installation you're controlling. You can find this ID in your VRM portal URL or by using the VRM API directly to list your installations.- The
api_type
is set toinstallations
andinstallations
topatch-dynamic-ess-settings
, indicating that this call is updating the dynamic ESS settings. - The
payload
of this node comes from the function node and contains the JSON string of the battery discharge schedule.
Debug Node (be370ca5931e2729): This node is used for debugging. It's currently inactive. If you activate it, it will display the messages passing through the flow, which can be useful for troubleshooting.
In summary: The flow retrieves sunrise/sunset times, creates a battery discharge schedule based on these times, and sends that schedule to the Victron VRM API to dynamically adjust the ESS behavior. The critical step is to replace the placeholder 000000
in the idSite
field of the VRM API node with your actual VRM site ID. Without this change, the flow will not work correctly and will likely result in errors.
[{"id":"d7b06853644b688b","type":"group","z":"1fb7f5b976e694f6","name":"Set battery discharge restrictions based on sunrise sunset - maximize Sun generation","style":{"label":true},"nodes":["426f5b74668d1a6b","be370ca5931e2729","37c9a6df5ed98310","e0b6c70677569798","1d4ac16e0acc5e6a"],"x":34,"y":519,"w":792,"h":322},{"id":"426f5b74668d1a6b","type":"inject","z":"1fb7f5b976e694f6","g":"d7b06853644b688b","name":"Daily at 22:00 Your Timezone","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"00 22 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":560,"wires":[["37c9a6df5ed98310"]]},{"id":"be370ca5931e2729","type":"debug","z":"1fb7f5b976e694f6","g":"d7b06853644b688b","name":"All object debug","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":700,"y":740,"wires":[]},{"id":"37c9a6df5ed98310","type":"suncron","z":"1fb7f5b976e694f6","g":"d7b06853644b688b","name":"Set Your Location coordinates here","lat":"48.9147167","lon":"24.6682185","replay":false,"ejectScheduleOnUpdate":false,"sunrisePayload":"1","sunrisePayloadType":"num","sunriseTopic":"sunrise","sunriseOffsetType":1,"sunriseOffsetHours":0,"sunriseOffsetMinutes":0,"sunriseOffset":0,"sunriseEndPayload":"","sunriseEndPayloadType":"str","sunriseEndTopic":"","sunriseEndOffsetType":1,"sunriseEndOffsetHours":0,"sunriseEndOffsetMinutes":0,"sunriseEndOffset":0,"goldenHourEndPayload":"","goldenHourEndPayloadType":"str","goldenHourEndTopic":"","goldenHourEndOffsetType":1,"goldenHourEndOffsetHours":0,"goldenHourEndOffsetMinutes":0,"goldenHourEndOffset":0,"solarNoonPayload":"","solarNoonPayloadType":"str","solarNoonTopic":"","solarNoonOffsetType":1,"solarNoonOffsetHours":0,"solarNoonOffsetMinutes":0,"solarNoonOffset":0,"goldenHourPayload":"","goldenHourPayloadType":"str","goldenHourTopic":"","goldenHourOffsetType":1,"goldenHourOffsetHours":0,"goldenHourOffsetMinutes":0,"goldenHourOffset":0,"sunsetStartPayload":"","sunsetStartPayloadType":"str","sunsetStartTopic":"","sunsetStartOffsetType":1,"sunsetStartOffsetHours":0,"sunsetStartOffsetMinutes":0,"sunsetStartOffset":0,"sunsetPayload":"1","sunsetPayloadType":"num","sunsetTopic":"sunset","sunsetOffsetType":1,"sunsetOffsetHours":0,"sunsetOffsetMinutes":0,"sunsetOffset":0,"duskPayload":"","duskPayloadType":"str","duskTopic":"","duskOffsetType":1,"duskOffsetHours":0,"duskOffsetMinutes":0,"duskOffset":0,"nauticalDuskPayload":"","nauticalDuskPayloadType":"str","nauticalDuskTopic":"","nauticalDuskOffsetType":1,"nauticalDuskOffsetHours":0,"nauticalDuskOffsetMinutes":0,"nauticalDuskOffset":0,"nightPayload":"","nightPayloadType":"str","nightTopic":"","nightOffsetType":1,"nightOffsetHours":0,"nightOffsetMinutes":0,"nightOffset":0,"nadirPayload":"","nadirPayloadType":"str","nadirTopic":"","nadirOffsetType":1,"nadirOffsetHours":0,"nadirOffsetMinutes":0,"nadirOffset":0,"nightEndPayload":"","nightEndPayloadType":"str","nightEndTopic":"","nightEndOffsetType":1,"nightEndOffsetHours":0,"nightEndOffsetMinutes":0,"nightEndOffset":0,"nauticalDawnPayload":"","nauticalDawnPayloadType":"str","nauticalDawnTopic":"","nauticalDawnOffsetType":1,"nauticalDawnOffsetHours":0,"nauticalDawnOffsetMinutes":0,"nauticalDawnOffset":0,"dawnPayload":"","dawnPayloadType":"str","dawnTopic":"","dawnOffsetType":1,"dawnOffsetHours":0,"dawnOffsetMinutes":0,"dawnOffset":0,"x":260,"y":800,"wires":[["e0b6c70677569798"]]},{"id":"e0b6c70677569798","type":"function","z":"1fb7f5b976e694f6","g":"d7b06853644b688b","name":"Set battery discharge restrictions based on sunrise sunset","func":"const suncronData = msg;\n\nif (suncronData && suncronData.schedule && suncronData.schedule.sunrise && suncronData.schedule.sunset) {\n const sunriseTime = new Date(suncronData.schedule.sunrise.sunEventTime);\n const sunsetTime = new Date(suncronData.schedule.sunset.sunEventTime);\n\n const schedule = [ // Creating the inner schedule array directly\n {\n from: \"00:00\",\n to: sunriseTime.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }),\n restrict: true\n },\n {\n from: sunriseTime.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }),\n to: sunsetTime.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }),\n restrict: false\n },\n {\n from: sunsetTime.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }),\n to: \"00:00\", // or \"00:00\" for the next day\n restrict: true\n }\n ];\n\n const batteryDischargeRestrictionSchedule = {\n days: [0, 1, 2, 3, 4, 5, 6],\n schedule: schedule // Assign the schedule array\n };\n\n msg = {'payload': {}}; // Important: Clear the entire msg object\n\n msg.payload = {'batteryDischargeRestrictionSchedule': JSON.stringify([ // Creating the array with the object inside\n {\n days: batteryDischargeRestrictionSchedule.days,\n schedule: batteryDischargeRestrictionSchedule.schedule\n }\n ])};\n\n\n} else {\n node.warn(\"Invalid or missing suncron data. Check if 'schedule', 'sunrise', and 'sunset' properties exist.\");\n msg.payload = []; // or a default schedule if you have one. Returning an empty array to match expected format.\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":640,"wires":[["be370ca5931e2729","1d4ac16e0acc5e6a"]]},{"id":"1d4ac16e0acc5e6a","type":"vrm-api","z":"1fb7f5b976e694f6","g":"d7b06853644b688b","vrm":"33cf008ea8e9d911","name":"Update Dynamic ESS configuration","api_type":"installations","idUser":"","users":"","idSite":"000000","installations":"patch-dynamic-ess-settings","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":true,"x":640,"y":800,"wires":[["be370ca5931e2729"]]},{"id":"33cf008ea8e9d911","type":"config-vrm-api","name":"VRM"}]