diff --git a/Valden_HeatPumpController.ino b/Valden_HeatPumpController.ino
new file mode 100644
index 0000000..0e9daa0
--- /dev/null
+++ b/Valden_HeatPumpController.ino
@@ -0,0 +1,3184 @@
+/*
+
+ Valden Heat Pump.
+
+ Heat Pump Controller firmware.
+
+ https://github.com/OpenHP/
+
+ Copyright (C) 2018-2021 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 .
+*/
+
+
+//-----------------------USER OPTIONS-----------------------
+//#define SELFTEST_RELAYS_LEDS_SPEAKER //speaker and relays QA test, uncomment to enable
+//#define SELFTEST_EEV //EEV QA test, uncomment to enable
+//#define SELFTEST_T_SENSORS //temperature sensors QA test, uncomment to enable
+
+//communication protocol with external world
+//#define RS485_JSON 1 //json, external systems integration
+//#define RS485_HUMAN 2 //RS485 is used in the same way as the local console, warning: Use only if 2 devices (server and this controller) connected to the same RS485 line
+#define RS485_MODBUS 3 //default, MODBUS via RS485, connection to the display (both sensor or 1602, see https://GitHub.com/OpenHP/Display/) or connection to any other MODBUS application or device
+
+//system type, comment both if HP with EEV
+//#define EEV_ONLY //Valden controller as EEV controller: NO target T sensor. No relays. Oly EEV. Sensors required: Tae, Tbe, current sensor. Additional T sensors can be used but not required.
+//#define NO_EEV //capillary tube or TXV, EEV not used
+
+//which sensor is used to check setpoint, uncomment one of options
+#define SETPOINT_THI //"warm floor" scheme: "hot in" (Thi) temperature used as setpoint
+//#define SETPOINT_TS1 //"swimming pool" or "water tank heater" scheme: "sensor 1" (Ts1) is used as setpoint and located somewhere in a water tank
+
+#define HUMAN_AUTOINFO 30000 //print stats to console, every milliseconds
+
+#define WATCHDOG //disable for older bootloaders
+//-----------------------USER OPTIONS END-----------------------
+
+
+
+//-----------------------Fine Tuning OPTIONS-----------------------
+//next sections: advanced options
+
+
+
+//-----------------------T Sensors -----------------------
+//temperature sensors used in a system, comment to disable
+#define T_cold_in; //cold side (heat source) inlet sensor
+#define T_cold_out; //cold side outlet sensor
+#define T_before_evaporator; //"before" and "after evaporator" sensors required to control EEV, both "EEV_ONLY" and "full" schemes
+#define T_after_evaporator; //"before" and "after evaporator" sensors required to control EEV, both "EEV_ONLY" and "full" schemes
+//#define T_separator_gas; //no longer used (PCB 1.3 MI +) artifact from experimental scheme with separator
+//#define T_separator_liquid; //no longer used (PCB 1.3 MI +) artifact from experimental scheme with separator
+//#define T_before_valve; //no longer used (PCB 1.3 MI +) artifact from experimental scheme with separator
+//#define T_suction; //no longer used (PCB 1.3 MI +) artifact from experimental scheme with separator
+#ifdef SETPOINT_TS1
+ #define T_sensor_1; //T values from the additional sensor S1 used as a "setpoint" in "pool" or "water tank heater" schemes
+#endif
+//!!!
+#define T_sensor_2; //additional sensor, any source; for example, outdoor temperature, in-case temperature, and so on
+#define T_crc; //if defined, enables the crankcase T sensor and crankcase heater on the relay "Crankcase heater"
+//#define T_regenerator; //an additional sensor, the regenerator temperature sensor (inlet or outlet or housing); used only to obtain a temperature data if necessary
+#define T_afrer_condenser; //after condenser (and before valve)
+//!!!#define T_before_condenser; //before condenser (discharge)
+#define T_hot_out; //hot side outlet
+//In full scheme Hot IN required! Optional in "EEV_ONLY" scheme (see "EEV_ONLY" option),
+#define T_hot_in; //hot side inlet
+
+//-----------------------TEMPERATURES-----------------------
+#define MAGIC 0x66; //change this value if you want to rewrite the T setpoint in EEPROM
+#define T_SETPOINT 26.0; //This is a predefined target temperature value (start temperature). EEPROM-saved. Ways to change this value: 1. Console command 2. Change the "setpoint" on a display 3. Change value here AND change "magic number" 4. JSON command
+#define T_SETPOINT_MAX 48.0; //maximum "setpoint" temperature that an ordinary user can set
+#define T_SETPOINT_MIN 10.0; //min. "setpoint" temperature that an ordinary user can set, lower values not recommended until antifreeze fluids at hot side used.
+#define T_CRANKCASE_MIN 8.0; //compressor (crankcase) min. temperature, HP will not start if T lower
+#define T_CRANKCASE_MAX 110.0; //compressor (crankcase) max. temperature, overheating protection, HP will stop if T higher
+#define T_CRANKCASE_HEAT_THRESHOLD 16.0; //crankcase heater threshold, the compressor heater will be powered on if T lower
+#define T_WORKINGOK_CRANKCASE_MIN 25.0; //compressor temperature: additional check. HP will stop if T is lower than this value after 5 minutes of work. Do not set the value too high to ensure normal operation after long pauses.
+#define T_BEFORE_CONDENSER_MAX 108.0; //discharge MAX, system stops if discharge higher
+#define T_COLDREF_MIN -14.0; //suction min., HP stops if T lower, cold side (glycol) loop freeze protection and compressor protection against liquid
+#define T_BEFORE_EVAP_WORK_MIN -25.5; //!!!before evaporator (after valve) min. T; can be very low for a few minutes after a startup, ex: capillary tube in some conditions; and for all systems: after long shut-off, lack of refrigerant, 1st starts, and many others
+#define T_COLD_MIN -15.5; //cold side (glycol) loop freeze protection: HP stops if inlet or outlet temperature lower
+#define T_HOT_MAX 50.0; //hot loop: HP stops if hot side inlet or outlet temperature higher than this threshold
+
+//#define T_REG_HEAT_THRESHOLD 17.0; //no longer used (PCB 1.3 MI +) artifact from experimental scheme with separator
+//#define T_HOTCIRCLE_DELTA_MIN 2.0; //not used since ~FW v1.6, "water heater with intermediate heat exchanger" scheme, where Ts1 == "sensor in water"; hot side CP will be switched on if "Ts1 - hot_out > T_HOTCIRCLE_DELTA_MIN"
+
+//-----------------------WATTS AND CYCLES TIMES-----------------------
+//time: milliseconds, power: watts
+#define MAX_WATTS 1000.0 + 70.0 + 80.0 //power limit, watt, HP stops if exceeded, examples: // installation1: compressor 165: 920 Watts, + 35 watts 25/4 circ. pump at 1st speed + 53 watts 25/4 circ. pump at 2nd speed
+ // installation2: compressor unk: ~1000 + hot CP 70 + cold CP 80 = 1150 watts
+ // installation3: and so on
+#define POWERON_PAUSE 300000 //after power on: wait 5 minutes before starting HP (power faults protection)
+#define MINCYCLE_POWEROFF 600000 //after a normal compressor stop: 10 minutes pause (max 99999 seconds)
+#define MINCYCLE_POWERON 3600000 //after compressor start: minimum compressor operation time, i.e. work time is not less than this value (or more, depending on the setpoint temperature) 60 minutes = 3.6 KK 120mins = 5.4 kK.
+#define POWERON_HIGHTIME 7000 //after compressor start: defines time when power consumption can be 3 times greater than normal, 7 sec. by default
+#define COLDCIRCLE_PREPARE 90000 //before compressor start: power on cold CP and wait 90 sec.; if false start: CP will off twice this time; and (hotcircle_stop_after - this_value) must be > hotcircle_check_prepare or HP will go sleep cycle instead of start
+#define DEFFERED_STOP_HOTCIRCLE 1200000 //after compressor stop: wait 20 minutes, if no need to start compressor: stop hot WP; value must be > 0
+#define HOTCIRCLE_START_EVERY 2400000 //while pauses: pump on "hot side" starts every 40 minutes (by default) (max 9999 seconds) to circulate water and get exact temperature reading, option used if "warm floor" installation (Thi as setpoint)...
+#define HOTCIRCLE_CHECK_PREPARE 150000 //while pauses: ...and wait for temperature stabilization 2.5 minutes (by default), after that do setpoint checks...
+#define HOTCIRCLE_STOP_AFTER (HOTCIRCLE_CHECK_PREPARE + COLDCIRCLE_PREPARE + 30000) //...and then stop after few minutes of circulating, if temperature is high and no need to start compressor; value must be check_prepare + coldcircle_prepare + 30 seconds (or more)
+
+
+//-----------------------EEV-----------------------
+//If you are using a capillary tube or TXV: simply skip next section.
+//Depending on how many milliseconds allocated per step, the speed of automatic tuning will change.
+//Remember that your refrigeration system reaction on every step is not immediate. The system reacts after a few minutes, sometimes after tens of minutes.
+
+#define EEV_MAXPULSES 250 //max steps, 250 is tested for sanhua 1.3
+
+//steps tuning: milliseconds per fast and slow (precise) steps
+#define EEV_PULSE_FCLOSE_MILLIS 20 //(20 tube evaporator) fast closing, closing on danger (milliseconds per step)
+#define EEV_PULSE_CLOSE_MILLIS 45000 //(50000 tube evaporator) accurate closing while the compressor works (milliseconds per step)
+#define EEV_PULSE_WOPEN_MILLIS 20 //(20 tube evaporator) standby (waiting) pos. set (milliseconds per step)
+#define EEV_PULSE_FOPEN_MILLIS 1400 //(1300 tube evaporator) fast opening, fast search (milliseconds per step)
+#define EEV_PULSE_OPEN_MILLIS 30000 //(60000 tube evaporator) accurate opening while the compressor works (milliseconds per step)
+#define EEV_STOP_HOLD 500 //0.1..1sec for Sanhua hold time (milliseconds per step)
+#define EEV_CLOSEEVERY 86400000 //86400000: EEV full close (zero calibration) every 24 hours, executed while HP is NOT working (milliseconds per cycle)
+
+//positions
+#define EEV_CLOSE_ADD_PULSES 8 //read below, additional steps after zero position while full closing
+#define EEV_OPEN_AFTER_CLOSE 45 //0 - set the zero position, then add EEV_CLOSE_ADD_PULSES (zero insurance, read EEV guides for this value) and stop, EEV will be in zero position.
+ //N - set the zero position, then add EEV_CLOSE_ADD_PULSES, than open EEV on EEV_OPEN_AFTER_CLOSE pulses
+ //i.e. it's a "waiting position" while HP isn't working, value must be <= MINWORKPOS
+#define EEV_MINWORKPOS 50 //position will be not less during normal work, open EEV to this position after compressor start
+
+//temperatures
+#define EEV_PRECISE_START 8.6 //(8.6 tube evaporator) precise tuning threshold: make slower pulses if (real_diff-target_diff) less than this value. Used for fine auto-tuning
+#define EEV_EMERG_DIFF 1.7 //(2.5 tube evaporator) liquid at suction threshold: if dangerous condition occurred, real_diff =< (target_diff - EEV_EMERG_DIFF) then EEV will be closed to min. work position //Ex: EEV_EMERG_DIFF = 2.0, target diff 5.0, if real_diff =< (5.0 - 2.0) then EEV will be closed to EEV_MINWORKPOS
+#define EEV_HYSTERESIS 0.45 //(0.6 tube evaporator) hysteresis, to stop fine tuning: must be less than EEV_PRECISE_START, ex: target difference = 4.0, hysteresis = 0.3, no EEV pulses will be done while real difference in range 4.0..4.3
+#define EEV_TARGET_TEMP_DIFF 3.6 //(3.6 tube evaporator) target difference between Before Evaporator and After Evaporator, the head of the whole algorithm
+
+//additional options
+#define EEV_REOPENLAST 1 ///1 = reopen to last position on compressor start, useful for ordinary schemes with everyday working cycles, 0 = not
+#define EEV_REOPENMINTIME 40000 //after system start: min. delay between "min. work pos." (must be > 0 in this case and > waiting position) set and reopening start
+//#define EEV_MANUAL //comment to disable, manual set of EEV position via a console; warning: this option will stop all EEV auto-activities, including zero position find procedure; so this option not recommended: switch auto/manual mode from a console
+
+//do not use next option if you're not sure what are you doing
+//#define EEV_DEBUG //debug, useful during system fine-tuning, works both with local serial and RS485_HUMAN
+//-----------------------ADDRESSES-----------------------
+const char devID = 0x45; //used only if JSON communication, does not matter for MODBUS and Valden display https://github.com/OpenHP/Display/
+const char hostID = 0x30; //used only if JSON communication, not used for MODBUS
+
+//-----------------------OTHER-----------------------
+#define MAX_SEQUENTIAL_ERRORS 15 //max cycles to wait auto-clean error, ex: T sensor appears, stop compressor after counter exceeded (millis_cycle * MAX_SEQUENTIAL_ERRORS)
+//-----------------------Fine Tuning OPTIONS END -----------------------
+
+//-----------------------changelog-----------------------
+/*
+v1.0, 01 Sep 2019:
++ initial version, hardware and software branch ready
+
+v1.1: 21 Sep 2019:
++ Dev and Host ID to header
+
+v1.2: 20 Dec 2019:
++- ?seems to be fixed minor bug while HP stopped: wattage is 0, if tCrc < T_CRANKCASE_HEAT_THRESHOLD and may be few sensors absence
++ min_user_t/max_user_t to header
+
+v1.3: 05 Jan 2020:
++ manual EEV mode (high priority, ex: new system 1st starts and charge)
++ rs485_modbus
++ reopen to last EEV value at startup
+
+v1.4: 22 Jan 2020
++ crankcase naming
+
+v1.5: 05 Jun 2020
++ minor modbus updates
+
+v1.6: 09 Dec 2020
++ NO_EEV option
++ some variables renames
++ Tho instead of Thi (stop conditions) bugfix
++ Last Start Message added
+
+v1.7: 03 Feb 2021
++ 1.3 PCB revision support, previous revisions also supported
++ enable cold circle if tci < col_min (circulate ground loop, if outdoor installation and very cold and deep freeze)
++ inputs support
++ add option "Thi" and "Ts1" to header, enable Ts1 by this option
++ temperature check after start of hot side circle + 5 mins for Thi target
+
+v1.8: 06 Feb 2021
++ very rare case: 0.0 readings, 2-3 attempts then pass 0.0
++ countdown for compressor relay after cold CP start (stab. cold loop T)
++ self-test options to header
+
+v1.9-1.11: 25-27 Feb 2021:
++ lot of small workflow logic and user terminal changes
+
+v1.12: 21 Mar 2021:
++ TS1/THO #define way fix
++ CWP and HWP prepare optimisation
+
+v1.13: 26 Mar 2021:
++ rounding error via Modbus found and fixed
+
+//TODO:
+? lower bit resolution for all sensors, except Tbe, Tae, Ts1 ?
+? poss. DoS: infinite read to nowhere, fix it, set finite counter (ex: 200)
+? add "heater start" and "cold circle start" and "not start HP" if t_crc < t_coldin/coldout(?)/tae/tbe(?) + 2.0
+? ref. migration protection for summer season with long waiting periods: start cold circle and crankcase heater if tCrc =< tci+1, add option to header
+? EEV manual mode and position by RS485 python or modbus command ?
+? add speaker and err code for ""ERR: no Tae or Tbe for EEV!""
+? deffered HWP stop: check HP stop cause, stop HWP if protective/error stop
+? wclose and fclose to EEV
+? valve_4way
+? rewite re-init proc from MAGIC to another way
+? EEV: target to EEPROM (?? no need ?)
+? EEV: define maximum working position
+*/
+//-----------------------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
+//
+
+//Speaker
+//
+// 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 ~10K..470K resistor to GND
+- via ~10K..470K resistor to +5 (same as prev.)
+if 10K+10K used: current is 25mA
+use 100K+100K 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
+
+
+/*
+relay 1: heat pump
+relay 2: hot side circulator pump
+relay 3: cold side circulator pump
+relay 4: crankcase heater
+relay 5: (1.3+: not used anymore)
+
+relay 6: reserved
+relay 7: reserved
+
+T sensors:
+
+0 cold_in;
+1 cold_out;
+2 before_evaporator;
+3 after_evaporator;
+4 separator_gas; //if flooded evaporator: separator out
+5 separator_liquid; //if flooded evaporator: separator out
+6 before_valve; //before expansion valve, if regenerator used
+7 suction; //compressor suction, if regenerator
+8 sensor_1; //additional sensor 1
+9 sensor_2; //additional sensor 2
+A crankcase; //compressor case
+B regenerator;
+C afrer_condenser;
+D before_condenser;
+E hot_out;
+F hot_in;
+*/
+
+String fw_version = "1.13";
+
+//hardware resources
+#define RELAY_HEATPUMP A2
+#define RELAY_HOTSIDE_CIRCLE A1
+
+#define PR_LOW A6
+#define PR_HIGH A7
+
+#define OW_BUS_ALLTSENSORS 9
+#define speakerOut 6
+#define em_pin1 A3
+
+
+String hw_version = "v1.1+";
+
+#define LATCH_595 3
+#define CLK_595 2
+#define DATA_595 7
+#define OE_595 4
+
+//---------------------------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(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
+#include
+
+#define SEED 0xFFFF
+#define POLY 0xA001
+unsigned int crc16;
+int cf;
+#define MODBUS_MR 50 //50 ok now
+
+#include
+#define SerialRX 12 //RX connected to RO - Receiver Output
+#define SerialTX 11 //TX connected to DI - Driver Output Pin
+#define SerialTxControl 13 //RS485 Direction control DE and RE to this pin
+#define RS485Transmit HIGH
+#define RS485Receive LOW
+
+SoftwareSerial RS485Serial(SerialRX, SerialTX); // RX, TX
+
+#include
+#include
+//library's DEVICE_DISCONNECTED_C -127.0
+
+OneWire ow_ALLTSENSORS(OW_BUS_ALLTSENSORS);
+DallasTemperature s_allTsensors(&ow_ALLTSENSORS);
+
+DeviceAddress dev_addr; //temp
+
+
+//short names used to prevent unreadeable source
+#ifdef T_cold_in
+ bool TciE = 1;
+#else
+ bool TciE = 0;
+#endif
+double Tci = -127.0;
+
+#ifdef T_cold_out
+ bool TcoE = 1;
+#else
+ bool TcoE = 0;
+#endif
+double Tco = -127.0;
+
+#ifdef T_before_evaporator
+ bool TbeE = 1;
+#else
+ bool TbeE = 0;
+#endif
+double Tbe = -127.0;
+
+
+#ifdef T_after_evaporator
+ bool TaeE = 1;
+#else
+ bool TaeE = 0;
+#endif
+double Tae = -127.0;
+
+
+/*
+#ifdef T_separator_gas
+ bool TsgE = 1;
+#else
+ bool TsgE = 0;
+#endif
+double Tsg = -127.0;
+
+
+#ifdef T_separator_liquid
+ bool TslE = 1;
+#else
+ bool TslE = 0;
+#endif
+double Tsl = -127.0;
+
+
+#ifdef T_before_valve
+ bool TbvE = 1;
+#else
+ bool TbvE = 0;
+#endif
+double Tbv = -127.0;
+
+
+#ifdef T_suction
+ bool TsucE = 1;
+#else
+ bool TsucE = 0;
+#endif
+double Tsuc = -127.0;
+*/
+
+#ifdef T_sensor_1
+ bool Ts1E = 1;
+#else
+ bool Ts1E = 0;
+#endif
+double Ts1 = -127.0;
+
+
+#ifdef T_sensor_2
+ bool Ts2E = 1;
+#else
+ bool Ts2E = 0;
+#endif
+double Ts2 = -127.0;
+
+
+#ifdef T_crc
+ bool TcrcE = 1;
+#else
+ bool TcrcE = 0;
+#endif
+double Tcrc = -127.0;
+
+#ifdef T_regenerator
+ bool TregE = 1;
+#else
+ bool TregE = 0;
+#endif
+double Treg = -127.0;
+
+
+#ifdef T_afrer_condenser
+ bool TacE = 1;
+#else
+ bool TacE = 0;
+#endif
+double Tac = -127.0;
+
+#ifdef T_before_condenser
+ bool TbcE = 1;
+#else
+ bool TbcE = 0;
+#endif
+double Tbc = -127.0;
+
+#ifdef T_hot_out
+ bool ThoE = 1;
+#else
+ bool ThoE = 0;
+#endif
+double Tho = -127.0;
+
+#ifdef T_hot_in
+ bool ThiE = 1;
+#else
+ bool ThiE = 0;
+#endif
+double Thi = -127.0;
+
+double T_setpoint = T_SETPOINT;
+double T_setpoint_lastsaved = T_setpoint;
+double T_EEV_setpoint = EEV_TARGET_TEMP_DIFF;
+double T_EEV_dt = 0.0; //real, used during run
+const double cT_setpoint_max = T_SETPOINT_MAX;
+const double cT_setpoint_min = T_SETPOINT_MIN;
+//const double cT_hotcircle_delta_min = T_HOTCIRCLE_DELTA_MIN;
+const double cT_crc_min = T_CRANKCASE_MIN;
+const double cT_crc_max = T_CRANKCASE_MAX;
+const double cT_crc_heat_threshold = T_CRANKCASE_HEAT_THRESHOLD;
+//const double cT_reg_heat_threshold = T_REG_HEAT_THRESHOLD;
+const double cT_before_condenser_max = T_BEFORE_CONDENSER_MAX;
+const double cT_coldref_min = T_COLDREF_MIN;
+const double cT_before_evap_work_min = T_BEFORE_EVAP_WORK_MIN;
+const double cT_cold_min = T_COLD_MIN;
+const double cT_hot_max = T_HOT_MAX;
+//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;
+const double cT_workingOK_crc_min = T_WORKINGOK_CRANKCASE_MIN; //need to be not very high to normal start after deep freeze
+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/5; //
+
+unsigned int pr_low_state_anal = 0; //sensors are NC for spec. conditions, so 1 == ok, 0 == error
+unsigned int pr_high_state_anal = 0; //
+
+bool pr_low_state_bool = 1; //sensors are NC for spec. conditions, so 1 == ok, 0 == error
+bool pr_high_state_bool = 1; //
+
+bool heatpump_state = 0;
+bool hotside_circle_state = 0;
+bool coldside_circle_state = 0;
+bool crc_heater_state = 0;
+//bool reg_heater_state = 0;
+
+//bool relay6_state = 0;
+//bool relay7_state = 0;
+
+bool LED_OK_state = 0;
+bool LED_ERR_state = 0;
+
+bool S0_state = 0;
+bool S1_state = 0;
+bool S2_state = 0;
+bool S3_state = 0;
+
+bool EEV1_state = 0;
+bool EEV2_state = 0;
+bool EEV3_state = 0;
+bool EEV4_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
+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;
+
+int EEV_cur_pos = 0;
+int EEV_reopen_pos = 0;
+bool EEV_must_reopen_flag = 0;
+
+int EEV_apulses = 0; //for async
+bool EEV_adonotcare = 0;
+const unsigned char EEV_steps[4] = {0b1010, 0b0110, 0b0101, 0b1001};
+char EEV_cur_step = 0;
+bool EEV_fast = 0;
+#ifdef EEV_MANUAL
+ bool EEV_manual = 1;
+#else
+ bool EEV_manual = 0;
+#endif
+const bool c_EEV_reopenlast = EEV_REOPENLAST;
+
+//main cycle vars
+unsigned long millis_prev = 0;
+unsigned long millis_now = 0;
+unsigned long millis_cycle = 1000;
+
+unsigned long millis_last_heatpump_on = 0;
+unsigned long millis_last_heatpump_off = 0;
+
+unsigned long millis_last_hotWP_on = 0;
+unsigned long millis_last_hotWP_off = 0;
+
+unsigned long millis_last_coldWP_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_485 = 0;
+unsigned long millis_charinput_485 = 0;
+unsigned long millis_escinput_local = 0;
+unsigned long millis_charinput_local = 0;
+
+
+unsigned long millis_lasteesave = 0;
+
+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;
+unsigned long millis_eev_minworkpos_time = 0;
+unsigned long millis_eev_last_work = 0;
+
+unsigned long tmic1 = 0;
+unsigned long tmic2 = 0;
+
+int skipchars_485 = 0;
+int skipchars_local = 0;
+
+#define BUFSIZE 150
+
+unsigned char dataBuf[BUFSIZE+1]; // 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 u = 0;
+int z = 0;
+int x = 0;
+int y = 0;
+double tempdouble = 0.0;
+double tempdouble_intpart = 0.0;
+
+int tempint = 0;
+bool tempbool = 0;
+
+char fp_integer = 0;
+char fp_fraction = 0;
+
+String outString;
+String lastStopCauseTxt; //20 reserved, but use 12 chars of text max
+bool fl_printSS_lastStopCauseTxt = 0; //flag to call printSS
+#define LSCint_normal 0
+#define LSCint_protective 1
+#define LSCint_error 2
+int LSCint = LSCint_normal; //0 = normal, 1 = protective, 2 = error
+String lastStartMsgTxt; //same as LSC
+bool fl_printSS_lastStartMsgTxt = 0; //flag to call printSS
+String t_sensorErrString;
+
+char convBuf[13];
+
+//-------------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_P_HI 2
+#define ERR_P_LO 3
+
+int errorcode = 0;
+unsigned char sequential_errors = 0;
+
+//--------------------------- for wattage
+#define ADC_BITS 10 //10 fo regular arduino
+#define ADC_COUNTS (1<>1; //Low-pass filter output
+double sqI_1,sumI_1 = 0; //sq = squared, sum = Sum, inst = instantaneous
+double async_Irms_1 = 0;
+double async_wattage = 0;
+//--------------------------- for wattage END
+
+const char str1[] PROGMEM = "Valden Heat Pump Controller, https://github.com/OpenHP/\n\r\n\rCommands: \n\r(?) help\n\r(-) decrease setpoint T\n\r\n\r(+) increase setpoint T";
+const char str2[] PROGMEM = "(<) decrease EEV T diff \n\r(>) increase EEV T diff\n\r\n\r(M) manual EEV mode\n\r(A) auto EEV mode\n\r\n\r(z) -1 EEV\t(Z) -10 EEV\n\r(x) +1 EEV\t(X) +10 EEV\n\r(G) get stats";
+const char str3[] PROGMEM = "EEV:auto";
+const char str4[] PROGMEM = "EEV:manual";
+const char str5[] PROGMEM = "N/A,auto";
+const char str6[] PROGMEM = "+10 ok";
+const char str7[] PROGMEM = "-10 ok";
+const char str8[] PROGMEM = "+1 ok";
+const char str9[] PROGMEM = "-1 ok";
+const char str10[] PROGMEM = "Max!";
+const char str11[] PROGMEM = "Min!";
+const char str12[] PROGMEM = "HWP ON by Setp. update";
+const char str13[] PROGMEM = "EE->mem";
+const char str14[] PROGMEM = "mem->EE";
+const char str15[] PROGMEM = "OK:E.T.Sens.";
+const char str16[] PROGMEM = "OK:Pr.Cold";
+const char str17[] PROGMEM = "OK:Pr.Hot";
+const char str18[] PROGMEM = "HWP_ON";
+const char str19[] PROGMEM = "unkn_F";
+
+PGM_P const const_strs[] PROGMEM = {
+ str1, str2, str3, str4, str5, str6, str7, str8, str9, str10,
+ str11, str12, str13, str14, str15, str16, str17, str18, str19
+};
+
+#define IDX_HELP1 0
+#define IDX_HELP2 1
+#define IDX_EEVAUTO 2
+#define IDX_EEVMANUAL 3
+#define IDX_NAAUTO 4
+#define IDX_PLUS10_OK 5
+#define IDX_MINUS10_OK 6
+#define IDX_PLUS1_OK 7
+#define IDX_MINUS1_OK 8
+#define IDX_MAX 9
+#define IDX_MIN 10
+#define IDX_HWP_ONBYUPD 11
+#define IDX_EEtoMEM 12
+#define IDX_MEMtoEE 13
+#define IDX_OK_ETSENS 14
+#define IDX_OK_PRCOLD 15
+#define IDX_OK_PRHOT 16
+#define IDX_HWPON 17
+#define IDX_UNKNF 18
+
+
+//--------------------------- 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
+}
+
+/*void PrintS (String str) {
+ #ifdef RS485_HUMAN
+ char *outChar=&str[0];
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outChar);
+ RS485Serial.println();
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+}*/
+
+void PrintSS (String str) {
+ char *outChar=&str[0];
+ if (str == "") {
+ return;
+ }
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outChar);
+ RS485Serial.println();
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+ Serial.println(outChar);
+ Serial.flush();
+}
+
+void PrintSSch(char idx) {
+ strcpy_P(dataBuf, (PGM_P)pgm_read_word(&const_strs[idx]));
+ Serial.println((const char *) dataBuf);
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print((const char *) dataBuf);
+ RS485Serial.println();
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+}
+void PrintSS_SaD (double num) { //global string + double
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outString);
+ RS485Serial.println(num);
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+ Serial.print(outString);
+ Serial.println(num);
+ Serial.flush();
+}
+
+void PrintSS_SaBl (bool num) {
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outString);
+ RS485Serial.println(num);
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+ Serial.print(outString);
+ Serial.println(num);
+ Serial.flush();
+}
+
+void ApToOut_D (double num) {
+ outString += String(num);
+}
+
+void PrintSS_SaI (int num) {
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outString);
+ RS485Serial.println(num);
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+ Serial.print(outString);
+ Serial.println(num);
+ Serial.flush();
+}
+
+
+/*void PrintSS_SaI (int num) { //global string + double
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outString);
+ RS485Serial.println(num);
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+ Serial.print(outString);
+ Serial.println(num);
+ Serial.flush();
+}*/
+
+void _PrintHelp(void) {
+ PrintSS("fw: " + fw_version + " board: "+ hw_version);
+ PrintSSch(IDX_HELP1);
+ #ifndef NO_EEV
+ PrintSSch(IDX_HELP2);
+ #endif
+}
+
+void PrintSS_double (double double_to_print) {
+ dtostrf(double_to_print,1,2,temp);
+ PrintSS(temp);
+}
+
+void Add_Double_To_Buf_IntFract (double float_to_convert) { //uses tempdouble tempdouble_intpart fp_integer fp_fraction
+ if (float_to_convert > 255.0 || float_to_convert < -127.0) {
+ fp_integer = -127;
+ fp_fraction = 0;
+ } else {
+ tempdouble = modf (float_to_convert , &tempdouble_intpart);
+ fp_integer = trunc(tempdouble_intpart);
+ tempdouble = tempdouble * 100;
+ fp_fraction = round(tempdouble);
+ }
+ dataBuf[i] = fp_integer;
+ i++;
+ dataBuf[i] = fp_fraction;
+ i++;
+ /*
+ Serial.println(float_to_convert);
+ Serial.println(fp_integer, DEC);
+ Serial.println(fp_fraction, DEC);*/
+}
+
+
+void IntFract_to_tempdouble (char _int_to_convert, char _fract_to_convert) { //fract is also signed now!
+ tempdouble = (double) _fract_to_convert / 100;
+ tempdouble += _int_to_convert;
+ /*Serial.println(_int_to_convert);
+ Serial.println(_fract_to_convert);
+ Serial.println(tempdouble);*/
+}
+
+
+void _ProcessInChar(void){
+ //remote commands +,-,G,0x20/?/Enter/A/M/x/X/z/Z
+ 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;
+ #ifndef NO_EEV
+ case 0x3C:
+ Dec_E();
+ break;
+ case 0x3E:
+ Inc_E();
+ break;
+ case 0x41:
+ EEV_manual = 0;
+ PrintSSch(IDX_EEVAUTO);
+ break;
+ #endif
+ case 0x47:
+ PrintStats_SS();
+ millis_last_printstats = millis_now;
+ break;
+ #ifndef NO_EEV
+ case 0x4D:
+ EEV_manual = 1;
+ PrintSSch(IDX_EEVMANUAL);
+ break;
+ case 0x58: //+10
+ if (EEV_manual != 1){
+ PrintSSch(IDX_NAAUTO);
+ break;
+ }
+ EEV_apulses += 10;
+ EEV_fast = 1;
+ PrintSSch(IDX_PLUS10_OK);
+ break;
+ case 0x5A: //-10
+ if (EEV_manual != 1){
+ PrintSSch(IDX_NAAUTO);
+ break;
+ }
+ EEV_apulses -= 10;
+ EEV_fast = 1;
+ PrintSSch(IDX_MINUS10_OK);
+ break;
+ case 0x78: //+1
+ if (EEV_manual != 1){
+ PrintSSch(IDX_NAAUTO);
+ break;
+ }
+ EEV_apulses += 1;
+ EEV_fast = 1;
+ PrintSSch(IDX_PLUS1_OK);
+ break;
+ case 0x7A: //-1
+ if (EEV_manual != 1){
+ PrintSSch(IDX_NAAUTO);
+ break;
+ }
+ EEV_apulses += 10;
+ EEV_fast = 1;
+ PrintSSch(IDX_MINUS1_OK);
+ break;
+ #endif
+ }
+
+}
+
+int Inc_T (void) {
+ if (T_setpoint + 0.5 > cT_setpoint_max) {
+ PrintSSch(IDX_MAX);
+ delay (200);
+ return 0;
+ }
+ T_setpoint += 0.5;
+ PrintSS_double(T_setpoint);
+ return 1;
+}
+
+int Dec_T (void) {
+ if (T_setpoint - 0.5 < cT_setpoint_min) {
+ PrintSSch(IDX_MIN);
+ delay (200);
+ return 0;
+ }
+ T_setpoint -= 0.5;
+ PrintSS_double(T_setpoint);
+ return 1;
+}
+
+int Inc_E (void) { ///!!! unprotected
+ T_EEV_setpoint += 0.25;
+ PrintSS_double(T_EEV_setpoint);
+ return 1;
+}
+
+int Dec_E (void) { ///!!! unprotected
+ T_EEV_setpoint -= 0.25;
+ PrintSS_double(T_EEV_setpoint);
+ return 1;
+}
+
+
+
+
+
+void _HotWPon_by_Setpoint_update(void){ //if setpoint updated: start hot circle to check temperature
+ if ( (heatpump_state == 0) && (hotside_circle_state == 0) && ((unsigned long)(millis_now - millis_last_hotWP_on) < HOTCIRCLE_START_EVERY) ) { //process START_EVERY for hot side
+ millis_last_hotWP_off = millis_now;
+ hotside_circle_state = 1;
+ PrintSSch(IDX_HWP_ONBYUPD);
+ }
+}
+
+void PrintStats_SS (void) {
+
+ if (TciE) { outString = F("\n\r---\n\r\tTbe:\t") ; PrintSS_SaD(Tbe); }
+ if (TaeE) { outString = F("\tTae:\t") ; PrintSS_SaD(Tae); }
+ if (TcoE) { outString = F("\tTci:\t"); PrintSS_SaD(Tci); }
+ if (TcoE) { outString = F("\tTco:\t") ; PrintSS_SaD(Tco); }
+
+ //if (TsgE) { outString = F("\tTsg: ") ; PrintSS_SaD(Tsg); }
+ //if (TslE) { outString = F("\tTsl: ") ; PrintSS_SaD(Tsl); }
+ //if (TbvE) { outString = F("\tTbv: ") ; PrintSS_SaD(Tbv); }
+ //if (TsucE) { outString = F("\tTsuc: ") ; PrintSS_SaD(Tsuc); }
+ if (Ts1E) { outString = F("\tTs1:\t") ; PrintSS_SaD(Ts1); }
+ if (Ts2E) { outString = F("\tTs2:\t") ; PrintSS_SaD(Ts2); }
+ //Tcrc misorder due to large string
+ if (TregE) { outString = F("\tTreg:\t") ; PrintSS_SaD(Treg); }
+ if (TbcE) { outString = F("\tTbc:\t") ; PrintSS_SaD(Tbc); }
+ if (TacE) { outString = F("\tTac:\t") ; PrintSS_SaD(Tac); }
+ if (ThiE) { outString = F("\tThi:\t") ; PrintSS_SaD(Thi); }
+ if (ThoE) { outString = F("\tTho:\t") ; PrintSS_SaD(Tho); }
+ if (TcrcE) { outString = F("\tTcrankcase:\t"); PrintSS_SaD(Tcrc); }//misorder due to large string
+ outString = F("\tSetpoint:\t");
+ PrintSS_SaD(T_setpoint);
+
+ outString = F("\n\r\tHP:\t");
+ PrintSS_SaBl(heatpump_state);
+ outString = F("\tHWP:\t");
+ PrintSS_SaBl(hotside_circle_state);
+ outString = F("\tCWP:\t");
+ PrintSS_SaBl(coldside_circle_state);
+ outString = F("\tCRCheat:");
+ PrintSS_SaBl(crc_heater_state);
+ outString = F("\tWatts:\t") ;
+ PrintSS_SaD(async_wattage);
+
+ #ifndef NO_EEV
+ outString = F("\n\r\tT_EEV_setpoint: ");
+ PrintSS_SaD(T_EEV_setpoint);
+ outString = "\tEEV_pos:\t";
+ PrintSS_SaI(EEV_cur_pos);
+ #endif
+
+ outString = "\n\r\tErr:\t";
+ PrintSS_SaI(errorcode);
+ outString = F("\tPr.Cold:") ;
+ if (pr_low_state_bool == 1) {
+ outString += F("OK");
+ } else {
+ outString += F("ERR");
+ }
+ outString += F("\n\r\tPr.Hot:\t") ;
+ if (pr_high_state_bool == 1) {
+ outString += F("OK");
+ } else {
+ outString += F("ERR");
+ }
+
+ outString += F("\n\r\n\r\tLast Stop Cause:\t");
+ outString += lastStopCauseTxt;
+ outString += F("\n\r\tLast Start Message:\t");
+ outString += lastStartMsgTxt;
+ outString += F("\n\r---\n\r");
+ PrintSS(outString);
+
+ #ifdef RS485_HUMAN
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ RS485Serial.print(outString);
+ RS485Serial.println();
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ #endif
+}
+
+void Calc_CRC(unsigned char b) { //uses/changes y
+ crc16 ^= b & 0xFF;
+ for (y=0; y<8; y++) {
+ cf = crc16 & 0x0001;
+ crc16>>=1;
+ if (cf) { crc16 ^= POLY; }
+ }
+}
+
+void CheckIsInvalidCRCAddr(unsigned char *addr) {
+ if (OneWire::crc8( addr, 7) != addr[7] ) {
+ i+= 1;
+ }
+}
+
+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;
+ }
+}
+
+double GetT (int channel) {
+ S0_state = bitRead(channel,0);
+ S1_state = bitRead(channel,1);
+ S2_state = bitRead(channel,2);
+ S3_state = bitRead(channel,3);
+ halifise();
+
+ tempdouble = -127.0;
+ for ( i = 0; i < 8; i++) {
+ #ifdef WATCHDOG
+ wdt_reset();
+ #endif
+ eevise();
+ tempdouble = s_allTsensors.getTempCByIndex(0);
+ if ( (tempdouble == 85.0) || (tempdouble < -55.0) || (tempdouble == 0.0) || (tempdouble > 125.0) ) { //0.0 added to test
+ //outString = F("Warn:T_SensReRead!");
+ //PrintSS_SaD(tempdouble);
+ if ( tempdouble == 85.0 || tempdouble == 0.0 ) { //initial value in dallas register after poweron
+ s_allTsensors.requestTemperatures(); //!!!added to test, seems to work ok
+ delay (375); //375 actual for 11 bits resolution, 2-3 retries OK for 12-bits resolution
+ } else {
+ delay (37);
+ }
+ } else {
+ break;
+ }
+ }
+ s_allTsensors.requestTemperatures();
+ if ( (tempdouble > 125.0) || (tempdouble < -55.0)) { //incorrect readings protection, rare
+ tempdouble = -127.0;
+ }
+ return tempdouble;
+}
+
+//older version of GetT
+/*double GetT (int channel) {
+ S0_state = bitRead(channel,0);
+ S1_state = bitRead(channel,1);
+ S2_state = bitRead(channel,2);
+ S3_state = bitRead(channel,3);
+ halifise();
+
+ tempdouble = -127.0;
+ for ( i = 0; i < 8; i++) {
+ #ifdef WATCHDOG
+ wdt_reset();
+ #endif
+ eevise();
+ tempdouble = s_allTsensors.getTempCByIndex(0);
+ if ( (tempdouble == 85.0) || (tempdouble == -127.0) ) {
+ if ( tempdouble == 85.0 ) { //initial value in dallas register after poweron
+ s_allTsensors.requestTemperatures();//!!! added to test
+ delay (375); //375 actual for 11 bits resolution, 2-3 retries OK for 12-bits resolution
+ } else {
+ delay (37);
+ }
+ } else {
+ break;
+ }
+ }
+ s_allTsensors.requestTemperatures();
+ return tempdouble;
+}*/
+
+void GetTemperatures(void){
+ if (TciE) { Tci = GetT(0);}
+ if (TcoE) { Tco = GetT(1);}
+ if (TbeE) { Tbe = GetT(2);}
+ if (TaeE) { Tae = GetT(3);}
+ //if (TsgE) { Tsg = GetT(4);}
+ //if (TslE) { Tsl = GetT(5);}
+ //if (TbvE) { Tbv = GetT(6);}
+ //if (TsucE) { Tsuc = GetT(7);}
+ if (Ts1E) { Ts1 = GetT(8);}
+ if (Ts2E) { Ts2 = GetT(9);}
+ if (TcrcE) { Tcrc = GetT(10);}
+ if (TregE) { Treg = GetT(11);}
+ if (TacE) { Tac = GetT(12);}
+ if (TbcE) { Tbc = GetT(13);}
+ if (ThoE) { Tho = GetT(14);}
+ if (ThiE) { Thi = GetT(15);}
+}
+
+void on_EEV(){
+ x = EEV_steps[EEV_cur_step];
+ EEV1_state = bitRead(x, 0);
+ EEV2_state = bitRead(x, 1);
+ EEV3_state = bitRead(x, 2);
+ EEV4_state = bitRead(x, 3);
+ halifise();
+}
+
+void off_EEV(){
+ EEV1_state = 0;
+ EEV2_state = 0;
+ EEV3_state = 0;
+ EEV4_state = 0;
+ //PrintSS("off_EEV");
+ halifise();
+}
+
+void halifise(void){
+ /*
+ relay 1: heat pump
+ relay 2: hot side circulator pump
+ relay 3: cold side circulator pump
+ relay 4: crankcase heater
+ (no more v1.3mi) relay 5:
+
+ #define RELAY_HEATPUMP A2
+ #define RELAY_HOTSIDE_CIRCLE A1
+
+ Reg 1:
+ 595.0: 4067 S3
+ 595.1: 4067 S0
+ 595.2: 4067 S1
+ 595.3: 4067 S2
+ 595.4: EEV_1
+ 595.5: EEV_2
+ 595.6: EEV_3
+ 595.7: EEV_4
+
+ Reg 2:
+ 595.8: !! free
+ 595.9: ok/err LED 2
+ 595.A: Relay 6
+ 595.B: Relay 7
+ 595.C: Relay 5
+ 595.D: Relay 4
+ 595.E: Relay 3
+ 595.F: ok/err LED 1
+
+ Reg 3:
+ 595.10: LED "EEV opening"
+ 595.11: LED "EEV closing"
+ 595.12: LED "EEV Fast"
+ 595.13: LED "485 RX"
+ 595.14: LED "485 TX"
+ 595.15: LED "Manual mode"
+ 595.16: LED "LSC: error"
+ 595.17: LED "LSC: protection"
+ */
+
+ digitalWrite(LATCH_595, 0);
+ //17
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ if (LSCint == LSCint_protective) {
+ digitalWrite(DATA_595, 1);
+ } else {
+ digitalWrite(DATA_595, 0);
+ }
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //16
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ if (LSCint == LSCint_error) {
+ digitalWrite(DATA_595, 1);
+ } else {
+ digitalWrite(DATA_595, 0);
+ }
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //15
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV_manual);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //14
+ tempbool = digitalRead (13);
+
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, tempbool);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //13
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, !tempbool);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //12
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV_fast);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //11
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ if ( EEV_apulses < 0 ) {
+ digitalWrite(DATA_595, 1);
+ } else {
+ digitalWrite(DATA_595, 0);
+ }
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //10
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ if ( EEV_apulses > 0 ) {
+ digitalWrite(DATA_595, 1);
+ } else {
+ digitalWrite(DATA_595, 0);
+ }
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //F
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, LED_ERR_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //E
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, coldside_circle_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //D
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, crc_heater_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //C
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ //digitalWrite(DATA_595, reg_heater_state);
+ digitalWrite(DATA_595, 0);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //B
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ //digitalWrite(DATA_595, relay7_state);
+ digitalWrite(DATA_595, 0);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //A
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ //digitalWrite(DATA_595, relay6_state);
+ digitalWrite(DATA_595, 0);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //9
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, LED_OK_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //8
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, 0); //FREE
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //7
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV4_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //6
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV3_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //5
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV2_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //4
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, EEV1_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //3
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, S2_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //2
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, S1_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //1
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, S0_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ //0
+ digitalWrite(CLK_595, 0);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(DATA_595, S3_state);
+ digitalWrite(CLK_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(CLK_595, 0);
+ //
+ digitalWrite(LATCH_595, 1);
+ __asm__ __volatile__ ("nop\n\t");
+ digitalWrite(LATCH_595, 0);
+ digitalWrite (RELAY_HEATPUMP, heatpump_state);
+ digitalWrite (RELAY_HOTSIDE_CIRCLE, hotside_circle_state);
+}
+
+void eevise(void) {
+ 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;
+ //PrintSS("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;
+ //PrintSS("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];
+ EEV1_state = bitRead(x, 0);
+ EEV2_state = bitRead(x, 2); //!!!here pins are swapped fot sanhua
+ EEV3_state = bitRead(x, 1); //!!!here pins are swapped fot sanhua
+ EEV4_state = bitRead(x, 3);
+ }
+ if (EEV_cur_pos < 0) {
+ EEV_cur_pos = 0;
+ }
+ millis_eev_last_step = millis_now;
+ #ifdef EEV_DEBUG
+ PrintSS(String(EEV_cur_pos));
+ #endif
+ halifise();
+ }
+}
+
+//--------------------------- functions END
+
+void setup(void) {
+ pinMode (LATCH_595, OUTPUT);
+ pinMode (CLK_595, OUTPUT);
+ pinMode (DATA_595, OUTPUT);
+ pinMode (OE_595, OUTPUT);
+ pinMode (RELAY_HEATPUMP, OUTPUT);
+ pinMode (RELAY_HOTSIDE_CIRCLE, OUTPUT);
+ pinMode (PR_LOW, INPUT);
+ pinMode (PR_HIGH, INPUT);
+
+
+ digitalWrite (LATCH_595, LOW);
+ digitalWrite (CLK_595, LOW);
+ digitalWrite (DATA_595, LOW);
+ digitalWrite (OE_595, LOW);
+ digitalWrite (RELAY_HEATPUMP, LOW);
+ digitalWrite (RELAY_HOTSIDE_CIRCLE, LOW);
+ halifise();
+
+ #ifdef WATCHDOG
+ wdt_disable();
+ delay(2000);
+ #endif
+
+ // start serial port
+ Serial.begin(9600);
+ //Serial.print("Starting, dev_id:");
+ //Serial.println(devID);
+
+ RS485Serial.begin(9600);
+ pinMode(SerialTxControl, OUTPUT);
+ pinMode(SerialTX, OUTPUT);
+ pinMode(SerialRX, INPUT);
+ digitalWrite(SerialTxControl, RS485Receive);
+ delay(100);
+ PrintSS("ID: 0x" + String(devID, HEX));
+
+ delay(200);
+ off_EEV();
+
+ pinMode (em_pin1, INPUT);
+
+ //PrintSS("setpoint (C):");
+ //PrintSS(setpoint);
+
+ //PrintSS(String(freeMemory()));
+
+ s_allTsensors.begin();
+ s_allTsensors.setWaitForConversion(false); //ASYNC mode, request before get, see Dallas library for details
+
+ //----------------------------- self-tests ----------------------------- ----------------------------- -----------------------------
+ /*
+ index = 0;
+ outChar[index] = 0xFF;
+ index++;
+ outChar[index] = 0xAA;
+ index++;
+ outChar[index] = 0xBB;
+ index++;
+ outChar[index] = 0xCC;
+ index++;
+
+ crc16 = SEED;
+ for (z = 0; z < index; z++) {
+ Calc_CRC(outChar[z]);
+ }
+ outChar[index]=crc16 & 0xFF;
+ index++;
+ outChar[index]=crc16 >> 8;
+ index++;
+ outChar[index]=0x00;
+ index++;
+
+ Serial.println(crc16, HEX);
+ for (z = 0; z < index; z++) {
+ Serial.print(" ");
+ Serial.print(outChar[z], HEX);
+ }
+ Serial.println(" ");
+ */
+
+ //Relays self-test
+ #if (defined SELFTEST_RELAYS_LEDS_SPEAKER || defined SELFTEST_EEV || defined SELFTEST_T_SENSORS)
+ while ( 1 == 1) {
+ #if defined SELFTEST_RELAYS_LEDS_SPEAKER
+ PrintSS(F("Relays and LEDS self-test"));
+
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+
+ heatpump_state = 1; halifise(); delay(1000);
+ hotside_circle_state = 1; halifise(); delay(1000);
+ coldside_circle_state = 1; halifise(); delay(1000);
+ crc_heater_state = 1; halifise(); delay(1000);
+ //reg_heater_state = 1; halifise(); delay(1000);
+
+ //relay6_state = 1; halifise(); delay(1000);
+ //relay7_state = 1; halifise(); delay(1000);
+
+ EEV_apulses = 10; halifise(); delay(1000);
+ EEV_apulses = -10; halifise(); delay(1000);
+ EEV_fast = 1; halifise(); delay(1000);
+ digitalWrite(SerialTxControl, RS485Transmit); halifise(); delay(1000);
+ EEV_manual = 1; halifise(); delay(1000);
+ LSCint = LSCint_error; halifise(); delay(1000);
+ LSCint = LSCint_protective; halifise(); delay(1000);
+
+ LED_OK_state = 1; halifise(); delay(1000);
+ LED_ERR_state = 1; halifise(); delay(1000);
+
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+
+ heatpump_state = 0; halifise(); delay(1000);
+ hotside_circle_state = 0; halifise(); delay(1000);
+ coldside_circle_state = 0; halifise(); delay(1000);
+ crc_heater_state = 0; halifise(); delay(1000);
+ //reg_heater_state = 0; halifise(); delay(1000);
+
+ //relay6_state = 0; halifise(); delay(1000);
+ //relay7_state = 0; halifise(); delay(1000);
+
+ EEV_apulses = 10; halifise(); delay(1000);
+ EEV_apulses = -10; halifise(); delay(1000);
+ EEV_fast = 0; halifise(); delay(1000);
+ digitalWrite(SerialTxControl, RS485Receive); halifise(); delay(1000);
+ digitalWrite(SerialTxControl, RS485Transmit); halifise(); delay(1000);
+ EEV_manual = 0; halifise(); delay(1000);
+ LSCint = LSCint_error; halifise(); delay(1000);
+ LSCint = LSCint_protective; halifise(); delay(1000);
+
+ LED_OK_state = 0; halifise(); delay(1000);
+ LED_ERR_state = 0; halifise(); delay(1000);
+
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+ #endif
+ #if defined SELFTEST_EEV
+ EEV_apulses = 0;
+ EEV_fast = 0;
+ halifise();
+ delay(1000);
+ //EEV self-test, also can be used for compressor test
+ //vacuuming/charge via low pressure side: leave EEV opened
+ //PrintSS("EEV self-test");
+ EEV_apulses = -(EEV_MAXPULSES + EEV_CLOSE_ADD_PULSES);
+ EEV_adonotcare = 1;
+ EEV_fast = 1;
+ while (EEV_apulses < 0){
+ millis_now = millis();
+ eevise();
+ }
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+ delay(1000);
+ //EEV_apulses = EEV_MAXPULSES;
+ EEV_apulses = 50;
+ EEV_fast = 1;
+ while (EEV_apulses > 0){
+ millis_now = millis();
+ eevise();
+ }
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+ delay(1000);
+ #endif
+ #if defined SELFTEST_T_SENSORS
+ GetTemperatures();
+
+ outString=F("Tbe: "); PrintSS_SaD(Tbe);
+ outString=F("Tae: "); PrintSS_SaD(Tae);
+ outString=F("Tci: "); PrintSS_SaD(Tci);
+ outString=F("Tco: "); PrintSS_SaD(Tco);
+ outString=F("Tbc: "); PrintSS_SaD(Tbc);
+ outString=F("Tac: "); PrintSS_SaD(Tac);
+ outString=F("Thi: "); PrintSS_SaD(Thi);
+ outString=F("Tho: "); PrintSS_SaD(Tho);
+ outString=F("Ts1: "); PrintSS_SaD(Ts1);
+ outString=F("Tcrc: "); PrintSS_SaD(Tcrc);
+ outString=F("Ts2: "); PrintSS_SaD(Ts2);
+ outString=F("Treg: "); PrintSS_SaD(Treg);
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+ delay(1000);
+ #endif
+
+ //---------DEBUG END--------
+
+ }
+ #endif
+
+ //----------------------------- self-test END----------------------------- ----------------------------- -----------------------------
+
+
+ eeprom_magic_read = EEPROM.read(eeprom_addr);
+ eeprom_addr += 1;
+ //EEPROM content: 0x00 - magic, 0x01..0x04 target value
+ if (eeprom_magic_read == eeprom_magic){
+ PrintSSch(IDX_EEtoMEM);
+ } else {
+ PrintSSch(IDX_MEMtoEE);
+ WriteFloatEEPROM(eeprom_addr, T_setpoint);
+ EEPROM.write(0x00, eeprom_magic);
+ }
+ T_setpoint = ReadFloatEEPROM(eeprom_addr);
+ PrintSS_double(T_setpoint);
+ //eeprom_addr += 4;
+
+ T_setpoint_lastsaved = T_setpoint;
+
+ #ifdef WATCHDOG
+ wdt_enable (WDTO_8S);
+ #endif
+
+ GetTemperatures();
+
+ outString.reserve(80);
+ lastStopCauseTxt.reserve(20);
+ lastStartMsgTxt.reserve(20);
+ t_sensorErrString.reserve(12);
+ //PrintSS(String(freeMemory()));
+
+ LED_OK_state = 1;
+
+ _PrintHelp();
+
+ analogWrite(speakerOut, 10);
+ delay (1500);
+ analogWrite(speakerOut, 0);
+ lastStopCauseTxt = F("Start Pause");
+ lastStartMsgTxt = "";
+}
+
+
+void loop(void) {
+
+ digitalWrite(SerialTxControl, RS485Receive);
+ millis_now = millis();
+ halifise();
+ eevise();
+
+ if (((unsigned long)(millis_now - millis_last_printstats) > HUMAN_AUTOINFO) || (millis_last_printstats == 0) ) {
+ PrintStats_SS();
+ millis_last_printstats = millis_now;
+ }
+ //--------------------async fuctions start
+ 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 !!!
+ /*
+ PrintSS("Async impl. results 1: ");
+ PrintSS(String(async_wattage)); // Apparent power
+ PrintSS(String(async_Irms_1)); // Irms
+ PrintSS(" voltage: ");
+ PrintSS(String(supply_voltage));
+ */
+ //----------------------------- self-test END
+
+ }
+ eevise();
+
+ //--------------------async fuctions END
+
+ 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*3)) {
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ LSCint = LSCint_protective;
+ halifise();
+ lastStopCauseTxt = ("P.WtMax:") + String(async_wattage);
+ PrintSS(lastStopCauseTxt);
+ }
+ }
+
+ //-------------------check cycle
+ if( ((unsigned long)(millis_now - millis_prev) > millis_cycle ) || (millis_prev == 0) ) {
+ millis_prev = millis_now;
+ GetTemperatures(); // wdt_reset here due to 85.0'C filtration
+ SaveSetpointEE();
+ pr_low_state_anal = analogRead(PR_LOW); //
+ pr_high_state_anal = analogRead(PR_HIGH); //shotrcut test shows 993-994 for analogRead (10.4ma)
+ if (pr_low_state_anal > 200) {
+ pr_low_state_bool = 1;
+ } else {
+ pr_low_state_bool = 0;
+ }
+ if (pr_high_state_anal > 200) {
+ pr_high_state_bool = 1;
+ } else {
+ pr_high_state_bool = 0;
+ }
+ //--------------------important logic
+ //check T sensors
+ if ( errorcode == ERR_OK ) {
+ if (TbeE == 1 && Tbe == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tbe");}
+ if (TaeE == 1 && Tae == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tae");}
+ if (TciE == 1 && Tci == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tci");}
+ if (TcoE == 1 && Tco == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tco");}
+ if (TbcE == 1 && Tbc == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tbc");}
+ if (TacE == 1 && Tac == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tac");}
+ if (ThiE == 1 && Thi == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Thi");}
+ if (ThoE == 1 && Tho == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tho");}
+ //if (TsgE == 1 && Tsg == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tsg");}
+ //if (TslE == 1 && Tsl == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tsl");}
+ //if (TbvE == 1 && Tbv == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tbv");}
+ //if (TsucE == 1 && Tsuc == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tsuc");}
+ if (Ts1E == 1 && Ts1 == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Ts1");}
+ if (Ts2E == 1 && Ts2 == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Ts2");}
+ if (TcrcE == 1 && Tcrc == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Tcrc");}
+ if (TregE == 1 && Treg == -127 ) {errorcode = ERR_T_SENSOR; outString = F("E.Treg");}
+
+ if (errorcode == ERR_T_SENSOR){
+ //PrintSS(String(outString));
+ t_sensorErrString = String(outString);
+ //printed to console below
+ }
+ }
+
+ //auto-clean sensor error on sensor appears
+ // add 1xor enable here!
+ if ( ( errorcode == ERR_T_SENSOR ) && ( ((TciE == 1 && Tci != -127 ) || (TciE ^1)) &&
+ ((TcoE == 1 && Tco != -127 ) || (TcoE ^1)) &&
+ ((TbeE == 1 && Tbe != -127 ) || (TbeE ^1)) &&
+ ((TaeE == 1 && Tae != -127 ) || (TaeE ^1)) &&
+ //((TsgE == 1 && Tsg != -127 ) || (TsgE ^1)) &&
+ //((TslE == 1 && Tsl != -127 ) || (TslE ^1)) &&
+ //((TbvE == 1 && Tbv != -127 ) || (TbvE ^1)) &&
+ //((TsucE == 1 && Tsuc != -127 ) || (TsucE ^1)) &&
+ ((Ts1E == 1 && Ts1 != -127 ) || (Ts1E ^1)) &&
+ ((Ts2E == 1 && Ts2 != -127 ) || (Ts2E ^1)) &&
+ ((TcrcE == 1 && Tcrc != -127 ) || (TcrcE ^1)) &&
+ ((TregE == 1 && Treg != -127 ) || (TregE ^1)) &&
+ ((TacE == 1 && Tac != -127 ) || (TacE ^1)) &&
+ ((TbcE == 1 && Tbc != -127 ) || (TbcE ^1)) &&
+ ((ThoE == 1 && Tho != -127 ) || (ThoE ^1)) &&
+ ((ThiE == 1 && Thi != -127 ) || (ThiE ^1)) )) {
+ errorcode = ERR_OK;
+ PrintSSch(IDX_OK_ETSENS);
+ sequential_errors = 0;
+ t_sensorErrString = "";
+ }
+
+ //check pressure sensors
+ //auto-clean prev. errors first
+ if ( errorcode == ERR_P_LO ) {
+ if (pr_low_state_bool == 1) {
+ errorcode = ERR_OK;
+ PrintSSch(IDX_OK_PRCOLD);
+ }
+ }
+ if ( errorcode == ERR_P_HI ) {
+ if (pr_high_state_bool == 1) {
+ errorcode = ERR_OK;
+ PrintSSch(IDX_OK_PRHOT);
+ }
+ }
+
+
+ //recheck, if another sensor
+ if ( errorcode == ERR_OK ) {
+ if (pr_low_state_bool == 0) {errorcode = ERR_P_LO;} //for PrintSS scroll down
+ if (pr_high_state_bool == 0) {errorcode = ERR_P_HI;} //for PrintSS scroll down
+ }
+
+ //-------------- EEV cycle
+ /*
+ //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 ){
+ PrintSS("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
+ PrintSS("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
+ PrintSS("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) {
+ T_EEV_dt = Tae.T - Tbe.T;
+ PrintSS("EEV: driving " + String(T_EEV_dt));
+ if (EEV_cur_pos <= 0){
+ PrintSS("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;
+ }
+ } else if (EEV_cur_pos > 0) {
+ if (T_EEV_dt < (T_EEV_setpoint - EEV_EMERG_DIFF) ) { //emerg!
+ PrintSS("EEV: emergency closing!");
+ EEV_apulses = -EEV_EMERG_STEPS;
+ EEV_adonotcare = 0;
+ EEV_fast = 1;
+ } else if (T_EEV_dt < T_EEV_setpoint) { //too
+ PrintSS("EEV: closing");
+ //EEV_apulses = -EEV_NONPRECISE_STEPS;
+ EEV_apulses = -1;
+ EEV_adonotcare = 0;
+ EEV_fast = 0;
+ } else if (T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) { //very
+ PrintSS("EEV: fast opening");
+ //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
+ PrintSS("EEV: opening");
+ EEV_apulses = +1;
+ EEV_adonotcare = 0;
+ EEV_fast = 0;
+ } else if (T_EEV_dt > T_EEV_setpoint) { //ok
+ PrintSS("EEV: OK");
+ //
+ }
+ }
+ off_EEV();
+ }
+
+ }
+ */
+ //v1.2 algo: reopen added
+ #ifndef NO_EEV
+ if ( EEV_manual == 0 && errorcode == 0 && async_wattage >= c_workingOK_wattage_min && EEV_cur_pos > 0 ) {
+ T_EEV_dt = Tae - Tbe;
+ #ifdef EEV_DEBUG
+ PrintSS("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
+ PrintSS(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
+ PrintSS(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
+ PrintSS(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 ( EEV_must_reopen_flag == 1 && (T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS) && ((unsigned long)(millis_now - millis_eev_minworkpos_time) > EEV_REOPENMINTIME) && (millis_eev_last_work < millis_eev_minworkpos_time) ) { //reopen
+ EEV_must_reopen_flag = 0;
+ EEV_apulses = EEV_reopen_pos - EEV_cur_pos;
+ EEV_adonotcare = 0;
+ EEV_fast = 1;
+ #ifdef EEV_DEBUG
+ PrintSS(F("EEV: 14 reopening last"));
+ PrintSS(String(EEV_apulses));
+ PrintSS(String(millis_now));
+ PrintSS(String(millis_eev_minworkpos_time));
+ PrintSS(String(millis_eev_last_work));
+ #endif
+ } else if (T_EEV_dt > T_EEV_setpoint + EEV_HYSTERESIS + EEV_PRECISE_START) { //very
+ #ifdef EEV_DEBUG
+ PrintSS(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
+ PrintSS(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
+ PrintSS(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
+ PrintSS(F("EEV: 7 enforce faster closing!"));
+ #endif
+ //EEV_apulses = -EEV_EMERG_STEPS;
+ EEV_adonotcare = 0;
+ EEV_fast = 1;
+ }
+ }
+ off_EEV();
+ }
+
+ if ( EEV_manual == 0 && 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
+ PrintSS(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
+ EEV_reopen_pos = EEV_cur_pos; //reopen pos. set
+ EEV_must_reopen_flag = 1;
+ millis_eev_last_work = millis_now;
+ #ifdef EEV_DEBUG
+ PrintSS(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_manual == 0 && EEV_apulses == 0 && async_wattage < c_workingOK_wattage_min && EEV_cur_pos < EEV_OPEN_AFTER_CLOSE) {
+ #ifdef EEV_DEBUG
+ PrintSS(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_manual == 0 && EEV_apulses == 0 && async_wattage >= c_workingOK_wattage_min && EEV_cur_pos < EEV_MINWORKPOS) {
+ #ifdef EEV_DEBUG
+ PrintSS(F("EEV: 13 open to work"));
+ #endif
+ if (EEV_MINWORKPOS != 0) {
+ EEV_apulses = EEV_MINWORKPOS - EEV_cur_pos;
+ EEV_adonotcare = 0;
+ EEV_fast = 1;
+ //millis_eev_minworkpos_time = millis_now;
+ }
+ off_EEV();
+ }
+ if (EEV_cur_pos < EEV_MINWORKPOS) { //for reopen
+ millis_eev_minworkpos_time = millis_now;
+ }
+ if ( EEV_manual == 0 && EEV_apulses == 0 && EEV_fast == 1 ) {//just for LED
+ EEV_fast = 0;
+ }
+ if ( ((unsigned long)(millis_now - millis_eev_last_on) > 10000) || millis_eev_last_on == 0 ) {
+ //PrintSS("EEV: ON/OFF");
+ on_EEV();
+ //delay(30);
+ //off_EEV(); //off_EEV called somewhere else takes care of it
+ millis_eev_last_on = millis_now;
+ }
+ //-------------- EEV cycle END
+ #endif
+ #ifndef EEV_ONLY
+ //process heatpump crankcase heater
+ if (TcrcE == 1) {
+ if ( Tcrc < cT_crc_heat_threshold && crc_heater_state == 0 && Tcrc != -127) {
+ crc_heater_state = 1;
+ } else if (Tcrc >= cT_crc_heat_threshold && crc_heater_state == 1) {
+ crc_heater_state = 0;
+ } else if (Tcrc == -127) {
+ crc_heater_state = 0;
+ }
+ halifise();
+ }
+
+ //main logic
+ if (_1st_start_sleeped == 0) {
+ //enable hot WP immidiately
+ if (hotside_circle_state == 0){
+ millis_last_hotWP_off = millis_now;
+ hotside_circle_state = 1;
+ }
+ //_1st_start_sleeped = 1;
+ if ( (millis_now < poweron_pause) && (_1st_start_sleeped == 0) ) {
+ outString = String(((poweron_pause-millis_now))/1000);
+ //PrintSS("Wait: " + outString + " s.");
+ lastStartMsgTxt = "StCntd:" + outString; //start countdown, max 5 numerical places
+ fl_printSS_lastStartMsgTxt = 1;
+ //PrintSS(lastStartMsgTxt);
+ //return;
+ } else {
+ _1st_start_sleeped = 1;
+ lastStopCauseTxt="";
+ lastStartMsgTxt="";
+ }
+ }
+
+ //process_heatpump:
+ //start if
+ // (last_on > N or not_started_yet)
+ // and (no errors)
+ // and (t hot out < t target)
+ // and (t hot out < t hot max)
+ // and (t hot in < t hot max)
+ // and (crc t > min'C)
+ // and (crc 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 && errorcode == ERR_T_SENSOR) {
+ lastStartMsgTxt = t_sensorErrString;
+ //fl_printSS_lastStartMsgTxt = 1;
+ }
+
+ if (heatpump_state == 0 && errorcode == ERR_P_LO ) {
+ lastStartMsgTxt = F("E.PresCold");
+ }
+
+ if (heatpump_state == 0 && errorcode == ERR_P_HI ) {
+ lastStartMsgTxt = F("E.PresHot");
+ }
+
+ if (heatpump_state == 0 && errorcode == ERR_OK && _1st_start_sleeped == 1) {
+ i = 0;
+ #ifdef SETPOINT_THI
+ if ( Thi < T_setpoint ) {i+=1;} else { lastStartMsgTxt = F("#Thi>Setp."); } //or1 //Thi = warm floor heat pump
+ #endif
+ #ifdef SETPOINT_TS1
+ if ( Ts1 < T_setpoint ) {i+=1;} else { lastStartMsgTxt = F("#Ts1>Setp."); } //or1 //Ts1 = tank heater
+ #endif
+ //2 wait cold circe if needed
+ if ( coldside_circle_state == 1 && ((unsigned long)(millis_now - millis_last_coldWP_off) > COLDCIRCLE_PREPARE) ){
+ i+= 1;
+ //only if hot runned and T < setpoint
+ } else if ((coldside_circle_state == 0) && (hotside_circle_state == 1) && ((unsigned long)(millis_now - millis_last_hotWP_off) > HOTCIRCLE_CHECK_PREPARE) ) {
+ #ifdef SETPOINT_THI
+ if ( Thi < T_setpoint ) {
+ #endif
+ #ifdef SETPOINT_TS1
+ if ( Ts1 < T_setpoint ) {
+ #endif
+ lastStartMsgTxt = F("#CPpStart");
+ millis_last_coldWP_off = millis_now;
+ coldside_circle_state = 1;
+ fl_printSS_lastStartMsgTxt = 1;
+ //PrintSS(lastStartMsgTxt);
+ }
+ } else if (coldside_circle_state == 1) {
+ lastStartMsgTxt = "#CPp:" + String( (COLDCIRCLE_PREPARE -(unsigned long)(millis_now - millis_last_coldWP_off))/1000 );
+ }
+ //3 wait hot circe if needed
+ #ifdef SETPOINT_THI
+ if ((hotside_circle_state == 1) && ((unsigned long)(millis_now - millis_last_hotWP_off) > HOTCIRCLE_CHECK_PREPARE) ) {
+ i+=1;
+ } else if (hotside_circle_state == 1) { //waiting for T stabilisation
+ lastStartMsgTxt = "#HotPrp:" + String( (HOTCIRCLE_CHECK_PREPARE -(unsigned long)(millis_now - millis_last_hotWP_off))/1000 );
+ } else if (hotside_circle_state == 0) { //sleeping, hot CP off, waiting for next check cycle
+ lastStartMsgTxt = "#HotSlp:" + String( (HOTCIRCLE_START_EVERY -(unsigned long)(millis_now - millis_last_hotWP_on))/1000 );
+ }
+ #else ifdef SETPOINT_TS1
+ i+=1;
+ #endif
+ //4 countdown, compressor min. cycle
+ if (((unsigned long)(millis_now - millis_last_heatpump_on) > mincycle_poweroff) || (millis_last_heatpump_on == 0) ) {
+ i+=1;
+ } else {
+ if (millis_last_heatpump_on != 0){
+ lastStartMsgTxt = "#HPSlp:" + String( (mincycle_poweroff -(unsigned long)(millis_now - millis_last_heatpump_on))/1000 );
+ }
+ }
+
+ if ( (TcrcE == 1 && Tcrc > cT_crc_min) || (TcrcE^1)) {i+=1;} else { lastStartMsgTxt = F("#CaseCold"); } //5
+ if ( (TaeE == 1 && Tae > cT_coldref_min) || (TaeE^1)) {i+=1;} else { lastStartMsgTxt = F("#Tae cT_coldref_min) || (TbeE^1)) {i+=1;} else { lastStartMsgTxt = F("#Tbe cT_cold_min) || (TciE^1)) {i+=1;} else { lastStartMsgTxt = F("#Tci cT_cold_min) || (TcoE^1)) {i+=1;} else { lastStartMsgTxt = F("#TcoMax"); } //10
+ if ( (ThiE == 1 && Thi < cT_hot_max) || (ThiE^1)) {i+=1;} else { lastStartMsgTxt = F("#Thi>Max"); } //11
+ //t1_crc > t2_cold_in && ???
+ if ( (TcrcE == 1 && Tcrc < cT_crc_max) || (TcrcE^1)) {i+=1;} else { lastStartMsgTxt = F("#CaseHot"); } //12
+ if ( (TbcE == 1 && Tbc < cT_before_condenser_max) || (TbcE^1)) {i+=1;} else { lastStartMsgTxt = F("#Tbc>Max"); } //13
+ //if ( (TregE == 1 && Treg > cT_crc_min) || (TregE^1)) {i+=1;} else { lastStartMsgTxt = F("RegCold"); } //14
+ //if ( (TsucE == 1 && Tsuc > cT_coldref_min) || (TsucE^1)) {i+=1;} else { lastStartMsgTxt = F("Suc N) and (t watertank > target) )
+ #ifdef SETPOINT_THI
+ if ( heatpump_state == 1 && ((unsigned long)(millis_now - millis_last_heatpump_off) > mincycle_poweron) && (Thi > T_setpoint) && errorcode == ERR_OK) {//or Ts1, if tank heater
+ #endif
+ #ifdef SETPOINT_TS1
+ if ( heatpump_state == 1 && ((unsigned long)(millis_now - millis_last_heatpump_off) > mincycle_poweron) && (Ts1 > T_setpoint) && errorcode == ERR_OK) {//or Thi, if default warm floor heat pump
+ #endif
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ LSCint = LSCint_normal;
+ lastStopCauseTxt=F("Normal_stop");
+ fl_printSS_lastStopCauseTxt = 1;
+ //PrintSS(lastStopCauseTxt);
+ }
+
+ //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) ) || ((_1st_start_sleeped == 0 ) && (hotside_circle_state == 0)) ){
+ PrintSSch(IDX_HWPON);
+ millis_last_hotWP_off = millis_now;
+ hotside_circle_state = 1;
+ }
+ #ifdef SETPOINT_THI
+ if ( (heatpump_state == 0) && (hotside_circle_state == 0) && ((unsigned long)(millis_now - millis_last_hotWP_on) > HOTCIRCLE_START_EVERY) ) { //process START_EVERY for hot side
+ millis_last_hotWP_off = millis_now;
+ hotside_circle_state = 1;
+ //PrintSS(F("HWP ON by startevery"));
+ lastStartMsgTxt = F("HWP_ON_by_ev");
+ fl_printSS_lastStartMsgTxt = 1;
+ }
+ #endif
+
+ if ( (heatpump_state == 0) && (hotside_circle_state == 1) ) {
+ if ( ( (unsigned long)(millis_now - millis_last_heatpump_on) > deffered_stop_hotcircle) || millis_last_heatpump_on == 0) { //deffered stop aftret heat pump stop and correct processing of 1st start, 1st_start sleeped flag not used - there's another logic
+ /*
+ //useful for tank heater with Ts1 as setpont control and large intermediate water reservoir
+ if ( (ThoE == 1 && Tho < (Ts1 + cT_hotcircle_delta_min)) ||
+ (ThiE == 1 && Thi < (Ts1 + cT_hotcircle_delta_min)) ) {
+ PrintSS(F("Hot CP OFF 1"));
+ millis_last_hotWP_on = millis_now;
+ hotside_circle_state = 0;
+ } else {
+ PrintSS(F("Hot CP OFF 2"));
+ millis_last_hotWP_on = millis_now;
+ hotside_circle_state = 0;
+ }
+ */
+ if ( (unsigned long)(millis_now - millis_last_hotWP_off) > HOTCIRCLE_STOP_AFTER) { //and START_EVERY processing
+ #ifdef SETPOINT_THI
+ if ( Thi > T_setpoint ) {
+ #endif
+ #ifdef SETPOINT_TS1
+ if ( Ts1 > T_setpoint ) {
+ #endif
+ //PrintSS(F("HWP OFF"));
+ lastStartMsgTxt = F("HWP_OFF");
+ fl_printSS_lastStartMsgTxt = 1;
+ millis_last_hotWP_on = millis_now;
+ hotside_circle_state = 0;
+ }
+ }
+ }
+ }
+
+ //heat if we can, just in case, ex. if lost power, usefull for tank heater with large intermediate water reservoir
+ /*
+ if ( (hotside_circle_state == 0) &&
+ ( ThoE == 1 && Tho > (Ts1 + cT_hotcircle_delta_min) ) ||
+ ( ThiE == 1 && Thi > (Ts1 + cT_hotcircle_delta_min) ) ) {
+ PrintSS(F("Hot WP ON"));
+ hotside_circle_state = 1;
+ }
+ */
+
+ //process_cold_side_pump:
+ //start if (heatpump_enabled)
+ //stop if (heatpump_disbled)
+ //start if tci < cold_min
+ if ( (heatpump_state == 1) && (coldside_circle_state == 0) ) {
+ //PrintSS(F("CWP_ON"));
+ millis_last_coldWP_off = millis_now;
+ coldside_circle_state = 1;
+ }
+
+ if ( (heatpump_state == 0) && (TciE == 1) && (Tci > -127.0) && (Tci < cT_cold_min) && (coldside_circle_state == 0) ) {
+ //PrintSS(F("CWP ON by ColdMin"));
+ lastStartMsgTxt = F("CWP_ON_CoMin");
+ fl_printSS_lastStartMsgTxt = 1;
+ millis_last_coldWP_off = millis_now;
+ coldside_circle_state = 1;
+ }
+
+ if ( (heatpump_state == 0) && (coldside_circle_state == 1) ) { //is on
+ if ( (TciE == 1 && Tci > cT_cold_min) || (TciE^1)) { //does not overfrozen
+ //next: deal with unstable env. to prevent false starts (water tank with dynamic flows, maybe air heating): stop CWP while waiting period if false start
+ //stop if T>S OR if not needed by prepare
+ #ifdef SETPOINT_THI
+ if ( ( Thi > T_setpoint ) || ((unsigned long)(millis_now - millis_last_coldWP_off) > (COLDCIRCLE_PREPARE*2)) ) {
+ #endif
+ #ifdef SETPOINT_TS1
+ if ( ( Ts1 > T_setpoint ) || ((unsigned long)(millis_now - millis_last_coldWP_off) > (COLDCIRCLE_PREPARE*2)) ) {
+ #endif
+ //PrintSS(F("CWP_OFF"));
+ coldside_circle_state = 0;
+ }
+ }
+ }
+
+ //protective_cycle:
+ //stop if
+ // (error)
+ // (t hot out > hot max)
+ // (t hot in > hot max)
+ // (crc 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 == ERR_OK ){
+ if (ThoE == 1 && Tho > cT_hot_max) {heatpump_state = 0; lastStopCauseTxt = F("P.Tho"); }
+ if (ThiE == 1 && Thi > cT_hot_max) {heatpump_state = 0; lastStopCauseTxt = F("P.Thi"); }
+ if (TcrcE == 1 && Tcrc > cT_crc_max) {heatpump_state = 0; lastStopCauseTxt = F("P.Tcrc"); }
+ if (TaeE == 1 && Tae < cT_coldref_min) {heatpump_state = 0; lastStopCauseTxt = F("P.Tae"); }
+ if (TbeE == 1 && Tbe < cT_before_evap_work_min) {heatpump_state = 0; lastStopCauseTxt = F("P.Tbe"); }
+ //if (TsucE == 1 && Tsuc < cT_coldref_min) {heatpump_state = 0; lastStopCauseTxt = F("P.Tsuc"); }
+ if (TbcE == 1 && Tbc > cT_before_condenser_max) {heatpump_state = 0; lastStopCauseTxt = F("P.Tbc"); }
+ if (TciE == 1 && Tci < cT_cold_min) {heatpump_state = 0; lastStopCauseTxt = F("P.Tci"); }
+ if (TcoE == 1 && Tco < cT_cold_min) {heatpump_state = 0; lastStopCauseTxt = F("P.Tco"); }
+ if (heatpump_state == 0){
+ LSCint = LSCint_protective;
+ fl_printSS_lastStopCauseTxt = 1;
+ //PrintSS(lastStopCauseTxt);
+ millis_last_heatpump_on = millis_now;
+ }
+ }
+
+ //5 minutes workout checks
+ //alive_check_cycle_after_5_mins:
+ //(old)error if
+ //(new)not error, just poweroff all
+ //next disabled: issues after a deep freeze, long time needed for stabilisation
+ //DISABLED// or (t cold in - t cold out < t workingok min diff)
+ //DISABLED// or (t hot out - t hot in < t workingok min diff)
+ // or (crc 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 ) ) {
+ // 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 ) && ( TcrcE == 1 && Tcrc < cT_workingOK_crc_min ) ) {
+ //errorcode = ERR_HEATPUMP;
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ LSCint = LSCint_protective;
+ lastStopCauseTxt = F("P.W.TcrcMIN");
+ fl_printSS_lastStopCauseTxt = 1;
+ //PrintSS(lastStopCauseTxt);
+ }
+ if ( ( errorcode == ERR_OK ) && ( async_wattage < c_workingOK_wattage_min ) ) {
+ //errorcode = ERR_WATTAGE;
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ LSCint = LSCint_protective;
+ lastStopCauseTxt = F("P.W.wattMIN");
+ fl_printSS_lastStopCauseTxt = 1;
+ //PrintSS(lastStopCauseTxt);
+ }
+ //digitalWrite(RELAY_HEATPUMP, heatpump_state); ////!!! old, now halifised
+ }
+
+
+ //disable pump by t.sensor error, sequentially
+ if ( heatpump_state == 1 && errorcode == ERR_T_SENSOR ) {
+ sequential_errors += 1;
+ if (sequential_errors > MAX_SEQUENTIAL_ERRORS) {
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ LSCint = LSCint_error;
+ lastStopCauseTxt = t_sensorErrString;
+ fl_printSS_lastStopCauseTxt = 1;
+ }
+ //PrintSS(t_sensorErrString);
+ }
+
+ if ( errorcode == ERR_OK ) { //auto-clean counter just in case
+ sequential_errors = 0;
+ }
+
+ //disable pump by pressure error, immediately
+ if ( heatpump_state == 1 && ( errorcode == ERR_P_HI || errorcode == ERR_P_LO ) ) {
+ millis_last_heatpump_on = millis_now;
+ heatpump_state = 0;
+ if (errorcode == ERR_P_HI) {
+ lastStopCauseTxt = F("E.PressHot");
+ } else if (errorcode == ERR_P_LO) {
+ lastStopCauseTxt = F("E.PressCold");
+ }
+ LSCint = LSCint_error;
+ fl_printSS_lastStopCauseTxt = 1;
+ //PrintSS(lastStopCauseTxt);
+ }
+
+ //!!! self-test
+ ///heatpump_state = 1;
+
+ halifise();
+
+ if (errorcode == ERR_T_SENSOR) {
+ PrintSS(t_sensorErrString);
+ }
+
+ if (fl_printSS_lastStartMsgTxt == 1){
+ PrintSS(lastStartMsgTxt);
+ fl_printSS_lastStartMsgTxt = 0;
+ }
+
+ if (fl_printSS_lastStopCauseTxt == 1){
+ PrintSS(lastStopCauseTxt);
+ fl_printSS_lastStopCauseTxt = 0;
+ }
+ #endif
+
+ //process errors
+ //beep N times error
+ if ( errorcode != ERR_OK ) {
+ LED_OK_state = 0;
+ LED_ERR_state = 1;
+ if ( ((unsigned long)(millis_now - millis_notification) > millis_notification_interval) || millis_notification == 0 ) {
+ millis_notification = millis_now;
+ outString = F("Err: ");
+ PrintSS_SaI(errorcode);
+ for ( i = 0; i < errorcode; i++) {
+ LED_ERR_state = 0;
+ halifise();
+ analogWrite(speakerOut, 10); delay (500);
+ LED_ERR_state = 1;
+ halifise();
+ analogWrite(speakerOut, 0); delay (500);
+ }
+ }
+ } else {
+ LED_OK_state = 1;
+ LED_ERR_state = 0;
+ halifise();
+ }
+ }
+
+ if (Serial.available() > 0) {
+ inChar = Serial.read();
+ if ( inChar == 0x1B ) {
+ skipchars_local += 3;
+ inChar = 0x00;
+ millis_escinput_local = millis();
+ }
+ if ( skipchars_local != 0 ) {
+ millis_charinput_local = millis();
+ if ((unsigned long)(millis_charinput_local - millis_escinput_local) < 16*2 ) { //2 chars for 2400
+ if (inChar != 0x7e) {
+ skipchars_local -= 1;
+ }
+ if (inChar == 0x7e) {
+ skipchars_local = 0;
+ }
+ if (inChar >= 0x30 && inChar <= 0x35) {
+ skipchars_local += 1;
+ }
+ inChar = 0x00;
+ } else {
+ skipchars_local = 0;
+ }
+ }
+ _ProcessInChar();
+ }
+
+ if (RS485Serial.available() > 0) {
+ //PrintSS("some on 485.."); //!!!debug
+ #ifdef RS485_HUMAN
+ if (RS485Serial.available()) {
+ inChar = RS485Serial.read();
+ //RS485Serial.print(inChar); //!!!debug
+ if ( inChar == 0x1B ) {
+ skipchars_485 += 3;
+ inChar = 0x00;
+ millis_escinput_485 = millis();
+ }
+ if ( skipchars_485 != 0 ) {
+ millis_charinput_485 = millis();
+ //if (millis_escinput_485 + 2 > millis_charinput_485)
+ if ((unsigned long)(millis_charinput_485 - millis_escinput_485) < 16*2 ) { //2 chars for 2400
+ if (inChar != 0x7e) {
+ skipchars_485 -= 1;
+ }
+ if (inChar == 0x7e) {
+ skipchars_485 = 0;
+ }
+ if (inChar >= 0x30 && inChar <= 0x35) {
+ skipchars_485 += 1;
+ }
+ inChar = 0x00;
+ } else {
+ skipchars_485 = 0;
+ }
+ }
+ _ProcessInChar();
+ }
+ #endif
+
+ #ifdef RS485_JSON
+ 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
+ dataBuf[index] = inChar; // Store it
+ index++; // Increment where to write next
+ dataBuf[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
+ /*
+ if (dataBuf[0] != 0x00) {
+ PrintSS("-");
+ PrintSS(dataBuf);
+ PrintSS("-");
+ }
+ */
+ //or this debug
+ /*
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(10);
+ RS485Serial.println(dataBuf);
+ RS485Serial.flush();
+ RS485Serial.println(index);
+ */
+
+ //ALL lines must be terminated with \n!
+ if ( (dataBuf[0] == hostID) && (dataBuf[1] == devID) ) {
+ // COMMANDS:
+ // G (0x47): (G)et main data
+ // TNN.NN (0x54): set aim (T)emperature
+ // ENN.NN (0x45): set (E)EV difference aim
+ digitalWrite(SerialTxControl, RS485Transmit);
+ halifise();
+ delay(1);
+ //PrintSS(freeMemory());
+ outString = "";
+ outString = devID;
+ outString += hostID;
+ outString += "A "; //where A is Answer, space after header
+ char *outChar=&outString[0];
+ if ( (dataBuf[2] == 0x47 ) ) {
+ //PrintSS("G");
+ //WARNING: this procedure can cause "NO answer" effect if no or few T sensors connected
+
+ //outString = "";
+ //if (TsgE) { outString += ",\"TSG\":" + String(Tsg); }
+ //if (TslE) { outString += ",\"TSL\":" + String(Tsl); }
+ //if (TbvE) { outString += ",\"TBV\":" + String(Tbv); }
+ //if (TsucE) { outString += ",\"TSUC\":" + String(Tsuc);}
+ //RS485Serial.write(outChar); //dirty hack to transfer long string
+ //RS485Serial.flush();
+ //delay (1); //lot of errors without delay
+ outString += "{";
+ outString += "\"E1\":" + String(errorcode);
+ if (TciE) { outString += ",\"TCI\":"; ApToOut_D(Tci); }
+ if (TcoE) { outString += ",\"TCO\":"; ApToOut_D(Tco); }
+ if (TbeE) { outString += ",\"TBE\":"; ApToOut_D(Tbe); }
+ if (TaeE) { outString += ",\"TAE\":"; ApToOut_D(Tae); }
+ if (Ts1E) { outString += ",\"TS1\":"; ApToOut_D(Ts1); }
+ if (Ts2E) { outString += ",\"TS2\":"; ApToOut_D(Ts2); }
+ if (TcrcE) { outString += ",\"TCRC\":"; ApToOut_D(Tcrc);}
+ if (TregE) { outString += ",\"TR\":"; ApToOut_D(Treg);}
+ RS485Serial.write(outChar); //dirty hack to transfer long string
+ RS485Serial.flush();
+ delay (1); //lot of errors without delay
+
+ outString = "";
+ if (TacE) { outString += ",\"TAC\":"; ApToOut_D(Tac); }
+ if (TbcE) { outString += ",\"TBC\":"; ApToOut_D(Tbc); }
+ if (ThoE) { outString += ",\"THO\":"; ApToOut_D(Tho); }
+ if (ThiE) { outString += ",\"THI\":"; ApToOut_D(Thi);}
+ outString += ",\"W1\":"; ApToOut_D(async_wattage);
+ outString += ",\"EEVP\":" + String(EEV_cur_pos);
+ outString += ",\"EEVA\":"; ApToOut_D(T_EEV_setpoint);
+
+ #ifndef EEV_ONLY
+ outString += ",\"A1\":"; ApToOut_D(T_setpoint); //(A)im (target)
+ outString += ",\"RP\":" + String(heatpump_state*RELAY_HEATPUMP);
+ outString += ",\"RH\":" + String(hotside_circle_state*RELAY_HOTSIDE_CIRCLE);
+ outString += ",\"RC\":" + String(coldside_circle_state*1);
+ outString += ",\"RCRCH\":" + String(crc_heater_state*3);
+ //if (TregE) { outString += ",\"RRH\":" + String(reg_heater_state*4);}
+ //RS485Serial.write(outChar); //dirty hack to transfer long string
+ //RS485Serial.flush();
+ //delay (1); //lot of errors without delay
+ #endif
+ RS485Serial.write(outChar); //dirty hack to transfer long string
+ RS485Serial.flush();
+ delay (1); //lot of errors without delay
+
+ outString = "";
+ outString = ",\"LSC\":\"";
+ outString += lastStopCauseTxt;
+ outString += ("\"");
+ //RS485Serial.write(outChar); //dirty hack to transfer long string
+ //RS485Serial.flush();
+ //delay (1); //lot of errors without delay
+ outString += ",\"LSM\":\"";
+ outString += lastStartMsgTxt;
+ outString += ("\"");
+ outString += "}";
+
+ } else if ( (dataBuf[2] == 0x54 ) || (dataBuf[2] == 0x45 )) { //(T)arget or (E)EV target format NN.NN, text
+ if ( isDigit(dataBuf[ 3 ]) && isDigit(dataBuf[ 4 ]) && (dataBuf[ 5 ] == 0x2e) && isDigit(dataBuf[ 6 ]) && isDigit(dataBuf[ 7 ]) && ( ! isDigit(dataBuf[ 8 ])) ) {
+
+ analogWrite(speakerOut, 10);
+ delay (100);
+ analogWrite(speakerOut, 0);
+
+ char * carray = &dataBuf[ 3 ];
+ tempdouble = atof(carray);
+ if (dataBuf[2] == 0x54 ){
+ if (tempdouble > cT_setpoint_max) {
+ outString += "{\"r\":\"too hot!\"}";
+ } else if (tempdouble < cT_setpoint_min) {
+ outString += "{\"r\":\"too cold!\"}";
+ } else {
+ T_setpoint = tempdouble;
+ _HotWPon_by_Setpoint_update();
+ outString += "{\"r\":\"ok, new value: ";
+ ApToOut_D(T_setpoint);
+ outString += "\"}";
+ }
+ }
+ if (dataBuf[2] == 0x45 ) {
+ if (tempdouble > 10.0) { //!!!!!!! hardcode !!!
+ outString += "{\"r\":\"too hot!\"}";
+ } else if (tempdouble < 0.1) { //!!!!!!! hardcode !!!
+ outString += "{\"r\":\"too cold!\"}";
+ } else {
+ T_EEV_setpoint = tempdouble;
+ outString += "{\"r\":\"ok, new EEV value: ";
+ ApToOut_D(T_EEV_setpoint);
+ outString += "\"}";
+ }
+ }
+ } else {
+ outString += "{\"r\":\"NaN, format: NN.NN\"}";
+ }
+ } else {
+ //default, just for example
+ outString += "{\"r\":\"no_command\"}";
+ }
+ //crc.integer = CRC16.xmodem((uint8_t& *) outString, outString.length());
+ //outString += (crc, HEX);
+ outString += "\n";
+ RS485Serial.write(outChar);
+ }
+
+ index = 0;
+ for (i=0;i < (BUFSIZE);i++) { //clear buffer
+ dataBuf[i]=0;
+ }
+ RS485Serial.flush();
+ digitalWrite(SerialTxControl, RS485Receive);
+ delay(1);
+ #endif
+
+ #ifdef RS485_MODBUS
+ index = 0;
+ z = 0; //error flag
+ while ( 1 == 1 ) {//9600
+ //read
+ //!!!!!!!
+ //Serial.println("-");
+ if (RS485Serial.available()) {
+ if(index < BUFSIZE) {
+ inChar = RS485Serial.read();
+ //Serial.print(inChar, HEX);
+ //Serial.print(" ");
+ dataBuf[index] = inChar;
+ index++;
+ dataBuf[index] = '\0';
+ delayMicroseconds(80); //yep, 80, HERE
+ } else {
+ z = 1;
+ while (RS485Serial.available()) {
+ inChar = RS485Serial.read();
+ delayMicroseconds(1800);
+ }
+ break;
+ }
+ } else {
+ //Serial.print(".");
+ tmic1 = micros();
+ for (i = 0; i < 10; i++) {
+ delayMicroseconds(180);
+ if (RS485Serial.available()){
+ //Serial.print("babaika");
+ //Serial.println(i);
+ tmic2 = micros();
+ break;
+ }
+ tmic2 = micros();
+ if ( (unsigned long)(tmic2 - tmic1) > 1800 ){
+ i = 10;
+ break;
+ }
+ }
+ if (i == 10 && RS485Serial.available()) {
+ z = 2;
+ i = 0;
+ while (RS485Serial.available()) {
+ if (i > 200){
+ break;
+ }
+ inChar = RS485Serial.read();
+ delayMicroseconds(1800);
+ i++;
+ }
+ break;
+ } else if (!RS485Serial.available()) {
+ break;
+ } else if (RS485Serial.available()) {
+ continue;
+ } else {
+ //PrintSS(F("e2245"));
+ }
+ }
+ }
+
+
+ //check CRC
+ if (index < 3) {
+ z+= 10;
+ }
+ if ( dataBuf[1] == 0x03 && ( (index % 8 ) == 0) && index > 8 ) { //automatic "duplicated message" detector, can be found if lot of T sensors absent and requests are too fast
+ index = 8;
+ }
+
+ crc16 = SEED;
+ for (x = 0; x < (index-2); x++) {
+ Calc_CRC(dataBuf[x]);
+ }
+ x = dataBuf[index - 2];
+ y = dataBuf[index - 1];
+ if (( x != (crc16 & 0xFF )) || ( y != (crc16 >> 8))) {
+ z += 100;
+ }
+ //PrintSS(F("-----"));
+ if ( z != 0 ) {
+ //probably another proto
+ //PrintSS(F("MmsgERR: "));
+ /*Serial.println(z);
+ for (x =0; x MODBUS_MR) { //0x03
+ z = 3;
+ }
+ if (dataBuf[1] == 0x03 && dataBuf[5] > MODBUS_MR) { //0x05
+ z = 5;
+ }
+
+ i = 0;
+ //dataBuf[i] = devID;
+ //unchanged! can be devID or 0x00
+ i++;
+ if (z == 0) {
+ //PrintSS(F("ModParse"));
+ x = dataBuf[3]; //addr
+ y = dataBuf[5]; //num
+ if (dataBuf[1] == 0x03) {
+ //PrintSS(F("F03"));
+ dataBuf[i] = 0x03;
+ i++;
+ //the most significant byte is sent first
+ dataBuf[i] = y*2;
+ i++; // data
+ for (u = x; u < (x+y); u++) {
+ if (u > MODBUS_MR){
+ z = 2;
+ break;
+ }
+ switch (u) {
+ case 0x00:
+ Add_Double_To_Buf_IntFract(Tci); //uses dataBuf, i
+ break;
+ case 0x01:
+ Add_Double_To_Buf_IntFract(Tco); //uses dataBuf, i
+ break;
+ case 0x02:
+ Add_Double_To_Buf_IntFract(Tbe); //uses dataBuf, i
+ break;
+ case 0x03:
+ Add_Double_To_Buf_IntFract(Tae); //uses dataBuf, i
+ break;
+ case 0x04:
+ //Add_Double_To_Buf_IntFract(Tsg); //uses dataBuf, i
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = 0;
+ i++;
+ break;
+ case 0x05:
+ //Add_Double_To_Buf_IntFract(Tsl); //uses dataBuf, i
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = 0;
+ i++;
+ break;
+ case 0x06:
+ //Add_Double_To_Buf_IntFract(Tbv); //uses dataBuf, i
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = 0;
+ i++;
+ break;
+ case 0x07:
+ //Add_Double_To_Buf_IntFract(Tsuc); //uses dataBuf, i
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = 0;
+ i++;
+ break;
+ case 0x08:
+ Add_Double_To_Buf_IntFract(Ts1); //uses dataBuf, i
+ break;
+ case 0x09:
+ Add_Double_To_Buf_IntFract(Ts2); //uses dataBuf, i
+ break;
+ case 0x0A:
+ Add_Double_To_Buf_IntFract(Tcrc); //uses dataBuf, i
+ break;
+ case 0x0B:
+ Add_Double_To_Buf_IntFract(Treg); //uses dataBuf, i
+ break;
+ case 0x0C:
+ Add_Double_To_Buf_IntFract(Tac); //uses dataBuf, i
+ break;
+ case 0x0D:
+ Add_Double_To_Buf_IntFract(Tbc); //uses dataBuf, i
+ break;
+ case 0x0E:
+ Add_Double_To_Buf_IntFract(Tho); //uses dataBuf, i
+ break;
+ case 0x0F:
+ Add_Double_To_Buf_IntFract(Thi); //uses dataBuf, i
+ break;
+ case 0x10:
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = errorcode;
+ i++;
+ break;
+ case 0x11:
+ dataBuf[i] = (int)async_wattage >> 8;
+ i++;
+ dataBuf[i] = (int)async_wattage & 0xFF;
+ i++;
+ break;
+ case 0x12:
+ dataBuf[i] = 0;
+ i++;
+ dataBuf[i] = 0;
+ bitWrite(dataBuf[i], 0, heatpump_state);
+ bitWrite(dataBuf[i], 1, hotside_circle_state);
+ bitWrite(dataBuf[i], 2, coldside_circle_state);
+ bitWrite(dataBuf[i], 3, crc_heater_state);
+ //bitWrite(dataBuf[i], 4, reg_heater_state);
+ i++;
+ break;
+ case 0x13:
+ Add_Double_To_Buf_IntFract(T_EEV_setpoint); //uses dataBuf, i
+ break;
+ case 0x14:
+ Add_Double_To_Buf_IntFract(T_setpoint); //uses dataBuf, i
+ break;
+ case 0x15:
+ dataBuf[i] = (int)EEV_cur_pos >> 8;
+ i++;
+ dataBuf[i] = (int)EEV_cur_pos & 0xFF;
+ i++;
+ break;
+ case 0x16:
+ dataBuf[i] = lastStopCauseTxt.charAt(0);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(1);
+ i++;
+ break;
+ case 0x17:
+ dataBuf[i] = lastStopCauseTxt.charAt(2);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(3);
+ i++;
+ break;
+ case 0x18:
+ dataBuf[i] = lastStopCauseTxt.charAt(4);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(5);
+ i++;
+ break;
+ case 0x19:
+ dataBuf[i] = lastStopCauseTxt.charAt(6);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(7);
+ i++;
+ break;
+ case 0x1A:
+ dataBuf[i] = lastStopCauseTxt.charAt(8);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(9);
+ i++;
+ break;
+ case 0x1B:
+ dataBuf[i] = lastStopCauseTxt.charAt(10);
+ i++;
+ dataBuf[i] = lastStopCauseTxt.charAt(11);
+ i++;
+ break;
+ case 0x1C:
+ dataBuf[i] = lastStartMsgTxt.charAt(0);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(1);
+ i++;
+ break;
+ case 0x1D:
+ dataBuf[i] = lastStartMsgTxt.charAt(2);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(3);
+ i++;
+ break;
+ case 0x1E:
+ dataBuf[i] = lastStartMsgTxt.charAt(4);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(5);
+ i++;
+ break;
+ case 0x1F:
+ dataBuf[i] = lastStartMsgTxt.charAt(6);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(7);
+ i++;
+ break;
+ case 0x20:
+ dataBuf[i] = lastStartMsgTxt.charAt(8);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(9);
+ i++;
+ break;
+ case 0x21:
+ dataBuf[i] = lastStartMsgTxt.charAt(10);
+ i++;
+ dataBuf[i] = lastStartMsgTxt.charAt(11);
+ i++;
+ break;
+ default:
+ dataBuf[i] = 0x00;
+ i++;
+ dataBuf[i] = 0x00;
+ i++;
+ break;
+ }
+ }
+ } else if (dataBuf[1] == 0x06) { //de-facto echo
+ //PrintSS(F("F06"));
+ dataBuf[i] = 0x06;
+ i++;
+ dataBuf[i] = 0x00;
+ i++;
+ dataBuf[i] = x;
+ i++;
+
+ switch (x) {
+ case 0x13:
+ //PrintSS(F("06F_EEV_setpoint"));
+ IntFract_to_tempdouble(dataBuf[4], dataBuf[5]);
+ //Serial.println(tempdouble);
+ if (tempdouble > 15.0 || tempdouble < -15.0) { //incorrectest values filter
+ z = 3;
+ break;
+ }
+ T_EEV_setpoint = tempdouble;
+ //Serial.println(T_EEV_setpoint);
+ Add_Double_To_Buf_IntFract(T_EEV_setpoint); //uses dataBuf, i
+ break;
+ case 0x14:
+ //PrintSS(F("06F_T_setpoint"));
+ IntFract_to_tempdouble(dataBuf[4], dataBuf[5]);
+ //Serial.println(tempdouble);
+ if (tempdouble > cT_setpoint_max || tempdouble < cT_setpoint_min) { //incorrectest values filter
+ z = 3;
+ break;
+ }
+ T_setpoint = tempdouble;
+ _HotWPon_by_Setpoint_update();
+ //Serial.println(T_setpoint);
+ Add_Double_To_Buf_IntFract(T_setpoint); //uses dataBuf, i
+ break;
+ //case 0x15:
+ // //EEV_cur_pos
+ // break;
+ default:
+ z = 3;
+ break;
+ }
+ } else {
+ PrintSSch(IDX_UNKNF);
+ z = 1;
+ }
+ if (z != 0) {
+ i = 1;
+ bitWrite(dataBuf[i], 7, 1);
+ i++;
+ dataBuf[i] = z;
+ i++;
+ }
+
+ crc16 = SEED;
+ for (x = 0; x < (i); x++) {
+ Calc_CRC(dataBuf[x]);
+ }
+ dataBuf[i] = crc16 & 0xFF;
+ i++;
+ dataBuf[i] = crc16 >> 8;
+ i++;
+
+ RS485Serial.write(dataBuf, i);
+ RS485Serial.flush();
+ delay (1);
+
+ //!!! debug
+ /*
+ for (x = 0; x