@athersaleem waiting for you videos to be online
I tried the testpip.ino code, and as I initially wired the TX and RX to RS22 module, I got no response, after I swapped the RX with X i got some response, but it's not what I expected
Packet Sent - command 1
Got good packet!
QPIGS
SYSTEM STATUS
Inverter Fault: -
Bus Over Voltage: -
Bus Under Voltage: -
Bus Soft Fail: -
Line Fail: -
OPV Short: -
Inverter Voltage Too Low: -
Inverter Voltage Too High: -
Over Temperature: -
Fan Locked: -
Battery Voltage Too High: -
Battery Low Alarm: -
Battery Under Shutdown:
-
Overload - -
EEPROM Fault:
-
Packet Sent - command 0
Got good packet!
QPIWS
gridVoltage: PIWS
gridFrequency:
acOutput:
acFrequency:
acApparentPower:
acActivePower:
loadPercent:
busVoltage:
batteryVoltage:
batteryChargeCurrent:
batteryCharge:
inverterTemperature:
PVCurrent:
PVVoltage:
PVPower: 0
The response doesn't contain any data, I just see the command QPIWS.
The wiring can be seen in the photo bellow:
Grey wire from RS232 to D16, and WHITE wire to D17 of Mega 2560 PRO mini board (Serial2) and also have the LAN connector in the photo, PIN1 orange-white, PIN2 blue, PIN8 green-white.
Thank you for any more advices.
PS. Here is the CODE I TRIED (just modified to use Serial2 on my MEGA)
uint8_t pipInputBuf[500];
int pipInputPointer = 0;
// Structure to store the data from the PIP4048
struct pipVals_t {
char gridVoltage[16];
char gridFrequency[16];
char acOutput[16];
char acFrequency[16];
char acApparentPower[16];
char acActivePower[16];
char loadPercent[16];
char busVoltage[16];
char batteryVoltage[16];
char batteryChargeCurrent[16];
char batteryCharge[16];
char inverterTemperature[16];
char PVCurrent[16];
char PVVoltage[16];
} pipVals;
// Some useful PIP commands
struct pipCommands_t {
unsigned char qpigs[5];
unsigned char qpiws[5];
} pipCommands = {{'Q', 'P', 'I', 'G', 'S'}, {'Q', 'P', 'I', 'W', 'S'}};
int whichPIPCommand = 0, lastPIPCommand = 0; // which PIP values to read
void setup()
{
Serial.begin(115200); //Serial Monitor Console Baud Setting
Serial2.begin(2400, SERIAL_8N1); //MPP-Solar inverter Baud Setting(http://www.offgrid.casa/wp-content/uploads/2017/10/HS_MS_MSX_RS232_Protocol_20140822_after_current_upgrade.pdf)
}
void loop ()
{
uint16_t crc;
char *val;
char pipstatus[40];
delay(5000); // read every 5 seconds
// Send alternating commands to PIP - QPIGS then QPIWS
Serial.print("Packet Sent - command ");
Serial.println(whichPIPCommand);
switch (whichPIPCommand) {
case 0:
pipSend(pipCommands.qpigs, sizeof(pipCommands.qpigs));
lastPIPCommand = 0;
whichPIPCommand = 1; // Next command
break;
case 1:
pipSend(pipCommands.qpiws, sizeof(pipCommands.qpiws));
lastPIPCommand = 1;
whichPIPCommand = 0; // Next command
break;
}
// Check any return from the pip4048
int i = processPipInput(&crc);
if (i > 0) // Got a good packet
{
Serial.println("Got good packet!");
Serial.println((char *) pipInputBuf);
switch (lastPIPCommand) // Which paccket are we expecting?
{
case 0: // QPIGS
// Now split the packet into the values
val = strtok((char *) pipInputBuf, " "); // get the first value
strcpy(pipVals.gridVoltage, val + 1); // Skip the initial '('
val = strtok(0, " "); // Get the next value
strcpy(pipVals.gridFrequency, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.acOutput, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.acFrequency, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.acApparentPower, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.acActivePower, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.loadPercent, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.busVoltage, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.batteryVoltage, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.batteryChargeCurrent, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.batteryCharge, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.inverterTemperature, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.PVCurrent, val);
val = strtok(0, " "); // Get the next value
strcpy(pipVals.PVVoltage, val);
// Print out readings
Serial.print("gridVoltage: ");
Serial.println(pipVals.gridVoltage);
Serial.print("gridFrequency: ");
Serial.println(pipVals.gridFrequency);
Serial.print("acOutput: ");
Serial.println(pipVals.acOutput);
Serial.print("acFrequency: ");
Serial.println(pipVals.acFrequency);
Serial.print("acApparentPower: ");
Serial.println(pipVals.acApparentPower);
Serial.print("acActivePower: ");
Serial.println(pipVals.acActivePower);
Serial.print("loadPercent: ");
Serial.println(pipVals.loadPercent);
Serial.print("busVoltage: ");
Serial.println(pipVals.busVoltage);
Serial.print("batteryVoltage: ");
Serial.println(pipVals.batteryVoltage);
Serial.print("batteryChargeCurrent: ");
Serial.println(pipVals.batteryChargeCurrent);
Serial.print("batteryCharge: ");
Serial.println(pipVals.batteryCharge);
Serial.print("inverterTemperature: ");
Serial.println(pipVals.inverterTemperature);
Serial.print("PVCurrent: ");
Serial.println(pipVals.PVCurrent);
Serial.print("PVVoltage: ");
Serial.println(pipVals.PVVoltage);
// Calculate PV Power
int I, V;
I = atoi(pipVals.PVCurrent);
V = atoi(pipVals.PVVoltage);
Serial.print("PVPower: ");
Serial.println(I * V);
break;
case 1: // QPIWS
val = strtok((char *) pipInputBuf, " "); // get the first value
strcpy(pipstatus, val + 1); // Skip the initial '(' - make a copy of the returned stricg for processing
Serial.println("SYSTEM STATUS");
// Now send the various PIP status messages
Serial.print("Inverter Fault: ");
if (pipstatus[1] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Bus Over Voltage: ");
if (pipstatus[2] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Bus Under Voltage: ");
if (pipstatus[3] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Bus Soft Fail: ");
if (pipstatus[4] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Line Fail: ");
if (pipstatus[5] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("OPV Short: ");
if (pipstatus[6] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Inverter Voltage Too Low: ");
if (pipstatus[7] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Inverter Voltage Too High: ");
if (pipstatus[8] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Over Temperature: ");
if (pipstatus[9] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Fan Locked: ");
if (pipstatus[10] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Battery Voltage Too High: ");
if (pipstatus[11] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Battery Low Alarm: ");
if (pipstatus[12] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.println("Battery Under Shutdown: ");
if (pipstatus[14] == '1') Serial.println("FAULT");
else Serial.println("-");
Serial.print("Overload - ");
if ((pipstatus[16] == '1') && (pipstatus[1] == '0')) Serial.println(" Warning");
else if ((pipstatus[16] == '1') && (pipstatus[1] == '1')) Serial.println(" FAULT");
else Serial.println("-");
Serial.println("EEPROM Fault: ");
if (pipstatus[17] == '1') Serial.println("FAULT");
else Serial.println("-");
break;
}
}
if (i == -1) // Got a bad packet
{
Serial.println("Got BAD packet");
Serial.println((char *) pipInputBuf);
}
}
// Check for input from Serial2, put it into a buffer and then return the
// buffer length if a <cr> has been detected and the packet is valid,
// 0 if <cr> hasn't yet been detected and -1 if an invalid crc has been sent
int processPipInput(uint16_t *retCrc)
{
uint8_t pipChar;
uint16_t newCrc;
while (Serial2.available()) // Got any input?
{
if ((pipChar = Serial2.read()) != 0x0d) // Read the byte
{
pipInputBuf[pipInputPointer++] = pipChar; // Not a <cr>
}
else
{ // Got a <cr>, calculate the crc
newCrc = cal_crc_half(pipInputBuf, pipInputPointer - 2);
if (newCrc == ((((pipInputBuf[pipInputPointer - 2]) << 8) & 0xff00) | (pipInputBuf[pipInputPointer - 1] & 0xff))) // Good crc
{
int8_t i = pipInputPointer - 2;
pipInputBuf[i] = 0; // Terminate the string in the input buffer, overwriting the crc - so it can easily be printed out
pipInputPointer = 0; // Zero the pointer ready for the next packet
*retCrc = newCrc; // Return the buffer CRC
return (i); // Return length of buffer
}
else
{
pipInputBuf[pipInputPointer + 1] = 0; // Terminate the string for display...keep the crc in place for checking
pipInputPointer = 0;
return (-1); // Indicate bad crc
}
}
}
return (0); // packet not yet finished
}
// Send a packet to the pip4048
void pipSend(uint8_t txArray[], int length)
{
int crc = cal_crc_half(txArray, length);
Serial2.write(txArray, length);
Serial2.write((crc >> 8) & 0xff);
Serial2.write(crc & 0xff);
Serial2.write(0x0d);
}
uint16_t cal_crc_half(uint8_t *pin, uint8_t len)
{
uint16_t crc;
uint8_t da;
uint8_t *ptr;
uint8_t bCRCHign;
uint8_t bCRCLow;
uint16_t 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 = ((uint8_t)(crc >> 8)) >> 4;
crc <<= 4;
crc ^= crc_ta[da ^ (*ptr >> 4)];
da = ((uint8_t)(crc >> 8)) >> 4;
crc <<= 4;
crc ^= crc_ta[da ^ (*ptr & 0x0f)];
ptr++;
}
bCRCLow = crc;
bCRCHign = (uint8_t)(crc >> 8);
if (bCRCLow == 0x28 || bCRCLow == 0x0d || bCRCLow == 0x0a)
{
bCRCLow++;
}
if (bCRCHign == 0x28 || bCRCHign == 0x0d || bCRCHign == 0x0a)
{
bCRCHign++;
}
crc = ((uint8_t)bCRCHign) << 8;
crc += bCRCLow;
return (crc);
}