Hello hello.
My name is Roel and I have become an autodidact in automating terrarium systems with the use of micro-controllers. During the day I have a completely different profession. Currently I'm in the proces of building a new terrarium enclosure. This is my 4th project. And this time I decided I wanted to give back to this amazing community by posting my progression (concept, design, building, testing and most of all: the mistakes!).
My build is a full glass terrarium, which when finished, will hopefully be able to do the following:
Display on OLED 128*64: Temps, Humidity %, system status and water reservoir %;
Regulate humidity by measuring and misting and/or activating fans accordingly;
Control Lighting either fixed or based on local sunrise/set;
Control small functions like cooling/heating fans, status LEDs, and drip wall pump mechanics.
I've drawn up a global schematic of the electronic involved in Affinity Designer (OSX). All of the components are in my stock. My attitude is 50% planning and 50% learning along the way. I love the proces learning while fiddling with materials and code lines. My next step is to globally setup the first sketch designs in Arduino IDE.
EDIT: Controller1 (the left) should probably only control Mister via Relay switches... the rest of Relay should be managed by Controller2, since those are 'daily tasks'
since ESP32 has WiFi and Bluetooth capabilities, you can add a primary (secondary) display, which would also enable remote control and monitoring. You can give GUI-O application (Android based) a try; you control all aspects of the GUI from the ESP32 side... There are a lot of examples for ESP32 to get started: GUI-O application: Create high-end GUI for any device - EXAMPLES.
I really don't want this to sound like a marketing effort, but I can see advantages of using GUI-O in your terrarium setup (maybe only during SW development / debugging).
Hi,
it's not an area I know very well, so I have doubts if these MOSFET modules are ideal for your project.
I don't know if they are logic level MOSFETs.
I think you might be on to something… I read that 4 pin fans could be controlled by just 1 PWM wire. And some PWM 4-wire fans do not have a 0% PWM = OFF mode. They turn into full speed at 0% PWM. You need to resolve that with separate relays, because I will need the functionality to fully shut down my fans.
The fans in my concept, which I have in stock, are fans with 2 wires: + & - .
A brief start with the first sketch for Controller 1 I made today. I'm currently trying to find a logical structure in the setup, loop & functions. As for disabling the mister, I need to write a time variable(?). Because the mister needs to pause before its starts spraying again immediately. I probably also need to be aware that functions are not competing with one another... like the ones controlling the Fans.
//===Main Program for ESP32 DOIT Devkit V1 - Controller1
//===Controller1: Monitoring sensors & Controlling humidity / Fans;
//===Controller2: Controling Daily cycles such as Lighting, dripwall and water pump;
//===Structure as by: https://forum.arduino.cc/t/planning-and-implementing-an-arduino-program/252364/3
//===User: Robin2
//===#includes placeholder
void setup() {
// put your setup code here, to run once:
}
// this code repeats itself
void loop() {
// CONCEPT PROGRAM [semi-structured ;)]
// ==A. Every 10 seconds, Measure Humidity of enclosure and take following action:
// if humidity < set_value: activate mister and disable the mister for upcomming 15 minutes
// disable FansOut & FansIn for 15 minutes when mister is activated
// if humidity > set_value: activate FansOut to 100% & FansIn to PWM 50%
// ==B.Every 10 seconds, Measure Temperature of 3 sensors (Top,Middle,Bottom) and control fans
// if temperature < set_value, and time = daytime: adjust PWM FansIn to (50-100%, dependend on gap from set_value)
// ==C.Synchronize Fans with lights on/off
// if light 3 is off (signal from GPIO controller2)
// then turn off FansIn, and turn on FansOut on PWM 50%
// ==D. Display status on OLED
// Scroll OLED display every 10 seconds:
// Temperature 1,2,3 + average temperature
// Humidity + last time mister was acitvated
// Fans Status In/Out
// Time of day
//=available functions
// GetCurrentTime();
// MeasureTempTop();
// MeasureTempMiddle();
// MeasureTempBottom();
// MeasureHumidity();
// ActivateMister();
// PauseMisterFunction();
// ActivateFansOut();
// ActivateFansIn();
// DeactivateFansOut();
// DeactivateFansIn();
// DisplayOled();
}
//===FUNCTIONS
void GetCurrentTime(){
}
void MeasureTempTop(){
}
void MeasureTempMiddle(){
}
void MeasureTempBottom(){
}
void MeasureHumidity (){
}
void ActivateMister(){
}
void PauseMisterFunction(){
}
void ActivateFansIn(){
}
void ActivateFansOut(){
}
void DeactivateFansIn(){
}
void DeactivateFansOut(){
}
void DisplayOled(){
}
I'm looking for a solution for the following objective:
I want to measure and display the humidity every 10 seconds. And when the measurement reaches a certain threshold, to activate either mister or fans. But I would like a pause of about 15 (or X) minutes after this activation. To prevent constant misting or fanning... So like a 'cooldown'. Meanwhile, during that cooldown keep measuring and displaying the humidity.
Do I create something like a 'timestamp' when I activate the mister or fans? And then add the 15 minutes to that timestamp into a temporary variable?
The code is working now. You can check it in serial.
6 states:
S_MISTER_IDLE, // 0
S_MISTER_ON, // 1 turns GPIO ON
S_MISTER_SETSTART, // 2 set starting time
S_MISTER_ACTIVE, // 3 starts counting the time when ON
S_MISTER_OFF, // 4 turns GPIO OFF
S_MISTER_PAUSE // 5 starts counting the time to disable/pause mister.
I got a little help from a friend. I was stuck counting the Millis, because I was not executing the count in the main loop.
typedef enum {
S_MISTER_IDLE, // 0
S_MISTER_ON, // 1
S_MISTER_SETSTART, // 2
S_MISTER_ACTIVE, // 3
S_MISTER_OFF, // 4
S_MISTER_PAUSE // 5
} misterState_t;
static misterState_t state = S_MISTER_IDLE;
bool requestMist = false;
const long misterDuration = 5000; // 15 sec, duration mister is active in millis
const long misterDisabled = 5000; // 15 min, duration of disabled mister in millis
unsigned long misterOnTime = 0; //time in millis when mister was activated
unsigned long misterPauseTime = 0; //time in millis when mister was paused
int misterPin = 13; //set GPIO mister
unsigned long currentMillis = 0;
// script om tijd op te vragen? en die dan gebruiken om
// OLED display te laten zien wanneer voor het laatste gemist is.
void setup() {
Serial.begin(115200);
pinMode(misterPin,OUTPUT); // set misterpin output
Serial.println("SETUP COMPLETED");
}
void processMisterFSM() {
//unsigned long currentMillis = millis();
switch (state) {
case S_MISTER_IDLE: // mister waiting for activation
digitalWrite(misterPin, LOW); // safety GPIO state
if(requestMist) {
requestMist = false;
Serial.println("IN STATE 1 - S_MISTER_IDLE");
state = S_MISTER_ON;
}
break;
case S_MISTER_ON: // turn on mister GPIO
digitalWrite(misterPin, HIGH);
Serial.println("IN STATE 1 - S_MISTER_ON - MISTER ON!");
state = S_MISTER_SETSTART;
break;
case S_MISTER_SETSTART: // set start misting time
misterOnTime = currentMillis;
Serial.println(misterOnTime);
Serial.println("IN STATE 1 - S_MISTER_SETSTART - MISTER ON!");
state = S_MISTER_ACTIVE;
break;
case S_MISTER_ACTIVE: // counting time while mister is active
Serial.println("IN STATE 1 - S_MISTER_ACTIVE - MISTER ON!");
if (currentMillis - misterOnTime >= misterDuration) {
Serial.println("SWITCHING OFF - to S_MISTER_OFF");
state = S_MISTER_OFF;
}
break;
case S_MISTER_OFF: // turn off mister GPIO
digitalWrite(misterPin, LOW);
misterPauseTime = currentMillis;
Serial.println("IN STATE 1 - S_MISTER_OFF");
state = S_MISTER_PAUSE;
break;
case S_MISTER_PAUSE: // counting time while mister is disabled
Serial.println("IN STATE 1 - S_MISTER_PAUSE");
if (currentMillis - misterPauseTime >= misterDisabled) {
//millis can pass through 0, it's the difference that counts for misterDisabled (=safe)
Serial.println("GOING TO IDLE STATE");
state = S_MISTER_IDLE;
}
break;
default:
state = S_MISTER_IDLE;
}
}
void loop() {
processMisterFSM();
if(true) { //measuring humidity level threshold example: < 80 %H
requestMist = true;
}
currentMillis = millis();
Serial.println("IN LOOP");
Serial.println(misterOnTime);
Serial.println(misterPauseTime);
Serial.println(currentMillis);
delay(100);
}