DIY Weather Station project

I'm making a small lighthouse (5-6 feet tall). I want to integrate my mailbox, collect and report weather data from the lighthouse, shine a beacon when its gets dark outside. I'm doing it in segments.

Parts: Lolin Wemos D-1 Mini Pro ESP8266, Adafruit BME280

1. I2C: Verify I2C address

/*
Check for I2C connection to Adafruit BME280
Wemos D1 Mini Pro
SCK - I2C clock pin
SDI - I2C data pin
VIN - 3-5V
GND - GND
By default, the I2C address is 0x77
*/


#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("\nI2C Scanner");
}

void loop() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    } else if (error==4) {
      Serial.print("Unknow error at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println("done\n");
  }
  delay(5000);          
}

2. Connect to BME, get Temp, Humidity, Barometric readings

/*
   WiFi BME280 humidity, temperature & pressure sensor (I2C)
   Reports current weather data via Mosquitto MQTT, WiFi, Raspberry Pi3(b)
*/

//#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
//#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>


// ASSIGN PINS  **************************************************
//#define BME_SCK 5;  //
//#define BME_MISO 12//
//#define BME_MOSI 11//
//#define BME_CS 4;  //

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme;  // I2C
//Adafruit_BME280 bme(BME_CS);
// hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO,  BME_SCK);

// Connect to the WiFi
const char* ssid = "MyIPaddress";
const char* password = "MyPassword!";
const char* mqtt_server = "192.168.#.###";

WiFiClient(espClient);
PubSubClient client(espClient);



void reconnect() {  // **********************************************************
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print(F("Contacting MQTT server..."));
    // Attempt to connect
    if (client.connect("BME280")) {  //assign a "client name".  Each wemos must have a unique name
      Serial.println(F("connected"));


    } else {
      Serial.print(F("Failed to connect. "));
      Serial.println(F(" Attempting connection again in 3 seconds"));
      // Wait 3 seconds before retrying
      delay(3000);
    }
  }
}


void setup() {
  {
    Serial.begin(115200);
    Wire.begin();
    client.setServer(mqtt_server, 1883);
  }

  // Connect to WiFinetwork
  Serial.println();
  Serial.println();
  Serial.print(F("Connecting to "));
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  WiFi.mode(WIFI_STA);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }
  Serial.println(F(""));
  Serial.println(F("WiFi connected"));
  // Print the IP address
  Serial.print(F("Local IP: "));
  Serial.println(WiFi.localIP());


  //  *********************************************************************************
  {
    Serial.println(F("BME280 located in Master Bedroom"));

    if (!bme.begin()) {
      Serial.println("Could not find a valid BME280 sensor, check wiring!");
      while (1)
        ;
    }
  }
}


void loop() {
  if (!client.connected()) {
    reconnect();
  }

  //  ****************  CREATE BUFFER TO STORE BINARY DATA ************************
#define INT_STR_SIZE 16
  char buffer[INT_STR_SIZE];

  //  ****************  TEMPERATURE (F) ************************

  dtostrf(bme.readTemperature() * 9.0 / 5.0 + 32.0, 3, 1, buffer);
  Serial.print("Temperature = ");
  Serial.print(buffer);
  Serial.println(" *F");
  client.publish("Office/BME280/TempF", buffer);


  //  ****************  TEMPERATURE (C) ************************
  dtostrf(bme.readTemperature(), 3, 0, buffer);
  Serial.print("Temperature = ");
  Serial.print(buffer);
  Serial.println(" *C");
  client.publish("Office/BME280/TempC", buffer);


  //  ****************  HUMIDITY  *********************
  dtostrf(bme.readHumidity(), 3, 0, buffer);
  Serial.print("Humidity = ");
  Serial.print(buffer);
  Serial.println(" %");
  client.publish("Office/BME280/Humidity", buffer);


  //  ****************  PRESSURE  *********************
  dtostrf(bme.readPressure() / 3386.39, 3, 2, buffer);
  Serial.print("Pressure = ");
  Serial.print(buffer);
  Serial.println(" inHg");
  client.publish("Office/BME280/Pressure", buffer);


  //  ****************  ALTITUDE  *********************
  //    Serial.print("Approx. Altitude = ");
  //    Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)+4);//   +4 to correct altitude?
  //    Serial.println(" m");
  Serial.println();


  delay(10000);


  client.loop();
}

I'll update the rest later. I can't find or don't have a light sensor and I fried my GPS. Waiting on new parts

  1. Light sensor for beacon to come on when it gets dark

  2. Time: I could go one of 2 ways; RTC or GPS which will give me the current time and Lat/Lon of my location

I have to ask…
Why not report the mailbox status via MQTT as well ?

The I2C connector has a 3.3volt power output.
You did connect it to the 5volt Vin input of the BME280.
Not that it makes a lot of difference, but it should be connected to the 3Vo input of the module. You should have bought a 3.3volt version of the BME280 module, without voltage regulator and level shifters.
Leo..

I probably will "just because"!

Just get it of the internet.
Takes a few lines of code, no hardware.
And you can get sunrise/sunset times too.
Leo..

Whoops. ESP8266
No. Adafruit made the BME280 3.3-5V input
Time: Good thinking. Thanks!

3.3volt input just passes through the built-in regulator to the 3Vo pin, with 0.1volt loss.
Leo..

Leo; I'm just making sure I understand what you stated...
You're suggesting I supply 3.3V to the 3Vo pin on the BME, resulting in more efficient use of power?
I was unaware!

For anyone following this thread, yes, I did rearrange the power supply: 3v3 pin on the ESP to the 3Vo pin on the BME. NO MAGIC SMOKE!

Nice, especially since I plan on using solar power.

Working on NTP sketch at the moment. Almost done... It works, I'm now just rearranging the Date/Time format to suit ME. I will post that once completed, then merge that into my "BME280 Weather" sketch.

Question: What is a reasonable time delay for reading/updating weather? 10 minutes, 1/2 hour? To conserve battery, I was thinking of having it "sleep"

If wind is part of weather, then updating every 5 seconds will be often enough.

I hope I'm not wasting my time with the NTP_TimeZone sketch. Although, I am learning something. I don't see anything in there about sunrise/sunset.

/*
  NTP-TZ-DST (v2)
  NetWork Time Protocol - Time Zone - Daylight Saving Time

  This example shows:
  - how to read and set time
  - how to set timezone per country/city
  - how is local time automatically handled per official timezone definitions
  - how to change internal sntp start and update delay
  - how to use callbacks when time is updated

  This example code is in the public domain.
*/


#ifndef STASSID
#define STASSID "MySSID"
#define STAPSK "MyPassword!"
#endif

// initial time (possibly given by an external RTC)
#define RTC_UTC_TEST 1510592825  // 1510592825 = Monday 13 November 2017 17:07:05 UTC


// This database is autogenerated from IANA timezone database
//    https://www.iana.org/time-zones
// and can be updated on demand in this repository
#include <TZ.h>

// "TZ_" macros follow DST change across seasons without source code change
// check for your nearest city in TZ.h

// espressif headquarter TZ
//#define MYTZ TZ_Asia_Shanghai

// example for "Not Only Whole Hours" timezones:
// Kolkata/Calcutta is shifted by 30mn
//#define MYTZ TZ_Asia_Kolkata

// example of a timezone with a variable Daylight-Saving-Time:
// demo: watch automatic time adjustment on Summer/Winter change (DST)


#define MYTZ TZ_America_New_York
//#define MYTZ TZ_US_Eastern      //  <- ******** Doesn't seem to work ********
////////////////////////////////////////////////////////

#include <ESP8266WiFi.h>
#include <coredecls.h>  // settimeofday_cb()
#include <Schedule.h>
#include <PolledTimeout.h>

#include <time.h>      // time() ctime()
#include <sys/time.h>  // struct timeval

#include <sntp.h>  // sntp_servermode_dhcp()

// for testing purpose:
extern "C" int clock_gettime(clockid_t unused, struct timespec* tp);

////////////////////////////////////////////////////////

static timeval tv;
static timespec tp;
static time_t now;
static uint32_t now_ms, now_us;

static esp8266::polledTimeout::periodicMs showTimeNow(600000);
static int time_machine_days = 0;  // 0 = present
static bool time_machine_running = false;
static bool time_machine_run_once = false;

// OPTIONAL: change SNTP startup delay
// a weak function is already defined and returns 0 (RFC violation)
// it can be redefined:
// uint32_t sntp_startup_delay_MS_rfc_not_less_than_60000 ()
//{
//    //info_sntp_startup_delay_MS_rfc_not_less_than_60000_has_been_called = true;
//    return 60000; // 60s (or lwIP's original default: (random() % 5000))
//}

// OPTIONAL: change SNTP update delay
// a weak function is already defined and returns 1 hour
// it can be redefined:
// uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()
//{
//    //info_sntp_update_delay_MS_rfc_not_less_than_15000_has_been_called = true;
//    return 15000; // 15s
//}

#define PTM(w) \
  Serial.print(" " #w "="); \
  Serial.print(tm->tm_##w);

void printTm(const char* what, const tm* tm) {
  Serial.print(what);
  PTM(isdst);
  PTM(yday);
  PTM(wday);
  PTM(year);
  PTM(mon);
  PTM(mday);
  PTM(hour);
  PTM(min);
  PTM(sec);
}

void showTime() {
  gettimeofday(&tv, nullptr);
  clock_gettime(0, &tp);
  now = time(nullptr);
  now_ms = millis();
  now_us = micros();


/*
  Serial.println();
  printTm("localtime:", localtime(&now));
  Serial.println();
  printTm("gmtime:   ", gmtime(&now));
  Serial.println();
*/

  // time from boot
/*
  Serial.print("clock:     ");
  Serial.print((uint32_t)tp.tv_sec);
  Serial.print("s + ");
  Serial.print((uint32_t)tp.tv_nsec);
  Serial.println("ns");
*/

/*
  // time from boot
  Serial.print("millis:    ");
  Serial.println(now_ms);
  Serial.print("micros:    ");
  Serial.println(now_us);
*/

/*
  // EPOCH+tz+dst
  Serial.print("gtod:      ");
  Serial.print((uint32_t)tv.tv_sec);
  Serial.print("s + ");
  Serial.print((uint32_t)tv.tv_usec);
  Serial.println("us");
*/

  // EPOCH+tz+dst
//   ***  Serial.print("time:      ");
//   ***  Serial.println((uint32_t)now);

  // timezone and demo in the future
//   ***  Serial.printf("timezone:  %s\n", getenv("TZ") ?: "(none)");


  // human readable
  Serial.print("ctime:     ");
  Serial.print(ctime(&now));

  // lwIP v2 is able to list more details about the currently configured SNTP servers
  for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
    IPAddress sntp = *sntp_getserver(i);
    const char* name = sntp_getservername(i);
    if (sntp.isSet()) {
      //Serial.printf("sntp%d:     ", i);
      if (name) {
        //Serial.printf("%s (%s) ", name, sntp.toString().c_str());
      } else {
        //Serial.printf("%s ", sntp.toString().c_str());
      }
      //Serial.printf("- IPv6: %s - Reachability: %o\n", sntp.isV6() ? "Yes" : "No", sntp_getreachability(i));
    }
  }

  Serial.println();

  // show subsecond synchronisation
  timeval prevtv;
  time_t prevtime = time(nullptr);
  gettimeofday(&prevtv, nullptr);

// *********

/*
  while (true) {
    gettimeofday(&tv, nullptr);
    if (tv.tv_sec != prevtv.tv_sec) {
      Serial.printf("time(): %u   gettimeofday(): %u.%06u  seconds are unchanged\n", (uint32_t)prevtime, (uint32_t)prevtv.tv_sec, (uint32_t)prevtv.tv_usec);
      Serial.printf("time(): %u   gettimeofday(): %u.%06u  <-- seconds have changed\n", (uint32_t)(prevtime = time(nullptr)), (uint32_t)tv.tv_sec, (uint32_t)tv.tv_usec);
      break;
    }
    prevtv = tv;
    delay(50);
  }
*/

  Serial.println();
}

void time_is_set(bool from_sntp /* <= this parameter is optional */) {
  // in CONT stack, unlike ISRs,
  // any function is allowed in this callback

  if (time_machine_days == 0) {
    if (time_machine_running) {
      time_machine_run_once = true;
      time_machine_running = false;
    } else {
      time_machine_running = from_sntp && !time_machine_run_once;
    }
    if (time_machine_running) { Serial.printf("\n-- \n-- Starting time machine demo to show libc's "
                                              "automatic DST handling\n-- \n"); }
  }

  Serial.print("settimeofday(");
  if (from_sntp) {
    Serial.print("SNTP");
  } else {
    Serial.print("USER");
  }
  Serial.print(")");

  // time machine demo
  if (time_machine_running) {
    now = time(nullptr);
    const tm* tm = localtime(&now);
    Serial.printf(": future=%3ddays: DST=%s - ", time_machine_days, tm->tm_isdst ? "true " : "false");
    Serial.print(ctime(&now));
    gettimeofday(&tv, nullptr);
    constexpr int days = 30;
    time_machine_days += days;
    if (time_machine_days > 360) {
      tv.tv_sec -= (time_machine_days - days) * 60 * 60 * 24;
      time_machine_days = 0;
    } else {
      tv.tv_sec += days * 60 * 60 * 24;
    }
    settimeofday(&tv, nullptr);
  } else {
    Serial.println();
  }
}


void setup() {
  WiFi.persistent(false);
  WiFi.mode(WIFI_OFF);

  Serial.begin(115200);
  Serial.println("\nStarting in 2secs...\n");
  delay(2000);

  // install callback - called when settimeofday is called (by SNTP or user)
  // once enabled (by DHCP), SNTP is updated every hour by default
  // ** optional boolean in callback function is true when triggered by SNTP **
  settimeofday_cb(time_is_set);

  // setup RTC time
  // it will be used until NTP server will send us real current time
  Serial.println("Manually setting some time from some RTC:");
  time_t rtc = RTC_UTC_TEST;
  timeval tv = { rtc, 0 };
  settimeofday(&tv, nullptr);

  // NTP servers may be overridden by your DHCP server for a more local one
  // (see below)

  // ----> Here is the ONLY ONE LINE needed in your sketch
  configTime(MYTZ, "pool.ntp.org");
  // <----
  // Replace MYTZ by a value from TZ.h (search for this file in your filesystem).

  // Former configTime is still valid, here is the call for 7 hours to the west
  // with an enabled 30mn DST
  // configTime(7 * 3600, 3600 / 2, "pool.ntp.org");

  // OPTIONAL: disable obtaining SNTP servers from DHCP
  // sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)

  // Give now a chance to the settimeofday callback,
  // because it is *always* deferred to the next yield()/loop()-call.
  yield();

  // start network
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);

  // don't wait for network, observe time changing
  // when NTP timestamp is received
  showTime();
}

void loop() {
  if (showTimeNow) { showTime(); }
}

@Wawa
Leo, This is what I have found that gives me the Date/Time in the format I'm used to.
I'll clean it up with all the comment notes and "Serial.print" lines when I'm done.

  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-date-time-ntp-client-server-arduino/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Replace with your network credentials
const char *ssid = "MySSID";
const char *password = "MyPassword";

// Define NTP Client to get time
WiFiUDP ntpUDP;
//NTPClient timeClient(ntpUDP, "pool.ntp.org"); //  ******** ORIGINAL LINE ********
NTPClient timeClient(ntpUDP, "3.us.pool.ntp.org");  // NTP servers in the US:  0.us.pool.ntp.org, 1.us.pool.ntp.org, 2.us.pool.ntp.org, 3.us.pool.ntp.org

//Week Days
String weekDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

//Month names
String months[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, for example:
  // GMT +1 = 3600
  // GMT +8 = 28800
  // GMT -1 = -3600
  // GMT 0 = 0

  timeClient.setTimeOffset(-14400);  //  adjusted for (Eastern Standard Time) time zone
}

void loop() {
  timeClient.update();

  time_t epochTime = timeClient.getEpochTime();
  //  Serial.print("Epoch Time: ");
  //  Serial.println(epochTime);

  // String formattedTime = timeClient.getFormattedTime();
  // Serial.print("Formatted Time: ");
  // Serial.println(formattedTime);

  int currentHour = timeClient.getHours();
  // Serial.print("Hour: ");
  // Serial.println(currentHour);

  int currentMinute = timeClient.getMinutes();
  //   Serial.print("Minutes: ");
  // Serial.println(currentMinute);

  int currentSecond = timeClient.getSeconds();
  // Serial.print("Seconds: ");
  // Serial.println(currentSecond);

  String weekDay = weekDays[timeClient.getDay()];
  // Serial.print("Week Day: ");
  // Serial.println(weekDay);

  //Get a time structure
  struct tm *ptm = gmtime((time_t *)&epochTime);

  int monthDay = ptm->tm_mday;
  // Serial.print("Month day: ");
  //  Serial.println(monthDay);

  int currentMonth = ptm->tm_mon + 1;
  // Serial.print("Month: ");
  // Serial.println(currentMonth);

  String currentMonthName = months[currentMonth - 1];
  // Serial.print("Month name: ");
  // Serial.println(currentMonthName);

  int currentYear = ptm->tm_year + 1900;
  // Serial.print("Year: ");
  // Serial.println(currentYear);

  //Print complete date:
  String currentDate = String(weekDay) + ": " + String(currentMonthName) + " " + String(monthDay) + ", " + String(currentYear);
  // Serial.print("Current date: ");
  Serial.print(currentDate);
  Serial.print("  ");
  String formattedTime = timeClient.getFormattedTime();
  // Serial.print("Formatted Time: ");
  Serial.println(formattedTime);
  Serial.println("");

  delay(60000);
}

I saw several of your sketches calculating Sunrise/Sunset. NICE. Not sure I really want all that. Mostly over my head. I just planned on using a light sensor, relay for a beacon light come on when visibility got dark. And, an Adafruit VCNL4010 (Distance sensor) to detect I have mail.

Old way to manually set the time offset.
configTime(MY_TZ, MY_NTP_SERVER);
with MY_TZ you can enter your location, which includes automatic daylight savings.
See this page.

Leo..

NOAA uses 15 minutes.

Post#12 seems a mashup of different codes, with some things not needed or double.
Forget about the RandomNerd Tutorial. They usually do a good job, but their NTP example is outdated.

I have writen an example with sunrise/set detection based on the more recent code from Werner Rothschopf (link in post#13). Make sure your ESP board files are up to date.
Two more NTP pools are added, not sure if that's needed.
The sketch assumes the location is New York. Instructions are in the code to change that.
The blue LED on the ESP8266 now simulates the lighthouse light, which comes on when the sun is 3.0 degrees behind the horizon.
You can of course also turn off the light earlier, using the tm.tm_hour (say at 23:00) or tm.tm_wday variable (midnight).
Tested on a NodeMCU ESP8266.
Leo..

Edit: changed to the native 74880 baudrate of the ESP8266.
Added a call back that waits in setup() for a valid NTP string.
Fixed (added) leading zeroes in time display.

#ifndef STASSID
#define STASSID "MySSID"  // set your SSID
#define STAPSK "MyPassword"       // set your wifi password
#endif

// to find lat/long in decimal degrees, Google maps, right-click location, left-click numbers, paste in program, round to four decimal places
const float latitude = 40.7159, longitude = -74.0047;  // New York

/* Configuration of NTP */
#define MY_NTP_SERVER1 "pool.ntp.org"
#define MY_NTP_SERVER2 "0.pool.ntp.org"
#define MY_NTP_SERVER3 "1.pool.ntp.org"
#define MY_TZ "EST5EDT,M3.2.0,M11.1.0"  // New York

/* Necessary Includes */
#include <ESP8266WiFi.h>      // we need wifi to get internet access
#include <SolarCalculator.h>  // install jpb10 library
#include <coredecls.h>        // optional settimeofday_cb() callback to check on server

/* Globals */
const char *weekDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
const char *months[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
double az, el;
bool reSync;
unsigned long prevTime;
char timeStr[9];
time_t now;  // this are the seconds since Epoch (1970) - UTC
tm tm;       // the structure tm holds time information in a more convenient way

void time_is_set() {  // no parameter until 2.7.4
  Serial.println(F("time was sent!"));
  reSync = true;
}

void showTime() { // optional printout
  Serial.print("sun elevation: ");
  Serial.print(el);  // elevation in degrees, azimuth (az) is also available
  Serial.print("  ");
  Serial.print(weekDays[tm.tm_wday]);
  Serial.print(" ");
  Serial.print(months[tm.tm_mon]);  // January = 0
  Serial.print(" ");
  Serial.print(tm.tm_mday);  // day of month
  Serial.print("  ");
  sprintf(timeStr, "%02u:%02u:%02u", tm.tm_hour, tm.tm_min, tm.tm_sec);
  Serial.print(timeStr);
  Serial.print("  ");
  if (tm.tm_isdst) Serial.print("Summer");  // Daylight Saving Time flag
  else Serial.print("Winter");
  Serial.print("  ");
  Serial.print(tm.tm_year + 1900);  // years since 1900
  Serial.println();
}

void setup() {
  Serial.begin(74880); // native baudrate for the ESP8266
  pinMode(LED_BUILTIN, OUTPUT);  // TEST: onboard LED as lighthouse LED
  Serial.println("\nNTP TZ DST + solar");
  configTime(MY_TZ, MY_NTP_SERVER1, MY_NTP_SERVER2, MY_NTP_SERVER3);  // --> Here is the IMPORTANT ONE LINER needed in your sketch!
  settimeofday_cb(time_is_set);                                       // optional: callback if time was sent
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);  // start network
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");  // by default, the NTP will be started after 60 secs
  while (!reSync) yield();             // wait here for a valid time string
}

void loop() {
  time(&now);                                                     // load epoch
  if (now != prevTime) {                                          // if time(seconds)has changed
    prevTime = now;                                               // remember
    localtime_r(&now, &tm);                                       // convert to local time
    calcHorizontalCoordinates(now, latitude, longitude, az, el);  // calculate sun position
    if (el > -3.0) digitalWrite(LED_BUILTIN, HIGH);                // turn lighthouse on when the sun is x degrees behind the horizon
    else digitalWrite(LED_BUILTIN, LOW);                          // turn lighthouse off
    showTime();                                                   // can remove this and it's function if no printing is required
  }
}

You can connect LDR to 3.3V and a fixed resistor (e.g., 10kΩ) to GND.
Connect the junction to an analog pin (A0 on ESP8266).
Read analogRead(A0), and use a threshold value to determine "dark".
If you want to build a Web-Server Based Weather Monitoring System Using ESP32, you can see here:

I use the above sunrise/sunset code in my indoor clocks, to adjust brightness, and it works very well.
No need to construct a watertight LDR that could rot away in two years (as LDRs do in a damp environment).
Leo..

LDR? Same as a Photo Resister? Nah, I like your sketch WAY better. Watching the onboard LED switch on/off with Sunrise/Sunset. Spot-on!
Couple of Questions/Notes embedded in the sketch (*******)

#ifndef STASSID
#define STASSID "MySSID"      // set your SSID
#define STAPSK "MyPassword!"  // set your wifi password
#endif

// to find lat/long in decimal degrees, Google maps, right-click location, left-click numbers, paste in program, round to four decimal places
//  ******** WHY four DECIMAL PLACES? ********
const float latitude = 34.7761849, longitude = -77.439806;  // Near Me

/* Configuration of NTP */
#define MY_NTP_SERVER1 "pool.ntp.org"
#define MY_NTP_SERVER2 "0.pool.ntp.org"
#define MY_NTP_SERVER3 "1.pool.ntp.org"
#define MY_TZ "EST5EDT,M3.2.0,M11.1.0"  // New York

/* Necessary Includes */
#include <ESP8266WiFi.h>      // we need wifi to get internet access
#include <SolarCalculator.h>  // install jpb10 library  ******** INSTALLED! ********
#include <coredecls.h>        // optional settimeofday_cb() callback to check on server

/* Globals */
const char *weekDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
const char *months[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
double az, el;
bool reSync;
unsigned long prevTime;
time_t now;  // this are the seconds since Epoch (1970) - UTC
tm tm;       // the structure tm holds time information in a more convenient way

void time_is_set() {  // no parameter until 2.7.4
  Serial.println(F("time was sent!"));
  reSync = true;
}

void showTime() {  // optional printout
  Serial.print(weekDays[tm.tm_wday]);
  Serial.print(" ");
  Serial.print(months[tm.tm_mon]);  // January = 0
  Serial.print(" ");
  Serial.print(tm.tm_mday);  // day of month
  Serial.print(", ");
  Serial.print(tm.tm_year + 1900);  // years since 1900
  Serial.print("  ");
  Serial.print(tm.tm_hour);  // hours since midnight  0-23
  Serial.print(":");
  Serial.print(tm.tm_min);  // minutes after the hour  0-59
  //  Serial.print(":");
  //  Serial.print(tm.tm_sec);  // seconds after the minute  0-61*
  Serial.print("  ");
  if (tm.tm_isdst) Serial.print("Summer: DST");  // Daylight Saving Time flag
  else Serial.print("Winter: !DST");
  Serial.print("  ");
  // ********  Shows the angle of the sun; used to calculate sunrise/sunset ********
  Serial.print("sun elevation: ");
  Serial.print(el);  // elevation in degrees, azimuth (az) is also available
  Serial.print("  ");


  // ******** ADDED "SUNRISE/SUNSET" if STATEMENT ********
  if (el < -3) Serial.println("Sunset");
  else Serial.println("Sunrise");
}

void setup() {
  Serial.begin(74880);
  pinMode(LED_BUILTIN, OUTPUT);  // TEST: onboard LED as lighthouse LED  ******** WORKS! ********
  Serial.println("\nNTP TZ DST + solar");
  configTime(MY_TZ, MY_NTP_SERVER1, MY_NTP_SERVER2, MY_NTP_SERVER3);  // --> Here is the IMPORTANT ONE LINER needed in your sketch!
  settimeofday_cb(time_is_set);
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);  // start network
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");  // by default, the NTP will be started after 60 secs
  while (!reSync) yield();             // wait here for a valid time string
}

void loop() {
  time(&now);                                                     // load epoch
  if (now != prevTime) {                                          // if time(seconds)has changed
    prevTime = now;                                               // remember
    localtime_r(&now, &tm);                                       // convert to local time
    calcHorizontalCoordinates(now, latitude, longitude, az, el);  // calculate sun position
    if (el > -3.0) digitalWrite(LED_BUILTIN, HIGH);               // turn lighthouse on when the sun is x degrees behind the horizon
    //  ********  WHY -3.0?  ********
    else digitalWrite(LED_BUILTIN, LOW);                          // turn lighthouse off
    showTime();                                                   // can remove this and it's function if no printing is required
  }
  delay(10000);  // Run every ten seconds  ********  Does not need delay; I added it to see changes in the serial print  ********
}

Thanks! Nick

Good to hear you got it working.

Four is already enough accuracy for sunrise difference at both ends of your street.
No harm done if you use all decimal places.

if (now >= prevTime + 10) { // should do the same
This if condition was added to only print when the time in seconds had changed.

Twilight at -3 degrees was used in the code, but for a lighthouse nautical twilight at -6 or even -12 could be more suitable.You can of course still print sunrise/set at 0.0 degrees.
Leo..