16 Commits
v2.0 ... main

Author SHA1 Message Date
b1ae6e456d Added link to 2nd blog post in README. 2019-03-03 21:12:08 +01:00
7a729863b2 Reordered objects to be engraved to a single sublayer of 'frontplate'. 2019-02-21 12:34:16 +01:00
7cacedcf81 Removed hole from backplate - enough space in mid-layer (barrel) 2019-02-13 13:07:32 +01:00
d525635b14 Fixed minor issues in svg: repositioned numbers, fixed holes for input devices.
Added intermediate Files for direct laser usage - probably specific for the warpzone laser software.
2019-02-11 08:16:21 +01:00
42d39f2548 Moved input area out away from frontplate numbers. 2019-02-09 13:46:01 +01:00
ac691e196a Fixed error with barrel. 2019-02-08 15:03:35 +01:00
12ce5ad02f Added frontplate numbers, moved logos. 2019-02-08 14:58:54 +01:00
b3869b7314 Added logos for engraving. Still needs mounting holes/places for button/poti. 2019-02-07 15:33:11 +01:00
007407d2a1 Added Backplate and Arduino mounting holes as well as hidden (=green) Arduino Uno shapes. 2019-02-07 13:53:18 +01:00
6168a43384 Initial Form with "barrel" and frontplate. 2019-02-06 22:21:46 +01:00
86a7d401bd Added useful information and removed legacy stuff. 2019-02-05 18:43:23 +01:00
e4dfc3e6fe Fixed formatting of library links. 2019-02-03 20:16:08 +01:00
85ebffce1e Changed LED ring size back to sane default of 60. 2019-02-03 20:06:22 +01:00
e20dd310f9 Fixed disappearing hour / minute handles the dirty way. 2019-02-03 19:41:25 +01:00
e6a7f59f5c Removed RTClib reference 2019-02-03 00:10:36 +01:00
cbf6b79e73 Exchanged RTClib with NtpClientLib (currently branch develop)
added additional variables to constants.h
2019-02-02 23:54:59 +01:00
4 changed files with 25908 additions and 50 deletions

25805
Hardware/laser_template.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -1,13 +1,25 @@
# led-ring-clock # led-ring-clock
An Arduino-based analog clock using an WS2812B addressable RGB LED ring as a display. An Arduino-based analog clock using an WS2812B addressable RGB LED ring as a display.
This sketch requires the FastLED library, the Wire library (built-in), the EEPROM library (built-in), and the Adafruit RTClib. This sketch requires the FastLED library, the Wire library (built-in), the EEPROM library (built-in), and the NtpClientLib
(currently requires develop branch).
https://github.com/FastLED/FastLED
https://github.com/adafruit/RTClib https://github.com/FastLED/FastLED
### 3D-printable enclosure https://github.com/gmag11/NtpClient/tree/develop
Design files available on Thingiverse: https://www.thingiverse.com/thing:2730265
### 3D-printable enclosure for NeoPixel Ring (24 LEDs)
### Electronics information Design files available on Thingiverse: https://www.thingiverse.com/thing:2730265
The LED ring is connected to digital pin 3. Momentary N/O button is connected to digital pin 4 with 10K pullup resistor. 10K potentiometer is connected across power and ground and the wiper is connected to Analog 0. DS1307 RTC breakout is connected to the board's default I2C pins. This code has only been tested with an Adafruit 24 Neopixel Ring, but should (hopefully) work with any type or size of WS2812B ring, and with minimal changes it should work with rings using other types of RGB LEDs. The code should work on any ATmega328 based board.
### Electronics information
The LED ring is connected to digital pin 3. Momentary N/O button is connected to digital pin 5.
10K potentiometer is connected across power and ground and the wiper is connected to Analog 0.
This code has been tested with WS2812B LED Strips of up to 120 LEDs, but more should
be possible. With minimal changes it should work with rings using other types of RGB LEDs.
The code should work on any ATmega328 based board.
### Blog-Post with howto and more details (German)
https://www.commander1024.de/wordpress/2019/02/analoge-arduino-led-uhr/
### Blog-Post with hardware build instructions (German)
https://www.commander1024.de/wordpress/2019/02/bau-der-analogen-uhr/

View File

@@ -1,6 +1,7 @@
// //
// WS2812 LED Analog Clock Firmware // WS2812 LED Analog Clock Firmware
// Copyright (c) 2016-2018 jackw01 // Copyright (c) 2016-2018 jackw01
// NTP Changes: 2019 Commander1024
// This code is distrubuted under the MIT License, see LICENSE for details // This code is distrubuted under the MIT License, see LICENSE for details
// //
@@ -12,11 +13,19 @@
// IO Pin Assignments // IO Pin Assignments
const uint8_t pinLeds = 3; const uint8_t pinLeds = 3;
const uint8_t pinButton = 4; const uint8_t pinButton = 5;
const uint8_t pinBrightness = 0; const uint8_t pinBrightness = 0;
// Define MAC Address
byte mac[] = {
0xA8, 0x61, 0x0A, 0x10, 0x24, 0x01
};
// NTP Server to use
char* ntp_server = "warpfire.warpzone";
// Number of LEDs in ring // Number of LEDs in ring
const int ledRingSize = 24; const int ledRingSize = 60;
// Default colors - tweaked to look right on WS2812Bs // Default colors - tweaked to look right on WS2812Bs
const CRGB red = CRGB(255, 0, 0); const CRGB red = CRGB(255, 0, 0);
@@ -58,8 +67,8 @@ const int buttonClickRepeatDelayMs = 1500;
const int buttonLongPressDelayMs = 300; const int buttonLongPressDelayMs = 300;
// Serial // Serial
const long serialPortBaudRate = 115200; const long serialPortBaudRate = 9600;
const int debugMessageIntervalMs = 2000; const int debugMessageIntervalMs = 5000;
// Clock modes // Clock modes
typedef enum { typedef enum {

View File

@@ -1,20 +1,25 @@
// //
// WS2812 LED Analog Clock Firmware // WS2812 LED Analog Clock Firmware
// Copyright (c) 2016-2018 jackw01 // Copyright (c) 2016-2018 jackw01
// NTP Changes: 2019 Commander1024
// This code is distrubuted under the MIT License, see LICENSE for details // This code is distrubuted under the MIT License, see LICENSE for details
// //
#include <math.h> #include <math.h>
#include <FastLED.h> #include <FastLED.h>
#include <Wire.h>
#include <EEPROM.h> #include <EEPROM.h>
#include <RTClib.h> #include <TimeLib.h>
#include <NtpClientLib.h>
#include <SPI.h>
#include <EthernetUdp.h>
#include <Ethernet.h>
#include <Dns.h>
#include <Dhcp.h>
#include "constants.h" #include "constants.h"
// LED ring and RTC // LED ring size
CRGB leds[ledRingSize]; CRGB leds[ledRingSize];
RTC_DS1307 rtc;
// Globals to keep track of state // Globals to keep track of state
int clockMode, colorScheme; int clockMode, colorScheme;
@@ -26,23 +31,41 @@ uint8_t previousBrightness[16];
int lastSecondsValue = 0; int lastSecondsValue = 0;
uint32_t lastMillisecondsSetTime = 0; uint32_t lastMillisecondsSetTime = 0;
int milliseconds; int milliseconds;
DateTime now;
void setup() { void setup() {
// Begin serial port // Begin serial port
Serial.begin(serialPortBaudRate); Serial.begin(serialPortBaudRate);
// Initialize Network and NTP
if (Ethernet.begin (mac) == 0) {
Serial.println ("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
for (;;)
;
}
NTP.onNTPSyncEvent ([](NTPSyncEvent_t error) {
if (error) {
Serial.print ("Time Sync error: ");
if (error == noResponse)
Serial.println ("NTP server not reachable");
else if (error == invalidAddress)
Serial.println ("Invalid NTP server address");
} else {
Serial.print ("Got NTP time: ");
Serial.println (NTP.getTimeDateString (NTP.getLastNTPSync ()));
}
});
NTP.setInterval (60, 900);
NTP.setNTPTimeout (1000);
NTP.begin (ntp_server, 1, true);
// Init FastLED // Init FastLED
FastLED.addLeds<NEOPIXEL, pinLeds>(leds, ledRingSize); FastLED.addLeds<NEOPIXEL, pinLeds>(leds, ledRingSize);
FastLED.setTemperature(Halogen); FastLED.setTemperature(Halogen);
FastLED.show(); FastLED.show();
// Connect to the RTC
Wire.begin();
rtc.begin();
// Set button pin // Set button pin
pinMode(pinButton, INPUT); pinMode(pinButton, INPUT_PULLUP);
// Read saved config from EEPROM // Read saved config from EEPROM
colorScheme = EEPROM.read(eepromAddrColorScheme); colorScheme = EEPROM.read(eepromAddrColorScheme);
@@ -52,10 +75,13 @@ void setup() {
if (digitalRead(pinButton) == LOW) { if (digitalRead(pinButton) == LOW) {
for (int i = 0; i < ledRingSize; i++) leds[i] = white; for (int i = 0; i < ledRingSize; i++) leds[i] = white;
FastLED.show(); FastLED.show();
delay(60000); delay(10000);
} }
} }
static int i = 0;
static int last = 0;
void loop() { void loop() {
uint32_t currentTime = millis(); uint32_t currentTime = millis();
if (currentTime - lastLoopTime > runLoopIntervalMs) { if (currentTime - lastLoopTime > runLoopIntervalMs) {
@@ -94,8 +120,7 @@ void loop() {
FastLED.setBrightness(currentBrightness); FastLED.setBrightness(currentBrightness);
// Get time and calculate milliseconds value that is synced with the RTC's second count // Get time and calculate milliseconds value that is synced with the RTC's second count
now = rtc.now(); int currentSeconds = second(now());
int currentSeconds = now.second();
if (currentSeconds != lastSecondsValue) { if (currentSeconds != lastSecondsValue) {
lastSecondsValue = currentSeconds; lastSecondsValue = currentSeconds;
milliseconds = 0; milliseconds = 0;
@@ -107,6 +132,9 @@ void loop() {
// Show clock // Show clock
clearLeds(); clearLeds();
showClock(); showClock();
// Check/Renew DHCP
Ethernet.maintain ();
} }
} }
@@ -131,18 +159,17 @@ void showClock() {
// Print debugging info over serial // Print debugging info over serial
void printDebugMessage() { void printDebugMessage() {
Serial.print("Current date/time: "); Serial.print("Current date/time: ");
DateTime now = rtc.now(); Serial.print(year(now()), DEC);
Serial.print(now.year(), DEC);
Serial.print("/"); Serial.print("/");
Serial.print(now.month(), DEC); Serial.print(month(now()), DEC);
Serial.print("/"); Serial.print("/");
Serial.print(now.day(), DEC); Serial.print(day(now()), DEC);
Serial.print(" "); Serial.print(" ");
Serial.print(now.hour(), DEC); Serial.print(hour(now()), DEC);
Serial.print(":"); Serial.print(":");
Serial.print(now.minute(), DEC); Serial.print(minute(now()), DEC);
Serial.print(":"); Serial.print(":");
Serial.print(now.second(), DEC); Serial.print(second(now()), DEC);
Serial.println(); Serial.println();
Serial.print("Display mode: "); Serial.print("Display mode: ");
Serial.println(clockMode); Serial.println(clockMode);
@@ -160,7 +187,7 @@ void drawRingClock() {
float s = secondPosition(); float s = secondPosition();
if (m > h) { if (m > h) {
for (int i = 0; i < m; i++) setLed(i, minuteColor(), BlendModeOver, 1.0); for (int i = 0; i < m; i++) setLed(i, minuteColor(), BlendModeOver, 1.0);
for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver, 1.0); for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver, 1.0);
} else { } else {
for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver, 1.0); for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver, 1.0);
@@ -223,35 +250,40 @@ void drawDotClockGlow() {
// Get floating point hour representation // Get floating point hour representation
float floatHour() { float floatHour() {
return (float)now.hour() + mapFloat(now.minute() + mapFloat(now.second(), 0.0, 59.0, 0.0, 1.0), 0.0, 59.0, 0.0, 1.0); return (float)hour(now()) + mapFloat(minute(now()) + mapFloat(second(now()), 0.0, 59.0, 0.0, 1.0), 0.0, 59.0, 0.0, 1.0);
} }
// Get positions mapped to ring size // Get positions mapped to ring size
float hourPosition() { float hourPosition() {
if (twelveHour) { if (twelveHour) {
int hour; int hourt;
if (now.hour() > 12) hour = (now.hour() - 12) * (ledRingSize / 12);
else hour = now.hour() * (ledRingSize / 12); if (hour(now()) > 12) hourt = (hour(now()) - 12) * (ledRingSize / 12);
return hour + mapFloat(now.minute(), 0.0, 59.0, 0.0, (ledRingSize / 12.0) - 1.0); else hourt = hour(now()) * (ledRingSize / 12);
return hourt + mapFloat(minute(now()) + 0.001, 0.0, 59.0, 0.0, (ledRingSize / 12.0) - 1.0);
} else { } else {
int hour = now.hour() * (ledRingSize / 24); int hourt = hour(now()) * (ledRingSize / 24);
return hour + mapFloat(now.minute(), 0, 59, 0, (ledRingSize / 24.0) - 1.0); return hourt + mapFloat(minute(now()) + 0.001, 0, 59, 0, (ledRingSize / 24.0) - 1.0);
} }
} }
float minutePosition() { float minutePosition() {
return mapFloat((float)now.minute() + ((1.0 / 60.0) * (float)now.second()), 0.0, 59.0, 0.0, (float)ledRingSize); return mapFloat(
(float)minute(now()) + ((0.001 + 1.0 / 60.0) * (float)second(now())), 0.0, 59.0, 0.0, (float)ledRingSize
);
} }
float secondPosition() { float secondPosition() {
return mapFloat(now.second() + (0.001 * milliseconds), 0.0, 60.0, 0.0, (float)ledRingSize); return mapFloat(
second(now()) + (0.001 * milliseconds), 0.0, 60.0, 0.0, (float)ledRingSize
);
} }
// Get colors // Get colors
CRGB hourColor() { CRGB hourColor() {
if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][0]; if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][0];
else if (colorScheme == colorSchemeCount + 0) { else if (colorScheme == colorSchemeCount + 0) {
return CHSV(map(now.hour(), 0, 24, 0, 255), 255, 255); return CHSV(map(hour(now()), 0, 24, 0, 255), 255, 255);
} else if (colorScheme == colorSchemeCount + 1) { } else if (colorScheme == colorSchemeCount + 1) {
return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255); return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255);
} }
@@ -260,7 +292,7 @@ CRGB hourColor() {
CRGB minuteColor() { CRGB minuteColor() {
if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][1]; if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][1];
else if (colorScheme == colorSchemeCount + 0) { else if (colorScheme == colorSchemeCount + 0) {
return CHSV(map(now.minute(), 0, 59, 0, 255), 255, 255); return CHSV(map(minute(now()), 0, 59, 0, 255), 255, 255);
} else if (colorScheme == colorSchemeCount + 1) { } else if (colorScheme == colorSchemeCount + 1) {
return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255); return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255);
} }
@@ -269,7 +301,7 @@ CRGB minuteColor() {
CRGB secondColor() { CRGB secondColor() {
if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][2]; if (colorScheme < colorSchemeCount) return colorSchemes[colorScheme][2];
else if (colorScheme == colorSchemeCount + 0) { else if (colorScheme == colorSchemeCount + 0) {
return CHSV(map(now.second(), 0, 59, 0, 255), 255, 255); return CHSV(map(second(now()), 0, 59, 0, 255), 255, 255);
} else if (colorScheme == colorSchemeCount + 1) { } else if (colorScheme == colorSchemeCount + 1) {
return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255); return CHSV((uint8_t)mapFloat(fmod(20.0 - floatHour(), 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255);
} }