โปรเจกต์ ระบบ Ventilation สำหรับ Basement/Crawlspace
ลด Moisture ใน Basement/Crawlspace ของคุณอย่างชาญฉลาดเพื่อช่วยควบคุมการเติบโตของ Mildew และลดค่า Heating/Cooling
ลด Moisture ใน Basement/Crawlspace ของคุณอย่างชาญฉลาดเพื่อช่วยควบคุมการเติบโตของ Mildew และลดค่า Heating/Cooling



เชื่อมต่อ Arduino Nano เข้ากับ IO Expander และ Program มันด้วย Code ต่อไปนี้ โดย 6 pin header คือ software serial debug port ซึ่งไม่จำเป็นต้องใช้ในการติดตั้งจริง

ตรวจสอบให้แน่ใจว่าคุณได้เปลี่ยน address ที่ระบุใน ONEWIRE_TO_I2C_ROM ให้ตรงกับ address ของ 1-Wire to I2C ของคุณ
/* IO Expander
*
* Basement/Crawlspace Ventilation System v1.1
*
*/
#include <math.h>
#include <SoftwareSerial.h>
#include <avr/wdt.h>
#include "IOExpander.h"
#define FAHRENHEIT
#define ONEWIRE_TO_I2C_ROM "i4s71"
#define INIT_OLED "st13;si;sc;sd"
#define HUMIDITY_SENSOR_INSIDE "s6t1"
#define HUMIDITY_SENSOR_OUTSIDE "s8t1"
#define FAN_ON "r1o"
#define FAN_OFF "r1f"
#define ABSOLUTE_DELTA_FAN_ON 1 // Fan on if absolute humidity delta of inside >= outside
#define ABSOLUTE_DELTA_FAN_OFF 0.5 // Fan off if absolute humidity delta of inside <= outside
#define OUTSIDE_RELATIVE_FAN_ON 88 // Fan on if outside relative humidity is <= %
#define OUTSIDE_RELATIVE_FAN_OFF 90 // Fan off if outside relative humidity is >= %
#define MINIMUM_TEMPERATURE 15 // Cycle vent on/off if outside temperature <= 15C/59F
#define FAN_ON_TIME (20*60*1000L) // 20 min
#define FAN_OFF_TIME (20*60*1000L) // 20 min
//#define SERIAL_DEBUG
#define SERIAL_TIMEOUT 5000 // 5 sec delay between DHT22 reads
#ifdef SERIAL_DEBUG
SoftwareSerial swSerial(8,7);
#endif
struct HS {
float temp;
float relative;
float absolute;
bool error;
};
int led = 13;
bool init_oled = true;
long ontime, offtime;
#ifdef FAHRENHEIT
#define C2F(temp) CelsiusToFahrenheit(temp)
float CelsiusToFahrenheit(float celsius)
{
return ((celsius*9)/5)+32;
}
#else
#define C2F(temp) (temp)
#endif
void SerialPrint(const char* str, float decimal, char error)
{
Serial.print(str);
if (error) Serial.print(F("NA"));
else Serial.print(decimal, 1);
}
float DewPoint(float temp, float humidity)
{
float t = (17.625 * temp) / (243.04 + temp);
float l = log(humidity/100);
float b = l + t;
// Use the August-Roche-Magnus approximation
return (243.04*b)/(17.625-b);
}
#define MOLAR_MASS_OF_WATER 18.01534
#define UNIVERSAL_GAS_CONSTANT 8.21447215
float AbsoluteHumidity(float temp, float relative)
{
//taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-hu midity-to-absolute-humidity/
//precision is about 0.1°C in range -30 to 35°C
//August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
//Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
//reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html // Use Buck (1981)
return (6.1121 * pow(2.718281828, (17.67 * temp) / (temp + 243.5)) * relative * MOLAR_MASS_OF_WATER) / ((273.15 + temp) * UNIVERSAL_GAS_CONSTANT);
}
void ReadHumiditySensor(HS* hs)
{
SerialCmd("sr");
if (SerialReadFloat(&hs->temp) &&
SerialReadFloat(&hs->relative)) {
//hs->dewpoint = DewPoint(hs->temp, hs->relative);
hs->absolute = AbsoluteHumidity(hs->temp, hs->relative);
hs->error = false;
}
else hs->error = true;
SerialReadUntilDone();
}
void setup() {
Serial.begin(115200);
#ifdef SERIAL_DEBUG
swSerial.begin(115200);
//swSerialEcho = &swSerial;
#endif
pinMode(led, OUTPUT);
wdt_enable(WDTO_8S);
offtime = millis() - FAN_OFF_TIME;
}
void loop() {
HS inside, outside;
static bool fan = false;
static bool cycle = false;
static long last_time = -(60L * 1000L);
Serial.println();
if (SerialReadUntilDone()) {
// Read the humidity sensors only once a minute or they will self heat if read too quickly
if (millis() - last_time > 60L * 1000L)
{
if (SerialCmdDone(HUMIDITY_SENSOR_INSIDE))
ReadHumiditySensor(&inside);
if (SerialCmdDone(HUMIDITY_SENSOR_OUTSIDE))
ReadHumiditySensor(&outside);
if (inside.error || outside.error) fan = false;
else {
if (fan) {
if (outside.relative >= OUTSIDE_RELATIVE_FAN_OFF || inside.absolute - outside.absolute <= ABSOLUTE_DELTA_FAN_OFF)
cycle = fan = false;
else {
if (cycle && outside.temp <= MINIMUM_TEMPERATURE &&
millis() - ontime > FAN_ON_TIME) fan = false;
}
if (!fan) offtime = millis();
}
else {
if (outside.relative <= OUTSIDE_RELATIVE_FAN_ON && inside.absolute - outside.absolute >= ABSOLUTE_DELTA_FAN_ON)
cycle = fan = true;
if (cycle && outside.temp <= MINIMUM_TEMPERATURE)
fan = (millis() - offtime > FAN_OFF_TIME) ? true : false;
if (fan) ontime = millis();
}
}
if (fan) SerialCmdDone(FAN_ON);
else SerialCmdDone(FAN_OFF);
if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM)) {
if (init_oled) {
SerialCmdDone(INIT_OLED);
init_oled = false;
}
SerialCmdDone("st13;sc;sf0;sa1;sd70,0,\\"INSIDE\\";sd127,0,\\"OUTSIDE\\";sf1;sa0;sd0,12,248,\\""
#ifdef FAHRENHEIT
"F"
#else
"C"
#endif
"\\";sd0,30,\\"%\\";sf0;sd0,50,\\"g/m\\";sd20,46,\\"3\\";");
SerialPrint("sf1;sa1;sd70,12,\\"", C2F(inside.temp), inside.error);
SerialPrint("\\";sd70,30,\\"", inside.relative, inside.error);
SerialPrint("\\";sd70,48,\\"", inside.absolute, inside.error);
SerialPrint("\\";sd127,12,\\"", C2F(outside.temp), outside.error);
SerialPrint("\\";sd127,30,\\"", outside.relative, outside.error);
SerialPrint("\\";sd127,48,\\"", outside.absolute, outside.error);
Serial.print("\\";");
Serial.print("sf0;sa0;sd0,0,\\"");
if (fan) Serial.print("FAN");
else Serial.print("v1.1");
Serial.println("\\";sd");
SerialReadUntilDone();
}
else init_oled = true;
last_time = millis();
}
delay(1000);
}
else {
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
init_oled = true;
}
wdt_reset();
}หมายเหตุ: หากคุณใช้พอร์ต USB ในการ Program Arduino Nano คุณต้องตัดการเชื่อมต่อออกจาก IO Expander เนื่องจากใช้ serial port เดียวกัน แต่หากต้องการ debug ให้ใช้พอร์ต ICSP ในการ Program ATmega328P แทน และหากต้องการเปิดใช้งาน software debugging port ให้ลบเครื่องหมาย comment ที่นิยาม SERIAL_DEBUG ออก
เชื่อมต่อสายไฟ 110VAC เข้ากับพัดลมทั้งสองตัว

เจาะรูขนาด 7/16" และ 9/16" ที่ด้านใดด้านหนึ่งของกล่อง Enclosure สำหรับ PG7 และ PG9 ใช้เครื่องมือ dremel เพื่อขยายรูเล็กน้อยจนกระทั่ง Cable Gland ใส่ได้พอดี โดย PG7 จะใช้สำหรับสายไฟ input 12VDC และ PG9 สำหรับ Sensor และพัดลม

หาช่องระบายอากาศที่เปิดอยู่และไม่ถูกปิดกั้น ซึ่งจะเป็นช่องระบายอากาศออกที่เราจะใช้เป่าอากาศจากห้องใต้ดิน/crawlspace ออกไป ตรวจสอบให้แน่ใจว่าช่องระบายอากาศอื่นๆ ในด้านตรงข้ามเปิดอยู่ เพราะสิ่งเหล่านี้จะเป็นช่องรับอากาศเข้า ปิดช่องระบายอากาศที่อยู่ติดกันเพื่อสร้างการไหลเวียนของอากาศทั่วทั้งบริเวณห้องใต้ดิน/crawlspace แทนที่จะไหลเวียนอยู่แค่จุดเดียว

ติดตั้งพัดลมที่ด้านในของช่องระบายอากาศโดยใช้สายรัด (tie wraps) ตรวจสอบให้แน่ใจว่าคุณหันพัดลมไปในทิศทางที่ถูกต้องเพื่อเป่าอากาศออก

หาจุดทางเข้าที่มีอยู่และสอดสาย Sensor วัดความชื้นภายนอกเข้าไปข้างใน ตรวจสอบให้แน่ใจว่า Sensor วัดความชื้นอยู่ห่างจากตัวบ้านและสิ่งกีดขวางมากพอ เพื่อให้สามารถวัดอุณหภูมิ/ความชื้นโดยรอบได้อย่างแม่นยำ ตรวจสอบค่าที่คุณอ่านได้เทียบกับรายงานสภาพอากาศในท้องถิ่นของคุณ

ต่อสาย Sensor วัดความชื้นภายนอกเข้ากับ Keystone Jack และ Enclosure แล้วติดตั้งไว้ด้านใน

ต่อสาย Sensor วัดความชื้นภายในเข้ากับ Keystone Jack และ Enclosure แล้วติดตั้งไว้ด้านใน แนะนำให้ติดตั้งในตำแหน่งส่วนกลางหรือบริเวณที่ต้องการควบคุมความชื้นเป็นพิเศษ

เชื่อมต่อสาย RJ11 ยาว 50 ฟุตเข้ากับ Sensor วัดความชื้น และเดินสายไปพร้อมกับสายพัดลมไปยังจุดที่จะติดตั้งกล่องควบคุม Enclosure

เชื่อมต่อสายไฟทั้งหมดและประกอบ/ป้อนชิ้นส่วนทั้งหมดเข้าไปในกล่องควบคุม Enclosure หากสาย RJ11 ยาว 50 ฟุตของคุณมาพร้อมกับหัวเชื่อมต่อที่เข้าหัวมาแล้ว คุณจะต้องตัดหัวออกเพื่อสอดสายผ่าน Cable Gland และเข้าหัว connectors ใหม่

ทดสอบระบบและตรวจสอบให้แน่ใจว่าทุกอย่างทำงานถูกต้อง ในการทดสอบ Relay และพัดลม ให้ถอด Arduino ออกจาก IO Expander แล้วเชื่อมต่อเข้ากับคอมพิวเตอร์ของคุณโดยตรงเพื่อควบคุมแบบ manual เมื่อคุณตรวจสอบแล้วว่าทุกอย่างทำงานได้ปกติ ให้ประกอบชิ้นส่วนทั้งหมดเข้าในกล่อง Enclosure โดยใช้เทปกาวสองหน้าและโฟมกันกระแทกเพื่อยึด Board ของคุณให้แน่นหนา และเพลิดเพลินไปกับประโยชน์และการประหยัดจากระบบ Smart Moisture Control Ventilation System
หลังจากรันระบบระบายอากาศใน crawlspace มาสองสามเดือนโดยไม่มีอาการค้าง และมีความชื้นสัมพัทธ์สูงสุดมากกว่า 95% หลังจากเกิดปัญหาน้ำรั่วจากเครื่องทำน้ำอุ่น ระบบสามารถลดความชื้นสัมพัทธ์ลงเหลือต่ำกว่า 50% ได้สำเร็จ ระบบระบายอากาศนี้เป็นระบบควบคุมที่ใช้งานได้จริง!

เปลี่ยนจากหน้าจอ SSD1306 0.96" OLED Display เป็นหน้าจอ SH1106 1.3" OLED Display มันมีขนาดใหญ่กว่ามากและอ่านง่ายกว่า การเปลี่ยนหน้าจอทำได้ง่ายมากด้วยการอัปเดต firmware ของ IO Expander เพียงแค่เปลี่ยน 'ST10' เป็น 'ST13' ใน Code ของคุณ

ปล่อยเวอร์ชัน v1.1 ที่แก้ไขปัญหา cold boot ที่หน้าจอ OLED แสดงผลเป็นสีว่างเปล่าตอนเปิดเครื่อง ยังคงทำงานระบายอากาศใน crawlspace ของฉันได้ดี!
สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้