Skip to content
View in the app

A better way to browse. Learn more.

Power Forum - Renewable Energy Discussion

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

SunSynk - Inverter Monitoring

Featured Replies

  • Replies 734
  • Views 205.8k
  • Created
  • Last Reply

Top Posters In This Topic

Most Popular Posts

  • Thanks to @Bloubul7and all the other contributors. This is my HA dashboard. It has all I need to view at a glance. (PS: really impressed with the Sunsynk)  

  • Thanks for sharing. Did not know about the horseshoe or plotly cards. Added to Dashboard  

  • Think I figured it out. Copied the Raw Config file. EDIT: Open the file at the bottom with notepad or Text Editor. Copy and paste in Dashboard "Raw configuration editor" You need to install

Posted Images

14 minutes ago, GVC said:

Thanks to @Bloubul7and all the other contributors. This is my HA dashboard. It has all I need to view at a glance. (PS: really impressed with the Sunsynk)

 

Screenshot from 2023-01-02 07-18-16.png

I want to add, that 3 metrics exposed on the top, thats some good ergonomics.  It just eases and routes the eye towards the important stuff. 

Pity that 7 and 10 inch TFT displays are expensive, would be great to have that on permanent display. 

For sure.... That is the custom Flex-Horseshoe-Card. Been using it since a couple of inverters ago.

Edit: I am running it on an old 27-inch Dell monitor.

 

Edited by GVC

1 hour ago, GVC said:

Thanks to @Bloubul7and all the other contributors. This is my HA dashboard. It has all I need to view at a glance. (PS: really impressed with the Sunsynk)

 

Screenshot from 2023-01-02 07-18-16.png

This is pretty. Care to share the dashboard json?

Think I figured it out. Copied the Raw Config file.

EDIT: Open the file at the bottom with notepad or Text Editor. Copy and paste in Dashboard "Raw configuration editor"

You need to install the following custom cards:

card-mod

Flexible Horseshoe card

Layout card

Atomic Calendar Revive card

Mushroom card

Plotly Graph card

Sunsynk card (manual download from @slipx

 

Home Assistant Dashboard

Edited by GVC
Added resources

41 minutes ago, GVC said:

Think I figured it out. Copied the Raw Config file.

EDIT: Open the file at the bottom with notepad or Text Editor. Copy and paste in Dashboard "Raw configuration editor"

You need to install the following custom cards:

card-mod

Flexible Horseshoe card

Layout card

Atomic Calendar Revive card

Mushroom card

Plotly Graph card

Sunsynk card (manual download from @slipx

 

Home Assistant Dashboard 50.37 kB · 1 download

Nice one, thanks!


 

On 2023/01/02 at 7:30 AM, GVC said:

Thanks to @Bloubul7and all the other contributors. This is my HA dashboard. It has all I need to view at a glance. (PS: really impressed with the Sunsynk)

 

Screenshot from 2023-01-02 07-18-16.png

Thanks for sharing. Did not know about the horseshoe or plotly cards. Added to Dashboard

image.thumb.png.fc83c32cf6bd4bdcdf7d105f257c5923.png

 

Edited by slipx

Wow slipx! please can you share your dash with me- it's proper!
 

On 2023/01/02 at 9:02 PM, slipx said:


 

Thanks for sharing. Did not know about the horseshoe or plotly cards. Added to Dashboard

image.thumb.png.fc83c32cf6bd4bdcdf7d105f257c5923.png

 

 

I hate asking stuff like this, but without reading through all 25 pages... does anyone know of a good USB-RS485 cable to get for communicating with the Sunsynks? Im most likely going to use it through a Raspberry pi.

1 hour ago, RocketBoy said:

I hate asking stuff like this, but without reading through all 25 pages... does anyone know of a good USB-RS485 cable to get for communicating with the Sunsynks? Im most likely going to use it through a Raspberry pi.

Lol, and that ain't the half of it. 

There are good instructions on getting it to work on @kellerza 's Github page 

https://github.com/kellerza/sunsynk

3 hours ago, RocketBoy said:

I hate asking stuff like this, but without reading through all 25 pages... does anyone know of a good USB-RS485 cable to get for communicating with the Sunsynks? Im most likely going to use it through a Raspberry pi.

I went through all the suggestions. This was the one that was easiest and worked the best for me:

https://solar-assistant.io/shop/products/sunsynk_rs485

22 hours ago, JuanH said:

I went through all the suggestions. This was the one that was easiest and worked the best for me:

https://solar-assistant.io/shop/products/sunsynk_rs485

There is probably nothing wrong with the cable, but if I see a pre made-up cable, I always wonder: Do you cut the connector off to route the cable through sprague & the cable glands, or do you cut the cable gland to make the connector fit? 

(And if you use a RJ45 inline extender, then you still need a crimping tool 😉)

On 2023/01/17 at 4:17 PM, ridwan said:

It a bit expensive, but the victron cable worked very well for me. 

I have a spare Victron cable if anybody's interested in one.  Still sealed and unopened in its bag.

I have just started playing with node-red to try move my geyser control from Arduino for easier automation and remote management.

To do this, I need to read a block of values every second. Doing this register by register is just way too inefficient, so I need to read them in bulk and then process the results sequentially.

I have never used node-red before, so I am not sure what will work best.

For testing, I have created a decoder function based on https://github.com/jacauc/SunSynk-NodeRed :

//  per register
//   props = properties of new message object
//   conv = conversion function to get payload.value from modbus response data
//   scale = (optional) scaling factor to apply to payload.value after conversion
//   skip = (optional) do not produce output for this register
//
//  conversion algorithms
//   s16 = signed 16 bit
//   u16 = unsigned 16 bit
//   temp = sunsynk temperature value
const regs = {
  '182': {
    props: {
      topic: 'battery_temp',
      deviceclass: 'battery',
      unit: '°C',
    },
    conv: 'temp',
  },
  '183': {
    props: {
      topic: 'battery_volt',
      deviceclass: 'battery',
      unit: 'V',
    },
    conv: 'u16',
    scale: 0.01,
  },
  '184': {
    props: {
      topic: 'battery_soc',
      deviceclass: 'battery',
      unit: '%',
    },
    conv: 's16',
  },
};

// paranoia
if (msg.values.length != msg.modbusRequest.quantity) {
  node.warn("Read failed - response length does not match request...");
  return null;
}
var base = msg.modbusRequest.address;
//node.warn("start: "+base);
var outs = [];
var i = 0;
while(i < msg.values.length) {
  var reg = base + i;
  var rem = msg.values.length - i;
  //node.warn("reg: "+reg);
  //node.warn("remain: " + rem);
  if(!(reg in regs)) {
    //node.warn('key not found:'+reg)
    i++;
    continue;
  }
  var config = regs[reg];
  //node.warn("config: "+config);
  if("skip" in config && config.skip) {
    node.warn('key set to skip:' + reg)
    i++;
    continue;
  }
  var newmsg = Object.assign({}, config.props);
  if(config.conv == 's16') {
    var val = (msg.values[i] + 0);
    if(val > 32767) {
      val = val - 65535;
    }
    newmsg.payload = val;
  } else if (config.conv == 'u16') {
    newmsg.payload = (msg.values[i] + 0);
  } else if (config.conv == 'temp') {
    newmsg.payload = (msg.values[i] - 1000) / 10;
  } else {
    node.warn('conversion function not found:' + config.conv);
    i++;
    continue;
  }
  if("scale" in config) {
    newmsg.payload *= config.scale;
  }
  outs.push(newmsg);
  i++;
}
//node.warn("outs: "+outs.length);
return [outs];

So, issue a bulk read to Modbus-Flex-Getter ( {"fc": 3,"unitid": 1,"address":180,"quantity":10} ) - pass the result into the above function, and it spits out a stream of messages for each configured register.

From the outset, that 'regs' array should not be defined here.  Probably an external JSON file loaded into global context and referenced from there.

Other than that, what do the node-red experts think.  Will this scale efficiently if I extend 'regs' to include all registers of interest?

26 minutes ago, JustinSchoeman said:

I have just started playing with node-red to try move my geyser control from Arduino for easier automation and remote management.

To do this, I need to read a block of values every second. Doing this register by register is just way too inefficient, so I need to read them in bulk and then process the results sequentially.

I have never used node-red before, so I am not sure what will work best.

For testing, I have created a decoder function based on https://github.com/jacauc/SunSynk-NodeRed :

//  per register
//   props = properties of new message object
//   conv = conversion function to get payload.value from modbus response data
//   scale = (optional) scaling factor to apply to payload.value after conversion
//   skip = (optional) do not produce output for this register
//
//  conversion algorithms
//   s16 = signed 16 bit
//   u16 = unsigned 16 bit
//   temp = sunsynk temperature value
const regs = {
  '182': {
    props: {
      topic: 'battery_temp',
      deviceclass: 'battery',
      unit: '°C',
    },
    conv: 'temp',
  },
  '183': {
    props: {
      topic: 'battery_volt',
      deviceclass: 'battery',
      unit: 'V',
    },
    conv: 'u16',
    scale: 0.01,
  },
  '184': {
    props: {
      topic: 'battery_soc',
      deviceclass: 'battery',
      unit: '%',
    },
    conv: 's16',
  },
};

// paranoia
if (msg.values.length != msg.modbusRequest.quantity) {
  node.warn("Read failed - response length does not match request...");
  return null;
}
var base = msg.modbusRequest.address;
//node.warn("start: "+base);
var outs = [];
var i = 0;
while(i < msg.values.length) {
  var reg = base + i;
  var rem = msg.values.length - i;
  //node.warn("reg: "+reg);
  //node.warn("remain: " + rem);
  if(!(reg in regs)) {
    //node.warn('key not found:'+reg)
    i++;
    continue;
  }
  var config = regs[reg];
  //node.warn("config: "+config);
  if("skip" in config && config.skip) {
    node.warn('key set to skip:' + reg)
    i++;
    continue;
  }
  var newmsg = Object.assign({}, config.props);
  if(config.conv == 's16') {
    var val = (msg.values[i] + 0);
    if(val > 32767) {
      val = val - 65535;
    }
    newmsg.payload = val;
  } else if (config.conv == 'u16') {
    newmsg.payload = (msg.values[i] + 0);
  } else if (config.conv == 'temp') {
    newmsg.payload = (msg.values[i] - 1000) / 10;
  } else {
    node.warn('conversion function not found:' + config.conv);
    i++;
    continue;
  }
  if("scale" in config) {
    newmsg.payload *= config.scale;
  }
  outs.push(newmsg);
  i++;
}
//node.warn("outs: "+outs.length);
return [outs];

So, issue a bulk read to Modbus-Flex-Getter ( {"fc": 3,"unitid": 1,"address":180,"quantity":10} ) - pass the result into the above function, and it spits out a stream of messages for each configured register.

From the outset, that 'regs' array should not be defined here.  Probably an external JSON file loaded into global context and referenced from there.

Other than that, what do the node-red experts think.  Will this scale efficiently if I extend 'regs' to include all registers of interest?

While I cannot really comment on where you want to store these registers in Node-Red, I can comment on the concept behind bulk reading. And agree that it makes a lot of sense!

A call to read the RS485 holding registers needs a start and a length, so you obviously want to read the optimal length. Since all the registers you need are not sequential, you will have to group your reads. There is a couple of factors you should keep in mind. Sometimes it might make sense to read a register or two that you do not need, since skipping one might be expensive. With some hardware the size of the blocks you can read can be limited.

Once you've figured out what registers you need, you can have a look at what we do in the Sunsynk Python library to group these - groups 

Btw with the library it's easy to react within a second or two to a major load/power change. The idea from the start was that I can control loads, and even remove them if the inverter goes above its rated 5Kw output. In reality the solution was much simpler, and I ended up simply spreading my heavy loads through the day (geyser & pool pump+heatpump).

 

I already have everything working (batched reads and such) on my Arduino setup:

https://github.com/justinschoeman/ModbusThermostat/blob/master/SunsynkController/sunsynk.h

Been running flawlessly 24/7 for over 2 years now.

But now I would like to add some UI components and flexible load management for more loads (with priorities and overrides).

I could extend the Arduino code to do this. I could also do it in Python. But both would require a lot of UI development around it.

Node-red gives me a UI with the flexibility I require.  But I have 0 experience in it, and would appreciate some feedback on my implementation choices.

If, at the same time, I can preserve the basics of the existing node-red project, then I can steal the logging and dashboarding goodness that has already been developed.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.