Ethernet, RTC, and Time Stamping

I'm attempting to use an Arduino Ethernet with a Chronodot RTC to keep track of the state of a door(s). I need to be able to tell wether they are open or closed (the really easy part) and when the last time the state of the door changed. I've attempted to update a variable using an if statement

  int door1 = digitalRead(8);
  Serial.print("Door is: ");
    if (door1 == LOW) { 
     DateTime door_state1 = RTC.now();
     Serial.println("OPEN");

to only update the time when the door was opened. However if I don't declare door_state1 in the void loop outside of the if statement I get the error that "'door_state1' was not declared in this scope" which makes sense since it was not declared. I tried to declare it in the top of the sketch above the void setup, the sketch would load to the arduino but would fail (even serial output was blank) I presume because the RTC had not yet been started by the void setup.

Any help with this would be much appreciated.

Any help with this would be much appreciated.

There is nothing wrong with the code snippet you posted, so, clearly, the problem is in the code you didn't post.

If you post all of your code, we promise not to laugh (too much). And, we'll be much more likely to be able to help.

I’ll post the full sketch tomorrow, I do not have access to the computer it is on. Also I realize the fallacy of using an if statement to update a variable because the variable being update will only be valid inside of that if statement.

What would be the proper way to update a variable and have it readable to the rest of the loop? IE what is the best way to set a variable to the current time from the RTC and have it survive until the next state change?

Read up on variable scope - http://arduino.cc/en/Reference/Scope.

I would make door_state1 global, so I would define it outside of any function, usually at the top of the code, after any #includes, but before the void setup() line.

#include <somelibrary.h>
...
DateTime door_state1;
...
void setup()
...
    if (door1 == LOW) { 
     door_state1 = RTC.now();
     Serial.println("OPEN");
...

I would make door_state1 global, so I would define it outside of any function

When you do this, and see the variable door_state1 sitting there be itself, you'll probably (hopefully, at least) notice that door_state1 implies something like open or closed, not the time that the state changed. Hopefully, you'll recognize then that door_state1 is a lousy name, and you'll use a more meaningful name.

I am using a Library for the Chronodot pulled from here. Here is the code I am working with, parts of it are from example included with that library as a starting point. I’m not particularly attached to any piece of this code nor even sure if it can do what I want in the end; it is all a learning process. When the “door” is closed I want the time to display the time of the last event (door opened), when the door is open showing the current time is preferable.

#include <Wire.h>
#include "Chronodot.h"
Chronodot RTC;
DateTime door_state1;

void setup () {
    
    pinMode(8, INPUT); 
  pinMode(9, INPUT); 
  Serial.begin(9600);
 Wire.begin();
RTC.begin();
    Serial.println("Initializing Chronodot.");
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");

  }
}

void loop () {
    // start door
  int door1 = digitalRead(8);
  Serial.print("door_1: ");
    if (door1 == LOW) { 
     DateTime door_state1 = RTC.now();
     Serial.println("OPEN");
      Serial.print(door_state1.year(), DEC);
    Serial.print('/');
    if(door_state1.month() < 10) Serial.print("0");
    Serial.print(door_state1.month(), DEC);
    Serial.print('/');
    if(door_state1.day() < 10) Serial.print("0");
    Serial.print(door_state1.day(), DEC);
    Serial.print(' ');
    if(door_state1.hour() < 10) Serial.print("0");
    Serial.print(door_state1.hour(), DEC);
    Serial.print(':');
    if(door_state1.minute() < 10) Serial.print("0");
    Serial.print(door_state1.minute(), DEC);
    Serial.print(':');
    if(door_state1.second() < 10) Serial.print("0");
    Serial.print(door_state1.second(), DEC);
    Serial.println(); 
 
  } 
    else {
      Serial.println("closed");
      Serial.print(door_state1.year(), DEC);
    Serial.print('/');
    if(door_state1.month() < 10) Serial.print("0");
    Serial.print(door_state1.month(), DEC);
    Serial.print('/');
    if(door_state1.day() < 10) Serial.print("0");
    Serial.print(door_state1.day(), DEC);
    Serial.print(' ');
    if(door_state1.hour() < 10) Serial.print("0");
    Serial.print(door_state1.hour(), DEC);
    Serial.print(':');
    if(door_state1.minute() < 10) Serial.print("0");
    Serial.print(door_state1.minute(), DEC);
    Serial.print(':');
    if(door_state1.second() < 10) Serial.print("0");
    Serial.print(door_state1.second(), DEC);
    Serial.println(); 
  }
    delay(3000);
}

Here is the serial output just for kicks, with DateTime door_state1; declared as a global variable the RTC returns a time of 2106/02/06 06:28:16 which I am guessing is the furtherest point in the future it can read. When the input is LOW (IE Door Open) the RTC returns the correct time.

Initializing Chronodot.
door_1: closed
2106/02/06 06:28:16
Initializing Chronodot.
2106/02/06 06:28:16
door_1: closed
2106/02/06 06:28:16
door_1: closed
2106/02/06 06:28:16
door_1: OPEN
2012/02/14 08:25:31
door_1: OPEN
2012/02/14 08:25:34
door_1: OPEN
2012/02/14 08:25:37
door_1: OPEN
2012/02/14 08:25:40
door_1: OPEN
2012/02/14 08:25:43
door_1: closed
2106/02/06 06:28:16
door_1: closed

I completely agree that door_state1 is a lousy variable name, all variables are subject to change once I am out of the prototype stage.

all variables are subject to change once I am out of the prototype stage.

Meanwhile you’ll struggle to understand what the code is doing, because the variable names don’t make sense. Well, OK, if that works for you.

#include <Wire.h>
#include "Chronodot.h"
Chronodot RTC;

DateTime openTime;
DateTime closeTime;

void setup ()
{
  pinMode(8, INPUT); 
  pinMode(9, INPUT); 
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  Serial.println("Initializing Chronodot.");
  if (! RTC.isrunning())
  {
    Serial.println("RTC is NOT running!");
  }
}

void loop ()
 {
   int door1 = digitalRead(8);
   Serial.print("door_1: ");
   if (door1 == LOW)
   {
      Serial.print("open at ");
      openTime = RTC.now();
      printTime(openTime);
   }
   else
   {
      Serial.print("closed at ");
      closeTime = RTC.now();
      printTime(closeTime);
   }
}

You’ll need to implement the printTime() function (instead of replicating the code to print the time).

Note though that this will print the status and time on every pass through loop, which is probably not what you want.

You want to keep track of the previous state of the door, so you can detect transitions (now open but was closed or now closed but was open) and only print when the state changes. Perhaps a nice variable name like doorTime to keep track of the state.

Meanwhile you'll struggle to understand what the code is doing, because the variable names don't make sense. Well, OK, if that works for you.

Point taken, especially when asking for help and having others dissect your code.

You want to keep track of the previous state of the door, so you can detect transitions (now open but was closed or now closed but was open) and only print when the state changes. Perhaps a nice variable name like doorTime to keep track of the state.

That is precisely what I want to do, how do I keep it from being over written every time the loop starts again? Thanks for the help and the patience.

That is precisely what I want to do, how do I keep it from being over written every time the loop starts again?

Global variables!

Like so:

int currDoorState = LOW;
int prevDoorState = LOW;

void loop()
{
   currDoorState = digitalRead(doorPin);
   if(currDoorState != prevDoorState) // The door just opened or closed
   {
      if(currDoorState == LOW)
      {
         // Door is now open
      }
      else
      {
         // Door is now closed
      }
   }
   prevDoorState = currDoorState;
}

I guess I needed to be more precise, I need to track the time the door was opened, not specifically that it was. I've poured over the example sketch StateChangeDetection and was able to track the stage change just fine. I was however not able to find a way to carry over the time variable from the open to the closed function.

I guess I needed to be more precise, I need to track the time the door was opened, not specifically that it was.

How will you do that if you don't know that the door is now open but wasn't last time, or is closed but was open last time? You must be able to detect a transition in order to know when the door is opened (or closed).

In the last code I posted, all you need to do is set (and send) the door open time or the door closed time in the appropriate if blocks.

I was able to work through it and get things working as desired, thanks for the patience and the knowledge.

I was able to work through it and get things working as desired,

Excellent.