Black Lives Matter - Action and Equality.
0

Dusk2Dawn.h won't compile on Trinket M0
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Fri Sep 13, 2019 1:23 pm

My sketch uses a DS3231, a 16x2 LCD and small solid state relay to turn a small light on and off based on sunrise and sunset. I'm using wire.h, LCD.h, RTClib.h, LiquidCrystal_I2C.h and Dusk2Dawn.h. The latter is used to calculate sunrise and sunset times. The sketch runs just fine on a Feather M0. On the Trinket M0 Dusk2Dawn will not compile. When I comment out everything having to do with this library, the rest of the sketch compiles, loads and runs just fine on the Trinket M0. I get these two errors:

error: cannot declare member function 'static bool Dusk2Dawn::min2str(char*, int)' to have static linkage [-fpermissive]

error: cannot declare member function 'static bool Dusk2Dawn::zeroPadTime(char*, byte)' to have static linkage [-fpermissive]

Anyone have any idea what this means and how I can fix it?

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by adafruit_support_mike on Sun Sep 15, 2019 4:00 am

'Static member functions' are functions associated with a class, and not with any specific instance of that class. They're generally used to set or read behind-the-scenes 'static variables' that control the way objects behave.. configuring all objects in a 'String' class to switch between UTF-8 and ASCII, for instance.

The error above means the code used the 'static' keyword where it shouldn't. Post the contents of your Dusk2Dawn.h and Dusk2Dawn.cpp files between CODE tags please.

adafruit_support_mike
 
Posts: 61107
Joined: Thu Feb 11, 2010 2:51 pm

Re: Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Mon Sep 16, 2019 10:54 am

Looking again at the compiler error, it appears to be with Dusk2Dawn.cpp. However, I cannot find any reference to "static" in the .cpp file. I did find one reference to "static" very close to the end of the .h file:

static bool zeroPadTime(char*, byte);

I wonder if I just eliminate the word "static", would that solve the problem?

I've attached/uploaded both the .cpp and .h libraries but not sure I am doing it correctly. Please forgive me. Thanks for your help.

Code: Select all | TOGGLE FULL SIZE
/*  Dusk2Dawn.cpp
 *  Get time of sunrise and sunset.
 *  Created by DM Kishi <dm.kishi@gmail.com> on 2017-02-01.
 *  <https://github.com/dmkishi/Dusk2Dawn>
 */

#include "Arduino.h"
#include <math.h>
#include "Dusk2Dawn.h"



/******************************************************************************/
/*                                   PUBLIC                                   */
/******************************************************************************/
/* Though most time zones are offset by whole hours, there are a few zones
 * offset by 30 or 45 minutes, so the argument must be declared as a float.
 */
Dusk2Dawn::Dusk2Dawn(float latitude, float longitude, float timezone) {
  _latitude  = latitude;
  _longitude = longitude;
  _timezone  = timezone;
}


int Dusk2Dawn::sunrise(int y, int m, int d, bool isDST) {
  return sunriseSet(true, y, m, d, isDST);
}


int Dusk2Dawn::sunset(int y, int m, int d, bool isDST) {
  return sunriseSet(false, y, m, d, isDST);
}


/* Convert minutes elapsed since midnight, the figure returned by the public
 * methods sunrise() and sunset(), to a 24-hour clock format, e.g. "23:00".
 *
 * This is done by filling a passed character array, which must be of length 6,
 * e.g. "12:34\0". In case of an error, the array is written as "ERROR" (which
 * is coincidently the same length as the clock format.) This is much friendlier
 * and obvious than having to check the function return, which is still provided
 * for error handling purposes.
 *
 * This function is provided as a static method so that returned minutes can be
 * worked on before requesting a formatted time. For instance, given the time of
 * sunrise and sunset, the solar noon can be calculated, at which point it can
 * be converted to a 24-hour clock format.
 *
 * String classes are avoided to keep memory use to a minimum.
 */
bool Dusk2Dawn::min2str(char *str, int minutes) {
  bool isError = false;

  if (minutes < 0 || minutes >= 1440) {
    isError = true;
  }

   float floatHour   = minutes / 60.0;
   float floatMinute = 60.0 * (floatHour - floor(floatHour));
   byte  byteHour    = (byte) floatHour;
   byte  byteMinute  = (byte) floatMinute;

   if (byteMinute > 59) {
     byteHour   += 1;
     byteMinute  = 0;
   }

   char strHour[]   = "00";
   char strMinute[] = "00";

   // In case of an error, keep passing it down.
   isError = isError ? isError : !zeroPadTime(strHour, byteHour);
   isError = isError ? isError : !zeroPadTime(strMinute, byteMinute);

   // This is fugly but I can't think of a better way....
   if (!isError) {
     str[0] = strHour[0];
     str[1] = strHour[1];
     str[2] = ':';
     str[3] = strMinute[0];
     str[4] = strMinute[1];
     str[5] = '\0';
   } else {
     str[0] = 'E';
     str[1] = 'R';
     str[2] = 'R';
     str[3] = 'O';
     str[4] = 'R';
     str[5] = '\0';
   }

   return !isError;
}


/******************************************************************************/
/*                                  PRIVATE                                   */
/******************************************************************************/
int Dusk2Dawn::sunriseSet(bool isRise, int y, int m, int d, bool isDST) {
  float jday, newJday, timeUTC, newTimeUTC;
  int timeLocal;

  jday    = jDay(y, m, d);
  timeUTC = sunriseSetUTC(isRise, jday, _latitude, _longitude);

  // Advance the calculated time by a fraction of itself. I've no idea what the
  // purpose of this is.
  newJday    = jday + timeUTC / (60 * 24);
  newTimeUTC = sunriseSetUTC(isRise, newJday, _latitude, _longitude);

  if (!isnan(newTimeUTC)) {
    timeLocal  = (int) round(newTimeUTC + (_timezone * 60));
    timeLocal += (isDST) ? 60 : 0;
  } else {
    // There is no sunrise or sunset, e.g. it's in the (ant)arctic.
    timeLocal = -1;
  }

  return timeLocal;
}


float Dusk2Dawn::sunriseSetUTC(bool isRise, float jday, float latitude, float longitude) {
  float t         = fractionOfCentury(jday);
  float eqTime    = equationOfTime(t);
  float solarDec  = sunDeclination(t);
  float hourAngle = hourAngleSunrise(latitude, solarDec);

  hourAngle = isRise ? hourAngle : -hourAngle;
  float delta   = longitude + radToDeg(hourAngle);
  float timeUTC = 720 - (4 * delta) - eqTime; // in minutes
  return timeUTC;
}


/* ---------------------------- EQUATION OF TIME ---------------------------- */
/* The difference between mean solar time (as shown by clocks) and apparent
 * solar time (indicated by sundials), which varies with the time of year.
 */
float Dusk2Dawn::equationOfTime(float t) {
  float epsilon = obliquityCorrection(t);
  float l0      = geomMeanLongSun(t);
  float e       = eccentricityEarthOrbit(t);
  float m       = geomMeanAnomalySun(t);

  float y = tan(degToRad(epsilon) / 2);
  y *= y;

  float sin2l0 = sin(2.0 * degToRad(l0));
  float sinm   = sin(degToRad(m));
  float cos2l0 = cos(2.0 * degToRad(l0));
  float sin4l0 = sin(4.0 * degToRad(l0));
  float sin2m  = sin(2.0 * degToRad(m));

  float Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m;
  return radToDeg(Etime) * 4.0; // in minutes of time
}


/* Obliquity of the ecliptic is the term used by astronomers for the inclination
 * of Earth's equator with respect to the ecliptic, or of Earth's rotation axis
 * to a perpendicular to the ecliptic.
 */
float Dusk2Dawn::meanObliquityOfEcliptic(float t) {
  float seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * 0.001813));
  float e0      = 23 + (26 + (seconds / 60)) / 60;
  return e0; // in degrees
}


float Dusk2Dawn::eccentricityEarthOrbit(float t) {
  float e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
  return e; // unitless
}


/* --------------------------- SOLAR DECLINATION ---------------------------- */
float Dusk2Dawn::sunDeclination(float t) {
  float e      = obliquityCorrection(t);
  float lambda = sunApparentLong(t);

  float sint  = sin(degToRad(e)) * sin(degToRad(lambda));
  float theta = radToDeg(asin(sint));
  return theta; // in degrees
}


float Dusk2Dawn::sunApparentLong(float t) {
  float o      = sunTrueLong(t);
  float omega  = 125.04 - 1934.136 * t;
  float lambda = o - 0.00569 - 0.00478 * sin(degToRad(omega));
  return lambda; // in degrees
}


float Dusk2Dawn::sunTrueLong(float t) {
  float l0 = geomMeanLongSun(t);
  float c  = sunEqOfCenter(t);
  float O  = l0 + c;
  return O; // in degrees
}


float Dusk2Dawn::sunEqOfCenter(float t) {
  float m     = geomMeanAnomalySun(t);
  float mrad  = degToRad(m);
  float sinm  = sin(mrad);
  float sin2m = sin(mrad * 2);
  float sin3m = sin(mrad * 3);
  float C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
  return C; // in degrees
}


/* ------------------------------- HOUR ANGLE ------------------------------- */
float Dusk2Dawn::hourAngleSunrise(float lat, float solarDec) {
  float latRad = degToRad(lat);
  float sdRad  = degToRad(solarDec);
  float HAarg  = (cos(degToRad(90.833)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad));
  float HA     = acos(HAarg);
  return HA; // in radians (for sunset, use -HA)
}


/* ---------------------------- SHARED FUNCTIONS ---------------------------- */
float Dusk2Dawn::obliquityCorrection(float t) {
  float e0    = meanObliquityOfEcliptic(t);
  float omega = 125.04 - 1934.136 * t;
  float e     = e0 + 0.00256 * cos(degToRad(omega));
  return e; // in degrees
}


float Dusk2Dawn::geomMeanLongSun(float t) {
  float L0 = 280.46646 + t * (36000.76983 + t * 0.0003032);
  while (L0 > 360) {
    L0 -= 360;
  }
  while (L0 < 0) {
    L0 += 360;
  }
  return L0; // in degrees
}


float Dusk2Dawn::geomMeanAnomalySun(float t) {
  float M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
  return M; // in degrees
}


/* --------------------------- UTILITY FUNCTIONS ---------------------------- */
/* Convert Gregorian calendar date to Julian Day.
 */
float Dusk2Dawn::jDay(int year, int month, int day) {
  if (month <= 2) {
    year  -= 1;
    month += 12;
  }

  int A = floor(year/100);
  int B = 2 - A + floor(A/4);
  return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) +
         day + B - 1524.5;
}


/* Return fraction of time elapsed this century, AD 2000–2100.
 *
 * NOTE: 2,451,545 was the Julian day starting at noon UTC on 1 January AD 2000.
 *       36,525 is a Julian century.
 */
float Dusk2Dawn::fractionOfCentury(float jd) {
  return (jd - 2451545) / 36525;
}


float Dusk2Dawn::radToDeg(float rad) {
  return 180 * rad / PI;
}


float Dusk2Dawn::degToRad(float deg) {
  return PI * deg / 180;
}


/* Zero-pad a component of time, e.g. 1 → "01", 24 → "24".
 *
 * NOTE: Supports integers of up to only two digits.
 */
bool Dusk2Dawn::zeroPadTime(char *str, byte timeComponent) {
  if (timeComponent >= 100) { return false; }

  str[0] = (floor(timeComponent / 10)) + '0';
  str[1] = (timeComponent % 10) + '0';
  return true;
}


Code: Select all | TOGGLE FULL SIZE
/*  Dusk2Dawn.h
 *  Get time of sunrise and sunset.
 *  Created by DM Kishi <dm.kishi@gmail.com> on 2017-02-01.
 *  <https://github.com/dmkishi/Dusk2Dawn>
 */

#ifndef Dusk2Dawn_h
#define Dusk2Dawn_h

  #include "Arduino.h"
  #include <math.h>

  class Dusk2Dawn {
    public:
      Dusk2Dawn(float, float, float);
      int sunrise(int, int, int, bool);
      int sunset(int, int, int, bool);
      static bool min2str(char*, int);
    private:
      float _latitude, _longitude;
      int   _timezone;
      int   sunriseSet(bool, int, int, int, bool);
      float sunriseSetUTC(bool, float, float, float);
      float equationOfTime(float);
      float meanObliquityOfEcliptic(float);
      float eccentricityEarthOrbit(float);
      float sunDeclination(float);
      float sunApparentLong(float);
      float sunTrueLong(float);
      float sunEqOfCenter(float);
      float hourAngleSunrise(float, float);
      float obliquityCorrection(float);
      float geomMeanLongSun(float);
      float geomMeanAnomalySun(float);
      float jDay(int, int, int);
      float fractionOfCentury(float);
      float radToDeg(float);
      float degToRad(float);
      static bool zeroPadTime(char*, byte);
  };

#endif
Attachments
Dusk2Dawn.h
(1.18 KiB) Downloaded 9 times
Dusk2Dawn.cpp
(8.75 KiB) Downloaded 10 times

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by adafruit_support_mike on Tue Sep 17, 2019 1:26 am

That looks okay.. the 'static' keyword can only appear inside the class definition, and I don't see any use of it anywhere else.

Post your own code between CODE tags please.. let's see if that has any clues.

adafruit_support_mike
 
Posts: 61107
Joined: Thu Feb 11, 2010 2:51 pm

Re: Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Wed Sep 18, 2019 12:13 am

Attached is the original sketch that would not compile due to the "error" in Dusk2Dawn. However, I shortened the sketch into a debugger version and tried a couple of things. If I run the sketch as coded below, it won't compile and I get the error messages discussed. If I remove all the functions and code from the body of the sketch that have anything to do with Dusk2Dawn but leave in "#include Dusk2Dawn.h" it won't compile. If I then comment out "#include Dusk2Dawn.h" it compiles OK. So it appears that the issue is when it runs across the phrase "#include Dusk2Dawn.h", not the actual stuff in the body of the code.

I am going to mock up this project using the Adafruit Feather 32U4 basic photo, upon which a different sketch also using Dusk2Dawn compiles and runs just fine. I think it's the board foursome reason, or maybe the specific processor.

Code: Select all | TOGGLE FULL SIZE
/*   This sketch uses a generic Chinese LCD backpack to allow any LCD screen to be driven via I2C through a PCF8574T multiplexing chip.
 *   
 *   
 *  This sketch is designed to control the gate lights at 1130 Watercress Way such that the lights come on at a stated time on or after
 *  sunset and turn off at a stated time on or before sunrise.
 * 
 *  Timing of Sunrise and sunset is retrieved from the Dusk2Dawn library in minutes since midnight Standard time.
 * 
 *  All timer events based on sunrise and sunset are calculated and used in Standard Time.
 * 
 *  Timing is controlled by a high accuracy Adafruit DS3231 RTC with coin cell battery backup to maintain clock in the event of a power outage. Coin cell does not recharge.
 * 
 *  Order of flow:
 *  -include libraries
 *  -define and preload variables
 *  -In void setup():
 *     define output pins.
 *  -In void loop():
 *     Get time from RTC at the beginning of each loop cycle.
 *     Get sunrise/sunset times once daily.
 *     Turn lights on in evening, approximately at sunset, with an offset available.
 *     Turn lights off at sunrise or thereabouts.
 *  End of loop
 * 
 *  END
 * 
 *  SEE ADDITIONAL COMMENTS IMMEDIATELY PRECEDING EACH SECTION BELOW.
 *  NOTE 1: There is a debugging flag that will turn on serial printing and print debugging text.
 *  Note 2: This program does not set RTC to the correct time. Load and run arduino sketch "DS3231_set_time" to update RTC prior to using this sketch.
 * 
 *  Written by:
 * 
       *  W. James Gealy, Jr. MD
       * 
       *  Varian Ranch Rocket Works
       *  1130 Watercress Way
       *  Arroyo Grande, CA 93420
       *  (805) 441-3967
       *  jgealy@mac.com
 * 
 *  Version History   
 *    v.1a   June 21, 2019
 * 
 
 *  Hardware and Arduino development board consist of Adafruit Trinket M0, Adafruit DS3231 RTC, Adafruit blue or generic
 *  green LCD with Chineses I2C backpack. Sketch uses XXX bytes of
 *  program storage space. Maximum is YYY bytes. Global variables use ZZZ bytes of dynamic memory.
 */

#include <Wire.h>                      // Allows use of I2C for LED backpack and DS3231 RTC.
#include "RTClib.h"
#include <LCD.h>
#include <LiquidCrystal_I2C.h>         // Library for cheap Chinese LCD backpack multiplexing.
#include <Dusk2Dawn.h>                 // Library for calculating solar times

RTC_DS3231 rtc;                        // designates the Adfruit DS3231 as the RTC

LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7); // 0x27 is the I2C bus address for an unmodified cheap Chinese LCD backpack


bool debugFlag = true;      // set here to TRUE to turn on serial printing
bool useDST = true;         // set here to TRUE to allow timer to display time in DST as appropriate on LCD. FALSE allows DST to be disabled if not used regionally
                            //   or if government decides to eliminate DST nationally. NOTE: This affects display only. ON/OFF events are solely based on sunrise/sunset
                            //   calculated times.


char shortMonth[12][6] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};  // sets three letter month for LCD display

const float myLat = 35.186;      // latitude of Varian Ranch, Arroyo Grande, CA
const float myLong = -120.548;   // longitude of Varian Ranch, Arroyo Grande, CA
const float myTZ = -8;           // time zone offset in hours from UTC (is float to handle certain partial-hour time zones like Newfoundland.

const byte relayPin = 5;      // Designates digitalWrite pin for setting relay. To activate relay, pin must go HIGH.

const byte sunriseOffset = 0;    // + or - minutes of offset from sunrise you want an event to occur
const byte sunsetOffset = 0;     // + or - minutes of offset from sunset you want an event to occur

int sunriseMinutes = 0;
int sunsetMinutes = 0;
int sunriseHr = 0;
int sunriseMin = 0;
int sunsetHr = 0;
int sunsetMin = 0;

byte nowSecond = 0;

byte getSRSSflag = 0;        // flag is set to current day when SRSS function is queried. Allows query to happen only once per day at 0100. values 1-31
                             // or 0 if sunrise/sunset function has never been run (like at first startup).

bool DST = false;            // Flag to indicate whether daylight savings time is in effect or not.

bool DSTchecked = false;     // Flag to indicate whether DST has ever been checked. Allows first check at time of first run, otherwise only once daily at 0200.
bool overrideTrigger = false;

byte Lminicolon[8] =          // define the Left mini-colon symbol for use with LCD display
    {
     B00000,
     B00000,
     B01000,
     B00000,
     B00000,
     B01000,
     B00000,
     B00000
    };
 
  byte Cminicolon[8] =        // define the Center mini-colon symbol for use with LCD display
    {
     B00000,
     B00000,
     B00100,
     B00000,
     B00000,
     B00100,
     B00000,
     B00000
    };

  byte specialApost[8] =      // define the special apostrophe symbol for use with LCD display
    {
     B00001,
     B00001,
     B00000,
     B00000,
     B00000,
     B00000,
     B00000,
     B00000
    };
   
   byte miniD[8] =            // define the special DST diamond symbol for use with LCD display
    {
     B00000,
     B00000,
     B00100,
     B01010,
     B00100,
     B00000,
     B00000,
     B00000
    };



 
   
void setup() {
 
  pinMode(relayPin, OUTPUT);
  pinMode(13, OUTPUT);      // To light LED on board and possibly on outside of box indicating that relay is ON.

  digitalWrite(13, LOW);    // Insures LED flag pin is low (LED off) at start of sketch
  digitalWrite(relayPin, LOW);  // Insures relay pin is low (relay is off) at start of sketch
   
  if (debugFlag){
    Serial.begin(9600);               // For display of debugging output.
  }

  lcd.begin(16, 2);                 // set up the LCD's number of columns and rows.
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);
 
  lcd.createChar(1, Lminicolon);    // create Left mini-colon symbol from the binary.
  lcd.createChar(2, Cminicolon);    // create Center mini-colon symbol from the binary.
  lcd.createChar(3, specialApost);  // create special small apostrophe from the binary.
  lcd.createChar(4, miniD);         // create small diamond to denote DST from the binary.
 

  lcd.setCursor(0,0);                       // prints first row of LCD.
  lcd.print("    BINFORD      ");
  lcd.setCursor(0, 1);
  lcd.print("Crepusculor Mk.1");
  delay(5000);
  lcd.setCursor(0, 0);
  lcd.print("Software v.1a  ");
  lcd.setCursor(0, 1);
  lcd.print("James Gealy 2019");
  delay(5000);
  lcd.clear();
 
}
 

void loop() {
 
   DateTime now = rtc.now();        // get current RTC time.
   
   /*Serial.print(now.year());
    Serial.print('/');
    Serial.print(now.month());
    Serial.print('/');
    Serial.print(now.day());
    Serial.print(" (");
    tester = now.second() - 2;
    Serial.print(now.dayOfTheWeek()
    );
    Serial.print(") ");
    Serial.print("(DST ");
    Serial.print(DST);
    Serial.print(") ");
    if ((now.hour()) <10){ Serial.print('0');}
    Serial.print(now.hour());
    Serial.print(':');
    if ((now.minute()) <10){ Serial.print('0');}
    Serial.print(now.minute());
    Serial.print(':');
    if ((now.second()) <10){ Serial.print('0');}
    Serial.print(now.second());
    Serial.println("   ");
   
*/
/********************************************************
    Calculate whether DST or not and set DST flag accordingly, 0 for standard time, +1 for Daylight Savings Time.
    Current rules for DST:  begins second Sunday in March at 0200 and ends first Sunday in November at 0200.
    To save processor overhead, DST is calculated once daily at 02:00:00.  DSTchecked flag is there to allow DST
    to be checked the first time at sketch upload, independent of current time.
********************************************************/

  if (useDST == false) {        // If useDST is false (via initial setup or DIP switch for example) the DST  algorithm is bypassed.
    DST = false;
  }
  else {
      if (((now.hour() == 2) && ((now.minute() + now.second()) == 0)) || !DSTchecked) {     // allows DST algorithm to run at startup or for only
            DSTchecked = true;                                                              //   one second daily at 0200.

            DST = false;                  // sets all dates to (DST = false) x specific else-if exceptions that fall out below.
           
           
            if ((now.month() > 3) && (now.month() < 11)) {      // Months Apr thru Oct are always DST.
               DST = true;
            }
                                                               
            // int y = now.year() - 2000     
            // int x = (y + y/4 + 2) % 7     // when subtracted from 7 or 14, modulo gives the day of the month that is Sunday
           
            else if ((now.month() == 3) && (now.day() >= (14 - (((now.year() - 2000) + ((now.year() - 2000) / 4) + 2) % 7)))) {   
               DST = true;                              // This line accounts for second Sunday in March and after.                   
            }
           
            else if ((now.month() == 11) && ((now.day() - now.dayOfTheWeek()) < 1)) {
              DST = true;                               // This line accounts for days in November BEFORE the first sunday.
            }
         
       
      }
  }


   
/********************************************************
    Get sunrise and sunset times once daily at 1:00AM Standard Time and set getSRSSflag to today's date so the sunrise/sunset
    function runs only once daily to cut down on processor overhead. "OR" statement in first line also allows an exception to get
    sunrise and sunset times the very first time the code is run at startup when getSRSSflag = 0 and the sketch is probably
    being first run at a time other than 0100. Note that after this section is run for the first time, getSRSSflag will always
    be between 1 and 31. 
********************************************************/
   
   if (((now.hour() == 1) && (getSRSSflag != now.day())) || (getSRSSflag == 0)) { // OR parameter allows sunrise/sunset time to also be acquired at first startup 
      getSRSSflag = now.day();            // resets getSRSSflag to today's date
   
      Dusk2Dawn myHouse(myLat, myLong, myTZ);
     
      sunriseMinutes = myHouse.sunrise(now.year(), now.month(), now.day(), false);   // value for sunrise is number of minutes since midnight, no DST
      sunsetMinutes = myHouse.sunset(now.year(), now.month(), now.day(), false);    // value for sunset is number of minutes since midnight, no DST
     
      sunriseHr = sunriseMinutes / 60;    // converts sunriseMinutes into hours
      sunriseMin = sunriseMinutes % 60;   // converts remainder into minutes
      sunsetHr = sunsetMinutes / 60;      // converts sunsetMinutes into hours (24 hour clock)
      sunsetMin = sunsetMinutes % 60;     // converts remainder into minutes

   }     
    /*Serial.print("getSRSSflag: ");
    Serial.print(getSRSSflag);
    Serial.print("  ");
    Serial.print(sunriseMinutes);
    Serial.print("  ");
    Serial.print(sunsetMinutes);
    Serial.print("  ");

    Serial.print(sunriseHr);
    Serial.print(":");
    Serial.print(sunriseMin);
    Serial.print("  ");
    Serial.print(sunsetHr);
    Serial.print(":");
    Serial.println(sunsetMin);
   */

   
/********************************************************
    Write month, day, year, current time, and sunrise/sunset times to LCD. Month displays as three letter abbreviation and year
    is shortened to an apostrophe and the last two digits. Sunrise and sunset are displayed in military 24 hour time. All times
    on this display are adjusted for DST as necessary and a special small diamond symbol follows the time to indicate whether
    DST is in effect. nowSecond allows screen rewrite only once per second to save processor overhead.
********************************************************/
  if (now.second() != nowSecond) {                 // if loop allows screen rewrite only once per second
        nowSecond = now.second();
 
        lcd.setCursor(0,0);                       // prints first row of LCD.
        lcd.print(shortMonth[now.month()-1]);
        lcd.print(' ');
        lcd.print(now.day());
        lcd.write(3);                             // prints special apostrophe before year.
        //if ((now.year() - 2000) < 10) { lcd.print('0'); }   // prints leading "0" if year less than 2010.
        lcd.print(now.year() -2000, DEC);
        if (now.day() < 10) { lcd.print(" "); }   // prints a blank to overwrite previous final year digit when day switches from 2 digits to 1 digit                   
        lcd.setCursor(10, 0);                     
        lcd.print("R");                           // prints sunrise designator "R".
        lcd.write(1);                             // prints a special colon.
        lcd.print('0');                          // Sunrise always between 0500 and 0900, thus hour always one digit and will always need leading zero.
        lcd.print(sunriseHr + DST);               // prints sunrise hour adjusted for DST as needed.                   
        if(sunriseMin < 10) { lcd.print('0'); }   // prints leading "0" for minutes as needed.
        lcd.print(sunriseMin);                    // prints sunrise minutes.
       
        lcd.setCursor(0, 1);                      // sets cursor to second row of LCD.
        byte DSThour = (now.hour() + DST);         // adjusts current hour for DST.
        if (DSThour == 24) {  DSThour = 0; }      // handles rollover from 23hr to 0hr.               
        //if (DSThour > 12) { DSThour = (DSThour - 12);}   //cconverts display format to 12 hour clock if un-commented.
        if ((DSThour) < 10) { lcd.print('0'); }   // prints leading "0" if necessary.
        lcd.print(DSThour);                       // prints current hour adjusted for DST.
        lcd.write(2);                             // prints a special colon.
        if ((now.minute()) < 10) { lcd.print('0'); }  // prints leading "0" if necessary.
        lcd.print(now.minute());                  // prints current minute
        lcd.write(2);                             // prints a special colon.
        if ((now.second()) < 10) { lcd.print('0'); }  // prints leading "0" if necessary.
        lcd.print(now.second());
        if (DST == true) {
          lcd.write(4);                           // prints DST diamond symbol if DST is true.
          }
        else
          {
            lcd.print(" ");                        // overwrites any pre-existing DST symbol if DST is false.
          }
        lcd.print(" ");                           // handles overwrite of DST symbol when hour switches from 2 digit to 1 digit

        lcd.setCursor(9, 1);
        lcd.print(" ");
       
       
        lcd.setCursor(10, 1);                     // moves cursor
        lcd.print("S");                           // prints sunset designator "S".
        lcd.write(1);                             // prints a special colon.
        lcd.print(sunsetHr + DST);                // sunset will always be between 1630 and 2100 so sunsetHr will always be 2 digits and never > 23.               
        if(sunsetMin < 10) { lcd.print('0'); }
        lcd.print(sunsetMin);                     // displays sunset time in hours and minutes, 24 hr clock
 
  }
   

/******************************************************************************************
    This section contains the code to turn an indicator LED ON or OFF depending on the status of the
    lighting circuit. i.e if the lights are off, the LED is off. If the lights are on the LED is on.
 * 
 *  this section uses:
 *  digitalRead
 *  digitalWrite
 * 
******************************************************************************************/
  if (digitalRead(relayPin)){
    digitalWrite(13, HIGH);
  }
  else if (!digitalRead(relayPin)){
    digitalWrite(13, LOW);
  }



/******************************************************************************************
    This section contains the code to turn lights on or off based on outlined criteria: Primary
    control is lights ON at at sunset and off at sunrise. The ON and OFF times can be offset by the
    use of sunriseOffset and sunsetOffset variables outlined at the beginning of the sketch.
 * 
 *  this section uses:
 *  sunriseMinutes
 *  sunsetMinutes
 *  DST
 *  lightsOut
 *  delayNight
 *  delayDay
 * 
 *  these IF parameters call the subroutine changeRelayState() to change the lights from on to off or vice-versa.
 * 
******************************************************************************************/
 
  // If current time matches sunsetMinutes + offset, turns lights ON.
  // Including now.second() == 0 limits exposure to a manual switching event during the second of eligibility.
  // No DST compensation since light-on event is triggered by Standard sunset time.
   if ((((now.hour() * 60) + now.minute()) == (sunsetMinutes + sunsetOffset)) && (now.second() == 0)){
    digitalWrite(relayPin, HIGH);
 
  }
 
  // If current time matches sunriseMinutes + offset, turns lights OFF.
  // Including now.second() == 0 limits exposure to a manual switching event during the second of eligibility.
  // No DST compensation since light-on event is triggered by Standard sunrise time.
   if ((((now.hour() * 60) + now.minute()) == (sunriseMinutes + sunriseOffset)) && (now.second() == 0)){
    digitalWrite(relayPin, LOW);
 
  }

}       //this is the end of the void() loop

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by adafruit_support_mike on Wed Sep 18, 2019 12:43 am

What version of the Arduino IDE are you using? I just tried to compile the code above (minus some lines related to the LCD libraries) and it worked.

Different versions of the Arduino IDE have different settings for compiler errors, usually required to keep the low-level Arduino code working properly.

adafruit_support_mike
 
Posts: 61107
Joined: Thu Feb 11, 2010 2:51 pm

Re: Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Thu Sep 19, 2019 1:49 am

I was beginning to wonder the same thing myself. The sketch that compiled OK on the Adafruit Feather 32u4 many months ago was I think Arduino IDE 1.8.6. The current compiling for the Trinket M0 was done with 1.8.9 and I tried it also on 1.8.10 which I downloaded a couple of days ago. It wouldn't compile on either one of these two latest versions.

Should I find a copy of the older 1.8.6 (I'm not sure whether that was the actual version I used - it was over a year ago) and try that again for the trinket M0?

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by adafruit_support_mike on Thu Sep 19, 2019 2:30 am

Yeah, give that a shot.

If you can get the code to compile for one board, but to throw the "can't have static linkage" error for another, it means there's a glitch in the compiler settings. If that happens, you'll have to check with the folks at the Arduino forums to see if there's any workaround:

https://forum.arduino.cc/

adafruit_support_mike
 
Posts: 61107
Joined: Thu Feb 11, 2010 2:51 pm

Re: Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Thu Sep 19, 2019 9:38 am

Ok, I’ll try both an older IDE and trying to upload to a different board. I presume there is nothing in the Arduino IDE preferences I could set to increase compatibility.

What version of the Arduino IDE did you get my sketch to compile on?

Thank you for your expert help. You have gone above and beyond. It’s because of this support that I buy Adafruit products

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by augendoc on Thu Sep 19, 2019 2:26 pm

I took all the different arduino and Adafruit boards I have, breadboarded my circuiting, and tried to compile and run my sketch with the problematic Dusk2Dawn library using Arduino IDE 1.8.10.

The sketch compiled and ran just fine on my Feather 32u4 Basic Proto, Arduino Uno, Arduino Micro, USB Boarduino 2.0, Itsy Bitsy 32u4 8MHz, and Itsy Bitsy M4 Express.

The sketch would NOT compile on my Feather M0 Express and Trinket M0 (the only M0 boards I have). If I comment out Dusk2Dawn.h the sketch compiles and runs OK except for the sunrise and sunset times not getting calculated.

The issue I believe is with the M0 chip itself or the way that the IDE handles certain instructions with that chip. I will approach the Arduino forums to see if they have a solution. My problem at the moment is the Trinket M0 is now soldered to a circuit board and hard wired. My options are to either remove the Trinket M0 and replace it with an Itsy Bitsy 32u4 and rewire everything or else use another sunrise-sunset calculator and rewrite my software. I'm not too keen to do either one.

augendoc
 
Posts: 14
Joined: Mon Dec 08, 2014 4:47 am

Re: Dusk2Dawn.h won't compile on Trinket M0

by adafruit_support_mike on Sat Sep 21, 2019 12:59 am

The microcontroller has nothing to do with compiler errors, especially not what are being reported as syntax errors.

The fact that the code compiles properly for any board means the library is syntactically correct. Whatever error the compiler is reporting is related to the way the compiler is being told to read the code.

The actual error is probably something more obscure. Compilers don't actually report errors, they only report the place where they gave up trying. Strange behavior like this usually means the real problem is somewhere else, but the compiler kept trying to make sense of things until it ran out of options.

adafruit_support_mike
 
Posts: 61107
Joined: Thu Feb 11, 2010 2:51 pm

Please be positive and constructive with your questions and comments.