#include <FastLED.h>
/* #include <OneWire.h>
#include <DallasTemperature.h> */
#define ARM_LEDS 90
#define PULSE_LEDS 175
#define RING_LEDS 12
#define BRIGHTNESS 255
#define ARM_1_LED_PIN 10
#define ARM_2_LED_PIN 11
#define ARM_3_LED_PIN 12
#define PULSE_LED_PIN 11
#define RING_LED_PIN 12
#define TEMP_CHANGE 2
#define POTENTIOMETER_TEMP A5
#define POTENTIOMETER_PIN_FADE A4
#define POTENTIOMETER_PIN_HUE A3
CRGB armLeds1[ARM_LEDS];
CRGB pulseLeds[PULSE_LEDS];
CRGB noisePulseLeds[PULSE_LEDS];
CRGB ringLeds[RING_LEDS];
/* OneWire oneWireChange(TEMP_CHANGE);
DallasTemperature sensorsChange(&oneWireChange); */
unsigned long lastPositiveReadingTime = 0;
uint8_t maxBrightness = BRIGHTNESS;
uint8_t currentBrightness = maxBrightness;
uint16_t idleTime = 5000;
uint16_t x1 = 0;
uint16_t x2 = 0;
uint16_t x3 = 0;
float zeroPoint = 0; // Variable to store the zero point temperature
float lastTemp = 0; // Variable to store the last temperature of sensor two
float accumulatedDifference = 0; // Variable to store the accumulated temperature difference
float currentTemp = 0;
uint8_t bloodHue = 255; // Blood color [hue from 0-255]
uint8_t bloodSat = 255; // Blood staturation [0-255]
int flowDirection = -1; // Use either 1 or -1 to set flow direction
uint16_t cycleLength = 2000; // Lover values = continuous flow, higher values = distinct pulses.
uint16_t pulseLength = 500; // How long the pulse takes to fade out. Higher value is longer.
uint16_t pulseOffset = 500; // Delay before second pulse. Higher value is more delay.
uint8_t baseBrightness = 30; // Brightness of LEDs when not pulsing. Set to 0 for off.
uint8_t potValueFade = 20;
uint8_t potValueHue = 50;
uint8_t potTemp = 8;
// Pulse
float y = 0; // Position in the sine wave, analogous to time
const float sinRes = 5.0; // Resolution of the sine wave, controls the frequency
float speed = 3.0;
uint16_t resetInterval = 5000;
float sin1;
float sin2;
float sin3;
// Define a palette.
DEFINE_GRADIENT_PALETTE(NorthernLightsPalette) {
0, 0, 207, 82, // Colder colors
62, 3, 46, 62,
143, 25, 100, 106,
192, 0, 198, 144,
255, 0, 223, 150
};
DEFINE_GRADIENT_PALETTE(WarmNorthernLightsPalette) {
0, 255, 40, 5, // Warmer reds and oranges
62, 255, 60, 5,
143, 255, 80, 0,
180, 255, 100, 0,
200, 255, 0, 0,
255, 255, 0, 0
};
CRGBPalette16 currentPalette = CRGBPalette16(NorthernLightsPalette);
CRGBPalette16 warmPalette = CRGBPalette16(WarmNorthernLightsPalette);
void setup() {
FastLED.addLeds<WS2811, ARM_1_LED_PIN, BRG>(armLeds1, ARM_LEDS);
FastLED.addLeds<WS2811, PULSE_LED_PIN, BRG>(pulseLeds, PULSE_LEDS);
FastLED.addLeds<WS2811, RING_LED_PIN, GRB>(ringLeds, RING_LEDS);
FastLED.setBrightness(BRIGHTNESS);
Serial.begin(115200);
/* sensorsChange.begin();
sensorsChange.setResolution(9); */
/* sensorsChange.requestTemperatures(); */
currentTemp = map(analogRead(POTENTIOMETER_TEMP), 0, 1023, 0, 15);
lastTemp = currentTemp; // Initialize the last temperature
}
void loop() {
// Read the potentiometer values
/* int potValueFade = map(analogRead(POTENTIOMETER_PIN_FADE), 0, 1023, 0, 50);
int potValueHue = map(analogRead(POTENTIOMETER_PIN_HUE), 0, 1023, 0, 255);
int potTemp = map(analogRead(POTENTIOMETER_TEMP), 0, 1023, 2, 15); */
cycleLength = map(accumulatedDifference * 100, 0, potTemp * 100, 2500, 1500);
pulseOffset = map(accumulatedDifference * 100, 0, potTemp * 100, 500, 800);
bloodSat = map(accumulatedDifference * 100, 0, potTemp * 100, 100, 255);
if (accumulatedDifference > 0.5) {
flowDirection = -1;
} else {
flowDirection = 1;
}
tempChange();
EVERY_N_MILLISECONDS(50) {
int hueValue;
int speed1;
hueValue = map(accumulatedDifference * 100, 0, potTemp * 100, potValueHue, 255);
speed1 = calculateSpeed(accumulatedDifference * 100, 1, potTemp * 100);
heartBeat();
fill_noise(ARM_LEDS, armLeds1, x1, hueValue, potValueFade);
if (accumulatedDifference > 1) {
fill_noise(PULSE_LEDS, noisePulseLeds, -x1, hueValue, 0);
} else {
fill_noise(PULSE_LEDS, noisePulseLeds, x1, hueValue, 0);
}
for (int i = 0; i < PULSE_LEDS; i++) {
uint8_t r = pulseLeds[i].red;
pulseLeds[i] = blend(noisePulseLeds[i].nscale8(30), pulseLeds[i], r); // Example: 50% blend
}
// Get the average color of armLeds1
CRGB averageColor = getAverageColor(armLeds1, ARM_LEDS);
// Set all ringLeds to the average color
for (int i = 0; i < 12; i++) {
ringLeds[i] = averageColor;
}
// Update offsets for each strip
x1 += speed1;
}
pulseEffect();
FastLED.show();
}
void fill_noise(int LEDS, CRGB* leds, int x_offset, int valueHue, int fade) {
uint8_t blendFactor = valueHue;
int fadeLength = fade; // Number of LEDs to fade in and out
for (int i = LEDS - 1; i >= 0; i--) { // Reverse iteration
uint8_t noise = inoise8(i * 15 + x_offset, 0, i * 15 + x_offset);
CRGB color1 = ColorFromPalette(currentPalette, noise);
CRGB color2 = ColorFromPalette(warmPalette, noise);
CRGB blendedColor = blend(color1, color2, blendFactor);
int reverseIndex = LEDS - i - 1; // Calculate the reverse index
uint8_t linearFadeFactor = 255;
bool isFading = false;
// Fade out logic at the end of the strip
if (i < fadeLength) {
linearFadeFactor = map(i, fadeLength - 1, 0, 255, 0);
isFading = true;
}
if (isFading) {
// Apply dripping effect only in fade areas
uint8_t noiseFade = inoise8(reverseIndex * 125 - x_offset, 0, reverseIndex * 125 + x_offset);
int noiseFadeFactor = map(noiseFade, 0, 255, 0, linearFadeFactor);
blendedColor.nscale8(noiseFadeFactor);
} else {
// No dripping effect outside fade areas
blendedColor.nscale8(linearFadeFactor);
}
leds[reverseIndex] = blendedColor; // Assigning color in reverse
}
}
CRGB getAverageColor(CRGB* leds, int numLeds) {
unsigned long totalR = 0, totalG = 0, totalB = 0;
for (int i = 0; i < numLeds; i++) {
totalR += leds[i].r;
totalG += leds[i].g;
totalB += leds[i].b;
}
CRGB averageColor(totalR / numLeds, totalG / numLeds, totalB / numLeds);
return averageColor;
}
int calculateSpeed(int difference, int stripNumber, int potValue) {
switch (stripNumber) {
case 1: return map(difference, 0, potValue, 10, 40);
case 2: return map(difference, 0, potValue, 15, 45);
case 3: return map(difference, 0, potValue, 20, 60);
default: return 3;
}
}
// Function for generating a heartbeat/pulse effect
void heartBeat() {
for (int i = 0; i < PULSE_LEDS; i++) {
uint8_t bloodVal = sumPulse((5 / PULSE_LEDS / 2) + (PULSE_LEDS / 2) * i * flowDirection);
pulseLeds[i] = CHSV(bloodHue, bloodSat, bloodVal);
}
}
int sumPulse(int time_shift) {
int pulse1 = pulseWave8(millis() / 3 + time_shift, cycleLength, pulseLength);
int pulse2 = pulseWave8(millis() / 3 + time_shift + pulseOffset, cycleLength, pulseLength);
return qadd8(pulse1, pulse2); // Add pulses together without overflow
}
uint8_t pulseWave8(uint32_t ms, uint16_t cycleLength, uint16_t pulseLength) {
uint16_t T = ms % cycleLength;
if (T > pulseLength) return baseBrightness;
uint16_t halfPulse = pulseLength / 2;
if (T <= halfPulse) {
return (T * 255) / halfPulse; //first half = going up
} else {
return ((pulseLength - T) * 255) / halfPulse; //second half = going down
}
}
void pulseEffect() {
static unsigned long lastResetTime = 0; // Stores the last time 'y' was reset
resetInterval = map(accumulatedDifference * 100, 0, potTemp * 100, 5000, 1500);
// Calculate the sine values as before
sin1 = sin(HALF_PI + y / sinRes);
sin2 = sin(y / (sinRes * 4));
sin3 = sin(PI + y / (sinRes * 8));
// Use the sine values to adjust brightness, as before
if (y < 100) {
if (sin2 > 0 && sin3 < 0) {
FastLED.setBrightness(map((sin1 + 1) * 100, 0, 200, 50, 255));
}
y += speed;
}
// Check if it's time to reset 'y'
if (millis() - lastResetTime >= resetInterval) {
y = 0; // Reset 'y'
lastResetTime = millis(); // Update the last reset time to the current time
}
}
void tempChange() {
currentTemp = map(analogRead(POTENTIOMETER_TEMP), 0, 1023, 0, 15);
// Calculate the difference since the last reading
float differenceSinceLast = max(currentTemp - lastTemp, 0.0);
// Check if the temperature has increased
if (differenceSinceLast >= 0.15) {
// Increase accumulatedDifference but do not exceed potTemp
accumulatedDifference += differenceSinceLast;
lastPositiveReadingTime = millis();
if (accumulatedDifference >= potTemp) {
accumulatedDifference = potTemp; // Cap accumulatedDifference at potTemp
}
} else if ((differenceSinceLast == 0) && (millis() - lastPositiveReadingTime > idleTime)) {
// Decrease accumulatedDifference, prevent it from going below 0
accumulatedDifference -= 0.15; // Adjust this value as needed
if (accumulatedDifference <= 0) {
accumulatedDifference = 0; // Prevent negative values
}
}
// Update the last temperature
lastTemp = currentTemp;
}