Skip to content
View in the app

A better way to browse. Learn more.

Power Forum - Renewable Energy Discussion

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

InfiniSolar V USB protocol

Featured Replies

1 minute ago, Praveen said:

Mine is not a off grid inverter. Its a hybrid inverter with battery backup. My understanding is, WatchPower is for off-grid inverter.

What is the make and model of your inverter?

  • Replies 104
  • Views 31.9k
  • Created
  • Last Reply

Top Posters In This Topic

Most Popular Posts

  • All I have to share are a few facts that I have learnt in my many decades through life which are edging towards eight although thankfully not quite. So perhaps some may reason that I am already senile

  • So personal story from my life, some 5 years ago. I lost my temper so badly one day that I physically started to bash in the door that my wife had just shut in my face. Thankfully the red mist cleared

Posted Images

  • Author
2 minutes ago, Don said:

What is the make and model of your inverter?

It is Infinisolar V model. Attached the device info view from WatchPower.

Screen Shot 2017-03-05 at 12.10.33 AM.png

  • Author
2 minutes ago, Don said:

@Praveen, you need to use WatchPower, whether you are Off-Grid, On-Grid or Hybrid, does not matter. SolarPower will not work with your inverter. 

I was trying to view the energy exported by the inverter to the Grid. WatchPower doesn't show those information. Is there any special privileges need to open the view?

Yes, I think the functionality you  are looking for is in SolarPower and not in WatchPower. We all started off with WatchPower. Play around with it and very soon realize it is very basic and not really what we require. That is where ICC and similar programs come in. They do have that functionality.  

  • Author

Figured out communication with inverter using python. Facing a weird problem.

SolarPower software sends command "PI" command and gets back "P18" as value. When I send the same, I get back "(NAKss". However, sending "QPI" command returns "P30". I am assuming the inverter is defaulting to P30 protocol because of something wrong with the command I send. Is there any encoding/transformation to be done before sending command to the inverter?

2 hours ago, Praveen said:

Is there any encoding/transformation to be done before sending command to the inverter?

Yes, there is the CRC (two Cyclic Redundancy Check characters). That's why the NAK comes back as NAKss; the "ss" part is the two-byte (two-character) CRC.

There are a very few commands that don't require a CRC, and I think that QPI must be one of them, since it doesn't send back a checksum, just the 6 characters "(QPI30" and a carriage return. Try sending the CRC with the PI command. In this case, it's 0xD752. The second character is just "R", but the first is "W" with the sign bit set. Comms programs differ in how to send such characters. 

Some background on using commands (for the non-V Axpert, but the principles should be the same).

The end of this post has how to send 8-bit characters using the Windows program TeraTerm.

C source code for generating CRCs.

A Windows applet for generating the CRCs more painlessly.

You can gain some insight on using the python struct module to pack binary data for the inverter.Together with pyserial that should be all you need. You can glean some examples here (this is for the mk2, but similar).

 

  • Author

I do have CRC implemented now. I am validating CRC for every output. Also sending CRC bit for every input I send to the inverter.

The problem is, the SolarPower software sends the command "PI"(from java) and it somehow gets translated to "^P005PIq..005PIq" while sending to inverter.(It sends two 8 byte hex -> 5E 50 30 30 35 50 49 71 8B 0D 30 30 35 50 49 71). A CRC doesn't explain this translation. I am thinking there is some function(in the libUSBDevice.so file) which does this translation. I want to manually send this hex message to the inverter. Is there any utility where I can directly send hex bytes to inverter and see the output?

I have attached the USB communication between inverter and SolarPower 1.21 software(See the sequence id "0910").

usbread.html

On 2017/03/16 at 5:35 AM, Praveen said:

Is there any utility where I can directly send hex bytes to inverter and see the output?

My understanding is that when it is set up, USB comms is just the same as serial comms, including being as slow as 2400 bps serial. There is then a virtual comm port like comm12. [ Edit: this isn't quite right; see Gnome's reply. ] So then you can use any serial comms program like TeraTerm. [ Edit: and this last part is completely wrong. ] But the trick is in setting it up. I never figured it out, and I've never seen it documented anywhere.

Edited by Coulomb

22 minutes ago, Praveen said:

I looked for a COM device in device manager(in a windows machine) when connected the inverter and I couldn't find one.

Yes, it's not that simple, and I don't get why there isn't one visible. I didn't try hard to sort it out. 

10 hours ago, Praveen said:

I do have CRC implemented now. I am validating CRC for every output. Also sending CRC bit for every input I send to the inverter.

The problem is, the SolarPower software sends the command "PI"(from java) and it somehow gets translated to "^P005PIq..005PIq" while sending to inverter.(It sends two 8 byte hex -> 5E 50 30 30 35 50 49 71 8B 0D 30 30 35 50 49 71). A CRC doesn't explain this translation. I am thinking there is some function(in the libUSBDevice.so file) which does this translation. I want to manually send this hex message to the inverter. Is there any utility where I can directly send hex bytes to inverter and see the output?

I have attached the USB communication between inverter and SolarPower 1.21 software(See the sequence id "0910").

usbread.html

OK, below is the simplified version of my function to built the command strings, it is in Delphi, but I'm sure if you are not familiar with Delphi, google will be able to assist. :)

You get 2 command types (CmdType in the function below) namely Poll commands and Set commands, a poll command is used to inquire something from the inverter and a set command is used to set something to the inverter (adjust a setting). The reply to a poll command will be a value depending on what you've requested and the reply to a set command will either be ACK (acknowledge) or NAK (not acknowledge). All responses might or might not include the security string and/or crc check-sum, depending on the inverter model - see below.

Some inverter models require the CRC check-sum (UseCRC in function below) added to command strings and will sometimes include the crc check-sums added to the responses.

Some inverter models require the "security string" (UseSec in function below) added to the command strings and will sometimes include the "security strings" added to the responses.

So you have to start off by sending the the PI and QPI commands to the inverter with different combinations of UseCRC and UseSec until you get a valid response from the inverter. Once you get a valid response you'll have to use that specific combination of UseCRC and UseSec for all other commands to that inverter. A valid response (to a PI or QPI command) from the inverter will be something like ^D00517Êì or (PI16œ¯ which indicates the model number of the inverter, in this case 17 (    ^D00517Êì    ) or 16 (    (PI16œ¯    ).

So you will use the function below with the following parameters until you get a valid response from the inverter:

  • BuildCommandString('PI', ctPoll, False, False)
  • BuildCommandString('PI', ctPoll, False, True)
  • BuildCommandString('PI', ctPoll, True, False)
  • BuildCommandString('PI', ctPoll, True, True)
  • BuildCommandString('QPI', ctPoll, False, False)
  • BuildCommandString('QPI', ctPoll, False, True)
  • BuildCommandString('QPI', ctPoll, True, False)
  • BuildCommandString('QPI', ctPoll, True, True)

As example: If you got a valid response from the inverter after sending the command from BuildCommandString('PI', ctPoll, True, False), you don't have to send any more PI or QPI commands to the inverter (because you received a valid response) and then you have to use the setting for UseCRC and UseSec which gave you a valid response for all other commands for that inverter, as explained above. So in this example each and every command send to this specific inverter needs to include the CRC checksum, but not the "security string", because you received a valid response by sending a command with UseCRC = True and UseSec = False.

So examples of other poll commands to this inverter will be:

  • BuildCommandString('QMD', ctPoll, True, False)
  • BuildCommandString('QVFW', ctPoll, True, False)
  • BuildCommandString('QFLAG', ctPoll, True, False)
  • BuildCommandString('QPIGS', ctPoll, True, False)

TIP: Sometimes data corruption, noise on the lines, partial old commands on the input-buffer of the inverter etc. prevents the inverter from returning a valid response and therefore it is good practice to send each command up to 3 consecutive times, obviously if you've received a valid response after the first or second time you're sending the command, you won't send it again.

 

type
  TCommandType = (ctPoll, ctSet);

function BuildCommandString(InpStr: string; CmdType: TCommandType; UseCRC, UseSec: boolean): string;

  function PadInteger(Val, FinalStrLen: integer): string;
  begin
    Result := IntToStr(Val);
    while Length(Result) < FinalStrLen do
      Result := '0'+Result;
  end;

  function AddSetHeader(DataToSend: string; CRCLength: integer): string;
  begin
    Result := '^S'+PadInteger(Length(DataToSend)+CRCLength+1, 3)+DataToSend;
  end;

  function AddPollHeader(DataToSend: string; CRCLength: integer): string;
  begin
    Result := '^P'+PadInteger(Length(DataToSend)+CRCLength+1, 3)+DataToSend;
  end;

  function GetCRC(ptr: pchar; len: word): word;
  const
    crc_ta: array [0..255] of word =
           ($0000, $1021, $2042, $3063, $4084, $50A5, $60C6, $70E7, $8108, $9129,
            $A14A, $B16B, $C18C, $D1AD, $E1CE, $F1EF, $1231, $0210, $3273, $2252,
            $52B5, $4294, $72F7, $62D6, $9339, $8318, $B37B, $A35A, $D3BD, $C39C,
            $F3FF, $E3DE, $2462, $3443, $0420, $1401, $64E6, $74C7, $44A4, $5485,
            $A56A, $B54B, $8528, $9509, $E5EE, $F5CF, $C5AC, $D58D, $3653, $2672,
            $1611, $0630, $76D7, $66F6, $5695, $46B4, $B75B, $A77A, $9719, $8738,
            $F7DF, $E7FE, $D79D, $C7BC, $48C4, $58E5, $6886, $78A7, $0840, $1861,
            $2802, $3823, $C9CC, $D9ED, $E98E, $F9AF, $8948, $9969, $A90A, $B92B,
            $5AF5, $4AD4, $7AB7, $6A96, $1A71, $0A50, $3A33, $2A12, $DBFD, $CBDC,
            $FBBF, $EB9E, $9B79, $8B58, $BB3B, $AB1A, $6CA6, $7C87, $4CE4, $5CC5,
            $2C22, $3C03, $0C60, $1C41, $EDAE, $FD8F, $CDEC, $DDCD, $AD2A, $BD0B,
            $8D68, $9D49, $7E97, $6EB6, $5ED5, $4EF4, $3E13, $2E32, $1E51, $0E70,
            $FF9F, $EFBE, $DFDD, $CFFC, $BF1B, $AF3A, $9F59, $8F78, $9188, $81A9,
            $B1CA, $A1EB, $D10C, $C12D, $F14E, $E16F, $1080, $00A1, $30C2, $20E3,
            $5004, $4025, $7046, $6067, $83B9, $9398, $A3FB, $B3DA, $C33D, $D31C,
            $E37F, $F35E, $02B1, $1290, $22F3, $32D2, $4235, $5214, $6277, $7256,
            $B5EA, $A5CB, $95A8, $8589, $F56E, $E54F, $D52C, $C50D, $34E2, $24C3,
            $14A0, $0481, $7466, $6447, $5424, $4405, $A7DB, $B7FA, $8799, $97B8,
            $E75F, $F77E, $C71D, $D73C, $26D3, $36F2, $0691, $16B0, $6657, $7676,
            $4615, $5634, $D94C, $C96D, $F90E, $E92F, $99C8, $89E9, $B98A, $A9AB,
            $5844, $4865, $7806, $6827, $18C0, $08E1, $3882, $28A3, $CB7D, $DB5C,
            $EB3F, $FB1E, $8BF9, $9BD8, $ABBB, $BB9A, $4A75, $5A54, $6A37, $7A16,
            $0AF1, $1AD0, $2AB3, $3A92, $FD2E, $ED0F, $DD6C, $CD4D, $BDAA, $AD8B,
            $9DE8, $8DC9, $7C26, $6C07, $5C64, $4C45, $3CA2, $2C83, $1CE0, $0CC1,
            $EF1F, $FF3E, $CF5D, $DF7C, $AF9B, $BFBA, $8FD9, $9FF8, $6E17, $7E36,
            $4E55, $5E74, $2E93, $3EB2, $0ED1, $1EF0);

  var
    crc, bCRCLow, bCRCHign, tmp: word;
    da: byte;
  begin
    crc := 0;
    while (len <> 0) do
    begin
      len := len - 1;
      da := $FF and ($FF and (crc shr 8)) shr 4;
      crc := crc shl 4;

      crc := crc xor (crc_ta[$FF and (da xor (Ord(ptr^) shr 4))]);
      da := $FF and ($FF and (crc shr 8)) shr 4;
      crc := crc shl 4;
      tmp := $FF and (da xor (Ord(ptr^) and $F));
      crc := crc xor crc_ta[tmp];
      ptr := ptr + 1;
    end;

    bCRCLow := $FF and crc;
    bCRCHign := $FF and (crc shr 8);
    if (bCRCLow = $28) or (bCRCLow = $0D) or (bCRCLow = $0A) then
      bCRCLow := bCRCLow+1;
    if (bCRCHign = $28) or (bCRCHign = $0D) or (bCRCHign = $0A) then
      bCRCHign := bCRCHign+1;

    crc := ($FF and bCRCHign) shl 8;
    crc := crc+bCRCLow;
    Result := crc;
  end;

begin
  Result := '';
  if Trim(InpStr) = '' then
    Exit;

  if UseCRC then
  begin
    if UseSec then
    begin
      if CmdType = ctPoll then
        InpStr := AddPollHeader(InpStr, 2)
      else
        InpStr := AddSetHeader(InpStr, 2);
    end;
    Result := InpStr+HexStrToStr(Format('%.4x', [GetCRC(PChar(InpStr), Length(InpStr))]));
  end
  else
  begin
    if UseSec then
    begin
      if CmdType = ctPoll then
        Result := AddPollHeader(InpStr, 0)
      else
        Result := AddSetHeader(InpStr, 0);
    end
    else
      Result := InpStr;
  end;
end;

 

  • 1 year later...
  • 2 months later...
On 2017/03/16 at 12:09 PM, Praveen said:

@superdiy This is exactly what I was looking. Just run the command through this code in my mind and getting the expected output. I will implement this and write my findings here.

Thank you very much.

@superdiy I have a question.  Looking at Delphi code above, it looks that appending the final <CR> at the end of InpStr is the final step just before sending it to the inverter, right?  Because I don't see this is being done at least in this code.  Which also means that the CRC calculation should be done for every thing except the last <CR> character.  As an example CRC should be calculated for ^P005PI and then after appending it as ^P005PI<CRC> then CR should be appended such as ^P005PI<CRC><CR>.

 

Please confirm.

9 hours ago, Nadeem Ahmed said:

CRC should be calculated for ^P005PI and then after appending it as ^P005PI<CRC> then CR should be appended such as ^P005PI<CRC><CR>.

That's how it works for Axperts.

On 2017/03/16 at 12:19 AM, Coulomb said:

My understanding is that when it is set up, USB comms is just the same as serial comms, including being as slow as 2400 bps serial. There is then a virtual comm port like comm12. So then you can use any serial comms program like TeraTerm. But the trick is in setting it up. I never figured it out, and I've never seen it documented anywhere.

It has the same latency and bandwidth as the serial because it seems to be limited by the underlying processor. But the protocol is different for sure.

It is just a USB HID device that accepts 8 bytes at a time. In Linux you just open the device (/dev/hidraw0) as a file and write to it and read from it. You'll need to set it as non-blocking read and write.

HIDApi will allow you to communicate with it regardless of your operating system

Edited by Gnome

On 2017/03/16 at 12:19 AM, Coulomb said:

My understanding is that when it is set up, USB comms is just the same as serial comms, including being as slow as 2400 bps serial. There is then a virtual comm port like comm12. [ Edit: this isn't quite right; see Gnome's reply. ] So then you can use any serial comms program like TeraTerm. [ Edit: and this last part is completely wrong. ] But the trick is in setting it up. I never figured it out, and I've never seen it documented anywhere.

I was under the impression USB is faster than serial, i.e. not 2400bps anymore. And it should give full duplex communications, which serial doesn't (or, at least do properly)

31 minutes ago, SilverNodashi said:

I was under the impression USB is faster than serial, i.e. not 2400bps anymore. And it should give full duplex communications, which serial doesn't (or, at least do properly)

From the PC up to the USB-serial chip it is faster. From there onwards it runs at normal serial speeds. Granted, it is usually capable of much higher speeds, eg FTDI chips can go up to 12 mbit if I recall correctly (there are some caveats I don't recall exactly). I did some of my own testing a few years ago, and found out that it is pretty silly to go above around 500kbaud, at that point all sorts of other software layers starts bottle-necking you.

Nevertheless, many designs still use slower speeds because they can get away with it. More dependable, and the volume of data is super low in any case.

Some designs kick up the speed when doing firmware updates.

7 minutes ago, plonkster said:

From the PC up to the USB-serial chip it is faster. From there onwards it runs at normal serial speeds. Granted, it is usually capable of much higher speeds, eg FTDI chips can go up to 12 mbit if I recall correctly (there are some caveats I don't recall exactly). I did some of my own testing a few years ago, and found out that it is pretty silly to go above around 500kbaud, at that point all sorts of other software layers starts bottle-necking you.

Nevertheless, many designs still use slower speeds because they can get away with it. More dependable, and the volume of data is super low in any case.

Some designs kick up the speed when doing firmware updates.

In the case of electronics like an inverter I would thinks it's still quicker than serial communications? On an Arduino, for example, I can communicate much quicker than 2400pbs, and in fact in many instances (like a GPS tracker) anything below 115200 is too slow to get all the data quick enough. Microprocessors have real time processing. An Arduino, as example again, runs at 16Mhz - that's 1/16000000 of a second  that it could run an instruction. Some instructions run on two cycles, and some on three, but that's still super fast. Computers are faster but due to multiprocessing things could happen slower, depending on how many threads, and cores are being used.

1 hour ago, SilverNodashi said:

I was under the impression USB is faster than serial, i.e. not 2400bps anymore. And it should give full duplex communications, which serial doesn't (or, at least do properly)

Several things to note about USB:

  • USB doesn't have any kind of synchronous protocol
    • Sure the actual data transfer is full-duplex but the protocol itself is asynchronous model
    • You tell the USB controller to send packets to the device and it'll send it when it is good and ready
    • The device then responds to the controller which will notify VIA an IRQ again when it is ready
  • USB has higher latency and unpredictable latency
    • Because of the above, USB is not used for time critical applications like GPS and time sources
    • RS232 is still considered superior in this space

Now as for RS232 it does not have the bandwidth that USB has but it has lower latency. Other than parallel there is no lower latency protocol (OK there is SPI but it isn't well supported). Not only that, the actual latency is 100% predictable and repeatable.

Meaning if you are running a real-time operating system (which we are not), you can exactly time your RS232 on clock cycles with relative accuracy (some accommodation must be made for clock drift on the order of μs, but compared to USB it is orders of magnitude better).

Lastly, the Axpert device isn't limited by the speed of the RS232, it is limited by the device. 2400bps is as good as it gets.

I've got a library I wrote that allows both USB & RS232 to be used for Axpert. The library is otherwise using the exact same code. The total latency is exactly the same between the two ± 15ms.

I found USB to be less reliable on the Axpert. Doing things wrong on USB I was able to cause the inverter to stop responding to commands which required a restart (mind you the inverter still ran normally). But on RS232 it was more reliable.

Edited by Gnome

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.