Vbus 2 rs232 Json

Bonjour,
Dans cet article je propose le partage du développement que j’ai réalisé pour décoder les trames Vbus. toutes les spécification se trouvent ici: https://danielwippermann.github.io/resol-vbus/vbus-specification.html
tout à disparu de son site. Je ne l’ai hélas pas téléchargé……
Le code ci-après est dérivé du travail de M. Wipperman. Vous pouvez échanger sur le sujet en me contactant via formulaire contact
Version raspberry pi: vbus_decode

Version arduino:

/*
nouvelle version de Vbusread
* permet de selectionner un DFA
* serveur web fichiers json
* Prise en compte du CRC
* version ok  pas toucher
* 
* Legal Notices
* RESOL, VBus, VBus.net and others are trademarks or registered trademarks of RESOL - Elektronische Regelungen GmbH.
* Le sketch d'origine provient de M. Wiperman,  http://danielwippermann.github.io
* 
* Vbus 9600 bauds 8 bits pas de parité un stop bit
*  Vbus ttl avec un opto coupleur  SFH6206 une resistance de 4,7k en série avec  led, coté transistor, collecteur sur +5V,emeteur une résistance pulldown de 3,3K vers la masse
*  |  C  E |   40 @ Ic/Iin  Iin 1mA  
*  |          |
* .| in  in|

* si pas de vbus -> affiche timeout -> ok
* sonde dht22 pour température et humidité local
* test:  curl http://192.168.1.140/vbus.json
* switch debug rs232:  curl http://192.168.1.141/disp_rs232.json
http://192.168.1.141/temperatures.json
modif ligne 230 inversion poid fort et faible et _ manquant
 */
 #include <SoftwareSerial.h>
#include <EtherCard.h> //doc: https://www.aelius.com/njh/ethercard/
#include <DHT.h>
#define VERSION "0.1.04"
#define DHTPIN 7
#define soft_rxd_pin 8
#define LED 2
#define DHTTYPE DHT22 // DHT 22
DHT dht(DHTPIN, DHTTYPE);
#define FLength 6   // Framelength
#define FOffset 10  // Offset start of Frames
#define FSeptet 4   // Septet byte in Frame
#define LED 2

#define timerInterval 1500
SoftwareSerial Soft_serial(soft_rxd_pin, 9,false);

#define debug 1
//ENC28J60 ethernet
	// Ethernet uses 10,11,12,13
	static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x34 };
	#define STATIC 1 // DHCP=0 , static=1
	#define version 0.1.0
	#if STATIC
		static byte myip[] = { 192,168,1,141 }; // static ip address
	#endif
	byte Ethernet::buffer[400]; // tcp ip send and receive buffer
	BufferFiller bfill;

#define FLOATEMIT

const char header_json[] PROGMEM =
    "HTTP/1.0 200 OK\r\n"
    "content-Type: application/json;charset=utf-8\r\n"
    "\r\n";

const char header_json2[] PROGMEM =
    "HTTP/1.0 200 OK\r\n"
    "content-Type: application/json;charset=utf-8\r\n"
    "Refresh: 5\r\n"
    "\r\n";

const char header_refresh[] PROGMEM = "Refresh: 5\r\n";

const char page_help[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"content-Type: application/json;charset=utf-8\r\n"
"\r\n"
"{\"help\":{ "
	"\"compil_date\": \"" __DATE__"\","
	"\"compil_time\": \"" __TIME__"\","
	"\"src_file\": \"" __FILE__"\","
	"\"version\": \""VERSION"\""
"}}\r\n";

const char error_json[] PROGMEM =
    "HTTP/1.0 404 Not Found\r\n"
    "content-Type: application/json;charset=utf-8\r\n"
    "\r\n"
    "{\"vbus\":{ \"error\": 404}}"
    "\r\n";

bool all;
bool disp_rs232 = false;
bool refresh = false;
unsigned char Buffer[75];
char char_buffer[80];

long lastTimeTimer;
//long timerInterval =600;
//int temp;
byte i;
uint16_t networkaddress;
byte nb_crc_error;
char sensor1_tempc [6];
char sensor2_tempc [6];
char sensor3_tempc [6];
char sensor4_tempc [6];
char refresh_string [] = "false";
//char * refresh_string ;
char temp_VFD [6];
char PumpSpeed1;  // in  %
char PumpSpeed2;  //  in %
char RelaisMask;
char ErrorMask;
char Scheme;
uint16_t OperatingHoursRelais1;
uint16_t OperatingHoursRelais2;
uint32_t HeatQuantity;
uint16_t Version;
uint16_t OperatingHoursRelais1Today;
uint16_t SystemTime;

uint16_t flow_VFD;
unsigned int Destination_address;
unsigned int Source_address;
unsigned char ProtocolVersion;
unsigned int Command;
unsigned char Framecnt;
unsigned char Septet;
unsigned char Checksum;
unsigned char calc_Checksum;
unsigned char tot_crc_error =0;






void setup() {
  
	pinMode(LED, OUTPUT);
	digitalWrite(LED, HIGH);
	dht.begin();
   Serial.println("Arduino debugging started");
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
	; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Go!");
  // set the data rate for the SoftwareSerial port
  Soft_serial.begin(9600);
  	//ether.begin(sizeof Ethernet::buffer, mymac);
	if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
		Serial.println( "Failed to access Ethernet controller");
	#if STATIC
		ether.staticSetup(myip);
		Serial.println("Static IP");
	#else
	if (!ether.dhcpSetup())
		Serial.println("DHCP failed");
	#endif
	ether.printIp("IP: ", ether.myip);
	digitalWrite(LED, LOW);
}

void loop() {
      //String refresh_string = "    ";
	word pos = ether.packetLoop(ether.packetReceive());
	// check if valid tcp data is received
	if (pos) {
		char* data = (char *) Ethernet::buffer + pos;
	#if debug
		Serial.println(data);
	#endif
		if (strncmp("GET / ", data, 6) == 0) {
			//Serial.println("http Get /");
			ether.httpServerReplyAck(); // send ack to the request
			memcpy_P(ether.tcpOffset(), page_help, sizeof page_help);//only the first part will sended
			ether.httpServerReply_with_flags(sizeof page_help - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
		}
		else
			if (strncmp("GET /vbus.json", data, 14) == 0) {
				//Serial.println("http GET /vbus.json");
					//digitalWrite(LED, HIGH);
				if (VBusRead(0x10)){
					//Serial.println(temp);
					nb_crc_error = extract_septep();
					tot_crc_error += nb_crc_error;
					bfill = ether.tcpOffset();

                    if (refresh)  {                
                        bfill.emit_p(PSTR("$F"),header_json2);
                        strcpy(refresh_string, "true");
                    }    
                    else {
                        bfill.emit_p(PSTR("$F"),header_json); 
                        strcpy(refresh_string, "false");
                    }
					bfill.emit_p(PSTR(
					"{\"Vbus\":{"
					"\"src_address\":\"0x$H$H\","
					"\"t_1\":$S,"
					"\"t_2\":$S,"
					"\"t_3\":$S,"
					"\"t_4\":$S,"
					"\"t_VFD\":$S,"
					"\"VFD_flow\":$D,"
					"\"Vpump1\":$D,"
					"\"heures_P1\":$D,"
					"\"Vpump2\":$D,"
					"\"heures_P2\":$D,"
					"\"heure\":\"$D:$D\","
					"\"P_tot\":$L,"
					"\"ErrorMask\":\"0x$H\","
					"\"nb_crc_error\":$D,"
					"\"tot_crc_error\":$D,"
                    "\"refresh\":\"$S\""
					"}}"
					),Buffer[4],Buffer[3],sensor1_tempc,sensor2_tempc,sensor3_tempc,sensor4_tempc,temp_VFD,flow_VFD,
					  PumpSpeed1,OperatingHoursRelais1,PumpSpeed2,OperatingHoursRelais2, SystemTime/60,SystemTime%60,
					  HeatQuantity, ErrorMask,nb_crc_error, tot_crc_error,refresh_string);
					  ether.httpServerReply(bfill.position());
				}
                else {
                    bfill = ether.tcpOffset();
					bfill.emit_p(PSTR("{\"Vbus\":{\"error\" :\"timeout\" }}"));
                    ether.httpServerReply(bfill.position());
                }
			}
			else
            
				if (strncmp("GET /infos_10.json", data, 17) == 0) {
					//Serial.println("GET /infos_15.json");
				   byte vbusread_code;
				   vbusread_code = VBusRead(0x10);
					if (vbusread_code){
						extract_septep();
						bfill = ether.tcpOffset();
						bfill.emit_p(PSTR(
						"$F{\"Vbus\":{"
						"\"vbusread code\":$D,"
						"\"sync\":\"0x$H\","
						"\"Src address\":\"0x$H$H\","
						"\"Dst address\":\"0x$H$H\","
						"\"22\":$D,"
						"\"23\":$D,"
						"\"24\":$D,"
						"\"25\":$D,"
						"\"28\":$D,"
						"\"29\":$D,"
						"\"30\":$D,"
						"\"31\":$D,"
						"\"34\":$D,"
						"\"35\":$D,"
						"\"35\":$D,"
						"\"37\":$D"
						"}}"
						),header_json,vbusread_code,Buffer[0],Buffer[2],Buffer[1],Buffer[3],Buffer[4],
						Buffer[22],Buffer[23],Buffer[24],Buffer[25],
						Buffer[28],Buffer[29],Buffer[30],Buffer[31],
						Buffer[34],Buffer[35],Buffer[36],Buffer[37]
						);
						ether.httpServerReply(bfill.position());
					}
				}
				else
					if (strncmp("GET /infos.json", data, 14) == 0) {
					   byte vbusread_code;
					   vbusread_code = VBusRead(0x10);
						if (vbusread_code){
							//Serial.println(temp);
							bfill = ether.tcpOffset();
							bfill.emit_p(PSTR(
							"$F{\"Vbus\":{"
							"\"vbusread code\":$D,"
							"\"sync\":\"0x$H\","
							"\"Src address\":\"0x$H$H\","
							"\"Dst address\":\"0x$H$H\","
							"\"Protocol Version\":\"0x$H\","
							"\"Command:=\":\"0x$H$H\","
							"\"Framecount\":$D,"
							"\"Checksum\":\"0x$H\","
							"\"calc Checksum\":\"0x$H\""
							"}}"
							),header_json,vbusread_code,Buffer[0],Buffer[2],Buffer[1],Buffer[3],Buffer[4],ProtocolVersion,Buffer[6],Buffer[7],Framecnt,temp_VFD,Buffer[9],VBus_CalcCrc(Buffer, 1, 8));
							ether.httpServerReply(bfill.position());
						}
					}
					else
						if (strncmp("GET /temperatures.json", data, 22) == 0) {
							bfill = ether.tcpOffset();
							char char_value[5];
							bfill.emit_p(PSTR("$F{\"dht22\":"),header_json);
							dtostrf(dht.readHumidity(),5,1 ,char_value);
							bfill.emit_p(PSTR("{\"humidity\":$S,"),char_value);
							dtostrf(dht.readTemperature(),5,1 ,char_value);
							bfill.emit_p(PSTR("\"temperature\":$S"),  char_value);
							bfill.emit_p(PSTR("}}"));
						   ether.httpServerReply(bfill.position());
						}
						else
							if (strncmp("GET /disp_rs232.json", data, 20) == 0) {
								bfill = ether.tcpOffset();
								bfill.emit_p(PSTR("$F{\"disprs232\":"),header_json);
								disp_rs232 = (! disp_rs232);
								if (disp_rs232)
									bfill.emit_p(PSTR("\"true\"}"));
								else
									bfill.emit_p(PSTR("\"false\"}"));
							   ether.httpServerReply(bfill.position());

							}
                            else
                                if (strncmp("GET /refresh.json", data, 17) == 0) {
                                    bfill = ether.tcpOffset();
                                    bfill.emit_p(PSTR("$F{\"refresh\":"),header_json);
                                    refresh = (! refresh);
                                    if (refresh)
                                        bfill.emit_p(PSTR("\"true\"}"));
                                    else
                                        bfill.emit_p(PSTR("\"false\"}"));
                                   ether.httpServerReply(bfill.position());
                                }
                                else {
                                    ether.httpServerReplyAck(); // send ack to the request
                                    memcpy_P(ether.tcpOffset(), error_json, sizeof error_json);//only the first part will sended
                                    ether.httpServerReply_with_flags(sizeof error_json - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
                                }
                                
	} //if (strncmp("GET /vbus.json"

}
byte VBusRead (byte DFA) {
	/*code sortie   0 no data
	 *              3 sortie sur deuxieme Sync
	 * 				2 trop de données

	*/
	byte c;
	bool start;
	bool DFA_ok = false;
	lastTimeTimer = millis();

	int index;
	index = 0;

	while (index < 73) {
		if (Soft_serial.available()) {
			c= (byte) Soft_serial.read();
			lastTimeTimer = millis();
			if (c == 0xAA) {
				if (DFA_ok) {
					digitalWrite(LED, HIGH);
					return 3;
				}
				index = 0;
				Buffer[0]=c;
			#if debug
				Serial.println("Sync found");
			#endif
				digitalWrite(LED, LOW);
			}
			else
				if (index == 1){
					if (c == DFA)
						DFA_ok = true;
				}
			if (DFA_ok) {
				Buffer[index]=c;
			#if debug
				char s[7];
				sprintf(s, "%02X ",c);
				Serial.print(s);
			#endif
			}
			index ++;
		}
		if ((timerInterval > 0) &&  (millis() - lastTimeTimer > timerInterval )  ) {
            if (disp_rs232) {
                Serial.print("time_out ");
                Serial.println(lastTimeTimer);
            }
			return 0;

		}
	}
	digitalWrite(LED, LOW);
	return 2;
} //byte VBusRead (byte DFA)


byte extract_septep () {
	byte F;
	byte nb_crc_error =0;
	//0       SYNC byte 0XAA
	//1 2      dest address
	//3 4      source address
	//5 protocol verion
	//6 7 command
	//8 Number of payload frames
	//9 Checksum for offset 1-8
	Destination_address = Buffer[2] << 8 | Buffer[1];
	Source_address      = Buffer[4] << 8 | Buffer[3];
	Command 			= Buffer[7] << 8 | Buffer[6];
	ProtocolVersion 	= (Buffer[5]>>4) + (Buffer[5] &(1<<15));
	Framecnt = Buffer[8];
	Checksum = Buffer[9];
	calc_Checksum = VBus_CalcCrc(Buffer, 1, 8);

	///*******************  Frame 1  *******************
	F=FOffset;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum) 
		nb_crc_error ++;
    else {
        Septet=Buffer[F+FSeptet];
        InjectSeptet(Buffer,F,4);
        dtostrf(CalcTemp(Buffer[F+1], Buffer[F])  ,5,1 ,sensor1_tempc);
        dtostrf(CalcTemp(Buffer[F+3], Buffer[F+2]),5,1 ,sensor2_tempc);
    }
	///*******************  Frame 2  *******************
	F=FOffset+FLength;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum) 
		nb_crc_error ++;
    else {
        Septet=Buffer[F+FSeptet];
        InjectSeptet(Buffer,F,4);
        dtostrf(CalcTemp(Buffer[F+1], Buffer[F])  ,5,1 ,sensor3_tempc);
        dtostrf(CalcTemp(Buffer[F+3], Buffer[F+2]),5,1 ,sensor4_tempc);
    }
	///*******************  Frame 3  *******************
	F=FOffset+FLength*2;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
    if (Buffer[F+5] != calc_Checksum) {
		nb_crc_error ++;
        PumpSpeed1 =255;
    }
    else {
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	PumpSpeed1 = ((Buffer[F] & 0X7F));
	OperatingHoursRelais1=Buffer[F+3] << 8 | Buffer[F+2];
}
	///*******************  Frame 4  *******************
	F=FOffset+FLength*3;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
    if (Buffer[F+5] != calc_Checksum) {
		nb_crc_error ++;
        PumpSpeed2 =255;
    }
    else {
        Septet=Buffer[F+FSeptet];
        InjectSeptet(Buffer,F,4);
        PumpSpeed2 = (Buffer[F+0] & 0X7F);
        OperatingHoursRelais2=Buffer[F+3] << 8| Buffer[F+2];
    }
	///*******************  Frame 5  *******************
	F=FOffset+FLength*4;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	Scheme    =  Buffer[F+1];
	///*******************  Frame 6  *******************
	F=FOffset+FLength*5;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	ErrorMask= Buffer[F];
	SystemTime = Buffer[F+3] << 8 | Buffer[F+2];
	///*******************  Frame 7  *******************
	F=FOffset+FLength*6;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	///*******************  Frame 8  *******************
	F=FOffset+FLength*7;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
 //HeatQuantity = (Buffer[F + 3] << 24| Buffer[F+2]  << 16 | Buffer[F + 1] << 8 | Buffer[F]);
 HeatQuantity = (Buffer[F+2] * 65535) + word ((Buffer[F + 1] << 8 | Buffer[F]));

	//HeatQuantity = (Buffer[F + 3] << 8 | Buffer[F+2]) + word ((Buffer[F + 1] << 8 | Buffer[F]));
	///*******************  Frame 9  *******************
	F=FOffset+FLength*8;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	Version=Buffer[F+1] << 8| Buffer[F];
	///*******************  Frame 10  *******************
	F=FOffset+FLength*9;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	if (Buffer[F+5] != calc_Checksum)
		nb_crc_error ++;
	Septet=Buffer[F+FSeptet];
	InjectSeptet(Buffer,F,4);
	dtostrf(CalcTemp(Buffer[F+1], Buffer[F])  ,5,1 ,temp_VFD);
	flow_VFD=Buffer[F+3] << 8| Buffer[F+2];
	///******************* End of frames ****************
	if (disp_rs232) {
		for (int i = 0; i < 10; i++) {
			F=FOffset+FLength * i;
			serial_print_buffer(Buffer,F,i);
		}
	}
	return nb_crc_error;
} //byte extract_septep ()

// This function converts 2 data bytes to a temperature value.
float CalcTemp(int Byte1, int Byte2) {
   int v;
	v = Byte1 << 8 | Byte2; //bit shift 8 to left, bitwise OR
	if (Byte1 == 0x00)
		v= v & 0xFF;
	if (Byte1 == 0xFF)
		v = v - 0x10000;
	return (float)((float) v * 0.1);
}

unsigned char VBus_CalcCrc(const unsigned char *Buffer, int Offset, int Length) {
	//source: VBus Protocol Specification page 9
	unsigned char Crc = 0x7F;
	for (int i = 0; i < Length; i++) {
		Crc = (Crc - Buffer [Offset + i]) & 0x7F;
	}
	return Crc;
}
// The following is needed for decoding the data
void  InjectSeptet(unsigned char *Buffer, int Offset, int Length) {
	for (unsigned int i = 0; i < Length; i++) {
		if (Septet & (1 << i)) {
			Buffer [Offset + i] |= 0x80;
		}
	}
}
void serial_print_buffer (unsigned char *Buffer,int F, int i) {
	byte calc_Checksum;
	calc_Checksum = VBus_CalcCrc(Buffer, F, 5);
	sprintf(char_buffer,"frame %02d: %03d  %03d %03d %03d",i,Buffer[F],Buffer[F+1],Buffer[F+2],Buffer[F+3]);
	Serial.print(char_buffer);
	if (Buffer[F+5] == calc_Checksum)
		Serial.println("  checksum: OK");
	else {
		Serial.print(Buffer[F+5]);
		Serial.print(" ");
		Serial.println(calc_Checksum);
	}
}

// Frame info for the Resol resol CS4 and CS plus
// modidied by Dimi
// voir doc deltasol bs+ id: 2211 
// http://danielwippermann.github.io/resol-vbus/#/#0010_1122_0100
// protocole: les bits de poids forts sont à zéro, il sont contenus dans le 5 e octet
// T° exemple 19,9°  199 D  0 D   28,6°  30 D 1 D  30 * 0.1 + 2.26 * 30
//-1,2° 244D 255D
//Offset  Size    Mask    Name                    Factor  Unit
//frame 0
//0 SYNC byte 0xAA
//1 LSB dest address appelé DFA valeur 0x10 ou 0x15
//2 MSB dest address
//3 LSB src address
//4 MSB src address
//5 protocol version
//6 LSB command  
//7 MSB command  
//      0x0100 Packet contains data for slave
//      0x0100 Packet contains data for slave
//      0x0300 Request answer of slave
//Frame 1 pour dest adress 0x0010
//10			1     Temperature sensor 1    0.1     C°
//11			1     Temperature sensor 1    25.6    C°
//12			1     Temperature sensor 2    0.1     C°
//13			1     Temperature sensor 2    25.6    C°
//frame 2
//16			1     Temperature sensor 3    0.1     C°
//17			1     Temperature sensor 3    25.6    C°
//18			1     Temperature sensor 4    0.1     C°
//19			1     Temperature sensor 4    25.6    C°
//frame 3
//22       1               Pump speed pump         %
//23       1               ?
//24      1               heure relai 1             1h
//25      1               heure relai 1             256
//frame 4
//28      2               vitesse relai 2           %
//29			?
//30      1               heure relai 2            1
//31      1               heure relai 2            256
//frame 5
//34      1               unit type       1
//35      1               system                    1
//37
//37
//frame 6
//40		0x01	sensor 1 defekt        1
//40		0x02	sensor 2 defekt        1
//40		0x04	sensor 3 defekt        1
//40		0x08	sensor 4 defekt        1
//40		0x10	sensor GFD        1
//41			error mask		256
//42 			temps en minutes	1
//43			temps			256
//frame 7
//46			status mask		1
//47			status mask		256
//48			status mask		65536
//49			status mask		16777216
//frame 8
//52			compteur energie	1	wh
//53			compteur energie	256	wh
//54			compteur energie	65536	wh
//55			compteur energie	1	wh
//frame 9
//58			sw version		0.01
//59			sw version		2.56
//60
//61
//frame 10 a verifier -> ok
//64			Temp GFD		0.1
//65			temp GFD		2.56
//66			debit1			1	l/h
//67			debit1			256	l/h

// Each frame has 6 bytes
// byte 1 to 4 are data bytes -> MSB of each bytes
// byte 5 is a septet and contains MSB of bytes 1 to 4
// byte 6 is a checksum
Shéma opto coupleur

Laisser un commentaire