RS232 read data from MPP-Solar inverter

Hello all!
I need your help to read data from my MPP-Solar inverter.
My goal is to close a relay when battery capacity is under 70% and open back when battery capacity is 100%. The relay is connected with a power generator.

My problem is to get the data from the inverter. I thought it would be easy but I overestimated my skills.

My hardware setup is an Arduino Mega connected throw serial1 to a MAX3232 module which is connected to the inverter's serial port. To connect MAX3232 with the inverter I routed RX -> TX and TX -> RX

So, I have the communication protocol and for start I tried to send QID command.

QID: The device serial number inquiry
Computer: QID
Device: (XXXXXXXXXXXXXX

Serial1.print ("QID");               // Asking for MPP-Solar serial number

the response is 51 49 44

I believe is because the protocol of the MPP require CRC to be processed and I don't know how to do it.
I found a similar project but it is to complicated.

So I need you to guide me with CRC

Ok, reading the protocol manual, make sure your code sets the serial baud rate to 2400 8N1

void setup() {
  Serial1.begin(2400);
}

Next, it states there will be a Fortunately, this post on another forum copies and reformats the crc from another forum. I will paste it here, but have not tested and make no guarantees of it's abilities:

INT16U cal_crc_half(INT8U far *pin, INT8U len)
{
     INT16U crc;
     INT8U da;
     INT8U far *ptr;
     INT8U bCRCHign;
    INT8U bCRCLow;
     INT16U crc_ta[16]=
     { 
          0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
          0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef
     };
     ptr=pin;
     crc=0;
     while(len--!=0) 
     {
          da=((INT8U)(crc>>8))>>4; 
          crc<<=4;
          crc^=crc_ta[da^(*ptr>>4)]; 
          da=((INT8U)(crc>>8))>>4; 
          crc<<=4;
          crc^=crc_ta[da^(*ptr&0x0f)]; 
          ptr++;
     }
     bCRCLow = crc;
    bCRCHign= (INT8U)(crc>>8);
     if(bCRCLow==0x28||bCRCLow==0x0d||bCRCLow==0x0a)
    {
         bCRCLow++;
    }
    if(bCRCHign==0x28||bCRCHign==0x0d||bCRCHign==0x0a)
    {
          bCRCHign++;
    }
    crc = ((INT16U)bCRCHign)<<8;
    crc += bCRCLow;
     return(crc);
}

Lastly, the string must end in a which I interpret as:

'\r'

Thanks Perehama,
I try this code but Not working!

int incomingData ;   // for incoming serial data




#define INT16U unsigned int
#define INT8U byte
int crc ; 

unsigned short cal_crc_half(byte* pin, byte len)
{
  unsigned short crc;
  byte da;
  byte *ptr;
  byte bCRCHign;
  byte bCRCLow;

  const unsigned short crc_ta[16]=
  { 
      0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
      0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef
  };
  
  ptr=pin;
  crc=0;
  while(len--!=0) 
  {
    da=((byte)(crc>>8))>>4; 
    crc<<=4;
    crc^=crc_ta[da^(*ptr>>4)]; 
    da=((byte)(crc>>8))>>4; 
    crc<<=4;
    crc^=crc_ta[da^(*ptr&0x0f)]; 
    ptr++;
  }
  bCRCLow = crc;
  bCRCHign= (byte)(crc>>8);
  if(bCRCLow==0x28||bCRCLow==0x0d||bCRCLow==0x0a)
  {
    bCRCLow++;
  }
  if(bCRCHign==0x28||bCRCHign==0x0d||bCRCHign==0x0a)
  {
    bCRCHign++;
  }
  crc = ((unsigned short)bCRCHign)<<8;
  crc += bCRCLow;
  return(crc);
}



void setup() {
        Serial.begin(2400);     // opens serial port, sets data rate to 2400 bps
        Serial1.begin(2400);    // opens RS232 port, sets data rate to 2400 bps
}


void loop() {
  delay(2000);

        Serial1.print("QID");
        Serial1.print((3)((crc >> 8) & 0xFF));
        Serial1.print((3)((crc >> 0) & 0xFF));
        Serial1.print("\r");

        incomingData = Serial1.read();         // MPP-Solar Data
        Serial.print(incomingData );          // Display incoming Data to serial monitor

}

The problem is that you have an unknown (to the rest of us) solar inverter with very sketchy (very very very sketchy) documentation that is from an unverified source, and uses an undocumented CRC. This is a case of the blind looking to the blind for guidance. There is not a standard or common CRC (except maybe the parity bit not used).

kyr34:
Hello all!
I need your help to read data from my MPP-Solar inverter.
My goal is to close a relay when battery capacity is under 70% and open back when battery capacity is 100%. The relay is connected with a power generator.

My problem is to get the data from the inverter. I thought it would be easy but I overestimated my skills.

My hardware setup is an Arduino Mega connected throw serial1 to a MAX3232 module which is connected to the inverter's serial port. To connect MAX3232 with the inverter I routed RX -> TX and TX -> RX

So, I have the communication protocol and for start I tried to send QID command.

QID: The device serial number inquiry
Computer: QID
Device: (XXXXXXXXXXXXXX

Serial1.print ("QID");               // Asking for MPP-Solar serial number

the response is 51 49 44

I believe is because the protocol of the MPP require CRC to be processed and I don't know how to do it.
I found a similar project but it is to complicated.

So I need you to guide me with CRC

the link you provided for the communication protocol actually has an arduino code example! :o

donno if in the CRC cacl is ACTULLAY useful but here's the links:
http://www.offgrid.casa/wp-content/uploads/2017/10/testpip.c

EDIT:
I have attached the reworked code from the above link. It compiles for a MEGA but I have no means of testing it! :wink:

testpip.ino (9.65 KB)

Thanks for replying
sherzaad, there is no arduino example code in the official communication protocol pdf link.

So, here is my progress but no response from inverter

String QPI = "\x51\x50\x49\xBE\xAC\x0D";  // QPI + CRC + cr
// String QPIGS = "\x51\x50\x49\x47\x53\xB7\xA9\x0D";
// String QPIWS = "\x51\x50\x49\x57\x53\xB4\xDA\x0D";
// String QDI = "\x51\x44\x49\x71\x1B\x0D";
// String QMOD = "\x51\x4D\x4F\x44\x49\xC1\x0D";
// String QVFW =  "\x51\x56\x46\x57\x62\x99\x0D";
// String QVFW2 = "\x51\x56\x46\x57\x32\xC3\xF5\x0D";

String Data; //incoming data


void setup() {
  Serial.begin(2400);     // opens serial port, sets data rate to 2400 bps
  Serial1.begin(2400);    // opens RS232 port, sets data rate to 2400 bps
}

void loop() {

  Serial1.print(QPI);     // command string to inverter

  //   Serial.print(Serial1.read());    // try to read something


  Data = Serial1.readStringUntil('\r');

  if (Serial1.available()) {
    Serial.write("Data: ");
    Serial.println(Data);   // Please talk to me!!!!!
  } else {
    Serial.println("Sorry no data...");
  }

}

Perehama:
The problem is that you have an unknown (to the rest of us) solar inverter with very sketchy (very very very sketchy) documentation that is from an unverified source, and uses an undocumented CRC. This is a case of the blind looking to the blind for guidance. There is not a standard or common CRC (except maybe the parity bit not used).

I found a lot of information in this forum:
https://forums.aeva.asn.au/viewtopic.php?f=64&t=4332

This is more about CRC:
https://forums.aeva.asn.au/viewtopic.php?title=pip4048ms-inverter&p=57733&t=4332#p57733

kyr34:
I try this code but Not working!

Does it compile? Does it give compiler errors? On this forum, we can assist with Arduino language errors or sytax, but solar forums seem to be the most relevant help for your specific application. However, it's still stabbing in the dark since you do not have adequate documentation from the manufacturer.

Hi, not sure if you ever got this working or not. An alternative is to purchase a monitor like the victron bmv-712 or similar. It already has a built in relay just for the purpose you're looking for:

It is also possible to trigger the relay when an alarm condition occurs. The relay contact is open when the coil is de-energized (NO contact), and will close when the relay is energized.Factory default setting: the relay is controlled by the state-of-charge of the battery bank. The relay will be energized when the state-of-charge decreases to less than 50% (the ‘discharge floor’), and will be de-energized when the battery has been recharged to 90% state-of-charge. See section 4.2.2.The relay function can be inverted: de-energized becomes energized and vice versa. See section 4.2.2.When the relay is energized, the current drawn by the BMV will increase slightly: see technical data.
<<

Looking at the bmv-712, I can see that the soc, low and high voltage are fully customizable.

Regards, streakr6

kyr34:
I found a lot of information in this forum:
https://forums.aeva.asn.au/viewtopic.php?f=64&t=4332

This is more about CRC:
PIP-4048MS and PIP-5048MS inverters - Page 21 - AEVA Forums

hi, do you solve with code?, can you share news, thanks!

mihaigsm2003:
hi, do you solve with code?, can you share news, thanks!

What specifically do you need?

What have you tried?

Hi, I want to create smart BMS, read voltage from each cells ( this is simply) and send special command to inverter for change change current on top of cell voltage , commands like this: QID

mihaigsm2003:
Hi, I want to create smart BMS, read voltage from each cells ( this is simply) and send special command to inverter for change change current on top of cell voltage , commands like this: QID

have a look at the attachment in post#4

sherzaad:
have a look at the attachment in post#4

thanks, will test, and will reply.

sherzaad:
have a look at the attachment in post#4

do you have some schematics?

I test today but not working good: same time receiving “got a good packed “ but not any value show, else I received “ got BAD packet” but all data in good string.

Hi guys,

Here in France we found how to read the strings properly from mpp solar and other clones of these kind inverters using Arduino and MAX3232 module.

Code example for Arduino Uno working perfect:

#include <SoftwareSerial.h>
SoftwareSerial Serial4(7, 6); // RX, TX

String QPIGS = "\x51\x50\x49\x47\x53\xB7\xA9\x0D";

String stringOne;

void setup() {

Serial.begin(115200);
Serial4.begin(2400);
Serial4.setTimeout(10);

}

void loop() {
establishContact();

stringOne = Serial4.readString();
Serial.println (stringOne);

stringOne = "";

}
void establishContact() {
while (Serial4.available() <= 0) {

Serial4.print(QPIGS); // send an initial string RESQUEST

delay(50);

}

}

More about protocol and crcs :

There are few protocols, so with different request commands regarding the type and generation of the inverter. But the string reading code remains the same for any of them.

To know what crcs to put at the end of request commands, the best solution i found is first using a serial port monitor software as Eltima Software Serial Port Monitor for exemple.

Do these steps :

-Install Eltima Software Serial Port Monitor first. Do not launch it

-Plug your inverter on your PC as usual and launch your inverter software that could be watchpower, solarpower or watchmppt. Let it begin to talk with the inverter.

-Launch Eltima Software Serial Port Monitor. Click on Session, then New session.
Select the right virtual serial com port and make sure the Dumper view and Terminal view are selected.
Make sure Start monitoring now, Create/Close, Read/write, Device Control are selected.

Then you can see watchpower and the inverter talking to each other.

The Dump view window is where you can find the requests in full Hex strings with the right crcs.
Regarding a request is always the same "word", the endind crc is always the same for the given request. I hope you follow.

Crcs are changing only with the inverter responses, because crc are used by watchpower to be sure that datas are new datas and they are coherents. I hope you still follow.

Ok guys, do not hesitate to ask for help if you have troubles

From France.
Your buddy.

1 Like

MIB File for complete command list

Plus a Arduino project by some MIT guru

I stiill have to do for myself, hope this will be helpful for some.

WatchPower-master.zip (90.9 KB)

Hope MIB File gets attached this time.

volmib_toclient.zip (27.1 KB)

I am only getting '?' type response

Need Help

used resilient_buddy code