Compare commits

..

2 Commits

Author SHA1 Message Date
Neale Pickett 8323450957 Move to gitea 2023-12-31 10:17:53 -07:00
Neale Pickett 837932c257 Attempt to automate build 2023-12-31 10:11:55 -07:00
5 changed files with 102 additions and 102 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -1,5 +1,52 @@
#FQBN = adafruit:samd:adafruit_trinket_m0 PACKAGE = holiday-lights
FQBN = adafruit:avr:protrinket5
install: holiday-lights.ino FQBN_QTPY = adafruit:samd:adafruit_qtpy_m0
arduino --upload --board $(FQBN) $@ 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) $<

View File

@ -3,6 +3,8 @@ Holiday Lights
Some twinkling lights for your tree/menorah/office/door/roof/habitrail. 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 Materials
--------- ---------

View File

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

15
install.sh Executable file
View File

@ -0,0 +1,15 @@
#! /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!"