#include <ArduinoJson.h>
#include <EEPROM.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // can be removed as it isn't compatible with Arduino
// This program is a simulator for the indoor farm at the University of Baltimore. After
// verifying that you're connected with the arduino or to the simulator, you can prompt for
// specific values as they change over time. The values will also automatically update every 5 minutes.
// by Tara Vickers and Eric Williams, 2024
// Constants
const int LIGHT1_PIN = 4;
const int LIGHT2_PIN = 5;
const int PUMP_PIN = 8;
const int DHTPIN = 7;
#define DHTTYPE DHT22
const int THERMISTER_PIN = A2;
const int EC_PIN = A1;
const int PH_PIN = A8;
const int WATER_LEVEL_PIN = A3;
const int PH_SAMPLING_INTERVAL = 20;
const int PH_SAMPLING_NUMBER = 40;
const int PRINT_INTERVAL = 800;
bool found = false;
// Simulator constants
const int lux = 300;
// Control for pump run length (in milliseconds)
int PUMP_TIME = 1000;
// Message flow variables
String sending;
String sensor;
int state = 0;
// Sensor variables
float hum = 45;
float reading = 21;
float temp = 25;
float fahrenheit;
int water_level_reading = 600;
int pH_array[PH_SAMPLING_NUMBER];
int pH_index = 0;
float voltage, ecValue, temperature = 25;
float pHValue = 0.0;
// Light variables
bool lights_status = false;
char lights_color[10] = "blue";
// Wavelength structure for light colors
struct LightWavelength {
char color[10];
int wavelength;
};
struct LightWavelength light_wavelengths[7] = {
{"red", 650},
{"orange", 600},
{"yellow", 580},
{"green", 550},
{"cyan", 500},
{"blue", 450},
{"violet", 400}
};
// Light functions
void lights_on(bool status, const char* color) {
lights_status = status;
bool light_time = true;
strncpy(lights_color, color, sizeof(lights_color) - 1);
// Timer for light cycle (every 3 hours)
while (light_time) {
int lux = 300;
//delay(10800000); // sleep(10800000);
// Simulate lux value changes
lux = 0;
//delay(10800000);
}
}
int read_wavelength() {
int wavelength = 0;
for (int i = 0; i < sizeof(light_wavelengths) / sizeof(light_wavelengths[0]); i++) {
if (strcmp(light_wavelengths[i].color, lights_color) == 0) {
wavelength = light_wavelengths[i].wavelength;
break;
}
}
return wavelength + (rand() % (5 + (-5) + 1) + (-5));
}
// Sensor reading functions
double readAirTemperature() {
if ((lux == 300) && (temp <= 30)) { // as the lights stay on, the temp rises
temp = temp + 2;
//delay(300000); // sleep(300000);
//delay(30);
return temp;
}
if ((lux == 0) && (temp >= 25)) {
temp = temp - 2;
return temp;
//delay(300000); // sleep(300000);
}
}
double readWaterLevel() {
//double new_water_level_reading;
if ((lux == 300) && (water_level_reading >= 316)) { // as the lights stay on, water level decreases
water_level_reading -= (0.5 * water_level_reading);
//delay(300000); // sleep(300000);
return (double) water_level_reading;
}
}
double Conductivity(double initialEC, double initialWaterLevel, double currentWaterLevel) {
if (currentWaterLevel <= 0) {// Prevent division by zero
return -1;
}
double concentration = initialWaterLevel / currentWaterLevel;// Calculate the concentration
double adjustedEC = initialEC * concentration;// Adjust EC based on the concentration
return adjustedEC;
}
double readElectricConductivity() {
double initialEC = 300.0; // Initial EC of water in µS/cm
double initialWaterLevel = 600.0; // Initial water level in mL
double currentLevel = 600.0; //simulation input for different water levels
//double currentLevel = readWaterLevel(); // Function to get the current water level
return Conductivity(initialEC, initialWaterLevel, currentLevel);
}
double readVisibleLight() {
return 300; // Simulated UV sensor reading
}
double readPH() {
if ((lux == 300) && pHValue <= 414.12) {
pHValue += 50.00;
//delay(300000); // sleep(300000);
return (double) pHValue;
}
}
double sim_readAirHumidity() { // humidity increases as temp increases, temp increases by lux
if ((lux == 300) && (hum <= 100)){
hum += 1;
//delay(300000); // sleep(300000);
return hum;
}
if ((lux == 0) && (hum >= 45)) {
hum -= 1;
//delay(300000); // sleep(300000);
return hum;
}
return hum;
}
double readWaterTemperature() { // water temp increases as lights stay on
if ((lux == 300) && (reading <= 25)) {
reading += 1;
//delay(300000); // sleep(300000);
return reading;
}
if ((lux == 0) && (reading >= 21)) {
reading -= 1;
//delay(300000); // sleep(300000);
return reading;
}
}
double averageArray(int* arr, int number){
int amount = 0;
for(int i = 0; i < number; i++) {
amount += arr[i];
}
return (double) amount / number;
}
// begin serial
void setup() {
Serial.begin(9600);
Serial.println("Welcome to the Serial Monitor!");
pinMode(LIGHT1_PIN, OUTPUT);
pinMode(LIGHT2_PIN, OUTPUT);
pinMode(PUMP_PIN, OUTPUT);
}
// check if serial is available
void loop() {
while (!found) {
if (Serial.available() > 0) {
String sync_message = Serial.readStringUntil('\n');
if (sync_message == "Old MacDonald") {
// output every 5 minutes
found = true;
while(true) {
Serial.println("had a farm");
Serial.println("Air Temperature: ");
Serial.println(readAirTemperature());
Serial.println("Water Level: ");
Serial.println(readWaterLevel());
Serial.println("Air Humidity: ");
Serial.println(sim_readAirHumidity());
Serial.println("Water Temperature: ");
Serial.println(readWaterTemperature());
Serial.println("PH Level: ");
Serial.println(readPH());
Serial.println("Light Level: ");
Serial.println(readVisibleLight());
Serial.println("Electric Conductivity: ");
Serial.println(readElectricConductivity());
//delay(300000);
delay(10000);
}
}
}
}
if (Serial.available() > 0) {
String request = Serial.readStringUntil('\n');
DynamicJsonDocument serialDoc(2048);
DeserializationError err = deserializeJson(serialDoc, request);
if (err) {
Serial.print("Error Parsing JSON");
return;
}
JsonObject toSerial = serialDoc.as<JsonObject>();
sensor = serialDoc["sensor"].as<String>();
// statements to output reading based on command
if (sensor == "airTemp") {
toSerial["value"] = readAirTemperature();
} else if (sensor == "humidity") {
toSerial["value"] = sim_readAirHumidity();
} else if (sensor == "lightCheck") {
toSerial["value"] = readVisibleLight();
} else if (sensor == "waterTemp") {
toSerial["value"] = readWaterTemperature();
} else if (sensor == "PH") {
toSerial["value"] = readPH();
} else if (sensor == "EC") {
toSerial["value"] = readElectricConductivity();
} else if (sensor == "waterLevel") {
toSerial["value"] = readWaterLevel();
} else if (sensor == "light1") {
state = int(serialDoc["value"]);
digitalWrite(LIGHT1_PIN, state);
} else if (sensor == "light2") {
state = int(serialDoc["value"]);
digitalWrite(LIGHT2_PIN, state);
} else if (sensor == "pump") {
PUMP_TIME = int(serialDoc["value"]);
digitalWrite(PUMP_PIN, HIGH);
delay(PUMP_TIME);
digitalWrite(PUMP_PIN, LOW);
}
serializeJson(serialDoc, sending);
Serial.println(sending);
sending = "";
}
}