Vbus 2 rs232 Json

Bonjour,
Dans cet article je propose le partage du développement que j’ai réalisé pour décoder les trammes Vbus. toutes les pécification se trouvent ici: https://danielwippermann.github.io/resol-vbus/vbus-specification.html
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

/* VBus decoder to rs232 json data
 * * 
 *Version specifique à la régulation delta CS plus
 * ok le 2/11/20
 * * Legal Notices
 * RESOL, VBus, VBus.net and others are trademarks or registered trademarks of RESOL - Elektronische Regelungen GmbH.
 * All other trademarks are the property of their respective owners.
 * Le sketch d'origine provient de M. Wiperman,  http://danielwippermann.github.io
sur ses page vous trouverez énormément d'infos sur le Vbus.  J'a simplifié l'interface electronique.
 * Vbus ttl avec un opto coupleur  SFH6206 une resistance de 4,7k en série avec les led coté transistor une résistance pullup de 1K vers le 3,3v
 * 
 * La version d'origine envoyait en POST le json au serveur.  J'aurais souhaiter faire fonctionner la carte reseau ENC28J60 hélas
 * la libray est trop lourde, et le reste plus suffisament de place pour le code.
 *	
*/

#include <SoftwareSerial.h>
//True permet d'inverser le signal TTL
SoftwareSerial portOne(8, 9,true);

//opto coupleur sur D8 avec resistance pullup 1K
// Ethernet uses 10,11,12,13
// and 4 for the SD card.
char buffer[80];
long lastTime = 0;        // will store last time 
long lastTimedht = 0;
long lastTimetemp = 0;
long lastTimevbus = 0;

long intervalvbus = 30000;           // interval at which to send data (milliseconds)

String relayPump = "off";
String relay3WayValve = "off";
String SystemAlert = "off";
char s[30];

// Settings for the VBus decoding
#define Sync  0xAA  // Synchronisation bytes
#define FLength 6   // Framelength
#define FOffset 10  // Offset start of Frames
#define FSeptet 4   // Septet byte in Frame
//#define ResolAddress 0x3271  //   ConergyDT5 (0x3271) Original default Address of the controller
 #define ResolAddress 0x2211  //    Original default Address of the controller

#define SENSORNOTCONNECTED 8888 // Sometimes this might be 888 instead.
#define DEBUG


uint16_t networkaddress;
float Sensor1_temp;
float Sensor2_temp;
float Sensor3_temp;
float Sensor4_temp;

float Sensor1_temp_max;
float Sensor2_temp_max;
float Sensor3_temp_max;
float Sensor4_temp_max;


  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 temp_GFD;
  uint16_t flow_GFD;
  //


  //Resol DeltaTherm FK specific
  char Relay1;  // in  %
  char Relay2;  //  in %

  char SystemNotification;
  //

  // These are set neither to 'on' or 'off' at initialization so at startup the value
  // from the first valid datagram will be sent to Domoticz.
  String lastRelay1 = "1";
  String lastRelay2 = "1" ;
  String lastSystemAlert = "1" ;

unsigned char Buffer[80];
volatile unsigned char Bufferlength;

unsigned int Destination_address;
unsigned int Source_address;
unsigned char ProtocolVersion;
unsigned int Command;
unsigned char Framecnt;
unsigned char Septet;
unsigned char Checksum;

long lastTimeTimer;
long timerInterval;
bool all;

// Set to "1" when debugging 
// If enabled, the Arduino sends the decoded values over the Serial port.
// If enabled it also prints the source address in case you do not
// know what controller(s) you have.
#define DEBUG 1

// Clear all maximum values
void VBusClearMax() {
	Sensor1_temp_max=0.0;
	Sensor2_temp_max=0.0;
	Sensor3_temp_max=0.0;
	Sensor4_temp_max=0.0;
}

// Initialize some parameters
// Currently setting the controller does nothing special.
void VBusInit(int addr=0) {
	timerInterval=4000;
	if (addr!=0)
		networkaddress=addr;
	else
		networkaddress=ResolAddress;

}
/* ----------Setup ----------*/
 
void setup() {
	portOne.begin(9600);

	#if DEBUG
		Serial.begin(9600);
		Serial.println("Arduino debugging started");
	#endif


all=false;
VBusClearMax();
VBusInit(0x4212);

} 
// end void setup()

/* ----------main loop  ----------*/
void loop() {

	if (VBusRead()){
		 Serial.write (0xAA); //debut tramme de sortie
        sprintf(buffer, "{\"dest_addr\":\"0x%02x\"\,\"src_addr\":\"0x%02x\"\,\"command\":%02d,\"frames\":%02d\, \"checksum\":\"0x%02x\"",Destination_address, Source_address, Command,Framecnt,Checksum);
        Serial.println(buffer);
        Serial.print("\,\"Sensor1\":");  
        Serial.print(Sensor1_temp, 1);
        Serial.print(",\"Sensor2\":"); 
        Serial.print(Sensor2_temp, 1);
        Serial.print(",\"Sensor3\":");  
        Serial.print(Sensor3_temp, 1);
        Serial.print(",\"Sensor4\":");  
        Serial.print(Sensor4_temp, 1);
        //Serial.println("}");   
		 sprintf(buffer, "\,\"time\":\"%d:%d\"\,\"error\":\"0x%04x\"\,\"energie\":%ld\,", SystemTime/60,SystemTime%60,ErrorMask,HeatQuantity);

        //sprintf(s, "{\"time\": %d:%d\"version\":%d}\n", SystemTime/60,SystemTime%60,Version);
		Serial.print(buffer);

		 sprintf(buffer, "\"P1\":%d\,\"P1_hours\":%d\,", PumpSpeed1, OperatingHoursRelais1);
		Serial.print(buffer);       

		 sprintf(buffer, "\"P2\":%d\,\"P2_hours\":%d}", PumpSpeed2, OperatingHoursRelais2);
		Serial.print(buffer);   
        Serial.write (0xEE); //fin tramme de sortie       
 
	} //end if (VBusRead)

  // loop for VBus readout and http GET requests
  // This loop is executed every intervalvbus milliseconds.
	if(millis() - lastTimevbus > intervalvbus) {
		lastTimevbus = millis(); 
	} //end loop VBus readout

  
}// end void loop()

// 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) {
		Serial.print(Buffer[F]);
		Serial.print(" ");
		Serial.print(Buffer[F+1]);
		Serial.print(" ");
		Serial.print(Buffer[F+2]);
		Serial.print(" ");
		Serial.print(Buffer[F+3]);
		Serial.print(" ");
		Serial.print(Buffer[F+4]);
		Serial.print(" ");
		Serial.println(Buffer[F+5]);
	}
// The following function reads the data from the bus and converts it all
// depending on the used VBus controller.
bool VBusRead() {
	int F;
	char c;
	bool start,stop,quit;

	start = true;
	stop = false;
	quit = false;
	Bufferlength=0;
	lastTimeTimer = 0;
	lastTimeTimer = millis();
	while ((!stop) and (!quit))  {
		portOne.listen();
		if (portOne.available()) {
			c=portOne.read();
			char sync1 =Sync;
			if (c == sync1) {
#if DEBUG
				Serial.println("Sync found");
#endif
	
				if (start) {
					start=false;
					Bufferlength=0;
//#if DEBUG
//#endif
				} else {
					if (Bufferlength<20) {
					   lastTimeTimer = 0;
					   lastTimeTimer = millis();
						Bufferlength=0;
					} else
						stop=true;
				}
			}
#if DEBUGG
			Serial.print(c, HEX);
			Serial.print(" ");
#endif            

#if DEBUGG
			char s[7];
			sprintf(s, "%02x ", c);
			Serial.print(s);
#endif





			if ((!start) and (!stop)) {
				Buffer[Bufferlength]=c;
				Bufferlength++;
			}
		}
		if ((timerInterval > 0) &&  (millis() - lastTimeTimer > timerInterval )  ) {
			quit=true;
#if DEBUG
			Serial.print("Timeout: ");
			Serial.println(lastTimeTimer);
#endif
		}
	}

   lastTimeTimer = 0;

	if (!quit) {
			//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;
		Destination_address |= Buffer[1];
		Source_address = Buffer[4] << 8;
		Source_address |= Buffer[3];
		ProtocolVersion = (Buffer[5]>>4) + (Buffer[5] &(1<<15));

		Command = Buffer[7] << 8;
		Command |= Buffer[6];
		Framecnt = Buffer[8];
		Checksum = Buffer[9];  //TODO check if Checksum is OK
#if DEBUGG
		Serial.println("---------------");
		Serial.print("Destination: ");
		Serial.println(Destination_address, HEX);
		Serial.print("Source: ");
		Serial.println(Source_address, HEX);
		Serial.print("Protocol Version: ");
		Serial.println(ProtocolVersion);
		Serial.print("Command: ");
		Serial.println(Command, HEX);
		Serial.print("Framecount: ");
		Serial.println(Framecnt);
		Serial.print("Checksum: ");
		Serial.println(Checksum);
		Serial.println("---------------");
	   
#endif
		// Only analyse Commands 0x100 = Packet Contains data for slave
		// with correct length = 10 bytes for HEADER and 6 Bytes  for each frame

		if ((Command==0x0100) and (Bufferlength==10+Framecnt*6)) {

#define deltasol_CS4
	   if (Source_address == 0x2211) { 
#if DEBUG
		Serial.println("---------------");
		Serial.println("Now decoding for 0x2211 resol CS plus");
		Serial.println("---------------");


			// Frame info for the Resol resol CS4
			//modidied by Dimi
			//voir doc deltasol bs+ id: 4221 page 26
		   // http://danielwippermann.github.io/resol-vbus/vbus-packets.html#0010_1122_0100
		   //protocole: les bits de poids forts sont à zéro, il sont contenus dans le 5 e octet 

			//Offset  Size    Mask    Name                    Factor  Unit
			//F1
			//0			2               Temperature sensor 1    1     C°
			//2			2               Temperature sensor 2    .01    C°
			//frame 2
			//4			2               Temperature sensor 3    1    C°
			//6			2               Temperature sensor 4    0.01    C°
			//frame 3
			//8       1               Pump speed pump         %      
			//9       1               ?
			//10      1               heure relai 1             1h
			//11      1               heure relai 1             256
			//frame 4
			//12      2               vitesse relai 2           %
			//13			?
			//14      1               heure relai 2            1
			//15      1               heure relai 2            256
			//frame 5
			//16      1               unit type       1
			//17      1               system                    1
			//18
			//19
			//frame 6
			//20		10x01		sensor 1 defekt        1
			//20		0x02	sensor 2 defekt        1
			//20		0x04	sensor 3 defekt        1
			//20		0x08	sensor 4 defekt        1
			//20		0x10	sensor GFD        1            
			//21			error mask		256 
			//22 			temps en minutes	1
			//23			temps			256
			//frame 7
			//24			status mask		1
			//25			status mask		256
			//26			status mask		65536
			//27			status mask		16777216
			//frame 8
			//28			compteur energie	1	wh
			//29			compteur energie	256	wh
			//30			compteur energie	65536	wh
			//31			compteur energie	1	wh
			//frame 9
			//32			sw version		0.01
			//33			sw version		2.56
			//34
			//35
			//frame 10 a verifier
			//36			Temp GFD		0.1
			//37			temp GFD		2.56
			//38			debit1			1	l/h
			//39			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
			//
			
            ///*******************  Frame 1  *******************
			F=FOffset;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);

			Sensor1_temp =CalcTemp(Buffer[F+1], Buffer[F]);
			Sensor2_temp =CalcTemp(Buffer[F+3], Buffer[F+2]);
 
			Serial.print("frame1: ");
			serial_print_buffer(Buffer,F);
			///*******************  Frame 2  *******************
			F=FOffset+FLength;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);

			Sensor3_temp =CalcTemp(Buffer[F+1], Buffer[F]);
			Sensor4_temp =CalcTemp(Buffer[F+3], Buffer[F+2]);
			Serial.print("frame2: ");
			serial_print_buffer(Buffer,F);
 			///*******************  Frame 3  *******************
			F=FOffset+FLength*2;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);

			PumpSpeed1 = ((Buffer[F] & 0X7F));
   			OperatingHoursRelais1=Buffer[F+3] << 8 | Buffer[F+2];
			Serial.print("frame3: ");
			serial_print_buffer(Buffer,F);
			///*******************  Frame 4  *******************
			F=FOffset+FLength*3;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
			PumpSpeed2 = (Buffer[F+0] & 0X7F);
			OperatingHoursRelais2=Buffer[F+3] << 8| Buffer[F+2];
			Serial.print("frame4: ");
			serial_print_buffer(Buffer,F);
 			///*******************  Frame 5  *******************
			F=FOffset+FLength*4;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
            Scheme    =  Buffer[F+1];
			Serial.print("frame5: ");
			serial_print_buffer(Buffer,F);
			///*******************  Frame 6  *******************
			F=FOffset+FLength*5;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
			ErrorMask= Buffer[F];
			SystemTime = Buffer[F+3] << 8 | Buffer[F+2];
			Serial.print("frame6: ");
			serial_print_buffer(Buffer,F);
			///*******************  Frame 7  *******************
			F=FOffset+FLength*6;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
			Serial.print("frame7: ");
			serial_print_buffer(Buffer,F);
			///*******************  Frame 8  *******************
			F=FOffset+FLength*7;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
            HeatQuantity = (Buffer[F + 3] << 8 | Buffer[F+2]) + word ((Buffer[F + 1] << 8 | Buffer[F]));
			Serial.print("frame8: ");
			serial_print_buffer(Buffer,F);
            ///*******************  Frame 9  *******************
			F=FOffset+FLength*8;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            
            Version=Buffer[F+1] << 8| Buffer[F];
			Serial.print("frame9: ");
			serial_print_buffer(Buffer,F);
            ///*******************  Frame 10  *******************
			F=FOffset+FLength*9;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
            temp_GFD=Buffer[F+1] << 8| Buffer[F];
            flow_GFD=Buffer[F+3] << 8| Buffer[F+2];
			Serial.print("frame10: ");
			serial_print_buffer(Buffer,F);          	
			///******************* End of frames ****************
#endif //DEBUG
		   }// end 0x2211 Resol CS4        
		   
		   
		   else {

			// Default temp 1-4 extraction
			// For most Resol controllers temp 1-4 are always available, so
			// even if you do not know the datagram format you can still see
			// these temps 1 to 4.

			// 

			//Offset  Size    Mask    Name                    Factor  Unit
			// Frame 1
			//0       2               Temperature sensor 1    0.1     &#65533;C
			//2       2               Temperature sensor 2    0.1     &#65533;C
			// Frame 2
			//4       2               Temperature sensor 3    0.1     &#65533;C
			//6       2               Temperature sensor 4    0.1     &#65533;C
			//
			// 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
			//
			//*******************  Frame 1  *******************
			F=FOffset;
			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);
			
			Sensor1_temp =CalcTemp(Buffer[F+1], Buffer[F]);
			Sensor2_temp =CalcTemp(Buffer[F+3], Buffer[F+2]);

			//*******************  Frame 2  *******************
			F=FOffset+FLength;

			Septet=Buffer[F+FSeptet];
			InjectSeptet(Buffer,F,4);

			Sensor3_temp =CalcTemp(Buffer[F+1], Buffer[F]);
			Sensor4_temp =CalcTemp(Buffer[F+3], Buffer[F+2]);

			///******************* End of frames ****************

		   } //End of Default temp 1-4 extraction

			if (Sensor1_temp>Sensor1_temp_max)
				Sensor1_temp_max=Sensor1_temp;
			if (Sensor2_temp>Sensor2_temp_max)
				Sensor2_temp_max=Sensor2_temp;
			if (Sensor3_temp>Sensor3_temp_max)
				Sensor3_temp_max=Sensor3_temp;
			if (Sensor4_temp>Sensor4_temp_max)
				Sensor4_temp_max=Sensor4_temp;
		  
		} // end if command 0x0100
	} // end !quit

	return !quit;
} // end VBusRead()

// 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;
	if (v==SENSORNOTCONNECTED)
		v=0;
	return (float)((float) v * 0.1);
}    
Shéma opto coupleur

Laisser un commentaire