I own an 800 gallon reef aquarium. It is controlled by a Neptune Apex.
Neptune offers a "cute" LED moonlight system which is basically 5 tiny LED's and a controller box. The internal programming of the Apex isn't capable of simulating moonlight. 5 tiny LED's won't even light up the refugium on this monster. My moonlights are 5x 10W LED's driven by a MeanWell HLG driver.
I want to make a real moonlight simulator, using an ESP8266.
Even though mine is done, installed and working, I went ahead and designed and ordered a PCB for this, because I was already placing an order for a different board, and figured why not toss 5 of them in with the shipping. I don't really have a use for them, but I just figure why not?
I've done a few days of testing now on the bench, checking the ohm values at various points to make sure it did the right thing. It totally does. It 100% works.
Got a new MeanWell driver last night (the old one I was using was unsuitable for this, because at 100% it would have over-driven the LED's and at lower power ratings I would lose alot of precision in the steps between 0 and 100 %), wired it in, and this morning at 3am, looked, and I have beautiful moonlight at the perfect setting for today.
The circuit was dead easy. Will upload schematic in a few days.
The coding was non-trivial. Took about 2 days. More or less, we need a few things:
First, we need the current lunar phase. This wasn't super difficult. I had to find the date and time of a known new moon. Once I have that, I can calculate the difference between now, and that known moon, and divide by a lunar period. Knock off the left of the decimal point, and we have what percentage we are in the current phase. Then it's just simple math to get the illumination.
The hard part was talking to the Apex. There is a known undocumented json API on the Apex, that gives the states of all the outlets/inputs/etc. The problem is it dumps 14k of data, which, when you try to read with the Async http client library, just chokes it, and then ArduinoJson can't allocate enough ram to deserialize it anyhow. So I had to do a bunch of hackery to find the specific section of the json I wanted, cut it out, and then pass that into the json lib.
So now I have a pretty little box that calculates the moon phase, sets the illumination, multiplies it by what the Apex *thinks* the illumination should be, and then sets the potentiometer to that setting.
The idea is you code the Apex with profiles to ramp up/down to 100% at the beginning and end of the moon up, and use the apex to power on the Meanwell, but the ESP sets the actual brightness based on the phase. So if we were at say 50% full moon:
The Apex determines the time is right to start the moon, so it powers on the outlet.
Then the ramp profile starts ramping up from 0% to 100% over say, 90 minutes, to simulate the rise. However, the ramp profile isn't connected to a physical device at all.
Then we multiply that ramp setting by the lunar illumination. So when the ramp says 100%, we are actually at 50%, because we are 50% of full moon. The ESP sets the potentiometer, which is connected to the MeanWell, and the dimming is set to the proper number.