summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremias Stotter <jeremias@stotter.eu>2022-07-06 10:23:31 +0200
committerJeremias Stotter <jeremias@stotter.eu>2022-07-06 10:23:31 +0200
commit884b776973d2be0c9e6b443435d418cc121a74f2 (patch)
tree36927efd6e4e3ccdeafa073db24dd21bd8a904dd
downloadalarmclock-master.tar.gz
alarmclock-master.tar.bz2
alarmclock-master.zip
Initial commitHEADmaster
-rw-r--r--alarmclock.ino433
-rw-r--r--case.scad221
2 files changed, 654 insertions, 0 deletions
diff --git a/alarmclock.ino b/alarmclock.ino
new file mode 100644
index 0000000..a7aa8c9
--- /dev/null
+++ b/alarmclock.ino
@@ -0,0 +1,433 @@
+#include <RTClib.h>
+#include <LiquidCrystal.h>
+
+#include <time.h>
+
+#define TRUE 1
+#define FALSE 1
+
+// Pins
+#define JOY_X A0
+#define JOY_Y A1
+#define JOY_BTN 22
+int JoyX, JoyY;
+int JoyBtn;
+int JoyDirection;
+
+#define SOUND 50
+bool Sound;
+
+#define BUZZER 45
+
+#define D4 30
+#define D5 31
+#define D6 32
+#define D7 33
+#define RS 38
+#define E 39
+
+RTC_DS1307 rtc;
+
+LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
+
+byte clock_symbol[8] = {
+ B00000,
+ B10001,
+ B01110,
+ B10101,
+ B10111,
+ B10001,
+ B01110,
+ B11011,
+};
+
+// Current menu position
+unsigned int MenuPosition;
+// True if we are to display a menu
+bool inMenu;
+// The time of the last menu interaction so that we can return to the clock screen after some time
+// 32 bit unixtime, das leben am limit
+uint32_t menuTime;
+#define MENU_TIMEOUT 5
+// This will be true if we are in a submenu
+bool inSubmenu;
+
+// This will be set if the alarm is on
+bool alarmOn = false;
+// This will be on if the user has shoutet the alarm into silence
+bool alarmKilled = false;
+
+void setup() {
+ // put your setup code here, to run once:
+ Serial.begin(57600);
+ Serial.println("Hallo");
+ // Joystick setup
+ pinMode(JOY_BTN, INPUT_PULLUP);
+ pinMode(SOUND, INPUT);
+ pinMode(BUZZER, OUTPUT);
+ // RTC Setup
+ Wire.begin();
+ if(!rtc.begin()) {
+ Serial.println("RTC konnte nicht initialisiert werden");
+ while(1);
+ }
+ MenuPosition = 0;
+ inMenu = 0;
+ menuTime = 0;
+ inSubmenu = false;
+ if (!rtc.isrunning())
+ Serial.println("RTC is NOT running!");
+
+ // LCD Setup
+ lcd.begin(16,2);
+ lcd.createChar('\n', clock_symbol);
+
+ menuTime = rtc.now().unixtime();
+
+}
+
+#define MENU_ENTRIES_N 3
+// All the menu entries
+char MenuEntries[MENU_ENTRIES_N][32] = {
+ "Wecker",
+ "Uhrzeit",
+ "Datum"
+};
+
+unsigned short int alarmTime[2] = {0};
+bool alarmEn = false;
+// The position of the cursor in the alarm submenu, 0 for hours, 1 for minutes
+short int alarmSetPosition = 0;
+
+unsigned int setTime[3] = {0};
+uint16_t setDate[3] = {0};
+// The position of the cursor in the time set menu
+short int timeSetPosition = 0;
+short int dateSetPosition = 0;
+
+enum JoyPosition {joy_mid, joy_left, joy_right, joy_up, joy_down};
+char alarmString[16] = "";
+char timeSetString[16] = "";
+char dateSetString[20] = "";
+struct tm* curtm;
+time_t curtime_ux = 0;
+
+short int date_lut_max[12] = {
+ 31,
+ 28,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31
+};
+
+void update_menu() {
+ lcd.home();
+
+ if(!inSubmenu) {
+ // If we are on the last menu entry the active entry will be at the bottom
+ if(MenuPosition == MENU_ENTRIES_N - 1) {
+ lcd.setCursor(1,0);
+ lcd.print(MenuEntries[MenuPosition -1]);
+ lcd.setCursor(0,1);
+ lcd.print(">");
+ lcd.print(MenuEntries[MenuPosition]);
+ } else {
+ lcd.print(">");
+ lcd.print(MenuEntries[MenuPosition]);
+ lcd.setCursor(1, 1);
+ lcd.print(MenuEntries[MenuPosition + 1]);
+ }
+ // This is the menu select
+ switch (JoyDirection) {
+ case joy_down :
+ // Unten
+ MenuPosition = (MenuPosition + 1) % MENU_ENTRIES_N;
+
+ delay(300);
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ break;
+ case joy_up :
+ // Oben
+ MenuPosition = (MenuPosition - 1) % MENU_ENTRIES_N;
+
+ delay(300);
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ break;
+ default:
+ if(JoyBtn) {
+ inSubmenu = true;
+ // Set up the submenu
+ switch(MenuPosition) {
+ case 1:
+ setTime[0] = rtc.now().hour();
+ setTime[1] = rtc.now().minute();
+ setTime[2] = rtc.now().second();
+ break;
+ case 2:
+ setDate[0] = rtc.now().day();
+ setDate[1] = rtc.now().month();
+ setDate[2] = rtc.now().year();
+ break;
+ }
+ menuTime = UINT32_MAX;
+ lcd.clear();
+ delay(300);
+ }
+ break;
+ }
+ } else {
+ menuTime = rtc.now().unixtime();
+ // This is where the submenu magic happens
+ switch(MenuPosition) {
+ case 0:
+ alarmOn = false;
+ // Weckfunktion
+ switch(JoyDirection) {
+ case joy_up:
+ if(alarmSetPosition == 2) {
+ alarmEn = !alarmEn;
+ } else
+ alarmTime[alarmSetPosition] = (alarmTime[alarmSetPosition] + 1) % (alarmSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_down:
+ if(alarmSetPosition == 2) {
+ alarmEn = !alarmEn;
+ } else
+ alarmTime[alarmSetPosition] = (alarmTime[alarmSetPosition] - 1) % (alarmSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_left:
+ if(alarmSetPosition == 0)
+ alarmSetPosition = 2;
+ else
+ alarmSetPosition = (alarmSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ alarmSetPosition = (alarmSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(alarmString, "%02hd:%02hd %s", alarmTime[0], alarmTime[1], alarmEn ? "On" : "Off");
+ lcd.clear();
+ lcd.home();
+ lcd.print(alarmString);
+ lcd.setCursor(alarmSetPosition + (alarmSetPosition << 1), 1);
+ lcd.print("^^");
+ delay(200);
+ break;
+ case 1:
+ switch(JoyDirection) {
+ case joy_up:
+ setTime[timeSetPosition] = (setTime[timeSetPosition] + 1) % (timeSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_down:
+ setTime[timeSetPosition] = (setTime[timeSetPosition] - 1) % (timeSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_left:
+ if(timeSetPosition == 0)
+ timeSetPosition = 2;
+ else
+ timeSetPosition = (timeSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ timeSetPosition = (timeSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(timeSetString, "%02hd:%02hd:%02hd", setTime[0], setTime[1], setTime[2]);
+ lcd.clear();
+ lcd.home();
+ lcd.print(timeSetString);
+ lcd.setCursor(timeSetPosition + (timeSetPosition << 1), 1);
+ lcd.print("^^");
+
+ curtime_ux = rtc.now().unixtime();
+ curtm = gmtime(&curtime_ux);
+
+ // Get the current time
+ curtm->tm_hour = setTime[0];
+ curtm->tm_min = setTime[1];
+ curtm->tm_sec = setTime[2];
+
+ delay(200);
+ break;
+ case 2:
+ lcd.clear();
+ lcd.home();
+
+ switch(JoyDirection) {
+ case joy_up:
+ switch(dateSetPosition) {
+ case 0:
+ setDate[0] = (setDate[0] + 1) % (date_lut_max[setDate[1] - 1] + 1);
+ break;
+ case 1:
+ setDate[1] = (setDate[1] + 1) % 13;
+ if(setDate[0] > date_lut_max[setDate[1] - 1]) setDate[0] = date_lut_max[setDate[1] - 1];
+ break;
+ case 2:
+ setDate[2]++;
+ if(setDate[2] < 2000) setDate[2] = 2000;
+ if(setDate[2] < 2099) setDate[2] = 2099;
+ }
+ // Check if any date is 0
+ for(int i = 0; i < 3; i++) {
+ if(setDate[i] == 0) setDate[i] = 1;
+ }
+ break;
+ case joy_down:
+ switch(dateSetPosition) {
+ case 0:
+ setDate[0] = (setDate[0] - 1) % (date_lut_max[setDate[1] - 1] + 1);
+ break;
+ case 1:
+ setDate[1] = (setDate[1] - 1) % 13;
+ if(setDate[0] > date_lut_max[setDate[1] - 1]) setDate[0] = date_lut_max[setDate[1] - 1];
+ break;
+ case 2:
+ setDate[2]--;
+ if(setDate[2] < 2000) setDate[2] = 2000;
+ if(setDate[2] > 2099) setDate[2] = 2099;
+ }
+ // Check if any date is 0
+ for(int i = 0; i < 3; i++) {
+ if(setDate[i] == 0) setDate[i] = 1;
+ }
+ break;
+ case joy_left:
+ if(dateSetPosition == 0)
+ dateSetPosition = 2;
+ else
+ dateSetPosition = (dateSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ dateSetPosition = (dateSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(dateSetString, "%02hd.%02hd.%04hd", setDate[0], setDate[1], setDate[2]);
+ lcd.clear();
+ lcd.home();
+ lcd.print(dateSetString);
+ lcd.setCursor(dateSetPosition + (dateSetPosition << 1), 1);
+ lcd.print("^^");
+ delay(200);
+
+ break;
+ default:
+ Serial.println("I should not be here");
+ lcd.print(MenuPosition);
+ break;
+ }
+ if(JoyBtn) {
+ inSubmenu = false;
+ if(MenuPosition == 1) {
+ rtc.adjust(DateTime(mktime(curtm)));
+ menuTime = rtc.now().unixtime();
+ } else if(MenuPosition == 2) {
+ rtc.adjust(DateTime(setDate[2], setDate[1], setDate[0], rtc.now().hour(), rtc.now().minute(), rtc.now().second()));
+ menuTime = rtc.now().unixtime();
+ }
+ lcd.clear();
+ delay(300);
+ }
+ }
+}
+
+const char Weekday[7][3] {
+ "Mo",
+ "Di",
+ "Mi",
+ "Do",
+ "Fr",
+ "Sa",
+ "So"
+};
+
+void print_time_now() {
+ DateTime now = rtc.now();
+ lcd.home();
+ char timestring_s[20] = "";
+ // AHHHHHHHH don't touch the trinaries!!!
+ sprintf(timestring_s, "%02d:%02d:%02d %c", now.hour(), now.minute(), now.second(), alarmEn ?
+ (!alarmOn || rtc.now().unixtime() % 2 ? '\n' : ' ') :
+ ' ');
+ lcd.print(timestring_s);
+ lcd.setCursor(0,1);
+ char datestring[20] = "";
+ sprintf(datestring, "%s %02d.%02d.%04d", Weekday[now.dayOfTheWeek() - 1], now.day(), now.month(), now.year());
+ lcd.print(datestring);
+}
+
+
+void playSound() {
+ for(int i = 0; i < 10; i++) {
+ digitalWrite(BUZZER, HIGH);
+ delay(1);
+ digitalWrite(BUZZER, LOW);
+ delay(1);
+ }
+}
+
+void loop() {
+ //if(!menuTime) menuTime = rtc.now().unixtime();
+ // Analoger Joystick
+ // 1024 - entfernen wenn gedreht wird
+ JoyX = analogRead(JOY_X);
+ JoyY = analogRead(JOY_Y);
+
+ Serial.println(JoyY);
+
+ JoyDirection = joy_mid;
+ if(JoyX < 50) {
+ JoyDirection = joy_down;
+ } else if(JoyX > 850) {
+ JoyDirection = joy_up;
+ } else if(JoyY < 50) {
+ JoyDirection = joy_left;
+ } else if(JoyY > 850) {
+ JoyDirection = joy_right;
+ }
+
+ // Joystick button
+ JoyBtn= !digitalRead(JOY_BTN);
+
+ // Read in the sound
+ Sound = digitalRead(SOUND);
+
+ // If the button is pressed and we are not in a menu enter the menu
+ if(JoyBtn && !inMenu && !alarmOn) {
+ inMenu = true;
+ inSubmenu = false;
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ delay(300);
+ } else if(inMenu) { // Do this if we are in a menu
+ update_menu();
+ if(menuTime < rtc.now().unixtime() -5 ) { // Check if the menu interaction has timed out.
+ Serial.println(rtc.now().unixtime());
+ Serial.println(menuTime);
+ inMenu = false;
+ MenuPosition = 0;
+ lcd.clear();
+ }
+ } else {
+ print_time_now();
+ // Check the alarm, ring if we pass it
+ if(alarmTime[0] == rtc.now().hour() && alarmTime[1] == rtc.now().minute() && alarmEn) {
+ if(!alarmKilled) alarmOn = true;
+ } else alarmKilled = false;
+ if(alarmOn && Sound) {
+ alarmKilled = true;
+ alarmOn = false;
+ }
+ if(alarmOn) {
+ playSound();
+ }
+ }
+}
diff --git a/case.scad b/case.scad
new file mode 100644
index 0000000..6514728
--- /dev/null
+++ b/case.scad
@@ -0,0 +1,221 @@
+$fn = 100;
+
+corner_radius = 30;
+inner_length = 185;
+inner_width = 113;
+
+union() {
+ difference () {
+ // Outer box
+ linear_extrude(height = 100, center = true)
+ minkowski() {
+ square([inner_length - corner_radius * 2 + 8, inner_width - corner_radius * 2 ], center = true);
+ circle(r = corner_radius);
+ }
+
+ // Inner box
+ translate([0, 0, 5])
+ linear_extrude(height = 100, center = true)
+ minkowski() {
+ square([inner_length - corner_radius * 2, inner_width - corner_radius * 2 - 5], center = true);
+ circle(r = corner_radius);
+ }
+
+ /*
+ // Remove front
+ translate([0,-65,5])
+ cube([160, 4.5, 90], center = true);
+
+ // front carving
+ translate([0,-68.3,1])
+ cube([170, 3.5, 90], center = true);
+ */
+
+ // LCD Holes
+ translate([-56, -40, -8])
+ rotate([90, 0, 0])
+ {
+ translate([-1,-0.25,0])
+ cube([74, 25.5, 50]);
+ // Screws
+ translate([-1.5, -2.2, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([72 + 1.5, -2.2, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([72 + 1.5, 24 + 4.2, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([-1.5, 24 + 4.2, 0])
+ cylinder(h = 50, d = 2.8);
+ }
+
+ // Joystick
+ translate([45,-40,-10])
+ rotate([90,0,0])
+ {
+ translate([7.5,12,0])
+ cylinder(h=50, d=32);
+/*
+ cylinder(h = 50, d = 2.8);
+ translate([16.5, 0, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([16.5, 25, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([0, 25, 0])
+ cylinder(h = 50, d = 2.8);
+*/
+ }
+
+ // DC
+ translate([-60, 60, -20])
+ rotate([90,0,0])
+ cylinder(d=13, h = 20);
+
+ // Speaker
+ translate([-100,0,0])
+ rotate([0,90,0])
+ for(i = [0:8]) {
+ translate([(i % 3) *3.5,floor(i / 3) * 3.5,0])
+ cylinder(d=3, h=20);
+ }
+
+ // Speaker
+ translate([80,0,0])
+ rotate([0,90,0])
+ for(i = [0:8]) {
+ translate([(i % 3) * 3.5,floor(i / 3) * 3.5, 0])
+ cylinder(d=3, h=20);
+ }
+
+ }
+ // Joystick backplate
+ translate([39,-31,-48])
+ difference() {
+ cube([33, 3, 80]);
+ // Schrauben
+ translate([5.5,9,64])
+ rotate([90,0,0])
+ cylinder(d=3, h=20);
+ translate([25.1,9,64])
+ rotate([90,0,0])
+ cylinder(d=3, h=20);
+ translate([5.5,9,38.1])
+ rotate([90,0,0])
+ cylinder(d=3, h=20);
+ translate([25.1,9,38.1])
+ rotate([90,0,0])
+ cylinder(d=3, h=20);
+ }
+ // Supports
+ translate([39,-30,-48])
+ rotate([90,0,90])
+ linear_extrude(height = 2)
+ polygon( points = [
+ [8,0],
+ [0,80],
+ [-15,0]
+ ]);
+ translate([70,-30,-48])
+ rotate([90,0,90])
+ linear_extrude(height = 2)
+ polygon( points = [
+ [8,0],
+ [0,80],
+ [-15,0]
+ ]);
+}
+
+
+/*
+// front panel
+translate([200,-68.5,3])
+difference() {
+ union() {
+ cube([169.5, 3, 92], center = true);
+ translate([0,3,0])
+ cube([159.5, 3, 85], center = true);
+ }
+
+ // LCD Holes
+ translate([-60, 30, -8])
+ rotate([90, 0, 0])
+ {
+ cube([72, 16, 50]);
+ // Screws
+ translate([-2.5, -3, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([72 + 2.5, -3, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([72 + 2.5, 16 + 4.4, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([-2.5, 16 + 4.4, 0])
+ cylinder(h = 50, d = 2.8);
+ }
+
+ // Joystick
+ translate([45,30,-10])
+ rotate([90,0,0])
+ {
+ translate([7,12,0])
+ cylinder(h=50, d=24);
+
+ cylinder(h = 50, d = 2.8);
+ translate([16.5, 0, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([16.5, 25, 0])
+ cylinder(h = 50, d = 2.8);
+ translate([0, 25, 0])
+ cylinder(h = 50, d = 2.8);
+ }
+}
+*/
+
+
+
+// Lid
+//translate([0, inner_width + 6, 0])
+//translate([0,0,5])
+//rotate([180,0,0])
+difference() {
+ // Outer box
+ linear_extrude(height = 100, center = true)
+ minkowski() {
+ square([inner_length - corner_radius * 2 + 14, inner_width - corner_radius * 2 + 5], center = true);
+ circle(r = corner_radius);
+ }
+ // Inner Box
+ translate([0,0,-5])
+ linear_extrude(height = 100, center = true)
+ minkowski() {
+ square([inner_length - corner_radius * 2 + 8.3, inner_width - corner_radius * 2 + 0.3], center = true);
+ circle(r = corner_radius);
+ }
+ // Cut the bottom
+ translate([0,0,-463])
+ cube([1000,1000,1000], center = true);
+/*
+ // Hole for the front
+ translate([0,-61.5,1.5])
+ cube([160, 4.5 , 86], center = true);
+*/
+
+ // Text
+ translate([0,0,47.5])
+ linear_extrude(12)
+ {
+ translate([0,30,0])
+ text ("The", font = "FiraCode:style=Bold", halign = "center", valign = "center", size = 20);
+ text("Morning", font = "FiraCode:style=Bold", halign = "center", valign = "center", size = 20);
+ translate([0,-28,0])
+ text("Piss Off", font = "FiraCode:style=Bold", halign = "center", valign = "center", size = 20);
+ }
+}
+
+//if($preview) {
+ translate([-20,-50,5])
+ rotate([90])
+ import("/home/jeremias/Downloads/LCD_1602.stl");
+
+ translate([-12,-38,-400])
+ rotate([90,0,0])
+ import("/home/jeremias/Downloads/FICBOX_Dual-axis_XY_Joystick_Module_For_Arduino_Dummy.stl");
+//} \ No newline at end of file
Jeremias Stotters git repositories generated by CGIT