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