#include <Timer.h>
#include <DS1307new.h>
#include "structs.h"
#include <Wire.h>
#include <math.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define NIGHT 0 //FLAG Nacht
#define SUNRISE 1 //FLAG Sonnenaufgang
#define DAY 2 //FLAG Tag
#define SUNSET 3 //FLAG Sonnuntergang
#define THUNDER_ON 4 //FLAG Gewitter kommt
#define THUNDER_TIME 5 //FAG Zeit für Blitze
#define THUNDER_OFF 6 //FLAG Gewitter geht
#define CLOUD_ON 7 //FLAG Wolke kommt
#define CLOUD_OFF 8 //FLAG Wolke geht
#define OFF 9
#define DAYLIGHT 10 //FLAG Tageslicht
#define REDLIGHT 11 //FLAG Rotlicht
#define BLUELIGHT 12 //FLAG Blaulicht
#define LIGHTNING 13
#define LIGHTCHANALS 12 //Anzahl der Lichtkanäle
#define LIGHTNINGS 3 //Anzahl der Blitzkanäle
#define MAXBRIGHTNESS_DAYLIGHT 100 //Maximale Helligkeit in Prozent
#define MAXBRIGHTNESS_REDLIGHT 70 //Maximale Helligkeit in Prozent
#define MAXBRIGHTNESS_BLUELIGHT 70 //Maximale Helligkeit in Prozent
#define THUNDERBRIGHTNESS_DAYLIGTH 10 //Maximale Helligkeit bei Gewitter in Prozent
#define THUNDERBRIGHTNESS_REDLIGTH 10 //Maximale Helligkeit bei Gewitter in Prozent
#define THUNDERBRIGHTNESS_BLUELIGTH 10 //Maximale Helligkeit bei Gewitter in Prozent
#define CLOUD_SPEED 5 //Zeit für Dimmvorgang in Sek.
#define CLOUD_AMOUNT 30000 // max 65535 Bereich für Zufallszahl je kleiner um so häufiger
#define CLOUD_MAXBRIGHTNESS 30 //Maximale Wolkenhelligkeit in Prozent
#define THUNDER_SPEED 3 //Zeit für Dimmvorgang in Sek.
#define THUNDER_LENGTH 1 //Länge der Dunkelphase beim Gewitter in Min.
Timer t;
uint16_t startAddr = 0x0000; // Start address to store in the NV-RAM Uhr
uint16_t lastAddr; // new address for storing in NV-RAM Uhr
uint16_t TimeIsSet = 0xaa55;
unsigned long last_calc = 0;
uint32_t thunder_start_time = get_ts(8, 2, 0);
byte thunder_status;
int lightnings[]={4,9,14};
CHANAL chanals[] = { {0, DAYLIGHT,get_ts(8, 0, 10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{3, DAYLIGHT,get_ts(8, 0, 10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{5, DAYLIGHT,get_ts(8, 0, 10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{8, DAYLIGHT,get_ts(8, 0, 10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{10,DAYLIGHT,get_ts(8, 0,10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{13,DAYLIGHT,get_ts(8, 0,10), get_ts(8, 5, 0), 1, 1, NIGHT, 0, 0, 0, 0},
{2, REDLIGHT,get_ts(8, 0, 0), get_ts(8, 5, 10), 1, 1, NIGHT, 0, 0, 0, 0},
{7, REDLIGHT,get_ts(8, 0, 0), get_ts(8, 5, 10), 1, 1, NIGHT, 0, 0, 0, 0},
{12,REDLIGHT,get_ts(8, 0, 0), get_ts(8, 5, 10), 1, 1, NIGHT, 0, 0, 0, 0},
{1, BLUELIGHT,get_ts(8, 0, 10), get_ts(8, 5, 15), 1, 1, NIGHT, 0, 0, 0, 0},
{6, BLUELIGHT,get_ts(8, 0, 10), get_ts(8, 5, 15), 1, 1, NIGHT, 0, 0, 0, 0},
{11,BLUELIGHT,get_ts(8, 0, 10), get_ts(8, 5, 15), 1, 1, NIGHT, 0, 0, 0, 0}};
void setup() {
Serial.begin(9600);
randomSeed(analogRead(0));
setupClock(7, 59, 20, 1, 2018);
pwm.begin();
pwm.setPWMFreq(1600); // This is the maximum PWM frequency
// save I2C bitrate
uint8_t twbrbackup = TWBR;
// must be changed after calling Wire.begin() (inside pwm.begin())
TWBR = 12; // upgrade to 400KHz!
delay(3000);
RTC.getTime();
for (int i = 0; i < 48; i++) {
pwm.setPWM(i, 0, 0);
}
thunder_status = NIGHT;
}
void loop()
{
word w;
RTC.getTime();
t.update();
if (millis() > last_calc)
{
last_calc = millis();
for (int i = 0; i < LIGHTCHANALS; i++)
{
if (TimeStamp() >= chanals[i].starttime && TimeStamp() <= (chanals[i].endtime + get_ts(0, chanals[i].sunsetlenght, 0)))
{
switch (chanals[i].status)
{
case NIGHT:
switch (chanals[i].wrb)
{
case DAYLIGHT:
chanals[i].freq = float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT / 60000.0 / chanals[i].sunriselength);
break;
case REDLIGHT:
chanals[i].freq = float(4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT / 60000.0 / chanals[i].sunriselength);
break;
case BLUELIGHT:
chanals[i].freq = float(4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT / 60000.0 / chanals[i].sunriselength);
break;
}
chanals[i].status = SUNRISE;
chanals[i].startmillis = last_calc;
Serial.print(printTime());
Serial.print(" PIN: ");
Serial.print(chanals[i].pin);
Serial.println(" AN");
break;
case SUNRISE:
chanals[i].pos = chanals[i].freq * (last_calc - chanals[i].startmillis);
switch (chanals[i].wrb)
{
case DAYLIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT ))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT );
chanals[i].status = DAY;
}
break;
case REDLIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT ))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT );
chanals[i].status = DAY;
}
break;
case BLUELIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT );
chanals[i].status = DAY;
}
break;
}
break;
case DAY:
w = random(0, CLOUD_AMOUNT);
if (w < LIGHTCHANALS && chanals[i].wrb==DAYLIGHT) //Nur Kanäle mit Tageslicht
{
if (TimeStamp() <= (chanals[i].endtime + get_ts(0,0,CLOUD_SPEED)))
{
chanals[i].startmillis = last_calc;
chanals[i].status = CLOUD_ON; //Status Wolke an
chanals[i].endpos = chanals[i].pos; //Aktuelle Position zwischenspeichern
chanals[i].freq = float((chanals[i].pos - (4095 / 100 * CLOUD_MAXBRIGHTNESS)) / 1000.0 / CLOUD_SPEED); //Frequenz berechnen für Dimmvorgang
}
}
break;
case CLOUD_ON:
if (chanals[i].wrb==DAYLIGHT) //Nur Kanäle mit Tageslicht
{
chanals[i].pos = chanals[i].endpos - (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos <= float(4095 / 100 * CLOUD_MAXBRIGHTNESS))
{
chanals[i].pos = float(4095 / 100 * CLOUD_MAXBRIGHTNESS);
chanals[i].status = CLOUD_OFF;
chanals[i].startmillis = last_calc;
chanals[i].freq = float(((4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT ) - chanals[i].pos) / 1000.0 / CLOUD_SPEED); //Frequenz berechnen für Dimmvorgang
chanals[i].endpos = chanals[i].pos;
}
}
break;
case CLOUD_OFF:
if (chanals[i].wrb==DAYLIGHT) //Nur Kanäle mit Tageslicht
{
chanals[i].pos = chanals[i].endpos + (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT ))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT );
chanals[i].status = DAY;
}
}
break;
case SUNSET:
chanals[i].pos = chanals[i].endpos - (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos <= 0.0)
{
chanals[i].pos = 0;
chanals[i].status = OFF;
Serial.print(printTime());
Serial.print(" PIN: ");
Serial.print(chanals[i].pin);
Serial.println(" Aus");
}
break;
case THUNDER_ON:
switch (chanals[i].wrb)
{
case DAYLIGHT:
chanals[i].pos = chanals[i].endpos - (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos <= (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_DAYLIGTH))
{
chanals[i].pos = (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_DAYLIGTH);
chanals[i].status = THUNDER_TIME;
chanals[i].startmillis = last_calc;
}
break;
case REDLIGHT:
chanals[i].pos = chanals[i].endpos - (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos <= (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_REDLIGTH))
{
chanals[i].pos = (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_REDLIGTH);
chanals[i].status = THUNDER_TIME;
chanals[i].startmillis = last_calc;
}
break;
case BLUELIGHT:
chanals[i].pos = chanals[i].endpos - (chanals[i].freq * (last_calc - chanals[i].startmillis));
if (chanals[i].pos <= (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_BLUELIGTH))
{
chanals[i].pos = (chanals[i].endpos / 100 * THUNDERBRIGHTNESS_BLUELIGTH);
chanals[i].status = THUNDER_TIME;
chanals[i].startmillis = last_calc;
}
break;
}
break;
case THUNDER_TIME:
w=random(0, 1500);
if (w<=2)
{
for (int j=95;j<=4095;j=j+500)
{
pwm.setPWM(lightnings[int(w)], 0, j);
}
pwm.setPWM(lightnings[int(w)], 0, 0);
}
if (last_calc >= (chanals[i].startmillis+(THUNDER_LENGTH*60000)))
{
switch (chanals[i].wrb)
{
case DAYLIGHT:
chanals[i].status = THUNDER_OFF;
chanals[i].startmillis = last_calc;
chanals[i].freq = float(((4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT) - chanals[i].pos) / 1000.0 / THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
chanals[i].endpos = chanals[i].pos;
break;
case REDLIGHT:
chanals[i].status = THUNDER_OFF;
chanals[i].startmillis = last_calc;
chanals[i].freq = float(((4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT) - chanals[i].pos) / 1000.0 / THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
chanals[i].endpos = chanals[i].pos;
break;
case BLUELIGHT:
chanals[i].status = THUNDER_OFF;
chanals[i].startmillis = last_calc;
chanals[i].freq = float(((4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT) - chanals[i].pos) / 1000.0 / THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
chanals[i].endpos = chanals[i].pos;
break;
}
}
break;
case THUNDER_OFF:
chanals[i].pos = chanals[i].endpos + (chanals[i].freq * (last_calc - chanals[i].startmillis));
switch (chanals[i].wrb)
{
case DAYLIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_DAYLIGHT);
chanals[i].status = DAY;
}
break;
case REDLIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_REDLIGHT);
chanals[i].status = DAY;
}
break;
case BLUELIGHT:
if (chanals[i].pos >= float(4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT))
{
chanals[i].pos = float(4095 / 100.0 * MAXBRIGHTNESS_BLUELIGHT);
chanals[i].status = DAY;
}
break;
}
break;
}
if (TimeStamp() >= chanals[i].endtime && chanals[i].status != SUNSET && chanals[i].status != OFF)
{
chanals[i].status = SUNSET;
chanals[i].startmillis = last_calc;
chanals[i].freq = float(chanals[i].pos / 60000.0 / chanals[i].sunsetlenght);
chanals[i].endpos = chanals[i].pos;
}
setpwm(chanals[i].pin, int(chanals[i].pos));
}
}
if (TimeStamp() >= thunder_start_time && thunder_status == NIGHT)
{
thunder_status = THUNDER_ON;
Serial.println("Gewitter an");
for (int i = 0; i < LIGHTCHANALS; i++)
{
chanals[i].status = THUNDER_ON;
chanals[i].startmillis = last_calc;
chanals[i].endpos = chanals[i].pos;
switch (chanals[i].wrb)
{
case DAYLIGHT:
if (chanals[i].pos <= float(4095 / 100 * THUNDERBRIGHTNESS_DAYLIGTH))
{
chanals[i].freq=0.0;
}
if (chanals[i].pos > float(4095 / 100 * THUNDERBRIGHTNESS_DAYLIGTH))
{
chanals[i].freq=float((chanals[i].pos-(4095/100*THUNDERBRIGHTNESS_DAYLIGTH))/1000.0/THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
}
break;
case REDLIGHT:
if (chanals[i].pos <= float(4095 / 100 * THUNDERBRIGHTNESS_REDLIGTH))
{
chanals[i].freq=0.0;
}
if (chanals[i].pos > float(4095 / 100 * THUNDERBRIGHTNESS_REDLIGTH))
{
chanals[i].freq=float((chanals[i].pos-(4095/100*THUNDERBRIGHTNESS_REDLIGTH))/1000.0/THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
}
break;
case BLUELIGHT:
if (chanals[i].pos <= float(4095 / 100 * THUNDERBRIGHTNESS_BLUELIGTH))
{
chanals[i].freq=0.0;
}
if (chanals[i].pos > float(4095 / 100 * THUNDERBRIGHTNESS_BLUELIGTH))
{
chanals[i].freq=float((chanals[i].pos-(4095/100*THUNDERBRIGHTNESS_BLUELIGTH))/1000.0/THUNDER_SPEED); //Frequenz berechnen für Dimmvorgang
}
break;
}
}
}
}
}
void setpwm(int CH, int pos)
{
pwm.setPWM(CH, 0, int(exp(sqrt(pos) * 0.144295) * 0.4));
}