Must-haves for EASY DIY controller?

It would be nice to have a generic scheduler function. If the "on" time is after the "off" time then I'd assume to wrap across midnight, i.e. overnight from one day to the next.

We should probably switch to the optiboot bootloader on the AVRs. It's only half a k, as opposed to 2k for the old default bootloader we're all probably using.
 
It would be nice to have a generic scheduler function. If the "on" time is after the "off" time then I'd assume to wrap across midnight, i.e. overnight from one day to the next.

We should probably switch to the optiboot bootloader on the AVRs. It's only half a k, as opposed to 2k for the old default bootloader we're all probably using.

not familiar with the optiboot; what are the pros/cons over the default?

and here's a snippet of my code in reference to the relay. feel free to use it. if you optimize please share w/ me :D I THINK this works, haven't ran it long enough but as far as logically it should be sound (I have been staring at this for some time so could be flawed)

Code:
.
.
.

int alarm_on_hr, alarm_off_hr, alarm_on_min, alarm_off_min, HR, MIN;
boolean alarm_state, alarm_counter;
.
.
.
void setup () {
.
.
.
alarm_on_hr = 8;           //
  alarm_on_min = 20;        // Controls what times A/C Controller Turns on/off
  alarm_off_hr = 18;        //
  alarm_off_min = 20;       //


HR = RTC.get(DS1307_HR,true); //pulls HR from DS1307 
  MIN = RTC.get(DS1307_MIN,false); //pulls MIN from DS1307

  //this statement check if OFF time is BEFORE or AFTER the ON time to account for the midnight wrap around
  if(alarm_off_hr == alarm_on_hr  && alarm_off_min >= alarm_on_min)
  {
    alarm_state= true;
  }
  else{ 
    alarm_state= false;
  }

  if(alarm_off_hr > alarm_on_hr)
  {
    alarm_state = true;
  }

  switch(alarm_state){
  case true:
    if(alarm_on_hr > HR) //before ON HR= false/off
      alarm_counter = false;
    if(alarm_on_hr== HR && alarm_on_min <= MIN) //during ON HR and MIN = true/on
      alarm_counter = true;
    if(alarm_on_hr< HR) //after alarm has been triggered = true/on
      alarm_counter = true;
    if(alarm_off_hr< HR) //after alarm off HR = false/off
      alarm_counter = false;
    if(alarm_off_hr == HR && alarm_off_min <= MIN) //during OFF HR and MIN = false/off
      alarm_counter = false;   
    break;
  case false:
    if(alarm_off_hr > HR)
      alarm_counter = true;
    if(alarm_off_hr== HR && alarm_off_min <= MIN)
      alarm_counter = false;
    if(alarm_off_hr < HR)
      alarm_counter = false;
    if(alarm_on_hr< HR)
      alarm_counter = true;
    if(alarm_on_hr == HR && alarm_on_min <= MIN)
      alarm_counter = true;
    break;
  }
.
.
.
}


void alarm() {

  if(alarm_counter == false)//if alarm on time has not passed, check for ON
  {
    if (alarm_on_hr == HR && alarm_on_min == MIN) 
    {
      alarm_counter=true; //turns A/C Controller ON
    }
  }
  else{   //if current hour is not part of ON time perform this check..
    if (alarm_off_hr == HR && alarm_off_min == MIN)  //checks weather current hour is part of OFF time
    {
      alarm_counter=false;  //turns A/C Controller OFF
    }
  }
.
.
.
}

please disect and LMK what you think
 
Last edited:
As far as I know optiboot is fully compatible. Besides being smaller it uses a faster default upload speed, so loading firmware is also quicker. There really are no disadvantages, except that if we really do use the "extra" space then optiboot will truly be required, meaning people who have older AVRs with larger pre-loaded bootloaders will need to upgrade.

I'll let Dustin and/or terahz comment on your code, they're the software experts 'round this project. :) Might be useful in the future to enclose it in "code" or "php" tags so it shows up with good formatting.
 
Time doesn't really "schedule" things, it just keeps track of date/time. I don't think we need it, since we can probably write the code required to do the minimum interface with the RTC ourselves and save room. What we really need is a function that lets a user say "Turn on X at time A, and turn it off at time B." The user shouldn't need to know how to code a bunch of If statements, they should be able to just call a function and pass it a few variables and have everything work out.
 
Regarding scheduler, if we go the non-interrupt way, I'm thinking of having a check every second that will go through a list of events. If the time is right, flip the relay else, move on. Something as basic as this should be very easy to implement. Ideally we want an interrupt driven scheduler, but that will probably require some more coding, and to be honest I don't know if I want my lights to interrupt the ATO Off or something more important.

Just a general idea in my head.


MA70Snowman, what you have can be simplified a bit by combining the HR and MIN into a minute_since_midnight counter and just check if it is the right minute to turn on/off a given relay. Other than that, you probably want some struct Event/Alarm that holds time on, time off and relay, and then a list of all the alarms. Otherwise it will be one big *** if/else statement :)
 
In some cases like the ATO it may be simpler to think of it as a start time and a length to run. If you have a power failure when it is suppose to come on no big deal. It will cycle the next time (ok maybe the next day). This would work great if we had an interrupt handler.

Light on the other hand should have an on and off time and get reset in the event of a power failure.

Can you break the list down and just check lights (and a few others) and turn them on if between on and off time.
 
I guess we need to be more specific in what we mean by "scheduler function." I am interpreting that requirement in an extremely basic sense: "Do event X at time Y." It strikes me that something like "limit X such that it only runs Y minutes per day" could be implemented with a basic scheduler, but isn't inherently the goal of a basic scheduler - if that makes sense.
 
Time doesn't really "schedule" things, it just keeps track of date/time. I don't think we need it, since we can probably write the code required to do the minimum interface with the RTC ourselves and save room. What we really need is a function that lets a user say "Turn on X at time A, and turn it off at time B." The user shouldn't need to know how to code a bunch of If statements, they should be able to just call a function and pass it a few variables and have everything work out.

See that's exactly what I'd like to be able to do, unfortunately, I'm still pretty new at the arduino coding and not all to familiar w/ creating a library. I had thoughts of breaking it out to a function but i was mostly going for the concept at the moment.

Regarding scheduler, if we go the non-interrupt way, I'm thinking of having a check every second that will go through a list of events. If the time is right, flip the relay else, move on. Something as basic as this should be very easy to implement. Ideally we want an interrupt driven scheduler, but that will probably require some more coding, and to be honest I don't know if I want my lights to interrupt the ATO Off or something more important.

Just a general idea in my head.[\QUOTE]

See that's exactly what I was going for and I feel thatswhat my code does. It checks every loop weather the alarm time has passed or not. and I'm not quiet sure I"m following on w hat you mean by an "interrupt driven scheduler." maybe i'm missing a concept here.

MA70Snowman, what you have can be simplified a bit by combining the HR and MIN into a minute_since_midnight counter and just check if it is the right minute to turn on/off a given relay. Other than that, you probably want some struct Event/Alarm that holds time on, time off and relay, and then a list of all the alarms. Otherwise it will be one big *** if/else statement :)

I THINK i see where you're going with this line of thought, however even if you do a minute-since-midnight counter, thats an additional variable/s as well as another check statement that would replace the current check statement. Currently I total there's 8 check statements, 4 if ON time is later (closer to midnight) then the OFF time, and 4 for the opposite.

In some cases like the ATO it may be simpler to think of it as a start time and a length to run. If you have a power failure when it is suppose to come on no big deal. It will cycle the next time (ok maybe the next day). This would work great if we had an interrupt handler.

Light on the other hand should have an on and off time and get reset in the event of a power failure.

Can you break the list down and just check lights (and a few others) and turn them on if between on and off time.

see that's a concept I hadn't thought of. ON time, and then a RUN time. that ideally could be much simpler to implement.

and talking about power failures. that's the reason I have the large check in the SETUP function. if there is a power failure. when Power is restored, it performs an indepth check of what the time/alarm status is, and this will restore all functions to where they should be.



One more thought. ATO is what exactly? it's 5 am and still asleep.
 
DWZM: The problem isn't with the flash memory, so the optiboot shouldn't be required. My large sketch with almost everything other than ATO and detailed scheduling(basic relay control now) is only at around 18,400 now. The problem is in the RAM, before I did some optimization I only had around 200 bytes free. Now I have about 600-800 free, depending on how accurate the memoryfree method is.

That said, if all everyone wants is a basic scheduler system where we can set the channel, start time and end time, I don't think it will be a problem.

TeraHz: I haven't dug into the interrupts a great deal, but I'd be worried something might go wrong with it, not to mention the added code for it. Like you said, I don't think I'd feel comfortable with my ATO hooked up to the same chip while using interrupts. I'm going to be running dosing pumps on this strip as well.

FishMan: I was planning on having ATO code running off one of the free pins through the float switch, with a timeout value in case something didn't work right. This should cover any power outages no problem. Even if it got stuck and there was a power outage, the running time variable would just get reset and run no longer than the set value, not end up in an infinite loop. You know, TeraHz did some ATO code, though I never got a chance to look much into it. I'm sure he's already got this covered.

Whatever we do guys, I think the biggest thing is going to have simple, bulletproof code for the general public. I would really hate to have something happen to someone's tank due to some code I wrote and a possible problem I didn't account for. Sure, fancy features are all fine and good, but things like that need to be tested on someone's empty quarantine tank for a few months with simulated problems.

I was also planning on writing some code to send SMS messages or something similar, though I haven't had a chance to look into it yet. This would at least "maybe" notify you of some of these issues depending on what happened.
 
Good point about memory. I had lost track of which kind it was we'd run out of. :D

There are several implementations using the ENC to tweet, that was the route I was thinking of - then you could follow the twitter account on multiple phones/email accounts and the message would get distributed appropriately.

I agree 100% with making the core firmware simple to understand and bulletproof. It's no use how bulletproof it is if it's prone to misinterpretation. In other words, if we write this scheduler function, we need to make it clear how it works, so people don't misinterpret, pass it bad data, and end up in a pickle.
 
What I figured was you will typically have 8 relay locations. You would have a basic scheduler system that would allow you do perform the following 3 settings for each one:

***Index Location (1-8)***
Set Active: True/False
Start Time: 24 hour format
End Time: 24 hour format

We could replace end time with "time to run". I was thinking about maybe having an option in the code to set the number of positions to avoid accidentally controlling any positions that are controlled by other means, i.e. ATO. That way people could set the number of scheduler controlled positions. For example, set variable to 7 positions, have ATO pump on position 8.
 
Are we assuming that the scheduler will ONLY be controlling I/O pins on an external MCP23008, or should we allow provisions for the user to specify exactly what a given instance of the function is controlling?
 
DustinB, Sound good, BUT (of course someone always has a but). I want may ATO to come on 4 times a day and run for a maximum of 15 minutes each time. And I want my water change to occur every other day (well maybe not, but I am sure some one will).

This is why I don't like the above. What I pictured was a linked list of events. When each one occurs it is responsible for adding the next step. So in the ATO example turning on the pump deletes the turn on from the list, but adds a turn off to the list.

Just some thoughts.
 
I think a way to call a function at a set time is the way to go. This would allow scheduling of reading temperature, ph, and whatever else we add.
 
What about temp control and conditional on/off type things. Such as watertemp>84 turn off lights, heater, skimmer pump ect.
 
Are we assuming that the scheduler will ONLY be controlling I/O pins on an external MCP23008, or should we allow provisions for the user to specify exactly what a given instance of the function is controlling?

That's what I'm thinking, controlling the IO pins. Maybe we could compromise and have each scheduler index control a function with "default" code in each to control start/stop.

DustinB, Sound good, BUT (of course someone always has a but). I want may ATO to come on 4 times a day and run for a maximum of 15 minutes each time. And I want my water change to occur every other day (well maybe not, but I am sure some one will).

This is why I don't like the above. What I pictured was a linked list of events. When each one occurs it is responsible for adding the next step. So in the ATO example turning on the pump deletes the turn on from the list, but adds a turn off to the list.

Just some thoughts.

I see where you are going with this, but IMHO you are wanting functionality that is beyond the average user and beyond the scope of the basic project goals. I think this is best left to the end user to customize for his needs.

What about temp control and conditional on/off type things. Such as watertemp>84 turn off lights, heater, skimmer pump ect.

I think functions like this would likely be hardcoded with something to override the timed functions. There are going to be many different setups that it will be hard to try to account for each possible scenario.
 
I think it's important to keep in mind that, right now, we're trying to develop a baseline firmware that's easy to understand and customizable for individual's needs. We're not trying to pre-program for every possible use case, as the goal of this project is to present a framework, not a finished product.
 
I agree DWZm I was trying to throw out possible cases that might want to be considered. While I don't agree with some of the answers Dustin gave, I am not familiar enough with the limitation of the system to provide a better solution. So I must leave it to those that have them up to decide what is best.
 
ATO: apparently we have different implementations of ATO which drives different implementations. I, for example, have a high flow pump that is triggered by 2 float switches and runs for about 4-5 secs until the level of the water is back to where I want it. That amounts to about 1/4 cup of fresh water dumped in my tank every so often. Personally, I don't like the idea of scheduling ATO at all because you either have to always adjust it to your rate of evaporation or you will be causing changes in salinity over long term.. My ATO just monitors the float switches and has a few safety triggers like running too long, not enough water in RODI bucket etc. So for me ATO is not a scheduled event, it is ... externally triggered one with safety.

MA70Snowman: a simple pseudo code assuming alarm is a struct with variables .callback ( a callback method that 'knows' how to turn on/off the event); .start; .end and you have a list of alarms called 'alarms':
foreach alarm in alarms:
if current_abs_minute == alarm.start:
alarm.callback(on);
if current_abs_minute == alarm.end:
alarm.callback(off);
end

The above does not care for midnight/rolling over it just turns a relay on/off at a given time. If you setup 'duration' you will have to worry about going over midnight.

It gets a bit more complicated if you want to start/stop something multiple times per day. Then you'll need a bit more complex data structure but still the idea is about the same. Just instead of checking one .start and .end you check all .starts and all .ends

Also the above is fairly generic, and the callback method can define what does "on" and "off" mean for the given alarm/event.



EDIT: for non-time triggers, the events above can have a method that returns true/false based on what defines their trigger. That way you can define a method that triggers based on time, one that is based on temperature etc.


On a general note, writing a generic scheduler is not the simplest thing and will require some thought. All I'm doing above is laying down ideas. They might be a totally wrong way to approach this.
 
Back
Top