Help with mpp solar pip inverter

what?!

first you need get data from the inverter then only you can send it to cayenne.

1 Like
#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space

#include <CayenneMQTTEthernet.h>
#include <Firmata.h>
#include <ArduinoJson.h>
#include "utility/SerialFirmata.h"
#define TEST_MODE                   0x40
#define RELOAD_NOW                  0x41      
#define SET_MOD                     0x42 

unsigned long lastMillis=0;
unsigned long lastMillis1=0;

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"; 
char username[] = "
char password[] = "
char clientID[] = "
String POP02 = "\x50\x4F\x50\x30\x32\xE2\x0B\x0D";  //SBU priority
String POP01 = "\x50\x4F\x50\x30\x32\xE2\xD2\x69";  //solar first
String POP00 = "\x50\x4F\x50\x30\x30\xC2\x48\x0D";  //utility first

StaticJsonBuffer<300> jsonBuffer;
JsonObject& root = jsonBuffer.createObject(); 
boolean isResetting = false;
signed char queryIndex = -1;
unsigned long currentMillis;        // store the current value from millis()
unsigned long previousMillis;       // for comparison with currentMillis




void systemResetCallback()
{
  isResetting = true;

  // initialize a defalt state
  // TODO: option to load config from EEPROM instead of default


  for (byte i = 0; i < TOTAL_PINS; i++) {
    // pins with analog capability default to analog input
    // otherwise, pins default to digital output
    if (IS_PIN_ANALOG(i)) {
      // turns off pullup, configures everything
      //tPinModeCallback(i, PIN_MODE_ANALOG);
    } else if (IS_PIN_DIGITAL(i)) {
      // sets the output to 0, configures portConfigInputs
     //etPinModeCallback(i, OUTPUT);
    }

  }
  isResetting = false;
}

void setup()
{  
  Serial.begin(9600);
  
  Serial1.begin(2400);
   

 // Serial1.begin(2400);
 Cayenne.begin(username, password, clientID);

 
 Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
 Firmata.attach(STRING_DATA, stringCallback);
  Firmata.attach(SYSTEM_RESET, systemResetCallback);
  Firmata.attach(START_SYSEX, sysexCallback); 
  Serial.println("finito setup");
}

void loop()
{   Cayenne.loop();
    
  


}
CAYENNE_OUT_DEFAULT()
{
  // Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
  Cayenne.virtualWrite(0, millis());
  Serial.println ("invio a cayenne");
  // Some examples of other functions you can use to send data.
  //Cayenne.celsiusWrite(1, 22.0);
  //Cayenne.luxWrite(2, 700);
  //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}

// Default function for processing actuator commands from the Cayenne Dashboard.
// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}
void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte stopTX;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  switch (command) {
    case TEST_MODE:
         if( argc == 1 ) //verify we received the whole message
            {
                //the MSB is always sent in the LSB position 2nd byte
                byte val;
                if( argv[0] == 1 )
                {
                    val = HIGH;
                }
                else
                {
                    val = LOW;
                }
        
                
                Firmata.write(END_SYSEX);
            }

     break;
      case SET_MOD:
    Serial.println("SET_MOD");
    if (argc == 1) //verify we received the whole message
    {
      byte val;
      switch (argv[0]) {
      case 0:
        Serial1.print(POP00);
        break;
      case 1:
        Serial1.print(POP00);
        break;
      case 2:
        Serial1.print(POP00);
        break;
      }
    }
    break;
        Firmata.write(END_SYSEX);
    case RELOAD_NOW:
             Serial.println("RELOAD_NOW");
             //read_QMOD();
             //read_QPIGS();
             //read_QPIWS();     
        
             String x;
             root.printTo(x);
             Firmata.sendString(x.c_str()); 
             Firmata.write(END_SYSEX);
      break;

  }
}


void setPinValueCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
    if (Firmata.getPinMode(pin) == OUTPUT) {
      Firmata.setPinState(pin, value);
      
    }
  }
};
void stringCallback(char *myString)

{
   Serial.println(myString);
   //Firmata.sendString(myString);
  
};

questo è il codice che ho prodotto, ma niente, non comunica con la com

As i said, you need to first get data from the inverter. there are several factors that can go wrong here as the RS232 to TTL converter you have build is not working properly. you will need to solve this issue and try to get data from the inverter.

Hi, I managed to solve the hardware problem Arduino side, with a TTL RS232 port from PC you see that it prints the necessary, but the inverter does not respond.

well it looks like an issue with your inverter.

1 Like

funziona alla grande

What exactly is the problem?

hardware, I had not calculated that in the connection board rs232-ttl on the inverter side rx-tx they had to be reversed, the code works perfectly for those who want to use

2 Likes

Awesome, nice job!

it would be great if you would make a detailed tutorial on how to send inverter data to cayenne.

#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space

#include <CayenneMQTTEthernet.h>

#include <ArduinoJson.h>

unsigned long lastMillis=0;
unsigned long lastMillis1=0;
long previousMillis = 0;
long interval = 1000;


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"; 
char username[] = "f";
char password[] = "";
char clientID[] = "";
String POP02 = "\x50\x4F\x50\x30\x32\xE2\x0B\x0D";  //SBU priority
String POP01 = "\x50\x4F\x50\x30\x32\xE2\xD2\x69";  //solar first
String POP00 = "\x50\x4F\x50\x30\x30\xC2\x48\x0D";  //utility first


float imp_volt;
float imp_freq;
float out_volt;
float out_freq;
int out_load_va;
int out_load_w;
int out_load_perc;
float bat_volt;
int chg_amp;
int  batt_level_perc;
float  pv_amp;
float pv_volt;
int disc_amp;
int inv_temp;
float  W_ftv;
String stato;
StaticJsonBuffer<300> jsonBuffer;
JsonObject& root = jsonBuffer.createObject(); 



int readvalue;

void setup()
{  
  Serial.begin(9600);
  
  Serial1.begin(2400);
   
 Cayenne.begin(username, password, clientID);

 

  Serial.println("finito setup2");
}

void loop(){

  Cayenne.loop(); 
unsigned long currentMillis = millis();
if   (currentMillis - previousMillis > interval) {
          previousMillis = currentMillis;  

     Serial.println("ciclo if e stampo json");
     
     read_QMOD();
    
     read_QPIGS();
    
     String x;
     
     root.printTo(x);
    
     Serial.println(x.c_str());  
     
    
    imp_volt=root["INP_VOLT"];
    imp_freq=root["INP_FREQ"] ;
    out_volt=root["OUT_VOLT"];
    out_freq=root["OUT_FREQ"];
    out_load_va=root["OUT_LOAD_VA"];
    out_load_w=root["OUT_LOAD_W"];
    out_load_perc= root["OUT_LOAD_PERC"];
    bat_volt=root["INP_BAT_VOLT"];
    chg_amp=root["INP_CHG_AMP"];
    batt_level_perc=root["BATT_LEVEL_PERC"];
    pv_amp=root["INP_PV_amp"];
    pv_volt=root["INP_PV_amp2"];
    disc_amp=root["OUT_DISC_AMP"];
    inv_temp=root["inv_temp"];
    W_ftv=( pv_volt*pv_amp);
     JsonObject& root = jsonBuffer.createObject();     
     //} 
}
Serial.print("stato=");

Serial.println(stato);


}

CAYENNE_OUT_DEFAULT()
{
  // Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
  Cayenne.virtualWrite(0, millis());
  Cayenne.virtualWrite(1,imp_volt,"voltage","v");
  Cayenne.virtualWrite(2,imp_freq,"freq","hz");
  Cayenne.virtualWrite(3,out_volt,"voltage","v");
  Cayenne.virtualWrite(4,out_freq,"freq","hz");
  Cayenne.virtualWrite(5,out_load_va,"pow","w");
  Cayenne.virtualWrite(6,out_load_w,"pow","w");
  Cayenne.virtualWrite(7,out_load_perc);
  Cayenne.virtualWrite(8, bat_volt,"batt","v");
  Cayenne.virtualWrite(9,chg_amp,"current","a");
  Cayenne.virtualWrite(10,batt_level_perc,"batt","p");
  Cayenne.virtualWrite(11,pv_volt,"voltage","v");
  
  Cayenne.virtualWrite(12,disc_amp);
  Cayenne.virtualWrite(14,pv_amp,"current","a");
  Cayenne.celsiusWrite(15,inv_temp);
  Cayenne.virtualWrite(16,W_ftv,"pow","w");

  Serial.println ("invio a cayenne");
  if (stato==("B")) {
  Cayenne.virtualWrite(13,1,"digital_sensor","d");
  Serial.println("led acceso");}
else
 {Serial.println("led spento");
  Cayenne.virtualWrite(13,0,"digital_sensor","d");}
 }
  
  // Some examples of other functions you can use to send data.
  //Cayenne.celsiusWrite(1, 22.0);
  //Cayenne.luxWrite(2, 700);
  //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);


// Default function for processing actuator commands from the Cayenne Dashboard.
// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}
void read_QPIGS()
{
  
  
  Serial1.print(QPIGS);
  
 while (Serial1.available() == 0 )   ///wait for answer or timeout
  {
  }
  
  if (Serial1.find("(")) {
    Serial.println("provo a stampa dalla seriale 1");
    root["INP_VOLT"] = Serial1.parseFloat();        //QPIGS.1 Grid voltage      
    root["INP_FREQ"] = Serial1.parseFloat();        //QPIGS.2 Grid frequency
    root["OUT_VOLT"] = Serial1.parseFloat();       //QPIGS.3 Out voltage  
    root["OUT_FREQ"] = Serial1.parseFloat();       //QPIGS.4 Out frequency
    root["OUT_LOAD_VA"] = Serial1.parseInt();     //QPIGS.5 AC output apparent power
    root["OUT_LOAD_W"] = Serial1.parseInt();      //QPIGS.6 AC output active power
    root["OUT_LOAD_PERC"] = Serial1.parseInt();   //QPIGS.7 Output load percent 
    root["INP_nonso"]=Serial1.parseInt();                             //skip
    root["INP_BAT_VOLT"] = Serial1.parseFloat();    //QPIGS.9 Battery voltage 
    root["INP_CHG_AMP"] = Serial1.parseInt();     //QPIGS.10 Battery charging current
    root["BATT_LEVEL_PERC"] = Serial1.parseInt(); //QPIGS.11 Battery capacity 
    root["inv_temp"] =Serial1.parseInt();                             //skip
    root["INP_PV_amp"] =Serial1.parseFloat();                             //skip
    root["INP_PV_amp2"] =Serial1.parseFloat();     //QPIGS.14 PV Input voltage 
    root["INP_PV_VOLT121"] = Serial1.parseFloat();                             //skip
    root["OUT_DISC_AMP"] = Serial1.parseInt();    //QPIGS.16 Battery discharge current
    
    }


};
void read_QPIWS(){
  String inData;
  
  //ledblink(MKR_LED, 500, 3);
  Serial1.print(QPIWS);
  while (Serial1.available() == 0&&  millis()< lastMillis+1000)   ///wait for answer or timeout
  {
  }
  inData= Serial1.readStringUntil('\r');
  //while (Serial1.available() > 0)
    // {   
    //    char recieved = Serial1.read();
    //
    //      inData += recieved; 
    //
    //  }
    root["I_SETTING"] = inData.substring(1,30);
};
void read_QMOD(){
  
  while (Serial1.available() > 0)
  {Serial1.flush();
   byte a=Serial1.read();}

    String inData;
 
  
  //ledblink(MKR_LED, 500, 3);
  Serial1.print(QMOD);
  while (Serial1.available() == 0 )   ///wait for answer or timeout
  {
  }
  inData= Serial1.readStringUntil('\r');
  //while (Serial1.available() > 0)
    // {   
    //    char recieved = Serial1.read();
    //
    //      inData += recieved; 
    //
    //  }
    root["MODE_MAINS"] = inData.substring(1,2);
   stato= inData.substring(1,2);
}

a tutorial I don’t even know where to start, I’m not good or competent like many who hang out on the forum …
pro to describe the code very quickly …
I used the json library which fortunately is already part of the work and used arduino 2. an rs232-ttl interface and an etherne cable where I connected to the inverter mpp solar as specified by the manufacturer (rx-tx-gnd pin 1 and 2 and 5 of the ethernet plug.
I declared the support variables for sending to cayenne and copied the values ​​from the json library … in practice qnd sends the qpigs command to the inverter he replies with a string of raw data that by copying are the jobs you need (power, voltage ,current)
for those who like me like I have practically gone crazy to succeed, I really hope to be able to give a valid hand to the forum in my small way … then if you have ideas for improvement I am open to everything … for now it does its job well.
I am always waiting for an implementation of dialogue between devices.
in the sense I have too much production I would like to have a resistive load attached, but only if there is nothing else connected, but I can only know by interpolating values ​​from different arduino …

1 Like

A tutorial as a new topic in the community with a attractive topic and some few details like what is the project about, hardware used, circuit diagram code and anything important that need to be added. Once done we can also share your project on cayenne social media.

the hardware for technical reasons and speed / power and availability of 3 serial I used an arduino 2 and an ethernet shield, but it also works with nodecu, but in my opinion it occupies too many resources with the Softwareserial library.
connected tx1 / rx1 to the rs232-ttl card (https://www.ebay.it/i/153202774298?chn=ps),
then if you want other things let me know because I have not but never made a tutorial … I’m excited :stuck_out_tongue:

i am excited too to see the tutorial and get a chance to make a similer project

how do you want the tutorial to be done

tutorial as in where people can have a look at your post and do their project. which provide them with the necessary instruction to complete the project.

What an excellent script Massimotruglio83 !
Grazie mille!!!
You saved me a lot of time.
I tried your script but I have problem connecting to my 2424 MSXE anyway . Probably a hardware problem. I double checked the cable wiring… I hope to find a solution soon to enjoy your code

2 Likes

figurati e grazie per i complimenti, il cablaggio controllalo bene e ricorda TX RX rovesciati quando ti colleghi, io pure cio sbattuto un sacco di tempo