User Tools

Site Tools


vedirect_protocol:faq

VE.Direct Protocol FAQ

More information on the VE.Direct protocol is available here:

Note that, besides an FAQ, this page also contains a framehandler reference implementation in C code. See at the bottom.

1. FAQ

Q1: Can I use RS232 instead of USB?

Yes, use the VE.Direct to RS232 interface, part number ASS030520500.

Q2: When using the VE.Direct to RS232 interface, what pins do I need?

For the communication use the GND, RX and TX pins: pin 5, 2 and 3 on the DB9 connector.

Also the DTR signal (pin 4 on the DB9 connector) and/or the RTS signal (pin 7 on the DB9 connector) must be driven high to power the isolated side of the the interface. How to program the DTR and RTS differs between used operating systems and hardware. Please note that most RS232 drivers are inverting so the logic level of the DTR must be programmed to zero in most cases. When one of those pins is not driven high, you will not be able to receive data!

Background: the “VE.Direct to RS232 interface - ASS030520500” provides galvanic isolation between the VE.Direct product and the host (your computer/PLC/etc). The VE.Direct side of the PCB is powered from VE.Direct. And the RS232 side takes its power from the DTR and RTS pins.

When using an external power supply to power DTR or RTS, the minimum voltage is 5V, and maximum is 12V. Note that it is normally not necessary to use an external power supply for this: normal serial ports will either automatically drive DTR or RTS high. And if not that, than you can control those pins to be high from within the software.

Q3: How do I calculate the HEX checksum?

I have been able to get the data I need from the sensor (BMV-700H), as show in your examples (im quoting your last email below): Consider the following example:

Get Battery Capacity
:70010003E<LF>     -> Command; checksum 0x55 – 0x7 – 0x0 – 0x10 – 0x0 = 0x3E
:7001000C80076<LF> -> Response; checksum 0x55 – 0x7 – 0x0 – 0x10 – 0x0 – 0xC8 – 0x0 = 0x76

So, this works fine when the code of the operation is less than 55 (for instance, 0x10 and 0x00 = 0x1000), and I get the same checksums as you do. However, to ask for the SOC of the batteries, Im not being able to understand how to construct the request, since the code is 0x0FFF, which is greater than 0x55. Can you provide me with an example of a request, for the SOC of the batteries? I would be much appreciated.

Anwser: VE.Direct/VE.Hex data is encoded as little endian. The checksum needs to be a byte, therefore you need to wrap it while calculating the checksum.

So in code you can loop through the message as in the following pseudo code: byte checksum = 0x55; byte message[] = { 0x7, 0xff, 0x0f, 0x00 }; for (int i =0; i < sizeof(message); i++)

              checksum -= message[i];

Get command: :7<register id><flags><checksum>\n

Get Soc, register 0x0FFF :7FF0F0040\n → Checksum = 0x55 – 7 – 0xFF – 0xF – 0 = 0x40

Q4: Is the VE.Direct interface 3.3 or 5V ?

It depends on the product: some are 5v, others 3.3.

The circuits in our panels and USB interfaces work on both voltages. And they automatically adapt their TX voltage to the voltage level coming from the VE.Direct product (bmv/mppt/inverter/etc).

List of the products:

  • BMV-700: 3v3
  • MPPT all models: 5v
  • Newer MPPTs (as now under development) will remain 5V.

Q5: How much current can I draw from the power pin in the VE.Direct port?

Max 10mA average, with max 20mA/5ms bursts.

2. Framehandler reference implementation

This the main data receival routine of our consumer stack.

#include "framehandler.h"

#include <cctype>
#include <cstring>
#include <velib/utils/ve_logger.h>

#define MODULE "VE.Frame"

// The name of the record that contains the checksum.
static constexpr char checksumTagName[] = "CHECKSUM";

VeDirectFrameHandler::VeDirectFrameHandler() :
	mStop(true),
	mState(IDLE),
	mChecksum(0),
	mTextPointer(0)
{
}

void VeDirectFrameHandler::rxData(uint8_t inbyte)
{
	if (mStop) return;
	if ( (inbyte == ':') && (mState != CHECKSUM) ) {
		mState = RECORD_HEX;
	}
	if (mState != RECORD_HEX) {
		mChecksum += inbyte;
	}
	inbyte = toupper(inbyte);

	switch(mState) {
	case IDLE:
		/* wait for \n of the start of an record */
		switch(inbyte) {
		case '\n':
			mState = RECORD_BEGIN;
			break;
		case '\r': /* Skip */
		default:
			break;
		}
		break;
	case RECORD_BEGIN:
		mTextPointer = mName;
		*mTextPointer++ = inbyte;
		mState = RECORD_NAME;
		break;
	case RECORD_NAME:
		// The record name is being received, terminated by a \t
		switch(inbyte) {
		case '\t':
			// the Checksum record indicates a EOR
			if ( mTextPointer < (mName + sizeof(mName)) ) {
				*mTextPointer = 0; /* Zero terminate */
				if (strcmp(mName, checksumTagName) == 0) {
					mState = CHECKSUM;
					break;
				}
			}
			mTextPointer = mValue; /* Reset value pointer */
			mState = RECORD_VALUE;
			break;
		default:
			// add byte to name, but do no overflow
			if ( mTextPointer < (mName + sizeof(mName)) )
				*mTextPointer++ = inbyte;
			break;
		}
		break;
	case RECORD_VALUE:
		// The record value is being received.  The \r indicates a new record.
		switch(inbyte) {
		case '\n':
			// forward record, only if it could be stored completely
			if ( mTextPointer < (mValue + sizeof(mValue)) ) {
				*mTextPointer = 0; // make zero ended
				textRxEvent(mName, mValue);
			}
			mState = RECORD_BEGIN;
			break;
		case '\r': /* Skip */
			break;
		default:
			// add byte to value, but do no overflow
			if ( mTextPointer < (mValue + sizeof(mValue)) )
				*mTextPointer++ = inbyte;
			break;
		}
		break;
	case CHECKSUM:
	{
		bool valid = mChecksum == 0;
		if (!valid)
			logE(MODULE,"[CHECKSUM] Invalid frame");
		mChecksum = 0;
		mState = IDLE;
		frameEndEvent(valid);
		break;
	}
	case RECORD_HEX:
		if (hexRxEvent(inbyte)) {
			mChecksum = 0;
			mState = IDLE;
		}
		break;
	}
}

DISQUS

vedirect_protocol/faq.txt · Last modified: 2017-09-22 10:07 by mvader