Hi There,
I'am quite new with programming of the Arduino, however I get pretty far by using the AI tools. unfortunattely it seems that i reach the limit where they can help me, so I am looking for some human intelligence that is open to help me.
I am working on a project, in the project I use an ESP32 devkit1 that I program via the Arduino IDE. Here I will command an SK6812 adressable led strip. The goal is to adres every led to an "place in the world" via longitude and latitude coordinates. Then the solar engine should calculate the angle of the sun related to the horizon on that place and via that it must defined the state of the specific led, "Dusk", "sunrise", "dawn", "Sunset". during Day the led should be off and during night the led should be on. during the twilights there is a fase of fading.
This will result in a led strip that will be a live corresponding to the day night cycles as in the real world.
For so far this worked quite in the good direction. However it seems that it has some problem due to the datum line and refresh the date. For example it is now 20:44 in Amsterdam and led 0 is still on, where it should be off because in Sydney the new day is allready started.
Is there some one that allready made something like this or will take the challenge to help slove this problem.
see the sketch as it is right now:
#include <WiFi.h>
#include <Adafruit_NeoPixel.h>
#include <time.h>
/* ================= HARDWARE ================= */
#define LED_PIN 4
#define LED_COUNT 13
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);
/* ================= WIFI ================= */
const char* ssid = "XXXXX";
const char* password = "XXXXX";
const char* ntpServer = "pool.ntp.org";
/* ================= LOCATIONS ================= */
float ledLat[LED_COUNT]={52.37,48.85,51.50,41.90,59.33,55.75,1.35,35.68,-33.87,40.71,19.43,34.05,-23.55};
float ledLon[LED_COUNT]={4.90,2.35,-0.12,12.50,18.07,37.62,103.82,139.69,151.21,-74.01,-99.13,-118.24,-46.63};
/* ================= SOLAR ================= */
struct SolarState{
time_t civilDawn;
time_t sunrise;
time_t sunset;
time_t civilDusk;
bool valid;
};
SolarState solar[LED_COUNT];
/* ================= MATH ================= */
constexpr double DEG2RAD=PI/180.0;
constexpr double RAD2DEG=180.0/PI;
double d2r(double d){return d*DEG2RAD;}
double r2d(double r){return r*RAD2DEG;}
float gammaCorrect(float x){
if(x<0)x=0;
if(x>1)x=1;
return pow(x,2.2);
}
/* ================= SOLAR CALC ================= */
bool solarEventUTC(int year,int month,int day,double lat,double lon,double altitude,bool sunrise,time_t* outUTC){
time_t midnight=utcMidnight(year,month,day);
struct tm tmDay;
gmtime_r(&midnight,&tmDay);
int N=tmDay.tm_yday+1;
double lngHour=lon/15.0;
double tApprox=sunrise?N+(6-lngHour)/24.0:N+(18-lngHour)/24.0;
double M=0.9856*tApprox-3.289;
double L=M+1.916*sin(d2r(M))+0.020*sin(2*d2r(M))+282.634;
while(L<0)L+=360;
while(L>=360)L-=360;
double RA=r2d(atan2(0.91764*sin(d2r(L)),cos(d2r(L))));
while(RA<0)RA+=360;
while(RA>=360)RA-=360;
double Lq=floor(L/90)*90;
double RAq=floor(RA/90)*90;
RA=(RA+(Lq-RAq))/15.0;
double sinDec=0.39782*sin(d2r(L));
double cosDec=cos(asin(sinDec));
double cosH=(sin(d2r(altitude))-sinDec*sin(d2r(lat)))/(cosDec*cos(d2r(lat)));
if(cosH>1 || cosH<-1) return false;
double H=sunrise?360-r2d(acos(cosH)):r2d(acos(cosH));
H/=15.0;
double T=H+RA-0.06571*tApprox-6.622;
double UT=T-lngHour;
while(UT<0)UT+=24;
while(UT>=24)UT-=24;
time_t result=midnight+(time_t)(UT*3600.0);
if(!sunrise && UT<12) result+=86400;
*outUTC=result;
return true;
}
/* ================= UPDATE SOLAR ================= */
void updateSolar(int i,time_t now){
time_t solarNow = now + (time_t)(ledLon[i] * 240.0);
struct tm tm;
gmtime_r(&solarNow,&tm);
int y=tm.tm_year+1900;
int m=tm.tm_mon+1;
int d=tm.tm_mday;
bool ok=
solarEventUTC(y,m,d,ledLat[i],ledLon[i],-6,true,&solar[i].civilDawn)&&
solarEventUTC(y,m,d,ledLat[i],ledLon[i],-0.833,true,&solar[i].sunrise)&&
solarEventUTC(y,m,d,ledLat[i],ledLon[i],-0.833,false,&solar[i].sunset)&&
solarEventUTC(y,m,d,ledLat[i],ledLon[i],-6,false,&solar[i].civilDusk);
if(!ok){
solar[i].valid=false;
return;
}
/* sanity check volgorde */
if(!(solar[i].civilDawn <= solar[i].sunrise &&
solar[i].sunrise <= solar[i].sunset &&
solar[i].sunset <= solar[i].civilDusk)){
solar[i].valid=false;
return;
}
solar[i].valid=true;
}
/* ================= COLOR ================= */
uint32_t makeColor(float p){
uint8_t r=76*p;
uint8_t g=42*p;
uint8_t b=15*p;
uint8_t w=4*p;
return strip.Color(g,r,b,w);
}
/* ================= SETUP ================= */
void setup(){
Serial.begin(115200);
strip.begin();
strip.clear();
strip.show();
setenv("TZ","UTC0",1);
tzset();
WiFi.begin(ssid,password);
while(WiFi.status()!=WL_CONNECTED){delay(500);}
configTime(0,0,ntpServer);
while(time(nullptr)<1000000000){delay(500);}
}
/* ================= LOOP ================= */
void loop(){
time_t now=time(nullptr);
static int lastDay=-1;
struct tm tm;
gmtime_r(&now,&tm);
if(tm.tm_yday!=lastDay){
lastDay=tm.tm_yday;
for(int i=0;i<LED_COUNT;i++)
updateSolar(i,now);
}
for(int i=0;i<LED_COUNT;i++){
uint32_t c=0;
if(!solar[i].valid){
strip.setPixelColor(i,0);
continue;
}
if(now>=solar[i].civilDawn && now<solar[i].sunrise){
float dur=solar[i].sunrise-solar[i].civilDawn;
if(dur>0){
float p=gammaCorrect(1.0-float(now-solar[i].civilDawn)/dur);
c=makeColor(p);
}
}else if(now>=solar[i].sunrise && now<solar[i].sunset){
c=0;
}else if(now>=solar[i].sunset && now<solar[i].civilDusk){
float dur=solar[i].civilDusk-solar[i].sunset;
if(dur>0){
float p=gammaCorrect(float(now-solar[i].sunset)/dur);
c=makeColor(p);
}
}else{
c=makeColor(1.0);
}
strip.setPixelColor(i,c);
}
strip.show();
delay(100);
}


