Compare commits

..

No commits in common. "8323450957635bb5f049ccc32e7e0b3a3b2918a2" and "e702145635de763d9d50d2bb56e38d8db123253c" have entirely different histories.

5 changed files with 102 additions and 102 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
build/

View File

@ -1,52 +1,5 @@
PACKAGE = holiday-lights
#FQBN = adafruit:samd:adafruit_trinket_m0
FQBN = adafruit:avr:protrinket5
FQBN_QTPY = adafruit:samd:adafruit_qtpy_m0
FQBN_XIAO = Seeeduino:samd:seeed_XIAO_m0
UF2_MOUNT = /mnt/chromeos/removable/Arduino
ARDUINO_DIR = /app/Arduino
BUILDER = flatpak run --command ${ARDUINO_DIR}/arduino-builder cc.arduino.arduinoide
default: build/$(PACKAGE).qtpy.uf2 build/$(PACKAGE).xiao.uf2
install: build/$(PACKAGE).xiao.uf2
./install.sh $< $(UF2_MOUNT)
clean:
rm -rf build/*
# uf2conv.py is covered by an MIT license.
build/uf2conv.py: build/uf2families.json
mkdir -p build
curl -L https://raw.githubusercontent.com/microsoft/uf2/master/utils/$(@F) > $@
chmod +x $@
build/uf2families.json:
mkdir -p build
curl -L https://raw.githubusercontent.com/microsoft/uf2/master/utils/$(@F) > $@
%.xiao.uf2: %.xiao.bin build/uf2conv.py
build/uf2conv.py -b 0x2000 -c -o $@ $<
%.qtpy.uf2: %.qtpy.bin build/uf2conv.py
build/uf2conv.py -b 0x2000 -c -o $@ $<
build/%.qtpy.bin: FQBN = $(FQBN_QTPY)
build/%.xiao.bin: FQBN = $(FQBN_XIAO)
build/$(PACKAGE).%.bin: $(PACKAGE).ino *.cpp *.h
mkdir -p build/$*
arduino-builder \
-build-cache ~/.cache/arduino \
-build-path build/$* \
-core-api-version 10813 \
-fqbn $(FQBN) \
-hardware ~/.arduino15/packages \
-tools $(ARDUINO_DIR)/tools-builder \
-tools ~/.arduino15/packages \
-hardware $(ARDUINO_DIR)/hardware \
-hardware ~/.arduino15/packages \
-built-in-libraries $(ARDUINO_DIR)/libraries \
-libraries ~/Arduino/libraries \
-compile \
$<
mv build/$*/$(<F).bin $@
upload: $(PACKAGE).ino
arduino --upload --board $(FQBN) $<
install: holiday-lights.ino
arduino --upload --board $(FQBN) $@

View File

@ -3,8 +3,6 @@ Holiday Lights
Some twinkling lights for your tree/menorah/office/door/roof/habitrail.
The canonical home for this code is https://git.woozle.org/neale/holiday-lights
Materials
---------

View File

@ -1,20 +1,39 @@
#if defined(__AVR_ATtiny85__)
#define TINY
#endif
#include <FastLED.h>
#include "Debounce.h"
#include "durations.h"
#include "morse.h"
#include "pulse.h"
// Which pins your LED strips are connected to
#define NUM_OUTPUTS 2
#define OUTPUT_PIN1 7
#define OUTPUT_PIN2 8
// Do you want it to run forever, or cycle every 24 hours?
#ifdef TINY
#define FOREVER true
#else
#define FOREVER false
#endif
// Which pin your LED strip is connected to
#if defined(TINY)
#define NEOPIXEL_PIN 3
#elif defined(ADAFRUIT_TRINKET_M0)
#define NEOPIXEL_PIN 2
#else
#define NEOPIXEL_PIN 6
#endif
// Which pin has the momentary switch to toggle full white.
#define BUTTON_PIN 4
// How many LEDs you have per output. It's okay if this is too big.
// How many LEDs you have. It's okay if this is too big.
#define LEDS_PER_GROUP 10
#define NUM_GROUPS 10
#ifdef TINY
#define NUM_GROUPS 7
#else
#define NUM_GROUPS 20
#endif
#define NUM_LEDS (LEDS_PER_GROUP * NUM_GROUPS)
// How many milliseconds between activity in one group
@ -33,22 +52,33 @@
// How long a dit lasts
#define DIT_DURATION_MS 150
// Color for all-white mode
#define WHITE 0x886655
// The Neopixel library masks interrupts while writing.
// This means you lose time.
// How much time do you lose?
// I'm guessing 10 minutes a day.
#define SNOSSLOSS_DAY (DURATION_DAY - (10 * DURATION_MINUTE))
#define ON_FOR (6 * DURATION_HOUR)
#define ARK "\x03\x04"
const char *message = (
"seasons greetings" ARK
"happy holiday" ARK
"merry xmas" ARK
"happy new year" ARK
"CQ CQ OF9X" ARK
);
CRGB leds[NUM_OUTPUTS][NUM_LEDS];
CRGB leds[NUM_LEDS];
Debounce button(BUTTON_PIN, false, true);
void setup() {
FastLED.addLeds<WS2812, OUTPUT_PIN1, RGB>(leds[0], NUM_LEDS);
FastLED.addLeds<WS2812, OUTPUT_PIN2, RGB>(leds[1], NUM_LEDS);
FastLED.setTemperature(Tungsten40W);
FastLED.addLeds<WS2812, NEOPIXEL_PIN, RGB>(leds, NUM_LEDS);
FastLED.setBrightness(52);
pinMode(LED_BUILTIN, OUTPUT);
}
@ -70,59 +100,94 @@ uint8_t RandomHue() {
}
}
Pulse mainPulse = Pulse(DELAY_MS);
bool strandUpdate(unsigned long now, bool white) {
static Pulse pulse = Pulse(DELAY_MS);
if (!pulse.Ticked(now)) {
if (!mainPulse.Ticked(now)) {
return false;
}
for (int output = 0; output < NUM_OUTPUTS; output += 1) {
for (int group = 0; group < NUM_GROUPS; group += 1) {
for (int group = 0; group < NUM_GROUPS; ++group) {
int pos = (group * LEDS_PER_GROUP) + random(LEDS_PER_GROUP);
if (random(100) < GROUP_UPDATE_PROBABILITY) {
uint8_t hue = 0;
uint8_t saturation = white?0:255;
uint8_t saturation = 255;
uint8_t value = 255;
if (random(100) < ACTIVITY) {
if (white) {
saturation = 0;
} else {
hue = RandomHue();
}
} else {
value = 0;
}
leds[output][pos] = CHSV(hue, saturation, value);
leds[pos] = CHSV(hue, saturation, value);
group = (group + 1) % NUM_GROUPS;
}
}
return true;
}
bool black(unsigned long now) {
if (!mainPulse.Ticked(now)) {
return false;
}
FastLED.clear();
return true;
}
bool morseUpdate(unsigned long now) {
static MorseEncoder enc;
static Pulse pulse = Pulse(DIT_DURATION_MS);
if (!pulse.Ticked(now)) {
return false;
}
bool ret = false;
if (pulse.Ticked(now)) {
if (!enc.Tick()) {
enc.SetText(message);
}
leds[0][MORSE_PIXEL] = enc.Transmitting ? MORSE_COLOR : CRGB::Black;
ret = true;
}
leds[MORSE_PIXEL] = enc.Transmitting ? MORSE_COLOR : CRGB::Black;
return true;
return ret;
}
bool timeUpdate(unsigned long now, unsigned long timeLeft) {
unsigned int hoursLeft = timeLeft / DURATION_HOUR;
unsigned int minutesLeft = (timeLeft / DURATION_MINUTE) % 60;
int i;
for (i = 0; i < hoursLeft; ++i) {
leds[i] = CHSV(0, 255, 32);
}
if ((timeLeft / DELAY_MS) % minutesLeft == 0) {
leds[i]= CHSV(0, 255, 32);
} else {
leds[i] = CRGB::Black;
}
return false;
}
void loop() {
bool white = false;
bool update = false;
unsigned long now = millis(); // Everybody uses the same time so we don't do spurious updates 5ms apart
unsigned long timeOfDay = now % DURATION_DAY;
button.read();
white = (button.count() % 2 == 1);
if (FOREVER || white || (timeOfDay < ON_FOR)) {
update |= strandUpdate(now, white);
//update |= morseUpdate(now);
update |= morseUpdate(now);
} else {
update |= black(now);
update |= timeUpdate(now, DURATION_DAY - timeOfDay);
}
if (update) {
FastLED.show();

View File

@ -1,15 +0,0 @@
#! /bin/sh
src=$1
dst=$2
info=$dst/INFO_UF2.txt
echo -n "Waiting for $info to appear..."
while ! [ -f $info ]; do
echo -n "."
sleep 1
done
echo "👍"
cp $src $dst
echo "Installed!"