From 51f6e85f26473db90d74b4fb0ce8ca798d053b74 Mon Sep 17 00:00:00 2001
From: gonzho000 <gonzho@web.de>
Date: Thu, 2 May 2019 15:52:19 +0300
Subject: [PATCH] Add files via upload

---
 CHPC_PCB_v1_a1.8.9.ino | 445 ++++++++++++++++++++++++++++++-----------
 1 file changed, 329 insertions(+), 116 deletions(-)

diff --git a/CHPC_PCB_v1_a1.8.9.ino b/CHPC_PCB_v1_a1.8.9.ino
index 785e620..553cfc2 100644
--- a/CHPC_PCB_v1_a1.8.9.ino
+++ b/CHPC_PCB_v1_a1.8.9.ino
@@ -21,54 +21,57 @@
 
 
 //-----------------------USER OPTIONS-----------------------
-//#define BOARD_TYPE_G 				//Type "G"
-#define BOARD_TYPE_F				//Type "F"
+#define BOARD_TYPE_G 				//Type "G"
+//#define BOARD_TYPE_F				//Type "F"
 
-//#define DISPLAY_096 		1
-#define DISPLAY_1602 		2 		// patch "inline size_t LiquidCrystal_I2C::write(uint8_t value)" if only 1st character appears: "return 1" instead of "return 0"
+//#define DISPLAY_096 		1		//1st tests, support WILL BE DROPPED OUT SOON! small OLEDs support
+#define DISPLAY_1602 		2 		//if only 1st character appears: patch 1602 library "inline size_t LiquidCrystal_I2C::write(uint8_t value)"  "return 1" instead of "return 0"
 //#define DISPLAY_NONE		-1
 
-//#define INPUTS_AS_BUTTONS	1  		//pulldown resistors required!
-//#define RS485_PYTHON		1  	
-#define RS485_HUMAN   		2
+#define INPUTS_AS_BUTTONS	1  		//pulldown resistors required!
+
+#define RS485_PYTHON		1  	
+//#define RS485_HUMAN   	2
+//#define RS485_NONE		3
+
 #define EEV_SUPPORT
 //#define	EEV_ONLY				//NO target, no relays. Oly EEV, Tae, Tbe, current sensor and may be additional T sensors
 
 #define HUMAN_AUTOINFO	10000			//print stats to console
 
-//#define WATCHDOG          			//only if u know what to do
+#define WATCHDOG          			//only if u know what to do
 //-----------------------TUNING OPTIONS -----------------------
 #define MAX_WATTS		1170.0		//user for power protection
 
-#define DEFFERED_STOP_HOTCIRCLE	3000000		//5 mins
+#define DEFFERED_STOP_HOTCIRCLE	3000000		//50 mins
 
 #define POWERON_PAUSE     	300000    	//5 mins
 #define MINCYCLE_POWEROFF 	300000    	//5 mins
 #define MINCYCLE_POWERON  	3600000  	//60 mins
+#define POWERON_HIGHTIME	10000		//10 sec, defines time after start when power consumption can be 2 times greater than normal
 
 //EEV
 #define EEV_MAXPULSES		480
 
 #define EEV_PULSE_FCLOSE_MILLIS	20		//fast close, set waiting pos., close on danger
-#define EEV_PULSE_CLOSE_MILLIS	20000		//precise close
+#define EEV_PULSE_CLOSE_MILLIS	50000		//precise close
 #define EEV_PULSE_WOPEN_MILLIS	20		//waiting pos. set
-#define EEV_PULSE_FOPEN_MILLIS	2000		//fast open, fast search 
-#define EEV_PULSE_OPEN_MILLIS	55000		//precise open
+#define EEV_PULSE_FOPEN_MILLIS	1300		//fast open, fast search 
+#define EEV_PULSE_OPEN_MILLIS	60000		//precise open
 
 #define EEV_STOP_HOLD		500		//0.1..1sec for Sanhua
 #define EEV_CLOSE_ADD_PULSES	8		//read below, close algo
-#define EEV_OPEN_AFTER_CLOSE	40		//0 - close to zero position, than close on EEV_CLOSE_ADD_PULSES
-						//N - close to zero position, than close on EEV_CLOSE_ADD_PULSES, than open on N pulses
-#define EEV_MINWORKPOS		45		//position will be not less during normal work
-//#define EEV_NONPRECISE_STEPS	3		//pulses per fast step
-#define EEV_PRECISE_START	8.5		//T difference, threshold: make slower pulses if less
-#define EEV_EMERG_DIFF		3.5		//see below
-#define EEV_EMERG_STEPS		3		//pulses per emergency close step, if dangerous condition: diff =< (desired_overheat - EEV_EMERG_DIFF) occured
-#define EEV_HYSTERESIS		0.6		//must be less than EEV_PRECISE_START, ex: overheating = 4.0, hysteresis = 0.1, if overheating in range 4.0..4.1 no EEV pulses will be done; 
-#define EEV_CLOSEEVERY		86400000	//86400000: every 24 hours, when HP is NOT working
-#define EEV_OVERHEATING		4.0
+#define EEV_OPEN_AFTER_CLOSE	47		//0 - close to zero position, than close on EEV_CLOSE_ADD_PULSES
+						//N - close to zero position, than close on EEV_CLOSE_ADD_PULSES, than open on EEV_OPEN_AFTER_CLOSE pulses
+#define EEV_MINWORKPOS		52		//position will be not less during normal work
+#define EEV_PRECISE_START	8.6		//T difference, threshold: make slower pulses if less
+#define EEV_EMERG_DIFF		2.5		//if dangerous condition: diff =< (target_diff - EEV_EMERG_DIFF) occured, ex: target diff 5.0, emerg. diff 2.0, if calculated nowtime diff <= 3.0 then EEV will be closed
+#define EEV_HYSTERESIS		0.6		//must be less than EEV_PRECISE_START, ex: target difference = 4.0, hysteresis = 0.1, when difference in range 4.0..4.1 no EEV pulses will be done; 
+#define EEV_CLOSEEVERY		86400000	//86400000: every 24 hours, done while HP is NOT working
+#define EEV_TARGET_TEMP_DIFF	4.0		//target difference between Before Evaporator and After Evaporator
+//#define EEV_DEBUG				//used to debug during fine tuning
 
-#define MAGIC     		0x39   		//change if u want to reinit T sensors
+#define MAGIC     		0x46   		//change if u want to reinit T sensors
 //-----------------------USER OPTIONS END -----------------------
 
 //#define INPUTS_AS_INPUTS	2  		//
@@ -104,16 +107,21 @@ v1.1, 15 Apr 2019:
 v1.2, 16 Apr 2019:
 - "Type F" support
 
+v1.3, 30 Apr 2019:
+- EEV changed "overheating" to "delta T"
+- EEV algo v1.1
+
 //TODO:
-- EEV define maximum working position
-- EEV to EEPROM
-- few devices at same lane for RS485_HUMAN
+- liquid ref. protection: start cold circle and sump heater if tsump =< tco/tci+1
+- periodical start of hot side circle
 - valve_4way
-- rewite re-init proc from MAGIC to emergency jumper removal at board start
 - emergency jumper support
-? Liquid ref. T protection
-? current sensor optional
-? periodical start of hot side circle
+- inputs support
+- ? rewite re-init proc from MAGIC to emergency jumper removal at board start
+- ? few devices at same lane for RS485_HUMAN
+- ? EEV target to EEPROM
+- ? list T and other things on screen with buttons
+- ? EEV define maximum working position
 */
 //-----------------------changelog END-----------------------
 
@@ -225,7 +233,7 @@ wattage1
 
 */
 
-String fw_version = "1.2";
+String fw_version = "1.3";
 
 #ifdef DISPLAY_096
 	#define DISPLAY DISPLAY_096
@@ -273,6 +281,10 @@ String fw_version = "1.2";
 	char ishuman = 1;
 #endif
 
+#ifdef RS485_NONE
+	char ishuman = 0;
+#endif
+
 //hardware resources
 #define OW_BUS_ALLTSENSORS    12
 #define SerialTxControl       13   //RS485 Direction control DE and RE to this pin
@@ -314,6 +326,10 @@ String fw_version = "1.2";
 		#define EEV_3		4
 		#define EEV_4		2
 	#endif
+	#ifdef INPUTS_AS_BUTTONS		//not sure
+		#define BUT_RIGHT 	A3
+		#define BUT_LEFT  	A2
+	#endif
 	
 #endif
 //---------------------------memory debug
@@ -354,7 +370,7 @@ union _crc {
 #define RS485Transmit    HIGH
 #define RS485Receive     LOW
 
-const char devID  = 0x44;
+const char devID  = 0x41;
 const char hostID = 0x30;
 
 SoftwareSerial RS485Serial(SerialRX, SerialTX); // RX, TX
@@ -404,17 +420,17 @@ st_tsens Ts2	;
 
 unsigned int used_sensors = 0	;    			//bit array
 
-double T_setpoint 			= 26.5;  
+double T_setpoint 			= 26.5;
 double T_setpoint_lastsaved		= T_setpoint;
-double T_EEV_setpoint 			= EEV_OVERHEATING;  
-double T_EEV_overheating		= 0.0;		//real, used during run
+double T_EEV_setpoint 			= EEV_TARGET_TEMP_DIFF;  
+double T_EEV_dt				= 0.0;		//real, used during run
 const double cT_setpoint_max 		= 45.0;  
-const double cT_heat_delta_min 		= 2.0;
-const double cT_sump_min 		= 8.0;
-const double cT_sump_max 		= 101.0;
+const double cT_hotcircle_delta_min 	= 2.0;
+const double cT_sump_min 		= 9.0;
+const double cT_sump_max 		= 110.0;
 const double cT_sump_heat_threshold 	= 16.0;
 //const double cT_sump_outerT_threshold	= 18.0;    	//?? seems to be not useful
-const double cT_before_condenser_max 	= 99.0;      
+const double cT_before_condenser_max 	= 108.0;      
 const double cT_after_evaporator_min 	= -7.0;      	// working evaporation presure ~= -10, it is constant due to large evaporator volume     // waterhouse v1: -12 is too high
 const double cT_cold_min 		= -8.0;
 const double cT_hotout_max 		= 50.0;
@@ -425,15 +441,15 @@ const double c_wattage_max 		= MAX_WATTS;   	//FUNAI: 1000W seems to be normal w
 							//PH165X1CY : 920 Watts, 4.2 A  
 const double c_workingOK_wattage_min 	= c_wattage_max/2.5;     //
 
-int heatpump_state    		= 0;
-int hotside_circle_state  	= 0;
-int coldside_circle_state 	= 0;
-int sump_heater_state    	= 0;
+bool heatpump_state    		= 0;
+bool hotside_circle_state  	= 0;
+bool coldside_circle_state 	= 0;
+bool sump_heater_state    	= 0;
 
 const long poweron_pause     	= POWERON_PAUSE    ;    	//default 5 mins
 const long mincycle_poweroff 	= MINCYCLE_POWEROFF;    	//default 5 mins
 const long mincycle_poweron  	= MINCYCLE_POWERON ;  		//default 60 mins
-int _1st_start_sleeped 		= 0;
+bool _1st_start_sleeped 		= 0;
 //??? TODO: periodical start ?
 //const long floor_circle_maxhalted = 6000000;  //circle NOT works max 100 minutes
 const long deffered_stop_hotcircle = DEFFERED_STOP_HOTCIRCLE;
@@ -592,6 +608,18 @@ void InitS_and_D(void) {
 	RS485Serial.begin(9600);
 }
 
+void PrintS (String str) {
+	#ifdef RS485_HUMAN
+		char *outChar=&str[0];  
+		digitalWrite(SerialTxControl, RS485Transmit);
+		delay(1);    
+		RS485Serial.print(outChar);
+		RS485Serial.println();
+		RS485Serial.flush();
+		digitalWrite(SerialTxControl, RS485Receive);  
+	#endif
+}
+
 void PrintS_and_D (String str, int printSerial = 1) {
 	char *outChar=&str[0];  
 	//#ifdef RS485_HUMAN
@@ -620,18 +648,22 @@ void PrintS_and_D (String str, int printSerial = 1) {
 	#endif
 }
 
-void _PrintHelp(void) {   
-	//sprintf(tweetMsg, "first variable = %d, 2nd variable = %ul", var1, var2) 
-	PrintS_and_D( "CHPC, https://github.com/gonzho000/chpc/ fw: " + fw_version  + " board: "+ hw_version);
-	PrintS_and_D(F("Commands:"));
-	PrintS_and_D(F("(?) help"));
-	PrintS_and_D(F("(+) increase aim T"));
-	PrintS_and_D(F("(-) decrease aim T"));
-	#ifdef EEV_SUPPORT
-		PrintS_and_D(F("(<) increase EEV overheating UNIMPLEMENTED!!!"));
-		PrintS_and_D(F("(>) decrease EEV overheating UNIMPLEMENTED!!!"));
+void Print_D2 () {
+	#ifdef   DISPLAY_1602
+		lcd.setCursor(0, 1);
+		lcd.print(outString);
 	#endif
-	PrintS_and_D(F("(G) get stats"));
+}
+
+
+
+void _PrintHelp(void) {   
+	PrintS( "CHPC, https://github.com/gonzho000/chpc/ fw: " + fw_version  + " board: "+ hw_version);
+	PrintS(F("Commands: \n (?) help\n (+) increase aim T\n (-) decrease aim T\n \n"));		
+	#ifdef EEV_SUPPORT
+		PrintS(F("(<) decrease EEV T diff \n(>) increase EEV T diff"));
+	#endif
+	PrintS(F("(G) get stats"));
 }
 
 void PrintS_and_D_double (double double_to_print) {
@@ -641,7 +673,7 @@ void PrintS_and_D_double (double double_to_print) {
 
 int Inc_T (void) {
 	if (T_setpoint + 0.5 > cT_setpoint_max) {
-		PrintS_and_D(F("ERR: Max T!"));	
+		PrintS_and_D(F("Max!"));	
 		delay (200);
 		return 0;
 	}
@@ -652,7 +684,7 @@ int Inc_T (void) {
 
 int Dec_T (void) {
 	if (T_setpoint - 0.5 < 1.0) {
-		PrintS_and_D(F("ERR: Min T!"));	
+		PrintS_and_D(F("Min!"));	
 		delay (200);
 		return 0;
 	}
@@ -715,8 +747,9 @@ void ReadEECheckAddr(unsigned char *to_addr) {
 	CheckIsInvalidCRCAddr(to_addr);
 	if (i != 0) {
 		while (1) { 
+			//PrintAddr(to_addr);
 			PrintS_and_D(F("Err:EEPROM, reinit!"));
-			delay(1000);
+			delay(5000);
 		}
 	}
 }
@@ -759,7 +792,6 @@ void SaveSetpointEE(void) {
 			WriteFloatEEPROM(eeprom_addr, T_setpoint);
 			millis_lasteesave = millis_now;
 			T_setpoint_lastsaved = T_setpoint;
-			//PrintS_and_D("Deb: EEsave!"); //!!!
 		}
 }
 
@@ -804,7 +836,7 @@ unsigned char FindAddr(String what, int required = 0) {
 			delay(1000);
 		}
 		if ( OneWire::crc8( dev_addr, 7) != dev_addr[7]) {
-			RS485Serial.print("Invalid CRC!\n");
+			PrintS_and_D(F("Invalid CRC! Remove and insert same sensor!\n"));
 			delay(200);
 			continue;
 		} else if (CheckAddrExists() == 1) {
@@ -816,10 +848,10 @@ unsigned char FindAddr(String what, int required = 0) {
 		}
 	}
 	while (1) {
-		PrintAddr(dev_addr);
+		//PrintAddr(dev_addr);
 		delay(1000);
 		if (s_allTsensors.getAddress(dev_addr, 0)) {
-			PrintS_and_D("Remove " + what);
+			PrintS_and_D("OK! Remove " + what);
 			delay(1000);
 		} else {
 			delay(100);
@@ -907,6 +939,7 @@ void off_EEV(){	//1 = do not take care of position
 	digitalWrite	(EEV_2,	0);
 	digitalWrite	(EEV_3,	0);
 	digitalWrite	(EEV_4,	0);
+	//PrintS_and_D("off_EEV");
 }
 
 #endif
@@ -1050,7 +1083,7 @@ void setup(void) {
 		eeprom_addr += 1;
 		T_setpoint = ReadFloatEEPROM(eeprom_addr);
 		eeprom_addr += 4;
-		PrintS_and_D("EEPROM->T " + String(T_setpoint));
+		//PrintS_and_D("EEPROM->T " + String(T_setpoint));
 		
 		z = EEPROM.read(eeprom_addr);  //high
 		eeprom_addr += 1;
@@ -1079,21 +1112,35 @@ void setup(void) {
 				}
 			}
 		#endif
-	
 		ReadEECheckAddr(Tae.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tae");
 		ReadEECheckAddr(Tbe.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tbe");
 		ReadEECheckAddr(Ttarget.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Ttarget");
 		ReadEECheckAddr(Tsump.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tsump");
 		ReadEECheckAddr(Tci.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tci");
 		ReadEECheckAddr(Tco.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tco");
 		ReadEECheckAddr(Thi.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Thi");
 		ReadEECheckAddr(Tho.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tho");
 		ReadEECheckAddr(Tbc.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tbc");
 		ReadEECheckAddr(Tac.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Tac");
 		ReadEECheckAddr(Touter.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Touter");
 		ReadEECheckAddr(Ts1.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Ts1");
 		ReadEECheckAddr(Ts2.addr);  //eeprom_addr incremeneted here
+		//PrintS_and_D("k:Ts2");
 		
+		/*
+		//?code duplicated, see ReadEECheckAddr
 		i = 0;
 		if (Tae.e == 1) 	CheckIsInvalidCRCAddr(Tae.addr	);
 		if (Tbe.e == 1) 	CheckIsInvalidCRCAddr(Tbe.addr	);
@@ -1111,11 +1158,12 @@ void setup(void) {
 		if (i != 0) {
 			while ( 1 ) { PrintS_and_D(F("EEPROM err1!")); delay (1000); }
 		}
+		*/
 	} else {
 		eeprom_addr += 1;
 		ishuman += 1;
 		WriteFloatEEPROM(eeprom_addr, T_setpoint);
-		PrintS_and_D(F("init EEPROM"));
+		//PrintS_and_D(F("init EEPROM"));
 		eeprom_addr += 4;
 		eeprom_addr += 2; //used sensors, skip
 		//Ttarget -needed, other - optional
@@ -1229,11 +1277,11 @@ void loop(void) {
 	//----------------------------- self-test !!!
 	/*
 	digitalWrite(RELAY_HEATPUMP,HIGH);
-	//delay(300);
+	delay(300);
 	digitalWrite(RELAY_HOTSIDE_CIRCLE,HIGH);
-	//delay(300);
+	delay(300);
 	digitalWrite(RELAY_COLDSIDE_CIRCLE,HIGH);
-	//delay(300);
+	delay(300);
 	digitalWrite(RELAY_SUMP_HEATER,HIGH);
 	delay(2000);
 	digitalWrite(RELAY_HEATPUMP,LOW);
@@ -1333,16 +1381,22 @@ void loop(void) {
 				EEV_cur_pos = 0;	
 			}
 			millis_eev_last_step = millis_now;
-			PrintS_and_D(String(EEV_cur_pos));		//!!!!
+			#ifdef EEV_DEBUG 
+				PrintS(String(EEV_cur_pos));	
+			#endif
 		}
 	#endif
 	//--------------------async fuctions END    
 	
-	if (  heatpump_state == 1   &&  async_wattage > c_wattage_max   ){
-		PrintS_and_D(F("Overload stop."));
-		millis_last_heatpump_on = millis_now;
-		heatpump_state = 0;
-		digitalWrite(RELAY_HEATPUMP, heatpump_state);
+	if ( heatpump_state == 1   &&  async_wattage > c_wattage_max  ) {
+		if (  ((unsigned long)(millis_now - millis_last_heatpump_off) > POWERON_HIGHTIME )	||	(async_wattage > c_wattage_max*2)) {
+			#ifdef RS485_HUMAN 
+				PrintS(("Overload." + String(async_wattage)));
+			#endif
+			millis_last_heatpump_on = millis_now;
+			heatpump_state = 0;
+			digitalWrite(RELAY_HEATPUMP, heatpump_state);
+		}
 	}
 	
 	//-------------------buttons processing
@@ -1371,7 +1425,7 @@ void loop(void) {
 					if ( i == 1 ) {
 						T_EEV_setpoint += 0.25;
 					}
-					PrintS_and_D("New EEV o.h.: " + String(T_EEV_setpoint));
+					PrintS_and_D("New EEV Td: " + String(T_EEV_setpoint));
 					delay(300);
 				#endif
 			}
@@ -1391,6 +1445,16 @@ void loop(void) {
 					outString +=  "ERR";
 				}
 				PrintS_and_D(outString, 1);    //do not print serial
+				
+				//2
+				//#ifdef EEV_SUPPORT
+				//	outString = "Tbe:" + String(Tbe.T, 1) + "Tae:" + String(Tbe.T, 1);
+				//	Print_D2();
+				//#endif
+				if (Touter.e == 1){
+					outString = "Outer:" + String(Touter.T, 1);
+					Print_D2();
+				}
 			#else
 				outString = "be:";
 				if (Tbe.e == 1){
@@ -1430,7 +1494,9 @@ void loop(void) {
 							(Ts1.e == 1 && Ts1.T == -127 )	|| 
 							(Ts2.e == 1 && Ts2.T == -127 )             ) ) {
 										errorcode = ERR_T_SENSOR;
-										PrintS_and_D("ERR:T.sens." + String(errorcode));
+										#ifdef RS485_HUMAN 
+											PrintS_and_D("ERR:T.sens." + String(errorcode)); 
+										#endif
 		}
 		//auto-clean sensor error on sensor appear	
 		// add 1xor enable here!
@@ -1455,7 +1521,9 @@ void loop(void) {
 		if ( errorcode != ERR_OK ) {
 			if (  ((unsigned long)(millis_now - millis_notification) > millis_notification_interval)  ||  millis_notification == 0 ) {
 				millis_notification = millis_now;
-				PrintS_and_D("Error:" + String(errorcode));
+				#ifdef RS485_HUMAN 
+					PrintS_and_D("Error:" + String(errorcode));
+				#endif
 				for ( i = 0; i < errorcode; i++) {
 					tone(speakerOut, ERR_HZ);  	delay (500);      
 					noTone(speakerOut);      	delay (500);
@@ -1465,6 +1533,8 @@ void loop(void) {
 
 		//-------------- EEV cycle
 		#ifdef EEV_SUPPORT
+			/*
+			//v1 algo
 			if ( EEV_apulses == 0 )	{
 				if ( 	((async_wattage < c_workingOK_wattage_min) && ((unsigned long)(millis_now - millis_eev_last_close) > EEV_CLOSEEVERY))		||  millis_eev_last_close == 0  ){
 					PrintS_and_D("EEV: FULL closing");//!!!
@@ -1491,39 +1561,39 @@ void loop(void) {
 						EEV_fast = 1;
 					}
 				} else if (errorcode == 0 && async_wattage > c_workingOK_wattage_min) {
-					T_EEV_overheating = Tae.T - Tbe.T;
-					PrintS_and_D("EEV: driving " + String(T_EEV_overheating));//!!!
+					T_EEV_dt = Tae.T - Tbe.T;
+					PrintS_and_D("EEV: driving " + String(T_EEV_dt));//!!!
 					if (EEV_cur_pos <= 0){
 						PrintS_and_D("EEV: full close protection");	
 						if (EEV_OPEN_AFTER_CLOSE != 0) {				//full close protection
 							EEV_apulses = +EEV_OPEN_AFTER_CLOSE;
+							EEV_adonotcare = 0;
 							EEV_fast = 1;
 						}
-						EEV_adonotcare = 0;
 					} else if (EEV_cur_pos > 0) {
-						if (T_EEV_overheating  < (T_EEV_setpoint - EEV_EMERG_DIFF) ) {				//emerg!
+						if (T_EEV_dt  < (T_EEV_setpoint - EEV_EMERG_DIFF) ) {				//emerg!
 							PrintS_and_D("EEV: emergency closing!");//!!!
 							EEV_apulses = -EEV_EMERG_STEPS;
 							EEV_adonotcare = 0;
 							EEV_fast = 1;
-						} else if (T_EEV_overheating  < T_EEV_setpoint) {					//too
+						} else if (T_EEV_dt  < T_EEV_setpoint) {					//too
 							PrintS_and_D("EEV: closing");//!!!
 							//EEV_apulses = -EEV_NONPRECISE_STEPS;
 							EEV_apulses = -1;
 							EEV_adonotcare = 0;
 							EEV_fast = 0;
-						} else if (T_EEV_overheating  > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) {	//very
+						} else if (T_EEV_dt  > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) {	//very
 							PrintS_and_D("EEV: fast opening");//!!!
 							//EEV_apulses =  +EEV_NONPRECISE_STEPS;
 							EEV_apulses =  +1;
 							EEV_adonotcare = 0;
 							EEV_fast = 1;
-						} else if (T_EEV_overheating > T_EEV_setpoint + EEV_HYSTERESIS) {			//too
+						} else if (T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS) {			//too
 							PrintS_and_D("EEV: opening");//!!!
 							EEV_apulses =  +1;
 							EEV_adonotcare = 0;
 							EEV_fast = 0;
-						} else if (T_EEV_overheating  > T_EEV_setpoint) {					//ok
+						} else if (T_EEV_dt  > T_EEV_setpoint) {					//ok
 							PrintS_and_D("EEV: OK");//!!!
 							//
 						}
@@ -1532,11 +1602,128 @@ void loop(void) {
 				} 
 				
 			}
-			if (	((unsigned long)(millis_now - millis_eev_last_on) > 10000)  ||  millis_eev_last_on == 0 ) {
-				PrintS_and_D("EEV: ON/OFF");//!!!
-				on_EEV();
-				delay(30);	//!!!
+			*/
+			//v1.1 algo
+			if ( errorcode == 0 && async_wattage > c_workingOK_wattage_min && EEV_cur_pos > 0 )	{
+				T_EEV_dt = Tae.T - Tbe.T;
+				#ifdef EEV_DEBUG
+					PrintS("EEV Td: " + String(T_EEV_dt));
+				#endif
+				if ( EEV_apulses >= 0 && EEV_cur_pos >= EEV_MINWORKPOS)	{
+					if (T_EEV_dt  < (T_EEV_setpoint - EEV_EMERG_DIFF) ) {				//emerg!
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 1 emergency closing!"));
+						#endif
+						EEV_apulses = -1;
+						EEV_adonotcare = 0;
+						EEV_fast = 1;
+					} else if (T_EEV_dt  < T_EEV_setpoint) {					//too
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 2 closing"));
+						#endif
+						//EEV_apulses = -EEV_NONPRECISE_STEPS;
+						EEV_apulses = -1;
+						EEV_adonotcare = 0;
+						EEV_fast = 0;
+					}
+					//faster open when needed, condition copypasted (see EEV_apulses <= 0)
+					if (T_EEV_dt  > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) {		//very
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 3 enforce faster opening"));
+						#endif
+						//EEV_apulses =  +EEV_NONPRECISE_STEPS;
+						//EEV_apulses =  +1;
+						EEV_adonotcare = 0;
+						EEV_fast = 1;
+					}
+				}
+				if ( EEV_apulses <= 0 )	{
+					if (T_EEV_dt  > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) {		//very
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 4 fast opening"));
+						#endif
+						//EEV_apulses =  +EEV_NONPRECISE_STEPS;
+						EEV_apulses =  +1;
+						EEV_adonotcare = 0;
+						EEV_fast = 1;
+					} else if (T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS) {			//too
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 5 opening"));
+						#endif
+						EEV_apulses =  +1;
+						EEV_adonotcare = 0;
+						EEV_fast = 0;
+					} else if (T_EEV_dt  > T_EEV_setpoint) {					//ok
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 6 OK"));
+						#endif
+						//
+					}
+					//faster closing when needed, condition copypasted (see EEV_apulses >= 0)
+					if (T_EEV_dt  < (T_EEV_setpoint - EEV_EMERG_DIFF) ) {				//emerg!
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 7 enforce faster closing!"));
+						#endif
+						//EEV_apulses = -EEV_EMERG_STEPS;
+						EEV_adonotcare = 0;
+						EEV_fast = 1;
+					}
+				}
 				off_EEV();
+			}
+			if ( EEV_apulses == 0 )	{
+				if ( 	((async_wattage < c_workingOK_wattage_min) && ((unsigned long)(millis_now - millis_eev_last_close) > EEV_CLOSEEVERY))		||  millis_eev_last_close == 0  ){	//close every 24h by default
+					#ifdef EEV_DEBUG
+						PrintS(F("EEV: 10 FULL closing"));
+					#endif
+					if ( millis_eev_last_close != 0 ) {
+						EEV_apulses =  -(EEV_cur_pos + EEV_CLOSE_ADD_PULSES);
+					} else {
+						EEV_apulses =  -(EEV_MAXPULSES + EEV_CLOSE_ADD_PULSES);
+					}
+					EEV_adonotcare = 1;
+					EEV_fast = 1;
+					//delay(EEV_STOP_HOLD);
+					millis_eev_last_close = millis_now;
+				} else if (errorcode != 0 || async_wattage < c_workingOK_wattage_min) {		//err or sleep
+					if (EEV_cur_pos > 0  && EEV_cur_pos > EEV_OPEN_AFTER_CLOSE) {	//waiting pos. set
+						#ifdef EEV_DEBUG
+							PrintS(F("EEV: 11 close before open"));
+						#endif
+						EEV_apulses =  -(EEV_cur_pos + EEV_CLOSE_ADD_PULSES);
+						EEV_adonotcare = 1;
+						EEV_fast = 1;
+					}
+				}
+				off_EEV();
+			}
+			if ( EEV_apulses == 0 && async_wattage < c_workingOK_wattage_min && EEV_cur_pos < EEV_OPEN_AFTER_CLOSE) {
+				#ifdef EEV_DEBUG
+					PrintS(F("EEV: 12 full close protection"));
+				#endif
+				if (EEV_OPEN_AFTER_CLOSE != 0) {				//full close protection
+					EEV_apulses = EEV_OPEN_AFTER_CLOSE - EEV_cur_pos;
+					EEV_adonotcare = 0;
+					EEV_fast = 1;
+				}
+				off_EEV();
+			}
+			if ( EEV_apulses == 0 && async_wattage >= c_workingOK_wattage_min && EEV_cur_pos < EEV_MINWORKPOS) {
+				#ifdef EEV_DEBUG
+					PrintS(F("EEV: 13 open to work"));	
+				#endif
+				if (EEV_OPEN_AFTER_CLOSE != 0) {				//full close protection
+					EEV_apulses = EEV_MINWORKPOS - EEV_cur_pos;
+					EEV_adonotcare = 0;
+					EEV_fast = 1;
+				}
+				off_EEV();
+			}
+			if (	((unsigned long)(millis_now - millis_eev_last_on) > 10000)  ||  millis_eev_last_on == 0 ) {
+				//PrintS_and_D("EEV: ON/OFF");
+				on_EEV();
+				//delay(30);
+				//off_EEV();	//off_EEV called everywhere takes care of it
 				millis_eev_last_on  =  millis_now;
 			}
 		#endif
@@ -1559,8 +1746,8 @@ void loop(void) {
 	
 			//main logic
 			if (_1st_start_sleeped == 0) {
-				PrintS_and_D("!!!!sleep disabled!!!!");
-				_1st_start_sleeped = 1;
+				//PrintS_and_D("!!!!sleep disabled!!!!");
+				//_1st_start_sleeped = 1;
 				if ( (millis_now < poweron_pause) && (_1st_start_sleeped == 0) ) {
 					PrintS_and_D("Wait: " + String(((poweron_pause-millis_now))/1000) + " s.");
 					return;
@@ -1582,7 +1769,7 @@ void loop(void) {
 			//    and (t cold out > cold min)
 			if ( 	heatpump_state == 0     		&&
 				(((unsigned long)(millis_now - millis_last_heatpump_on) > mincycle_poweroff)   ||   (millis_last_heatpump_on == 0)  )  &&
-				//( tr_hot_out < (tr_sens_1 + cT_heat_delta_min)  )    &&
+				//( tr_hot_out < (tr_sens_1 + cT_hotcircle_delta_min)  )    &&
 				errorcode == 0         							&&
 				( (Tsump.e == 1 	&& Tsump.T > cT_sump_min)  	|| (Tsump.e^1))	&&
 				( (Tsump.e == 1 	&& Tsump.T < cT_sump_max)  	|| (Tsump.e^1))	&&
@@ -1592,7 +1779,9 @@ void loop(void) {
 				( (Tbc.e == 1 	&& Tbc.T < cT_before_condenser_max) 	|| (Tbc.e^1))	&&
 				( (Tci.e == 1 	&& Tci.T > cT_cold_min)  		|| (Tci.e^1))	&&
 				( (Tco.e == 1 	&& Tco.T > cT_cold_min) 		|| (Tco.e^1))	) {
-					PrintS_and_D(F("Start"));
+					#ifdef RS485_HUMAN
+						PrintS(F("Start"));
+					#endif
 					millis_last_heatpump_off = millis_now;
 					heatpump_state = 1;
 			}
@@ -1600,7 +1789,9 @@ void loop(void) {
 			//stop if
 			//    ( (last_off > N) and (t watertank > target) )
 			if ( heatpump_state == 1     &&     ((unsigned long)(millis_now - millis_last_heatpump_off) > mincycle_poweron)    &&    (Ttarget.T > T_setpoint)) {
-				PrintS_and_D(F("Normal stop"));
+				#ifdef RS485_HUMAN 
+					PrintS(F("Normal stop"));
+				#endif
 				millis_last_heatpump_on = millis_now;
 				heatpump_state = 0;
 			}
@@ -1609,18 +1800,24 @@ void loop(void) {
 			//start if (heatpump_enabled)
 			//stop if (heatpump_disabled and (t hot out or in < t target + heat delta min) )
 			if (  (heatpump_state == 1)   &&  (hotside_circle_state  == 0)  ) {    
-				PrintS_and_D(F("Hot WP ON"));
+				#ifdef RS485_HUMAN 
+					PrintS(F("Hot WP ON"));
+				#endif
 				hotside_circle_state  = 1;
 			}
 			
 			if (  (heatpump_state == 0)        &&    (hotside_circle_state  == 1) ) {
 				if (  (deffered_stop_hotcircle != 0 	&& 	((unsigned long)(millis_now - millis_last_heatpump_on) > deffered_stop_hotcircle)   )	) {
-					if ( 	(Tho.e == 1 && Tho.T < (Ttarget.T + cT_heat_delta_min))	||
-						(Thi.e == 1 && Thi.T < (Ttarget.T + cT_heat_delta_min))	) {
-						PrintS_and_D(F("Hot WP OFF 1"));
+					if ( 	(Tho.e == 1 && Tho.T < (Ttarget.T + cT_hotcircle_delta_min))	||
+						(Thi.e == 1 && Thi.T < (Ttarget.T + cT_hotcircle_delta_min))	) {
+						#ifdef RS485_HUMAN 
+							PrintS(F("Hot WP OFF 1"));
+						#endif
 						hotside_circle_state  = 0;
 					} else {
-						PrintS_and_D(F("Hot WP OFF 2"));
+						#ifdef RS485_HUMAN 
+							PrintS(F("Hot WP OFF 2"));
+						#endif
 						hotside_circle_state  = 0;
 					}
 				}
@@ -1628,9 +1825,11 @@ void loop(void) {
 			
 			//heat if we can, just in case, ex. if lost power
 			if ( (hotside_circle_state  == 0) && 
-				( Tho.e == 1 && Tho.T > (Ttarget.T + cT_heat_delta_min)  )  	||
-				( Thi.e == 1 && Thi.T > (Ttarget.T + cT_heat_delta_min)  )  ) {
-					PrintS_and_D(F("Hot WP ON"));
+				( Tho.e == 1 && Tho.T > (Ttarget.T + cT_hotcircle_delta_min)  )  	||
+				( Thi.e == 1 && Thi.T > (Ttarget.T + cT_hotcircle_delta_min)  )  ) {
+					#ifdef RS485_HUMAN 
+						PrintS(F("Hot WP ON"));
+					#endif
 					hotside_circle_state  = 1;
 			}
 			
@@ -1638,12 +1837,16 @@ void loop(void) {
 			//start if (heatpump_enabled)
 			//stop if (heatpump_disbled)
 			if (  (heatpump_state == 1)   &&  (coldside_circle_state  == 0)  ) {
-				PrintS_and_D(F("Cold WP ON"));
+				#ifdef RS485_HUMAN 
+					PrintS(F("Cold WP ON"));
+				#endif
 				coldside_circle_state  = 1;
 			}
 			
 			if (  (heatpump_state == 0)   &&  (coldside_circle_state  == 1)  ) {
-				PrintS_and_D(F("Cold WP OFF"));
+				#ifdef RS485_HUMAN 
+					PrintS(F("Cold WP OFF"));
+				#endif
 				coldside_circle_state  = 0;
 			}
 			
@@ -1665,7 +1868,9 @@ void loop(void) {
 					(Tbc.e 	== 1 	&& 	Tbc.T 	> cT_before_condenser_max) ||
 					(Tci.e 	== 1 	&& 	Tci.T 	< cT_cold_min )       	||
 					(Tco.e 	== 1 	&& 	Tco.T 	< cT_cold_min) )     ) {
-						PrintS_and_D(F("Protective stop"));
+						#ifdef RS485_HUMAN 
+							PrintS(F("Protective stop"));
+						#endif
 						millis_last_heatpump_on = millis_now;
 						heatpump_state = 0;
 						digitalWrite(RELAY_HEATPUMP, heatpump_state);
@@ -1673,11 +1878,12 @@ void loop(void) {
 			
 			//alive_check_cycle_after_5_mins:
 			//error if
+			//v1.3: not error, just poweroff all
 			//      or (t cold in - t cold out < t workingok min)
 			//      or (t hot out - t hot in < t workingok min)
 			//      or (sump t < 25'C)
 			//      or wattage too low
-			/*
+			
 			if (  heatpump_state == 1   &&  ((unsigned long)(millis_now - millis_last_heatpump_off) > 300000)  ) {
 				//cold side processing simetimes works incorrectly, after long period of inactivity, due to T inertia on cold tube sensor, commented out
 				//if ( ( errorcode == ERR_OK )     &&   (  tr_cold_in - tr_cold_out < cT_workingOK_cold_delta_min ) ) {
@@ -1687,19 +1893,26 @@ void loop(void) {
 				//	errorcode = ERR_HOT_PUMP;
 				//}
 				if ( ( errorcode == ERR_OK )     &&   (  Tsump.e == 1 && Tsump.T < cT_workingOK_sump_min )  ) {
-					errorcode = ERR_HEATPUMP;
+					//errorcode = ERR_HEATPUMP;
+					millis_last_heatpump_on = millis_now;
+					heatpump_state = 0;
 				}
 				if ( ( errorcode == ERR_OK )     &&   ( async_wattage < c_workingOK_wattage_min )  ) {
-					errorcode = ERR_WATTAGE;
+					//errorcode = ERR_WATTAGE;
+					millis_last_heatpump_on = millis_now;
+					heatpump_state = 0;
 				}
-			}*/
+				digitalWrite(RELAY_HEATPUMP, heatpump_state);
+			}
 				
 			//disable pump by error
 			if ( errorcode != ERR_OK ) {
 				millis_last_heatpump_on = millis_now;
 				heatpump_state = 0;
 				digitalWrite(RELAY_HEATPUMP, heatpump_state);
-				//PrintS_and_D("Error stop: " + String(errorcode, HEX));
+				#ifdef RS485_HUMAN 
+					PrintS("Error stop: " + String(errorcode, HEX));
+				#endif
 			}
 			
 			//!!! self-test
@@ -1857,7 +2070,7 @@ void loop(void) {
 					}
 					outString += ",\"W1\":" + String(async_wattage);
 					#ifndef EEV_ONLY
-						outString += "\"A1\":" + String(T_setpoint);  //(A)im (target)
+						outString += ",\"A1\":" + String(T_setpoint);  //(A)im (target)
 						outString += ",\"RP\":" + String(heatpump_state*RELAY_HEATPUMP);  
 					#endif
 					if (Tci.e == 1) {
@@ -1871,9 +2084,9 @@ void loop(void) {
 						outString += ",\"THI\":" + String(Thi.T);
 					}
 					#ifndef EEV_ONLY
-						outString += ",\"RSH\":" + String(sump_heater_state*RELAY_SUMP_HEATER);                  
-						outString += ",\"RH\":" + String(hotside_circle_state*RELAY_HOTSIDE_CIRCLE);                  
-						outString += ",\"RC\":" + String(coldside_circle_state*RELAY_COLDSIDE_CIRCLE);  
+						outString += ",\"RSH\":" + String(sump_heater_state*3);                  
+						outString += ",\"RH\":" + String(hotside_circle_state*2);                  
+						outString += ",\"RC\":" + String(coldside_circle_state*1);  
 					#endif
 					if (Tbc.e == 1) {
 						outString += ",\"TBC\":" + String(Tbc.T);
@@ -1892,8 +2105,8 @@ void loop(void) {
 						outString += ",\"TT\":" + String(Ttarget.T);                                
 					}
 					#ifdef EEV_SUPPORT
-						outString += ",\"EEVP\":" + String (EEV_cur_pos);
-						outString += ",\"EEVA\":" + String (T_EEV_setpoint);
+						outString += ",\"EEVP\":" + String(EEV_cur_pos);
+						outString += ",\"EEVA\":" + String(T_EEV_setpoint);
 					#endif
 					outString += "}";
 				} else if ( (inData[2] == 0x54 ) || (inData[2] == 0x45 )) {  //(T)arget or (E)EV target format NN.NN, text