2019-04-01 03:02:55 +00:00
/*
Cheap Heat Pump Controller ( CHPC ) firmware .
Copyright ( C ) 2018 - 2019 Gonzho ( gonzho @ web . de )
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
See https : //github.com/gonzho000/chpc/ for more details
*/
//-----------------------USER OPTIONS-----------------------
2019-05-02 12:52:19 +00:00
# define BOARD_TYPE_G //Type "G"
//#define BOARD_TYPE_F //Type "F"
2019-04-01 03:02:55 +00:00
2019-05-02 12:52:19 +00:00
//#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"
2019-04-01 03:02:55 +00:00
//#define DISPLAY_NONE -1
2019-05-02 12:52:19 +00:00
# define INPUTS_AS_BUTTONS 1 //pulldown resistors required!
2019-06-01 19:16:28 +00:00
//#define RS485_PYTHON 1
# define RS485_HUMAN 2
2019-05-02 12:52:19 +00:00
//#define RS485_NONE 3
2019-04-16 15:53:34 +00:00
# define EEV_SUPPORT
2019-04-16 20:31:36 +00:00
//#define EEV_ONLY //NO target, no relays. Oly EEV, Tae, Tbe, current sensor and may be additional T sensors
2019-04-16 15:53:34 +00:00
# define HUMAN_AUTOINFO 10000 //print stats to console
2019-04-01 03:02:55 +00:00
2019-05-02 12:52:19 +00:00
# define WATCHDOG //only if u know what to do
2019-04-01 03:02:55 +00:00
//-----------------------TUNING OPTIONS -----------------------
# define MAX_WATTS 1170.0 //user for power protection
2019-05-02 12:52:19 +00:00
# define DEFFERED_STOP_HOTCIRCLE 3000000 //50 mins
2019-04-01 03:02:55 +00:00
2019-04-16 15:53:34 +00:00
# define POWERON_PAUSE 300000 //5 mins
# define MINCYCLE_POWEROFF 300000 //5 mins
# define MINCYCLE_POWERON 3600000 //60 mins
2019-05-02 12:52:19 +00:00
# define POWERON_HIGHTIME 10000 //10 sec, defines time after start when power consumption can be 2 times greater than normal
2019-04-16 15:53:34 +00:00
//EEV
# define EEV_MAXPULSES 480
# define EEV_PULSE_FCLOSE_MILLIS 20 //fast close, set waiting pos., close on danger
2019-05-02 12:52:19 +00:00
# define EEV_PULSE_CLOSE_MILLIS 50000 //precise close
2019-04-16 15:53:34 +00:00
# define EEV_PULSE_WOPEN_MILLIS 20 //waiting pos. set
2019-05-02 12:52:19 +00:00
# define EEV_PULSE_FOPEN_MILLIS 1300 //fast open, fast search
# define EEV_PULSE_OPEN_MILLIS 60000 //precise open
2019-04-16 15:53:34 +00:00
# define EEV_STOP_HOLD 500 //0.1..1sec for Sanhua
# define EEV_CLOSE_ADD_PULSES 8 //read below, close algo
2019-05-02 12:52:19 +00:00
# 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
2019-06-01 19:16:28 +00:00
//#define EEV_DEBUG //used to debug during fine tuning, "RS485_HUMAN" only
2019-05-02 12:52:19 +00:00
# define MAGIC 0x46 //change if u want to reinit T sensors
2019-04-01 03:02:55 +00:00
//-----------------------USER OPTIONS END -----------------------
2019-04-16 20:31:36 +00:00
//#define INPUTS_AS_INPUTS 2 //
//#define RS485_MACHINE 3 //?? or part of Python?
2019-04-01 03:02:55 +00:00
//-----------------------changelog-----------------------
/*
v1 .0 :
- Displays support
- define TYPE F / G and rearrange ports
- multi - DS18b20 support on lane
- skip non - important DS18B20 during init
- rewrite Main Cycle to unification : some sensors can be absent , ex : T_hot_out can be absent because i ' ts used as target
- 2 on - board buttons support : + / - aim
- DISPLAY : indication : real and aim
- RS485_HUMAN : remote commands + , - , G , 0x20 / ? / Enter
- buttons : < > increase_decrease t
- simpliest thermostat scheme : only T target
- rename all procs
- RS485_PYTHON : print to console inspite of mode diring init proc
- faster wattage overload processing
- write aim value to EE if needed , period : 15 mins ( eq . 1041 days )
- deferred stop of hot side circle
- 80 microseconds at 9600
2019-04-16 15:53:34 +00:00
v1 .1 , 15 Apr 2019 :
2019-04-01 03:02:55 +00:00
- HUMAN_AUTOINFO time
2019-04-16 15:53:34 +00:00
- EEV_ONLY mode
2019-04-01 03:02:55 +00:00
- EEV_Support
2019-04-16 15:53:34 +00:00
- EEV auto poweron / poweroff every 10 sec
2019-04-16 20:31:36 +00:00
- EEV_recalibration_time to stop HP and recalibrate EEV from zero level ex : every 24 hours
2019-04-16 15:53:34 +00:00
2019-04-16 16:35:20 +00:00
v1 .2 , 16 Apr 2019 :
2019-04-16 20:31:36 +00:00
- " Type F " support
2019-04-16 16:35:20 +00:00
2019-05-02 12:52:19 +00:00
v1 .3 , 30 Apr 2019 :
- EEV changed " overheating " to " delta T "
- EEV algo v1 .1
2019-04-16 15:53:34 +00:00
//TODO:
2019-05-02 12:52:19 +00:00
- liquid ref . protection : start cold circle and sump heater if tsump = < tco / tci + 1
- periodical start of hot side circle
2019-04-01 03:02:55 +00:00
- valve_4way
- emergency jumper support
2019-05-02 12:52:19 +00:00
- inputs support
- ? rewite re - init proc from MAGIC to emergency jumper removal at board start
- ? EEV target to EEPROM
- ? list T and other things on screen with buttons
- ? EEV define maximum working position
2019-06-01 19:16:28 +00:00
- ? few devices at same lane for RS485_HUMAN
2019-04-01 03:02:55 +00:00
*/
//-----------------------changelog END-----------------------
// DS18B20 pins: GND DATA VDD
//Connections:
//DS18B20 Pinout (Left to Right, pins down, flat side toward you)
//- Left = Ground
//- Center = Signal (Pin N of arduino): (with 3.3K to 4.7K resistor to +5 or 3.3 )
//- Right = +5 or +3.3 V
//
//
// high volume scheme: +---- +5V (12V not tested)
// |
// +----+
// 1MOhm piezo
// +----+
// |(C)
// pin -> 1.6 kOhms -> (B) 2n2222 < front here
// |(E)
// +--- GND
//
/*
scheme SCT - 013 - 000 :
2 pins used : tip and sleeve , center ( ring ) not used http : //cms.35g.tw/coding/wp-content/uploads/2014/09/SCT-013-000_UNO-1.jpg
pins are interchangeable due to AC
32 Ohms ( 22 + 10 ) between sensor pins ( 35 = = ideal )
Pin1 :
- via elect . cap . to GND
- via ~ 10 K . .470 K resistor to GND
- via ~ 10 K . .470 K resistor to + 5 ( same as prev . )
if 10 K + 10 K used : current is 25 mA
use 100 K + 100 K for 3 phases
Pin2 :
- to analog pin
- via 32. .35 Ohms resistor to Pin1
+ 5 - - - - - - - - - - - - - - - - - - - - - - - - - +
|
|
# R1 10K+
|
|
| ~ 2.5 at this point
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - +
| | | |
# _ elect. cap. # R2 10K+ (same as R1) SCT-013-000 $ # R3 = 35 Ohms (ideal case), 32 used
| | | |
GND - - - - - - - - + - - - - - - - - - - - - - - - + + - - - - + - - - - - - - - > to Analog pin
WARNING : calibrate 3 sensors together , from different sellers , due to case of incorrectly worked 1 of 3 sensor
P ( watts ) = 220 * 220 / R ( Ohms )
*/
//
//MAX 485 voltage - 5V
//
// use resistor at RS-485 GND
// 1st test: 10k result lot of issues
// 2nd test: 1k, issues
// 3rd test: 100, see discussions
//16-ch Multiplexer EN pin: active LOW, connect to GND
//used pins:
//!!! ACTUALISE
//2: Z
//3: S3
//4: S2
//5: S1
//6: S0
//7: relay 2
//8: relay 3
//9: speaker
//10: relay 4
//11-13: rs485
//A0: relay 1
//A1: power monitor
/*
relay 1 : heat pump
relay 2 : hot side pump
relay 3 : cold side pump
relay 4 : ( future ) heatpump sump heater
t0 : room
t1 : heatpump sump
t2 : cold in
t3 : cold out
t4 : hot in
t5 : hot out
t6 : before condenser
t7 : condenser - evaporator
t8 : after evaporator
t9 : outer
tA : warm floor
wattage1
*/
2019-06-01 19:16:28 +00:00
String fw_version = " 1.4 " ;
2019-04-01 03:02:55 +00:00
# ifdef DISPLAY_096
# define DISPLAY DISPLAY_096
# include <Wire.h>
# include "SSD1306Ascii.h"
# include "SSD1306AsciiWire.h"
# define I2C_ADDRESS 0x3C
SSD1306AsciiWire oled ;
# endif
# ifdef DISPLAY_1602
# define DISPLAY DISPLAY_1602
# include <Wire.h>
# include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd ( 0x3f , 16 , 2 ) ; // set the LCD address to 0x27 for a 16 chars and 2 line display
# endif
# ifdef DISPLAY_NONE
# define DISPLAY DISPLAY_NONE
# endif
# ifndef DISPLAY
# define DISPLAY -1
# endif
//
# ifdef INPUTS_AS_BUTTONS
# define INPUTS INPUTS_AS_BUTTONS
# endif
# ifdef INPUTS_AS_INPUTS
# define INPUTS INPUTS_AS_INPUTS
# endif
//
# ifdef RS485_PYTHON
# define RS485 RS485_PYTHON
char ishuman = 0 ;
# endif
# ifdef RS485_HUMAN
# define RS485 RS485_HUMAN
char ishuman = 1 ;
# endif
2019-05-02 12:52:19 +00:00
# ifdef RS485_NONE
char ishuman = 0 ;
# endif
2019-04-01 03:02:55 +00:00
//hardware resources
# define OW_BUS_ALLTSENSORS 12
# define SerialTxControl 13 //RS485 Direction control DE and RE to this pin
# define speakerOut 6
# define em_pin1 A6
# define EMERGENCY_PIN A7
2019-04-16 17:38:55 +00:00
2019-04-16 16:35:20 +00:00
2019-04-01 03:02:55 +00:00
# ifdef BOARD_TYPE_G
2019-04-16 15:53:34 +00:00
String hw_version = " Type G v1.x " ;
2019-04-01 03:02:55 +00:00
# define RELAY_HEATPUMP 8
# define RELAY_HOTSIDE_CIRCLE 9
# define RELAY_COLDSIDE_CIRCLE 7
# define RELAY_SUMP_HEATER 10
# define RELAY_4WAY_VALVE 11
# ifdef INPUTS_AS_BUTTONS
2019-04-16 15:53:34 +00:00
# define BUT_RIGHT A3
# define BUT_LEFT A2
# endif
2019-04-16 17:38:55 +00:00
# ifdef EEV_SUPPORT
# define EEV_1 2
# define EEV_2 4
# define EEV_3 3
# define EEV_4 5
2019-04-01 03:02:55 +00:00
# endif
2019-04-16 16:35:20 +00:00
# endif
# ifdef BOARD_TYPE_F
String hw_version = " Type F v1.x " ;
# define RELAY_HEATPUMP 7
# define RELAY_COLDSIDE_CIRCLE 8
2019-04-16 20:31:36 +00:00
# define LATCH_595 10
# define CLK_595 11
# define DATA_595 9
//595.0: relay 3 RELAY_HOTSIDE_CIRCLE, 595.1: relay 4 RELAY_SUMP_HEATER, 595.2: relay 5 RELAY_4WAY_VALVE, 595.3: uln 6, 595.4: uln 7, 595.5: uln 8, 595.6: uln 9, 595.7: uln 10
2019-04-16 17:38:55 +00:00
# ifdef EEV_SUPPORT
# define EEV_1 5
# define EEV_2 3
# define EEV_3 4
# define EEV_4 2
# endif
2019-05-02 12:52:19 +00:00
# ifdef INPUTS_AS_BUTTONS //not sure
# define BUT_RIGHT A3
# define BUT_LEFT A2
# endif
2019-04-16 16:35:20 +00:00
2019-04-01 03:02:55 +00:00
# endif
//---------------------------memory debug
# ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern " C " char * sbrk ( int incr ) ;
# else // __ARM__
extern char * __brkval ;
# endif // __arm__
int freeMemory ( ) {
char top ;
# ifdef __arm__
return & top - reinterpret_cast < char * > ( sbrk ( 0 ) ) ;
# elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
return & top - __brkval ;
# else // __arm__
return __brkval ? & top - __brkval : & top - __malloc_heap_start ;
# endif // __arm__
}
//---------------------------memory debug END
# include <avr/wdt.h>
# include <EEPROM.h>
//#include <FastCRC.h>
/*FastCRC16 CRC16;
union _crc {
unsigned int integer ;
char bytes [ 2 ] ;
} crc ;
*/
# include <SoftwareSerial.h>
# define SerialRX 0 //RX connected to RO - Receiver Output
# define SerialTX 1 //TX connected to DI - Driver Output Pin
# define RS485Transmit HIGH
# define RS485Receive LOW
2019-05-02 12:52:19 +00:00
const char devID = 0x41 ;
2019-04-01 03:02:55 +00:00
const char hostID = 0x30 ;
SoftwareSerial RS485Serial ( SerialRX , SerialTX ) ; // RX, TX
# include <OneWire.h>
# include <DallasTemperature.h>
//library's DEVICE_DISCONNECTED_C -127.0
OneWire ow_ALLTSENSORS ( OW_BUS_ALLTSENSORS ) ;
DallasTemperature s_allTsensors ( & ow_ALLTSENSORS ) ;
typedef struct {
DeviceAddress addr ;
bool e ; //enabled
double T ;
} st_tsens ;
DeviceAddress dev_addr ; //temp
st_tsens Tae ;
st_tsens Tbe ;
st_tsens Ttarget ;
st_tsens Tsump ;
st_tsens Tci ;
st_tsens Tco ;
st_tsens Thi ;
st_tsens Tho ;
st_tsens Tbc ;
st_tsens Tac ;
st_tsens Touter ;
st_tsens Ts1 ;
st_tsens Ts2 ;
# define BIT_Tae 0
# define BIT_Tbe 1
# define BIT_Ttarget 2
# define BIT_Tsump 3
# define BIT_Tci 4
# define BIT_Tco 5
# define BIT_Thi 6
# define BIT_Tho 7
# define BIT_Tbc 8
# define BIT_Tac 9
# define BIT_Touter 10
# define BIT_Ts1 11
# define BIT_Ts2 12
unsigned int used_sensors = 0 ; //bit array
2019-05-02 12:52:19 +00:00
double T_setpoint = 26.5 ;
2019-04-01 03:02:55 +00:00
double T_setpoint_lastsaved = T_setpoint ;
2019-05-02 12:52:19 +00:00
double T_EEV_setpoint = EEV_TARGET_TEMP_DIFF ;
double T_EEV_dt = 0.0 ; //real, used during run
2019-04-01 03:02:55 +00:00
const double cT_setpoint_max = 45.0 ;
2019-05-02 12:52:19 +00:00
const double cT_hotcircle_delta_min = 2.0 ;
const double cT_sump_min = 9.0 ;
const double cT_sump_max = 110.0 ;
2019-04-01 03:02:55 +00:00
const double cT_sump_heat_threshold = 16.0 ;
//const double cT_sump_outerT_threshold = 18.0; //?? seems to be not useful
2019-05-02 12:52:19 +00:00
const double cT_before_condenser_max = 108.0 ;
2019-04-01 03:02:55 +00:00
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 ;
//const double cT_workingOK_cold_delta_min = 0.5; // 0.7 - 1st try, 2nd try 0.5
const double cT_workingOK_hot_delta_min = 0.5 ;
2019-04-16 15:53:34 +00:00
const double cT_workingOK_sump_min = 30.0 ; //need to be not very high to normal start after deep freeze
2019-04-01 03:02:55 +00:00
const double c_wattage_max = MAX_WATTS ; //FUNAI: 1000W seems to be normal working wattage INCLUDING 1(one) CR25/4 at 3rd speed
//PH165X1CY : 920 Watts, 4.2 A
const double c_workingOK_wattage_min = c_wattage_max / 2.5 ; //
2019-05-02 12:52:19 +00:00
bool heatpump_state = 0 ;
bool hotside_circle_state = 0 ;
bool coldside_circle_state = 0 ;
bool sump_heater_state = 0 ;
2019-04-01 03:02:55 +00:00
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
2019-05-02 12:52:19 +00:00
bool _1st_start_sleeped = 0 ;
2019-04-01 03:02:55 +00:00
//??? TODO: periodical start ?
//const long floor_circle_maxhalted = 6000000; //circle NOT works max 100 minutes
const long deffered_stop_hotcircle = DEFFERED_STOP_HOTCIRCLE ;
2019-04-16 15:53:34 +00:00
int EEV_cur_pos = 0 ;
int EEV_apulses = 0 ; //for async
bool EEV_adonotcare = 0 ;
const unsigned char EEV_steps [ 4 ] = { 0 b1010 , 0 b0110 , 0 b0101 , 0 b1001 } ;
char EEV_cur_step = 0 ;
bool EEV_fast = 0 ;
2019-04-01 03:02:55 +00:00
//main cycle vars
unsigned long millis_prev = 0 ;
unsigned long millis_now = 0 ;
2019-04-16 15:53:34 +00:00
unsigned long millis_cycle = 1000 ;
2019-04-01 03:02:55 +00:00
unsigned long millis_last_heatpump_on = 0 ;
unsigned long millis_last_heatpump_off = 0 ;
unsigned long millis_notification = 0 ;
unsigned long millis_notification_interval = 33000 ;
unsigned long millis_displ_update = 0 ;
unsigned long millis_displ_update_interval = 10000 ;
unsigned long millis_escinput = 0 ;
unsigned long millis_charinput = 0 ;
unsigned long millis_lasteesave = 0 ;
2019-04-16 15:53:34 +00:00
unsigned long millis_last_printstats = 0 ;
unsigned long millis_eev_last_close = 0 ;
unsigned long millis_eev_last_on = 0 ;
unsigned long millis_eev_last_step = 0 ;
2019-04-01 03:02:55 +00:00
int skipchars = 0 ;
# define ERR_HZ 2500
char inData [ 50 ] ; // Allocate some space for the string, do not change that size!
char inChar = - 1 ; // space to store the character read
byte index = 0 ; // Index into array; where to store the character
//-------------temporary variables
char temp [ 10 ] ;
int i = 0 ;
int z = 0 ;
int x = 0 ;
2019-04-16 15:53:34 +00:00
int y = 0 ;
2019-04-01 03:02:55 +00:00
double tempdouble = 0.0 ;
int tempint = 0 ;
String outString ;
//-------------EEPROM
int eeprom_magic_read = 0x00 ;
int eeprom_addr = 0x00 ;
//initial values, saved to EEPROM and can be modified later
//CHANGE eeprom_magic after correction!
const int eeprom_magic = MAGIC ;
//-------------ERROR states
# define ERR_OK 0
# define ERR_T_SENSOR 1
# define ERR_HOT_PUMP 2
# define ERR_COLD_PUMP 3
# define ERR_HEATPUMP 4
# define ERR_WATTAGE 5
int errorcode = 0 ;
//--------------------------- for wattage
# define ADC_BITS 10 //10 fo regular arduino
# define ADC_COUNTS (1<<ADC_BITS)
2019-04-16 15:53:34 +00:00
float em_calibration = 62.5 ;
int em_samplesnum = 2960 ; // Calculate Irms only 1480 == full 14 periods for 50Hz
//double Irms = 0; //for tests with original procedure
2019-04-01 03:02:55 +00:00
int supply_voltage = 0 ;
int em_i = 0 ;
//phase 1
int sampleI_1 = 0 ;
double filteredI_1 = 0 ;
2019-04-16 15:53:34 +00:00
double offsetI_1 = ADC_COUNTS > > 1 ; //Low-pass filter output
double sqI_1 , sumI_1 = 0 ; //sq = squared, sum = Sum, inst = instantaneous
2019-04-01 03:02:55 +00:00
double async_Irms_1 = 0 ;
double async_wattage = 0 ;
//--------------------------- for wattage END
//--------------------------- functions
long ReadVcc ( ) {
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
# if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV ( REFS0 ) | _BV ( MUX4 ) | _BV ( MUX3 ) | _BV ( MUX2 ) | _BV ( MUX1 ) ;
# elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV ( MUX5 ) | _BV ( MUX0 ) ;
# elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV ( MUX3 ) | _BV ( MUX2 ) ;
# else
ADMUX = _BV ( REFS0 ) | _BV ( MUX3 ) | _BV ( MUX2 ) | _BV ( MUX1 ) ;
# endif
delay ( 2 ) ; // Wait for Vref to settle
ADCSRA | = _BV ( ADSC ) ; // Start conversion
while ( bit_is_set ( ADCSRA , ADSC ) ) ; // measuring
uint8_t low = ADCL ; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH ; // unlocks both
long result = ( high < < 8 ) | low ;
//constant NOT same as in battery controller!
result = 1126400L / result ; // Calculate Vcc (in mV); (me: !!) 1125300 (!!) = 1.1*1023*1000
return result ; // Vcc in millivolts
}
char CheckAddrExists ( void ) {
2019-06-01 19:16:28 +00:00
/*
2019-04-01 03:02:55 +00:00
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tae . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tbe . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Ttarget . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tsump . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tci . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tco . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Thi . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tho . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tbc . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Tac . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Touter . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Ts1 . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
for ( i = 0 ; i < 8 ; i + + ) { if ( dev_addr [ i ] ! = Ts2 . addr [ i ] ) break ; }
if ( i = = 8 ) return 1 ;
return 0 ;
2019-06-01 19:16:28 +00:00
*/
//!!!!! optimised v1.4, untested !!!!!
for ( i = 0 ; i < 8 ; i + + ) {
if ( ( dev_addr [ i ] ! = Tae . addr [ i ] ) & &
( dev_addr [ i ] ! = Tbe . addr [ i ] ) & &
( dev_addr [ i ] ! = Ttarget . addr [ i ] ) & &
( dev_addr [ i ] ! = Tsump . addr [ i ] ) & &
( dev_addr [ i ] ! = Tci . addr [ i ] ) & &
( dev_addr [ i ] ! = Tco . addr [ i ] ) & &
( dev_addr [ i ] ! = Thi . addr [ i ] ) & &
( dev_addr [ i ] ! = Tho . addr [ i ] ) & &
( dev_addr [ i ] ! = Tbc . addr [ i ] ) & &
( dev_addr [ i ] ! = Tac . addr [ i ] ) & &
( dev_addr [ i ] ! = Touter . addr [ i ] ) & &
( dev_addr [ i ] ! = Ts1 . addr [ i ] ) & &
( dev_addr [ i ] ! = Ts2 . addr [ i ] )
)
break ;
}
if ( i = = 8 ) return 1 ;
return 0 ;
2019-04-01 03:02:55 +00:00
}
void InitS_and_D ( void ) {
# ifdef DISPLAY_096
Wire . begin ( ) ;
oled . begin ( & Adafruit128x64 , I2C_ADDRESS ) ;
oled . setFont ( Adafruit5x7 ) ;
# endif
# ifdef DISPLAY_1602
lcd . init ( ) ; // initialize the lcd
lcd . backlight ( ) ; // not really needed
# endif
RS485Serial . begin ( 9600 ) ;
}
2019-05-02 12:52:19 +00:00
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
}
2019-04-01 03:02:55 +00:00
void PrintS_and_D ( String str , int printSerial = 1 ) {
char * outChar = & str [ 0 ] ;
//#ifdef RS485_HUMAN
if ( ishuman ! = 0 ) {
if ( printSerial = = 1 ) {
digitalWrite ( SerialTxControl , RS485Transmit ) ;
delay ( 1 ) ;
RS485Serial . print ( outChar ) ;
RS485Serial . println ( ) ;
RS485Serial . flush ( ) ;
digitalWrite ( SerialTxControl , RS485Receive ) ;
}
}
//#endif
if ( str = = " " ) {
return ;
}
# ifdef DISPLAY_096
oled . clear ( ) ;
oled . println ( str ) ;
# endif
# ifdef DISPLAY_1602
lcd . backlight ( ) ;
lcd . clear ( ) ;
lcd . print ( str ) ;
# endif
}
2019-05-02 12:52:19 +00:00
void Print_D2 ( ) {
# ifdef DISPLAY_1602
lcd . setCursor ( 0 , 1 ) ;
lcd . print ( outString ) ;
# endif
}
2019-04-01 03:02:55 +00:00
void _PrintHelp ( void ) {
2019-05-02 12:52:19 +00:00
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 " ) ) ;
2019-04-16 15:53:34 +00:00
# ifdef EEV_SUPPORT
2019-05-02 12:52:19 +00:00
PrintS ( F ( " (<) decrease EEV T diff \n (>) increase EEV T diff " ) ) ;
2019-04-16 15:53:34 +00:00
# endif
2019-05-02 12:52:19 +00:00
PrintS ( F ( " (G) get stats " ) ) ;
2019-04-01 03:02:55 +00:00
}
void PrintS_and_D_double ( double double_to_print ) {
dtostrf ( double_to_print , 1 , 2 , temp ) ;
PrintS_and_D ( temp ) ;
}
int Inc_T ( void ) {
if ( T_setpoint + 0.5 > cT_setpoint_max ) {
2019-05-02 12:52:19 +00:00
PrintS_and_D ( F ( " Max! " ) ) ;
2019-04-01 03:02:55 +00:00
delay ( 200 ) ;
return 0 ;
}
T_setpoint + = 0.5 ;
PrintS_and_D_double ( T_setpoint ) ;
return 1 ;
}
int Dec_T ( void ) {
if ( T_setpoint - 0.5 < 1.0 ) {
2019-05-02 12:52:19 +00:00
PrintS_and_D ( F ( " Min! " ) ) ;
2019-04-01 03:02:55 +00:00
delay ( 200 ) ;
return 0 ;
}
T_setpoint - = 0.5 ;
PrintS_and_D_double ( T_setpoint ) ;
return 1 ;
}
2019-04-16 15:53:34 +00:00
int Inc_E ( void ) { ///!!!!!! unprotected
T_EEV_setpoint + = 0.25 ;
PrintS_and_D_double ( T_EEV_setpoint ) ;
return 1 ;
}
int Dec_E ( void ) { ///!!!!!! unprotected
T_EEV_setpoint - = 0.25 ;
PrintS_and_D_double ( T_EEV_setpoint ) ;
return 1 ;
}
2019-04-01 03:02:55 +00:00
void print_Serial_SaD ( double num ) { //global string + double
RS485Serial . print ( outString ) ;
RS485Serial . println ( num ) ;
}
void PrintStats_Serial ( void ) {
# ifdef RS485_HUMAN
digitalWrite ( SerialTxControl , RS485Transmit ) ;
delay ( 1 ) ;
if ( Tae . e = = 1 ) { outString = " Tae: " ; print_Serial_SaD ( Tae . T ) ; }
if ( Tbe . e = = 1 ) { outString = " Tbe: " ; print_Serial_SaD ( Tbe . T ) ; }
if ( Ttarget . e = = 1 ) { outString = " Ttarget: " ; print_Serial_SaD ( Ttarget . T ) ; }
if ( Tsump . e = = 1 ) { outString = " Tsump: " ; print_Serial_SaD ( Tsump . T ) ; }
if ( Tci . e = = 1 ) { outString = " Tci: " ; print_Serial_SaD ( Tci . T ) ; }
if ( Tco . e = = 1 ) { outString = " Tco: " ; print_Serial_SaD ( Tco . T ) ; }
if ( Thi . e = = 1 ) { outString = " Thi: " ; print_Serial_SaD ( Thi . T ) ; }
if ( Tho . e = = 1 ) { outString = " Tho: " ; print_Serial_SaD ( Tho . T ) ; }
if ( Tbc . e = = 1 ) { outString = " Tbc: " ; print_Serial_SaD ( Tbc . T ) ; }
if ( Tac . e = = 1 ) { outString = " Tac: " ; print_Serial_SaD ( Tac . T ) ; }
if ( Touter . e = = 1 ) { outString = " Touter: " ; print_Serial_SaD ( Touter . T ) ; }
if ( Ts1 . e = = 1 ) { outString = " Ts1: " ; print_Serial_SaD ( Ts1 . T ) ; }
if ( Ts2 . e = = 1 ) { outString = " Ts2: " ; print_Serial_SaD ( Ts2 . T ) ; }
outString = " Err: " + String ( errorcode ) + " \n \r Watts: " + String ( async_wattage ) + " \n \r Aim: " ; print_Serial_SaD ( T_setpoint ) ;
2019-04-16 15:53:34 +00:00
# ifdef EEV_SUPPORT
outString = " EEV_pos: " + String ( EEV_cur_pos ) ;
RS485Serial . print ( outString ) ;
# endif
2019-04-01 03:02:55 +00:00
RS485Serial . println ( ) ;
RS485Serial . flush ( ) ;
digitalWrite ( SerialTxControl , RS485Receive ) ;
# endif
}
void ReadEECheckAddr ( unsigned char * to_addr ) {
for ( i = 0 ; i < 8 ; i + + ) {
to_addr [ i ] = EEPROM . read ( eeprom_addr ) ;
eeprom_addr + + ;
}
i = 0 ;
CheckIsInvalidCRCAddr ( to_addr ) ;
if ( i ! = 0 ) {
while ( 1 ) {
2019-05-02 12:52:19 +00:00
//PrintAddr(to_addr);
2019-04-01 03:02:55 +00:00
PrintS_and_D ( F ( " Err:EEPROM, reinit! " ) ) ;
2019-05-02 12:52:19 +00:00
delay ( 5000 ) ;
2019-04-01 03:02:55 +00:00
}
}
}
void CheckIsInvalidCRCAddr ( unsigned char * addr ) {
if ( OneWire : : crc8 ( addr , 7 ) ! = addr [ 7 ] ) {
i + = 1 ;
}
}
void CopyAddrStoreEE ( unsigned char * addr_to , int bit_offset ) { //get result from dev_addr, autoincrement eeprom_addr
//dev_addr and z from globals used
for ( i = 0 ; i < 8 ; i + + ) { //no matter
if ( z = = 0 ) {
dev_addr [ i ] = 0x00 ;
}
addr_to [ i ] = dev_addr [ i ] ;
EEPROM . write ( eeprom_addr , dev_addr [ i ] ) ;
eeprom_addr + + ;
}
bitWrite ( used_sensors , bit_offset , z ) ;
}
void WriteFloatEEPROM ( int addr , float val ) {
byte * x = ( byte * ) & val ;
for ( byte u = 0 ; u < 4 ; u + + ) EEPROM . write ( u + addr , x [ u ] ) ;
}
float ReadFloatEEPROM ( int addr ) {
byte x [ 4 ] ;
for ( byte u = 0 ; u < 4 ; u + + ) x [ u ] = EEPROM . read ( u + addr ) ;
float * y = ( float * ) & x ;
return y [ 0 ] ;
}
void SaveSetpointEE ( void ) {
if ( ( T_setpoint_lastsaved ! = T_setpoint ) & &
( ( ( unsigned long ) ( millis_now - millis_lasteesave ) > 15 * 60 * 1000 ) | | ( millis_lasteesave = = 0 ) ) ) {
eeprom_addr = 1 ;
WriteFloatEEPROM ( eeprom_addr , T_setpoint ) ;
millis_lasteesave = millis_now ;
T_setpoint_lastsaved = T_setpoint ;
}
}
void PrintAddr ( unsigned char * str ) {
outString = " " ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( str [ i ] < 0x10 ) outString + = " 0 " ;
outString + = String ( str [ i ] , HEX ) ;
}
PrintS_and_D ( outString ) ;
}
unsigned char FindAddr ( String what , int required = 0 ) {
i = 1 ;
while ( RS485Serial . available ( ) > 0 ) {
inChar = RS485Serial . read ( ) ;
delay ( 1 ) ;
}
inChar = 0x00 ;
while ( 1 ) {
while ( ! s_allTsensors . getAddress ( dev_addr , 0 ) ) {
if ( required = = 0 ) {
PrintS_and_D ( F ( " Press > to skip " ) ) ;
delay ( 500 ) ;
while ( RS485Serial . available ( ) > 0 ) {
inChar = RS485Serial . read ( ) ;
if ( inChar = = 0x3E ) {
PrintS_and_D ( " Skipped: " + what ) ;
return 0 ;
}
}
# ifdef INPUTS_AS_BUTTONS
i = digitalRead ( BUT_RIGHT ) ;
if ( i = = 1 ) {
PrintS_and_D ( " Skipped: " + what ) ;
delay ( 4000 ) ;
return 0 ;
}
# endif
}
PrintS_and_D ( " Insert " + what ) ;
delay ( 1000 ) ;
}
if ( OneWire : : crc8 ( dev_addr , 7 ) ! = dev_addr [ 7 ] ) {
2019-05-02 12:52:19 +00:00
PrintS_and_D ( F ( " Invalid CRC! Remove and insert same sensor! \n " ) ) ;
2019-04-01 03:02:55 +00:00
delay ( 200 ) ;
continue ;
} else if ( CheckAddrExists ( ) = = 1 ) {
PrintS_and_D ( F ( " USED! Remove! " ) ) ;
delay ( 1000 ) ;
continue ;
} else {
break ;
}
}
while ( 1 ) {
2019-05-02 12:52:19 +00:00
//PrintAddr(dev_addr);
2019-04-01 03:02:55 +00:00
delay ( 1000 ) ;
if ( s_allTsensors . getAddress ( dev_addr , 0 ) ) {
2019-05-02 12:52:19 +00:00
PrintS_and_D ( " OK! Remove " + what ) ;
2019-04-01 03:02:55 +00:00
delay ( 1000 ) ;
} else {
delay ( 100 ) ;
break ;
}
}
return i ;
}
double GetT ( unsigned char * str ) {
tempdouble = - 127.0 ;
for ( i = 0 ; i < 8 ; i + + ) {
# ifdef WATCHDOG
wdt_reset ( ) ;
# endif
if ( ( tempdouble = = 85.0 ) | | ( tempdouble = = - 127.0 ) ) {
if ( tempdouble = = 85.0 ) { //initial value in dallas register after poweron
delay ( 375 ) ; //375 actual for 11 bits resolution, 2-3 retries OK for 12-bits resolution
} else {
delay ( 37 ) ;
}
tempdouble = s_allTsensors . getTempC ( str ) ;
} else {
break ;
}
}
return tempdouble ;
}
void Get_Temperatures ( void ) {
if ( Tae . e ) Tae . T = GetT ( Tae . addr ) ;
if ( Tbe . e ) Tbe . T = GetT ( Tbe . addr ) ;
2019-04-16 15:53:34 +00:00
if ( Ttarget . e ) Ttarget . T = GetT ( Ttarget . addr ) ;
2019-04-01 03:02:55 +00:00
if ( Tsump . e ) Tsump . T = GetT ( Tsump . addr ) ;
if ( Tci . e ) Tci . T = GetT ( Tci . addr ) ;
if ( Tco . e ) Tco . T = GetT ( Tco . addr ) ;
if ( Thi . e ) Thi . T = GetT ( Thi . addr ) ;
if ( Tho . e ) Tho . T = GetT ( Tho . addr ) ;
if ( Tbc . e ) Tbc . T = GetT ( Tbc . addr ) ;
if ( Tac . e ) Tac . T = GetT ( Tac . addr ) ;
if ( Touter . e ) Touter . T = GetT ( Touter . addr ) ;
if ( Ts1 . e ) Ts1 . T = GetT ( Ts1 . addr ) ;
if ( Ts2 . e ) Ts2 . T = GetT ( Ts2 . addr ) ;
s_allTsensors . requestTemperatures ( ) ; //global request
//---------DEBUG and self-test !!!--------
/*PrintS_and_D("");
PrintS_and_D_double ( Tae . T ) ;
PrintS_and_D_double ( Tbe . T ) ;
PrintS_and_D_double ( Ttarget . T ) ;
PrintS_and_D_double ( Tsump . T ) ;
PrintS_and_D ( " " ) ; */
/*
PrintS_and_D ( " Sensor 1 " ) ;
PrintS_and_D_double ( tr_sens_1 ) ;
PrintS_and_D ( " , \t ci " ) ;
PrintS_and_D_double ( tr_cold_in ) ;
PrintS_and_D ( " , \t cout " ) ;
PrintS_and_D_double ( tr_cold_out ) ;
PrintS_and_D ( " , \t hin " ) ;
PrintS_and_D_double ( tr_hot_in ) ;
PrintS_and_D ( " , \t ho " ) ;
PrintS_and_D_double ( tr_hot_out ) ;
PrintS_and_D ( " , \t bcond " ) ;
PrintS_and_D_double ( tr_before_condenser ) ;
PrintS_and_D ( " , \t outer " ) ;
PrintS_and_D_double ( tr_outer ) ;
PrintS_and_D ( " , \t Sensor 2 " ) ;
PrintS_and_D_double ( tr_sens_2 ) ;
*/
//---------DEBUG END--------
}
2019-04-16 15:53:34 +00:00
# ifdef EEV_SUPPORT
void on_EEV ( ) { //1 = do not take care of position
x = EEV_steps [ EEV_cur_step ] ;
digitalWrite ( EEV_1 , bitRead ( x , 0 ) ) ;
digitalWrite ( EEV_2 , bitRead ( x , 1 ) ) ;
digitalWrite ( EEV_3 , bitRead ( x , 2 ) ) ;
digitalWrite ( EEV_4 , bitRead ( x , 3 ) ) ;
}
2019-04-01 03:02:55 +00:00
2019-04-16 15:53:34 +00:00
void off_EEV ( ) { //1 = do not take care of position
digitalWrite ( EEV_1 , 0 ) ;
digitalWrite ( EEV_2 , 0 ) ;
digitalWrite ( EEV_3 , 0 ) ;
digitalWrite ( EEV_4 , 0 ) ;
2019-05-02 12:52:19 +00:00
//PrintS_and_D("off_EEV");
2019-04-16 15:53:34 +00:00
}
# endif
2019-04-16 20:31:36 +00:00
void halifise ( void ) {
# ifdef BOARD_TYPE_F
/*#define LATCH_595 = 10;
# define CLK_595 = 11;
# DEFINE DATA_595 = 9;
//595.0: relay 3 RELAY_HOTSIDE_CIRCLE, 595.1: relay 4 RELAY_SUMP_HEATER, 595.2: relay 5 RELAY_4WAY_VALVE, 595.3: uln 6, 595.4: uln 7, 595.5: uln 8, 595.6: uln 9, 595.7: uln 10
*/
digitalWrite ( LATCH_595 , 0 ) ;
//7
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//6
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//5
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//4
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//3
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//2
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , 0 ) ; //4way valve here
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//1
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , sump_heater_state ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
//0
digitalWrite ( CLK_595 , 0 ) ;
digitalWrite ( DATA_595 , hotside_circle_state ) ;
digitalWrite ( CLK_595 , 1 ) ;
__asm__ __volatile__ ( " nop \n \t " ) ;
digitalWrite ( CLK_595 , 0 ) ;
//
digitalWrite ( LATCH_595 , 1 ) ;
# endif
# ifdef BOARD_TYPE_G
digitalWrite ( RELAY_SUMP_HEATER , sump_heater_state ) ;
digitalWrite ( RELAY_HOTSIDE_CIRCLE , hotside_circle_state ) ;
# endif
}
2019-04-16 15:53:34 +00:00
//--------------------------- functions END
2019-04-01 03:02:55 +00:00
void setup ( void ) {
2019-04-16 20:31:36 +00:00
pinMode ( RELAY_HEATPUMP , OUTPUT ) ;
pinMode ( RELAY_COLDSIDE_CIRCLE , OUTPUT ) ;
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_HEATPUMP , LOW ) ;
digitalWrite ( RELAY_COLDSIDE_CIRCLE , LOW ) ;
2019-04-16 20:31:36 +00:00
# ifdef BOARD_TYPE_G
pinMode ( RELAY_SUMP_HEATER , OUTPUT ) ;
pinMode ( RELAY_HOTSIDE_CIRCLE , OUTPUT ) ;
digitalWrite ( RELAY_SUMP_HEATER , LOW ) ;
digitalWrite ( RELAY_HOTSIDE_CIRCLE , LOW ) ;
# endif
# ifdef BOARD_TYPE_F
pinMode ( LATCH_595 , OUTPUT ) ;
pinMode ( CLK_595 , OUTPUT ) ;
pinMode ( DATA_595 , OUTPUT ) ;
digitalWrite ( LATCH_595 , LOW ) ;
digitalWrite ( CLK_595 , LOW ) ;
digitalWrite ( DATA_595 , LOW ) ;
# endif
2019-04-01 03:02:55 +00:00
# ifdef WATCHDOG
wdt_disable ( ) ;
delay ( 2000 ) ;
# endif
InitS_and_D ( ) ;
pinMode ( SerialTxControl , OUTPUT ) ;
digitalWrite ( SerialTxControl , RS485Receive ) ;
//digitalWrite(SerialTxControl, RS485Transmit);
//RS485Serial.println("starting..."); //!!!debug
delay ( 100 ) ;
PrintS_and_D ( " ID: 0x " + String ( devID , HEX ) ) ;
//Print_Lomem(C_ID);
2019-04-16 15:53:34 +00:00
delay ( 200 ) ;
# ifdef EEV_SUPPORT
pinMode ( EEV_1 , OUTPUT ) ;
pinMode ( EEV_2 , OUTPUT ) ;
pinMode ( EEV_3 , OUTPUT ) ;
pinMode ( EEV_4 , OUTPUT ) ;
off_EEV ( ) ;
# endif
pinMode ( em_pin1 , INPUT ) ;
2019-04-01 03:02:55 +00:00
//PrintS_and_D("setpoint (C):");
//PrintS_and_D(setpoint);
//PrintS_and_D(String(freeMemory())); //!!! debug
s_allTsensors . begin ( ) ;
s_allTsensors . setWaitForConversion ( false ) ; //ASYNC mode, request before get, see Dallas library for details
eeprom_magic_read = EEPROM . read ( eeprom_addr ) ;
# ifdef INPUTS_AS_BUTTONS
pinMode ( BUT_RIGHT , INPUT ) ;
//digitalWrite (BUT_RIGHT, LOW);
pinMode ( BUT_LEFT , INPUT ) ;
//digitalWrite (BUT_LEFT, LOW);
# endif
//EEPROM content:
//0x00 - magic,
//0x01 .. 0x04 Target value,
//0x05 and 0x06 if sensor enabled or not, used_sensors HI and LO
//0x07 .. 0x0e 1st addr, etc..
// tr_after_evaporator(0); tr_before_evaporator(1); tr_target(2); tr_sump(3);
// tr_cold_in(4); tr_cold_out(5); tr_hot_in(6); tr_hot_out(7);
// tr_before_condenser(8); tr_after_condenser(9); tr_outer(10); tr_sens_1(11);
// tr_sens_2(12);
eeprom_addr = 0x00 ;
if ( eeprom_magic_read = = eeprom_magic ) {
eeprom_addr + = 1 ;
T_setpoint = ReadFloatEEPROM ( eeprom_addr ) ;
eeprom_addr + = 4 ;
2019-05-02 12:52:19 +00:00
//PrintS_and_D("EEPROM->T " + String(T_setpoint));
2019-04-01 03:02:55 +00:00
z = EEPROM . read ( eeprom_addr ) ; //high
eeprom_addr + = 1 ;
i = EEPROM . read ( eeprom_addr ) ; //lo
eeprom_addr + = 1 ;
used_sensors = word ( z , i ) ;
Tae . e = bitRead ( used_sensors , BIT_Tae ) ;
Tbe . e = bitRead ( used_sensors , BIT_Tbe ) ;
Ttarget . e = bitRead ( used_sensors , BIT_Ttarget ) ;
Tsump . e = bitRead ( used_sensors , BIT_Tsump ) ;
Tci . e = bitRead ( used_sensors , BIT_Tci ) ;
Tco . e = bitRead ( used_sensors , BIT_Tco ) ;
Thi . e = bitRead ( used_sensors , BIT_Thi ) ;
Tho . e = bitRead ( used_sensors , BIT_Tho ) ;
Tbc . e = bitRead ( used_sensors , BIT_Tbc ) ;
Tac . e = bitRead ( used_sensors , BIT_Tac ) ;
Touter . e = bitRead ( used_sensors , BIT_Touter ) ;
Ts1 . e = bitRead ( used_sensors , BIT_Ts1 ) ;
Ts2 . e = bitRead ( used_sensors , BIT_Ts2 ) ;
# ifdef EEV_SUPPORT
if ( Tae . e ! = 1 | | Tbe . e ! = 1 ) {
while ( 1 ) {
PrintS_and_D ( " ERR: no Tae or Tbe for EEV! " ) ;
delay ( 1000 ) ;
}
}
# endif
ReadEECheckAddr ( Tae . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tae");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tbe . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tbe");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Ttarget . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Ttarget");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tsump . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tsump");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tci . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tci");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tco . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tco");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Thi . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Thi");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tho . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tho");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tbc . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tbc");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Tac . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Tac");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Touter . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Touter");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Ts1 . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Ts1");
2019-04-01 03:02:55 +00:00
ReadEECheckAddr ( Ts2 . addr ) ; //eeprom_addr incremeneted here
2019-05-02 12:52:19 +00:00
//PrintS_and_D("k:Ts2");
2019-04-01 03:02:55 +00:00
2019-05-02 12:52:19 +00:00
/*
//?code duplicated, see ReadEECheckAddr
2019-04-01 03:02:55 +00:00
i = 0 ;
if ( Tae . e = = 1 ) CheckIsInvalidCRCAddr ( Tae . addr ) ;
if ( Tbe . e = = 1 ) CheckIsInvalidCRCAddr ( Tbe . addr ) ;
if ( Ttarget . e = = 1 ) CheckIsInvalidCRCAddr ( Ttarget . addr ) ;
if ( Tsump . e = = 1 ) CheckIsInvalidCRCAddr ( Tsump . addr ) ;
if ( Tci . e = = 1 ) CheckIsInvalidCRCAddr ( Tci . addr ) ;
if ( Tco . e = = 1 ) CheckIsInvalidCRCAddr ( Tco . addr ) ;
if ( Thi . e = = 1 ) CheckIsInvalidCRCAddr ( Thi . addr ) ;
if ( Tho . e = = 1 ) CheckIsInvalidCRCAddr ( Tho . addr ) ;
if ( Tbc . e = = 1 ) CheckIsInvalidCRCAddr ( Tbc . addr ) ;
if ( Tac . e = = 1 ) CheckIsInvalidCRCAddr ( Tac . addr ) ;
if ( Touter . e = = 1 ) CheckIsInvalidCRCAddr ( Touter . addr ) ;
if ( Ts1 . e = = 1 ) CheckIsInvalidCRCAddr ( Ts1 . addr ) ;
if ( Ts2 . e = = 1 ) CheckIsInvalidCRCAddr ( Ts2 . addr ) ;
if ( i ! = 0 ) {
while ( 1 ) { PrintS_and_D ( F ( " EEPROM err1! " ) ) ; delay ( 1000 ) ; }
}
2019-05-02 12:52:19 +00:00
*/
2019-04-01 03:02:55 +00:00
} else {
eeprom_addr + = 1 ;
ishuman + = 1 ;
WriteFloatEEPROM ( eeprom_addr , T_setpoint ) ;
2019-05-02 12:52:19 +00:00
//PrintS_and_D(F("init EEPROM"));
2019-04-01 03:02:55 +00:00
eeprom_addr + = 4 ;
eeprom_addr + = 2 ; //used sensors, skip
//Ttarget -needed, other - optional
# ifdef EEV_SUPPORT
z = FindAddr ( " Tae " , 1 ) ; //holds result in dev_addr, returns "is used"
# else
z = FindAddr ( " Tae " ) ; //holds result in dev_addr, returns "is used"
# endif
Tae . e = z ;
CopyAddrStoreEE ( Tae . addr , BIT_Tae ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
# ifdef EEV_SUPPORT
z = FindAddr ( " Tbe " , 1 ) ;
# else
z = FindAddr ( " Tbe " ) ;
# endif
Tbe . e = z ;
CopyAddrStoreEE ( Tbe . addr , BIT_Tbe ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
2019-04-16 15:53:34 +00:00
# ifdef EEV_ONLY
//z = FindAddr("Ttarget");
z = 0 ;
# else
z = FindAddr ( " Ttarget " , 1 ) ;
# endif
2019-04-01 03:02:55 +00:00
Ttarget . e = z ;
CopyAddrStoreEE ( Ttarget . addr , BIT_Ttarget ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tsump " ) ;
Tsump . e = z ;
CopyAddrStoreEE ( Tsump . addr , BIT_Tsump ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tci " ) ;
Tci . e = z ;
CopyAddrStoreEE ( Tci . addr , BIT_Tci ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tco " ) ;
Tco . e = z ;
CopyAddrStoreEE ( Tco . addr , BIT_Tco ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Thi " ) ;
Thi . e = z ;
CopyAddrStoreEE ( Thi . addr , BIT_Thi ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tho " ) ;
Tho . e = z ;
CopyAddrStoreEE ( Tho . addr , BIT_Tho ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tbc " ) ;
Tbc . e = z ;
CopyAddrStoreEE ( Tbc . addr , BIT_Tbc ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Tac " ) ;
Tac . e = z ;
CopyAddrStoreEE ( Tac . addr , BIT_Tac ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Touter " ) ;
Touter . e = z ;
CopyAddrStoreEE ( Touter . addr , BIT_Touter ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Ts1 " ) ;
Ts1 . e = z ;
CopyAddrStoreEE ( Ts1 . addr , BIT_Ts1 ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
z = FindAddr ( " Ts2 " ) ;
Ts2 . e = z ;
CopyAddrStoreEE ( Ts2 . addr , BIT_Ts2 ) ; //dev_addr and z used by proc, autoincrement eeprom_addr, store bit
//
//final, off-the-sequence
EEPROM . write ( 0 + 1 + 4 + 0 , highByte ( used_sensors ) ) ;
EEPROM . write ( 0 + 1 + 4 + 1 , lowByte ( used_sensors ) ) ;
EEPROM . write ( 0x00 , eeprom_magic ) ;
ishuman - = 1 ;
}
T_setpoint_lastsaved = T_setpoint ;
//s_allTsensors.setResolution(ad_Tae, 12);
/*PrintAddr(Tae.addr);
PrintAddr ( Tbe . addr ) ;
PrintAddr ( Ttarget . addr ) ;
PrintAddr ( Tsump . addr ) ;
PrintAddr ( Tci . addr ) ;
PrintAddr ( Tco . addr ) ;
PrintAddr ( Thi . addr ) ;
PrintAddr ( Tho . addr ) ;
PrintAddr ( Tbc . addr ) ;
PrintAddr ( Tac . addr ) ;
PrintAddr ( Touter . addr ) ;
PrintAddr ( Ts1 . addr ) ;
PrintAddr ( Ts2 . addr ) ; */
2019-04-16 20:31:36 +00:00
# ifdef WATCHDOG
wdt_enable ( WDTO_8S ) ;
# endif
2019-04-01 03:02:55 +00:00
Get_Temperatures ( ) ;
tone ( speakerOut , 2250 ) ;
delay ( 1500 ) ; // like ups power on
noTone ( speakerOut ) ;
2019-04-16 15:53:34 +00:00
2019-04-01 03:02:55 +00:00
outString . reserve ( 200 ) ;
//PrintS_and_D(String(freeMemory())); //!!! debug
}
void loop ( void ) {
digitalWrite ( SerialTxControl , RS485Receive ) ;
millis_now = millis ( ) ;
//----------------------------- self-test !!!
2019-04-16 15:53:34 +00:00
/*
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_HEATPUMP , HIGH ) ;
2019-05-02 12:52:19 +00:00
delay ( 300 ) ;
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_HOTSIDE_CIRCLE , HIGH ) ;
2019-05-02 12:52:19 +00:00
delay ( 300 ) ;
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_COLDSIDE_CIRCLE , HIGH ) ;
2019-05-02 12:52:19 +00:00
delay ( 300 ) ;
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_SUMP_HEATER , HIGH ) ;
2019-04-16 15:53:34 +00:00
delay ( 2000 ) ;
2019-04-01 03:02:55 +00:00
digitalWrite ( RELAY_HEATPUMP , LOW ) ;
delay ( 300 ) ;
digitalWrite ( RELAY_HOTSIDE_CIRCLE , LOW ) ;
delay ( 300 ) ;
digitalWrite ( RELAY_COLDSIDE_CIRCLE , LOW ) ;
delay ( 300 ) ;
digitalWrite ( RELAY_SUMP_HEATER , LOW ) ;
*/
// step one revolution in one direction:
2019-04-16 15:53:34 +00:00
//!!! write self-test for EEV
2019-04-01 03:02:55 +00:00
//----------------------------- self-test END
2019-04-16 15:53:34 +00:00
# ifdef RS485_HUMAN
if ( ( ( unsigned long ) ( millis_now - millis_last_printstats ) > HUMAN_AUTOINFO ) | | ( millis_last_printstats = = 0 ) ) {
PrintStats_Serial ( ) ;
millis_last_printstats = millis_now ;
}
# endif
//--------------------async fuctions start
2019-04-01 03:02:55 +00:00
if ( em_i = = 0 ) {
supply_voltage = ReadVcc ( ) ;
}
if ( em_i < em_samplesnum ) {
sampleI_1 = analogRead ( em_pin1 ) ;
// Digital low pass filter extracts the 2.5 V or 1.65 V dc offset, then subtract this - signal is now centered on 0 counts.
offsetI_1 = ( offsetI_1 + ( sampleI_1 - offsetI_1 ) / 1024 ) ;
filteredI_1 = sampleI_1 - offsetI_1 ;
// Root-mean-square method current
// 1) square current values
sqI_1 = filteredI_1 * filteredI_1 ;
// 2) sum
sumI_1 + = sqI_1 ;
em_i + = 1 ;
} else {
em_i = 0 ;
double I_RATIO = em_calibration * ( ( supply_voltage / 1000.0 ) / ( ADC_COUNTS ) ) ;
async_Irms_1 = I_RATIO * sqrt ( sumI_1 / em_samplesnum ) ;
async_wattage = async_Irms_1 * 220.0 ;
//Reset accumulators
sumI_1 = 0 ;
//----------------------------- self-test !!!
/*
PrintS_and_D ( " Async impl. results 1: " ) ;
2019-04-16 15:53:34 +00:00
PrintS_and_D ( String ( async_wattage ) ) ; // Apparent power
2019-04-01 03:02:55 +00:00
PrintS_and_D ( " " ) ;
2019-04-16 15:53:34 +00:00
PrintS_and_D ( String ( async_Irms_1 ) ) ; // Irms
2019-04-01 03:02:55 +00:00
PrintS_and_D ( " voltage: " ) ;
2019-04-16 15:53:34 +00:00
PrintS_and_D ( String ( supply_voltage ) ) ;
2019-04-01 03:02:55 +00:00
*/
//----------------------------- self-test END
}
2019-04-16 15:53:34 +00:00
# ifdef EEV_SUPPORT
if ( ( ( ( EEV_apulses < 0 ) & & ( EEV_fast = = 1 ) ) & & ( ( unsigned long ) ( millis_now - millis_eev_last_step ) > ( EEV_PULSE_FCLOSE_MILLIS ) ) ) | |
( ( ( EEV_apulses < 0 ) & & ( EEV_fast = = 0 ) ) & & ( ( unsigned long ) ( millis_now - millis_eev_last_step ) > ( EEV_PULSE_CLOSE_MILLIS ) ) ) | |
( ( ( EEV_apulses > 0 ) & & ( EEV_cur_pos < EEV_MINWORKPOS ) ) & & ( ( unsigned long ) ( millis_now - millis_eev_last_step ) > ( EEV_PULSE_WOPEN_MILLIS ) ) ) | |
( ( ( EEV_apulses > 0 ) & & ( EEV_fast = = 1 ) & & ( EEV_cur_pos > = EEV_MINWORKPOS ) ) & & ( ( unsigned long ) ( millis_now - millis_eev_last_step ) > ( EEV_PULSE_FOPEN_MILLIS ) ) ) | |
( ( ( EEV_apulses > 0 ) & & ( EEV_fast = = 0 ) & & ( EEV_cur_pos > = EEV_MINWORKPOS ) ) & & ( ( unsigned long ) ( millis_now - millis_eev_last_step ) > ( EEV_PULSE_OPEN_MILLIS ) ) ) | |
( millis_eev_last_step = = 0 )
) {
if ( EEV_apulses ! = 0 ) {
if ( EEV_apulses > 0 ) {
if ( EEV_cur_pos + 1 < = EEV_MAXPULSES ) {
EEV_cur_pos + = 1 ;
EEV_cur_step + = 1 ;
EEV_apulses - = 1 ;
} else {
EEV_apulses = 0 ;
//PrintS_and_D("EEmax!");
}
}
if ( EEV_apulses < 0 ) {
if ( ( EEV_cur_pos - 1 > = EEV_MINWORKPOS ) | | ( EEV_adonotcare = = 1 ) ) {
EEV_cur_pos - = 1 ;
EEV_cur_step - = 1 ;
EEV_apulses + = 1 ;
} else {
EEV_apulses = 0 ;
//PrintS_and_D("EEmin!");
}
}
if ( EEV_cur_step > 3 ) EEV_cur_step = 0 ;
if ( EEV_cur_step < 0 ) EEV_cur_step = 3 ;
x = EEV_steps [ EEV_cur_step ] ;
digitalWrite ( EEV_1 , bitRead ( x , 0 ) ) ;
digitalWrite ( EEV_2 , bitRead ( x , 1 ) ) ;
digitalWrite ( EEV_3 , bitRead ( x , 2 ) ) ;
digitalWrite ( EEV_4 , bitRead ( x , 3 ) ) ;
}
if ( EEV_cur_pos < 0 ) {
EEV_cur_pos = 0 ;
}
millis_eev_last_step = millis_now ;
2019-05-02 12:52:19 +00:00
# ifdef EEV_DEBUG
PrintS ( String ( EEV_cur_pos ) ) ;
# endif
2019-04-16 15:53:34 +00:00
}
# endif
//--------------------async fuctions END
2019-04-01 03:02:55 +00:00
2019-05-02 12:52:19 +00:00
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 ) ;
}
2019-04-01 03:02:55 +00:00
}
//-------------------buttons processing
# ifdef INPUTS_AS_BUTTONS
2019-04-16 15:53:34 +00:00
z = digitalRead ( BUT_LEFT ) ;
i = digitalRead ( BUT_RIGHT ) ;
if ( ( z = = 1 ) & & ( i = = 1 ) ) {
//
} else if ( ( z = = 1 ) | | ( i = = 1 ) ) {
# ifndef EEV_ONLY
if ( z = = 1 ) {
x = Dec_T ( ) ;
}
if ( i = = 1 ) {
x = Inc_T ( ) ;
}
if ( x = = 1 ) {
PrintS_and_D ( " New aim: " + String ( T_setpoint ) ) ;
delay ( 300 ) ;
}
# else
if ( z = = 1 ) {
T_EEV_setpoint - = 0.25 ;
}
if ( i = = 1 ) {
T_EEV_setpoint + = 0.25 ;
}
2019-05-02 12:52:19 +00:00
PrintS_and_D ( " New EEV Td: " + String ( T_EEV_setpoint ) ) ;
2019-04-16 15:53:34 +00:00
delay ( 300 ) ;
# endif
2019-04-01 03:02:55 +00:00
}
2019-04-16 15:53:34 +00:00
2019-04-01 03:02:55 +00:00
# endif
//-------------------buttons processing END
//-------------------display
# if (DISPLAY == 2) || (DISPLAY == 1)
if ( ( ( unsigned long ) ( millis_now - millis_displ_update ) > millis_displ_update_interval ) | | ( millis_displ_update = = 0 ) ) {
2019-04-16 15:53:34 +00:00
//EEV_ONLY SUPPORT!!!!!!!
# ifndef EEV_ONLY
outString = " A: " + String ( T_setpoint , 1 ) + " Real: " ;
if ( Ttarget . e = = 1 ) {
outString + = String ( Ttarget . T , 1 ) ;
} else {
outString + = " ERR " ;
}
PrintS_and_D ( outString , 1 ) ; //do not print serial
2019-05-02 12:52:19 +00:00
//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 ( ) ;
}
2019-04-16 15:53:34 +00:00
# else
outString = " be: " ;
if ( Tbe . e = = 1 ) {
outString + = String ( Tbe . T , 1 ) ;
}
outString + = " ae: " ;
if ( Tae . e = = 1 ) {
outString + = String ( Tae . T , 1 ) ;
}
PrintS_and_D ( outString , 1 ) ; //do not print serial
# endif
2019-04-01 03:02:55 +00:00
millis_displ_update = millis_now ;
}
# endif
//-------------------display END
//-------------------check cycle
if ( ( ( unsigned long ) ( millis_now - millis_prev ) > millis_cycle ) | | ( millis_prev = = 0 ) ) {
millis_prev = millis_now ;
Get_Temperatures ( ) ; // wdt_reset here due to 85.0'C filtration
SaveSetpointEE ( ) ;
//--------------------important logic
//check T sensors
2019-06-01 19:16:28 +00:00
if ( ( errorcode = = ERR_OK ) & & ( ( Tae . e = = 1 & & Tae . T = = - 127 ) | |
( Tbe . e = = 1 & & Tbe . T = = - 127 ) | |
( Ttarget . e = = 1 & & Ttarget . T = = - 127 ) | |
( Tsump . e = = 1 & & Tsump . T = = - 127 ) | |
( Tci . e = = 1 & & Tci . T = = - 127 ) | |
( Tco . e = = 1 & & Tco . T = = - 127 ) | |
( Thi . e = = 1 & & Thi . T = = - 127 ) | |
( Tho . e = = 1 & & Tho . T = = - 127 ) | |
( Tbc . e = = 1 & & Tbc . T = = - 127 ) | |
( Tac . e = = 1 & & Tac . T = = - 127 ) | |
( Touter . e = = 1 & & Touter . T = = - 127 ) | |
( Ts1 . e = = 1 & & Ts1 . T = = - 127 ) | |
( Ts2 . e = = 1 & & Ts2 . T = = - 127 ) ) ) {
2019-04-01 03:02:55 +00:00
errorcode = ERR_T_SENSOR ;
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS_and_D ( " ERR:T.sens. " + String ( errorcode ) ) ;
# endif
2019-04-01 03:02:55 +00:00
}
//auto-clean sensor error on sensor appear
// add 1xor enable here!
if ( ( errorcode = = ERR_T_SENSOR ) & & ( ( ( Tae . e = = 1 & & Tae . T ! = - 127 ) | | ( Tae . e ^ 1 ) ) & &
( ( Tbe . e = = 1 & & Tbe . T ! = - 127 ) | | ( Tbe . e ^ 1 ) ) & &
2019-04-16 15:53:34 +00:00
( ( Ttarget . e = = 1 & & Ttarget . T ! = - 127 ) | | ( Ttarget . e ^ 1 ) ) & &
2019-04-01 03:02:55 +00:00
( ( Tsump . e = = 1 & & Tsump . T ! = - 127 ) | | ( Tsump . e ^ 1 ) ) & &
( ( Tci . e = = 1 & & Tci . T ! = - 127 ) | | ( Tci . e ^ 1 ) ) & &
( ( Tco . e = = 1 & & Tco . T ! = - 127 ) | | ( Tco . e ^ 1 ) ) & &
( ( Thi . e = = 1 & & Thi . T ! = - 127 ) | | ( Thi . e ^ 1 ) ) & &
( ( Tho . e = = 1 & & Tho . T ! = - 127 ) | | ( Tho . e ^ 1 ) ) & &
( ( Tbc . e = = 1 & & Tbc . T ! = - 127 ) | | ( Tbc . e ^ 1 ) ) & &
( ( Tac . e = = 1 & & Tac . T ! = - 127 ) | | ( Tac . e ^ 1 ) ) & &
( ( Touter . e = = 1 & & Touter . T ! = - 127 ) | | ( Touter . e ^ 1 ) ) & &
( ( Ts1 . e = = 1 & & Ts1 . T ! = - 127 ) | | ( Ts1 . e ^ 1 ) ) & &
2019-06-01 19:16:28 +00:00
( ( Ts2 . e = = 1 & & Ts2 . T ! = - 127 ) | | ( Ts2 . e ^ 1 ) ) ) ) {
2019-04-01 03:02:55 +00:00
errorcode = ERR_OK ;
}
//process errors
//beep N times error
if ( errorcode ! = ERR_OK ) {
if ( ( ( unsigned long ) ( millis_now - millis_notification ) > millis_notification_interval ) | | millis_notification = = 0 ) {
millis_notification = millis_now ;
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS_and_D ( " Error: " + String ( errorcode ) ) ;
# endif
2019-04-01 03:02:55 +00:00
for ( i = 0 ; i < errorcode ; i + + ) {
tone ( speakerOut , ERR_HZ ) ; delay ( 500 ) ;
noTone ( speakerOut ) ; delay ( 500 ) ;
}
}
}
2019-04-16 15:53:34 +00:00
//-------------- EEV cycle
# ifdef EEV_SUPPORT
2019-05-02 12:52:19 +00:00
/*
//v1 algo
2019-04-16 15:53:34 +00:00
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 " ) ; //!!!
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
PrintS_and_D ( " EEV: err or sleep " ) ; //!!!
if ( EEV_cur_pos < = 0 & & EEV_OPEN_AFTER_CLOSE ! = 0 ) { //set waiting pos
EEV_apulses = + EEV_OPEN_AFTER_CLOSE ;
EEV_adonotcare = 0 ;
EEV_fast = 1 ;
}
if ( EEV_cur_pos > 0 & & EEV_cur_pos ! = EEV_OPEN_AFTER_CLOSE & & EEV_cur_pos < = EEV_MAXPULSES ) { //waiting pos. set
PrintS_and_D ( " EEV: close " ) ; //!!!
EEV_apulses = - ( EEV_cur_pos + EEV_CLOSE_ADD_PULSES ) ;
EEV_adonotcare = 1 ;
EEV_fast = 1 ;
}
} else if ( errorcode = = 0 & & async_wattage > c_workingOK_wattage_min ) {
2019-05-02 12:52:19 +00:00
T_EEV_dt = Tae . T - Tbe . T ;
PrintS_and_D ( " EEV: driving " + String ( T_EEV_dt ) ) ; //!!!
2019-04-16 15:53:34 +00:00
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 ;
2019-05-02 12:52:19 +00:00
EEV_adonotcare = 0 ;
2019-04-16 15:53:34 +00:00
EEV_fast = 1 ;
}
} else if ( EEV_cur_pos > 0 ) {
2019-05-02 12:52:19 +00:00
if ( T_EEV_dt < ( T_EEV_setpoint - EEV_EMERG_DIFF ) ) { //emerg!
2019-04-16 17:38:55 +00:00
PrintS_and_D ( " EEV: emergency closing! " ) ; //!!!
2019-04-16 15:53:34 +00:00
EEV_apulses = - EEV_EMERG_STEPS ;
EEV_adonotcare = 0 ;
EEV_fast = 1 ;
2019-05-02 12:52:19 +00:00
} else if ( T_EEV_dt < T_EEV_setpoint ) { //too
2019-04-16 17:38:55 +00:00
PrintS_and_D ( " EEV: closing " ) ; //!!!
2019-04-16 15:53:34 +00:00
//EEV_apulses = -EEV_NONPRECISE_STEPS;
EEV_apulses = - 1 ;
EEV_adonotcare = 0 ;
EEV_fast = 0 ;
2019-05-02 12:52:19 +00:00
} else if ( T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START ) { //very
2019-04-16 17:38:55 +00:00
PrintS_and_D ( " EEV: fast opening " ) ; //!!!
2019-04-16 15:53:34 +00:00
//EEV_apulses = +EEV_NONPRECISE_STEPS;
EEV_apulses = + 1 ;
EEV_adonotcare = 0 ;
EEV_fast = 1 ;
2019-05-02 12:52:19 +00:00
} else if ( T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS ) { //too
2019-04-16 17:38:55 +00:00
PrintS_and_D ( " EEV: opening " ) ; //!!!
2019-04-16 15:53:34 +00:00
EEV_apulses = + 1 ;
EEV_adonotcare = 0 ;
EEV_fast = 0 ;
2019-05-02 12:52:19 +00:00
} else if ( T_EEV_dt > T_EEV_setpoint ) { //ok
2019-04-16 17:38:55 +00:00
PrintS_and_D ( " EEV: OK " ) ; //!!!
2019-04-16 15:53:34 +00:00
//
}
}
off_EEV ( ) ;
}
}
2019-05-02 12:52:19 +00:00
*/
//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
2019-06-01 19:16:28 +00:00
if ( EEV_MINWORKPOS ! = 0 ) { //full close protection
2019-05-02 12:52:19 +00:00
EEV_apulses = EEV_MINWORKPOS - EEV_cur_pos ;
EEV_adonotcare = 0 ;
EEV_fast = 1 ;
}
off_EEV ( ) ;
}
2019-04-16 15:53:34 +00:00
if ( ( ( unsigned long ) ( millis_now - millis_eev_last_on ) > 10000 ) | | millis_eev_last_on = = 0 ) {
2019-05-02 12:52:19 +00:00
//PrintS_and_D("EEV: ON/OFF");
2019-04-16 15:53:34 +00:00
on_EEV ( ) ;
2019-05-02 12:52:19 +00:00
//delay(30);
//off_EEV(); //off_EEV called everywhere takes care of it
2019-04-16 15:53:34 +00:00
millis_eev_last_on = millis_now ;
}
# endif
//-------------- EEV cycle END
# ifndef EEV_ONLY
//process heatpump sump heater
if ( Tsump . e = = 1 ) {
if ( Tsump . T < cT_sump_heat_threshold & & sump_heater_state = = 0 & & Tsump . T ! = - 127 ) {
sump_heater_state = 1 ;
} else if ( Tsump . T > = cT_sump_heat_threshold & & sump_heater_state = = 1 ) {
sump_heater_state = 0 ;
} else if ( Tsump . T = = - 127 ) {
sump_heater_state = 0 ;
}
2019-04-16 20:31:36 +00:00
halifise ( ) ;
2019-04-01 03:02:55 +00:00
}
2019-04-16 15:53:34 +00:00
//main logic
if ( _1st_start_sleeped = = 0 ) {
2019-05-02 12:52:19 +00:00
//PrintS_and_D("!!!!sleep disabled!!!!");
//_1st_start_sleeped = 1;
2019-04-16 15:53:34 +00:00
if ( ( millis_now < poweron_pause ) & & ( _1st_start_sleeped = = 0 ) ) {
PrintS_and_D ( " Wait: " + String ( ( ( poweron_pause - millis_now ) ) / 1000 ) + " s. " ) ;
return ;
2019-04-01 03:02:55 +00:00
} else {
2019-04-16 15:53:34 +00:00
_1st_start_sleeped = 1 ;
2019-04-01 03:02:55 +00:00
}
}
2019-04-16 15:53:34 +00:00
//process_heatpump:
//start if
// (last_on > N or not_started_yet)
// and (no errors)
// and (t hot out < t target + heat_delta_min)
// and (sump t > min'C)
// and (sump t < max'C)
// and (t watertank < target)
// and (t after evaporator > after evaporator min)
// and (t cold in > cold min)
// 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 ) ) & &
2019-05-02 12:52:19 +00:00
//( tr_hot_out < (tr_sens_1 + cT_hotcircle_delta_min) ) &&
2019-04-16 15:53:34 +00:00
errorcode = = 0 & &
( ( Tsump . e = = 1 & & Tsump . T > cT_sump_min ) | | ( Tsump . e ^ 1 ) ) & &
( ( Tsump . e = = 1 & & Tsump . T < cT_sump_max ) | | ( Tsump . e ^ 1 ) ) & &
//t1_sump > t2_cold_in && ???
Ttarget . T < T_setpoint & & //was room here, change to advanced algo with room temperature
( ( Tae . e = = 1 & & Tae . T > cT_after_evaporator_min ) | | ( Tae . e ^ 1 ) ) & &
( ( 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 ) ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Start " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
millis_last_heatpump_off = millis_now ;
heatpump_state = 1 ;
}
//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 ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Normal stop " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
millis_last_heatpump_on = millis_now ;
heatpump_state = 0 ;
}
2019-04-01 03:02:55 +00:00
2019-04-16 15:53:34 +00:00
//process_hot_side_pump:
//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 ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Hot WP ON " ) ) ;
# endif
2019-04-01 03:02:55 +00:00
hotside_circle_state = 1 ;
}
2019-04-16 15:53:34 +00:00
if ( ( heatpump_state = = 0 ) & & ( hotside_circle_state = = 1 ) ) {
if ( ( deffered_stop_hotcircle ! = 0 & & ( ( unsigned long ) ( millis_now - millis_last_heatpump_on ) > deffered_stop_hotcircle ) ) ) {
2019-05-02 12:52:19 +00:00
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
2019-04-16 15:53:34 +00:00
hotside_circle_state = 0 ;
} else {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Hot WP OFF 2 " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
hotside_circle_state = 0 ;
}
}
2019-04-01 03:02:55 +00:00
}
2019-04-16 15:53:34 +00:00
//heat if we can, just in case, ex. if lost power
if ( ( hotside_circle_state = = 0 ) & &
2019-05-02 12:52:19 +00:00
( 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
2019-04-16 15:53:34 +00:00
hotside_circle_state = 1 ;
}
//process_cold_side_pump:
//start if (heatpump_enabled)
//stop if (heatpump_disbled)
if ( ( heatpump_state = = 1 ) & & ( coldside_circle_state = = 0 ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Cold WP ON " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
coldside_circle_state = 1 ;
}
if ( ( heatpump_state = = 0 ) & & ( coldside_circle_state = = 1 ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Cold WP OFF " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
coldside_circle_state = 0 ;
}
//protective_cycle:
//stop if
// (error)
// (t hot out > hot out max)
// (sump t > max'C)
// or (t after evaporator < after evaporator min)
// or (t cold in < cold min)
// or (t cold out < cold min)
//
if ( heatpump_state = = 1 & &
( errorcode ! = 0 | |
( Tho . e = = 1 & & Tho . T > cT_hotout_max ) | |
( Tsump . e = = 1 & & Tsump . T > cT_sump_max ) | |
( Tae . e = = 1 & & Tae . T < cT_after_evaporator_min ) | |
( 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 ) ) ) {
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( F ( " Protective stop " ) ) ;
# endif
2019-04-16 15:53:34 +00:00
millis_last_heatpump_on = millis_now ;
heatpump_state = 0 ;
digitalWrite ( RELAY_HEATPUMP , heatpump_state ) ;
}
//alive_check_cycle_after_5_mins:
//error if
2019-05-02 12:52:19 +00:00
//v1.3: not error, just poweroff all
2019-04-16 15:53:34 +00:00
// 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
2019-05-02 12:52:19 +00:00
2019-04-16 15:53:34 +00:00
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 ) ) {
// errorcode = ERR_COLD_PUMP;
//}
//if ( ( errorcode == ERR_OK ) && ( Tho.e == 1 && Thi.e == 1 && (Tho.T - Thi.T < cT_workingOK_hot_delta_min )) ) {
// errorcode = ERR_HOT_PUMP;
//}
if ( ( errorcode = = ERR_OK ) & & ( Tsump . e = = 1 & & Tsump . T < cT_workingOK_sump_min ) ) {
2019-05-02 12:52:19 +00:00
//errorcode = ERR_HEATPUMP;
millis_last_heatpump_on = millis_now ;
heatpump_state = 0 ;
2019-04-16 15:53:34 +00:00
}
if ( ( errorcode = = ERR_OK ) & & ( async_wattage < c_workingOK_wattage_min ) ) {
2019-05-02 12:52:19 +00:00
//errorcode = ERR_WATTAGE;
millis_last_heatpump_on = millis_now ;
heatpump_state = 0 ;
2019-04-16 15:53:34 +00:00
}
2019-05-02 12:52:19 +00:00
digitalWrite ( RELAY_HEATPUMP , heatpump_state ) ;
}
2019-04-16 15:53:34 +00:00
//disable pump by error
if ( errorcode ! = ERR_OK ) {
millis_last_heatpump_on = millis_now ;
heatpump_state = 0 ;
digitalWrite ( RELAY_HEATPUMP , heatpump_state ) ;
2019-05-02 12:52:19 +00:00
# ifdef RS485_HUMAN
PrintS ( " Error stop: " + String ( errorcode , HEX ) ) ;
# endif
2019-04-16 15:53:34 +00:00
}
//!!! self-test
///heatpump_state = 1;
//write states to relays
digitalWrite ( RELAY_HEATPUMP , heatpump_state ) ;
digitalWrite ( RELAY_COLDSIDE_CIRCLE , coldside_circle_state ) ;
2019-04-16 20:31:36 +00:00
halifise ( ) ;
2019-04-16 15:53:34 +00:00
# endif
2019-04-01 03:02:55 +00:00
}
if ( RS485Serial . available ( ) > 0 ) {
//RS485Serial.println("some on serial.."); //!!!debug
# ifdef RS485_HUMAN
if ( RS485Serial . available ( ) ) {
inChar = RS485Serial . read ( ) ;
//RS485Serial.print(inChar); //!!!debug
if ( inChar = = 0x1B ) {
skipchars + = 3 ;
inChar = 0x00 ;
millis_escinput = millis ( ) ;
}
if ( skipchars ! = 0 ) {
millis_charinput = millis ( ) ;
//if (millis_escinput + 2 > millis_charinput)
if ( ( unsigned long ) ( millis_charinput - millis_escinput ) < 16 * 2 ) { //2 chars for 2400
if ( inChar ! = 0x7e ) {
skipchars - = 1 ;
}
if ( inChar = = 0x7e ) {
skipchars = 0 ;
}
if ( inChar > = 0x30 & & inChar < = 0x35 ) {
skipchars + = 1 ;
}
inChar = 0x00 ;
} else {
skipchars = 0 ;
}
}
//- RS485_HUMAN: remote commands +,-,G,0x20/?/Enter
switch ( inChar ) {
case 0x00 :
break ;
case 0x20 :
_PrintHelp ( ) ;
break ;
case 0x3F :
_PrintHelp ( ) ;
break ;
case 0x0D :
_PrintHelp ( ) ;
break ;
case 0x2B :
Inc_T ( ) ;
break ;
case 0x2D :
Dec_T ( ) ;
break ;
2019-04-16 15:53:34 +00:00
case 0x3C :
Dec_E ( ) ;
break ;
case 0x3E :
Inc_E ( ) ;
break ;
2019-04-01 03:02:55 +00:00
case 0x47 :
PrintStats_Serial ( ) ;
break ;
case 0x67 :
PrintStats_Serial ( ) ;
break ;
}
}
# endif
# ifdef RS485_PYTHON
index = 0 ;
while ( RS485Serial . available ( ) > 0 ) { // Don't read unless you know there is data
if ( index < 49 ) { // size of the array minus 1
inChar = RS485Serial . read ( ) ; // Read a character
inData [ index ] = inChar ; // Store it
index + + ; // Increment where to write next
inData [ index ] = ' \0 ' ; // clear next symbol, null terminate the string
delayMicroseconds ( 80 ) ; //80 microseconds - the best choice at 9600, "no answer"disappeared
//40(20??) microseconds seems to be good, 9600, 49 symbols
//
} else { //too long message! read it to nowhere
inChar = RS485Serial . read ( ) ;
delayMicroseconds ( 80 ) ;
//break; //do not break if symbols!!
}
}
//!!!debug, be carefull, can cause strange results
2019-04-16 15:53:34 +00:00
/*
if ( inData [ 0 ] ! = 0x00 ) {
2019-04-01 03:02:55 +00:00
RS485Serial . println ( " - " ) ;
RS485Serial . println ( inData ) ;
RS485Serial . println ( " - " ) ;
} */
//or this debug
/*
digitalWrite ( SerialTxControl , RS485Transmit ) ;
delay ( 10 ) ;
RS485Serial . println ( inData ) ;
RS485Serial . flush ( ) ;
RS485Serial . println ( index ) ;
*/
//ALL lines must be terminated with \n!
if ( ( inData [ 0 ] = = hostID ) & & ( inData [ 1 ] = = devID ) ) {
// COMMANDS:
// G (0x47): (G)et main data
// TNN.NN (0x54): set aim (T)emperature
digitalWrite ( SerialTxControl , RS485Transmit ) ;
delay ( 1 ) ;
//PrintS_and_D(freeMemory());
outString = " " ;
outString + = devID ;
outString + = hostID ;
outString + = " A " ; //where A is Answer, space after header
if ( ( inData [ 2 ] = = 0x47 ) ) {
//PrintS_and_D("G");
//WARNING: this procedure can cause "NO answer" effect if no or few T sensors connected
outString + = " { " ;
2019-04-16 15:53:34 +00:00
outString + = " \" E1 \" : " + String ( errorcode ) ;
2019-04-01 03:02:55 +00:00
if ( Ts1 . e = = 1 ) {
2019-04-16 15:53:34 +00:00
outString + = " , \" TS1 \" : " + String ( Ts1 . T ) ;
2019-04-01 03:02:55 +00:00
}
if ( Tsump . e = = 1 ) {
outString + = " , \" TS \" : " + String ( Tsump . T ) ;
}
if ( Tho . e = = 1 ) {
outString + = " , \" THO \" : " + String ( Tho . T ) ;
}
if ( Tae . e = = 1 ) {
outString + = " , \" TAE \" : " + String ( Tae . T ) ;
}
char * outChar = & outString [ 0 ] ;
2019-06-01 19:16:28 +00:00
RS485Serial . write ( outChar ) ; //dirty hack to transfer long string
2019-04-01 03:02:55 +00:00
RS485Serial . flush ( ) ;
delay ( 1 ) ; //lot of errors without delay
outString = " " ;
if ( Tbe . e = = 1 ) {
outString + = " , \" TBE \" : " + String ( Tbe . T ) ;
}
if ( Touter . e = = 1 ) {
outString + = " , \" TO \" : " + String ( Touter . T ) ;
}
if ( Tco . e = = 1 ) {
outString + = " , \" TCO \" : " + String ( Tco . T ) ;
}
outString + = " , \" W1 \" : " + String ( async_wattage ) ;
2019-04-16 15:53:34 +00:00
# ifndef EEV_ONLY
2019-05-02 12:52:19 +00:00
outString + = " , \" A1 \" : " + String ( T_setpoint ) ; //(A)im (target)
2019-04-16 15:53:34 +00:00
outString + = " , \" RP \" : " + String ( heatpump_state * RELAY_HEATPUMP ) ;
# endif
2019-04-01 03:02:55 +00:00
if ( Tci . e = = 1 ) {
outString + = " , \" TCI \" : " + String ( Tci . T ) ;
}
2019-06-01 19:16:28 +00:00
RS485Serial . write ( outChar ) ; //dirty hack to transfer long string
2019-04-01 03:02:55 +00:00
RS485Serial . flush ( ) ;
delay ( 1 ) ; //lot of errors without delay
outString = " " ;
if ( Thi . e = = 1 ) {
outString + = " , \" THI \" : " + String ( Thi . T ) ;
}
2019-04-16 15:53:34 +00:00
# ifndef EEV_ONLY
2019-05-02 12:52:19 +00:00
outString + = " , \" RSH \" : " + String ( sump_heater_state * 3 ) ;
outString + = " , \" RH \" : " + String ( hotside_circle_state * 2 ) ;
outString + = " , \" RC \" : " + String ( coldside_circle_state * 1 ) ;
2019-04-16 15:53:34 +00:00
# endif
2019-04-01 03:02:55 +00:00
if ( Tbc . e = = 1 ) {
outString + = " , \" TBC \" : " + String ( Tbc . T ) ;
}
RS485Serial . write ( outChar ) ; //dirty hack to transfer long string
RS485Serial . flush ( ) ;
delay ( 1 ) ; //lot of errors without delay
outString = " " ;
if ( Ts2 . e = = 1 ) {
outString + = " , \" TS2 \" : " + String ( Ts2 . T ) ;
}
if ( Tac . e = = 1 ) {
outString + = " , \" TAC \" : " + String ( Tac . T ) ;
}
2019-04-16 15:53:34 +00:00
if ( Ttarget . e = = 1 ) {
outString + = " , \" TT \" : " + String ( Ttarget . T ) ;
}
# ifdef EEV_SUPPORT
2019-05-02 12:52:19 +00:00
outString + = " , \" EEVP \" : " + String ( EEV_cur_pos ) ;
outString + = " , \" EEVA \" : " + String ( T_EEV_setpoint ) ;
2019-04-16 15:53:34 +00:00
# endif
2019-04-01 03:02:55 +00:00
outString + = " } " ;
2019-04-16 15:53:34 +00:00
} else if ( ( inData [ 2 ] = = 0x54 ) | | ( inData [ 2 ] = = 0x45 ) ) { //(T)arget or (E)EV target format NN.NN, text
2019-04-01 03:02:55 +00:00
if ( isDigit ( inData [ 3 ] ) & & isDigit ( inData [ 4 ] ) & & ( inData [ 5 ] = = 0x2e ) & & isDigit ( inData [ 6 ] ) & & isDigit ( inData [ 7 ] ) & & ( ! isDigit ( inData [ 8 ] ) ) ) {
tone ( speakerOut , 2250 ) ;
delay ( 100 ) ; // like ups power on
noTone ( speakerOut ) ;
char * carray = & inData [ 3 ] ;
tempdouble = atof ( carray ) ;
2019-04-16 15:53:34 +00:00
if ( inData [ 2 ] = = 0x54 ) {
if ( tempdouble > cT_setpoint_max ) {
outString + = " { \" err \" : \" too hot! \" } " ;
} else if ( tempdouble < 1.0 ) {
outString + = " { \" err \" : \" too cold! \" } " ;
} else {
T_setpoint = tempdouble ;
outString + = " { \" result \" : \" ok, new value is: " ;
outString + = String ( T_setpoint ) ;
outString + = " \" } " ;
}
}
if ( inData [ 2 ] = = 0x45 ) {
if ( tempdouble > 10.0 ) { //!!!!!!! hardcode !!!
outString + = " { \" err \" : \" too hot! \" } " ;
} else if ( tempdouble < 0.1 ) { //!!!!!!! hardcode !!!
outString + = " { \" err \" : \" too cold! \" } " ;
} else {
T_EEV_setpoint = tempdouble ;
outString + = " { \" result \" : \" ok, new EEV value is: " ;
outString + = String ( T_EEV_setpoint ) ;
outString + = " \" } " ;
}
2019-04-01 03:02:55 +00:00
}
} else {
outString + = " { \" err \" : \" NaN, format: NN.NN \" } " ;
}
} else {
//default, just for example
2019-06-01 19:16:28 +00:00
outString + = " { \" err \" : \" no_command \" } " ;
2019-04-01 03:02:55 +00:00
}
//crc.integer = CRC16.xmodem((uint8_t& *) outString, outString.length());
//outString += (crc, HEX);
outString + = " \n " ;
char * outChar = & outString [ 0 ] ;
RS485Serial . write ( outChar ) ;
}
index = 0 ;
for ( i = 0 ; i < 49 ; i + + ) { //clear buffer
inData [ i ] = 0 ;
}
RS485Serial . flush ( ) ;
digitalWrite ( SerialTxControl , RS485Receive ) ;
delay ( 1 ) ;
# endif
}
}