Any Node-Red gurus here?

I need a little more flexibility and control of my geyser and some additional heavy loads I am hopefully adding.

So I decided to replace my old Arduino set-up (ModbusThermostat) with Node-Red.

Now I need to bulk read settings from my Deye/Sunsynk inverter every second, and then reliably turn off the geyser within another second if I exceed maximum server load.

I started with SunSynk-NodeRed, and it works, but reads parameters one at a time, so is rather slow and ridiculously clunky for extending.

Now I am an absolute n00b at Node-Red, so I have no idea of best practices, or how well this will scale, and I was hoping for some advice.

Basically, I keep the Modbus-Flex-Getter from the original project, and set bigger quantities to bulk read parameters.

Then I have this function to decode them, and spit out a stream of parameter messages:

//  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',
  },
};
*/
var regs = global.get('sunsynk_regs');
if(!regs) {
  node.error('Error getting global sunsynk_regs!');
  node.status({ text:'Error getting global sunsynk_regs!'});
}

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];

The regs object has moved to the global context and is loaded from a JSON file, but I kept the originals in comment form, so you know what the object looks like. (Actually, with the eye to properly modularising it, it is 2 files - a system file with defaults and a user file with local overrides.)

Anyway, before I translate 100s of modbus register definitions into JSON configurations, I would like to try get an idea if I am going down the right path here, or will this approach not scale well?

Thanks,
Justin

1 Like

Looking at the function that you posted I suspect that you are not nearly a noob as what you claim.
It seems like it will do what you need it to do and if you get you values from it , go for it.

What you do with these values thereafter is what I would say counts. You could store them in memory (globla.set) for later use in a function or even place them in a SQLite db , even Influx DB should you want to use Grafana.
It all depends on what you want to keep/use within al those 100s of register’s and discard the rest.

Thanks. I have done some javascript work before. Just nothing in Node-Red. So I have no idea of best practices or performance constraints.

I have spent some time playing around, and the above code seems to work well enough, even if it is not very efficient. IIRC javascript object dictionaries are not hashed, so the register lookup is probably the big performance penalty. But for now, it is probably ‘good enough’.