SunRiseLamp "wake up more naturally"

There are services out there which expose an API for sunrise times. You only need to webhook 'em :wink:

here is the code I shared with @Jean-Pierre. I converted his strings to integers, save memory…

Here is the updated working code, but note that I tested with only one neoPixel, and mind your Pin numbers. I was testing on a different pin configuration

INO file (SunriseSunset.ino)

// Created by Jean-Pierre Figaredo

#include "application.h"
#include "neopixel.h"
#include "SunRiseLamp.h"

SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);

// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN D2
#define PIXEL_COUNT 1          //<<<<<<<<<<< check here
#define PIXEL_TYPE WS2812B     //<<<<<<<<<<< check here
#define PIXEL_BRIGHTNESS 100

#define SUN_RISE_HOUR 6
#define SUN_SET_HOUR 18

#define Sun_RISE_LENGTH_IN_SEC 60  // Set this for how many seconds you wish to take to rise or set

SunRiseLamp sunriseLeds;
int lastHour = 24;

void setup()
{
  Particle.function("test", testSunMachine);
  Serial.begin(9600);
  sunriseLeds.begin(Sun_RISE_LENGTH_IN_SEC, PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
}

void loop()
{
  sunriseLeds.update();
  int currentHour = Time.hour();
  if (currentHour == SUN_RISE_HOUR && currentHour != lastHour)
  {
    sunriseLeds.rise();
  }
  else if (Time.hour() == SUN_SET_HOUR && currentHour != lastHour)
  {
    sunriseLeds.set();
  }
  lastHour = currentHour;
}

int testSunMachine(const char* data)
{
  if(strstr(data, "set"))
  {
    Serial.println("Manually told to Set");
    sunriseLeds.set();
    return 0;
  }
  else if(strstr(data, "rise"))
  {
    Serial.println("Manually told to Rise");
    sunriseLeds.rise();
    return 1;
  }
  return -1;
}

I added a Particle.function() that allows you to call rise or set in a function called “test.”

here is the new header file (SunriseLamp.h)

#ifndef SunRiseLamp_h
#define SunRiseLamp_h

#include "application.h"
#include "neopixel.h"


const unsigned int colors[] =
{
  0x000000,
  0x030102,
  0x080403,
  0x0C0704,
  0x120A07,
  0x170C08,
  0x1E0F0A,
  0x25140D,
  0x2B1710,
  0x311A12,
  0x3A1E13,
  0x422217,
  0x482718,
  0x502B1B,
  0x592E1E,
  0x603222,
  0x663622,
  0x6C3924,
  0x733C27,
  0x784029,
  0x80442C,
  0x85472E,
  0x8C4A30,
  0x904D32,
  0x965134,
  0x9B5436,
  0xA15637,
  0xA55A3B,
  0xAA5E3E,
  0xAF603F,
  0xB36340,
  0xB66643,
  0xBA6843,
  0xBD6B46,
  0xBE6C46,
  0xC06E48,
  0xC26E49,
  0xC4704B,
  0xC6734B,
  0xC8754D,
  0xC9764C,
  0xCA774D,
  0xCB784E,
  0xCD7A50,
  0xCE7D52,
  0xCF7E51,
  0xD07F52,
  0xD28154,
  0xD38255,
  0xD48356,
  0xD68558,
  0xD58759,
  0xD7895B,
  0xD88A5A,
  0xD88C5B,
  0xD98D5C,
  0xDA8E5D,
  0xD98F5E,
  0xDB9160,
  0xDB9361,
  0xDC9462,
  0xDD9563,
  0xDD9764,
  0xDE9865,
  0xDF9966,
  0xDE9B67,
  0xDF9C68,
  0xDF9D69,
  0xE09E6A,
  0xDFA06B,
  0xE1A26D,
  0xE0A36D,
  0xE1A46E,
  0xE1A56F,
  0xE2A670,
  0xE3A771,
  0xE1A871,
  0xE3AA73,
  0xE3AC74,
  0xE4AD75,
  0xE3AF76,
  0xE3AF76,
  0xE3B077,
  0xE4B178,
  0xE4B178,
  0xE4B379,
  0xE5B47A,
  0xE3B57A,
  0xE5B67E,
  0xE6B77F,
  0xE6B77F,
  0xE6B980,
  0xE7BA81,
  0xE5BB81,
  0xE5BA83,
  0xE6BB84,
  0xE5BC84,
  0xE6BD85,
  0xE6BD85,
  0xE6BF86,
  0xE6BF86,
  0xE7C089,
  0xE5C089,
  0xE6C18A,
  0xE6C18A,
  0xE6C18A,
  0xE6C38B,
  0xE6C38D,
  0xE7C48E,
  0xE5C48E,
  0xE6C58F,
  0xE6C590,
  0xE6C590,
  0xE6C791,
  0xE6C791,
  0xE6C693,
  0xE5C793,
  0xE6C894,
  0xE7C995,
  0xE7C995,
  0xE7C997,
  0xE5C997,
  0xE6CA98,
  0xE6CA9A,
  0xE6CA9A,
  0xE5CB9A,
  0xE6CC9B,
  0xE6CB9C,
  0xE6CB9C,
  0xE6CB9C,
  0xE7CC9D,
  0xE5CD9F,
  0xE5CD9F,
  0xE5CD9F,
  0xE5CDA1,
  0xE5CDA1,
  0xE6CEA2,
  0xE6CEA2,
  0xE5CEA4,
  0xE6CFA5,
  0xE6CFA5,
  0xE5CFA6,
  0xE5CFA6,
  0xE5CFA6,
  0xE5CFA8,
  0xE3D0A8,
  0xE3D0A8,
  0xE3D0A8,
  0xE2D0AA,
  0xE3D1AB,
  0xE3D1AD,
  0xE3D1AD,
  0xE1D1AD,
  0xE0D0AC,
  0xE1D1AF,
  0xE0D2AF,
  0xE0D2AF,
  0xE0D1B0,
  0xDFD2B0,
  0xDFD2B0,
  0xDFD2B0,
  0xDFD2B2,
  0xDDD2B2,
  0xDDD2B2,
  0xDDD2B4,
  0xDDD2B4,
  0xDBD2B3,
  0xDBD2B5,
  0xDBD2B5,
  0xDBD2B5,
  0xD9D2B6,
  0xD9D2B6,
  0xD9D2B6,
  0xD8D3B6,
  0xD8D2B8,
  0xD8D2B8,
  0xD6D2B7,
  0xD6D2B9,
  0xD6D2B9,
  0xD4D2B9,
  0xD4D2B9,
  0xD4D2BB,
  0xD2D2BA,
  0xD2D2BA,
  0xD2D1BC,
  0xD0D2BC,
  0xD0D2BC,
  0xD0D2BC,
  0xCFD2BD,
  0xCED1BC,
  0xCED1BC,
  0xCDD2BC,
  0xCDD2BE,
  0xCDD2BE,
  0xCBD3BE,
  0xCBD2C0,
  0xCAD1BF,
  0xC9D2BF,
  0xC9D2C1,
  0xC9D2C1,
  0xC6D1C0,
  0xC7D2C1,
  0xC5D2C0,
  0xC5D2C1,
  0xC5D2C1,
  0xC3D1C2,
  0xC4D2C3,
  0xC3D1C4,
  0xC1D1C4,
  0xC1D1C4,
  0xC0D0C3,
  0xBFD1C5,
  0xBFD1C5,
  0xBED0C4,
  0xBCD0C5,
  0xBCD0C5,
  0xBCD0C5,
  0xBBD0C7,
  0xBACFC6,
  0xB9D0C6,
  0xB8CFC5,
  0xB9D0C8,
  0xB6D0C7,
  0xB6D0C7,
  0xB5CEC8,
  0xB4CFC8,
  0xB4CFC8,
  0xB2CFCA,
  0xB1CEC9,
  0xB1CEC9,
  0xB0CFC9,
  0xAFCEC9,
  0xAECEC9,
  0xAECEC9,
  0xAECEC9,
  0xADCDCA,
  0xABCECA,
  0xABCDCC,
  0xA9CDCB,
  0xA9CDCB,
  0xA7CECB,
  0xA5CDCC,
  0xA5CDCC,
  0xA3CDCB,
  0xA1CDCC,
  0xA1CDCC,
  0x9FCDCD,
  0x9FCDCD,
  0x9DCDCD,
  0x9CCCCE,
  0x9ACCCD,
  0x98CBCC,
  0x98CBCE,
  0x95CBCD,
  0x94CBCE,
  0x94CBCE,
  0x91CBCD,
  0x90CBCF,
  0x8FCACE,
  0x8ECBCE,
  0x8BCACF,
  0x8BCACF,
  0x89CACE,
  0x87CAD0,
  0x86C9CF,
  0x85CACF,
  0x84C9D0,
  0x82C9CF,
  0x80C9D0,
  0x80C9D0,
  0x7EC9CF,
  0x7EC9CF,
  0x7BC8D0,
  0x7AC9D0,
  0x79C8CF,
  0x78C8D1,
  0x76C9D1,
  0x75C8D0,
  0x74C9D0,
  0x73C7D1,
  0x71C8D1,
  0x71C8D1,
  0x6FC8D0,
  0x6EC6D0,
  0x6EC6D0,
  0x6DC7D0,
  0x6CC6D1,
  0x6AC6D1,
  0x6AC6D1,
  0x68C6D0,
  0x68C6D0,
  0x68C6D0,
  0x66C7D0,
  0x66C6D2,
  0x65C5D1,
  0x64C6D1,
  0x65C5D1,
  0x65C5D1,
  0x65C5D1,
  0x65C5D1,
};

union colorValues {
  unsigned int hexValue;
  byte ledValue[4];
};

class SunRiseLamp {
  public:
    SunRiseLamp() {};
    void begin(int totalTime, int pixelCount, int pixelPin, int pixelType);	// total time for sunrise
    bool update();
    void rise();
    void set();

  private:
    Adafruit_NeoPixel* pixelStringPtr = NULL;
    int colorInterval;
    int lastUpdate;
    int colorIndex = 0;
    int direction = 0;
    int _pixelCount;
    int _pixelPin;
    int _pixelType;
};

#endif

and the new implementation file (SunriseLamp.cpp):

#include <application.h>

#include "SunRiseLamp.h"
#include "neopixel.h"

void SunRiseLamp::begin(int totalTime, int pixelCount, int pixelPin, int pixelType)
{
  _pixelCount = pixelCount;
  _pixelPin = pixelPin;
  _pixelType = pixelType;
  pixelStringPtr = new Adafruit_NeoPixel(_pixelCount, _pixelPin, _pixelType);
  colorInterval = (totalTime * 1000) / (sizeof(colors)/sizeof(colors[0]));
  lastUpdate = millis();
  colorIndex = 0;
  pixelStringPtr->begin();
  pixelStringPtr->setBrightness(255);
  // pixelStringPtr->setPixelColor(0, 125,125,125);
  pixelStringPtr->show();
  delay(5000);
}

bool SunRiseLamp::update()
{
  bool updateLeds = false;
  int currentMillis = millis();
  if (currentMillis - lastUpdate > colorInterval)
  {
    if (direction == 1 && (colorIndex < sizeof(colors)/sizeof(colors[0]) -  1))
    {
      colorIndex++;
      updateLeds = true;
    }
    else if (direction == -1 && colorIndex > 0)
    {
      colorIndex--;
      updateLeds = true;
    }
    else
    {
      lastUpdate = currentMillis;
      return direction = 0;
    }
    lastUpdate = currentMillis;
  }
  if(updateLeds)
  {
    colorValues colorSet;
    colorSet.hexValue = colors[colorIndex];
    byte r = colorSet.ledValue[2];
    byte g = colorSet.ledValue[1];
    byte b = colorSet.ledValue[0];
    char colorString[32] = "";
    snprintf(colorString, sizeof(colorString), "Red:%x Green:%x Blue:%x", r, g, b);
    Serial.println(colorString);
    for (int i = 0; i < _pixelCount; i++)
    {
      pixelStringPtr->setPixelColor(i, r, g, b);
    }
    pixelStringPtr->show();
  }
  return true;
}

void SunRiseLamp::rise()
{

  colorIndex = 0;
  direction = 1;
}

void SunRiseLamp::set()
{

  colorIndex = sizeof(colors)/sizeof(colors[0]);
  direction = -1;
}

Make a folder with these three files and the neoPixel files like this:

your folder will contain the five files needed to compile, and you can do it with Dev or the CLI…

This is compiled and tested!

1 Like

The one I was fooling around with actually gave me local time printed on serial to be able to verify it would even fire at the proper time.

Is it just stabbing in the dark and figure it out for differing locales? I guess i will sit here until the top of the hour and see if it works.

Edit: Does not fire at correct time…Set it for “4” at 3:56 am local time, just hit 4, nothing.

The old .ino I was playing with, I had made the addition of

 Particle.syncTime();

  Time.zone(-7);

Which is not optional to me, seeing as everyone is all over the planet…

As soon as I made that addition in my setup loop it fired correctly.

Getting it’s a fire at a particular time of day is quite trivial.

The only question is, it what time of day would you like this to actuate?

Then, Put some logic into your Loop to include the logic to set the sunrise or sunset function.

Of course, collecting your own personal time zone should be part of your particular implementation.

My setup looks like this now,

void setup()

{
  Particle.function("test", testSunMachine);
  Serial.begin(9600);
  Particle.syncTime();
  Time.zone(-7);
  sunriseLeds.begin(Sun_RISE_LENGTH_IN_SEC, PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
}

Rises fine, even the few minutes after 4am I flashed the addition of this to it. Now to see if it turns off and sets at the set time in 53 minutes.

Thanks for sharing it it’s best if it came from you :smile: you did that all so thanks :smile:

Just update the github page with the new code

1 Like

UPDATE: Just committed a few changes but the biggest one is that I removed the hex array and now I’m using kelvin temp and then converting the color to RGB. This results in a more accurate representation of the sun’s true color and an overall better system efficiency.

Also made a new logo P.S. does anyone know how to center an image in markdown I have tried a few things but it’s not working

2 Likes

To center an image in markdown you have to use html.

<p align="center">
<img src=....>
</p>

2 Likes

I just made a pull request to improve some of the stuff in your README.md

1 Like

@peekay123 @bko Thanks for all the help I didn’t have time until now to work on this project but this is where I have the pcb now.

1 Like

You must be planning on using two strips? I see two pins for data control, as well as power/ground.

I will mainly use one strip but I added another one just in case if some one has a big bed and they want to split it for his and her section. :grinning:

2 Likes

@Jean-Pierre, there are many items I would recommend cleaning up. I’ll list a few here:

  1. Many traces seem to be split into multiple segments by looking at the 90 degree corners. All traces need to be contiguous segments.
  2. I recommend “softening” the 90 degree corners with a 45 degree trace:

  1. Avoid meandering lines and trace misalignment, especially at the 74HC pads. The power trace you have angling up to the larger trace could simply go straight to connect instead.

  1. Any unused INPUTS of the 74HC245 should be connected to GND so they don’t float.
1 Like

Thank you very much :innocent: should the input and output of the 74HC245 be connected to ground or just the output?

@Jean-Pierre, only unused INPUTS need to be grounded. This is done to prevent floating-input feedback which could cause oscillation and noise to be generated. :wink:

2 Likes

ok will do that.

1 Like

@peekay123 would this be ok/work to ground the inputs

<img src="//cdck-file-uploads-us1.s3.dualstack.us-west-2.amazonaws.com/flex026/uploads/particle/original/2X/e/eb3ee123d29384f6a442a713bea35fb7345dda30.png" width=“690” height=“314”

1 Like