#include "RTClib.h"
#include <DTutils.h>
#include <Servo.h>
#include <Stepper.h>
RTC_DS3231 rtc;
Servo servo;
#define pwmA 3
#define pwmB 11
#define dirA 12
#define dirB 13
const int stepsPerRevolution = 200;
const int stepsV = 16;
const int stepsR = -16;
const int stepsSR = -200;
float Deklination, Dekl;
char buffer[80];
Stepper myStepper = Stepper(stepsPerRevolution, dirA, dirB);
const int mvOst = 258;
const int mvSued = 510;
const int mvWest = 768;
const int servomax = 115;
const int servomin = 33;
void setup() {
if (! rtc.begin())
{
while (1)
{
delay(10);
}
}
Serial2.begin(9600);
pinMode(pwmA, OUTPUT);
pinMode(pwmB, OUTPUT);
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
myStepper.setSpeed(200);
servo.attach(5);
pinMode(A2, INPUT);
pinMode(5, OUTPUT);
pinMode(A5, INPUT);
pinMode(A8, OUTPUT);
pinMode(A9, OUTPUT);
pinMode(A10, OUTPUT);
pinMode(A11, OUTPUT);
pinMode(A12, OUTPUT);
pinMode(A13, OUTPUT);
Serial2.print("ref=page0.t0.txt");
endNextionCommand();
Serial2.print("ref=page0.t1.txt");
endNextionCommand();
Serial2.print("ref=page0.t2.txt");
endNextionCommand();
Serial2.print("ref=page0.t3.txt");
endNextionCommand();
Serial2.print("ref=page0.t4.txt");
endNextionCommand();
Serial2.print("ref=page1.t0.txt");
endNextionCommand();
Serial2.print("ref=page1.t1.txt");
endNextionCommand();
Serial2.print("ref=page1.t2.txt");
endNextionCommand();
Serial2.print("ref=page1.t3.txt");
endNextionCommand();
Serial2.print("ref=page1.t4.txt");
endNextionCommand();
Serial2.print("ref=page1.t5.txt");
endNextionCommand();
Serial2.print("ref=page1.t6.txt");
endNextionCommand();
Serial2.print("ref=page2.t0.txt");
endNextionCommand();
Serial2.print("ref=page2.t1.txt");
endNextionCommand();
Serial2.print("ref=page2.t2.txt");
endNextionCommand();
Serial2.print("ref=page2.t3.txt");
endNextionCommand();
Serial2.print("ref=page2.t4.txt");
endNextionCommand();
Serial2.print("ref=page2.t5.txt");
endNextionCommand();
Serial2.print("ref=page2.t6.txt");
endNextionCommand();
Serial2.print("ref=page3.t0.txt");
endNextionCommand();
Serial2.print("ref=page3.t1.txt");
endNextionCommand();
Serial2.print("ref=page3.t2.txt");
endNextionCommand();
}
void loop() {
float Temp = float(rtc.getTemperature());
DateTime now = rtc.now();
sprintf(buffer, "%02d.%02d.%04d Zeit: %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();
int yearday = DayOfYear(Jahr, Monat, Tag);
float Elevation, Aufgang, Untergang, Deklination;
float AzS;
float Zeitgleichung;
float Zeitdifferenz;
float AufgangOrtszeit;
float UntergangOrtszeit;
float Tageslaenge, MEZ, MOZ, WOZ;
float ZeitSeitMittag;
const float pi = 3.14159265;
const float kwert = pi / 180;
const float latitude = 51.222191;
const float longitude = 7.954169;
const float BreiteR = latitude * kwert;
const float hoeheSM = -(50.0 / 60.0) * kwert;
const int Zeitzone = 1;
String wr;
int Grenzwert;
int AzI;
int sensorValue;
int i2;
MEZ = Stunde + Minute / 60 + Sekunde / 3600;
Zeitgleichung = BerechneZeitgleichung (yearday);
ZeitSeitMittag = MEZ + longitude / 15.0 - Zeitzone - 12 + Zeitgleichung;
Deklination = BerechneDeklination (yearday);
Zeitdifferenz = BerechneZeitdifferenz (hoeheSM, pi, latitude, kwert, Deklination);
AzS = SunAngles(Deklination, BreiteR, kwert, pi, ZeitSeitMittag, Elevation);
Tageslaenge = BerechneTageslaenge (Zeitdifferenz, Zeitgleichung, longitude, Zeitzone, Aufgang, Untergang);
Elevation = Elevation / kwert;
Deklination = Deklination / kwert;
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;
}
sensorValue = analogRead(A2);
AzI = MotorenSteuerung (AzS, Elevation, sensorValue, Grenzwert, stepsV, stepsR, stepsSR, mvOst, mvSued, mvWest, servomax, servomin);
wr = Windrichtung(AzI);
const int analogPin = A5;
float pvmod = analogRead(analogPin);
float Volt = Solarspannung (pvmod);
float Prozent = Volt / 4.75 * 100;
int Std = (int)Tageslaenge;
int Min = (int)((Tageslaenge - Std) * 60);
Serial2.print("page0.t0.txt=\"");
Serial2.print("Nextion-Solartracker-Projekt");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t0.txt");
endNextionCommand();
Serial2.print("page0.t1.txt=\"");
Serial2.print("Version 4.3 vom 01.10.2023");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t1.txt");
endNextionCommand();
Serial2.print("page0.t2.txt=\"");
Serial2.print("Dr. Michael Schulte");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t2.txt");
endNextionCommand();
Serial2.print("page0.t3.txt=\"");
Serial2.print("http://wetterstation.mi-schu.de");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t5.txt");
endNextionCommand();
Serial2.print("page0.t4.txt=\"");
Serial2.print("E-Mail: wetter.roenkhausen@gmx.de");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t4.txt");
endNextionCommand();
Serial2.print("page1.t0.txt=\"");
Serial2.print(" Datum: " + String(buffer));
Serial2.print(" h (MEZ)");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t0.txt");
endNextionCommand();
Serial2.print("page1.t1.txt=\"");
Serial2.print(" Tag im Jahr: " + String(yearday));
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page0.t1.txt");
endNextionCommand();
Serial2.print("page1.t2.txt=\"");
if (WOZmin >= 0 && WOZmin < 10) {
Serial2.print(" Wahre Ortszeit (WOZ): " + String (WOZdez) + ":" + "0" + String (WOZmin) + " h");
}
else
{ Serial2.print(" Wahre Ortszeit (WOZ): " + String (WOZdez) + ":" + String (WOZmin) + " h");
}
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t2.txt");
endNextionCommand();
Serial2.print("page1.t3.txt=\"");
if (MOZmin >= 0 && MOZmin < 10) {
Serial2.print(" Mittlere Ortszeit (MOZ): " + String (MOZdez) + ":" + "0" + String (MOZmin) + " h");
}
else
{ Serial2.print(" Mittlere Ortszeit (MOZ): " + String (MOZdez) + ":" + String (MOZmin) + " h");
}
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t3.txt");
endNextionCommand();
Serial2.print("page1.t4.txt=\"");
if (MinA >= 0 && MinA < 10) {
Serial2.print(" Sonnenaufgang: " + String (StdA) + ":" + "0" + String (MinA) + " h");
}
else
{ Serial2.print(" Sonnenaufgang: " + String (StdA) + ":" + String (MinA) + " h");
}
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t4.txt");
endNextionCommand();
Serial2.print("page1.t5.txt=\"");
if (MinU >= 0 && MinU < 10) {
Serial2.println(" Sonnenuntergang: " + String (StdU) + ":" + "0" + String (MinU) + " h");
}
else
{ Serial2.println(" Sonnenuntergang: " + String (StdU) + ":" + String (MinU) + " h");
}
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t5.txt");
endNextionCommand();
Serial2.print("page1.t6.txt=\"");
if (MinL >= 0 && MinL < 10) {
Serial2.print(" Tageslaenge: " + String (StdL) + ":" + "0" + String (MinL) + " h");
}
else
{ Serial2.print(" Tageslaenge: " + String (StdL) + ":" + String (MinL) + " h");
}
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page1.t6.txt");
endNextionCommand();
Serial2.print("page2.t0.txt=\"");
Serial2.print(" Datum: " + String(buffer));
Serial2.print(" h (MEZ)");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t0.txt");
endNextionCommand();
Serial2.print("page2.t1.txt=\"");
Serial2.print(" Azimut-Soll: " + String(AzS) + " Grd " + "(" + String(wr) + ")");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t1.txt");
endNextionCommand();
Serial2.print("page2.t2.txt=\"");
Serial2.print(" Azimut-Ist: (GW " + String(Grenzwert) + ") " + String(AzI) + " Grd " + "(" + String(wr) + ")");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t2.txt");
endNextionCommand();
Serial2.print("page2.t3.txt=\"");
Serial2.print(" Elevation: " + String(Elevation) + " Grd");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref = page2.t3.txt");
endNextionCommand();
Serial2.print("page2.t4.txt=\"");
Serial2.print(" Deklination: " + String(Deklination) + " Grd");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t4.txt");
endNextionCommand();
Serial2.print("page2.t5.txt=\"");
Serial2.print(" Hall-Sensor (Pin2): " + String(sensorValue) + " Temp: " + String(Temp, 1) + " Grd C");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t5.txt");
endNextionCommand();
Serial2.print("page2.t6.txt=\"");
Serial2.print(" Solarspannung: " + String(Volt) + " V " + "(" + String (int (Prozent)) + "% Vmax" + ")");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t6.txt");
endNextionCommand();
Serial2.print("page3.t0.txt=\"");
Serial2.print(" Azimut-Soll: " + String(AzS) + " Grd");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref = page3.t5.txt");
endNextionCommand();
Serial2.print("page3.t1.txt=\"");
Serial2.print(" Azimut-Ist: " + String(AzI) + " Grd");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t2.txt");
endNextionCommand();
Serial2.print("page3.t2.txt=\"");
Serial2.print(" Elevation: " + String(Elevation) + " Grd");
Serial2.write('"');
endNextionCommand();
Serial2.print("ref=page2.t5.txt");
endNextionCommand();
}
void endNextionCommand()
{
Serial2.write(0xff);
Serial2.write(0xff);
Serial2.write(0xff);
}
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 kwert, float pi, float ZeitSeitMittag, float & Elevation) {
float DK = Deklination;
float cosdec = cos(DK);
float sindec = sin(DK);
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;
}
return (AzS / kwert);
}
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 pi, float latitude, float kwert, float Deklination) {
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;
}
int MotorenSteuerung (float AzS, float Elevation, int sensorValue, int Grenzwert, const int stepsV, const int stepsR, const int stepsSR, const int mvOst, const int mvSued, const int mvWest, const int servomax, const int servomin)
{
float AzI;
if (sensorValue >= 0 && sensorValue < mvSued) {
AzI = map(sensorValue, mvOst, mvSued, 90, 180);
}
if (sensorValue >= mvSued && sensorValue <= 900) {
AzI = map(sensorValue, mvSued, mvWest, 180, 270);
}
constrain(AzI, 40, 320);
if (Elevation > -1) {
int E2 = int(Elevation);
int elevation = map(E2, 90, 0, servomax, servomin);
constrain(elevation, 20, 130);
servo.write(elevation);
if ((int)AzI < (int)AzS) {
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(A10, HIGH);
digitalWrite(A11, HIGH);
myStepper.step(stepsV);
delay (250);
digitalWrite(A10, LOW);
digitalWrite(A11, LOW);
digitalWrite(A8, LOW);
digitalWrite(A13, LOW);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
}
if ((int)AzI > (int)AzS) {
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
digitalWrite(A8, HIGH);
digitalWrite(A13, HIGH);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
myStepper.step(stepsR);
delay (250);
digitalWrite(A8, LOW);
digitalWrite(A13, LOW);
digitalWrite(A10, LOW);
digitalWrite(A11, LOW);
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
}
}
else {
if (Elevation <= -1 && AzI >= Grenzwert) {
delay(250);
digitalWrite(pwmA, HIGH);
digitalWrite(pwmB, HIGH);
myStepper.step(stepsSR);
delay (250);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
delay(250);
digitalWrite(A9, HIGH);
digitalWrite(A12, HIGH);
delay(250);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
delay(250);
digitalWrite(A9, HIGH);
digitalWrite(A12, HIGH);
delay (250);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
delay(250);
digitalWrite(A9, HIGH);
digitalWrite(A12, HIGH);
delay (250);
digitalWrite(A9, LOW);
digitalWrite(A12, LOW);
delay (250);
digitalWrite(A9, HIGH);
digitalWrite(A12, HIGH);
delay (250);
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
delay(250);
}
}
if (int(AzI) == int(AzS)) {
digitalWrite(A9, HIGH);
digitalWrite(A12, HIGH);
digitalWrite(pwmA, LOW);
digitalWrite(pwmB, LOW);
}
return AzI;
}
float Solarspannung(float pvmod)
{
float Volt;
Volt = pvmod / 1023 * 4.75;
return Volt;
}