SilverNodashi Posted September 3, 2016 Posted September 3, 2016 Hi, I'm going to open this to anyone who is interested. Can someone please write me a small script, preferably in C# or C++ which just queries an Axpert inverter's status? I am more than willing to pay for it. I have a bigger project in mind which could make you a LOT of money if you are interested. Quote
___ Posted September 3, 2016 Posted September 3, 2016 Does it have to be C# or C++? Because for one, C# means Mono and that's a fairly rare thing among Linux devs, and it would be like 5 times faster to do this in Python than in C++ :-) Also, I generally prefer to have testing access to hardware. Maybe we can work something out, but even though I can code C++ I'm not really in the mood for the time requirements around that :-) Quote
SilverNodashi Posted September 3, 2016 Author Posted September 3, 2016 Just now, plonkster said: Does it have to be C# or C++? Because for one, C# means Mono and that's a fairly rare thing among Linux devs, and it would be like 5 times faster to do this in Python than in C++ :-) Also, I generally prefer to have testing access to hardware. Maybe we can work something out, but even though I can code C++ I'm not really in the mood for the time requirements around that :-) I would have preferred c# for a reason that I can't share without an NDA. Tying Python or anything else into C# would be impossible? Would remote access to the Pi be sufficient? OR would you need an inverter on your desk? Quote
SilverNodashi Posted September 3, 2016 Author Posted September 3, 2016 Perhaps I don't quite understand the Axpert command manual, in terms of what code the inverter actually expects, i.e does it expect a command like "QPIGS" or does it expect the HEX code? A basic script, opening the serial port, sending "QPIGS" and reading the response would be a good start. Quote
Coulomb Posted September 3, 2016 Posted September 3, 2016 47 minutes ago, SilverNodashi said: Perhaps I don't quite understand the Axpert command manual, in terms of what code the inverter actually expects, i.e does it expect a command like "QPIGS" or does it expect the HEX code? You send the actual text string (e.g. "QPIGS") and a carriage return, but before the carriage return you need two CRC characters. If the command is the same (e.g. always QPIGS), then you can hard code the CRC characters. For the actual QPIGS command, the CRC chars are 0xB7 and 0xA9. (So you need a way of sending hex values as characters, some with the sign bit set, as these two do.) If the commands are changing all the time (e.g. you need to set the float voltage to many different values), then you'll need to be able to calculate the required CRC characters. It's only a dozen lines of code and a short table if that's needed. The inverter will respond with a long string of data, as per the protocol document, which you need to parse to get the information that you need. The only other thing you need is a way to open the comms port and set it to 2400 BPS, 8 bits, no parity, one stop bit. it's quite possible to talk to the inverter with a comms program, though it's a pain looking up and sending the CRC characters. To find the CRC characters required, you can use an online calculator such as this one: https://www.lammertbies.nl/comm/info/crc-calculation.html . For that page, use the results from the line "CRC-CCITT (XModem) ". Quote
SilverNodashi Posted September 3, 2016 Author Posted September 3, 2016 54 minutes ago, Coulomb said: You send the actual text string (e.g. "QPIGS") and a carriage return, but before the carriage return you need two CRC characters. If the command is the same (e.g. always QPIGS), then you can hard code the CRC characters. For the actual QPIGS command, the CRC chars are 0xB7 and 0xA9. (So you need a way of sending hex values as characters, some with the sign bit set, as these two do.) If the commands are changing all the time (e.g. you need to set the float voltage to many different values), then you'll need to be able to calculate the required CRC characters. It's only a dozen lines of code and a short table if that's needed. The inverter will respond with a long string of data, as per the protocol document, which you need to parse to get the information that you need. The only other thing you need is a way to open the comms port and set it to 2400 BPS, 8 bits, no parity, one stop bit. it's quite possible to talk to the inverter with a comms program, though it's a pain looking up and sending the CRC characters. To find the CRC characters required, you can use an online calculator such as this one: https://www.lammertbies.nl/comm/info/crc-calculation.html . For that page, use the results from the line "CRC-CCITT (XModem) ". that's where I'm lost.... Quote
___ Posted September 3, 2016 Posted September 3, 2016 To check, I'm not at my computer and will answer more fully later but doing this in Python would be easy enough and of you're worried about some kind of intellectual property leaking out you could use cython to turn critical bits into compiled shared objects, though I can hardly think how anything about the axpert could still be secret :-) Sent from my GT-I9195 using Tapatalk Quote
SilverNodashi Posted September 3, 2016 Author Posted September 3, 2016 8 minutes ago, plonkster said: To check, I'm not at my computer and will answer more fully later but doing this in Python would be easy enough and of you're worried about some kind of intellectual property leaking out you could use cython to turn critical bits into compiled shared objects, though I can hardly think how anything about the axpert could still be secret :-) Sent from my GT-I9195 using Tapatalk how would you share information gathered from a Python script, with a C# application? Quote
___ Posted September 3, 2016 Posted September 3, 2016 Well, ordinarily you'd set up a pipe, then fork the main process, each side closes one half of the pipe (because both sides of the fork inherited all the file descriptors), then the child process calls dup2 to map the pipe onto stdout, and then if calls exec to run python. The output of the python script then automatically goes to the pipe where the main process can read it. No idea how you do these low-level unix things in C# though. The other option is to embed IronPython in C#. But the whole point of using python is that you get to use pyserial which saves you a lot of crap with working out the right termio/ioctl nonsense to set up the serial port correctly from C/C++, but I don't know how well PySerial is supported by IronPython. Also, I assume your using mono to run this on linux, so now it's ironpython on linux (instead of cpython) with mono... too many mashed together technologies just to use Python. Much better to find someone to write it in C# then. @edmundp or @TinkerBoy are the C# people. Having laid eyes on an attempt to do the checksum algorithm for the Victron MK2 protocol in Visual Basic by another forumite... that would be the only one I would say you should not attempt. VB should not breed :-) Quote
SilverNodashi Posted September 4, 2016 Author Posted September 4, 2016 On 9/3/2016 at 4:35 PM, plonkster said: Well, ordinarily you'd set up a pipe, then fork the main process, each side closes one half of the pipe (because both sides of the fork inherited all the file descriptors), then the child process calls dup2 to map the pipe onto stdout, and then if calls exec to run python. The output of the python script then automatically goes to the pipe where the main process can read it. No idea how you do these low-level unix things in C# though. The other option is to embed IronPython in C#. But the whole point of using python is that you get to use pyserial which saves you a lot of crap with working out the right termio/ioctl nonsense to set up the serial port correctly from C/C++, but I don't know how well PySerial is supported by IronPython. Also, I assume your using mono to run this on linux, so now it's ironpython on linux (instead of cpython) with mono... too many mashed together technologies just to use Python. Much better to find someone to write it in C# then. @edmundp or @TinkerBoy are the C# people. Having laid eyes on an attempt to do the checksum algorithm for the Victron MK2 protocol in Visual Basic by another forumite... that would be the only one I would say you should not attempt. VB should not breed :-) eish! Ok, so it would be better to stick to one particular language then. Quote
SilverNodashi Posted September 5, 2016 Author Posted September 5, 2016 Quick question: Should I be able to read some info from the inverter, if I use a terminal application to send the commands to it? I have tried something like from a terminal, but got no responses back: picocom v1.7 port is : /dev/ttyUSB0 flowcontrol : none baudrate is : 2400 parity is : none databits are : 8 escape is : C-a local echo is : yes noinit is : no noreset is : no nolock is : no send_cmd is : sz -vv receive_cmd is : rz -vv imap is : omap is : emap is : crcrlf,delbs, Terminal ready QPIGS (NAKss (NAKss 51 50 49 47 53 B7 A9 s I got the "51 50 49 47 53 B7 A9" from the Australian forums (http://forums.aeva.asn.au/pip4048ms-inverter_topic4332_post57750.html#57753) which is the HEX command with CRC for QPIGS. So it seems that I need to send the command in a different way, but can't seem to figure it out. Quote
___ Posted September 5, 2016 Posted September 5, 2016 Look at socat. It's the Swiss army knife of serial/network/pipes. Using that and a correctly constructed echo command in a pipe should be enough to evoke a response from the inverter. Sent from my GT-I9195 using Tapatalk Quote
SilverNodashi Posted September 5, 2016 Author Posted September 5, 2016 17 minutes ago, plonkster said: Look at socat. It's the Swiss army knife of serial/network/pipes. Using that and a correctly constructed echo command in a pipe should be enough to evoke a response from the inverter. Sent from my GT-I9195 using Tapatalk I had a look at socat but couldn't figure it out, will try again later. I'm beginning to think my Axpert's serial port doesn't work, as expected. I have downloaded the "AccessPort" and tried to manually enter some commands from my Windows PC, but got no response back either. Will first have to get the basics working, but I need a Windows 7 PC Quote
SilverNodashi Posted September 5, 2016 Author Posted September 5, 2016 37 minutes ago, TinkerBoy said: Are you using USB or serial? It seems you are using serial but you are trying to send hex bytes. Why are you doing that ? I'm using serial. tried both a commands from the manual, i.e. "QPI" or "QPIGS" and the hex commands. Quote
SilverNodashi Posted September 5, 2016 Author Posted September 5, 2016 2 minutes ago, TinkerBoy said: When you send the command in serial you send the command in ascii and you add the CRC to the end. To test you comm port just run Watchpower using your serial cable. Yea, I already did the test - no comms to / from inverter in watchpower. First need to sort this out. ___ 1 Quote
superdiy Posted September 5, 2016 Posted September 5, 2016 7 hours ago, SilverNodashi said: I'm beginning to think my Axpert's serial port doesn't work, as expected. (NAKss (NAKss The above is a response from the inverter - NAK - as in Not Acknowledged - the inverter does not understand your command. The response from these inverters always start with a ( and the ss after (NAK is the check-sum characters for "(NAK". The comms is definitely working. To send QPIGS, you'll have to send the check-sum as well, as Coulomb have said, that is the HEX characters B7A9 or in ASCII that would be "·©" (without the quotes) - try sending QPIGS·© to the inverter or try doing a hextostring in your code and convert hextostring(B7A9) and append that to QPIGS. Quote
Coulomb Posted September 6, 2016 Posted September 6, 2016 The trouble with ASCII characters that have the sign (most significant) bit set is that there is no standard on how to send them or even how tp display them. For example, in superdiy's post, the CRC values B7 and A9 come out on my phone as a centred dot and a copyright symbol. I bet others have seen them as other characters. On my favourite terminal program, TeraTerm, you send such characters using the right-alt key in combination with another key. For example, B7 = 80 + 37 (in hex), so 37 is B7 with the sign bit stripped off. From any ascii table, the character whose hex representation id 37 is '7' (the seven character), do you can send B7 (in TeraTerm, when it is set up correctly) by pressing right-alt and the 7 key together (use right-alt like a shift or control key). Similarly A9 is right-alt and ')' (i.e. shift zero on most keyboards). You can't type QPIGS without the CRC characters, or by typing thr two hex characters (e.g. 5 and 1 for Q). If you have a terminal program where you can send everything in hex, then don't forget to add 0D at the end for a carriage return. These things are difficult to explain on a forum, bit once you get the idea, and have the right software tools, it's pretty easy. Quote
SilverNodashi Posted September 6, 2016 Author Posted September 6, 2016 19 minutes ago, Coulomb said: The trouble with ASCII characters that have the sign (most significant) bit set is that there is no standard on how to send them or even how tp display them. For example, in superdiy's post, the CRC values B7 and A9 come out on my phone as a centred dot and a copyright symbol. I bet others have seen them as other characters. On my favourite terminal program, TeraTerm, you send such characters using the right-alt key in combination with another key. For example, B7 = 80 + 37 (in hex), so 37 is B7 with the sign bit stripped off. From any ascii table, the character whose hex representation id 37 is '7' (the seven character), do you can send B7 (in TeraTerm, when it is set up correctly) by pressing right-alt and the 7 key together (use right-alt like a shift or control key). Similarly A9 is right-alt and ')' (i.e. shift zero on most keyboards). You can't type QPIGS without the CRC characters, or by typing thr two hex characters (e.g. 5 and 1 for Q). If you have a terminal program where you can send everything in hex, then don't forget to add 0D at the end for a carriage return. These things are difficult to explain on a forum, bit once you get the idea, and have the right software tools, it's pretty easy. And that's where I'm stuck For now, trying it with a terminal program from Linux. Quote
___ Posted September 6, 2016 Posted September 6, 2016 Man... I feel your pain. What's that checksum algorithm? Maybe I can clobber something together for you quickly. Quote
___ Posted September 6, 2016 Posted September 6, 2016 Oh snap! I know this CRC algo! We use a variant of it in one of our embedded devices. https://pypi.python.org/pypi/crc16 So let me see about that. Quote
___ Posted September 6, 2016 Posted September 6, 2016 1 minute ago, TinkerBoy said: If he can not even send a hardcoded command why waste your time with the CRC? He needs to sort out his comms first. I get the idea he has trouble copy/pasting/reproducing the non-printable checksum bytes into a terminal emulator :-) Quote
SilverNodashi Posted September 6, 2016 Author Posted September 6, 2016 Just now, plonkster said: I get the idea he has trouble copy/pasting/reproducing the non-printable checksum bytes into a terminal emulator :-) Yes, that is the problem I'm facing. That and the fact that I don't have a spare Windows 7 PC to plug into the inverter, in the garage. And I don't have a long piece of CAT5 lying around to make a very long cable to my office, and use my Windows 10 laptop. So I can't test all the nice Windows goodies found all over the interwebs. Quote
___ Posted September 6, 2016 Posted September 6, 2016 Okay, here goes. Even went with the challenge of not using external libraries (like the crc16 one). The line repeated 8 times? Yes, you can loop that, but it is faster in unrolled form :-) Call it axpert.py import sys from struct import pack from serial import Serial # Polynomial for CRC-CCITT POLY = 0x1021 def crc16x(buf): crc = 0 for ch in buf: crc ^= ord(ch) << 8 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 return crc & 0xffff cmd = sys.argv[2] checksum = crc16x(cmd) result = cmd + pack(">H", checksum) print result.encode('hex') port = Serial(sys.argv[1], 2400, timeout=1, rtscts=False) port.write(result) i = iter(lambda: port.read(1), '') print list(i) What it will do is work out the checksum, pack it in big-endian format (that's what the > does, some equipment like the Victron wants it the other way round, then you use <). Call this with: python axpert.py /dev/ttyUSB0 QPIGS Ie the two arguments is the port and the command. What it will do at the end is read everything it can get in about a second (timeout=1), then print it out and quit. Adapt baud rate as required. Also, The rtscts part is necessary when you test with socat but might actually cause problems with real hardware, so just remove that keyword argument if you can. Also, you will need pyserial and python2.7. On ubuntu/debian type machines: apt-get install python-serial Hope that gets you started. Quote
SilverNodashi Posted September 6, 2016 Author Posted September 6, 2016 10 hours ago, plonkster said: Okay, here goes. Even went with the challenge of not using external libraries (like the crc16 one). The line repeated 8 times? Yes, you can loop that, but it is faster in unrolled form :-) Call it axpert.py import sys from struct import pack from serial import Serial # Polynomial for CRC-CCITT POLY = 0x1021 def crc16x(buf): crc = 0 for ch in buf: crc ^= ord(ch) << 8 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 crc = (crc << 1 ^ POLY) if (crc & 0x8000) else crc << 1 return crc & 0xffff cmd = sys.argv[2] checksum = crc16x(cmd) result = cmd + pack(">H", checksum) print result.encode('hex') port = Serial(sys.argv[1], 2400, timeout=1, rtscts=False) port.write(result) i = iter(lambda: port.read(1), '') print list(i) What it will do is work out the checksum, pack it in big-endian format (that's what the > does, some equipment like the Victron wants it the other way round, then you use <). Call this with: python axpert.py /dev/ttyUSB0 QPIGS Ie the two arguments is the port and the command. What it will do at the end is read everything it can get in about a second (timeout=1), then print it out and quit. Adapt baud rate as required. Also, The rtscts part is necessary when you test with socat but might actually cause problems with real hardware, so just remove that keyword argument if you can. Also, you will need pyserial and python2.7. On ubuntu/debian type machines: apt-get install python-serial Hope that gets you started. Thanx I did try this, but still got no response back from the inverter. Ugh! I am beginning to think there's something wrong with the USB to serial adapter I'm using. I'll make connect a cable directly to the serial pins tomorrow and see if that works.The Axpert remove interface works fine, so the serial port in the inverter works fine as well. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.