Modbus SE10K-RWB48BFN4

Hello,

I'm trying to read data from my SolarEdge SE10K-RWB48BFN4 with a 48V home battery via Modbus (TCP). This works mostly, except for registers 40226 to 40242. These are the M_Exported and M_Imported registers with their corresponding SF (40242).

I'm getting values ​​that I can't match to the ones in the SolarEdge portal.

Has anyone successfully read these registers?

Best regards,

Martin

verify that you are asking for one register for int16

Thanks for the reply.

The registers are uint32 with size 2. I'm querying the int16(be) register with this function:

[// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);

// Create influxdb JSON
msg.payload = [
    [{
        'AC Total Current':      round(uint16(40072) * scalefactor(40076), 2),
        // 'AC Current phase A':    round(uint16(40073) * scalefactor(40076), 2),
        // 'AC Current phase B':    round(uint16(40074) * scalefactor(40076), 2),
        // 'AC Current phase C':    round(uint16(40075) * scalefactor(40076), 2),
        // 'AC Voltage phase A':    round(uint16(40080) * scalefactor(40083), 2),
        // 'AC Voltage phase B':    round(uint16(40081) * scalefactor(40083), 2),
        // 'AC Voltage phase C':    round(uint16(40082) * scalefactor(40083), 2),
        'AC Power output':        round(int16(40084) * scalefactor(40085), 2),
        'AC Lifetimeproduction': round(uint32(40094) * scalefactor(40096), 2),
        'DC Current':            round(uint16(40097) * scalefactor(40098), 2),
        'DC Voltage':            round(uint16(40099) * scalefactor(40100), 2),
        'DC Power input':         round(int16(40101) * scalefactor(40102), 2),
        'Heat sink temp':         round(int16(40104) * scalefactor(40107), 2),
        // 'M_AC_Power':             round(int16(40207) * scalefactor(40207), 2),
        'Status':                round(uint16(40108), 2),
         
        time: new Date()
    },
    {
        inverter: '1'
    }]
];


return msg;

function word(address) {
    // Find the correct offset in bytes
    // 40070 is the starting address we fetch from SolarEdge inverter
    return (address-40070) * 2;
}

function scalefactor(address) {
    return Math.pow(10, buf.readInt16BE(word(address)));
}

function int16(address) {
    return buf.readInt16BE(word(address))
}

function uint16(address) {
    return buf.readUInt16BE(word(address));
}

function int32(address) {
    return buf.readInt32BE(word(address))
}

function uint32(address) {
    return buf.readUInt32BE(word(address))
}

function round(value, decimals) {
 return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
} ]

The problem I see is querying registers 40207 and 40242.
I don't know how to query them all at once.

Regards

Martin

The node-red-contrib-buffer-parser makes this all no-code and simplifies converting multiple registers to required format

tried using buffer-parser, but the result isn't good.

[{"id":"c0b7a2f6197b21ab","type":"tab","label":"Flow with buffer-parser","disabled":false,"info":"","env":[]},{"id":"c6057c46c76bb8a6","type":"buffer-parser","z":"c0b7a2f6197b21ab","name":"M_AC_Power","data":"payload.buffer","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"int16be","name":"M_AC_Power","offset":0,"length":5,"offsetbit":0,"scale":"1","mask":""},{"type":"uint32be","name":"M_AC_Energie","offset":40,"length":16,"offsetbit":0,"scale":"1","mask":""},{"type":"uint16be","name":"M_AC_Energie_SF17","offset":42,"length":1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"value","resultTypeType":"return","multipleResult":true,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":640,"y":280,"wires":[["823d9e922605a40b"]]},{"id":"73a8bc1b06ec9426","type":"modbus-flex-getter","z":"c0b7a2f6197b21ab","name":"","showStatusActivities":true,"showErrors":true,"showWarnings":true,"logIOActivities":false,"server":"d37bdace40c5d6c7","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":false,"delayOnStart":false,"enableDeformedMessages":false,"startDelayTime":"","x":410,"y":280,"wires":[[],["c6057c46c76bb8a6"]]},{"id":"de8eb1c99cd80026","type":"inject","z":"c0b7a2f6197b21ab","name":"","props":[{"p":"payload.fc","v":"3","vt":"str"},{"p":"payload.address","v":"40206","vt":"str"},{"p":"payload.quantity","v":"100","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"SE10K-RWB48BFN4 - Meter Power","x":220,"y":160,"wires":[["73a8bc1b06ec9426"]]},{"id":"823d9e922605a40b","type":"debug","z":"c0b7a2f6197b21ab","name":"debug 11","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":880,"y":280,"wires":[]},{"id":"d37bdace40c5d6c7","type":"modbus-client","name":"SE10K-RWS","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"192.168.2.40","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":1,"commandDelay":1,"clientTimeout":1000,"reconnectOnTimeout":true,"reconnectTimeout":2000,"parallelUnitIdsAllowed":true,"showErrors":false,"showWarnings":true,"showLogs":true},{"id":"c684fa1277b2be7e","type":"global-config","env":[],"modules":{"node-red-contrib-buffer-parser":"3.2.2","node-red-contrib-modbus":"5.45.2"}}]

What's wrong with this code? What do I need to improve?

Best regards,

Martin


Shouldn't your offset be 40 not 42?

Since I'm not at a computer for a week or so I can only offer advice like; try various combinations of swap and be/le data types (it depends on where the offset lands, how data is packed by the hardware manufacturer, how it is transmitted down the wire and other hardware factors that can muddy the waters)

How can I format int32 size 2 to an integer?

I would expect h40242 to return a number (1, -1, or something similar),

and I can't get that to work.

For example, the value of h40226 needed to be calculated together with the value of h40242. How do I do that?

I can't even read h40242 on its own right now.

H40210, on the other hand, works very well.

Why do you think that?

All modbus registers are 16bit.

Size 2 is saying 2 registers are required to make up the value.

40227 is the 2nd half of a 32bit value formed by combining 40226 & 40227

Since these are consecutive AND you set the right offset, the selected type (int32be or int32le) knows to read 4 bytes (2*16bits e.g. 32bits).

Thank you so much for your time!

Here's where my troubles begin:

h40226 to h40240 are uint32 size 2 and h40242 is int16 size 1.
That's one of the problems.

That's all just simple maths once you have values in correct format

Did you correct the offset as I mentioned above?

I'm starting with h40206.

Up to h40225, all values ​​are int16 size 1.
From h40226 to h40240, the values ​​are uint32 size 2.
Register h40242 is again int16 size 1, so I thought the offset for h40226 would be 40, and the offset for h40242 must be (40+7*2) 54.

Alternatively, perhaps 40+28=68.

However, I'm getting nowhere with either value.

Hello,

I've solved a problem.

Here's an example of reading the memory temperature (h62828).

This register is float32 and not documented in SunSpec.

Perhaps someone needs this.

What I'm still missing is reading the Imported and Exported values.

Best regards,
Martin

[{"id":"47477fe824209aca","type":"modbus-read","z":"cbf5417ec7d111d1","name":"SolarEdge mit Modbus-Read nur Speicher Temp","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"showWarnings":true,"unitid":"1","dataType":"HoldingRegister","adr":"62828","quantity":"4","rate":"591","rateUnit":"s","delayOnStart":false,"enableDeformedMessages":false,"startDelayTime":"","server":"d37bdace40c5d6c7","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":240,"y":1160,"wires":[[],["8590dfced25ab845"]]},{"id":"8590dfced25ab845","type":"buffer-parser","z":"cbf5417ec7d111d1","name":"","data":"payload.buffer","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"floatle","name":"B_Average_Temp","offset":0,"length":2,"offsetbit":0,"scale":"1","mask":""}],"swap1":"swap16","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"value","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":570,"y":1140,"wires":[["6d1148ec0952cb04"]]},{"id":"6d1148ec0952cb04","type":"function","z":"cbf5417ec7d111d1","name":"Wert vom ersten Feld ausgeben","func":"// Create influxdb JSON\nmsg.payload = [\n    [{\n    'Temperatur Speicher': msg.payload[0][0],\n         \n        time: new Date()\n    },\n    {\n        inverter: '1'\n    }]\n];\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":1140,"wires":[["086c953c5babe1bd","92ef9715d1c3e1cd"]]},{"id":"d37bdace40c5d6c7","type":"modbus-client","name":"SE10K-RWS","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"192.168.2.40","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":1,"commandDelay":1,"clientTimeout":1000,"reconnectOnTimeout":true,"reconnectTimeout":2000,"parallelUnitIdsAllowed":true,"showErrors":false,"showWarnings":true,"showLogs":true},{"id":"07f5da0d9187f6a0","type":"global-config","env":[],"modules":{"node-red-contrib-modbus":"5.45.2","node-red-contrib-buffer-parser":"3.2.2"}}]

According to the SolarEdge SunSpec docs, 40226/40227 are M_Exported (uint32 Wh), 40234/40235 are M_Imported (uint32 Wh), and 40242 is M_Energy_W_SF (int16 scale factor for all those energy values). So the actual values are:

Exported_Wh = M_Exported * 10^(M_Energy_W_SF)
Imported_Wh = M_Imported * 10^(M_Energy_W_SF)

In your flow where you start reading at 40206, the byte offsets should be:

40226 → (40226 - 40206) * 2 = 40
40234 → (40234 - 40206) * 2 = 56
40242 → (40242 - 40206) * 2 = 72

The registers are 16-bit, so offset is (reg - startReg) * 2. In buffer-parser that would look like:

uint32be, name M_Exported, offset 40, length 2
uint32be, name M_Imported, offset 56, length 2
int16be, name M_Energy_W_SF, offset 72, length 1

Then you can do the maths in a Function node. The portal usually shows kWh, so you may need to divide by 1000 to line up with what you see there. If you treat 40242 as a single int16 scale factor, does that fix the problem you're running into? I'm away from my own solar monitoring setup, but once I get back to it I can validate how it's outputting the data to make sure this works properly, but I think it's really just an offset/format issue.

Hello,

Thank you so much for your time.

With your help, I created a function that allows me to assign the values.

// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);

// Create influxdb JSON
msg.payload = [
    [{
        
          'M_Exported':             round(uint32(40226)* scalefactor(40242), 2)/1000,
          'M_Imported':             round(uint32(40234)* scalefactor(40242), 2)/1000,
         
        time: new Date()
    },
    {
        inverter: '1'
    }]
];


return msg;

function word(address) {
    // Find the correct offset in bytes
    // ORIGINAL -> 40070 is the starting address we fetch from SolarEdge inverter
    //40226 is the starting address we fetch from SolarEdge inverter
    return (address-40226) * 2;
}

function scalefactor(address) {
    return Math.pow(10, buf.readInt16BE(word(address)));
}

function int16(address) {
    return buf.readInt16BE(word(address))
}

function uint16(address) {
    return buf.readUInt16BE(word(address));
}

function int32(address) {
    return buf.readInt32BE(word(address))
}

function uint32(address) {
    return buf.readUInt32BE(word(address))
}

function round(value, decimals) {
 return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
} 

I was also able to read the battery values ​​from the Modbus.

The function looks like this:

// Create influxdb JSON
msg.payload = [
    [{
    'Speicher in kWh': (msg.payload[0][0]/(100)*(9.53)),
         
        time: new Date()
    },
    {
        inverter: '1'
    }]
];

return msg;

Perhaps someone else will find it useful.

Best regards,

Martin

Fantastic! Glad to see this working.