#include "pico/stdlib.h"
#include "lcd.h"
#include "servo.h"
#include "pir.h"
#include "dht22.h"
#include "relay.h"
#include "soil_moisture.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SERVO_PIN 16
#define PIR_PIN 2
#define PIR_LED 3
#define DHT_PIN 20
#define RELAY_PIN 15
typedef enum {
PERF_LOW,
PERF_MID,
PERF_HIGH
} performance_t;
typedef struct {
bool active;
uint64_t end_time;
uint64_t last_toggle;
bool relay_on;
uint32_t on_ms;
uint32_t off_ms;
} watering_t;
static watering_t watering = {0};
static performance_t current_zone = PERF_LOW;
static bool watering_allowed = true; // Enable auto-watering at start
static bool manual_override = false;
void update_servo(performance_t perf) {
int angle = 0;
switch(perf) {
case PERF_LOW: angle = 30; break;
case PERF_MID: angle = 90; break;
case PERF_HIGH: angle = 150; break;
}
servo_set_angle(SERVO_PIN, angle);
printf("[Main] Performance %d -> Angle %d\n", perf, angle);
}
void watering_start(uint pin, performance_t perf) {
watering.active = true;
watering.relay_on = true;
watering.last_toggle = time_us_64();
watering.end_time = watering.last_toggle + 30ULL * 1000000;
switch(perf) {
case PERF_LOW: watering.on_ms = 200; watering.off_ms = 800; break;
case PERF_MID: watering.on_ms = 500; watering.off_ms = 500; break;
case PERF_HIGH: watering.on_ms = 800; watering.off_ms = 200; break;
}
relay_set_state(pin, true);
update_servo(perf);
printf("[Watering] START\n");
}
void watering_stop(uint pin) {
watering.active = false;
watering_allowed = false;
relay_set_state(pin, false);
printf("[Watering] STOP\n");
switch(current_zone) {
case PERF_LOW: current_zone = PERF_MID; break;
case PERF_MID: current_zone = PERF_HIGH; break;
case PERF_HIGH: current_zone = PERF_LOW; break;
}
update_servo(current_zone);
}
void watering_update(uint pin) {
if (!watering.active) return;
uint64_t now = time_us_64();
if (now >= watering.end_time) {
watering_stop(pin);
return;
}
uint64_t period = watering.relay_on ?
(uint64_t)watering.on_ms * 1000 :
(uint64_t)watering.off_ms * 1000;
if (now - watering.last_toggle >= period) {
watering.relay_on = !watering.relay_on;
relay_set_state(pin, watering.relay_on);
watering.last_toggle = now;
}
static uint64_t last_lcd_update = 0;
if (now - last_lcd_update >= 1000000) {
int seconds_left = (int)((watering.end_time - now + 500000) / 1000000);
lcd_show_readings(0.0, 0.0, 0.0, seconds_left);
last_lcd_update = now;
}
}
int main() {
stdio_init_all();
srand(time(NULL));
gpio_init(PIR_LED);
gpio_set_dir(PIR_LED, true);
sleep_ms(1000);
printf("=== Modular Demo Start ===\n");
printf("Type '1' to start watering (30s max), '0' to stop, 'a' to reset auto\n");
lcd_init_display();
servo_init(SERVO_PIN);
pir_init(PIR_PIN);
relay_init(RELAY_PIN);
dht22_init(DHT_PIN);
soil_moisture_init();
gpio_put(PIR_LED, 0);
int test_angles[] = {0, 90, 150};
for(int i = 0; i < 3; i++) {
servo_set_angle(SERVO_PIN, test_angles[i]);
printf("[Servo Test] Moving to %d degrees\n", test_angles[i]);
sleep_ms(1000);
}
lcd_clear();
lcd_set_cursor(0, 0);
lcd_print("System Ready");
sleep_ms(2000);
int dht_read_counter = 0;
while(true) {
bool motion = pir_motion_detected(PIR_PIN);
gpio_put(PIR_LED, motion ? 1 : 0);
if(motion) printf("[PIR] Motion detected!\n");
int c = getchar_timeout_us(0);
if(c == '1') {
printf("[Manual] Watering START\n");
watering_allowed = true;
manual_override = true;
watering_start(RELAY_PIN, current_zone);
} else if(c == '0') {
printf("[Manual] Watering STOP\n");
manual_override = true;
watering_stop(RELAY_PIN);
} else if(c == 'a') {
printf("[Manual] Resetting auto-watering\n");
manual_override = false;
watering_allowed = true;
}
if(dht_read_counter % 4 == 0) {
dht22_data_t dht = dht22_read(DHT_PIN);
soil_moisture_data_t soil = soil_moisture_read();
if (dht.valid) {
printf("[DHT22] Temp: %.1f C, Hum: %.1f %%\n", dht.temperature, dht.humidity);
for(int i = 0; i < 3; i++) {
printf("[Soil] Zone %d ADC: %d Moisture: %.1f%%\n", i+1, soil.adc_values[i], soil.moisture[i]);
}
printf("[Soil] Dry zones: %d\n", soil.dry_count);
if(watering_allowed && !manual_override && !watering.active && dht.valid && dht.temperature >= 15.0 && soil.dry_count > 0) {
printf("[Auto] Watering due to dry zones\n");
watering_start(RELAY_PIN, soil.dry_count == 1 ? PERF_LOW : soil.dry_count == 2 ? PERF_MID : PERF_HIGH);
}
} else {
printf("[DHT22] Read failed\n");
}
if (!watering.active && dht.valid) {
float avg_moisture = (soil.moisture[0] + soil.moisture[1] + soil.moisture[2]) / 3.0;
lcd_show_readings(dht.temperature, dht.humidity, avg_moisture, 0);
} else if (!watering.active && !dht.valid) {
lcd_clear();
lcd_set_cursor(0, 0);
lcd_print("DHT22 Error");
lcd_set_cursor(0, 1);
lcd_print("Sprinkler: OFF");
printf("[LCD] Displaying: DHT22 Error, Sprinkler: OFF\n");
}
}
watering_update(RELAY_PIN);
dht_read_counter++;
sleep_ms(500);
}
return 0;
}