# breathe.py by J. Adam Sowers
# Generates an array of RGB values to make a NeoPixel device appear to
# 'breathe', similar to the sleeping MacBook LED indicator.


import math
import sys
import colorsys

r,g,b = 0x40,0xD0,0xFF # blue-ish glow
numSteps = 128


#colorsys expects RGB values in the range [0,1]
r,g,b = [ x / 255.0 for x in r,g,b]

# convert to HSV colorspace (hue, saturation, value)
# this makes it easier to adjust the values since we only have to
# vary the value (brightness)
h,s,v = colorsys.rgb_to_hsv (r,g,b)

# generate an Arduino-compatible array and store it in PROGMEM (flash memory)
# to free up SRAM for other uses.
sys.stdout.write("/* this array generated by breathe.py\n"
    "using LED 'breathing' function by Sean Voisen.\n"
    "http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ */\n"
    "const uint8_t numSteps = %d;\n" % numSteps
    )
sys.stdout.write("const uint32_t breath[numSteps] PROGMEM = {")

# About the breathing function:
# The generic function to simulate breathing appears to be e^(cos(x)).
# The inner function [cos(x)] output will be in [-1, 1].
# Therefore the min and max of the 'breathing' function will be [e^-1, e^1]
# We want values from [0,1], so we need to offset the min value by 1/e
# and scale by 1 / (e - 1/e).

min_offset = 1 / math.e
scaling_factor = 1 / (math.e - min_offset)
pi_over_numSteps = math.pi / numSteps

for n in range(numSteps):

    if not n % 8:
        sys.stdout.write("\n  ")

    # Calculate the scaling factor. This will output a value from [0,1]
    # which, when applied to the V in the HSV representation, will scale the
    # brightness without affecting hue or saturation.
    scale = (
        math.exp( math.cos( pi_over_numSteps * n - math.pi ) ) #breathing function
            - min_offset ) * scaling_factor

    # NeoPixels library expects integer RGB values in the range [0,255]
    r,g,b = [ int(x * 255) for x in colorsys.hsv_to_rgb(h,s,v*scale) ]

    # pack the r,g,b values into one hex value
    rgb = str.format('0x{:06X}', (r << 16) + (g << 8) + b)
    sys.stdout.write("%s" % rgb)

    if n < numSteps - 1:
        sys.stdout.write(", ")

sys.stdout.write("\n};\n")
