import machine
import onewire
import ds18x20
import time

# Define the pins for the temperature sensor, heater, PWM temperature, and PWM setpoint
sensor_pin = machine.Pin(2)
heater_pin = machine.Pin(15, machine.Pin.OUT)
temperature_pwm_pin = machine.Pin(13, machine.Pin.OUT)
setpoint_pwm_pin = machine.Pin(9, machine.Pin.OUT)

# Create a PWM object for the heater control, PWM temperature and PWM setpoint
heater_pwm = machine.PWM(heater_pin)
temperature_pwm = machine.PWM(temperature_pwm_pin)
setpoint_pwm = machine.PWM(setpoint_pwm_pin)

# Create a DS18B20 sensor object
sensor = ds18x20.DS18X20(onewire.OneWire(sensor_pin))
roms = sensor.scan()

# Set the desired temperature, PID constants, and PWM frequency
# You may need to adjust these values based on your system
desired_temperature = 50
proportional_constant = 10
integral_constant = 0.008
differential_constant = 30
pwm_frequency = 350

# Initialize variables for PID control
integral = 0
prev_error = 0

while True:
    sensor.convert_temp()

    for rom in roms:
        # Read the temperature from the sensor
        temperature = sensor.read_temp(rom)

        # Calculate the error (the difference between desired and current temperature)
        error = desired_temperature - temperature

        # Calculate the proportional control output
        proportional_output = proportional_constant * error

        # Accumulate the error for integral control
        integral += error

        # Calculate the integral control output
        integral_output = integral_constant * integral

        # Calculate the rate of change of the error for differential control
        differential = error - prev_erron

        # Calculate the differential control output
        differential_output = differential_constant * differential

        # Calculate the total control output
        total_output = proportional_output + integral_output + differential_output

        # Adjust the heater output based on total control output using PWM
        # Adjust the pwm temperature for 0 to 100 degrees C
        # Adjust the pwm setpoint for 0 to 100 degrees C
        pwm_value = max(0, min(1023, int(total_output)))
        pwm_temp_value = int((temperature / 100) * 1023)
        pwm_setpoint_value = int((desired_temperature / 100) * 1023)

        # duty is represented as a 16-bit value (0-65535)
        heater_pwm.duty_u16(pwm_value* 64)
        temperature_pwm.duty_u16(pwm_temp_value * 64)
        setpoint_pwm.duty_u16(pwm_setpoint_value * 64)

        # Print Setpoint, total output, Proportional, Integral, Differential,
        # Temperature and pwm value to the console
        print("Setpoint:", desired_temperature)
        print("Total Output:", total_output)
        print("Proportional Output:", proportional_output)
        print("Integral Output:", integral_output)
        print("Differential Output:", differential_output)
        print("Temperature:", temperature)
        print("PWM Value:", pwm_value)
        for _ in range(1):
            print("")

        # Update the previous error for the next iteration
        prev_error = error

        # Wait before reading the temperature again
        time.sleep(0.6)