// Townhouse dollhouse lighting, Arduino Uno R3, discrete zone outputs (no addressable data line). // Each zone = one PWM pin -> 1k -> PN2222 base; transistor sinks that zone's LEDs to ground. // Each LED has its own ~200-220 ohm series resistor: +5V -> LED -> R -> transistor collector. // FIRE zone uses a RED LED; all other zones warm-white/white. (Color is hardware only, no code change.) // No library needed. #define PIN_GF 3 // ground-floor interior (living + kitchen ceilings) -> Q1 base via 1k #define PIN_UP 5 // upstairs interior (bedrooms + attic) -> Q2 base via 1k #define PIN_EXT 6 // exterior (porch, entry, deck, balcony) -> Q3 base via 1k #define PIN_FIRE 9 // fireplace / hearth (red) -> Q4 base via 1k #define BTN_PIN 2 // momentary button to GND: cycles scenes / wakes #define BTN_SECT 4 // momentary button to GND: spotlight one zone at a time (GF->UP->EXT->FIRE->off) #define IDLE_OFF_MS (20UL * 60UL * 1000UL) // cordless: fade dark after 20 min idle // Per-zone brightness 0-255. Dollhouse rooms read best DIM, this is your knob // (or raise the LED series resistors to knock brightness back in hardware). uint8_t gGF, gUP, gEXT; bool fireOn; // ---- Scenes --------------------------------------------------------------- void sceneEvening(){ gGF = 60; gUP = 40; gEXT = 140; fireOn = true; } // cozy, fire lit void sceneAllOn() { gGF = 90; gUP = 90; gEXT = 120; fireOn = true; } void sceneNight() { gGF = 0; gUP = 0; gEXT = 30; fireOn = true; } // porch + embers void sceneOff() { gGF = 0; gUP = 0; gEXT = 0; fireOn = false; } typedef void (*Scene)(); Scene scenes[] = {sceneEvening, sceneAllOn, sceneNight, sceneOff}; const uint8_t N_SCENES = sizeof(scenes) / sizeof(scenes[0]); uint8_t sceneIdx = 0; unsigned long lastActive = 0; // ---- Section spotlight ---------------------------------------------------- // BTN_SECT lights exactly ONE zone at a time, then all off, then repeats. uint8_t sectIdx = 0; // 0=GF 1=UP 2=EXT 3=FIRE 4=all off const uint8_t N_SECT = 5; void applySpotlight(uint8_t i){ gGF = (i == 0) ? 90 : 0; gUP = (i == 1) ? 90 : 0; gEXT = (i == 2) ? 120 : 0; fireOn = (i == 3); } void setup() { pinMode(PIN_GF, OUTPUT); pinMode(PIN_UP, OUTPUT); pinMode(PIN_EXT, OUTPUT); pinMode(PIN_FIRE, OUTPUT); pinMode(BTN_PIN, INPUT_PULLUP); pinMode(BTN_SECT, INPUT_PULLUP); // Power-on self-check: pulse each output in turn, so a dead zone shows itself immediately. const uint8_t pins[] = {PIN_GF, PIN_UP, PIN_EXT, PIN_FIRE}; for (uint8_t i = 0; i < 4; i++) { analogWrite(pins[i], 120); delay(220); analogWrite(pins[i], 0); } scenes[sceneIdx](); lastActive = millis(); } void loop() { // Button: cycle scene + reset idle timer. static bool prev = HIGH; bool now = digitalRead(BTN_PIN); if (prev == HIGH && now == LOW) { sceneIdx = (sceneIdx + 1) % N_SCENES; scenes[sceneIdx](); lastActive = millis(); delay(30); // debounce } prev = now; // Section button: spotlight one zone at a time (GF -> UP -> EXT -> FIRE -> off). static bool prevS = HIGH; bool nowS = digitalRead(BTN_SECT); if (prevS == HIGH && nowS == LOW) { sectIdx = (sectIdx + 1) % N_SECT; applySpotlight(sectIdx); lastActive = millis(); delay(30); // debounce } prevS = nowS; // Cordless battery saver. if (millis() - lastActive > IDLE_OFF_MS) sceneOff(); analogWrite(PIN_GF, gGF); analogWrite(PIN_UP, gUP); analogWrite(PIN_EXT, gEXT); // Fireplace: amber-ish flicker around a low base when on. analogWrite(PIN_FIRE, fireOn ? (55 + random(0, 130)) : 0); delay(30); // ~33 Hz, smooth flicker, snappy button }