# Improved Arduino LED lighting code



## sink

I wasn't happy with any existing Arduino code for LED control so I wrote my own. I think it's quite nice though it needs polishing and probably some features added. It does light timing, sunrise/sunset fading and all that jazz.

Some improvements over existing code:


Shorter and simpler
Accurately set clock from a script on your PC. You don't need to modify any code or upload any sketches!
Much, much smoother dimming, especially at the low end (due to a combination of higher resolution PWM output and every-second dimming adjustment instead of every-minute).
Higher resolution PWM also means you can dim your LEDs down to a lower intensity than before if your driver is capable. I've found I can dim my LEDs down far enough to be used as moonlights.
Flexible timing logic. You can do anything you want (with minor modifications) so long as it's on a 24hr cycle.
 There are also some limitations:


Your Arduino needs to have either a DS3231(eg: ChronoDot) or DS1307 Real Time Clock chip connected via I2C (because I have one of those). These are probably the two most common RTC chips.
It only provides 2 PWM outputs (because I only have 2 LED strings). Of course you can modulate as many strings as you want from a single PWM signal but they'll modulate in unison.
It should work with the *Arduino Duimilanove/Uno* and probably any other micro-controller that uses the Atmega168/328 chip. In particular it _will not_ _work_ as-is with the Arduino Mega due to a difference in the onboard timers.
It depends on a few libraries but I've bundled them up in a download link below.
Only compiles with versions 0022/0023 of the Arduino IDE, *not version 1.0 (yet!)*

It works great for me. I'd love feedback, error reports, suggestions, free beers, etc. Post in the thread or PM me.

I hope this will be useful to people! :thumbsup:

*Get the code:*
Latest version
Libraries bundle

*Installing libraries:*
The libraries that don't come with the Arduino environment by default are bundled in the zipfile above. Just extract that zip into the _libraries_ folder inside your sketchbook folder and then restart the Arduino IDE. If _libraries_ doesn't exist, create it first.

Until I get around to writing documentation just post or PM installation questions/issues and I'll try to help.

*Latest Version:*
05/2014 -- O2surplus has made some significant improvements to this code, adding LCD and temp sensor support, please see his posts later on in this thread for the code.


----------



## jcgd

I would try it. But I'm not sure how to hook up my rtc. Could you e plain how or link me to a deceit walkthrough?


----------



## sink

jcgd said:


> I would try it. But I'm not sure how to hook up my rtc. Could you e plain how or link me to a deceit walkthrough?


What does the RTC circuit that you have look like? Is it a breakout board? Mine is integrated into my driver because I built it myself, but the principle is the same either way. You just need to power and ground it somehow (5V and GND from the Arduino) and then connect the data pins (SCL and SDA) from the chip to the Arduino. On most Arduino boards (including mine) SDA (data line) is on analog pin 4, and SCL (clock line) is on analog pin 5.

Here's a tutorial that might be applicable Adafruit also sells an RTC breakout board kit with everything you need except wires for under $10. I don't have one but I modeled my RTC circuit after theirs and it works great, so might be an option if you want to add an RTC to an existing setup.


----------



## O2surplus

I'll give it a try! Took me nearly an hour to hunt down and install the extra libraries, but I got the code to compile without issue. I'll hook up the Dueminlanove this weekend and see what happens. Good job sink- Now if you could only show me how to integrate that coding into the controller that I built, that would be awesome!


----------



## sink

O2surplus said:


> I'll give it a try! Took me nearly an hour to hunt down and install the extra libraries, but I got the code to compile without issue. I'll hook up the Dueminlanove this weekend and see what happens. Good job sink- Now if you could only show me how to integrate that coding into the controller that I built, that would be awesome!


You are welcome. Glad to know it compiles. Once past that step it should run fine. Please let me know what you think! As an aside, you'll probably want to change a couple of variables in the code to match your own needs regarding sunrise/sunset time and in particular how bright you want daylight to be because my default may be quite dim for others. The lines are all towards the beginning of the file and are commented pretty well as to what they do and possible values. I'll write up more detailed instructions when I have some time.

I'd love to make a bundle with the required libraries but I'm not sure if the licenses permit it. In the meantime I'll edit the original post with links to the needed libraries. Thanks for pointing out that task might not be trivial.

I'm willing to help with any driver integration you need. Do you mean the RTC or the code?


----------



## O2surplus

Sink, 

I found the TimerOne and Time libraries at Arduino.cc, so I think you could zip them up together with your code and be good to go. There's one thing you need to fix though, your code cannot be unzipped and moved directly into the Arduino IDE. The IDE will not recognize the folder until it is renamed. I had to change the name of the folder to "akl_tank_control" and the file name to "akl_tank_control.pde" and then it would open and compile properly. This is detail that may cause trouble for people who are not familiar with some of the Arduino IDE's file naming requirements.

I'll have to shoot you a PM with the coding for my controller. It works great as is, but I like the fact that your code updates the PWM every second, instead of once per minute. I've got the hardware side of things nailed down but I could use your help to improve the software.

Here's a photo of the controller board- without the 16x2 LCD on top.










I've got enough boot loaded ATMEGA328's to build 30 more, and a newer design that supports the MeanWell ELN-P's as well as my Cat4101's.

Maybe a trade- Chips or a completed controller for software?


----------



## sink

O2surplus said:


> I found the TimerOne and Time libraries at Arduino.cc, so I think you could zip them up together with your code and be good to go. There's one thing you need to fix though, your code cannot be unzipped and moved directly into the Arduino IDE. The IDE will not recognize the folder until it is renamed. I had to change the name of the folder to "akl_tank_control" and the file name to "akl_tank_control.pde" and then it would open and compile properly. This is detail that may cause trouble for people who are not familiar with some of the Arduino IDE's file naming requirements.


Clearly I too am unfamiliar with the IDE's file naming requirements :icon_smil. I just uploaded a version that should be better in that regard. I also bundled the libraries up and added a link above. Thanks much for the input.



> I'll have to shoot you a PM with the coding for my controller. It works great as is, but I like the fact that your code updates the PWM every second, instead of once per minute. I've got the hardware side of things nailed down but I could use your help to improve the software.
> 
> I've got enough boot loaded ATMEGA328's to build 30 more, and a newer design that supports the MeanWell ELN-P's as well as my Cat4101's


Driver looks great! I'd love to help on the software end.



> Maybe a trade- Chips or a completed controller for software?


Sounds very reasonable. I do love the barter system. I'll shoot you an email :icon_smil


----------



## O2surplus

Sink,

I loaded the code into my Duemilanove and connected it up to my Cat4101's, Looks good so far. I made some changes to the code to run the leds at max (1023) all day,and set the night time level to a minimum (20) for moon lighting at night. I think a pwm value of 20 works out to be a hair less than 2%. I should know by 10pm whether or not the leds will continue to run at such a low setting.
I did notice that there's something amiss with the time display in the serial monitor. The time displayed is 1 hour less than the correct time on my PC. Any idea what's causing that? Must be something to do with the DS1307 and daylight savings time?


----------



## sink

O2surplus said:


> Sink,
> 
> I loaded the code into my Duemilanove and connected it up to my Cat4101's, Looks good so far. I made some changes to the code to run the leds at max (1023) all day,and set the night time level to a minimum (20) for moon lighting at night. I think a pwm value of 20 works out to be a hair less than 2%. I should know by 10pm whether or not the leds will continue to run at such a low setting.


Your LEDs should run all the way down to a setting of 1 without any problems. The CAT4101s OTOH don't seem to have particularly precise dimming below about 1% though it will still work. I've lowered the default PWM frequency from 500Hz to 150Hz in an effort to improve that so I'm curious to see how your results are.



> I did notice that there's something amiss with the time display in the serial monitor. The time displayed is 1 hour less than the correct time on my PC. Any idea what's causing that? Must be something to do with the DS1307 and daylight savings time?


That's an interesting one. The DS1307 is completely naive of timezones so the issue would be with the time your computer is putting out somehow not compensating for DST. I presume you set the clock using the timerset.pde sketch?


----------



## O2surplus

sink said:


> That's an interesting one. The DS1307 is completely naive of timezones so the issue would be with the time your computer is putting out somehow not compensating for DST. I presume you set the clock using the timerset.pde sketch?


Oh- I forgot about that separate sketch. My DS1307 must still be running from the last time that I set it. That says a lot since it's been out in a drawer collecting dust for the last six months,LOL. I guess the back up battery must have kept it alive.:thumbsup:
I'll have to try that sketch. I just adjusted the start and stop time in the main sketch to compensate for now. hehe!


----------



## sink

O2surplus said:


> Oh- I forgot about that separate sketch. My DS1307 must still be running from the last time that I set it. That says a lot since it's been out in a drawer collecting dust for the last six months,LOL. I guess the back up battery must have kept it alive.:thumbsup:
> I'll have to try that sketch. I just adjusted the start and stop time in the main sketch to compensate for now. hehe!


I figured that was the case :icon_smil. My fault for not getting around to writing proper documentation yet. As an aside, the timeset.pde isn't specific to the lighting control code in any way. It's just a convenient way to easily set the RTC time. It'll work for any Arduino/DS1307 pair.

On battery power the DS1307 shuts down all functions except for keeping the clock running so it can run for 5+ years on a single coin cell. Pretty nifty.


----------



## Tbakes

Very cool - I'd like to upgrade my controller with the new code once it is worked out!


----------



## O2surplus

Tbakes said:


> Very cool - I'd like to upgrade my controller with the new code once it is worked out!



Well, we'll have to see what "coding magic" "Sink" can pull off! LOL Then I'll show you how to reprogram the controller. He's got a day job- so let's not rush him.LOL


----------



## O2surplus

Sink,

I uploaded the TimeSet code.....Worked perfectly. I also uploaded the TankControl code again after lowering the minimum PWM state to "5" and stting the fade duration to 1 hour. All I can say is "WOW!" The dimming is completely linear, seamless, and totally natural looking. That has got to be the best Dimming Simulation that I've ever seen! I now have 90 little "moon lights" over my tank. Too cool! Thanks so much for creating and posting the codes!:biggrin:roud:


----------



## jcgd

Wow, you are getting me excited to download this to my arduino. I need to get that RTC installed.


----------



## sink

O2surplus said:


> Sink,
> 
> I uploaded the TimeSet code.....Worked perfectly. I also uploaded the TankControl code again after lowering the minimum PWM state to "5" and stting the fade duration to 1 hour. All I can say is "WOW!" The dimming is completely linear, seamless, and totally natural looking. That has got to be the best Dimming Simulation that I've ever seen! I now have 90 little "moon lights" over my tank. Too cool! Thanks so much for creating and posting the codes!:biggrin:roud:


I'd like to thank the Academy...:icon_wink I'm glad it works for you.

Just kidding. You are welcome and thanks for testing. Cleaning this up and making it available to others is the least I can do in return for all of the knowledge I've shamelessly mined from this forum so far.


----------



## mistergreen

How are you guys setting your time? An lcd is pretty cheap.


----------



## O2surplus

mistergreen said:


> How are you guys setting your time? An lcd is pretty cheap.


Sink made it so easy " a cave man could do it". He wrote a program that pulls the current time from your computer and transfers it directly to the arduino. 

Look for the TimeSet sketch is his code bundle.


----------



## mistergreen

Yeah, I did that too  but I found an lcd is helpful where you can't connect to a PC.


----------



## sink

mistergreen said:


> Yeah, I did that too  but I found an lcd is helpful where you can't connect to a PC.


Strictly speaking an LCD would only display time, you can't actually set it using it :icon_mrgr. For that you need some buttons.

Anyway I thought about adding a display and/or buttons to my controller but ultimately I didn't see the relatively minor value being worth the added complexity. I'm very much a minimalist. You shouldn't have to set the clock very often at all--that's largely the point of the RTC--and tweaking something is a 2 minute job with a laptop.

In some way I intend this to be demo code and to be as easily adaptable as possible to different setups. To that end I don't make any assumptions about what hardware/driver/controller you have beyond there being an Arduino and a DS1307.


----------



## O2surplus

sink said:


> Anyway I thought about adding a display and/or buttons to my controller but ultimately I didn't see the relatively minor value being worth the added complexity. I'm very much a minimalist. You shouldn't have to set the clock very often at all--that's largely the point of the RTC--and tweaking something is a 2 minute job with a laptop.


I like the minimalist approach as well...... but it seems that I'm addicted to solder fumes! LOL:biggrin: I can hardly wait to build another batch of controllers that run your code.:biggrin:


----------



## jcgd

Would you guys be interested in some other ideas? There are a few more features I'm always hunting for.


----------



## O2surplus

jcgd said:


> Would you guys be interested in some other ideas? There are a few more features I'm always hunting for.


Okay - Justin AKA "XM-L Pioneer". What other ideas do you have? I've got my soldering iron warmed up. LOL:biggrin:


----------



## sink

jcgd said:


> Would you guys be interested in some other ideas? There are a few more features I'm always hunting for.


Ideas are always good.


----------



## reybie

Question for you electronics gurus. Since you're already using an arduino board already, is it possible to integrate a temperature sensor in it that can switch a relay on/off to say power a fan or heater?

I was browsing the arduino forum briefly today and I don't think there's a waterproof temp sensor (yet).


----------



## sink

reybie said:


> Question for you electronics gurus. Since you're already using an arduino board already, is it possible to integrate a temperature sensor in it that can switch a relay on/off to say power a fan or heater?
> 
> I was browsing the arduino forum briefly today and I don't think there's a waterproof temp sensor (yet).


You could probably just take a cheap temp sensor IC (LM35, etc) and then encase it in a tube.


----------



## reybie

Cool! Thanks, there was even an instructable on waterproofing the LM35.


----------



## Tbakes

Aaron / Sink -

I'm getting closer to my control box build (seriously - I almost have my plumbing done, electronics in the near future finally!). 

How would I go about re-programming my unit? Can I ship the Typhoon back to you Aaron, or is there a USB AVR programmer solution?

If you are taking requests for new projects - I'd be interested in some simple timer code to make an autodoser work a 4-relay module that they sell on Ebay. I have a arduino duemilanove and RTC available to dedicate to the unit. If there isn't code out there already, I figured I'd give it a shot programming myself. Course the last time I programmed was in 1997!


----------



## O2surplus

Hey Tony,

Sink is still working on the code. He's going to send me the new code for testing once he's finished. I'll test the code out and report back to him with any bugs, or changes that need to be addressed. When we're confident that the code will work, he or I will post it up so that you guys can get your hands on it. The only things that you'll need to reprogram the controller will be a USB/ FTDI adapter ($15) and the arduino software (free). Here's a photo of the FTDI adapter connected to the controller.


----------



## sink

Hi. Haven't forgotten about you guys, honest. I'm traveling for work stuff. I did much of the code rewrite already (made some great progress while bored waiting for my connecting flight at JFK) but I need to debug it on some actual hardware before I let others test it. O2surplus, I'll shoot you an email next week. Hopefully we can get a controller sent over here so it arrives soon after I get home and I can get you guys some improved firmware to play with.

As an aside, I figured out before I left that while the DS1307 on my homemade controller is very accurate on battery (less than 2s/day drift) it's wildly inaccurate when the controller is powered up. I guess there is some interference happening from the driver circuit due to me not knowing how to design the board properly. This is unique to my board and has nothing to do with the code.

Anyway, the easiest fix is to pick up a tiny ChronoDot RTC board that can be plugged right into the Arduino. It a significantly more accurate RTC using a different chip (DS3231). The end result is that you have one of these (or were thinking about getting one) my code will support it very shortly.


----------



## Tbakes

Any update on this? Even though I can't get all my strings lit concurrently, I'm interested in the new Typhoon code!


----------



## sink

I've done quite a bit of tinkering with the Typhon code, but it's a lower priority than the mountain of stuff that will get me fired if I don't do it . Inexcusable delay though, and I apologize about that. I'll do my best to get it done.

I do have an improved version of my simpler code (see first post in this thread) that I wrote a few months ago. It supports the ChronoDot RTC (the DS3231) and now you can set the time to the second from a PC without having to reflash the Arduino. Much cleaner than the previous way. I didn't post it because it isn't very documented yet, but it does work fine. If anybody wants this, let me know and I'll clean it up.


----------



## MoeBetta

Sink, is be very interested to see that, my chronodot rtc is already on order. 

Don't feel bad, and there is nothing inexcusable about it. Thanks for doing whatever real life allows.


----------



## sink

Okay, I've posted the latest version of my code (not the Typhon stuff yet, sigh) on bitbucket. I also updated the libraries.zip archive to include the library for the ChronoDot. The links in the first post point to the latest version of the code.

This one works a bit differently. Once you've uploaded the tank-control sketch to the Arduino, you can get the time/set the time using a Python script (client.py) you run on your PC while connected to the Arduino over USB. You'll need to change the "PORT" line in that script to match your system. You also need to install the "serial" library for Python for your system. Once that is done, you run the script and enter "sync" at the prompt to set the Arduino time from your PC system time. You can also enter "time" to see what the Arduino thinks the current time is. Finally, either "quit" or "exit" will quit the program.

It needs to be documented better and I'll get around to that eventually, but if you have any problems just PM me and I can help.


----------



## MoeBetta

Hey, thanks a lot.



Hope you had a good weekend.


----------



## MoeBetta

Sink,

The errors I was getting were while using the newest version of the Arduino IDE (1.0)

After finding the errors I PMed you about I looked at them in C++ and not knowing enough to fix them I decided to try them in the .0023 beta of the arduino IDE and it uploaded fine.

I'm working on the remaining steps, but just wanted to post this in case anyone had the same problem. It seems the 1.0 checks all included codes, while the beta did not?


----------



## MoeBetta

I'm currently stuck on the python bit, but that's more due to ignorance than anything.


----------



## sink

MoeBetta said:


> Sink,
> 
> The errors I was getting were while using the newest version of the Arduino IDE (1.0)
> 
> After finding the errors I PMed you about I looked at them in C++ and not knowing enough to fix them I decided to try them in the .0023 beta of the arduino IDE and it uploaded fine.
> 
> I'm working on the remaining steps, but just wanted to post this in case anyone had the same problem. It seems the 1.0 checks all included codes, while the beta did not?


Welcome to the exciting world of Arduino 1.0, which broke compatibility with nearly every existing library for no particularly good reason. The internet is littered with posts like this. In your case the included Time library is incompatible with 1.0. Probably others are too, but it didn't get far enough in the compilation to find out.

I'm not using the Arduino IDE at all but my hacked together build environment is based on the Arduino 0023 core libraries so the code is written to compile against that. I will eventually upgrade even though there isn't a very good technical reason to do so: the new core uses more RAM than before -- a big deal on a microprocessor -- and adds few useful features. But since it'll likely require modifying the libraries I'm not in a big hurry to do so. Use 0022 or 0023 for now :red_mouth.

Thanks for the report. Please let me know about any other issues you run into and I'll update the docs. Or write it up for me and I'll include it in the distribution roud:.


----------



## sink

MoeBetta said:


> I'm currently stuck on the python bit, but that's more due to ignorance than anything.


PM me with details :red_mouth

Nah, it's a good learning experience. Install python 2.7 (code isn't compatible with 3.x yet) and then the pyserial library (http://pypi.python.org/pypi/pyserial).

They you just have to figure out what the usb-serial port is called on your system, change that line ("PORT = ???") in the code, and you're off to the races.


----------



## MoeBetta

I got this script up and running last night. It works like a charm!

Esp. if you wire your circuit right.

Thank you Sink!


----------



## sink

MoeBetta said:


> I got this script up and running last night. It works like a charm!
> 
> Esp. if you wire your circuit right.
> 
> Thank you Sink!


You're welcome, let me know how it works when you have it all hooked up.

I just uploaded a new version with a bit better comments in the code for what people need to change to make it work. It doesn't add any features so no need to upgrade.


----------



## stephenpence

Well i'm playing catch up on this whole Code thing.. I'm basically worthless at it. BUT i bought an arduino Uno and a chronoDOt RTC and by gosh i'm gonna make this thing work. so a few questions:
If i were to reduce the code to only have one driver running off of it, what would i need to edit? 
Also, for the life of me, i can't figure out what the heck Python is. I got it, installed it, and i am still just absolutely clueless. 

In my defense, i am not an idiot.. i'm just an engineer. so i've never had a good reason to try and delve into this. Thanks in advance for the help!!


----------



## MoeBetta

Just remove the lines that reference one of the channels.

"const int kChan1Pin = 10; // Channel 1 Pin" is where the second channel is assigned to pin 10

" if (state[1] >= 0 && state[1] <= 1023) Timer1.setPwmDuty(kChan1Pin, state[1]);" Where the second channel state is set.

Really, all I did was delete that first line and try uploading it via the Arduino alpha ide, it told me what else wouldn't work.

Once I deleted the lines it told me to it uploaded and worked just fine.

Python is another program that works in a slightly different language. Let me see if I can remember how I set my RTC.


----------



## stephenpence

great thank you! also, is there a program that will show what's going on on the arduino board as it happens? I'm not used to sending a program, and hoping it's doing what i told it to.


----------



## MoeBetta

You can set up code for serial monitoring, as far as I know, that's the only way to do it.


----------



## MoeBetta

Shoot me a PM with your e-mail addy and I'll send you the serial monitoring code Sink send me a while back to see if it is what you're looking for.


----------



## O2surplus

stephenpence said:


> Well i'm playing catch up on this whole Code thing.. I'm basically worthless at it. BUT i bought an arduino Uno and a chronoDOt RTC and by gosh i'm gonna make this thing work. so a few questions:
> If i were to reduce the code to only have one driver running off of it, what would i need to edit?
> Also, for the life of me, i can't figure out what the heck Python is. I got it, installed it, and i am still just absolutely clueless.
> 
> In my defense, i am not an idiot.. i'm just an engineer. so i've never had a good reason to try and delve into this. Thanks in advance for the help!!


Unless you need that output pin for some other task- I don't see a need to modify the code at all. Since you say that you'll only be running one driver- just edit the start/stop times for one of the PWM channel pins and leave the other pin alone. You may find that you want to add another group of leds in the future and the code left, "as= is" will allow for that.


----------



## sink

stephenpence said:


> Well i'm playing catch up on this whole Code thing.. I'm basically worthless at it. BUT i bought an arduino Uno and a chronoDOt RTC and by gosh i'm gonna make this thing work. so a few questions:
> If i were to reduce the code to only have one driver running off of it, what would i need to edit?
> Also, for the life of me, i can't figure out what the heck Python is. I got it, installed it, and i am still just absolutely clueless.
> 
> In my defense, i am not an idiot.. i'm just an engineer. so i've never had a good reason to try and delve into this. Thanks in advance for the help!!


Hi, thanks for the interest!

You shouldn't have to change anything to get the code running for only one driver/channel. It should just work. The program will still send out a PWM signal on the second channel, but that won't hurt anything.

Python is a scripting language. I used it to write the control code that you run on your PC to set/check the Arduino clock. Since it's an interpreted language, you need to install Python to actually run that script. Make sure you install version 2.7 and not one of the 3.x versions, though you can safely have both installed at the same time. You also need the pyserial library from here: http://pypi.python.org/pypi/pyserial

Then you upload the control code sketch to the Arduino. As indicated above use the 0023 version of Arduino and not the 1.0 ones as a bunch of the libraries I use aren't updated to use the new version yet.


----------



## sink

stephenpence said:


> great thank you! also, is there a program that will show what's going on on the arduino board as it happens? I'm not used to sending a program, and hoping it's doing what i told it to.


When you upload the sketch using the Arduino IDE it's pretty clear whether or not it worked. If it uploads, you're almost set, then you just need to run the Python script to set the time properly. You should only have to do that once; the ChronoDot is scary accurate.

I have another version of the sketch with debugging turned on that can help if you're having an issue (it'll show if the RTC isn't hooked up properly, for example) but try with the normal version first.


----------



## stephenpence

wow guys thanks for the quick replies!! i figured since this thread had been asleep for a month i might have to poke the beehive a few times before anything happened haha... 
So here's MY update. I realized my first problem is that i hadn't set the time in my rtc shield. So that made a big difference (obviously). now then, when i woke up the serial code at the end of the tank control pde... it was talking to me in.. i dunno, klingon maybe. But i DID get the times set, and get the arduino to turn on and off the lights at the correct interval. This is for a smaller LED string (for now) and I'm running it on the Meanwell 60-27P driver. I've notices that anything below ~300 for brightness in the program just turns the LED's off. above 300 is pretty bright, and then it just gets brighter. Was i under a false impression thinking that these guys (CREE XP-Gs) would dim quite a bit? or is the dimming function just to pinpoint your PAR readings at the substrate?? I would love to see this thing power a full sunrise simulation but as of now it's less "sunrise" and more "daybreak". let me know if you have any ideas, and again, thanks for the quick responses!!


----------



## sink

stephenpence said:


> wow guys thanks for the quick replies!! i figured since this thread had been asleep for a month i might have to poke the beehive a few times before anything happened haha...
> So here's MY update. I realized my first problem is that i hadn't set the time in my rtc shield. So that made a big difference (obviously). now then, when i woke up the serial code at the end of the tank control pde... it was talking to me in.. i dunno, klingon maybe. But i DID get the times set, and get the arduino to turn on and off the lights at the correct interval. This is for a smaller LED string (for now) and I'm running it on the Meanwell 60-27P driver. I've notices that anything below ~300 for brightness in the program just turns the LED's off. above 300 is pretty bright, and then it just gets brighter. Was i under a false impression thinking that these guys (CREE XP-Gs) would dim quite a bit? or is the dimming function just to pinpoint your PAR readings at the substrate?? I would love to see this thing power a full sunrise simulation but as of now it's less "sunrise" and more "daybreak". let me know if you have any ideas, and again, thanks for the quick responses!!


I'm subscribed to this thread, so I get prodded when new posts show up. I assume the rest of these guys just spend all day on the forums...:icon_smil

I'm glad you got everything working. Did you set the clock using the Python script, or the time-set code? I guess the latter should still work, though the former is easier and more accurate (and allows you to reset the clock without having to re-sketch the Arduino. You should also make sure the time stays accurate across a power cycle: Pull the power to the arduino and RTC (leave the battery in though), wait about ten seconds, then turn it back on and make sure it still sets the lights the right way. The RTC should keep time fine during a power outage when configured properly.

The dimming issue is your driver. The XP-Gs (I have 6 each of Neutral White and Cool White over my tank...) allow linear dimming all the way down, and my code can dim to about 0.1% intensity (1/1023). The limitation regarding how much dimming you actually get is in the driver, though.

I use CAT4101 drivers on my board. The specs say they dim linearly to about 1% intensity and this is consistent with what I see in practice (I can dim below that, but it's not very smooth). Other drivers like the Meanwells are slower and only have linear dimming to a much higher cutoff. I recall the manufacturer telling me that the *P models (the ones with PWM) can only dim to about 11-12 % intensity. If yours cuts off at about 300, that's about 29%, which seems high.

If you don't mind experimenting a bit, try two things for me. Set your intensity to, say, 200 (a bit lower than you can achieve right now). Now, in the tank_control.pde sketch there is this on line 176:

Timer1.initialize(6666); // 150Hz PWM

That sets the frequency of your PWM output. I want you to try a few new values instead of that 6666 and see if your driver likes them better. Try 10000 first and experiment with the dimming, and then try 333. Those correspond to 100Hz and 3kHz respectively, the upper and lower frequencies that your Meanwell can handle (obviously you'll have to save and then upload the sketch again to the Arduino after each change). You might be able to eek out a bit better dimming using one of those settings. Don't expect miracles though, the Meanwells won't dim all the way down no matter what you do.

One more thing that may make a difference -- that 11-12% might be expressed as a percentage of *max* output. So if you aren't running the LEDs at full power during daylight anyway, turn the current knob on the Meanwell down all the way and then check. I bet that will give a bigger dimmable range...

Good luck and please let me know how it goes.


----------



## MoeBetta

I thought the meanwell driver was the limiting factor on those, I believe it has a minimum built in.

LED's will run as low as you want them to. This is the reason I've chosen to build a driver from scratch based on o2's design. I'm currently waiting on boards. As I understand it I'll be able to use my XM-L string as moonlights.

I know there is nothing in the code that cuts output below any level. I currently have a 3mm led dimming to a output value of 2. You can barely tell it is on, but it is.

Cheers!

Jason


----------



## sink

MoeBetta said:


> LED's will run as low as you want them to. This is the reason I've chosen to build a driver from scratch based on o2's design. I'm currently waiting on boards. As I understand it I'll be able to use my XM-L string as moonlights.


May work, but even well less than 1% or so of a very bright LED is still amusingly bright, especially if you have a string of them. If it's too bright, I may be able to knock up something for you. In theory you can get 16bit PWM output on the Arduino but it's fairly complex so I've never tried. That would let the code dim down to 0.0015% intensity (instead of the 0.1% currently). There would still be the limitation of your driver, but might be enough.


----------



## stephenpence

So i spent some time doing some fine tuning, to find my minimum allowable values. 
At 10000 - 233. (at this point the LEDs showed some pulsing, and the lights 
were pretty dim. just going from 233-235 is a dramatic 
difference in light output
At 6666 - 232. Lights were not significantly more dim than the 235 mark at 
10000. i was never able to achieve a significant dimming level.
At 333 - 234. Essentially the same as the 6666 level. no significant dimming 
level. 
I adjusted the SVR2 screw in the driver so that the 10000 test showed quite a bit of dimming. then we set the day night phase to go from 230 to 236 over a one mnute dimming inverval. 

At 10000 - the lights showed smooth dimming across the board, went from
lights out to bright.
At 6666 - Less smoooth than 10000. towards the dim end, they started to 
flicker before they turned off

At 333 - dimming was really choppy. towards the lowest value in the dimming the lights were flickering more and more rapidly until they shut off.


So i'm not entirely sure how to get a decent sunrise efffect. i'm thinkng starting one below the min value, and having it dim up to 800, which is visually about where i want the tank at. 
I have to admit, there's a not so small part of me that's bummed by the lack of dimming capabilities of these meanwell drivers. regretfully, before this build, i had no idea how any of it worked, so i bought the kit from Rapid LED so i could learn by doing. What is important is that i should have the ability, once i have my par meter built, to adjust the max brightness to the level i want at my substrate. 
If you have any thoughts on my results, or other ideas how to get this guy to work on the full spectrum, let me know!


----------



## sink

stephenpence said:


> So i spent some time doing some fine tuning, to find my minimum allowable values.
> At 10000 - 233. (at this point the LEDs showed some pulsing, and the lights
> were pretty dim. just going from 233-235 is a dramatic
> difference in light output
> At 6666 - 232. Lights were not significantly more dim than the 235 mark at
> 10000. i was never able to achieve a significant dimming level.
> At 333 - 234. Essentially the same as the 6666 level. no significant dimming
> level.
> I adjusted the SVR2 screw in the driver so that the 10000 test showed quite a bit of dimming. then we set the day night phase to go from 230 to 236 over a one mnute dimming inverval.
> 
> At 10000 - the lights showed smooth dimming across the board, went from
> lights out to bright.
> At 6666 - Less smoooth than 10000. towards the dim end, they started to
> flicker before they turned off
> 
> At 333 - dimming was really choppy. towards the lowest value in the dimming the lights were flickering more and more rapidly until they shut off.
> 
> 
> So i'm not entirely sure how to get a decent sunrise efffect. i'm thinkng starting one below the min value, and having it dim up to 800, which is visually about where i want the tank at.
> I have to admit, there's a not so small part of me that's bummed by the lack of dimming capabilities of these meanwell drivers. regretfully, before this build, i had no idea how any of it worked, so i bought the kit from Rapid LED so i could learn by doing. What is important is that i should have the ability, once i have my par meter built, to adjust the max brightness to the level i want at my substrate.
> If you have any thoughts on my results, or other ideas how to get this guy to work on the full spectrum, let me know!


Very thorough experimentation. You can safely use whatever of those frequencies works best in your case (probably 10000).

I understand the issue. Howabout this proposal:

Set the current knob on the Meanwell such that max intensity in the code (1023) corresponds to a bit higher than the highest light output you want during daytime over the tank. I know you might not know this value yet without a PAR meter, but you can always tweak it later. Set the nighttime intensity in the code to just less than the value needed to turn on the lights, and your daytime intensity to 1023. Then, set the sunrise/sunset duration (kFadeDuration) to be very long, say a few hours. Set the sunrise time (kTurnOn) to the time you want the lights to start coming on, and then set the sunset time (kTurnOff) to the time you want the lights to be off MINUS the long fade duration--meaning it will probably be a time in the afternoon.

This will give you a long dawn, then a while at high intensity, followed be a long drawn out sunset. Since much of the actual light fading happens at the extreme of each fade (courtesy of the Meanwell limitations) this should give you a decently smooth sunrise/sunset. You can probably tweak the values so that your plants still get enough light (and realistically this is a more natural cycle than a quick sunrise/sunset followed by a long flat noon).


----------



## stephenpence

brilliant. i'm setting it up now! one day i'll be able to justify buying some better drivers, and when i do, i'll be coming back here to ask you where to look. Seriously thank you for helping me make these work for the mean time though!!!


----------



## sink

stephenpence said:


> brilliant. i'm setting it up now! one day i'll be able to justify buying some better drivers, and when i do, i'll be coming back here to ask you where to look. Seriously thank you for helping me make these work for the mean time though!!!


You are very welcome, and please let us know if it works. For driver questions, ask O2Surplus. The board that I'm using on my tank is actually just a vastly inferior homemade copy of one of his designs :thumbsup:


----------



## MoeBetta

Stephen, fwiw, ill have some extra of o2's latest boards laying around as long as I dont ruin all 10 trying to solder the lm3409. 

We may have to work on setup values depending on you parameters. But I should be able to help you with a turn key solution.


----------



## O2surplus

MoeBetta said:


> Stephen, fwiw, ill have some extra of o2's latest boards laying around as long as I dont ruin all 10 trying to solder the lm3409.
> 
> We may have to work on setup values depending on you parameters. But I should be able to help you with a turn key solution.


Moe- Did I give you the design w/ analog current adjustment? If I did, The current can be adjusted from a maximum of 3000mA to a minimum of 100mA. That's enough adjustment range to drive practically any high power led on the market today. Stephen could just turn down the current to whatever level he desires and then PWM dim from there. As an experiment- I have the same driver pushing a single Bridgelux BXRA-C4500 to *75* watts (27vdc x 2750mA) right now. It's been up and running 24/7 since last week and there have been no failures yet. I think we have ourselves a winner in the search for a cheap and reliable DIY Led driver .


----------



## MoeBetta

Yeah, I've got the adjustable pot.

Sounds great to me, I can't wait to get these 12 XM-L blinding these poor fish. This 70" heatsink is pretty solid, hoping to not even need active cooling, but if I do I'll just get the arduino a sensor on the HS and have it switch on 4 12v fans in series off the 48v supply via a relay.

Did you get your most recent project up and running yet? I'm anxious to see what you came up with.


----------



## O2surplus

MoeBetta said:


> Yeah, I've got the adjustable pot.
> 
> Sounds great to me, I can't wait to get these 12 XM-L blinding these poor fish. This 70" heatsink is pretty solid, hoping to not even need active cooling, but if I do I'll just get the arduino a sensor on the HS and have it switch on 4 12v fans in series off the 48v supply via a relay.
> 
> Did you get your most recent project up and running yet? I'm anxious to see what you came up with.





70" Heat sink- Sounds pretty heavy duty to me. That should handle 12 XML's running at full tilt with ease. I've been so busy helping a couple of other members and a LFS with DIY drivers for their own systems that I haven't had much time to play with my own. I'm in the process of swapping out all my CAT4101 drivers for the more flexible LM3409, in my 300 watt LED retrofit fixture. I'm also waiting for a new 48Vdc power supply to show up. I ordered one from a seller on FleaBay and instead of sending the *MEAN WELL *that they advertised, I received a *MEANG WEL *- WTH? I tested it out and it couldn't even reach *47Vdc*! Needless to say- but I'm gonna be using some "choice words" directed at my little friends in China, if they don't give me what I paid for! I'll be posting the rebuild of the fixture as soon as I get all the parts and as time permits. I'm also waiting patiently to see what Sink comes up with for replacement coding for my little PWM controller. As soon as he has worked his magic on the software, I'll be tooling up for another production run of controllers. I've still got *20 *ATMEL AVR's to play with.


----------



## stephenpence

so a question for MoeBetta and O2surplus, where can i get ahold of these boards you guys are talking about???? they sound... well, perfect!!


----------



## MoeBetta

Ive got 10 on order with enough components to build five right away, I only need one, so ill have extras.


----------



## MoeBetta

Double post.


----------



## O2surplus

Stephenpence

How many XP-G's are you going to run? There are a couple of really good DIY drivers available, that you could use, that cost very little money to build. The CAT4101 chip can drive 6-7 XP-G's per channel, up to 1000mA, and is the most easy to build, as it takes the least number of parts. Next is the LM3409 based driver. It can drive more leds at higher voltages/currents, but is tricky to solder and costs a bit more due to the higher number of parts involved. Both driver designs require the purchase of an additional 24 or 48 volt supply to make them work. MoeBetta has an order of LM3409 boards on the way for his system. I also have a batch of the same design and some CAT4101 boards laying around. I could part with a couple,of either type if you want them.:icon_smil


----------



## stephenpence

my hi-tec tank is running 24 cool white XP-G's. my shrimp tank has 6 xp-g's over it. I currently have 2 meanwell 60-48P drivers on the hi-tec and one meanwell 60-27P over the shrimp tank. so do these driver boards also run the timing code? or is that a seperate board? this is seriously awesome (in the geekiest way i can imagine  )


----------



## O2surplus

Both of the driver designs that I mentioned will directly accept the 5v PWM signal from an Arduino, so there's nothing else needed. They have far better dimming performance than any of the "off the shelf" Mean Well drivers. I've been running 90 Cree XR-E's of the CAT4101's for nearly 2 years running and haven't experienced a failure yet. Prior to Sink posting his lighting control code, I had no idea how linear and extreme the dimming performance of these drivers could be. (Sink's the Arduino software Master/Guru, I'm just the grass hopper that learned the EAGLE electronic design software.)
If you'd like to try your hand at building your own, I'd recommend starting with the CAT4101 based design. Your particular set-up does not really require anything more elaborate than that. The CAT4101 driver IC's cost less than $4 each and you'd only need five to complete your project ( 4 on the Main tank, 1 on the shrimp tank ) I have some spare boards that contain 4 CAT chip positions( for your main tank) and a spare 2 CAT board ( for your shrimp tank ). Send me a PM with your mailing address and I'll drop them in the mail for you.:icon_smil


----------



## Chlorophile

Any way it would be possible to turn your co2 on and off too? 
My solenoid needs 24v, can the arduino deliver that in some way? 
Or would it be possible to use a relay? 
I'd love to have an arduino control all my stuff and not need any other timers.


----------



## sink

Chlorophile said:


> Any way it would be possible to turn your co2 on and off too?
> My solenoid needs 24v, can the arduino deliver that in some way?
> Or would it be possible to use a relay?
> I'd love to have an arduino control all my stuff and not need any other timers.


Very easy, though as you mention you'd need to use a relay (that operates on 5V) rather than trying to drive the solenoid with the Arduino directly. Then modifying the code is pretty easy, I can do it for you.


----------



## Chlorophile

sink said:


> Very easy, though as you mention you'd need to use a relay (that operates on 5V) rather than trying to drive the solenoid with the Arduino directly. Then modifying the code is pretty easy, I can do it for you.


Alright... Well I would have to buy LEDs, build and LED fixture, buy arduino, all the other stuff, assemble that, buy a relay, etc, first. 
But if I ever do all that I'll let you know!


----------



## sink

Chlorophile said:


> Alright... Well I would have to buy LEDs, build and LED fixture, buy arduino, all the other stuff, assemble that, buy a relay, etc, first.
> But if I ever do all that I'll let you know!


OK. By the way, 24VDC is a common supply voltage. It's also convenient for LEDs (you can drive a string of 6 x "3W" LEDs with it). So if I were you I'd design my circuit around a suitable 24V power supply and drive everything from it (LEDs; CO2 solenoid; Arduino; fans etc), saving the need for a bunch of wallwarts. For stuff that takes 5V, just add a regulator somewhere in the circuit.

On that note O2surplus, if your newest driver doesn't have a 5V output plug somewhere on it, I think it would be a very versatile addition...


----------



## O2surplus

sink said:


> OK. By the way, 24VDC is a common supply voltage. It's also convenient for LEDs (you can drive a string of 6 x "3W" LEDs with it). So if I were you I'd design my circuit around a suitable 24V power supply and drive everything from it (LEDs; CO2 solenoid; Arduino; fans etc), saving the need for a bunch of wallwarts. For stuff that takes 5V, just add a regulator somewhere in the circuit.
> 
> On that note O2surplus, if your newest driver doesn't have a 5V output plug somewhere on it, I think it would be a very versatile addition...


I like to include voltage regulators on my driver boards as it does make it easier to power additional cooling fans, arduino's. ect.. The regulators I use will provide up to 1.5 amps but are limited to 35 volts on the input side, so I have to look for another solution for my driver designs that utilize higher voltages than that. Here's the little LM3409 driver that includes an on board 5 volt reg for powering a "SynJet" Led cooler. I also built a few for myself that run a 12 volt reg instead.


----------



## sink

O2surplus said:


> I like to include voltage regulators on my driver boards as it does make it easier to power additional cooling fans, arduino's. ect..


Yeah, of course. I put a 5V regulator on mine too, but since I'm ghetto I just soldered a wire to a pad on the board to get the 5V out to external devices. I'm just saying having the that 5V output connected to something on a terminal block would be a nice touch if it isn't already.

PS -- nice board!


----------



## O2surplus

Oh- Coding Master, 

Didn't you see the "Everything- Including The Kitchen Sink" Version of the CAT4101 Driver? It's got *5v & 12v OUTputs*, Analog Current adjustment for each channel, and Independent/ganged PWM dimming. Take a close look- Everything you could ever want is "Built-In"


----------



## aaronbrown

i love what you guys are doing here im looking to set up leds on my newest 30g sa biotope it will be lightly planted mainly a few swords i think it will look more like natural sun light with leds but im lost as to 
what leds id need?
how many id need?
what driver or drivers to use?
ive already got an arduino mega rtc and a 16x4 lcd ive got the lcd hooked up all but the pot needed to adjust contrast but i cant find a decent pot localy i baught a trimmer but it didnt work i just started playing with it so everything is on breadboard still did i mention i have no electronics experince so i keep playing around with it hoping to not destroy anything i wish some one could put a nice package to geather with simple instructions as to how to put it togeather it be nice if it was all preprogramed but if the code was easy to get ahold of i could do that part 

so is there any one out there ready to put me a package togeather?


----------



## O2surplus

aaronbrown said:


> i love what you guys are doing here im looking to set up leds on my newest 30g sa biotope it will be lightly planted mainly a few swords i think it will look more like natural sun light with leds but im lost as to
> what leds id need?
> how many id need?
> what driver or drivers to use?
> ive already got an arduino mega rtc and a 16x4 lcd ive got the lcd hooked up all but the pot needed to adjust contrast but i cant find a decent pot localy i baught a trimmer but it didnt work i just started playing with it so everything is on breadboard still did i mention i have no electronics experince so i keep playing around with it hoping to not destroy anything i wish some one could put a nice package to geather with simple instructions as to how to put it togeather it be nice if it was all preprogramed but if the code was easy to get ahold of i could do that part
> 
> so is there any one out there ready to put me a package togeather?


I think if you were to ask Sink, he would probably be willing to send you a modified copy of his code for your Mega. I play with coding from time to time but I seem to be better at the hardware side of these projects. I recommend no more than 12 Cree XP-G's for your 30 gallon tank. I tend to error toward the high side with led counts, as dimming "too many leds" is always easier than trying to add more later on. You could use a single Mean Well ELN 60-48P driver to power your leds ( but their dimming performance sucks ) or build your own drivers from scratch, save some money, and learn some practical electronics along the way. Send me a PM if you'd like some info on building your own drivers, and PM Sink, as he's the go to guy around this forum for coding.


----------



## sink

Hi! There are lots of different (correct) answers to those questions and most of them have huge threads here on PT already so I'll refer you there. I will say that I have 12 XP-G leds over my 29G and it's plenty (I run them at maybe 50% power). If you're fairly handy making a driver isn't too hard, especially if you already have a board to use. Plus that means you can fix it when it breaks, and that you can upgrade it in the future if you need. My code won't run on the Mega out-of-the-box due to differences with the timers between the two platforms. It might be fixable, but admittedly I haven't looked into it much.


----------



## allknighter

Wow, I'm blown away by this forum.

I've been using arduino in several of my personal projects and was going to tackle the aquarium next. I'll probably look into using some of Master Sink's script since it sounds so high fidelity (curses that i've already invested in the Meanwell driver, I'd love to rather go with O2's). 

The only extra thing I'm going to be adding is a 2A 12v relay out to a pair of motors, which will drive a set of bevel gears pushing pistons and dosing my tank  so hopefully I'll be able to add to the discussion here.

Keep up the great work!


----------



## jeremyblevins

if anyone is still looking for a waterproof temperature sensor just take apart a coral life thermometer. mine was just a 10k thermistor


----------



## Profector

Couple of questions for you guys. I have the mega 2560, will your sketch work on it? Also I've been using a modded pc power supply for other projects and am hoping to use it to power the 12v 1amp leds I've ordered. Then stick a mosfet on each of the six channels and having the mega pulse it for the sunrise sunset effect. 5 channels for 6500k daylight and one for moonlight @ about 480nm. Would that work?


----------



## Profector

Oh and the heat sinks came off a bunch of old computers. If they're good enough to cool a processor they should be good enough to cool the LEDs, and prevent thermal runaway ...right?


----------



## O2surplus

Profector said:


> Couple of questions for you guys. I have the mega 2560, will your sketch work on it? Also I've been using a modded pc power supply for other projects and am hoping to use it to power the 12v 1amp leds I've ordered. Then stick a mosfet on each of the six channels and having the mega pulse it for the sunrise sunset effect. 5 channels for 6500k daylight and one for moonlight @ about 480nm. Would that work?


Sink's sketch won't work with the Mega because it has an altogether different AVR and pin out. You'll need a Duemilanove/Uno for his code to work. As far as pulsing the mosfets with a PWM signal, that should work, provided that you are using current limiting resistors in each of your strings. Otherwise the leds will "blow" when not being PWM'ed. If you're willing to go to that much trouble to use your particular power supply, why not use a chip that is actually designed with driving leds in mind? The OnSemi Cat4101 or National Semiconductor LM3409 are two such chips. Sink & I both use the CAT4101, they're cheap,reliable, and work beautifully with his control code. Let us know if you want more info.


----------



## Profector

I wouldn't know how to use either of those chips or were even where to put them.  Are they used to make your own drivers?


----------



## Profector

Well after a little more reading it looks like I would use one of there in place of a MOSFET. Is that correct?


----------



## O2surplus

Profector said:


> Well after a little more reading it looks like I would use one of there in place of a MOSFET. Is that correct?


Yep. The Cat4101 is really no more difficult to use than a Mosfet. The only difficulty is that the Cat4101 is only available in a surface mount component package, so you'll have to solder it down to a printed circuit board, but it's large enough to be soldered by hand without too much trouble. I have printed circuit boards for the CAT 4101 already drawn up and could send them to you if you wish. I use SeedStudio for manufacturing the PCB'sServices : Seeed Studio Bazaar, Boost ideas, extend the reach . They're really affordable as you can get 10 boards for as little as $10. If you look at the previous posts in this thread you'll find a few photos showing the CAT driver.


----------



## Profector

If you could send me the drawing that'll be great. I'll PM you my email shortly. I haven't looked at the code yet, but I'm hoping that I'll be able to adapt it. Not familiar with Python but I do light programing in C# and VB so with luck I'll be able to get it going on the Mega 2560. If not, I seen the Atmega328p with the bootloader for about $6 over at adafruit.


----------



## O2surplus

Profector said:


> If you could send me the drawing that'll be great. I'll PM you my email shortly. I haven't looked at the code yet, but I'm hoping that I'll be able to adapt it. Not familiar with Python but I do light programing in C# and VB so with luck I'll be able to get it going on the Mega 2560. If not, I seen the Atmega328p with the bootloader for about $6 over at adafruit.


PM & Email with Files sent


----------



## Chlorophile

WOW...
I think I have a cool idea.
Could you find the data in an almanac of say 2011 on then the sunrise and sunset was every day for somewhere closer to the equator and program say lights at 5% or 10% at sunrise and sunset with them the strongest at mid day + include a time skew so you could shift sunrise to your desired time?
It would be cool for fish to have a varying light cycle that actually mimicked the location they originated from... 

I'm sure it's possible, probably a lot of work, just wondered what you guys thought about it.


----------



## Gisimo

Hello i have a problem with the code, when i make changes to the code and upload it, it doesn't work unless i remove the ds1307 before i update the changes why is that? and i can't seem to find the file for setting the time on a ds1307 i currently use a arduino 1,0 file and program for that, is that the problem?
Thanks...


----------



## sink

Chlorophile said:


> WOW...
> I think I have a cool idea.
> Could you find the data in an almanac of say 2011 on then the sunrise and sunset was every day for somewhere closer to the equator and program say lights at 5% or 10% at sunrise and sunset with them the strongest at mid day + include a time skew so you could shift sunrise to your desired time?
> It would be cool for fish to have a varying light cycle that actually mimicked the location they originated from...
> 
> I'm sure it's possible, probably a lot of work, just wondered what you guys thought about it.


 Certainly possible, though due to storage requirements on the Arduino you'd have to approximate the sunrise/sunset times with an equation rather than hard coding it. Another possible thing would be have moonlights (if using them) follow a lunar cycle and wax and wane accordingly. Cool stuff. That said I'm way too busy to do any of this stuff, but I can help with code issues if anybody wants to try.


----------



## sink

Gisimo said:


> Hello i have a problem with the code, when i make changes to the code and upload it, it doesn't work unless i remove the ds1307 before i update the changes why is that? and i can't seem to find the file for setting the time on a ds1307 i currently use a arduino 1,0 file and program for that, is that the problem?
> Thanks...


 Hi Gisimo, Currently the libraries I use don't work on Arduino 1.0, so you need to use the version previous to that (22 or 23). Don't worry -- you aren't really losing any functionality when you do that and in fact code compiled with the older versions uses less memory to run. All of the needed files are in the latest version of the archive (see the first post). I'm using a DS3231 RTC now, so it defaults to using that. To use the DS1307 you'll need to swap some lines in the code. *EDIT:* Apparently they've changed the comment editor and it eats any code contained in < and > symbols thinking they are HTML tags, even inside code blocks. Truly brilliant. Basically, change this on line 48:


Code:


 //#include DS1307RTC.h
#include DS3231RTC.h

 To this: (ignore the missing < and >)


Code:


 #include DS1307RTC.h
 //#include DS3231RTC.h


----------



## Gisimo

Hi, and thanks. 

I hope that will work - but i haven't found the set time pde file. Can anyone help me with a link so I can update the time on my ds1307 with arduino 0023?
Thanks


----------



## O2surplus

Gisimo said:


> Hi, and thanks.
> 
> I hope that will work - but i haven't found the set time pde file. Can anyone help me with a link so I can update the time on my ds1307 with arduino 0023?
> Thanks



Here's the sketch, and the library you'll need is attached to this post. 


Code:


/*
 * Name:    timeset.pde
 * Author:    User "sink" at plantedtank.net forums
 * URL:        http://bitbucket.org/akl/tank-control
 *
 * This code sets the time on a DS1307 RTC chip attached to an Arduino
 * microcontroller board.  The time is set to the system time when the
 * sketch was compiled (using preprocessor macros), so make sure that:
 *
 *     1. Your system (PC) time is accurate.
 *     2. You recompile the sketch and then upload immediately.
 *
 * The time is skewed forward some seconds to accomodate for compilation and
 * upload time.  If you find the time is consistently off by the same amount,
 * you can modify the adjustment constant below.
 *
 * This code requires the following libraries: Wire, Time, DS1307RTC
 *
 * The latest version of this code can always be found at above url.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */

#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>

/*
 * Time adjustment forward in seconds.  Used to compensate for
 * compilation/upload time.
 */
const int kAdjustment = 10;

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}

void setup() {

  // convert compilation time and set system clock
  char const *date = __DATE__;
  char const *time = __TIME__;
  int sec, min, hour, day, month, year;
  
  char s_month[5];
  static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  sscanf(date, "%s %d %d", s_month, &day, &year);
  month = (strstr(month_names, s_month)-month_names)/3;
  sscanf(time, "%d:%d:%d", &hour, &min, &sec);

  setTime(hour, min, sec, day, month+1, year);
  adjustTime(kAdjustment); // crude fwd correction
  time_t t = now();

  // set RTC
  RTC.set(t);

  Serial.begin(115200);
}

void loop () {
  digitalClockDisplay();  
  Serial.println(); 
  delay(1000);
}


----------



## Gisimo

*thank you so much*


----------



## Gisimo

Hi I have a Question, is it normal, that i need to press reset if there have been a power loss?[censored]


----------



## O2surplus

Are you talking about the reset button on your Arduino? The Arduino should retain the dimming sketch indefinitely unless you upload a new sketch to it. The DS1307 RTC should keep the correct time as long as it's backup battery hold a charge. Unless your hardware has a defect a temporary power loss should not be a problem. The Arduino should just pickup and run it's program at whatever point that it should be at, as determined by the DS1307 RTC.


----------



## Gisimo

Yes i am talking about the reset button on the arduino!! I accidentally pulled the wrong cord and when i plug it in again it didn't light up so i pressed the reset button and that got the lights on again!!
Maybe i shut have waited a bit longer or is there somthing wrong ?


----------



## sink

O2surplus said:


> Are you talking about the reset button on your Arduino? The Arduino should retain the dimming sketch indefinitely unless you upload a new sketch to it. The DS1307 RTC should keep the correct time as long as it's backup battery hold a charge. Unless your hardware has a defect a temporary power loss should not be a problem. The Arduino should just pickup and run it's program at whatever point that it should be at, as determined by the DS1307 RTC.


 This is correct -- you definitely shouldn't have to reset.

Make sure your RTC and battery are properly connected and that your coin battery has sufficient charge. The battery isn't purely to provide backup voltage -- the RTC expects it to be there and will act erratically otherwise.


----------



## sink

Gisimo said:


> Yes i am talking about the reset button on the arduino!! I accidentally pulled the wrong cord and when i plug it in again it didn't light up so i pressed the reset button and that got the lights on again!!
> Maybe i shut have waited a bit longer or is there somthing wrong ?


Something else is wrong. What sketch is loaded on the Arduino? Usually when this happens it means the reset is also resetting the time on the RTC, either through the sketch or though power cycling the RTC.

Also rather than using the timeset.pde sketch, I'd recommend using the python script in the latest version of my code. It's a bit more work to set up since you have to download Python, but it is less error prone and when something goes wrong it is easier to see what is going on.


----------



## Gisimo

I use the sketch from this site! And my RTC is ok,, when i use the reset button the light start were it got cut off it doesn't start at the beginning! So what is wrong then?


----------



## sink

Gisimo said:


> I use the sketch from this site! And my RTC is ok,, when i use the reset button the light start were it got cut off it doesn't start at the beginning! So what is wrong then?


Ok good. I just want to make sure are were using the latest version of tank_control.pde, with I assume the minor modification on lines 48/49 to use the DS1307. This is correct?

Do you mean that the light level resumes at the correct level for where it got cut off, or at the correct level for the current time? Have you confirmed the clock advances correctly when only running on the battery?

If you are using the correct sketch (with the minor modifications), the clock advances correctly both when powered and on battery, and the sketch properly dims the lights and resumes the lights correctly when power is reapplied then you have a hardware problem somewhere.

I'd speculate that the Arduino is failing to boot the first time you apply power, but it works once your power supply has stabilized. So I'd have a look at your power supply/regulators. How are you supplying power to the Arduino/RTC?


----------



## Gisimo

I use a 12 volt dc power supply connected to the dc input on the arduino uno and i use the same for my lights! The light faded out at the right time to night so i think it is ok? I have just yesterday change the lines you told me about and it helped alot!! My rtc i connected to gnd and +5 v on the arduino and the two other is connected to a4 and a5 directly!!


----------



## Gisimo

my ds1307 is this: http://www.sparkfun.com/products/99

i measure the voltage on the battery and it is 3,34 volt so it is ok....

the sda is wired to A4 and sdl is wired to A5. the +5 volt and the gnd from ds1307 is connected to +5 volt and gnd on the Arduino uno.

i use 12 volt to my lamp and to run the arduino i have put an one way diode on the red wire and connect it to the dc plug.

i controle the dimming with two irf730 (like a motor controle) and it Worked fine so no problems there... 

I don´t now how to find out if my ds1307 i working correctly!!!!! help please......


----------



## O2surplus

Sink's "tank control" sketch features a serial output for the clock. I suggest re- flashing your arduino with the Timeset sketch and then the tank control sketch. Then open the serial monitor in the Arduino IDE while your still connected to your board. You may have to adjust the baud rate to see the output from the clock, but there's only a few choices to choose from. IF you see the time output in the serial monitor then you know the clock is working ok. If not- continue trouble shooting the hardware until you do get a clock output in the serial monitor.


----------



## sink

O2surplus said:


> Sink's "tank control" sketch features a serial output for the clock. I suggest re- flashing your arduino with the Timeset sketch and then the tank control sketch. Then open the serial monitor in the Arduino IDE while your still connected to your board. You may have to adjust the baud rate to see the output from the clock, but there's only a few choices to choose from. IF you see the time output in the serial monitor then you know the clock is working ok. If not- continue trouble shooting the hardware until you do get a clock output in the serial monitor.


While that is true on the older versions, the newer versions of my code actually use the serial output to talk with the PC to set & query time, so they don't spam the clock time continuously as it would interfere with the protocol.

Use the one linked below, which I just hacked up to include logging. When you've uploaded it fire up the serial console in Arduino and take note of the clock time and counter and compare it to your watch. Then disconnect the power for a few minutes. When you start it back up and look at the serial console, the clock shouldn't have lost time with respect to your watch. If it has, then the RTC clock isn't advancing on battery.

http://pastebin.ca/2135363


----------



## Gisimo

hi i have just testet the code and now it works.....
i don´t understand what has happened but now i worked!!! so thanks....


----------



## Travelbug

*LED lighting with Arduino PWM controller*

Hello O2Surplus/Sink!

I just stumbled across this forum and your thread on your LED lighting project!
Awesome work guys!! (first post...)

I am amazed because I have been working on a similar system - so similar its scary actually!

I had someone make some circuit boards with CAT4101 chips and 5v regulators with phoenix contact screw connectors to attach to strings of 6 CREE LEDs (XPG/XPE) and a 24v power supply. I bought the LEDs already (108 ) along with my 1 foot slabs of heat sink. The idea is to put 36 LEDs (6x6 array) per slab and control 3 colours (18white/12blue/6violet) independently via PWM from an Arduino and a Chronodot.
I have all the components but haven't put it all together. You guys are way ahead of me, but nearly identical plan!

Would love to see your circuit diagram on the cat4101 to compare to mine as well, your arduino code would save me hours and hours I am sure!!

any chance at getting a peek?

Again - would love to see a pic of the finished product - I plan to document my progress as well and am fine with sharing anything I do/have in terms of hardware/code/ideas.

Martin aka Travelbug.


----------



## O2surplus

Hey TravelBug,

Here are the EAGLE files and a Bill of Materials for a 4 channel version of my CAT4101 driver board led driver. My design includes an Analog current adjustment for each channel of leds and a 12 volt power regulator for cooling fans ect.. Let me know if you need any help with design changes as I can quickly customize it for you if you'd like:icon_smil


----------



## max2012

sink said:


> Certainly possible, though due to storage requirements on the Arduino you'd have to approximate the sunrise/sunset times with an equation rather than hard coding it. Another possible thing would be have moonlights (if using them) follow a lunar cycle and wax and wane accordingly. Cool stuff. That said I'm way too busy to do any of this stuff, but I can help with code issues if anybody wants to try.


Hello everyone, 
I'm new to the forum and I recently used with success* Arduino LED lighting code, *I state that I am not a programmer but, I follow with interest the development of the project and I'd like to contribute.
I found a code (which I tested) that in relation to date returns the correct time for sunrise and sunset.
It would be very nice to try and implement it.
You can find the source code at this link
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292938893/all


----------



## hylik

great code...thanks o2surplus for recomendation....


----------



## sink

Travelbug said:


> Would love to see your circuit diagram on the cat4101 to compare to mine as well, your arduino code would save me hours and hours I am sure!!
> 
> any chance at getting a peek?
> 
> Again - would love to see a pic of the finished product - I plan to document my progress as well and am fine with sharing anything I do/have in terms of hardware/code/ideas.
> 
> Martin aka Travelbug.


I'll borrow a camera and try to take some photos of my setup next week. The wiring doesn't look like much (I'm very much from the "get it done with whatever you have on hand" school of DIY) but I think the design for my hood is a nice balance of cheap, stylish and simple.

I'm sure you found it, but the code can be found at the link in the first post. It needs the 0023 and earlier versions of Arduino due to some library incompatibilities. Fixing that is on my todo list.

On that note I should also point out that I'll happily accept patches if anybody wants to add features/fix bugs/make the code run on arduino 1.0+. Just PM me or use the bitbucket repository in the first post.


----------



## sink

max2012 said:


> Hello everyone,
> I'm new to the forum and I recently used with success* Arduino LED lighting code, *I state that I am not a programmer but, I follow with interest the development of the project and I'd like to contribute.
> I found a code (which I tested) that in relation to date returns the correct time for sunrise and sunset.
> It would be very nice to try and implement it.
> You can find the source code at this link
> http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292938893/all


This is pretty cool. It wouldn't be too hard to implement if there is sufficient interest from people. I think I like having a nice consistent 12hr day in my tank though -- it lets me pretend I don't live in the frozen northern wastes.


----------



## jcgd

Something I have no idea how to add, but would love would be a minimum dimmming setting. Most of my lighting I want to fade all the way off, but is it possible to have a string stop at minimum value to act as the moonlights and then ramp up and down normally with the rest I the strings?


----------



## sink

jcgd said:


> Something I have no idea how to add, but would love would be a minimum dimmming setting. Most of my lighting I want to fade all the way off, but is it possible to have a string stop at minimum value to act as the moonlights and then ramp up and down normally with the rest I the strings?


Ta-daa! This feature is mostly built in already.



Code:


const int kDayState[] = { 600, 400 }; // daytime LED state
const int kNightState[] = { 0, 0 }; // nighttime LED state

Those two lines set the maximum (daytime) and minimum (nighttime) states for the two channels. The possible values for each number range from 0 (off) to 1024 (full power). The first number in each array is for channel one, the second number is for channel two. The default is to have kNightState be {0,0} which turns both channels all off. But you could change that (for example) to {10,0} to have channel one dim to ~1% intensity during nighttime instead of turning off. You'll probably have to experiment with the right number for your setup -- some drivers can't dim below a certain threshold and just cut off entirely rather than dimming.

Note that you can only *control* two channels using my code. If you have four strings and only want one to act as a moonlight, you could connect three of your strings to one channel and the fourth to the second channel and then control them that way.

Does that meet your requirements?


----------



## O2surplus

Sink-

"JCGD" is running 2 of the controllers that I built for him, so he's up against the software limitations that are inherent to the original "Typhon" Firmware. Have you made any progress with modding the original code to make it behave more like your own AKL Tank Control code?


----------



## sink

O2surplus said:


> Sink-
> 
> "JCGD" is running 2 of the controllers that I built for him, so he's up against the software limitations that are inherent to the original "Typhon" Firmware. Have you made any progress with modding the original code to make it behave more like your own AKL Tank Control code?


Ah, my misunderstanding. My comments above apply to my code only.

I stalled on that point because the LCD control code in the Typhon firmware was such a spaghetti mess that to get the good stuff from my code in there would require rewriting everything -- a sizeable task and I'm trying to focus on work that allows me to eat 

That said I still have visions of getting that done at some point.


----------



## sink

I should point out that if people want to run my code on the Typhon, they can, with probably a few very minor modifications that I could help with. There would be some limitations -- the LCD wouldn't be functional and you'd only have two channels to spread out among your strings. But you would get the benefits of much smoother dimming and higher resolution on the LEDs. You'd need an adapter to let you reflash the Arduino to do this, since the Typhon doesn't speak USB.


----------



## O2surplus

sink said:


> Ah, my misunderstanding. My comments above apply to my code only.
> 
> I stalled on that point because the LCD control code in the Typhon firmware was such a spaghetti mess that to get the good stuff from my code in there would require rewriting everything -- a sizeable task and I'm trying to focus on work that allows me to eat
> 
> That said I still have visions of getting that done at some point.


No worries- we all have to make a living! No one wants to hear that "sink" is posting thread replies while living under a highway overpass. We need our software guru well fed and happy.
From what you've seen in the original Typhon firmware, do you think a "Minimum ON state" variable could be added to that code? I'd take a stab at adding it myself - if you think it can be done?


----------



## sink

The problem is that to add it and make it functional for people to use without having to reflash to make changes means not just adding the that minimum state check in the code (which isn't terribly hard), but also adding a new option to the LCD menu, which requires extensive changes to the LCD code (which sucks).


----------



## O2surplus

Hey I've got an Idea! Now that I can buy Atmega's cheap and burn my own boot loaders, do you think we could do a complete re-design of the controller to use Dgital pins #9 & 10 from *multiple ATMEGA chips* using *I2C* or some other clever means? It should be possible? I don't know of hand if we would have to use some sort of master/slave configuration to do it or do it through a rotary encoder switch to address and send commands to multple AVR's? What do you think? If you can dream up the coding, I can build the prototype and we can have a controller that's truly our creation.


----------



## Knut

Hello guys, 

great work! I installed the code on my Arduino Uno (with DS1307) and it works perfect! :biggrin: 
I build a lamp with two strings (? or circuits?), one with warm white and one with cold white LEDs to simulate the sunrise. The lamp is driven by 2 PT4115 constant current regulators with 24V at ~1,1A. So I have round about 50W LED light power!

The only problem is now, how can I switch the 2 PWM outputs separately? For example: ww begins at 8h for 1h and after 45min the cw starts. Now it starts simultaneously.

It is possible to reduce the time for the moonlight? I think 2h (22-0) is enough.

The feature list says it is possible: "Flexible timing logic. You can do anything you want (with minor modifications) so long as it's on a 24hr cycle."

Regards
Knut

PS: Sorry for my bad english, I hope u understand me.


----------



## O2surplus

From what I can tell, by reading the sketch, both channels are governed by the same set of constants. Sink would have to re-write the code to make each channel independent of the other. I'm no expert in code writing but I think it's possible. Sink is the ultimate authority on that Subject though.


----------



## Knut

@Sink: Help me please :icon_bigg

Yes, I think you are right. So I wait for a reply from the master Sink!


----------



## electriccraft1

I have been looking for a solution like this, but was considering rgb. I an new to this, so what ask is required to get a working set up for a 80 gal salt tank ? DIY is not an issue for me as I have done holiday DIY for years now. Please lead me in the right direction as far as parts go. I would like to simulate the correct color temperatures for the full 24 HR cycle. Thank you in advance.


----------



## chuckxx

*Getting it to work on Ver 1 Arduino*

It's not much of a contribution but I'm sure this would save you a lot time rewriting the code.

You mention that this code is pre ver 1.0 Arduino

I have managed to compile it get it working on a Ver 1.01 Arduino UNO Rev3 with changing one Library Time.h

Thanks for the great code hope this helps to the cause.


----------



## O2surplus

chuckxx said:


> It's not much of a contribution but I'm sure this would save you a lot time rewriting the code.
> 
> You mention that this code is pre ver 1.0 Arduino
> 
> I have managed to compile it get it working on a Ver 1.01 Arduino UNO Rev3 with changing one Library Time.h
> 
> Thanks for the great code hope this helps to the cause.



Thanks A Lot! That's a big help for people running Arduino 1.0l


----------



## chuckxx

*Getting it to work with RGB*

Ok I have been at this for a week now, I too was looking at getting my RGB lights running off of this simple but wonderful code.

But looking into it getting it to run on the Uno was the easy part but getting 3 CH timer is an other story entirely and I'm not programer I'm more of a band aid hacker lets say.

Well to explain it shortly the Arduino has 3 Timer, Timer0, Timer1, Timer2,
each one of these timers have 2 CH with a variety feature for each.
It polls an compares the millis() and Freq ch A, B. The timers and says hey you need to Turn on, or off, or Fade, ext.. but each timer has 2 Registers to keep track of the time.

And see this is a great feature and what makes this code great, Is its not taking up all your clock times(CPU) while trying to keep track of the time and do other things.

Like keeping track of Temps, or controlling your 3 speed pump or turing them on and off ect..

I tried to add one of the other timer from pin 11 but I don't have all the programming knowledge to get it to work properly, I mean it was working sort of.

So I'm taking the easy route and using the Arduino Mega 2560 it adds 3 more 16 Bit Timers.

Making it easy to modify the code to work withe RGB lights.
Plus if you really wanted too you could use both Timer1 for your main lights and Timer3 for your complementary RGB Lights.

I am plaining to adding lots more features I just need to mash all this code a have together like setting the time from the LCD Unit it self with 2 Buttons or a rotary encoder, Alarms to tell you its time to do Water changes or clean your filter.

If any one is interested when I get it all done I can post it up.

Cheers! Happy coding..
Oh here's the Timer3 file for the Mega I have it using Pin 5,3,2
And you need to add or change this code.
I'm still trying to debug the Error so if you find one or see something wrong let me know.



Code:


#include <TimerThree.h>
const int kChan0Pin = 5; // Channel 0 Pin
const int kChan1Pin = 2; // Channel 1 Pin
const int kChan2Pin = 3; // Channel 2 Pin




Code:


const int kDayState[] = { 1023, 1023, 1023 }; // daytime LED state
const int kNightState[] = { 0, 0, 0 }; // nighttime LED state




Code:


int state_chan1, state_chan2, state_chan3;




Code:


void fader(long start_time, const int start_state[], const int end_state[], int out[3]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;
  float per_second_delta_2 = (float) (end_state[2]-start_state[2])/kFadeDuration;
  
  long elapsed = ctr-start_time; // Calculate the elapsed Time

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
  out[2] = start_state[2] + per_second_delta_2 * elapsed;
}




Code:


void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) {
    Timer3.setPwmDuty(kChan0Pin, state[0]);
    state_chan1 = state[0]; }
  if (state[1] >= 0 && state[1] <= 1023) {
    Timer3.setPwmDuty(kChan1Pin, state[1]);
    state_chan2 = state[1]; }
  if (state[2] >= 0 && state[2] <= 1023) {
    Timer3.setPwmDuty(kChan2Pin, state[2]);
    state_chan3 = state[2]; }
}


----------



## scapegoat

so uh... does anyone want to put together a shopping list via amazon.com? 

I'd love to get started on this to eventually control the lights and co2 of a 125g. I've heard of the arduino and knew it was being used for fun stuff like this. I'm a web developer by trade, so this hardware stuff is quite confusing to me, but i can definitely dig into the code.


----------



## mistergreen

scapegoat said:


> so uh... does anyone want to put together a shopping list via amazon.com?
> 
> I'd love to get started on this to eventually control the lights and co2 of a 125g. I've heard of the arduino and knew it was being used for fun stuff like this. I'm a web developer by trade, so this hardware stuff is quite confusing to me, but i can definitely dig into the code.


If you're new to arduino, I suggest playing with simple stuff first like making LED blink and such just to get yourself acquainted. Buy a starter kit like here

https://www.sparkfun.com/products/11226

It's too much and confusing if you jump right in.
If you want to get acquainted with the coding check here
http://aquatictechtank.net/viewtopic.php?f=37&t=8&sid=49595bf92ab9b6fd90bbdb9b12409943


----------



## scapegoat

mistergreen said:


> If you're new to arduino, I suggest playing with simple stuff first like making LED blink and such just to get yourself acquainted. Buy a starter kit like here
> 
> https://www.sparkfun.com/products/11226
> 
> It's too much and confusing if you jump right in.
> If you want to get acquainted with the coding check here
> http://aquatictechtank.net/viewtopic.php?f=37&t=8&sid=49595bf92ab9b6fd90bbdb9b12409943


jumping in is half the fun. I'm not concerned about programming the thing as I've got experience with scripting languages. More so concerned about selecting the right items to get it working. I'd love to have one control the timing of everything, ferts, food, lights, co2, etc.


----------



## Gisimo

Hi all i was wondering if it is possible to implement auto daylight savings time so it automatic change the time?!


----------



## Gisimo

I need help understanding how an n-fet works i have chosen one ( irf520) it can handel alot of power about 10 amp or so, but why is it getting so hot when it is only handling a load of 1.0 amp?
I have mounted it on a large heat sink because i want to make a salt water one day and i may then nead 6amp pr. Channel!!
But how hot vil it be at that load ?

Is it becurse i have a resistor betwin Arduino pin 9 and gaten on the fet so it dosent open totely?? Is it nessasery with a resistor?


----------



## mistergreen

Gisimo said:


> Hi all i was wondering if it is possible to implement auto daylight savings time so it automatic change the time?!


You have to write code for this but the time change date is arbitrary based on the government. It's easier just to change the time manually.




Gisimo said:


> I need help understanding how an n-fet works i have chosen one ( irf520) it can handel alot of power about 10 amp or so, but why is it getting so hot when it is only handling a load of 1.0 amp?
> I have mounted it on a large heat sink because i want to make a salt water one day and i may then nead 6amp pr. Channel!!
> But how hot vil it be at that load ?


It's natural for components with large amps to get warm/hot but not boiling hot. Check your circuit for shorts if it gets really hot and the circuit is broken.


----------



## Gisimo

Thank you!! Every thing works fine i just wondered why it gets hot when it is that little current!!! Is the fet getting hotter if the voltage on the gate is lover than 4.8 volts? Is it necessary to have a resistor in front of the gate?? (Between pin 9 and gate)


----------



## mistergreen

Gisimo said:


> Is it necessary to have a resistor in front of the gate?? (Between pin 9 and gate)


I usually do put resistor in front of the gate but it depends on the transistor's spec.

The wattage is what makes a component hot or not. Use the correct wattage rated component.

P = V*I

watts = volt * current


----------



## Gisimo

The IRF520 has a max power dissipation at 60w and i have only 10 watt pr channel it is the reason i am concerned that it is hot not much but 45 degrees celsius!!
The IRF520 Has a gate threshold voltage at 4 volts max and the arduino put out 4,8 voltage so i need a resistor between arduino and gate which is 10 ohm or am i wrong ????


----------



## mistergreen

45 C isn't too bad. It's not boiling hot.

R = V/I
5 = (5-4) / .2 ?

5 ohm seems to be it but 10 ohm should work too.


----------



## sink

Gisimo said:


> Hi all i was wondering if it is possible to implement auto daylight savings time so it automatic change the time?!


I know I haven't been around much, but I'm thrilled to see people are still using the code!

The main reason there is no auto-daylight savings code is that a library to do that (if a clean one even exists for the Arduino) would take up too much amount of the limited space available on the unit. Given how easy it is to just update the time twice a year I figured it wasn't worth it.


----------



## Gisimo

Thank you for your help !!


----------



## O2surplus

sink said:


> I know I haven't been around much, but I'm thrilled to see people are still using the code!


Hey Sink! Glad to see that you're still around. I'd been wondering where you'd disappeared too?


----------



## sink

Hi buddy. I hope you're well 
Work, mostly, with the woods being a close second. Also my tank is well established and the lighting setup Just Works so I haven't spent a lot of time thinking about the internals.


----------



## Gisimo

Hey sink would it be possible to make 3 channels instead of two??
I have one blue light and i would like to use it as a moon light !!
And i alreaddy use the two channels !!


----------



## sink

That has been a common request. I may end up adding a binary (just off or 5V) moonlight output eventually, but I am hesitant to add too much complexity. In many ways, the code is already more complex than I want it to be -- the plan was to have a barebones lighting system that was simple enough behind the scenes that by looking at it, reasonably techie people could see how to add their own things (CO2 control, temp, etc) where needed.

In any case, if I had a single moonlight I would just rig it to be on all of the time. Much easier and you won't notice it on during the day anyway with the normal lighting active.


----------



## Gisimo

Ok tanks sink!!


----------



## shrimper23

Hey Sink, so i'm really liking the look of your code and would like to use it on my new pico reef. However, I need 6 channels to control the fixture. How would i go about adding 4 more outputs? It seems to me i'd need to add the libraies for the other 2 timers, but will using different timers effect my dimming between channel's? I'm still very new to arduino, (this is my very first project) so i would very much appreciate your help. Thanks!


----------



## sink

shrimper23 said:


> Hey Sink, so i'm really liking the look of your code and would like to use it on my new pico reef. However, I need 6 channels to control the fixture. How would i go about adding 4 more outputs? It seems to me i'd need to add the libraies for the other 2 timers, but will using different timers effect my dimming between channel's? I'm still very new to arduino, (this is my very first project) so i would very much appreciate your help. Thanks!


The TimerOne library is only there to provide high-resolution output -- if coarser control is fine for your other channels you don't need libraries for them. Dimming for other channels would be the same, except your range would only be 8 bits (0-255) so you'd have to figure the math for that out in the code. As far as how the timers interrelate to each other...I'm not positive  It probably varies by device, but Google should be able to provide an answer there. It may be that you are limited to how many PWM outputs you can sent at once using the HW timers.

For making the changes to the code, you'd just basically duplicate what I've done for the two channels for the other four, creating appropriate variables and adding lines where needed in the dimming code etc. It's not that bad.


----------



## shrimper23

So if I added the libraries would I achieve higher resolution outputs on the other 4? What is the resolution of the outputs as the code stands? Could I perhaps add an I2C pwm breakout to my contoller such as this one? http://adafruit.com/products/815
I'd like to retain the higher resolution on all channels if possible. Also, I am using meanwell LDD-L's to drive my LED's if it makes any difference.


----------



## sink

shrimper23 said:


> So if I added the libraries would I achieve higher resolution outputs on the other 4?


Theoretically, but it is awkward. For example, messing with the settings for Timer0 will affect built in functions like delay() and millis() because they get their timing from it under the hood. There might be libraries to compensate for this, but I haven't really looked.


> What is the resolution of the outputs as the code stands?


Normally Arduino PWM outputs are 8 bits. The TimerOne library allows 10 bits resolution on its two outputs.


> Could I perhaps add an I2C pwm breakout to my contoller such as this one?


That thing looks sweet! 16 independent outputs with 12 bits of resolution. You'd have to make some changes to the code to use it, but ultimately with 6 (or more) outputs the code would be simpler using something like that. Plus you wouldn't have to deal with the libraries. Do note that at some point the limiting factor for how precisely you can set light level will be the driver itself (and how it interprets the PWM signal) and not the resolution of the PWM output itself.



> I'd like to retain the higher resolution on all channels if possible. Also, I am using meanwell LDD-L's to drive my LED's if it makes any difference.


The driver does certainly make a difference, but I couldn't speak as to how well the PWM control is for that driver. The control on some drivers is quite nonlinear at the low end (< 10% of light output) and can be inconsistent for fast PWM signals.


----------



## shrimper23

Sounds like I need to order that breakout! I already have 2 slave devices on my I2C, I would think adding this would be alright, correct me if I'm wrong. These are the current devices:
http://www.adafruit.com/products/264
http://www.adafruit.com/product/772
Better yet, I can now get full control on the refugium lights as well! 7 channels over a 4 gallon, gotta love DIY!

I was originally planning on the CAT's, then I got talking to a customer while testing his water. He peaked my interest when he told me about the LDD's. Then brought me 2 of the PCB's he had for them as a Christmas gift! From what I've read they have the best of dimming accuracy so I don't think it should be an issue.


----------



## shrimper23

Any idea on the I2C capability guys?  Also, Sink, a quick question on your code, I see you name the channels with a "k". Such as kChan0Pin, is there a reason for this? Just wondering as I haven't seen this before.


----------



## sink

shrimper23 said:


> Any idea on the I2C capability guys? Also, Sink, a quick question on your code, I see you name the channels with a "k". Such as kChan0Pin, is there a reason for this? Just wondering as I haven't seen this before.


It is a convention in C to name constants starting with a lowercase k. It helps distinguish later on things that should be constant from things that can be safely reassigned. It is not a requirement though, merely a suggested style.

I would think you will have no issues with multiple devices on I2C.

Cheers.


----------



## willflyfood

Sink I am driving my self nuts here.... what pins did you use for the RTC?


----------



## willflyfood

*Pins*

I am using pin 4 and 5 but when I run the serial monitor I see nothing...


----------



## sink

willflyfood said:


> Sink I am driving my self nuts here.... what pins did you use for the RTC?


Sorry for the delay in replying!

The RTC communicates over I2C, so you just use whatever pins those are on your board. On the Duemilanove that I have those are A4 and A5. It might be different on the Uno. There isn't anything special about my code in this respect, you hook up I2C the same way you would for any Arduino device. For just one I2C device (the RTC) you'd connect the SDA on the RTC to the SDA on the Arduino, and same for the SCL ports.


----------



## sink

willflyfood said:


> I am using pin 4 and 5 but when I run the serial monitor I see nothing...


The serial doesn't really send anything unless you "talk" to it with the client.py script I supplied in the code.

If you run the client.py script and enter "time" at the prompt, you get no response? Is there an error?


----------



## HunterX

Hello everyone. I want to thank you all for taking the time to put this information on the forum. I do have a question. Has anyone used the arduino to control LED fixtures made by build my led.com? From what I understand, they are built with LED Drivers built into the fixture. Further more, they can ship with a prefab APEX dimming cable. It appears to be a standard RJ45 connection on the end that would plug into the controller. Would it be possible do use the Arduino with that setup to control the LEDs? if so what would I need? 

Thank you in advance for your response.


----------



## O2surplus

HunterX said:


> Hello everyone. I want to thank you all for taking the time to put this information on the forum. I do have a question. Has anyone used the arduino to control LED fixtures made by build my led.com? From what I understand, they are built with LED Drivers built into the fixture. Further more, they can ship with a prefab APEX dimming cable. It appears to be a standard RJ45 connection on the end that would plug into the controller. Would it be possible do use the Arduino with that setup to control the LEDs? if so what would I need?
> 
> Thank you in advance for your response.



The Apex controller outputs a 0-10V analog signal to dim the leds. So chances are good that the dimmable drivers in the BuildMyLed fixture are designed to accept that type of dimming control signal. The Arduino outputs a 5V PWM signal, so it won't be directly compatible with the drivers in the BML fixture.
If you have your heart set on using the arduino as your controller, just purchase LED drivers that accept a 5V PWM signal directly, and you'll be set.Checkout the Meanwell LDD-L & LDD-H series of drivers. They will work well for your application, and they're cheap too. Here's a link-LDD-1000H | Mean-Well LDD-1000H | USA Warehouse


----------



## HunterX

O2surplus said:


> The Apex controller outputs a 0-10V analog signal to dim the leds. So chances are good that the dimmable drivers in the BuildMyLed fixture are designed to accept that type of dimming control signal. The Arduino outputs a 5V PWM signal, so it won't be directly compatible with the drivers in the BML fixture.
> If you have your heart set on using the arduino as your controller, just purchase LED drivers that accept a 5V PWM signal directly, and you'll be set.Checkout the Meanwell LDD-L & LDD-H series of drivers. They will work well for your application, and they're cheap too. Here's a link-LDD-1000H | Mean-Well LDD-1000H | USA Warehouse


Thanks for your reply. I'm sending you a PM.


----------



## estill

To address the 0-10V "signal", could you use the Arduino PWM output to control a transistor or MOSFET? I know you can do this to drive a DC motor, and it will fool most multimeters into seeing a lower voltage.


----------



## Gisimo

Hello everyone i am considering to make a new light for at nano tank and i was wondering if i could use a Arduino Micro or mini instead of an uno ??


----------



## shrimper23

*I2C freezing*

Hey Sink, wanted to see if you might be able to advise me on my project here. I have your code working beautifully with the Adafruit 16-channel 12-bit pwm driver. However, after integrating it into my full control code i'm having an issue. The code will perform as expected right up to the dimming stage, when it hits my LCD goes blank, LED's flash, and the whole I2C bus stops dead. It seems to me I may have to much going on with the I2C. I'm using an UNO R3 with a DS1307, the Adafruit PWM controller, and their I2C 16x2 LCD on the bus. Please let me know if you have any idea how I might fix this issue. Thank you.


#include <Wire.h>
#include "RTClib.h"
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <Adafruit_PWMServoDriver.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

#define OFF 0x0
#define WHITE 0x7
#define rxpin 3
#define txpin 2

RTC_DS1307 RTC;
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

const long kTurnOn = 39000; // 37800time dawn begins - 0900hrs
const long kTurnOff = 59000; // 70200 time sunset begins - 2100hrs
const int kDayState[] = { 3000, 4000, 4000, 4000, 0, 0, 2000, 3000 }; // daytime LED state
const int kNightState[] = { 0, 4, 45, 4, 2000, 0, 0, 4 }; // nighttime LED stat
const long kFadeDuration = 0;
long ctr;
int state_chan1, state_chan2, state_chan3, state_chan4, state_chan5, state_chan6, state_chan7, state_chan8;

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
SoftwareSerial myserial(rxpin, txpin);
int DS18S20_Pin = 4;
OneWire ds(DS18S20_Pin);

int floatstate = 0;

long phReadInterval = 10000;
long previousMillisPH = 0;
int PHState = HIGH;
float PH_Val;

void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;
float per_second_delta_2 = (float) (end_state[2]-start_state[2])/kFadeDuration;
float per_second_delta_3 = (float) (end_state[3]-start_state[3])/kFadeDuration;
float per_second_delta_4 = (float) (end_state[4]-start_state[4])/kFadeDuration;
float per_second_delta_5 = (float) (end_state[5]-start_state[5])/kFadeDuration;
float per_second_delta_6 = (float) (end_state[6]-start_state[6])/kFadeDuration;
float per_second_delta_7 = (float) (end_state[7]-start_state[7])/kFadeDuration;

long elapsed = ctr-start_time;

out[0] = start_state[0] + per_second_delta_0 * elapsed;
out[1] = start_state[1] + per_second_delta_1 * elapsed;
out[2] = start_state[2] + per_second_delta_2 * elapsed;
out[3] = start_state[3] + per_second_delta_3 * elapsed;
out[4] = start_state[4] + per_second_delta_4 * elapsed;
out[5] = start_state[5] + per_second_delta_5 * elapsed;
out[6] = start_state[6] + per_second_delta_6 * elapsed;
out[7] = start_state[7] + per_second_delta_7 * elapsed;
}

long seconds_since_midnight() {
DateTime now = RTC.now();
long hr = now.hour();
long min = now.minute();
long sec = now.second();
long total = hr * 3600 + min * 60 + sec;
return total;
}

void set_state(const int state[]) {
if (state[0] >= 0 && state[0] <= 4096) {
pwm.setPWM(0, 0, state[0]);
state_chan1 = state[0]; }
if (state[1] >= 0 && state[1] <= 4096) {
pwm.setPWM(1, 0, state[1]);
state_chan2 = state[1]; }
if (state[2] >= 0 && state[2] <= 4096) {
pwm.setPWM(2, 0, state[2]);
state_chan3 = state[2]; }
if (state[3] >= 0 && state[3] <= 4096) {
pwm.setPWM(3, 0, state[3]);
state_chan4 = state[3]; }
if (state[4] >= 0 && state[4] <= 4096) {
pwm.setPWM(4, 0, state[4]);
state_chan5 = state[4]; }
if (state[5] >= 0 && state[5] <= 4096) {
pwm.setPWM(5, 0, state[5]);
state_chan6 = state[5]; }
if (state[6] >= 0 && state[6] <= 4096) {
pwm.setPWM(6, 0, state[6]);
state_chan7 = state[6]; }
if (state[7] >= 0 && state[7] <= 4096) {
pwm.setPWM(7, 0, state[7]);
state_chan8 = state[7]; }
}

void determine_state() {
if ( ctr >= 0 && ctr < kTurnOn ) { // night
set_state(kNightState);
} else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
int foo[2];
fader(kTurnOn, kNightState, kDayState, foo);
set_state(foo);
} else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
set_state(kDayState);
} else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
int foo[2];
fader(kTurnOff, kDayState, kNightState, foo);
set_state(foo);
} else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
set_state(kNightState);
}
}

float getTemp(){
//returns the temperature from one DS18S20 in DEG Celsius

byte data[12];
byte addr[8];

if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}

if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return -1000;
}

if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print("Device is not recognized");
return -1000;
}

ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end

byte present = ds.reset();
ds.select(addr); 
ds.write(0xBE); // Read Scratchpad


for (int i = 0; i < 9; i++) { // we need 9 bytes
data_ = ds.read();
}

ds.reset_search();

byte MSB = data[1];
byte LSB = data[0];

float tempRead = ((MSB << 8) | LSB); //using two's compliment
float TemperatureSum = tempRead / 16;

return TemperatureSum;

}

void getPHvalue(){
unsigned long currentMillisPH = millis();

if(currentMillisPH - previousMillisPH > phReadInterval){
previousMillisPH = currentMillisPH;
if(PHState == HIGH){
PHState = LOW;
}
else {
PHState = HIGH;
myserial.print("r\r");
while(myserial.available() > 0){
PH_Val = myserial.parseFloat();
if(myserial.read() == '\r');
}
}
}
}

void setup() {
myserial.begin(38400);
RTC.begin();
lcd.begin(16,2);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, INPUT);
pwm.begin();
pwm.setPWMFreq(800);
ctr = seconds_since_midnight();
Serial.print(ctr);
}

void loop(){
ctr = seconds_since_midnight();
determine_state();
floatstate = digitalRead(7);
if (floatstate == HIGH) {
digitalWrite(6, HIGH);
delay(10000);
digitalWrite(6, LOW);
}
else {
digitalWrite(6, LOW);
}

if ( ctr >= 0 && ctr < 26000 ) {
lcd.setBacklight(OFF);
} if ( ctr >= 0 && ctr < kTurnOn ) {
digitalWrite(5, LOW);
} else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ){
lcd.setBacklight(OFF);
digitalWrite(5, LOW);
}
else {
lcd.setBacklight(WHITE);
digitalWrite(5, HIGH);
}


DateTime now = RTC.now();
lcd.setCursor(0, 1);
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);

getPHvalue();
lcd.setCursor(0,0);
lcd.print("PH:");
lcd.print(PH_Val);

float temperature = getTemp();
lcd.setCursor(8,0);
lcd.print(temperature);
lcd.print("C");

delay(5000); //just here to slow down the output so it is easier to read

}

My apologies for the post length._


----------



## Pady

Hello all of you
First of all I would like to say big thanks to Sink and O2surplus and all you other guys 
You all helped me getting started with my LED controller Arduino.
I'll have to read it all again to understand how it really works...
I need to fix up 4 channels with different 100% brightness and sunrise/down and moon light. Also putting in and reading everything to my laptop.


----------



## TomLS

Hi all,

I have been avidly reading this thread, and having no experience of Arduino before this (but a little experience with the Pi, Python, and Linux) I am having some problems.
Firstly, I know this code doesn't compile well with IDE v1.X+, but it seems to have exactly the same problems when I attempt compiling on IDE 0022 on another machine.
For this reason, I am attempting to get it to compile on v1.0.1 for linux, in the hope that I can give something back to the community when I finally have it working!

I have already been through the issues with the time library compatibility, and fixed the libraries on my machine, but I'm now having trouble with DS1307RTC libraries, and the errors mean nothing to me, so I'm hoping someone may be able to help.

It's also worth noting that my original aim was to use this code to take advantage of 4 PWM channels on the arduino, but due to a change in design of my lighting rig, I now only need 3 channels. I have left the fourth channel code in place, but have remmed it out to save myself work if I add extra strings in the future.

My modified version of the code is:



Code:


/*
 * Name:	tank_control.pde
 * Author:	User "sink" at plantedtank.net forums
 * URL:		http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS3231RTC.
 * A bundle of the required libraries (except for Wire, which you should
 * already have) is located in the downloads section of the URL above.  You can
 * always find the latest copy of the code at that location.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */

#include <Wire.h>
//#include <RTClib.h>
#include <TimerOne.h>
#include <Time.h>
#include <DS1307RTC.h>
//#include <DS3231RTC.h>

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin
const int kChan1Pin = 10; // Channel 1 Pin
const int kChan2Pin = 11; // Channel 2 Pin
//const int kChan3Pin = 6; // Channel 3 Pin

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 600, 800, 800/*, 600*/ }; // daytime LED state
const int kNightState[] = { 0, 0/*, 0*/, 100 }; // nighttime LED state

/*
 * Duration (in seconds) of fade.  At the moment the only fades are sunrise and
 * sunset but this value will apply to any other fades you came up with
 */
const long kFadeDuration = 7200; // 2 hrs

long ctr;

/* hold state info */
int state_chan1, state_chan2, state_chan3/*, state_chan4*/;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;
  
  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) {
    Timer1.setPwmDuty(kChan0Pin, state[0]);
    state_chan1 = state[0]; }
  if (state[1] >= 0 && state[1] <= 1023) {
    Timer1.setPwmDuty(kChan1Pin, state[1]);
    state_chan2 = state[1]; }
  if (state[2] >= 0 && state[2] <= 1023) {
    Timer1.setPwmDuty(kChan2Pin, state[2]);
    state_chan3 = state[2]; }
  /*if (state[3] >= 0 && state[3] <= 1023) {
    Timer1.setPwmDuty(kChan3Pin, state[1]);
    state_chan4 = state[3]; }*/
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}

void setup() {
  Serial.begin(115200); // Max for Arduino Uno
  setSyncProvider(RTC.get);
  Timer1.initialize(6666); // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(kChan2Pin, OUTPUT);     
  Timer1.pwm(kChan2Pin, 0);
/*  pinMode(kChan3Pin, OUTPUT);     
  Timer1.pwm(kChan3Pin, 0);*/
}

void loop () {
  ctr = seconds_since_midnight();
  determine_state();

  if (Serial.available() >= 5) {
    char data[4];
    for (int i=0; i<5; i++) {
      data[i] = Serial.read();
    }

    Serial.flush(); // ensure we never have more than 5 bytes buffered

    if (data[0] == 'A') { // send current time
      time_t longInt = now();
      unsigned char byteArray[4];
                
      // convert from an unsigned long int to a 4-byte array
      byteArray[0] = (int)((longInt >> 24) & 0xFF);
      byteArray[1] = (int)((longInt >> 16) & 0xFF);
      byteArray[2] = (int)((longInt >> 8) & 0XFF);
      byteArray[3] = (int)((longInt & 0XFF));
      // send time
      Serial.print("Z");
      Serial.print(byteArray[0]);
      Serial.print(byteArray[1]);
      Serial.print(byteArray[2]);
      Serial.print(byteArray[3]);
    }
    else if (data[0] == 'B') { // set time
      union u_tag {
        byte b[4];
        unsigned long ulval;
      } u;

      u.b[0] = data[4];
      u.b[1] = data[3];
      u.b[2] = data[2];
      u.b[3] = data[1];

      RTC.set(u.ulval);
      setTime(u.ulval);
      Serial.print("Z0000");
    }
    else {
      Serial.print("X0000");
    }
  }

 delay(250);


  Serial.print("ctr: ");
  Serial.print(ctr); // display counter
  Serial.println(); 
  Serial.print("channel 1, 2: "); 
  Serial.print(state_chan1); 
  Serial.print(", "); 
  Serial.print(state_chan2); 
  Serial.println(); 
  digitalClockDisplay(); //display time
  Serial.println(); 

}


And the resultant errors are:



Code:


/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp: In static member function ‘static time_t DS1307RTC::get()’:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:39:19: error: invalid operands of types ‘void’ and ‘bool’ to binary ‘operator==’
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp: At global scope:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:54:6: error: prototype for ‘bool DS1307RTC::read(tmElements_t&)’ does not match any in class ‘DS1307RTC’
In file included from /home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:26:0:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.h:19:14: error: candidate is: static void DS1307RTC::read(tmElements_t&)
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:95:6: error: prototype for ‘bool DS1307RTC::write(tmElements_t&)’ does not match any in class ‘DS1307RTC’
In file included from /home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:26:0:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.h:20:14: error: candidate is: static void DS1307RTC::write(tmElements_t&)
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:139:17: error: variable or field ‘exists’ declared void


Any help anyone can give me would be greatly appreciated.

I have also purchased a 20x4 LCD display that I hope to use to display PWM value for each channel, and water, heatsink, and air temperatures using the DS18B20 chip. But for now... baby steps!!

Many thanks,
Tom.


----------



## TomLS

Oh, and its probably worth noting that I'm using the Nano V3 ATMega328 board, but from what I can tell it's functionally identical to the uno...

This is related to a post which is still apparently being moderated!...


----------



## TomLS

Hi Sink et al.,

I have been avidly reading this thread, and having no experience of Arduino before this (but a little experience with the Pi, Python, and Linux) I am having some problems.
Firstly, I know this code doesn't compile well with IDE v1.X+, but it seems to have exactly the same problems when I attempt compiling on IDE 0022 on another machine.
For this reason, I am attempting to get it to compile on v1.0.1 for linux, in the hope that I can give something back to the community when I finally have it working!

I have already been through the issues with the time library compatibility, and fixed the libraries on my machine, but I'm now having trouble with DS1307RTC libraries, and the errors mean nothing to me, so I'm hoping someone may be able to help.

It's also worth noting that my original aim was to use this code to take advantage of 4 PWM channels on the arduino, but due to a change in design of my lighting rig, I now only need 3 channels. I have left the fourth channel code in place, but have remmed it out to save myself work if I add extra strings in the future.

My modified version of the code is:



Code:


/*
 * Name:	tank_control.pde
 * Author:	User "sink" at plantedtank.net forums
 * URL:		http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS3231RTC.
 * A bundle of the required libraries (except for Wire, which you should
 * already have) is located in the downloads section of the URL above.  You can
 * always find the latest copy of the code at that location.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */

#include <Wire.h>
//#include <RTClib.h>
#include <TimerOne.h>
#include <Time.h>
#include <DS1307RTC.h>
//#include <DS3231RTC.h>

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin
const int kChan1Pin = 10; // Channel 1 Pin
const int kChan2Pin = 11; // Channel 2 Pin
//const int kChan3Pin = 6; // Channel 3 Pin

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 600, 800, 800/*, 600*/ }; // daytime LED state
const int kNightState[] = { 0, 0/*, 0*/, 100 }; // nighttime LED state

/*
 * Duration (in seconds) of fade.  At the moment the only fades are sunrise and
 * sunset but this value will apply to any other fades you came up with
 */
const long kFadeDuration = 7200; // 2 hrs

long ctr;

/* hold state info */
int state_chan1, state_chan2, state_chan3/*, state_chan4*/;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;
  
  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) {
    Timer1.setPwmDuty(kChan0Pin, state[0]);
    state_chan1 = state[0]; }
  if (state[1] >= 0 && state[1] <= 1023) {
    Timer1.setPwmDuty(kChan1Pin, state[1]);
    state_chan2 = state[1]; }
  if (state[2] >= 0 && state[2] <= 1023) {
    Timer1.setPwmDuty(kChan2Pin, state[2]);
    state_chan3 = state[2]; }
  /*if (state[3] >= 0 && state[3] <= 1023) {
    Timer1.setPwmDuty(kChan3Pin, state[1]);
    state_chan4 = state[3]; }*/
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}

void setup() {
  Serial.begin(115200); // Max for Arduino Uno
  setSyncProvider(RTC.get);
  Timer1.initialize(6666); // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(kChan2Pin, OUTPUT);     
  Timer1.pwm(kChan2Pin, 0);
/*  pinMode(kChan3Pin, OUTPUT);     
  Timer1.pwm(kChan3Pin, 0);*/
}

void loop () {
  ctr = seconds_since_midnight();
  determine_state();

  if (Serial.available() >= 5) {
    char data[4];
    for (int i=0; i<5; i++) {
      data[i] = Serial.read();
    }

    Serial.flush(); // ensure we never have more than 5 bytes buffered

    if (data[0] == 'A') { // send current time
      time_t longInt = now();
      unsigned char byteArray[4];
                
      // convert from an unsigned long int to a 4-byte array
      byteArray[0] = (int)((longInt >> 24) & 0xFF);
      byteArray[1] = (int)((longInt >> 16) & 0xFF);
      byteArray[2] = (int)((longInt >> 8) & 0XFF);
      byteArray[3] = (int)((longInt & 0XFF));
      // send time
      Serial.print("Z");
      Serial.print(byteArray[0]);
      Serial.print(byteArray[1]);
      Serial.print(byteArray[2]);
      Serial.print(byteArray[3]);
    }
    else if (data[0] == 'B') { // set time
      union u_tag {
        byte b[4];
        unsigned long ulval;
      } u;

      u.b[0] = data[4];
      u.b[1] = data[3];
      u.b[2] = data[2];
      u.b[3] = data[1];

      RTC.set(u.ulval);
      setTime(u.ulval);
      Serial.print("Z0000");
    }
    else {
      Serial.print("X0000");
    }
  }

 delay(250);


  Serial.print("ctr: ");
  Serial.print(ctr); // display counter
  Serial.println(); 
  Serial.print("channel 1, 2: "); 
  Serial.print(state_chan1); 
  Serial.print(", "); 
  Serial.print(state_chan2); 
  Serial.println(); 
  digitalClockDisplay(); //display time
  Serial.println(); 

}


And the resultant errors are:

/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp: In static member function ‘static time_t DS1307RTC::get()’:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:39:19: error: invalid operands of types ‘void’ and ‘bool’ to binary ‘operator==’
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp: At global scope:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:54:6: error: prototype for ‘bool DS1307RTC::read(tmElements_t&)’ does not match any in class ‘DS1307RTC’
In file included from /home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:26:0:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.h:19:14: error: candidate is: static void DS1307RTC::read(tmElements_t&)
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:95:6: error: prototype for ‘bool DS1307RTC::write(tmElements_t&)’ does not match any in class ‘DS1307RTC’
In file included from /home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:26:0:
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.h:20:14: error: candidate is: static void DS1307RTC::write(tmElements_t&)
/home/tom/sketchbook/libraries/DS1307RTC/DS1307RTC.cpp:139:17: error: variable or field ‘exists’ declared void


Any help anyone can give me would be greatly appreciated.

I have also purchased a 20x4 LCD display that I hope to use to display PWM value for each channel, and water, heatsink, and air temperatures using the DS18B20 chip. But for now... baby steps!!

Many thanks,
Tom.


----------



## TomLS

Okay, I have tried to make a long post on here twice now, regarding questions about the code, but apparently it still remains in moderation. How long does this usually take?!

In the meantime I have made some achievements based on this code, which I would like to give back to the community. 
1) modified the libraries to make it fully compatible with IDE 1.0,
2) added temperature probe support,
3) added i2c LCD support,
4) split out the code to allow for different start times and durations for the fade of each channel.

I will attempt to post this up here in the next couple of days!


----------



## O2surplus

Hey everyone-

I'm no coding genius like "Sink" but I did manage to make his code compatible with Arduino 1.05 and add some new features. I've been using this version of the code to control the lighting on my tank fo a little over a week and it works great.

Note: If you already have the original Arduino 23 version of this code and want to upgrade to this one you'll need to update your libraries first and compile the code using Arduino 1.0. Updating the libraries is easy. Open each Library header file (.h) and add the following line of code to the beginning of the "define section".



Code:


#if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h"#endif

Here's what I added-

1.) I2C LCD supported. Time/Date/Temp/Dimming mode & fan control status are all displayed on the LCD.
2.) Dallas Temp support- Dallas OneWire DS18B20 Temp sensors are auto detected and the temperature is displayed to the LCD.
3.)Cooling fan control logic added in- Digital Pin#8 Turns on/off in accordance with the Led state.

Here's a photo of the Lcd -









Here's the modified code-


Code:


/*
 * Name:    tank-control.pde
 * Author:    User "sink" at plantedtank.net forums
 * URL:        http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS1307RTC
 *
 * The latest version of this code can always be found at above url.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */
/* NOTICE: 4/2/2014- Addtional support for I2C LCD & Dallas OneWire Temperature readout added by O2Surplus.
              The original Libraries used in this version of the code were updated for use with Arduino 1.5-r2.
              Please make sure to use the proper version of said libraries. */
              
#include <TimerOne.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <OneWire.h> // added to original code by O2Surplus 4/2/2014
#include <LiquidCrystal_I2C.h>// added to original code by O2Surplus 4/2/2014

//LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//Temperature chip i/o
int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2

OneWire ds(DS18S20_Pin);  // on digital pin 2

int fanEnable = 8;// assigns cooling fan ON/OFF control to digital pin 8.

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin
const int kChan1Pin = 10; // Channel 1 Pin

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 1023,1023 }; // daytime LED state
const int kNightState[] = { 0, 0 }; // nighttime LED state

// duration (in seconds) of sunrise/sunset fade
const long kFadeDuration = 3600; // 60 minutes

long ctr;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;

  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) Timer1.setPwmDuty(kChan0Pin, state[0]);
  if (state[1] >= 0 && state[1] <= 1023) Timer1.setPwmDuty(kChan1Pin, state[1]);
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE");         // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
      
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(3,2);
      lcd.print("SUNRISE/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);             
      lcd.print("DAY/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("SUNSET/MODE");              // LCD coding added by O2Surplus 4/2/2014
      //lcd.setCursor(11,2);
      //lcd.print("  ");
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE");          // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
 
}
void displayDigits(int digits) {
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
  
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}
void lcdClockDisplay() {
  lcd.setCursor(0,0);
  lcd.print(hour());
  displayDigits(minute());
  displayDigits(second());
  lcd.print("  ");
  lcd.print(month());
  lcd.print("/");
  lcd.print(day());
  lcd.print("/");
  lcd.print(year()); 
   
}
void setup() {
  Serial.begin(115200); // Max for Arduino Uno
  setSyncProvider(RTC.get);
  setSyncInterval(120);
  Wire.begin();
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines and turn on backlight
  Timer1.initialize(6666); // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(fanEnable,OUTPUT);   // Fan control coding added by O2Surplus 4/2/2014
}

void loop () {
  float temperature = getTemp();// Temperature serial display coding addded by O2Suplus 4/2/2014
  Serial.println(temperature);
  ctr = seconds_since_midnight();// Original code
 
  lcd.setCursor(0,1);          // Temperature to I2C LCD added by O2Surplus 4/2/2014
  lcd.print("Temp C = ");
  lcd.print(temperature);
 
  determine_state();// Original code
  Serial.print("ctr: ");
  Serial.print(ctr); // display counter
  Serial.println();
  digitalClockDisplay(); //display time
  Serial.println();
  lcd.setCursor(0,0); //Time/Date to I2C display added 4/2/2014 by O2Surplus
  lcd.println();
  lcdClockDisplay();
 
   

  
  delay(1000); // no need to do anything until next second
}// Original Code ends here.


float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius // Added by O2Suplus 4/2/2014

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
  
}


----------



## Guy.hall

This is spot on and I will be using this on mine as soon as there is water in it... On the workbench I couldnt even tell it was dimming it is that smooth. I have just got the 20x4 lcd to match it so hopefully can put ph etc on it too in the future.

Thanks O2.


----------



## jeffkrol

O2surplus said:


> SNIP..


I take it this is till only 2 channels dimming???
Also do you have any idea what RTC Steves Typhon uses..?

I'll be hooking up the serial USB port soon so I will finally be able to play "geek"...


----------



## O2surplus

jeffkrol said:


> I take it this is till only 2 channels dimming???
> Yep.
> 
> Also do you have any idea what RTC Steves Typhon uses..?
> Steve's is stealing er..... selling the original version of the Typhon, so it should be the DS1307.
> 
> I'll be hooking up the serial USB port soon so I will finally be able to play "geek"...


 LOL- Using a USB port alone does not qualify you as a "Geek". But if you whip out a FTDI adapter too......Now you're qualified. roud:


----------



## jeffkrol

O2surplus said:


> LOL- Using a USB port alone does not qualify you as a "Geek". But if you whip out a FTDI adapter too......Now you're qualified. roud:


Yep that is the next project.. My orig order was a plug and play one (just direct plug to the Typhon serial out) from your recommendation I believe, but they sent a "solder it yourself" board.. grrr ..
As soon as the parts come from LED Groupbuy come.. I get to "play" a bit..
(so who did they steal their 5up Meanwell boards from.. )

As you may remember I upgraded my shooting iron.. 

now which one is ground.............................. (just kidding)


----------



## O2surplus

jeffkrol said:


> Yep that is the next project.. My orig order was a plug and play one (just direct plug to the Typhon serial out) from your recommendation I believe, but they sent a "solder it yourself" board.. grrr ..
> As soon as the parts come from LED Groupbuy come.. I get to "play" a bit..
> (so who did they steal their 5up Meanwell boards from.. )
> As you may remember I upgraded my shooting iron..
> 
> now which one is ground.............................. (just kidding)


 LOL- I wouldn't call it stealing ... the designs were posted online and they just jumped on the band wagon like everyone else. Stealing is when you're a Chinese seller that's selling my designs as your own, but at the same time, too lazy to remove my name from the silkscreen. It's too bad for them now as most of my designs have become nearly impossible to mas produce using only machines. They'd need to employ an army of slaves... er.... "workers" to perform all the hand soldering- LOL. Oh Yeah? What was I thinking? they already do.:icon_eek:


----------



## Guy.hall

I have this problem running the code, when it changes mode etc, it doesn't clear the text properly? 

Everything still operates as normal, it just looks a bit funny lol

Sent from my Nexus 5 using Tapatalk


----------



## VintonC

Guy.hall said:


> I have this problem running the code, when it changes mode etc, it doesn't clear the text properly?
> 
> Everything still operates as normal, it just looks a bit funny lol
> 
> Sent from my Nexus 5 using Tapatalk


The old text isn't getting overwritten or cleared. You should make the strings the same length that are used to indicate the state change or mode, like 'FAN-ON ' or FAN-OFF'. Notice the extra space at the end of fan-on, it will clear the 'F' from fan off. You can put the extra spaces at either end of the string. It's just a matter of what looks better to you.

I haven't looked at the code, so I can't tell you where to make the change.


----------



## Guy.hall

Thank you, didn't think of that but will give it a shot  

Sent from my Nexus 5 using Tapatalk


----------



## O2surplus

Guy- try this version. This one doesn't leave any artifact text in the display.
Just remember to adjust the variables to your liking before you load it.:hihi:




PHP:


/*
 * Name:    tank-control.pde
 * Author:    User "sink" at plantedtank.net forums
 * URL:        http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS1307RTC
 *
 * The latest version of this code can always be found at above url.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */
/* NOTICE: 4/2/2014- Addtional support for I2C LCD & Dallas OneWire Temperature readout added by O2Surplus.
              The original Libraries used in this version of the code were updated for use with Arduino 1.5-r2.
              Please make sure to use the proper version of said libraries. */
              
#include <TimerOne.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <OneWire.h> // added to original code by O2Surplus 4/2/2014
#include <LiquidCrystal_I2C.h>// added to original code by O2Surplus 4/2/2014

//LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//Temperature chip i/o
int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2

OneWire ds(DS18S20_Pin);  // on digital pin 2

int fanEnable = 8;// assigns cooling fan ON/OFF control to digital pin 8.

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin "Cool White"
const int kChan1Pin = 10; // Channel 1 Pin "Warm White"

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 1023,512 }; // daytime LED state
const int kNightState[] = { 5, 0 }; // nighttime LED state

// duration (in seconds) of sunrise/sunset fade
const long kFadeDuration = 7200; // 2 hours

long ctr;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;

  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) Timer1.setPwmDuty(kChan0Pin, state[0]);
  if (state[1] >= 0 && state[1] <= 1023) Timer1.setPwmDuty(kChan1Pin, state[1]);
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
      
      lcd.setCursor(0,2);
      lcd.print("     NIGHT TIME     ");         // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(0,3);
      lcd.print("      FANS=OFF      ");
      
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
      
      lcd.setCursor(0,2);
      lcd.print("      SUNRISE       ");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(0,3);
      lcd.print("       FAN=ON       ");
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
      
      lcd.setCursor(0,2);      
      lcd.print("      DAY TIME      ");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(0,3);
      lcd.print("       FAN=ON       ");
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
      
      lcd.setCursor(0,2);     
      lcd.print("       SUNSET       ");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(0,3);      
      lcd.print("       FAN=ON       ");
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
      
      lcd.setCursor(0,2);     
      lcd.print("     NIGHT TIME     ");          // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(0,3);      
      lcd.print("      FANS=OFF      ");
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
 
}
void displayDigits(int digits) {
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
  
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}
void lcdClockDisplay() {
  lcd.setCursor(0,0);
  lcd.print(hour());
  displayDigits(minute());
  displayDigits(second());
  lcd.print("  ");
  lcd.print(month());
  lcd.print("/");
  lcd.print(day());
  lcd.print("/");
  lcd.print(year()); 
   
}
void setup() {
  Serial.begin(115200); // Max for Arduino Uno
  setSyncProvider(RTC.get);
  setSyncInterval(120);
  Wire.begin();
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines and turn on backlight
  Timer1.initialize(6666); // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(fanEnable,OUTPUT);   // Fan control coding added by O2Surplus 4/2/2014
}

void loop () {
  float temperature = getTemp();// Temperature serial display coding addded by O2Suplus 4/2/2014
  Serial.println(temperature);
  ctr = seconds_since_midnight();// Original code
 
  lcd.setCursor(0,1);          // Temperature to I2C LCD added by O2Surplus 4/2/2014
  lcd.print("Temp C = ");
  lcd.print(temperature);
 
  determine_state();// Original code
  Serial.print("ctr: ");
  Serial.print(ctr); // display counter
  Serial.println();
  digitalClockDisplay(); //display time
  Serial.println();
  lcd.setCursor(0,0); //Time/Date to I2C display added 4/2/2014 by O2Surplus
  lcd.println();
  lcdClockDisplay();
  
  delay(1000); // no need to do anything until next second
}// Original Code ends here.


float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius // Added by O2Suplus 4/2/2014

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
  
}


----------



## Guy.hall

Cheers o2, will give it a go ta

Sent from my Nexus 5 using Tapatalk


----------



## DaChicken

*LED Controller*

Good Morning all!!

I must say... what an awesome thread to read here....

thank you all for participating in this project. It is amazing and helpful for the noobs like us. 

I have uploaded the code to my Arduino Uno and it seems to be working, except that the time is 20 minutes late....

http://i1282.photobucket.com/albums/a527/DaChicken5/2014-06-11115632_zps329a0652.jpg

The main problem for me is the hardware setup.... 

Can anyone please give me a diagram for the setup to be used in order to work with O2's latest Arduino 1.05.-rev2 software?

The setup I tried was the one for the Typhoon controller but I keep on making a mistake... can anyone please assist?

Typhoon Controller Setup:









Regards

Hendrik Venter


----------



## sink

O2Surplus! You pimp! Love the LCD integration, very nice work. I don't even have a fishtank at the moment, having sold everything off before I moved across the country this month. But I'm contemplating an aquaponics setup in my garage, which would get me back into tinkering with this code again in coming months. In the meantime I'll put a note in the FP pointing people at your more recent improvements! Glad to see folks are still working with it.


----------



## O2surplus

sink said:


> O2Surplus! You pimp! Love the LCD integration, very nice work. I don't even have a fishtank at the moment, having sold everything off before I moved across the country this month. But I'm contemplating an aquaponics setup in my garage, which would get me back into tinkering with this code again in coming months. In the meantime I'll put a note in the FP pointing people at your more recent improvements! Glad to see folks are still working with it.



Whoa! Anders YOU'RE ALIVE! Glad to see you're back! You've been missed around here for a long time! I've been doing my best to keep this thread alive since it's the only aquarium code that I've ever found that takes advantage of TIMER1 to produce 10 bit dimming. Hopefully you'll get another tank set up and feel the need to tweak your code even further. I know that I'd love it to eventually have independent start times and fade durations for each channel. (hint-hint I can't figure that out on my own. LOL):icon_bigg


----------



## gus6464

O2,

Can your new code on page 11 be loaded on your custom Typhon boards? Is is possible to add the temp sensor to them?


----------



## O2surplus

gus6464 said:


> O2,
> 
> Can your new code on page 11 be loaded on your custom Typhon boards? Is is possible to add the temp sensor to them?



Unfortunately - the answer is no. The new code doesn't have any provisions in it for a user interface, and my version of the "Typhon" doesn't have a Dallas OneWire connection built in. I'd have to redesign it a bit to break out a digital pin to be used as an input for the temp sensor. My controller does have an I2C connection though. I'd have to do some research as it may be possible to build a small add on circuit board that could convert the temp data over to something readable by the I2C input.


----------



## cvasantrao

Just joined. I already have a arduino controller for my aquarium with light switching on at sunrise and switching off at sunset and moonlight coming on at sunset and switching off at 11 in the night.Found this interesting and planning to add dimming. Can the board design be shared. I am willing to share my code.


----------



## farrenator

Why can't you use the digital outputs on your existing arduino board?



cvasantrao said:


> Just joined. I already have a arduino controller for my aquarium with light switching on at sunrise and switching off at sunset and moonlight coming on at sunset and switching off at 11 in the night.Found this interesting and planning to add dimming. Can the board design be shared. I am willing to share my code.


----------



## cvasantrao

OK. Will Try it out
Thanks


----------



## karmacop

Hey guys. I've just discovered this thread and am going to try this out in one of my Snake vivariums. Im wondering if any of you have considered using the Timelord/AVR-Libc library which automatically determines the sunrise/sunset time based on your lat/long?
I'm going to have a crack at integrating it myself but my coding skills are limited to say the least...


----------



## scaLLas

Hi all
Have been playing around with the timer 3 library on a mega but need 3 more channels to do the fading
soooo.... I adapted the timer3 library to make timer 4. Its on pins no 6,7 and 8 on the Mega2560
So would love if someone can test it and give feedback?
Works EXACTLY as timer3... only as timer 4!

Gives three more channels that can fade led's!!


----------



## VitoA

*Arduino 1.0.6 support*

Hi, the original code for this led lighting was really usefull for me.
I've done some changes to be compactible with new arduino ide 1.0.6 instead of v0023/22
Dont know if anyone has done this but in anex are libraries .
Please check and confirm if it works
Only tested with DS3231RTC

https://dl.dropboxusercontent.com/u/44652491/libraries106.zip

Tanks for all

VitoA


----------



## VitorBello

*Problem with Daty State.*

Hello Everyone!

Discovered this threat and upload Sink program into the Arduino with a simple CAT4101's boar that I made. I set the NightState period to (5,5) in order to get the MoonLight efect, however I notice that this state did not change during the morning. I set the DayState to the maximum value.

I am using a DS1307, and notice that the sketch is using the DS3231RTC library

Do you guys think this can be the reason of the problem? I will change that today at night but only tomorrow i will have sure.

Thanks a lot!


----------



## MrSpiffy

Hate to resurrect an old thread, but I'm working on implementing this same idea and running into a problem.

Admittedly, I haven't received my temperature probe in the mail, and I don't have any fans or LEDs hooked up, yet. However, I'm not getting any output on my LCD. It does light up, and I'm able to perform a simple "hello world", as well as print text on each line of the screen. But the code the O2Surplus posted isn't working for me.

Any ideas? Does it matter if it's not wired up to the LEDs/fans/probe, yet?

Things I've changed in the code are:

LiquidCrystal instead of the LiquidCrystal_I2C library
Updated versions of OneWire, TimerOne, and Time.
Swapped out the DS1307 library for the DS3231 library.
Adafruit Trinket Pro 5V board (can't use pins 2 or 7, for USB only)

I've even tried commenting out anything to do with the temperature probe and fan controls, but that didn't help, either. The code compiles fine in Arduino IDE 1.0.5, so I'm not sure what the problem is. (I can attach libraries, if anyone needs them to compile the code.)

I also noticed some lcd.print and lcd.setCursor lines here and there that are commented out where the timing logic begins. Is there a reason for that? Or should I un-comment those lines?

EDIT: I'm wondering if it might have to do with this being a USB unit..? Perhaps serial commands won't work properly?



Code:


/*
 * Name:    tank-control.pde
 * Author:    User "sink" at plantedtank.net forums
 * URL:        http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS1307RTC
 *
 * The latest version of this code can always be found at above url.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */
/* NOTICE: 4/2/2014- Addtional support for I2C LCD & Dallas OneWire Temperature readout added by O2Surplus.
              The original Libraries used in this version of the code were updated for use with Arduino 1.5-r2.
              Please make sure to use the proper version of said libraries. */
              
#include <TimerOne.h>
#include <Time.h>
#include <Wire.h>
#include <DS3231RTC.h>
#include <OneWire.h> // added to original code by O2Surplus 4/2/2014
#include <LiquidCrystal.h>// added to original code by O2Surplus 4/2/2014

//LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal lcd(0,1,14,4,5,8);  // Set the LCD I2C address

//Temperature chip i/o
int DS18S20_Pin = 12; //DS18S20 Signal pin on digital 12

OneWire ds(DS18S20_Pin);  // on digital pin 12

int fanEnable = 8;// assigns cooling fan ON/OFF control to digital pin 8.

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin
const int kChan1Pin = 10; // Channel 1 Pin

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 1023,1023 }; // daytime LED state
const int kNightState[] = { 0, 0 }; // nighttime LED state

// duration (in seconds) of sunrise/sunset fade
const long kFadeDuration = 3600; // 60 minutes

long ctr;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;

  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) Timer1.setPwmDuty(kChan0Pin, state[0]);
  if (state[1] >= 0 && state[1] <= 1023) Timer1.setPwmDuty(kChan1Pin, state[1]);
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE");         // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
      
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(3,2);
      lcd.print("SUNRISE/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);             
      lcd.print("DAY/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("SUNSET/MODE");              // LCD coding added by O2Surplus 4/2/2014
      //lcd.setCursor(11,2);
      //lcd.print("  ");
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE");          // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
 
}
void displayDigits(int digits) {
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
  
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}
void lcdClockDisplay() {
  lcd.setCursor(0,0);
  lcd.print(hour());
  displayDigits(minute());
  displayDigits(second());
  lcd.print("  ");
  lcd.print(month());
  lcd.print("/");
  lcd.print(day());
  lcd.print("/");
  lcd.print(year()); 
   
}
void setup() {
  Serial.begin(115200);        // Max for Arduino Uno
  setSyncProvider(RTC.get);
  setSyncInterval(120);
  Wire.begin();
  lcd.begin(20,4);             // initialize the lcd for 20 chars 4 lines and turn on backlight
  Timer1.initialize(6666);     // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(fanEnable,OUTPUT);   // Fan control coding added by O2Surplus 4/2/2014
}

void loop () {
  float temperature = getTemp();  // Temperature serial display coding addded by O2Suplus 4/2/2014
  Serial.println(temperature);
  ctr = seconds_since_midnight(); // Original code
 
  lcd.setCursor(0,1);             // Temperature to I2C LCD added by O2Surplus 4/2/2014
  lcd.print("Temp C = ");
  lcd.print(temperature);
 
  determine_state();              // Original code
  Serial.print("ctr: ");
  Serial.print(ctr);              // display counter
  Serial.println();
  digitalClockDisplay();          //display time
  Serial.println();
  lcd.setCursor(0,0);             //Time/Date to I2C display added 4/2/2014 by O2Surplus
  lcd.println();
  lcdClockDisplay();
 
   

  
  delay(1000);                    // no need to do anything until next second
}// Original Code ends here.


float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius // Added by O2Suplus 4/2/2014

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
}


----------



## MrSpiffy

Looks like I made a rookie mistake. Apparently, using pins 0 and 1 is a bit of a no-no during programming. I could disconnect the Arduino from the LCD, and then it might program and run. But I ended up moving those wires to other pins and now it appears to upload and run just fine!

Now, just need to wait for the temperature probe, get some fans, and test final wiring to the LEDs...


----------



## O2surplus

MrSpiffy said:


> Looks like I made a rookie mistake. Apparently, using pins 0 and 1 is a bit of a no-no during programming. I could disconnect the Arduino from the LCD, and then it might program and run. But I ended up moving those wires to other pins and now it appears to upload and run just fine!
> 
> Now, just need to wait for the temperature probe, get some fans, and test final wiring to the LEDs...



Nice work! Your going to love the smooth dimming that "Sink"'s code provides.


----------



## paronaram

Hello ALL,

I'm new in all this Arduino controlling devices, so please pardon all incorrect lingo and terminology. 
I have a quick question: Does anybody know why when I run timeupdate code, it synchronizes time correctly, I get 12 min off?
Device came from O2 and it was PST time, and I'm in EST. So I decided to change the time...
Time on the PC is set correct.

Thanks.


----------



## kman

paronaram said:


> Hello ALL,
> 
> I'm new in all this Arduino controlling devices, so please pardon all incorrect lingo and terminology.
> I have a quick question: Does anybody know why when I run timeupdate code, it synchronizes time correctly, I get 12 min off?
> Device came from O2 and it was PST time, and I'm in EST. So I decided to change the time...
> Time on the PC is set correct.
> 
> Thanks.


Did you compile it first, and then immediately upload?


----------



## paronaram

Hi, thanks for reply.
Yes, I did.
It was not working at all, and I found that library was old, updated library and it works now.
but I get 12min off

Thanks


----------



## O2surplus

paronaram said:


> Hi, thanks for reply.
> Yes, I did.
> It was not working at all, and I found that library was old, updated library and it works now.
> but I get 12min off
> 
> Thanks


Aram-

Check line #57 your copy of the TimeSet code. This is what it looks like-
const int kAdjustment = 25;
The 25 stands for the number of seconds needed to compile & upload the code to your arduino (on average). You can change the 25 to any number you wish to skew the time forward or back. Since your clock is 12 minutes off (forward or back?) try changing the 25 to 720 or -720 to see if that corrects the time.:icon_smil


----------



## paronaram

It's 12min forward.
I change it to 720, same result...

Thanks


----------



## MrSpiffy

I'm not sure why, but my lights will not fade on or off during the sunrise or sunset periods. The period does appear to change, as the LCD does show the correct state at the proper times.

I have two rows of LEDs with the dimming input for each driver connected to pins 9 and 10, which is where I gathered they should be connected from evaluating the code.

My setup consists of a 24V PSU (trimmed down to 18V) running to a pair of MeanWell LDD drivers, each driving a set of 5 LEDs, 3W each. I also have a 4x20 LCD, DS18B20 temp probe, and the DS3231 RTC. Lastly, I'm using an Adafruit Trinket Pro 5V Arduino unit, so available pins may be a little different than for an Uno. Also, the 5V onboard output is only 150mA, not 800mA as the Uno would typically have.

The RTC was set and appears to be functioning correctly, as it's keeping time and date accurately. The temp probe also looks like it's working fine, as the temp updates regularly and shows an expected temp value for the ambient air. And the LCD is displaying fine, backlight and contrast working just fine.

Things that are NOT working are the fans and the PWM dimming. However, I believe the fans are due to the brand of fan I purchased. (Arctic F8 80mm PWM fans I guess use different frequencies for PWM. Although, even just using straight 12V and no PWM input, they wouldn't spin up at all.)

Pinouts:

LCD: 4,5,11,14,15,16,17 (RS,RW,E,D4-D7)
RTC: A4,A5 (analog pins)
PWM fans: 6
PWM dimming: 9,10
Temp probe: 12

I just moved all 5V power requirements for the temp probe, LCD, Backlight, and RTC over to the BUS pin to avoid using the onboard power regulation.

Pin 13 is used for an onboard LED, and pins 2 and 7 are only for onboard USB control, so I avoided using them.

Unused pins: 2,3,7,13,A6,A7

Is it possible I don't have the available onboard power required for all of these things in the Trinket Pro?

Any help troubleshooting this issue would be greatly appreciated. :help:



Code:


/*
 * Name:    tank-control.pde
 * Author:    User "sink" at plantedtank.net forums
 * URL:        http://bitbucket.org/akl/tank-control
 *
 * This is control code for an aquarium lighting system.  It is intended to be
 * run on an Arduino microcontroller board.  It allows independant
 * high-resolution control of two PWM outputs (normally connected to LED
 * drivers) and complete flexibility with respect to intensity, timing
 * schedules, and sunrise/sunset.
 *
 * This code requires the following libraries: Wire, TimerOne, Time, DS1307RTC
 *
 * The latest version of this code can always be found at above url.
 */

/*
 * Copyright (c) 2011, User "sink" at plantedtank.net forums
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.  
 */
/* NOTICE: 4/2/2014- Addtional support for I2C LCD & Dallas OneWire Temperature readout added by O2Surplus.
              The original Libraries used in this version of the code were updated for use with Arduino 1.5-r2.
              Please make sure to use the proper version of said libraries. */
              
#include <TimerOne.h>
#include <Time.h>
#include <Wire.h>
#include <DS3231RTC.h>
#include <OneWire.h> // added to original code by O2Surplus 4/2/2014
#include <LiquidCrystal.h>// added to original code by O2Surplus 4/2/201401.

//LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display, not using I2C here
LiquidCrystal lcd(4,5,11,14,15,16,17);  // Set the LCD I2C address

//Temperature chip i/o
int DS18B20_Pin = 12; //DS18S20 Signal pin on digital 17

OneWire ds(DS18B20_Pin);  // on digital pin 17

int fanEnable = 6;// assigns cooling fan ON/OFF control to digital pin 6.

/*
 * IMPORTANT:  These *must* be the pins corresponding to the Timer1 timer on
 * the ATmega168/328.  These are digital pins 9 and 10 on the Uno/Duemilanove.
 */
const int kChan0Pin = 9; // Channel 0 Pin
const int kChan1Pin = 10; // Channel 1 Pin

// All times are in seconds since midnight (valid 0 - 86399)
const long kTurnOn = 32400; // time dawn begins - 0900hrs
const long kTurnOff = 75600; // time sunset begins - 2100hrs

/*
 * Light "state" represents the PWM duty cycle for each channel This normally
 * dictates light intensity. It is an array { duty_chan_1, duty_chan_2 }.
 * Possible values for duty cycle are 0 - 1023.
 */
const int kDayState[] = { 1023,1023 }; // daytime LED state
const int kNightState[] = { 0, 0 }; // nighttime LED state

// duration (in seconds) of sunrise/sunset fade
const long kFadeDuration = 3600; // 60 minutes

long ctr;

/*
 * fader -- Determine output state for a given time to provide smooth fade from
 * one state to another.
 *     Args:
 *     start_time  -- time (in seconds) of start of fade
 *     start_state -- beginning state
 *     end_state   -- ending state
 *     out         -- array to update with state
 */
void fader(long start_time, const int start_state[], const int end_state[], int out[2]) {

  float per_second_delta_0 = (float) (end_state[0]-start_state[0])/kFadeDuration;
  float per_second_delta_1 = (float) (end_state[1]-start_state[1])/kFadeDuration;

  long elapsed = ctr-start_time;

  out[0] = start_state[0] + per_second_delta_0 * elapsed;
  out[1] = start_state[1] + per_second_delta_1 * elapsed;
}

// return seconds elapsed since midnight
long seconds_since_midnight() {
//  setTime(21, 45, 00, 16, 2, 2015);
//set the system time to 21hrs 45min 00sec 16,Feb 2015...does not set RTC, will reset upon powerup
  
  time_t t = now();
  long hr = hour(t);
  long min = minute(t);
  long sec = second(t);
  long total = hr * 3600 + min * 60 + sec;
  return total;
}

// set output state
void set_state(const int state[]) {
  if (state[0] >= 0 && state[0] <= 1023) Timer1.setPwmDuty(kChan0Pin, state[0]);
  if (state[1] >= 0 && state[1] <= 1023) Timer1.setPwmDuty(kChan1Pin, state[1]);
}

/*
 * determine_state -- This is where the actual timing logic resides.  We
 * examine ctr (seconds since midnight) and then set output state accordingly.
 * Variable ctr rolls back to 0 at midnight so stages that cross midnight (ie:
 * nighttime) are broken up into two stages.
 */
void determine_state() {
  if ( ctr >= 0 && ctr < kTurnOn ) { // night
      set_state(kNightState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE ");         // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
      
  } else if ( ctr >= kTurnOn && ctr <= (kTurnOn+kFadeDuration) ) { // sunrise
    int foo[2];
    fader(kTurnOn, kNightState, kDayState, foo);
    set_state(foo);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(3,2);
      lcd.print("SUNRISE/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOn+kFadeDuration) && ctr < kTurnOff ) { // day
    set_state(kDayState);
      
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);             
      lcd.print("DAY/MODE");              // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr >= kTurnOff && ctr <= (kTurnOff+kFadeDuration) ) { // sunset
    int foo[2];
    fader(kTurnOff, kDayState, kNightState, foo);
    set_state(foo);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("SUNSET/MODE");              // LCD coding added by O2Surplus 4/2/2014
      //lcd.setCursor(11,2);
      //lcd.print("  ");
      digitalWrite(fanEnable, HIGH);
      lcd.setCursor(7,3);
      lcd.print("FAN-ON");
  } else if ( ctr > (kTurnOff+kFadeDuration) && ctr < 86400 ) { // night
    set_state(kNightState);
      lcd.setCursor(0,2);
      //lcd.print("                   ");
      lcd.setCursor(5,2);
      lcd.print("NIGHT/MODE");          // LCD coding added by O2Surplus 4/2/2014
      digitalWrite(fanEnable,LOW);
      lcd.setCursor(6,3);
      lcd.print("FANS-OFF");
  }
}

/*
 * Utility function for pretty digital clock time output
 * From example code in Time library -- author unknown
 */
void printDigits(int digits) {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
 
}
void displayDigits(int digits) {
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
  
}

/*
 * Display time
 * Adapted from example code in Time library -- author unknown
 */
void digitalClockDisplay() {
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print("  ");
  Serial.print(month());
  Serial.print("/");
  Serial.print(day());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println(); 
}
void lcdClockDisplay() {
  lcd.setCursor(0,0);
  lcd.print(hour());
  displayDigits(minute());
  displayDigits(second());
  lcd.print("   ");
  lcd.print(month());
  lcd.print("/");
  lcd.print(day());
  lcd.print("/");
  lcd.print(year()); 
   
}
void setup() {
  Serial.begin(115200);        // Max for Arduino Uno
  setSyncProvider(RTC.get);
  setSyncInterval(120);
  Wire.begin();
  lcd.begin(20,4);             // initialize the lcd for 20 chars 4 lines and turn on backlight
  Timer1.initialize(6666);     // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
  pinMode(fanEnable,OUTPUT);   // Fan control coding added by O2Surplus 4/2/2014
}

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
  
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
    }
  
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
    }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
    }
  
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
    }  

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present, HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
    }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } 
  
  else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
  
  ctr = seconds_since_midnight(); // Original code
 
  lcd.setCursor(0,1);             // Temperature to I2C LCD added by O2Surplus 4/2/2014
  lcd.print("   Temp F = ");
  lcd.print(fahrenheit);
 
  determine_state();              // Original code
  Serial.print("ctr: ");
  Serial.print(ctr);              // display counter
  Serial.println();
  digitalClockDisplay();          //display time
  Serial.println();
  lcd.setCursor(0,0);             //Time/Date to I2C display added 4/2/2014 by O2Surplus
  lcd.println();
  lcdClockDisplay();
}


----------



## MrSpiffy

Ran across what may be a little detail that completely throws things off. It sounds like I should join the grounds for the Arduino and the LED PSU, otherwise the PWM may not function properly. I'll give that a shot and see how it goes.


----------



## O2surplus

MrSpiffy said:


> Ran across what may be a little detail that completely throws things off. It sounds like I should join the grounds for the Arduino and the LED PSU, otherwise the PWM may not function properly. I'll give that a shot and see how it goes.


LOL- Don't feel bad. Lots of people miss that "little detail". The Arduino and power supply *do* need to share a common ground. :hihi:


----------



## MrSpiffy

Yeah, there's definitely been a learning curve with the Arduino. But it's been interesting, despite the frustration.

I read somewhere that some people recommend a resistor or diode, or some other method, to protect the Arduino unit from the PSU power. Is that something you've found to be necessary, as well?


----------



## O2surplus

MrSpiffy said:


> Yeah, there's definitely been a learning curve with the Arduino. But it's been interesting, despite the frustration.
> 
> I read somewhere that some people recommend a resistor or diode, or some other method, to protect the Arduino unit from the PSU power. Is that something you've found to be necessary, as well?


The Arduino's on board regulator tends to overheat, if it's forced to drop too much voltage. I don't recommend powering the Arduino with more than 12V. Using 7 to 9V is optimal.


----------



## MrSpiffy

I'm using a separate power supply for the Arduino via micro-USB. That should be a standard 5V supply.

I was referring to protecting the Arduino from connections to the 24V LED supply, even via ground. Sounds like some people had heard from a guy who heard from another guy that you can fry your Arduino by doing that. I'm guessing that's just mumbo jumbo.


----------



## kman

http://www.ruggedcircuits.com/10-ways-to-destroy-an-arduino/


----------



## MrSpiffy

Those are all great to know. Thanks for sharing! However, it doesn't address the concern of joining the ground pin of the Arduino to the ground pin of the PSU for the LEDs.


----------



## MrSpiffy

Looks like the common ground was my problem. The dining works at night. Haven't gotten to test the sunrise portion, yet. Perhaps it's also the issue with the fans..?


----------



## Gisimo

*help*

hi guys im trying to make lights for my aquarium but this time i am going to use a hc-05 eller 06 bluetooth. i have triet the code for arduino 1.0 but it dosent work(it wont compile) so i tried the origional one but i cant get it to work with 1.0!!! is there one of you here who have the original code but for 1.0??(without lcd,fan ect)
The resen is the Arduino 0022 dont se the bluetooth com port... if you no of a way to get the 0022 to find the com-port please tell


----------



## kman

^^ Arduino has updated their software from 1.0.6 to 1.6.3 or something like that, and there are a LOT of sketches that won't compile correctly until the new version without making changes. You might want to try the previous software version and see if that helps. The old versions are still available on the Arduino.cc website.


----------



## Gisimo

*help*

i found the mistakes and now it is working


----------



## MrSpiffy

Any recommendations on cooling fans that will work with Arduino PWM? I noticed it's in the code, but it will not control the fans I purchased (Arctic F8 PWM). Looking for some suggestions.


----------



## salty joe

I've been looking around for awhile for a sketch like this-this is perfect but I can't get it loaded on my Arduino Uno. 

I downloaded the latest version and library bundle from sink's first post to my computer. I have the 3231 timer so I deleted the 1307 from the library bundle. 

On Arduino 1.6.7, I went to Sketch, Include Library, then Add .Zip Library. When I select the libraries folder and click 'open' then click 'open' again, I get the error 'A subfolder of your sketchbook is not a valid library'.

If anyone is willing to help me get this sorted out, it would be very much appreciated.


----------



## salty joe

Just for the heck of it I'm gonna take another stab at this thread. 

After much head scratching/pounding I got sink's sketch and the libraries installed on the Arduino program and it compiles. Yes! Thank you sink for putting that out there-that's very generous. 

I downloaded the Python program from post 39 but Pserial has become problematic. I have the RTC 3231. It was mentioned in this thread that daylight savings time could be adjusted for manually. 

Can the time and date be added manually? If so, can anyone please get me headed in the right direction? I put the time and date a couple places where I thought it might belong and downloaded a few times, but nothing. So I returned the sketch to original. I watched a bunch of YouTube videos on the 3231-no help there. So close, but so far away. Honestly, just knowing if it's possible to add time and date manually with this sketch would be helpful. 

Anybody? Please?


----------



## ichy

salty joe said:


> I've been looking around for awhile for a sketch like this-this is perfect but I can't get it loaded on my Arduino Uno.
> 
> I downloaded the latest version and library bundle from sink's first post to my computer. I have the 3231 timer so I deleted the 1307 from the library bundle.
> 
> On Arduino 1.6.7, I went to Sketch, Include Library, then Add .Zip Library. When I select the libraries folder and click 'open' then click 'open' again, I get the error 'A subfolder of your sketchbook is not a valid library'.
> 
> If anyone is willing to help me get this sorted out, it would be very much appreciated.


You have to UNZIP the library folder. Once done unzipping, there should a be folder inside the unzipped folder. Copy the entire folder, not individual files..into the Library folder for your Arduino SDK installation.

If it is installed correctly you can select it from the Add Library menu.
If the library has examples you can open a sample Sketch from the EXAMPLES menu and it will compile if correctly installed.


----------



## salty joe

Thanks ichy for that reply.
I did manage to get the libraries installed. It took me a real long time, but it's done. 

I am using Arduino 1.6.7. What is SDK?

Post 39 in this thread has a download for Python that gets the RTC 3231 set. I downloaded the Python program but when I try to install Pserial, it finds Python version 2.7 so I click 'next'. Says it's ready to install so I click 'next'. I get an error that says 'could not create key'. I click OK. Another error that says 'could not set key value'. I say OK, then another 'could not set key value'. I click OK then it says it loads. But I can't get it to set the time on this sketch.

I've spent hours trying to get this Pserial to work-IDK if it's an issue with my computer or what. 

Anyway, is it possible to manually set the time on this sketch?


----------



## pjayyy

Hi, I used the code from the first page.

I uploaded it on a Arduino Nano microUSB v3 168.

My problem is, the light doesnt dim on estimated time, it switches the light hard on/off. The timer works right, but it simply doesnt dim on time. After switching on the arduino first the light is at 1024 and after 2 seconds (the loop begins) I see it does dimm to my selected value (900). So thats right. But it doesn't dim on time.

what can be the fault?

wiring:
PWM to Arduino Pin Digital 9
VPin 12V
simple led stripe 50cm long powered by the pwm controller.


My PWM Controller is this:
3W 700mA DC DC 7.0 30V to 1.2 28V LED lamp Driver Support PWM Dimmer-in Other Electronic Components from Electronic Components & Supplies on Aliexpress.com | Alibaba Group


----------



## Arun.

*how to change PWM frequency from 150hz to 2Khz ?*

how to change PWM frequency ? 
should I edit TimerOne library or *changeTimer1.initialize(6666)* to some higher value / lower value ?


Code:


void setup() {
  Serial.begin(115200); // Max for Arduino Uno
  setSyncProvider(RTC.get);
  Timer1.initialize(6666); // 150Hz PWM
  pinMode(kChan0Pin, OUTPUT);     
  Timer1.pwm(kChan0Pin, 0);
  pinMode(kChan1Pin, OUTPUT);     
  Timer1.pwm(kChan1Pin, 0);
}

Thanks.


----------



## O2surplus

Arun. said:


> how to change PWM frequency ?
> should I edit TimerOne library or *changeTimer1.initialize(6666)* to some higher value / lower value ?
> 
> 
> Code:
> 
> 
> void setup() {
> Serial.begin(115200); // Max for Arduino Uno
> setSyncProvider(RTC.get);
> Timer1.initialize(6666); // 150Hz PWM
> pinMode(kChan0Pin, OUTPUT);
> Timer1.pwm(kChan0Pin, 0);
> pinMode(kChan1Pin, OUTPUT);
> Timer1.pwm(kChan1Pin, 0);
> }
> 
> Thanks.


To get the frequency you need....divide 1,000,000 by your desired frequency. i.e 1,000,000/ 2000 = 500.

Timer1.initialize(500); // 2000Hz PWM :grin2:


----------



## Arun.

O2surplus said:


> To get the frequency you need....divide 1,000,000 by your desired frequency. i.e 1,000,000/ 2000 = 500.
> 
> Timer1.initialize(500); // 2000Hz PWM :grin2:


Thanks @O2surplus, that code now runs my Arduino at 2Khz 0


----------



## greeffjl

*independent start times and fade durations for each channel*

Hi

I have been using this LED Code now for the last year and I just love the minimalistic code. O2surplus, Sink, are there any way to have independent start times and fade durations for each channel? I am running a Soft Coral tank and would love to have my Blue channel start first and end last during the day.

I cannot program (whish I could) for the death of myself so any help would be so appreciated. 

If not, this still is my best code to use for DIY. It just gets the job done.

Regards

J
ZA


----------



## remix7196

greeffjl said:


> Hi
> 
> I have been using this LED Code now for the last year and I just love the minimalistic code. O2surplus, Sink, are there any way to have independent start times and fade durations for each channel? I am running a Soft Coral tank and would love to have my Blue channel start first and end last during the day.
> 
> I cannot program (whish I could) for the death of myself so any help would be so appreciated.
> 
> If not, this still is my best code to use for DIY. It just gets the job done.
> 
> Regards
> 
> J
> ZA


I'll probably try to ask in an Arduino forum as well, as they are more technical with C programming. For me, I know Python, VBA, SQL, and a few other languages, but no C. The syntax and logic is a little too challenging for me to follow and suggest a specific custom code solution.

I know this is an old thread, but it's still great material and definitely relevant. I'm actually extremely interested in controlling two channels independently as well. How difficult would this be? Anyone?


----------



## Nicos

Hi,
Could you help me please to develop something similar?

I am an electronics specialist, but I sucks in programming so, I need your help here to make your code a bit different (maybe less complicated).
I want to make that project run yearly for many years using the RTC DS3231 to be accurate. Also I want it to recognize the summer and winter time changes (1 hour forward or back). (optional)
I need it to operate 24h 365 days, driving mosfets with PWM method under particular times to dimming LED lights.

I need it to follow the procedure below:
At winter:
Sunrise starts 5:00 morning and finishes at 100% at 8:00 in the morning.
Sunset starts at 17:00 and finishes at 0% at 20:00 the night.

At summer:
Sunrise starts 6:00 morning and finishes at 100% at 9:00 in the morning.
Sunset starts at 18:00 and finishes at 0% at 21:00 the night.

I would be really grateful if you can help!!
Thank you
Nicos


----------



## Wetherell33

*Compilation Errors*

I've tried to compile this on the latest version of Arduino IDE, but I keep getting compilation errors. I've got basic coding experience but cannot update this code to get it to run. I've tried to download the old versions of Arduino IDE v0022 but I cannot get them to open with Windows 10. Does anybody have a working code / libraries that will compile in the latest Arduino IDE. I would greatly appreciate it!


----------



## ranjib

Awesome details. I would certainly use some of the lessons learned here.


----------



## Lingwendil

Wetherell33 said:


> I've tried to compile this on the latest version of Arduino IDE, but I keep getting compilation errors. I've got basic coding experience but cannot update this code to get it to run. I've tried to download the old versions of Arduino IDE v0022 but I cannot get them to open with Windows 10. Does anybody have a working code / libraries that will compile in the latest Arduino IDE. I would greatly appreciate it!


I can't get the older versions to work on Windows 7 or 10, but both of my machines are 64 bit.

I've got an older XP laptop I'm going to try and get it working on. 


From what I understand from the Arduino Wizards I've asked, the code is not easy to convert without nearly a full rewrite, so unless you have access to an older machine it might be worth looking at something else.


----------

