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

Regulation chaudiere au bois

Bonjour,

J’ai commencé le développement d’une régulation basée sur un Arduino.
Pourquoi je n’acquière pas un produit du commerce:
Les solution commerciales ne répondent pas à mes attentes en particulier la réaction en cas de problèmes. D’autres part, bien qu’équipée de bus, la communication est souvent un protocole fermé, il est plus simple de développer un système de communication que comprendre et surtout arriver à utilser celui mis en place par le constructeur.