diff --git a/soler_chager.ino b/soler_chager.ino index b8e7ff2..7f5e901 100644 --- a/soler_chager.ino +++ b/soler_chager.ino @@ -9,6 +9,7 @@ #define photoL2 A1 #define photoL3 A2 #define photoL4 A3 +#define batteryPin A6 #define button 3 #define buzzer 6 #define circleServoPin 10 @@ -18,12 +19,18 @@ #define TILT_ANGLE_FLAT 0 #define TILT_ANGLE_MAX 170 +#define TURN_L1 0 +#define TURN_L2 45 #define TURN_L3 180 #define TURN_L4 90 -#define TURN_L1 0 #define SERVO_STEP 5 +// Battery monitoring constants +#define BATTERY_MIN_VOLTAGE 10.5 // Minimum safe voltage for 12V battery (1.75V per cell) +#define BATTERY_MAX_VOLTAGE 14.4 // Maximum charging voltage for 12V battery (2.4V per cell) +#define BATTERY_FULL_VOLTAGE 12.6 // Full charge voltage for 12V battery (2.1V per cell) + byte m_speed = 10; BH1750 lightMeter; dht11 DHT; @@ -32,6 +39,8 @@ volatile int lightReadL1 = 0; // EAST FACING volatile int lightReadL2 = 0; // NORTH FACING volatile int lightReadL3 = 0; // WEST FACING volatile int lightReadL4 = 0; // SOUTH FACING +float batteryVoltage = 0.0; +int batteryPercentage = 0; int value; LiquidCrystal_I2C lcd(0x27, 16, 2); Servo circleServo; @@ -39,6 +48,16 @@ Servo tiltServo; int tiltPos; int circlePos; +// Charging states +enum ChargingState { + NOT_CHARGING, + CHARGING, + FULLY_CHARGED, + ERROR +}; + +ChargingState chargingState = NOT_CHARGING; + void setup() { Serial.begin(9600); @@ -56,21 +75,28 @@ void setup() pinMode(LED, OUTPUT); //initialize digital pin LED as an output. pinMode(button, INPUT); pinMode(buzzer, OUTPUT); + pinMode(batteryPin, INPUT); - circleServo.attach(circleServoPin); + // Initialize servos with error checking + if (!circleServo.attach(circleServoPin)) { + Serial.println("Error: Failed to attach circle servo"); + } circleServo.write(TURN_L4); Serial.print("circle pos: "); Serial.print(TURN_L4); Serial.println(""); delay(1000); - tiltServo.attach(tiltServoPin); + if (!tiltServo.attach(tiltServoPin)) { + Serial.println("Error: Failed to attach tilt servo"); + } tiltServo.write(0); Serial.print("tilt pos: "); Serial.print(TILT_ANGLE_FLAT); Serial.println(""); delay(1000); + // Test servo movement if (false) { circleServo.write(TURN_L3); delay(1000); @@ -93,27 +119,262 @@ void setup() lcd.setCursor(0,0); lcd.printstr("done"); - //Intialize the 12C bus + //Initialize the I2C bus Wire.begin(); //On esp8266 you can select SCL and SDA pins using Wire.begin //For Wemos /Lolin D1 Mini Pro and the Ambient Light shield use - lightMeter.begin(); - Serial.println(F("BH1750 Test begin")); + if (!lightMeter.begin()) { + Serial.println("Error: Failed to initialize BH1750 sensor"); + lcd.setCursor(0,1); + lcd.printstr("Light ERR"); + } else { + Serial.println(F("BH1750 Test begin")); + } } long long count = 0; + +// Function to find the direction with maximum light +int findBrightestDirection() { + int maxLight = 0; + int direction = 0; + + if (lightReadL1 > maxLight) { + maxLight = lightReadL1; + direction = 1; // East + } + if (lightReadL2 > maxLight) { + maxLight = lightReadL2; + direction = 2; // North + } + if (lightReadL3 > maxLight) { + maxLight = lightReadL3; + direction = 3; // West + } + if (lightReadL4 > maxLight) { + maxLight = lightReadL4; + direction = 4; // South + } + + return direction; +} + +// More sophisticated solar tracking algorithm +void adjustPanelPosition() { + int direction = findBrightestDirection(); + + // Current positions + int currentCirclePos = circleServo.read(); + int currentTiltPos = tiltServo.read(); + + // Determine target positions + int targetCirclePos = currentCirclePos; + int targetTiltPos = currentTiltPos; + + switch (direction) { + case 1: // East + targetCirclePos = TURN_L1; + break; + case 2: // North + targetCirclePos = TURN_L2; + break; + case 3: // West + targetCirclePos = TURN_L3; + break; + case 4: // South + targetCirclePos = TURN_L4; + break; + default: + // Stay in current position + break; + } + + // Adjust tilt based on light intensity + // Simple algorithm: more light = more tilt up to max + int avgLight = (lightReadL1 + lightReadL2 + lightReadL3 + lightReadL4) / 4; + targetTiltPos = map(avgLight, 0, 1023, 0, TILT_ANGLE_MAX); + targetTiltPos = constrain(targetTiltPos, 0, TILT_ANGLE_MAX); + + // Move servos gradually to target positions to avoid jerky movement + // Only move if there's a significant difference + if (abs(targetCirclePos - currentCirclePos) > SERVO_STEP) { + int newPos = currentCirclePos; + if (targetCirclePos > currentCirclePos) { + newPos = currentCirclePos + SERVO_STEP; + } else { + newPos = currentCirclePos - SERVO_STEP; + } + circleServo.write(newPos); + Serial.print("Adjusted circle servo to: "); + Serial.println(newPos); + } + + if (abs(targetTiltPos - currentTiltPos) > SERVO_STEP) { + int newPos = currentTiltPos; + if (targetTiltPos > currentTiltPos) { + newPos = currentTiltPos + SERVO_STEP; + } else { + newPos = currentTiltPos - SERVO_STEP; + } + tiltServo.write(newPos); + Serial.print("Adjusted tilt servo to: "); + Serial.println(newPos); + } +} + +// Function to implement charging safety measures +void chargingSafetyCheck() { + // If battery is fully charged, stop charging + if (chargingState == FULLY_CHARGED) { + // In a real implementation, this would control a charging circuit + // For now, we'll just indicate it with the LED + digitalWrite(LED, HIGH); + if (count % 15 == 0) { // Every 30 seconds + tone(buzzer, 1500, 300); // Higher pitch short beep + } + } + + // If battery voltage is too high or too low, indicate error + if (chargingState == ERROR) { + // Flash LED rapidly to indicate error + for (int i = 0; i < 5; i++) { + digitalWrite(LED, HIGH); + delay(200); + digitalWrite(LED, LOW); + delay(200); + } + // Continuous beep for error + if (count % 10 == 0) { // Every 20 seconds + tone(buzzer, 300, 1000); + } + } +} + +// Function to check for extreme environmental conditions +bool isEnvironmentSafe() { + // Check for extreme temperatures + if (CtoF(DHT.temperature) > 104 || CtoF(DHT.temperature) < 32) { + // Temperature outside safe charging range (32°F to 104°F) + return false; + } + + // Check for extremely high humidity which might affect electronics + if (DHT.humidity > 85) { + return false; + } + + return true; +} + void loop() { char buf[40]; - //lcd.clear(); - //lcd.setCursor(0,0); - - sprintf(buf, "count: %d\n", count); + // Read sensor values with error checking + int chk = DHT.read(DHT11_PIN); + switch (chk) + { + case DHTLIB_OK: + // All good, continue + break; + case DHTLIB_ERROR_CHECKSUM: + Serial.println("[ERR] dht11 checksum"); + lcd.setCursor(0,0); + lcd.printstr("DHT11 ERR"); + break; + case DHTLIB_ERROR_TIMEOUT: + Serial.println("[ERR] dht11 timeout"); + lcd.setCursor(0,0); + lcd.printstr("DHT11 TO"); + break; + default: + Serial.println("[ERR] dht11 unknown"); + lcd.setCursor(0,0); + lcd.printstr("DHT11 UNK"); + break; + } + + float lux = lightMeter.readLightLevel(); + if (lux == -1) { + Serial.println("[ERR] BH1750 read error"); + lcd.setCursor(0,0); + lcd.printstr("Light ERR"); + } + + lightReadL1 = analogRead(photoL1); + lightReadL2 = analogRead(photoL2); + lightReadL3 = analogRead(photoL3); + lightReadL4 = analogRead(photoL4); + + // Read battery status + batteryVoltage = readBatteryVoltage(); + batteryPercentage = calculateBatteryPercentage(batteryVoltage); + chargingState = getChargingState(batteryVoltage); + + // Display sensor readings + char lStr[6]; + dtostrf(lux, 4, 2, lStr); + sprintf(buf, "h:%d,t:%dF,l:%s", DHT.humidity, CtoF(DHT.temperature), lStr); Serial.print(buf); - //lcd.printstr(buf); - + + sprintf(buf, " L1:%d,L2:%d", lightReadL1, lightReadL2); + Serial.println(buf); + + sprintf(buf, " L3:%d,L4:%d", lightReadL3, lightReadL4); + Serial.println(buf); + + char vStr[6]; + dtostrf(batteryVoltage, 4, 2, vStr); + sprintf(buf, " Batt:%sV %d%%", vStr, batteryPercentage); + Serial.println(buf); + + // Update LCD display + lcd.clear(); + lcd.setCursor(0,0); + sprintf(buf, "h:%d,t:%dF,l:%s", DHT.humidity, CtoF(DHT.temperature), lStr); + lcd.printstr(buf); + + // Display battery status on second line + displayBatteryStatus(); + + // Adjust solar panel position only if environment is safe + if (isEnvironmentSafe()) { + adjustPanelPosition(); + } else { + // Display environmental warning + lcd.setCursor(0,1); + lcd.printstr("ENV ERROR"); + } + + // Perform charging safety checks + chargingSafetyCheck(); + + // Check button state + buttonState = digitalRead(button); + if(buttonState == 0) { + analogWrite(LED, HIGH); + tone(buzzer, 1000, 100); // Short beep + delay(500); // Debounce + } else { + // Only turn off LED if not in error or full charge state + if (chargingState != ERROR && chargingState != FULLY_CHARGED) { + digitalWrite(LED, LOW); + } + } + + // Safety check for battery voltage - beep every 10 seconds if there's an issue + if ((batteryVoltage < BATTERY_MIN_VOLTAGE || batteryVoltage > BATTERY_MAX_VOLTAGE) && count % 5 == 0) { + // Alert user to battery problem (every 10 seconds with 2 second delay) + tone(buzzer, 500, 500); + digitalWrite(LED, HIGH); + delay(500); + if (chargingState != FULLY_CHARGED) { // Don't turn off if fully charged + digitalWrite(LED, LOW); + } + } + count++; + delay(2000); // Update every 2 seconds } @@ -181,6 +442,64 @@ void old_loop() } } +// Function to read battery voltage +float readBatteryVoltage() { + int sensorValue = analogRead(batteryPin); + // Convert the analog reading to voltage + // Assuming a voltage divider circuit that scales 12V to 5V range + float voltage = sensorValue * (12.0 / 1023.0); + return voltage; +} + +// Function to calculate battery percentage +int calculateBatteryPercentage(float voltage) { + // Simple linear mapping between min and max voltages + int percentage = map(voltage * 100, BATTERY_MIN_VOLTAGE * 100, BATTERY_FULL_VOLTAGE * 100, 0, 100); + return constrain(percentage, 0, 100); +} + +// Function to determine charging state +ChargingState getChargingState(float voltage) { + if (voltage < BATTERY_MIN_VOLTAGE) { + return ERROR; + } else if (voltage >= BATTERY_FULL_VOLTAGE) { + return FULLY_CHARGED; + } else if (voltage > BATTERY_MIN_VOLTAGE && voltage < BATTERY_FULL_VOLTAGE) { + return CHARGING; + } else { + return NOT_CHARGING; + } +} + +// Function to display battery status on LCD +void displayBatteryStatus() { + char buf[40]; + char vStr[6]; + dtostrf(batteryVoltage, 4, 2, vStr); + + lcd.setCursor(0,1); + + // Display different messages based on charging state + switch (chargingState) { + case NOT_CHARGING: + sprintf(buf, "B:%sV %d%% NC", vStr, batteryPercentage); + break; + case CHARGING: + sprintf(buf, "B:%sV %d%% CG", vStr, batteryPercentage); + break; + case FULLY_CHARGED: + sprintf(buf, "B:%sV %d%% FC", vStr, batteryPercentage); + break; + case ERROR: + sprintf(buf, "B:%sV %d%% ER", vStr, batteryPercentage); + break; + default: + sprintf(buf, "B:%sV %d%%", vStr, batteryPercentage); + break; + } + lcd.printstr(buf); +} + void blink() { digitalWrite(LED,HIGH); //turn the LED on (HIGH is the voltage level