09-07-14, 03:32 AM | #21 | |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Quote:
It achieves COP 2 so according to my electric meter it will have paid for itself vs resistance heating in the next month or so. Can't find the Chinese site now, but I did see an identical heat pump made in China with the same model number that claimed -15C operation. As with all Chinese ratings that's probably sales jargon. I've not checked refrigerant charge, I have no kit or experience in doing so. As it works to an almost acceptable efficiency I decided not to mess. The GSHP won't be operational until this time next year if all goes to plan, more importantly I now have the stairwell opening cut into the uninsulated and untiled loft letting all my heat out the top of the house. Steve |
|
09-07-14, 06:58 AM | #22 |
Master EcoRenovator
Join Date: Aug 2012
Location: Toronto
Posts: 958
Thanks: 40
Thanked 158 Times in 150 Posts
|
Hahaha, my fridgie friends in the UK just groan and roll their eyes when asked to come out to fix a unit like that. No way to get parts and no often 2 identical units have completely different components or are mismatched.
It is only Sept and that unit should not be freezing up the evaporator. Rather than running the heating cable all the time, why not just cut a way bigger hole in bottom, if you can? |
09-07-14, 09:04 AM | #23 | |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Quote:
Not worth having it looked at as I can,t imagine the efficiency improving enough to cover costs. I disconnected the trace heater back in march( it does have a thermostat but seemed to be running all the time regardless), no icing issues this time of year. I could easily cut a larger hole in the base but fear it would reduce airflow through the evaporator.The machine works by blowing air out the back, the negative internal pressure is what draws air tyhrtough the evaporator. When winter arrives I,ll reconnect the trace heater, other than that it,s not worth spending any more time or money on it. Steve |
|
09-07-14, 02:00 PM | #24 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Mikesolar
When i think about it the negative internal pressure stops the condensate draining, when i watched defrost cycles there would be the odd drip out the bottom then a torrent as it went into defrost and the fan stopped. Rear of the heatpump showing the fan. Steve |
09-07-14, 02:35 PM | #25 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
To get round the issue of wasting heat from the hot water tank i had to abandon my initial control strategy of switching to hot water as soon as the buffer reached temp.
The Arduino mega already had a RTC (real time clock) attached, i was using it to timestamp the data logs. I used the RTC to switch over from heating to hot water for 4 hours a day. 1H early morning to make sure there was water for a shower 2H from midday, air temp should be highest to help efficiency 1H in the evening to top up in case a bath is desired This gave me the issue of how to stop the heatpump when the buffer was at temp and no more heat is required. I used the circuit below to convince the heatpump it had achieved 60C. On the left is the original wiring to the heatpumps internal water temp thermistor, to the right is what i changed it to. From memory the potentiometer is 10K, adjust until the heatpump controller displays 60C. The changeover relay is driven by the Arduino when in heating mode and the buffer has reached temp. Steve |
09-07-14, 03:06 PM | #26 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
The hack to separate the heating and hot water modes created another unexpected issue.
When the heatpumps internal thermistor reads high(not sure of the exact temp but 50C+ sounds right) it no longer turns on the circulation pump every 15 mins to check the water temp. I realised this had 2 purposes, to check the water temp in the house/cylinder but also to prevent the heatpumps heat exchanger from freezing! The water that runs through the heatpump is just water, not antifreeze or such. Below graph shows original mode of operation in first half and revised (dangerous) operation in second half. (Looking at HP_LPM, this is water flow through the heatpump) Cue another software change to pulse the changover relay for a couple of seconds every 15mins if in heating mode, buffer is at temp and outside temp is 5C or lower. Steve |
09-07-14, 03:34 PM | #27 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Almost done on the heatpump (for now).
At this point i had no idea how much heat the heatpump was producing or how efficient it is. I had a KW/h meter feeding it and a current transformer monitoring instantaneous consumption but without knowing the output i could not calculate a COP or see how much heat the house was loosing. This is one of the reasons i had fitted a flow meter instead of a flow switch, the plan was to measure the flow and return temps and the flow rate and calculate the heat output. After several failed attempts with thermistors, trying different code and calibration methods i gave up and ordered some DB18B20's. As the temperature difference is so small a tiny discrepancy in temp reading ruined any chance of working out the output power. I had already used DS18B20's for the water cylinder and buffer temps so added 2 more for the flow and return temps. To calculate power out i use: HpWattsOut = (((HpFlow - HpRet) * 4184 * HpLPM) / 60); HPFlow and HpRet are the 2 DS18B20's, HpLPM is the water flow rate in litres/m At 15L/m a 1C temp difference is around 1KW Steve |
09-07-14, 04:00 PM | #28 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Last post about heatpumps.
As i was/am relatively new to C and Arduino i had absolutely no confidence in my hashed together controller working consistently. All the relays were in a single box so i added override switches so i could run the system in manual if needed. Flow switch override links the flow switch input to the heatpump so i can run without the flow meter. This has been a consistent headache, some days it works fine others it seems to jam and read nothing. Circ pump is the circulation pump from the buffer to and round the underfloor heating, whilst i have this connected to an output on the Arduino i never got round to writing and code to drive it. This acts as heating on/off for us. Water boost and heating boost are for the 2 immersion heaters, apart from trying them to make sure they work, these have not been used. Enable valves is the feed for the 2 motorised valves, by switching this off i can use the override lever on each valve to force the system into heating or hot water. Steve |
09-07-14, 04:08 PM | #29 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
Arduino code
This is poorly written and barely documented. It requires many libraries and even then will not compile on your PC as i had to install a mod to the arduino ide to make it do some conversions i couldn't find any other way to do. When i wrote this a had very little experience with arduino or C (not much better now). The code contains pages of redundant code from failed attempts to make the system do things and many features i have not discussed here. Code:
#include <EmonLib.h> #include <EasyScheduler.h> #include <SD.h> #include <OneWire.h> #include <DallasTemperature.h> #include <LiquidCrystal.h> #include <DS1307RTC.h> #include <Time.h> #include <Wire.h> #include <math.h> #include <EasyTransfer.h> EnergyMonitor emon1; // Create an instance Schedular Task1; Schedular Task2; Schedular Task3; Schedular Task4; Schedular Task5; Schedular Task6; Schedular Task7; Schedular Task8; // note: the _in array should have increasing values int multiMap(int val, int* _in, int* _out, uint8_t size) { // take care the value is within range // val = constrain(val, _in[0], _in[size-1]); if (val <= _in[0]) return _out[0]; if (val >= _in[size-1]) return _out[size-1]; // search right interval uint8_t pos = 1; // _in[0] allready tested while(val > _in[pos]) pos++; // this will handle all exact "points" in the _in array if (val == _in[pos]) return _out[pos]; // interpolate in the right segment for the rest return map(val, _in[pos-1], _in[pos], _out[pos-1], _out[pos]); } // Data wire is plugged into port 11 on the Arduino #define ONE_WIRE_BUS 11 #define TEMPERATURE_PRECISION 12 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); // arrays to hold device addresses DeviceAddress bufferThermometer, dhwhThermometer, dhwlThermometer, outsideThermometer, dsHPFlow, dsHPReturn; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); float DStemp; float Buffer; float DhwH; float DhwL; String dataString = ""; float Outside; int HpMinsRun; int HpMinsRunY; double DailyWatts; //byte HpDailyDC; //byte HpWeeklyDC; byte ChImm; byte DHwImm; float HpFlow; float HpRet; float HpLPM; float ChFlow; float ChRet; float ShowerRecIn; float ShowerRecOut; float ShowerLPM; int HpWattsIn; int HpWattsOut; float HpCOP; byte HpChAct = true; byte ChPump; float WCcurve = 2.1; //0.1 to 10 input byte WCofset = 0.5; //0 to 10 input float WCtarget = 23; byte setback = false; float predictCorrection = 0; float osLastHr = 0; byte LowFlow = 4; int LastHr = 0; int LastMint = 0; byte dumpFilePB = LOW; byte heatWater = LOW; byte lastMint = 0; byte HpRunning; float DailyKWh = 0; long unsigned int Uptime = 0; // out[] holds the values for defined temps x100 int outA8[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; int outA9[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; int outA10[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; int outA11[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; int outA12[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; int outA13[] = { 469, 1438, 2031, 2469, 3131, 3654, 4406, 6388}; // in[] holds the measured analogRead() // note: the in array should have increasing values //int inA8[] = {475, 571, 625, 664, 710, 745, 788, 861}; int inA8[] = { 424, 541, 606, 649, 705, 751, 800, 880}; int inA9[] = { 434, 551, 616, 659, 716, 762, 813, 897}; int inA10[] = { 428, 546, 610, 646, 709, 760, 811, 901}; int inA11[] = { 434, 562, 626, 670, 719, 772, 822, 912}; int inA12[] = { 419, 546, 610, 667, 702, 762, 814, 826}; int inA13[] = { 457, 570, 630, 674, 721, 776, 826, 913}; byte slowlogcounter; int R1 = 23; //Low for heating, High for DHW int R2 = 25; //Flow sensor relay to HP int R3 = 27; //Heating circulation pump int R4 = 29; //Buffer immersion int R5 = 31; //DHW immersion int R6 = 33; int R7 = 35; int R8 = 37; int heatsw = 39; int R4W = 41; const int chipSelect = 10; //set pin 10 as CS for SD card (also pin 53 on mega needs to be output) volatile int NbTopsFan; //measuring the rising edges of the signal float Calc; int hallsensor = 2; //The pin location of the sensor void hpFlow () //This is the function that the interupt calls { NbTopsFan++; //This function measures the rising and falling edge of the hall effect sensors signal } volatile int NbShowerFlow; //measuring the rising edges of the signal //float Calc; int hallsensor1 = 3; //The pin location of the sensor void sFlow () //This is the function that the interupt calls { NbShowerFlow++; //This function measures the rising and falling edge of the hall effect sensors signal } //create object EasyTransfer ET; struct SEND_DATA_STRUCTURE{ //put your variable definitions here for the data you want to send //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO int rxOS; int rxDHWh; int rxDHWl; int rxBuffer; int rxHeating; int rxWater; }; //give a name to the group of data SEND_DATA_STRUCTURE mydata; void setup(void) { Task1.start(30000); Task2.start(); Task3.start(10000); Task4.start(); Task5.start(); Task6.start(); Task7.start(); Task8.start(5000); emon1.current(1, 15); // Current: input pin, calibration. Serial.begin(9600); //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc. ET.begin(details(mydata), &Serial); pinMode(R1, OUTPUT); pinMode(R2, OUTPUT); pinMode(R3, OUTPUT); pinMode(R4, OUTPUT); pinMode(R5, OUTPUT); pinMode(R6, OUTPUT); pinMode(R7, OUTPUT); pinMode(R8, OUTPUT); pinMode(heatsw, INPUT); digitalWrite(R1, LOW); digitalWrite(R2, HIGH); digitalWrite(R3, HIGH); digitalWrite(R4, HIGH); digitalWrite(R5, HIGH); digitalWrite(R6, HIGH); digitalWrite(R7, HIGH); digitalWrite(R8, HIGH); pinMode(R4W, OUTPUT); digitalWrite(R4W, HIGH); pinMode(12, INPUT); //dumpFilePB pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input attachInterrupt(0, hpFlow, RISING); //and the interrupt is attached (1 for Leonardo 0 for mega) pinMode(hallsensor1, INPUT); //initializes digital pin 3 as an input attachInterrupt(1, sFlow, RISING); //and the interrupt is attached lcd.begin(20, 4); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Heating Control"); // Start up the library sensors.begin(); // method 1: by index if (!sensors.getAddress(bufferThermometer, 0)) Serial.println("Unable to find address for Device 0"); if (!sensors.getAddress(dsHPFlow, 1)) Serial.println("Unable to find address for Device 4"); if (!sensors.getAddress(dhwhThermometer, 2)) Serial.println("Unable to find address for Device 1"); if (!sensors.getAddress(dhwlThermometer, 3)) Serial.println("Unable to find address for Device 2"); if (!sensors.getAddress(outsideThermometer, 4)) Serial.println("Unable to find address for Device 3"); if (!sensors.getAddress(dsHPReturn, 5)) Serial.println("Unable to find address for Device 5"); // set the resolution to 9 bit sensors.setResolution(bufferThermometer, TEMPERATURE_PRECISION); sensors.setResolution(dhwhThermometer, TEMPERATURE_PRECISION); sensors.setResolution(dhwlThermometer, TEMPERATURE_PRECISION); sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION); sensors.setResolution(dsHPFlow, TEMPERATURE_PRECISION); sensors.setResolution(dsHPReturn, TEMPERATURE_PRECISION); pinMode(53, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { //Serial.println("Card failed, or not present"); // don't do anything more: return; } //Serial.println("card initialized.");c } // function to print a device address void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { // zero pad the address if necessary if (deviceAddress[i] < 16) Serial.print("0"); //Serial.print(deviceAddress[i], HEX); } } // function to print the temperature for a device void printTemperature(DeviceAddress deviceAddress) { float tempC = sensors.getTempC(deviceAddress); DStemp = tempC; } |
09-07-14, 04:09 PM | #30 |
Apprentice EcoRenovator
Join Date: Mar 2013
Location: UK
Posts: 131
Thanks: 13
Thanked 35 Times in 32 Posts
|
More code
Code:
// function to print a device's resolution void printResolution(DeviceAddress deviceAddress) { //Serial.print("Resolution: "); //Serial.print(sensors.getResolution(deviceAddress)); //Serial.println(); } // main function to print information about a device void printData(DeviceAddress deviceAddress) { //Serial.print("Device Address: "); printAddress(deviceAddress); //Serial.print(" "); printTemperature(deviceAddress); //Serial.println(); } void loop(void) { // call sensors.requestTemperatures() to issue a global temperature // request to all devices on the bus //Serial.print("Requesting temperatures..."); sensors.requestTemperatures(); //Serial.println("DONE"); Task2.check(ReadDS18B20,4000); // print the device information printData(bufferThermometer); Buffer = DStemp; printData(dhwhThermometer); DhwH = DStemp; printData(dhwlThermometer); DhwL = DStemp; printData(outsideThermometer); Outside = DStemp; printData(dsHPFlow); HpFlow = DStemp; printData(dsHPReturn); HpRet = DStemp; lcd.clear(); lcd.setCursor(0, 0); lcd.print("Buf"); lcd.setCursor(4, 0); lcd.print(Buffer); lcd.setCursor(11, 0); lcd.print("OS"); lcd.setCursor(15, 0); lcd.print(Outside); lcd.setCursor(0, 1); lcd.print("Dhw"); lcd.setCursor(4, 1); lcd.print(DhwH); lcd.setCursor(11, 1); lcd.print(DhwL); lcd.setCursor(0, 2); //lcd.print(HpWattsOut); lcd.print("SP"); lcd.setCursor(3, 2); lcd.print(WCtarget); lcd.setCursor(10, 2); if (HpWattsIn > 500) { HpCOP = ((float)HpWattsOut / (float)HpWattsIn); HpRunning = true; } else { HpCOP = 0; HpRunning = false; } if (heatWater == false) { lcd.print("Heating"); } else { lcd.print("H Water"); } lcd.setCursor(0, 3); lcd.print(HpWattsIn); lcd.setCursor(7, 3); lcd.print(HpWattsOut); lcd.setCursor(14, 3); lcd.print(HpCOP); if (HpChAct == false && heatWater == false) { digitalWrite(R6, LOW); } else if (HpChAct == true || heatWater == true) { digitalWrite(R6, HIGH); } if (HpRunning == true) { HpWattsOut = (((HpFlow - HpRet) * 4184 * HpLPM) / 60); } else { HpWattsOut = 0; } //txEmon(); //Task1.check(txEmon,10000); Task1.check(RTCevents,1000); Task3.check(txEmon,10000); Task4.check(readFlows,30000); Task5.check(weathercomp,30000); //Task6.check(ReadThermsCal,5000); Task6.check(ReadTherms,5000); Task7.check(FlowSW,4000); //Task8.check(DumpFile,3000); } /////////////////////////End of main loop///////////////////////////////////////// void txEmon() { mydata.rxOS = (Outside * 10); mydata.rxDHWh = (DhwH * 10); mydata.rxDHWl = (DhwL * 10); mydata.rxBuffer = (Buffer * 10); if (heatWater == false) { mydata.rxHeating = (((HpFlow - HpRet) * 4184 * HpLPM) / 60); mydata.rxWater = 0; } else { mydata.rxHeating = 0; mydata.rxWater = (((HpFlow - HpRet) * 4184 * HpLPM) / 60); } //send the data ET.sendData(); } void RTCevents() { tmElements_t tm; int Hr; int Mint; RTC.read(tm); Hr = int(tm.Hour); Mint = int(tm.Minute); if (Hr == 5 || Hr == 12 || Hr == 13 || Hr == 19 || (Hr == 20 && DhwH <= 40)) { //select DHW from 12 till 2 heatWater = true; digitalWrite(R1, HIGH); digitalWrite(R4W, LOW); } else { heatWater = false; digitalWrite(R1, LOW); } if (LastHr != Hr) { LastHr = Hr; Uptime++; predictCorrection = ((osLastHr - Outside) * 0.5); osLastHr = Outside; LogSlow(); } if (LastMint != Mint) { DailyWatts += HpWattsIn; DailyKWh = (DailyWatts / 60); if (HpRunning == true) HpMinsRun++ ; if (Hr == 0 && Mint == 0) { HpMinsRunY = HpMinsRun; HpMinsRun = 0; DailyWatts = 0; DailyKWh = 0; } LastMint = Mint; LogQuick(); } if (heatWater == false && Outside < 5 && HpChAct == false && lastMint != Mint) { if (Mint == 0 || Mint == 10 || Mint == 20 || Mint == 30 || Mint == 40 || Mint == 50) { digitalWrite(R6, LOW); delay(2000); digitalWrite(R6, HIGH); lastMint = Mint; } } } void ReadDS18B20() { // print the device information printData(bufferThermometer); Buffer = DStemp; printData(dhwhThermometer); DhwH = DStemp; printData(dhwlThermometer); DhwL = DStemp; printData(outsideThermometer); Outside = DStemp; printData(dsHPFlow); HpFlow = DStemp; printData(dsHPReturn); HpRet = DStemp; } void FlowSW() { NbTopsFan = 0; //Set NbTops to 0 ready for calculations interrupts(); //Enables interrupts delay (500); //Wait .5 second noInterrupts(); //Disable interrupts if (NbTopsFan > LowFlow) { digitalWrite(R2, LOW); } else { digitalWrite(R2, HIGH); } double Irms = emon1.calcIrms(1480); // Calculate Irms only HpWattsIn = (Irms*245.0); // Apparent power //Serial.print(" "); //Serial.println(Irms); // Irms } void readFlows() { NbTopsFan = 0; //Set NbTops to 0 ready for calculations NbShowerFlow = 0; //Set NbTops to 0 ready for calculations interrupts(); //Enables interrupts delay (5000); //Wait 5 second noInterrupts(); //Disable interrupts HpLPM = (NbTopsFan / 13.75); //ShowerLPM = (NbShowerFlow / 225); ShowerLPM = NbShowerFlow; } void ReadThermsCal() { // Routine used for calibration only int val = 0; // val=(analogRead(A8)); // read ADC and convert it to Celsius // HpFlow = val; // val=(analogRead(A9)); // read ADC and convert it to Celsius // HpRet = val; val=(analogRead(A10)); // read ADC and convert it to Celsius ChFlow = val; val=(analogRead(A11)); // read ADC and convert it to Celsius ChRet = val; val=(analogRead(A12)); // read ADC and convert it to Celsius ShowerRecIn = val; val=(analogRead(A13)); // read ADC and convert it to Celsius ShowerRecOut = val; } void ReadTherms() { int val = 0; //val=(analogRead(A8)); // read ADC and convert it to Celsius //HpFlow = multiMap(val, inA8, outA8, 8); //HpFlow = (HpFlow / 100); //val=(analogRead(A9)); // read ADC and convert it to Celsius //HpRet = multiMap(val, inA9, outA9, 8); //HpRet = (HpRet / 100); val=(analogRead(A10)); // read ADC and convert it to Celsius ChFlow = multiMap(val, inA10, outA10, 8); ChFlow = (ChFlow / 100); val=(analogRead(A11)); // read ADC and convert it to Celsius ChRet = multiMap(val, inA11, outA11, 8); ChRet = (ChRet / 100); val=(analogRead(A12)); // read ADC and convert it to Celsius ShowerRecIn = multiMap(val, inA12, outA12, 8); ShowerRecIn = (ShowerRecIn / 100); val=(analogRead(A13)); // read ADC and convert it to Celsius ShowerRecOut = multiMap(val, inA13, outA13, 8); ShowerRecOut = (ShowerRecOut / 100); } void DumpFile() { dumpFilePB = digitalRead(12); if (dumpFilePB == HIGH) { //Serial.begin(57600); delay(500); File dataFile = SD.open("quicklog.csv"); // if the file is available, write to it: if (dataFile) { while (dataFile.available()) { Serial.write(dataFile.read()); } dataFile.close(); } // if the file isn't open, pop up an error: else { Serial.println("error opening QUICKLOG.CSV"); } Serial.end(); } dumpFilePB = LOW; } |
|
|