I want to run cameras at a remote site from external batteries as long as possible. I need power-miser Arduino to switch battery power on/off at set intervals (e.g. 5 min) during daytime only. I am a beginner with Arduino and electronics.
Have set up 'breadboard' arduino with mosfet module for switching the power supply and RTC module, both from Freetronics (http://www.freetronics.com.au/collections/modules/products/real-time-clock-rtc-module#.V-i-S8knuPs). Following their recommendation I'm using RTC library here: http://rweather.github.io/arduinolibs/index.html
I need to refine the crude hour-based script below. Weatherley library returns separate objects e.g date.day, time.hour etc. Is there a simple way to convert to date-time object? Then calculate sunrise and sunset times based on latitude?
#include <JeeLib.h> // power saving library
ISR(WDT_vect) { Sleepy::watchdogEvent(); } // Setup jeelip watchdog
#include <SoftI2C.h> // rweather lib for RTC module
#include <DS3232RTC.h> //rweather lib for RTC module
SoftI2C i2c(A4, A5); // assign pins to SDA and SCL
DS3232RTC rtc(i2c);
RTCTime time;
int gatePin = 12; // mosfet Gate connected to digital pin
int startHour = 6; // want to replace with sunrise time
int endHour = 19; // want to replace with sunset time
void setup()
{
pinMode(gatePin, OUTPUT); // output pin for mosfet module
}
void loop()
{ // main loop starts here
rtc.readTime(&time); //get current time
if (time.hour >= startHour && time.hour < endHour) // check daytime
{ // if condition begins here
while(time.hour < endHour ) // daytime operating period
{ // while loop (day) begins here
digitalWrite(gatePin, HIGH); // turn on gate for power supply
Serial.flush(); //needed before sleepy
Sleepy::loseSomeTime(30000); // low power wait
digitalWrite(gatePin, LOW); // turn off gate for power supply
Serial.flush(); // needed before sleepy
for (int i=0; i <= 3; i++){
Sleepy::loseSomeTime(65000); // low power wait
} // end for loop
rtc.readTime(&time);
} // end while loop (day)
} // if condition (daytime) ends here
else
{ // else condition (night time) starts here
while (time.hour >= endHour || time.hour < startHour )
{ // while loop (night) begins here
for (int i=0; i <= 59; i++){
Serial.flush(); // needed before sleepy
Sleepy::loseSomeTime(65000); // low power wait
} // end for loop
rtc.readTime(&time);
} // while loop (night) ends here
// need to refine timing else hour-long wait periods can run past the end of night period
} // else condition (night) ends here
} // main loop ends here
I will be very grateful for advice, many thanks in advance!
EDIT: Part of my original question could be answered - see below about time-date format without using RTC. Issues with RTC appear harder than I expected. I think they will need a new question later.
-
I'd suggest using a light sensor. That way you can safe power if it is e.g.heavily clouded in the evening and therefor dark earlier.Gerben– Gerben09/26/2016 18:42:48Commented Sep 26, 2016 at 18:42
-
Light sensor not suitable in this situation. The cameras will be used for scientific project (monitor bird activity at their nests). Therefore need to record images atset time intervals for each day from sunrise to sunset. Also I need to learn about date-time programming in Arduino for further development from this basic script.jules– jules09/27/2016 06:50:16Commented Sep 27, 2016 at 6:50
-
1There is a potential solution in a helpful answer to my question about understanding compiler error text.jules– jules09/27/2016 07:08:56Commented Sep 27, 2016 at 7:08
-
1Clarification - my comment above does not refer to complete solution to this question. Answer to q about understanding compiler error has a good explanation and solution for TestRTC compiler error - see below in this question.jules– jules09/27/2016 07:35:56Commented Sep 27, 2016 at 7:35
-
I didn't mean to suggest removing the RTC. merely to suggest using a light sensor to detect sinrise and sunset. That way you don't have to enter latitude and longitude. Also data will still be collected if the time is wrong somehow (accidental reset of the RTC e.g.). SoGerben– Gerben09/27/2016 14:42:10Commented Sep 27, 2016 at 14:42
2 Answers 2
Is there a simple way to convert to date-time object?
Not with this library. But you can find other libraries supporting the DS3232 which work with the Arduino Time library[]. This time library provides both the date and time in a single object, either:
- a
time_t
, which is just the number of seconds elapsed since a standard "epoch" - a
tmElements_t
struct, which has the date and time broken into separate elements (year, month, day, hour...).
Then calculate sunrise and sunset times based on latitude?
There are quite a few algorithms describes on the Web for that. The more accurate ones are also the more complex.
#include <SoftI2C.h>
Doesn't your Arduino have a hardware I2C port? That would be more efficient than software emulation.
Serial.flush(); //needed before sleepy
It's only needed if you are actually using the serial port.
Edit: I saw on your other question that you have been bitten by
an incompatibility between the Arduino Time library and the file
time.h
from avr-libc. Now I just noticed that avr-libc includes the
functions sun_rise()
and sun_set()
that you may find
handy. Not sure they will play well with the Arduino time libraries
though. One possible incompatibility is the fact that they use different
epochs for defining time_t
(year 1970 v.s. 2000).
-
Many thanks and sorry I don't fully understand. Using SoftI2C.h because I followed example doing it that way. Unsure whether my RTC module and atmega chip will communicate without it. Started with Uno board connected to laptop via USB, using serial window to see what was happening. At that point had to add Serial.flush(). Left it in, being unsure if needed later. Have moved the atmega chip from Uno to a breadboard with no 'peripherals' in order to minimise power usage. How do I determine whether "hardware I2C port" is available or not? Many thanks for patience with total beginner!jules– jules09/26/2016 09:15:48Commented Sep 26, 2016 at 9:15
-
@jules: All the peripherals of the Arduino Uno are part of the ATmega328P chip. Thus you still have them on a "barebones" Uno (i.e. the bare ATmega). The I2C port (called TWI by Atmel) is available on pins PC4 = A4 = SDA and PC5 = A5 = SCL. You would use this port through the standard Wire library.Edgar Bonet– Edgar Bonet09/26/2016 10:06:53Commented Sep 26, 2016 at 10:06
-
Great to know I have required hardware, thanks. I installed DS3232 and Time libraries you linked above. TestRTC, the example sketch for tecsmith DS3232 library gave compile errors that I cannot understand. Error text too long to add here. Any advice on how to resolve this?jules– jules09/26/2016 12:01:35Commented Sep 26, 2016 at 12:01
-
Checked both two new libraries are present, Wire was already installed. Compile TestRTC has exit status 1 'tmElements_t' does not name a typejules– jules09/26/2016 12:23:44Commented Sep 26, 2016 at 12:23
-
@jules: TestRTC has
#include <Time.h>
on line 46. Did it find that header? Don't you havetypedef struct {...} tmElements_t, TimeElements, *tmElementsPtr_t;
in it?Edgar Bonet– Edgar Bonet09/26/2016 20:18:13Commented Sep 26, 2016 at 20:18
I hope I am allowed to summarise progress. Edgar Bonet's answer above pointed me in the right direction regarding date-time format and I want to 'accept' that answer, although it did not resolve my difficulties with RTC. I need to ask a new question about RTC later.
Using the Time library Edgar Bonet recommended, I managed to set and change date-time format, and calculate duration between date-time instances. I hope my example below could perhaps be useful for other beginners. If anyone has suggestions to improve this example, please add them.
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
time_t tstart;
void setup() {
Serial.begin(9600);
// assume no RTC available therefore set date-time in this sketch
// when serial monitor opens, date-time will be set as follows
setTime(8,30,0,17,10,2016); // (hr,min,sec,day,mnth,yr);
tstart = now();
Serial.print("Started at: ");
digitalClockDisplay();
Serial.println();
}
void loop(){
Serial.println("Waiting...");
delay(20000 + random(500, 5000) );
Serial.println();
time_t tnow = now();
Serial.print("Now it is: ");
digitalClockDisplay();
time_t duration = tnow - tstart;
Serial.print("Duration since start: ");
showDuration(duration);
Serial.println();
Serial.println();
}
// function to print current date-time
// modified from example in TimeLib
void digitalClockDisplay(){
Serial.print("Date: ");
Serial.print(day());
Serial.print("-");
Serial.print(month());
Serial.print("-");
Serial.print(year());
Serial.print(" Time: ");
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.println();
}
// utility function from TimeLib
// to print leading zeros
void printDigits(int digits){
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
// function from example TimeRTCLog
void showDuration(time_t duration){
// prints the duration in days, hours, minutes and seconds
if(duration >= SECS_PER_DAY){
Serial.print(duration / SECS_PER_DAY);
Serial.print(" day(s) ");
duration = duration % SECS_PER_DAY;
}
if(duration >= SECS_PER_HOUR){
Serial.print(duration / SECS_PER_HOUR);
Serial.print(" hour(s) ");
duration = duration % SECS_PER_HOUR;
}
if(duration >= SECS_PER_MIN){
Serial.print(duration / SECS_PER_MIN);
Serial.print(" minute(s) ");
duration = duration % SECS_PER_MIN;
}
Serial.print(duration);
Serial.print(" second(s) ");
}