Below is a concise description of how the sketch turns an ATtiny85 + WS2812 strip into a temperature‐sensing thermometer with ambient‐light–adjusted brightness.
- Hardware Setup (fully configurable in code)
• WS2812 strip on PB0 → DATA. You chooseNUM_LEDS(e.g. 60) and color order (GRB).
• Thermistor divider on PB2 → NTC. You set the fixed resistor value (R_SERIES), the NTC’s nominal resistance (R_NOMINAL), nominal temperature (T_NOMINAL), and B-coefficient (B_COEFF).
• Photoresistor (LDR) divider on PB3 → LDR. You configure the series resistor (R_LDR_SERIES), nominal lux (LUX_NOMINAL), and LDR gamma (LDR_GAMMA).
• Power rails: VCC = +5 V, GND = 0 V.

- ADC Reference
• UsesanalogReference(DEFAULT)so ADC measures 0…VCC.
• All voltage-conversion factors use theVCCconstant (e.g. 5.0 V). - Temperature Measurement (fully parameterized)
•analogRead(NTC_PIN)→ voltage → resistance viaR_SERIES.
• Steinhart–Hart B-parameter equation with yourR_NOMINAL,T_NOMINAL,B_COEFFto compute °C.
• Normalizes betweenT_MINandT_MAXinto a 0.0…1.0 fraction. - LED Mapping (user-settable)
• Computes LED index:round(fraction * (NUM_LEDS - 1)).
• Picks hue: interpolates betweenHUE_LOW(cold) andHUE_HIGH(hot). - Ambient-Light & Brightness (fully adjustable)
•analogRead(LDR_PIN)→ voltage → resistance viaR_LDR_SERIES.
• Converts to lux using yourLUX_NOMINALandLDR_GAMMA.
• Constrains lux to[LUX_MIN, LUX_MAX]and maps to brightness[BRIGHT_MIN, BRIGHT_MAX].
• Disables “glow” when lux exceedsLUX_GLOW_OFF. - Glow Effect (configurable)
• RadiusGLOW_SIZELEDs on each side of the main “thermometer” LED.
• Fall-off per step viaGLOW_FALLOFF(exponential). - Update Loop
• Runs everyUPDATE_MSmilliseconds (e.g. 5000 ms) to smooth sensor readings and LED updates.
All key parts—LED count, resistor values, thermistor characteristics, lux mapping, glow radius—are declared as constants at the top of the sketch so you can easily adapt this thermometer to different hardware or sensitivity requirements.
#include <FastLED.h>
/* ───────── CONFIGURATION ───────── */
// Choose display units:
// false → show °C
// true → show °F
#define DISPLAY_FAHRENHEIT false
// LED strip
#define NUM_LEDS 60
#define DATA_PIN 0 // PB0
#define CHIPSET WS2811
#define COLOR_ORDER GRB
// ADC reference & supply voltage
#define ADC_REF DEFAULT
const float VCC = 5.0f;
// Thermistor (10 kΩ NTC) on PB2 (A1)
#define NTC_PIN A1
const float R_SERIES = 10000.0f;
const float R_NOMINAL = 10000.0f;
const float T_NOMINAL = 25.0f;
const float B_COEFF = 3950.0f;
// Temperature range for color mapping
// These are in °C; if DISPLAY_FAHRENHEIT is true,
// they’ll be converted to °F automatically.
const float T_MIN = -15.0f; // bottom of strip
const float T_MAX = 40.0f; // top of strip
const uint8_t HUE_LOW = 160; // green at cold
const uint8_t HUE_HIGH = 0; // red at hot
// Ambient‐light sensor (LDR) on PB3 (A3)
#define LDR_PIN A3
const float R_LDR_SERIES = 10000.0f;
const float R_LDR_NOMINAL = 10000.0f;
const float LUX_NOMINAL = 10.0f;
const float LDR_GAMMA = 0.8f;
// Brightness mapping
const float LUX_MIN = 0.0f;
const float LUX_MAX = 500.0f;
const uint8_t BRIGHT_MIN = 5;
const uint8_t BRIGHT_MAX = 255;
const float LUX_GLOW_OFF = 60.0f;
// Glow effect
const uint8_t GLOW_SIZE = 1;
const float GLOW_FALLOFF = 0.08f;
// Update interval
const unsigned long UPDATE_MS = 5000;
CRGB leds[NUM_LEDS];
unsigned long lastUpdate = 0;
void setup() {
analogReference(ADC_REF);
FastLED.addLeds<CHIPSET, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHT_MAX);
FastLED.clear();
FastLED.show();
}
void loop() {
if (millis() - lastUpdate < UPDATE_MS) return;
lastUpdate = millis();
// 1) Read temperature in °C
int rawT = analogRead(NTC_PIN);
float vT = rawT * (VCC / 1023.0f);
float rT = R_SERIES * (VCC / vT - 1.0f);
float inv = 1.0f / (T_NOMINAL + 273.15f) + log(rT / R_NOMINAL) / B_COEFF;
float tempC = 1.0f / inv - 273.15f;
// 2) Possibly convert to °F
float temp = DISPLAY_FAHRENHEIT
? (tempC * 9.0f / 5.0f + 32.0f)
: tempC;
// 3) Determine mapping range
float minT = T_MIN;
float maxT = T_MAX;
if (DISPLAY_FAHRENHEIT) {
minT = T_MIN * 9.0f / 5.0f + 32.0f;
maxT = T_MAX * 9.0f / 5.0f + 32.0f;
}
// 4) Normalize temperature to [0…1]
float f = constrain((temp - minT) / (maxT - minT), 0.0f, 1.0f);
// 5) Read ambient light & set brightness/glow
int rawL = analogRead(LDR_PIN);
float vL = rawL * (VCC / 1023.0f);
float rLDR = R_LDR_SERIES * (VCC / vL - 1.0f);
float lux = LUX_NOMINAL * powf(rLDR / R_LDR_NOMINAL, -1.0f / LDR_GAMMA);
lux = constrain(lux, LUX_MIN, LUX_MAX);
uint8_t globalB = map(int(lux * 10),
int(LUX_MIN * 10), int(LUX_MAX * 10),
BRIGHT_MIN, BRIGHT_MAX);
FastLED.setBrightness(globalB);
uint8_t glow = (lux < LUX_GLOW_OFF) ? GLOW_SIZE : 0;
// 6) Draw thermometer bar
FastLED.clear();
int idx = int(round(f * (NUM_LEDS - 1)));
uint8_t hue = uint8_t(round(HUE_LOW + f * (HUE_HIGH - HUE_LOW)));
for (int d = -int(glow); d <= int(glow); d++) {
int i = idx + d;
if (i < 0 || i >= NUM_LEDS) continue;
float scale = powf(GLOW_FALLOFF, fabsf((float)d));
leds[i] = CHSV(hue, 255, 255);
leds[i].nscale8_video(uint8_t(scale * 255));
}
FastLED.show();
}