#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/pwm.h"
#include "hardware/i2c.h"
#include <math.h>

// Definições de pinos e parâmetros
#define POT_PIN 26         // Pino do sensor de umidade do solo
#define TEMP_SENSOR_PIN 27 // Pino do sensor de temperatura NTC
#define LDR_PIN 28         // Pino do sensor de luminosidade (LDR)
#define MOTOR_PIN 15       // Pino do PWM para o motor
#define IRRIGATION_PIN 14  // Pino de controle da irrigação
#define ADC_MAX 4095       // Resolução do ADC (12 bits)
#define VCC 3.3            // Tensão de referência
#define R_SERIES 10000.0   // Resistor em série (10kΩ)
#define BETA 3950.0        // Coeficiente beta do termistor
#define T0 298.15          // Temperatura de referência (25°C em Kelvin)
#define R0 10000.0         // Resistência a 25°C (10kΩ)
#define DS1307_ADDR 0x68   // Endereço I²C do DS1307
#define I2C_PORT i2c0      // Porta I²C
#define PIN_SDA 4          // Pino SDA
#define PIN_SCL 5          // Pino SCL

// Parâmetros de controle
const float UMIDADE_MIN = 70.0;  // Umidade mínima para irrigação (%)
const float TEMP_REF = 25.0;     // Temperatura de referência (°C)
const float TEMP_FATOR = 0.04;   // 4% de aumento por grau acima de 25°C

// Função para configurar o horário no DS1307
uint8_t dec_to_bcd(uint8_t val) {
    return ((val / 10) << 4) | (val % 10);
}

uint8_t bcd_to_dec(uint8_t val) {
    return ((val >> 4) * 10) + (val & 0x0F);
}

void ds1307_set_time(uint8_t hour, uint8_t min, uint8_t sec) {
    uint8_t data[4];
    data[0] = 0x00;
    data[1] = dec_to_bcd(sec);
    data[2] = dec_to_bcd(min);
    data[3] = dec_to_bcd(hour);
    i2c_write_blocking(I2C_PORT, DS1307_ADDR, data, 4, false);
    printf("Hora configurada: %02d:%02d:%02d\n", hour, min, sec);
}

void ds1307_read_time(uint8_t *hour, uint8_t *min, uint8_t *sec) {
    uint8_t data[1] = {0x00};
    uint8_t buffer[3];
    i2c_write_blocking(I2C_PORT, DS1307_ADDR, data, 1, true);
    i2c_read_blocking(I2C_PORT, DS1307_ADDR, buffer, 3, false);
    *sec = bcd_to_dec(buffer[0] & 0x7F);
    *min = bcd_to_dec(buffer[1]);
    *hour = bcd_to_dec(buffer[2] & 0x3F);
}

void setup_i2c() {
    i2c_init(I2C_PORT, 100 * 1000);
    gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
    gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
    gpio_pull_up(PIN_SDA);
    gpio_pull_up(PIN_SCL);
    sleep_ms(1000);
}

void setup_pwm(uint pin) {
    gpio_set_function(pin, GPIO_FUNC_PWM);
    uint slice_num = pwm_gpio_to_slice_num(pin);
    pwm_config config = pwm_get_default_config();
    pwm_config_set_clkdiv(&config, 488.0f);
    pwm_config_set_wrap(&config, 255);
    pwm_init(slice_num, &config, true);
    pwm_set_gpio_level(pin, 0);
}

// Função para ler a umidade do solo
float read_soil_moisture() {
    adc_select_input(0);
    uint16_t raw = adc_read();
    return (raw * 100.0f) / ADC_MAX;
}

// Função para ler a temperatura
float read_temperature() {
    adc_select_input(1);
    float voltage = (adc_read() * VCC) / ADC_MAX;
    float resistance = (R_SERIES * voltage) / (VCC - voltage);
    float temp_k = 1.0 / (log(resistance / R0) / BETA + 1.0 / T0);
    return temp_k - 273.15;
}

// Função para ler a luminosidade
float read_luminosity() {
    adc_select_input(2);
    uint16_t raw = adc_read();
    return (raw * VCC) / ADC_MAX;  // Retorna a tensão lida
}


int main() {
    stdio_init_all();
    adc_init();
    adc_gpio_init(POT_PIN);
    adc_gpio_init(TEMP_SENSOR_PIN);
    adc_gpio_init(LDR_PIN);
    gpio_init(IRRIGATION_PIN);
    gpio_set_dir(IRRIGATION_PIN, GPIO_OUT);
    setup_pwm(MOTOR_PIN);
    setup_i2c();

    ds1307_set_time(6, 30, 45);

    while (true) {
        float umidade = read_soil_moisture();
        float temp = read_temperature();
        float luminosity = read_luminosity();
        uint8_t duty = 0;
        uint8_t hour, min, sec;

        ds1307_read_time(&hour, &min, &sec);

        if (hour >= 6 && hour < 8) {
            gpio_put(IRRIGATION_PIN, 1);
            printf("Irrigação: LIGADA\n");
        } else {
            gpio_put(IRRIGATION_PIN, 0);
            printf("Irrigação: DESLIGADA\n");
        }

        if (umidade < UMIDADE_MIN && hour >= 6 && hour < 8) {
            float deficit = UMIDADE_MIN - umidade;
            float base_duty = (deficit / UMIDADE_MIN) * 255.0f;
            if (temp > TEMP_REF) {
                float temp_ajuste = 1.0 + (temp - TEMP_REF) * TEMP_FATOR;
                base_duty *= temp_ajuste;
            }
            duty = (uint8_t)fminf(base_duty, 255.0f);
        }

        if(luminosity <= 0.04){

          printf("\nAtenção! Luminosidade Excessiva 🚨\n");

        }

        pwm_set_gpio_level(MOTOR_PIN, duty);
        printf("Hora: %02d:%02d:%02d | Umidade: %.1f%% | Temp: %.1f°C | PWM: %d\n",
               hour, min, sec, umidade, temp, duty);

        sleep_ms(5000);
    }
}
GND5VSDASCLSQWRTCDS1307+