#include "RTClib.h"
#include <DTutils.h>
#include <Servo.h>
#include <AFMotor.h>
#include <LiquidCrystal_I2C.h>
RTC_DS3231 rtc;
AF_Stepper stepper(200, 2);
LiquidCrystal_I2C lcd(0x26, 20, 4);
Servo servo2;
float pi = 3.14159265;
float kwert = pi / 180;
float latitude = 51.222191;
float longitude = 7.954169;
float Elevation; float elevation;
float Aufgang; float Untergang;
float AzS; int AzI;
char buffer[80];
int zeitschritt = 4000;
void setup() {
if (! rtc.begin())
{
lcd.setCursor(1, 1);
lcd.print("Couldn't find RTC");
while (1)
{
delay(10);
}
}
pinMode(A3, INPUT);
pinMode(A2, INPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
servo2.attach(9);
stepper.setSpeed(10);
stepper.release();
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Solartracker v.16.0");
lcd.setCursor(0, 1);
lcd.print("Version vom 23.09.23");
lcd.setCursor(0, 2);
lcd.print("www.mi-schu.de");
lcd.setCursor(0, 3);
lcd.print("/solartracker.htm");
delay(zeitschritt);
lcd.clear();
}
void loop() {
float Temp = float(rtc.getTemperature());
DateTime now = rtc.now();
sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second());
int Jahr = now.year();
int Monat = now.month();
int Tag = now.day();
float Stunde = now.hour();
float Minute = now.minute();
float Sekunde = now.second();
float Deklination;
float Zeitgleichung;
float Zeitdifferenz;
float AufgangOrtszeit;
float UntergangOrtszeit;
float Tageslaenge;
float MEZ; float MOZ; float WOZ;
float ZeitSeitMittag;
float BreiteR = latitude * kwert;
float hoeheSM = -(50.0 / 60.0) * kwert;
int Grenzwert;
int Zeitzone = 1;
int sensorValue;
int yearday;
String wr;
MEZ = Stunde + Minute / 60 + Sekunde / 3600;
yearday = DayOfYear(now.year(), now.month(), now.day());
Zeitgleichung = BerechneZeitgleichung (yearday);
Deklination = BerechneDeklination (yearday);
Zeitdifferenz = BerechneZeitdifferenz (hoeheSM, latitude, kwert, Deklination, pi);
ZeitSeitMittag = MEZ + longitude / 15.0 - Zeitzone - 12 + Zeitgleichung;
AzS = SunAngles(Deklination, BreiteR, ZeitSeitMittag, Elevation);
Elevation = Elevation / kwert;
Tageslaenge = BerechneTageslaenge (Zeitdifferenz, Zeitgleichung, longitude, Zeitzone, Aufgang, Untergang);
MOZ = MEZ - (-longitude / 15) - 1;
WOZ = MOZ + Zeitgleichung;
int WOZdez = (int)WOZ;
int WOZmin = (WOZ - WOZdez) * 60;
int MOZdez = (int)MOZ;
int MOZmin = (MOZ - MOZdez) * 60;
int StdL = (int)Tageslaenge;
int MinL = (int)((Tageslaenge - StdL) * 60);
int StdA = (int)Aufgang;
int MinA = (int)((Aufgang - StdA) * 60);
int StdU = (int)Untergang;
int MinU = (int)((Untergang - StdU) * 60);
switch (StdL) {
case 7 ... 8:
Grenzwert = 135; break;
case 9 ... 10:
Grenzwert = 115; break;
case 11 ... 12:
Grenzwert = 95; break;
case 13 ... 14:
Grenzwert = 75; break;
case 15 ... 16:
Grenzwert = 55; break;
case 17 ... 18:
Grenzwert = 35; break;
}
elevation = map(Elevation, 90, 0, 96, 3);
constrain(elevation, 3, 96);
sensorValue = analogRead(A3);
if (sensorValue >= 121 && sensorValue < 500) {
AzI = map(sensorValue, 248, 503, 90, 180);
}
if (sensorValue >= 500 && sensorValue <= 883) {
AzI = map(sensorValue, 503, 752, 180, 270);
}
constrain(AzI, 40, 320);
float AzSoll = AzS;
AzS = int(AzS);
stepper.release();
if (Elevation > -1) {
servo2.write(elevation);
if (AzI < AzS) {
digitalWrite(14, HIGH);
stepper.step(32, FORWARD, MICROSTEP);
digitalWrite(15, LOW);
stepper.release();
}
if (AzI > AzS) {
digitalWrite(15, HIGH);
stepper.step(32, BACKWARD, MICROSTEP);
digitalWrite(14, LOW);
stepper.release();
}
if (AzI == AzS) {
digitalWrite(15, HIGH);
digitalWrite(14, HIGH);
}
}
else {
if (Elevation < -1 && AzI >= Grenzwert) {
digitalWrite(15, HIGH);
stepper.setSpeed(30);
stepper.step(100, BACKWARD, MICROSTEP);
digitalWrite(14, LOW);
stepper.release();
}
}
int analogPin = A2;
float pvmod;
float volt;
pvmod = analogRead(analogPin);
volt = pvmod / 1023 * 4.75;
int Std = (int)Tageslaenge;
int Min = (int)((Tageslaenge - Std) * 60);
Deklination = Deklination / kwert;
wr = Windrichtung(AzI);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(buffer);
lcd.setCursor(0, 1);
lcd.print("AzS");
lcd.setCursor(4, 1);
lcd.print(AzSoll, 2);
lcd.write(0xDF);
lcd.print(" ");
lcd.setCursor(12, 1);
if (WOZdez < 10) lcd.print("0");
lcd.print(WOZdez);
lcd.print(":");
if (WOZmin < 10) lcd.print("0");
lcd.print(WOZmin);
lcd.print(" WO");
lcd.setCursor(0, 2);
lcd.print("AzI ");
lcd.print(AzI);
lcd.write(0xDF);
lcd.print(wr);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print("Elv");
lcd.setCursor(12, 3);
lcd.setCursor(3, 3);
lcd.print(" ");
lcd.setCursor(4, 3);
lcd.print(Elevation, 2);
lcd.write(0xDF);
lcd.setCursor(12, 2);
lcd.print("TM ");
lcd.print(Temp, 1);
lcd.write(0xDF);
lcd.setCursor(12, 3);
lcd.print("PV ");
lcd.print(volt, 1);
lcd.print(" V");
delay(zeitschritt);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tageslaenge ");
if (Std < 10) lcd.print("0");
lcd.print(Std);
lcd.print(":");
if (Min < 10) lcd.print("0");
lcd.print(Min);
lcd.print(" h");
lcd.setCursor(0, 1);
lcd.print("So.Aufgang ");
if (StdA < 10) lcd.print("0");
lcd.print(StdA);
lcd.print(":");
if (MinA < 10) lcd.print("0");
lcd.print(MinA);
lcd.print(" h");
lcd.setCursor(0, 2);
lcd.print("So.Untergang ");
if (StdU < 10) lcd.print("0");
lcd.print(StdU);
lcd.print(":");
if (MinU < 10) lcd.print("0");
lcd.print(MinU);
lcd.print(" h");
lcd.setCursor(0, 3);
lcd.print("Deklination ");
if (Deklination >= 0 && Deklination < 10) {
lcd.print(" ");
lcd.print(Deklination, 2);
}
if (Deklination >= 10 || Deklination < 0 && Deklination > -10) {
lcd.print(" ");
lcd.print(Deklination, 3);
}
if (Deklination <= -10) lcd.print(Deklination, 3);
lcd.write(0xDF);
delay(zeitschritt);
}
String Windrichtung (int AzI) {
int i;
switch (AzI) {
case 0 ... 11:
i = 0; break;
case 12 ... 34:
i = 1; break;
case 35 ... 56:
i = 2; break;
case 57 ... 79:
i = 3; break;
case 80 ... 101:
i = 4; break;
case 102 ... 124:
i = 5; break;
case 125 ... 146:
i = 6; break;
case 147 ... 169:
i = 7; break;
case 170 ... 191:
i = 8; break;
case 192 ... 214:
i = 9; break;
case 215 ... 236:
i = 10; break;
case 237 ... 259:
i = 11; break;
case 260 ... 281:
i = 12; break;
case 282 ... 304:
i = 13; break;
case 305 ... 326:
i = 14; break;
case 327 ... 349:
i = 15; break;
}
const char* windrichtung[16] = {"N ", "NNO", "NO ", "ONO", "O ", "OSO", "SO ", "SSO", "S ", "SSW", "SW ", "WSW", "W ", "WNW", "NW ", "NNW"};
String wr = windrichtung[i];
return wr;
}
float SunAngles (float Deklination, float BreiteR, float ZeitSeitMittag, float & Elevation) {
float cosdec = cos(Deklination);
float sindec = sin(Deklination);
float lha = ZeitSeitMittag * (1.0027379 - 1 / 365.25) * 15 * kwert;
float coslha = cos(lha);
float sinlha = sin(lha);
float coslat = cos(BreiteR);
float sinlat = sin(BreiteR);
float N = -cosdec * sinlha;
float D = sindec * coslat - cosdec * coslha * sinlat;
Elevation = asin(sindec * sinlat + cosdec * coslha * coslat);
float AzS = atan2(N, D);
if (AzS < 0) {
AzS += 2 * pi;
}
AzS = AzS / kwert;
return AzS;
}
float BerechneZeitgleichung (int yearday) {
float Zeitgleichung = -0.170869921174742 * sin(0.0336997028793971 * yearday + 0.465419984181394) - 0.129890681040717 * sin(0.0178674832556871 * yearday - 0.167936777524864);
return Zeitgleichung;
}
float BerechneDeklination(int yearday) {
float Deklination = 0.409526325277017 * sin(0.0169060504029192 * (yearday - 80.0856919827619));
return Deklination;
}
float BerechneZeitdifferenz(float hoeheSM, float latitude, float kwert, float Deklination, float pi) {
float Zeitdifferenz;
Zeitdifferenz = 12 * acos((sin(hoeheSM) - sin(latitude * kwert) * sin(Deklination)) / (cos(latitude * kwert) * cos(Deklination))) / pi;
return Zeitdifferenz;
}
float BerechneTageslaenge (float Zeitdifferenz, float Zeitgleichung, float longitude, int Zeitzone, float & Aufgang, float & Untergang) {
float AufgangOrtszeit = 12 - Zeitdifferenz - Zeitgleichung;
float UntergangOrtszeit = 12 + Zeitdifferenz - Zeitgleichung;
Aufgang = AufgangOrtszeit - longitude / 15 + Zeitzone;
Untergang = UntergangOrtszeit - longitude / 15 + Zeitzone;
float Tageslaenge = Untergang - Aufgang;
return Tageslaenge;
}