How is it held in place? Caulk?Decided to DIY double pane the factory rear window.
How is it held in place? Caulk?
Thanks for the tips and posting that mod. I have an E350 and an Astro, both of which are passenger vans. Double pane windows would be a big win.
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define TempBus 3
//output pins
const int PUMPEngine = 5;
const int PUMPGray = 6;
const int PUMPHeater = 7;
const int MechFan = 8;
const int D5heater = 9;
const int BLight = 10;
/*relays 6, 7, and 8 are reserved for future use.
const int Relay6 = 11;
const int Relay7 = 12;
const int Relay8 = 13;
*/
//Target Temps
//Water Heater temperature for showers
const int ShowerTempH = 120;
const int ShowerTempL = 105;
//Antifreeze Loop Low
const int FreezeTemp = 45;
//Water Heater minimum temp for antifreeze operation
const int StandbyTemp = 60;
//Engine temp for preheat and switchover
const int EngineTarget = 145;
//LEDS
//Variables
float EngineT = 200;
float WaterT = 200;
float AntiFreezeT = 200;
float AmbientT = 200;
float MechCompT = 200;
float EngineT1;
float WaterT1;
float AntiFreezeT1;
float AmbientT1;
float MechCompT1;
int EngineTC = 0;
int WaterTC = 0;
int AntiFreezeTC = 0;
int AmbientTC = 0;
int ErrCount = 0;
int MechCompTC = 0;
bool PUMPEngineS = 0;
bool PUMPGrayS = 0;
bool PUMPHeaterS = 0;
bool MechFanS = 0;
bool EngineheatS = 0;
bool WaterheatS = 0;
bool AntifreezeS = 0;
bool DplusS = 0;
bool D5heaterS = 0;
bool ShowerHeat = 0;
bool EngSwitch = 0;
bool BLightS = 0;
int HeaterTarget = 0;
int FreezeTarget;
int CutIn = 0;
int CutOut = 0;
//Timers
long currentmillis;
long LastTemp = 0;
long LastPump = 0;
long LastGray = 0;
long LastLCD = 0;
long LastSwitch = 0;
long ShowerStart = 0;
long PUMPStart = 0;
//input pins
const int Engineheat = 0 ;
const int Waterheat = 1;
const int Antifreeze = 2;
const int Dplus = 4;
OneWire oneWire(TempBus);
//Pass onewire refference to Dallas Temperature function
DallasTemperature sensors(&oneWire);
//Sensor addresses
/*
1=EngineTAD
2=WaterTAD
3=AntiFreezeTAD
4=AmbientTAD
5=Spare
*/
//Temp Sensor addresses
DeviceAddress EngineTAD = {0x28, 0x15, 0x99, 0x07, 0xD6, 0x01, 0x3C, 0x7D};
DeviceAddress WaterTAD = {0x28, 0xF2, 0xDE, 0x79, 0xA2, 0x01, 0x03, 0x5A};
DeviceAddress AntiFreezeTAD = {0x28, 0xC0, 0x2F, 0x07, 0xD6, 0x01, 0x3C, 0x81};
DeviceAddress AmbientTAD = {0x28, 0x76, 0x32, 0x07, 0xD6, 0x01, 0x3C, 0xA4};
DeviceAddress MechCompTAD = {0x28, 0xEA, 0x3D, 0x07, 0xD6, 0x01, 0x3C, 0x07};
//Set LCD address and define lcd type
//Pins are A4 and A5 for LCD Control
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
//Set pin mode to output. Write pins immeadiately high to prevent relay closing during startup.
pinMode(PUMPEngine, OUTPUT);
digitalWrite(PUMPEngine, HIGH);
pinMode(PUMPGray, OUTPUT);
digitalWrite(PUMPGray, HIGH);
pinMode(PUMPHeater, OUTPUT);
digitalWrite(PUMPHeater, HIGH);
pinMode(MechFan, OUTPUT);
digitalWrite(MechFan, HIGH);
pinMode(D5heater, OUTPUT);
digitalWrite(D5heater, HIGH);
/*relay outputs are reserved for future use
pinMode(Relay6, OUTPUT);
pinMode(Relay7, OUTPUT);
pinMode(Relay8, OUTPUT);
*/
//Switches on control panel are all switched to ground. The D+ engine running signal is HIGH when active and LOW with engine off.
pinMode(Engineheat, INPUT_PULLUP);
pinMode(Waterheat, INPUT_PULLUP);
pinMode(Antifreeze, INPUT_PULLUP);
pinMode(BLight, INPUT_PULLUP);
pinMode(Dplus, INPUT);
//attachInterrupt(digitalPinToInterrupt(Waterheat), ShowerTime, FALLING);
//start temp sensor bus and set resolution to 10 bits
sensors.begin();
sensors.setResolution(10);
//initial LCD setup
lcd.init();
lcd.setCursor ( 0, 0 );
lcd.print("AMB ENG WTR GRY MEC ");
lcd.setCursor ( 0, 1 );
lcd.print("XXX XXX XXX XXX XXXF");
lcd.setCursor ( 0, 2 );
lcd.print(" HX X X ");
lcd.setCursor ( 0, 3 );
lcd.print(" PX X X XFAN");
sensors.begin();
sensors.setResolution(10);
}
void loop()
{
//Start timer
currentmillis = millis();
/*Do the things, Temperatures are updated every 10 seconds, pump status is updated every second to prevent odd behavior.
Some pumps are switched outside of the Updatepump function. This is to prevent the D5 heater from seeing no pump current, and faulting.
*/
if ((currentmillis - LastTemp) > 10000) UpdateTemp();
if ((currentmillis - LastPump) > 1000) UpdatePump();
if ((currentmillis - LastSwitch ) > 1000) UpdateSwitch();
HydronicControl();
AntifreezeControl();
if ((currentmillis - LastLCD) > 1000) LCDUpdate();
/*
if (ShowerHeat)
{
if ((currentmillis - ShowerStart) > 1200000)
{
WaterheatS = 0;
ShowerHeat = 0;
}
else WaterheatS = 1;
}
*/
}
void UpdateTemp() {
//This commmand tells alll the sensors to prepare to transmit the temperature. Depending on sensor resolution there is a certain cooldown time before it can be requested again.
//If no response is recieved, or if its funky, the sensor library will return a specific temperature value as error. Not all of them are documented.
sensors.requestTemperatures();
EngineT1 = sensors.getTempF(EngineTAD);
WaterT1 = sensors.getTempF(WaterTAD);
AntiFreezeT1 = sensors.getTempF(AntiFreezeTAD);
AmbientT1 = sensors.getTempF(AmbientTAD);
MechCompT1 = sensors.getTempF(MechCompTAD);
//Sanity Checks. If sensor does not respond the getTempF returns -196.6F. If temps are below -50, the function uses the previous value for 30 seconds.
//If no update is found in that time, the error value of 999 is used. ErrCount is incremented for debug reasons, I may remove in newer revisions.
if (EngineT1 < -50)
{
ErrCount++;
if (EngineTC > 3) EngineT = 999;
else EngineTC++;
}
else
{
EngineT = EngineT1;
EngineTC = 0;
}
if (WaterT1 < -50)
{
ErrCount++;
if (WaterTC > 3) WaterT = 999;
else WaterTC++;
}
else
{
WaterT = WaterT1;
WaterTC = 0;
}
if (AntiFreezeT1 < -50)
{
ErrCount++;
if (AntiFreezeTC > 3) AntiFreezeT = 999;
else AntiFreezeTC++;
}
else
{
AntiFreezeT = AntiFreezeT1;
AntiFreezeTC = 0;
}
if (AmbientT1 < -50)
{
ErrCount++;
if (AmbientTC > 3) AmbientT = 999;
else AmbientTC++;
}
else
{
AmbientT = AmbientT1;
AmbientTC = 0;
}
if (MechCompT1 < -50)
{
ErrCount++;
if (MechCompTC > 3) MechCompT = 999;
else MechCompTC++;
}
else
{
MechCompT = MechCompT1;
MechCompTC = 0;
}
/*if (WaterT1 < -50) WaterT = 999;
if (AntiFreezeT1 < -50) AntiFreezeT = 999;
if (EngineT1 < -50) EngineT = 999;
if (MechCompT1 < -50) MechCompT = 999;
if (AmbientT1 < -50) AmbientT = 999;
*/
currentmillis = millis();
LastTemp = millis();
}
void UpdatePump() {
//If engine is running, turn off engine coolant pump (ECU controls, but engine pump also is sufficient).
if (DplusS)
PUMPEngineS = 0;
//If engine is running, Noe engine preheat/boost is selected, and D5 is currently off
if (DplusS && !EngineheatS && !D5heaterS)
{
//If engine is warmed up, and water heataer is less than minimum, run the D5 coolant pump to heat water heater.
if ((EngineT > EngineTarget) && (WaterT < ShowerTempL))
{
PUMPHeaterS = 1;
}
//If engine isn't warmed up, or water heater is above max tank temp, turn off D5 pump.
if ((EngineT < EngineTarget) || (WaterT > ShowerTempH))
{
PUMPHeaterS = 0;
}
}
//Otherwise, let D5 heater control its pump
else
{
PUMPHeaterS = 0;
}
digitalWrite (PUMPEngine, !PUMPEngineS);
digitalWrite (PUMPGray, !PUMPGrayS);
digitalWrite (PUMPHeater, !PUMPHeaterS);
digitalWrite (MechFan, !MechFanS);
}
//read switches. Due to use of pullup status, some are inverted
void UpdateSwitch() {
EngineheatS = !digitalRead(Engineheat);
WaterheatS = !digitalRead(Waterheat);
AntifreezeS = !digitalRead(Antifreeze);
DplusS = digitalRead(Dplus);
BLightS = !digitalRead(BLight);
}
//Hydronic Heater Control
void HydronicControl()
{
//If engine preheat/boost is selected
if (EngineheatS)
//if D5 is on and engine is above preheat/boost target, turn off D5
{ if (D5heaterS && EngineT > EngineTarget)
{
digitalWrite(D5heater, HIGH);
D5heaterS = 0;
}
//If D5 is off, and engine temp more than 30 degrees below preheat target, then turn on D5 heater, and give D5 control of its pump. D5 status variable is updated.
if (D5heaterS == 0 && EngineT < (EngineTarget - 30))
{
digitalWrite(PUMPHeater, HIGH);
digitalWrite(D5heater, LOW);
D5heaterS = 1;
}
//If engine is off
if (!DplusS)
{
//If engine is more than 20 degrees below preheat target, and engine pump is off, turn it back on to check temperature.
if ( EngineT < (EngineTarget - 20) && PUMPEngineS == 0)
{
PUMPEngineS = 1;
}
//if the engine is greater than the target temperature and the pump is running, turn it off to conserve power.
if (EngineT > EngineTarget && PUMPEngineS == 1)
{
PUMPEngineS = 0;
}
}
//if the engine is running, turn off the engine pump.
if (DplusS)
{
PUMPEngineS = 0;
}
}
//if engine preheat is not active
else
{
//if water heating or gray tank antifreeze is active
if (WaterheatS || AntifreezeS)
{
//for water heating set the cut in/out temps to the higher values
if (WaterheatS)
{
CutIn = ShowerTempH;
CutOut = ShowerTempL;
}
//if only gray tank antifreeze is selected, use lower temps
else
{
if (AntifreezeS)
{
CutIn = StandbyTemp;
CutOut = ShowerTempL;
}
}
//if water heater is below cutout and D5 is on, keep heating, D5 controls pump
if ((WaterT < CutOut) && D5heaterS )
{
digitalWrite(PUMPHeater, HIGH);
digitalWrite(D5heater, LOW);
D5heaterS = 1;
PUMPHeaterS = 0;
}
//If water heater is above cutout and D5 heater is active, turn off D5.
if ((WaterT > CutOut) && D5heaterS )
{
digitalWrite(D5heater, HIGH);
D5heaterS = 0;
}
//if water heater is above cutin, and d5 is off, d5 stays off.
if (WaterT > CutIn && D5heaterS == 0) {
digitalWrite(D5heater, HIGH);
D5heaterS = 0;
}
//If water heater is less than cutin, turn on D5 and D5 controls its pump
if (WaterT < CutIn)
{
digitalWrite(PUMPHeater, HIGH);
digitalWrite(D5heater, LOW);
D5heaterS = 1;
PUMPHeaterS = 0;
}
}
//otherwise D5 is off
else
{
digitalWrite(D5heater, HIGH);
D5heaterS = 0;
}
PUMPEngineS = 0;
}
}
//this controls the gray tank antifreeze pump/loop
void AntifreezeControl()
{
//if the ambient temp is below 40 and the gray tank antifreeze is active
if ( AmbientT < 40 && AntifreezeS)
{
//If the mechanical cabinet is below 45F, run the fan to circulate cabin air.
if (MechCompT < 45) MechFanS = 1;
//The gray tank loop target temp
FreezeTarget = FreezeTemp;
//if the engine is running or water heating is active, increase the gray loops target temperature to 90F, as free heat is available.
if (DplusS || WaterheatS ) FreezeTarget = 90;
//if the gray tank loop is below the target temp, turn on the pump
if (AntiFreezeT < FreezeTarget) PUMPGrayS = 1;
//if the loop more than 20 degrees above the target, and the pump is running, turn it off. Update the last pump time.
if (AntiFreezeT > (FreezeTarget + 20) && PUMPGrayS)
{
PUMPGrayS = 0;
LastGray = currentmillis;
}
//if the loop is above the target, cycle the pump
if (AntiFreezeT > FreezeTarget )
{
//if the time since the pump was last cycled is greater than 30 minutes, turn the pump on, and reset pump start timer
if ((currentmillis - LastGray) > 1800000 && !PUMPGrayS )
{
PUMPStart = currentmillis;
PUMPGrayS = 1;
}
//if the pump is running and its been more than 2 minutes, turn the pump off and reset the last pump timer.
if ((currentmillis - PUMPStart) > 120000 && PUMPGrayS )
{
PUMPGrayS = 0;
LastGray = currentmillis;
}
}
}
//otherwise turn off the pump and mechanical fan
else
{
PUMPGrayS = 0;
MechFanS = 0;
}
}
/*
void ShowerTime()
{
ShowerHeat = 1;
ShowerStart = currentmillis;
}
*/
//update LCD screen with temperatures and statuses. To account for temperature length changes, each 3 digit position is written to blank/space before the temp is written.
void LCDUpdate()
{
//switch backlight based on switch status
lcd.setBacklight(BLightS);
// Format for cursor position is (column, row) Each row is written with each variable starting left and working right. Each floating temperature value is printed with no decimals
lcd.setCursor ( 0, 1 );
lcd.print(" ");
lcd.setCursor ( 0, 1 );
lcd.print(AmbientT, 0);
lcd.setCursor ( 4, 1 );
lcd.print(" ");
lcd.setCursor ( 4, 1 );
lcd.print(EngineT, 0);
lcd.setCursor ( 8, 1 );
lcd.print(" ");
lcd.setCursor ( 8, 1 );
lcd.print(WaterT, 0);
lcd.setCursor ( 12, 1 );
lcd.print(" ");
lcd.setCursor ( 12, 1 );
lcd.print(AntiFreezeT, 0);
lcd.setCursor ( 16, 1 );
lcd.print(" ");
lcd.setCursor ( 16, 1 );
lcd.print(MechCompT, 0);
lcd.setCursor ( 5, 2 );
lcd.print(EngineheatS);
lcd.setCursor ( 8, 2 );
lcd.print(WaterheatS);
lcd.setCursor ( 12, 2 );
lcd.print(AntifreezeS);
lcd.setCursor ( 5, 3 );
lcd.print(PUMPEngineS);
lcd.setCursor ( 8, 3 );
lcd.print(PUMPHeaterS);
lcd.setCursor ( 12, 3 );
lcd.print(PUMPGrayS);
lcd.setCursor ( 16, 3 );
lcd.print(MechFanS);
lcd.setCursor (0, 3 );
lcd.print(ErrCount);
//update last LCD time
LastLCD = currentmillis;
}
Clear RTV silicone adhesive. The outdoor stuff that's ~8$ a tube. There are clear urethanes that work as well, just not as common.
A couple notes on doing that to a window. You need to make sure that dust can't get behind the pane. My windows have a small drain around the pinch weld on the inside. So I had to seal that before putting in the plastic pane. Otherwise it would eventually fill with dust. You also need a single small hole to equalize pressure. This can be a 1/16" hole in the pane, or in my case I poked a small hole in the sealant at the bottom before it cured. You don't want more than one hole though, as that can cause air circulation which is undesirable in some situations.
Ok I'll look for that, thanks.
Probably out of stock because covid. Seems like most everything is in short supply these days.