Components and supplies
Button, Push, NO, MOM, sealed, low profile, SS
IR receiver (generic)
Rotary potentiometer (generic)
Display, LED, R/Y/G, Traffic Light
DHT-11 Temp/Humidity Sensor, 3 pin, Velleman VMA311
Power Supply, 5VDC @ 4A, 5.5x2.1 connector, wall
MicroSD card reader/writer
Buzzer, Active, +5, Velleman VMA319
Grove - RTC
Relay, SPDT, 5V, Velleman VMA406
Arduino Mega 2560
LED Dot Matrix Display, Red, 8x8x4
Player, MP3, serial, mono, w/spkr
DC Power Jack Male 2.1mm x 5.5mm Panel Mtg
microSD card, 32gb
Shield, Screw, Mega 2560
Tools and machines
3D Printer (generic)
Apps and platforms
NanoCAD - AutoCAD work-alike - FREE
TinkerCAD - 3D .STL generator
Arduino IDE
Project description
Code
Alarm Clock with temp/humidity and EPROM backup
arduino
TOO BIG TO UPLOAD LATEST VERSION! SORRY - MSG ME HERE IF YOU NEED LATEST CODE Remote control alarm clock with 8x8x4 LED matrix display. 12/24 hr, alarm set, Temperature F/C mode, displays humidity, chimes the hour, displays date, auto off coffee relay (on with alarm, auto off hr later) Plays MP3 files randomly for wake up alarm as well as scrolling message and beeps. Ack silences alarm.
1// 2// Cindy's alarm clock - By Mark M. Lambert on February 20th, 2022 3// Copyright Mark M. Lambert - All Rights Reserved 4// May be used or excepted with attribution 5// 6const float Version = 6.19; 7// 8// V6.19 - 18Mar22 - MML - Add radio code per original buttons 9// V6.18 - 17Mar22 - MML - Try I2C FM module with antenna! :D 10// V6.17 - 16Mar22 - MML - Swap ararm set and relay on LED's 11// V6.16 - 11Mar22 - MML - Work on MP3 player 12// V6.15 - 10Mar22 - MML - Fix bug in alarm on 13// V6.14 - 08Mar22 - MML - Turn off log dump & clean up auto off logic 14// V6.13 - 06Mar22 - MML - Invert Colon 15// V6.12 - 04Mar22 - MML - Install SD card - read data on first compile! :D 16// V6.11 - 03Mar22 - MML - Lint 17// V6.10 - Omitted to prevent being mistaken for a large rev 18// V6.09 - 01Mar22 - MML - Tweak display timing 19// V6.08 - 28Feb22 - MML - Indicate power relay state 20// V6.07 - 27Feb22 - MML - Resequence 420 & 840, simplify setting 21// V6.06 - 26Feb22 - MML - Add clock set (after glitching the RTC) 22// V6.05 - 25Feb22 - MML - Wire & rough out radio code - polish 23// V6.04 - 24Feb22 - MML - Cleanup & tweak functionality 24// V6.03 - 23Feb22 - MML - Add four digit 7 segment display & RTC 25// V6.02 - 22Feb22 - MML - Rough out command framework. RTC module due today 26// V6.01 - 21Feb22 - MML - LCD, DHT working, 8x8x4 matrix & buzzer up, time displaying 27// V6.00 - 20Feb22 - MML - Subset/superset of Rick Box to be custom alarm clock 28// V5.18 - 18Feb22 - MML - Fork from RTC project. See for 'tween versions 29// V1.00 - 06Dec21 - MML - Baseline with LCD - Mega 2650 has built in pullups 30// 31// ---------------------------------------------------------------------------- 32// ---------------------------------------------------------------------------- 33// 34// Device Master List 35// ================== 36// Mega 2560 Processor - Works 37// Screw terminal shield - Works 38// 8x8x4 dot matrix display module MOSI/MISO - Works 39// R/Y/G Traffic Light w/ traffic signal shroud - Works 40// IR remote command in & remote - Works 41// RTC - Works 42// DHT11 Temp/Humidity - Works 43// MP3 player - Serial Control - for rude wake up messages - Sorta works 44// Has own speaker - no relay needed 45// Coffee Pot Relay - Works 46// SD Card with MISO/MOSI - Works 47// Reset Button - Works 48// Ack Button (also Select) - Works 49// Analog pot for random input - Works 50// I2C FM radio module - Works 51// 52// ================================== 53// Start of Pin Constants 54// ================================== 55// 56// Analogs first 57// 58int xx = 0; // Placeholder value 59// 60const int Vnoise = A2; // Random number seed is open AI 61const int Vin = A3; // Power supply direct output monitor - NOT USED 62// 63const int I2C_A4 = A4; // RESERVED 64const int I2C_A5 = A5; // RESERVED 65// 66// Float constant 67// 68const float aiSteps = 1024.0; // 10 bit ADC 69const float VoltsPerBit = (5.0 / aiSteps); // Compute bit weight based on +5 Vin max 70const float stepsPerHr = aiSteps / 24.0; // Hours input 71const float stepsPerMin = aiSteps / 60.0; // Minutes input 72const float stepsPerYr = aiSteps / 100.0; // Year input, 20xx presumed 73const float stepsPerMon = aiSteps / 12.0; // Months input 74const float stepsPerDt = aiSteps / 31.0; // Date input 75const float stepsPerDoW = aiSteps / 7.0; // Day input, sat = 1, fri = 7 76const float stepsPerYN = aiSteps / 2.0; // 0/1 77// 78const int Wiper = A15; // Wiper from 5k pot for data entry 79// 80// Analogs end 81// ----------- 82// Now digitals 83// 84// D0 and D1 are rx/tx for serial programming 85// 86// 2-10 sorta spare 87// 88// D11 & 12 reserved for MOSI/MISO 89// D13 is LED_BUILTIN and is used (maybe) by MOSI/MISO devices 90// 91// Comm channel I/O's 92// 93const int S3_TX = 14; // ESP-01 WiFi - not wired 94const int S3_RX = 15; 95// 96const int S2_TX = 16; // Knob radio - OUT - See I2C 97const int S2_RX = 17; 98// 99const int S1_TX = 18; // MP3 player 100const int S1_RX = 19; 101// 102// I2C was brought out to buss bars for mass connections - wasn't needed 103// Actually the one I2C device (FM radio) connected thru the SDA/SCL pins up by D13 104// 105const int I2C_SDA = 20; // These are attached to the matching buss bars for bussing to all I2C devices 106const int I2C_SCL = 21; // Pullups are internal to Mega 2560 107// 108// 22-25 free 109// 110// RTC I/O pins - Working fine - Use SET_CLOCK project to preset time 111// 112const int kCePin = 26; // Chip Enable - grn 113const int kIoPin = 27; // Input/Output - yel 114const int kSclkPin = 28; // Serial Clock - orn 115// 116// 29-35 free 117// 118// Humidity/temp sensor - working great 119// 120const int DHTPIN = 36; // Digital pin connected to the DHT sensor 121// 122// IR remote control input - noisy - doesn't like LED lighting 123// 124const int RECV_PIN = 37; //IR Receiver input pin 125// 126// On the remote there are seven rows of three buttons each. 127// Each has a unique code. 128// We're going to define the button codes here instead 129// of scattering them in a massive SWITCH. 130// 131// ---------------------- 132// _00 = _RC, 0 indexed 133// 134// All the little IR remotes appear to use the same set of codes 135// Determined empirically: 136// 137const int Btn_00 = 23971; // Top Row, left button - Row 0, Col 0 138const int Btn_01 = 25245; // Row 0, Col 1 - 139const int Btn_02 = 7651; // Top Row, right button - Row 0, Col 2 140// 141const int Btn_10 = 8925; // Row 1, col 0 - (red) 142const int Btn_11 = 765; 143const int Btn_12 = 15811; 144// 145const int Btn_20 = 8161; 146const int Btn_21 = 22441; 147const int Btn_22 = 28561; 148// 149const int Btn_30 = 26775; 150const int Btn_31 = 26521; 151const int Btn_32 = 20401; 152// 153const int Btn_40 = 12495; 154const int Btn_41 = 6375; 155const int Btn_42 = 31365; 156// 157const int Btn_50 = 4335; 158const int Btn_51 = 14535; 159const int Btn_52 = 23205; 160// 161const int Btn_60 = 17085; 162const int Btn_61 = 19125; 163const int Btn_62 = 21165; // Bottom Row, right button 164// 165// Ordered a differnet brand of IR remote that has a DIFFERENT set of codes! 166// Haven't sussed everything out yet but there is at least SOME overlap 167// I've got half a dozen of these little remotes and this is the first 168// one that isn't a clone. Stay tuned - more to come 169// 170// ---------------------- 171// 172// 38, 39 - SPARE 173// 174// Relay pin 175// 176const int K2 = 40; // Coffee Pot 177// 178// 41-42 SPARE 179// 180const int Buzzer = 43; //Annunciator 181// 182// 44 SPARE 183// 184const int AckBtn = 45; // Acknowledge button to silence alarn 185// 186// Traffic lights are near top end of DOs 187// 188const int TL_R = 46; // Alarm On 189const int TL_Y = 47; // Follows AckBtn 190const int TL_G = 48; // Heartbeat 191// 192// SD card is MOSI/MISO, needs its own CS line 193// 194const int sdSel = 49; // SD card Chip Select 195// 196// 50-53 reserved for MOSI/MISO 197// SPI: 198// 50/25/11 (MISO) <<== not needed for output only 199// Needed for SD card 200// 51/24/12 (MOSI) 201// 52/23/13 (SCK)z 202// 53/22/10 (SS) <<== Device Select 203// 204// 11, 12 & 13 Are MISO/MOSI - AKA SPI on UNO 205// 22-25 reserved for MOSI/MISO SP1 devices 206// this conflicts with other docs or it may be 207// uno vs mega 2560 208// 209// Initializes the SD library and card. 210// This begins use of the SPI bus 211// pins 11, 12, and 13 on Arduino UNO boards; 212// pins 50, 51, and 52 on the Mega 213// and the chip select pin, 214// which defaults to the hardware SS pin 215// pin 10 on Arduino UNO boards, 216// pin 53 on the Mega 217// 218// Got dot matrix and 4 digit readouts in 219// The matrix needs MOSI and I think the readouts 220// are I2C, but I won't be sure until they arrive 221// Modules arrived, waiting on cables 222// 223// Mega 2560 pinout is correct - worked on first try 224// 225const int MISOLED = 50; // Needed for 8X8 LED matrix comms 226const int MOSILED = 51; 227const int SCKLED = 52; // builtin LED & SPI clock 228const int CSLED = 53; // 8x8 x4 LED matrix CS line 229// 230// End of Digitals 231// 232// ================================== 233// End of Pin Constants 234// ================================== 235// 236// Device Constants 237// 238const unsigned interval = 1200; // Don't overpoll 239// ---------------------------------------------------------------------------- 240// ---------------------------------------------------------------------------- 241// 242// EEPROM image - we need pointers, not variables 243// 244const int promTempFC = 0; // Flag - EEPROM BASE - ONLY ADD AT END 245const int promAlarmSet = 1; // Flag 246const int promMatrixBright = 2; // Int, 0-15 247const int promClockMode12 = 3; // Flag 248const int promScrollRateMs = 4; // Int 50 to 100 typical 249const int promAlarmHr = 5; // Int - 0-23 250const int promAlarmMin = 6; // Int - 0-59 251const int promFrequency = 7; // Int - 889-1079, two BYTES 252// 253// ---------------------------------------------------------------------------- 254// ---------------------------------------------------------------------------- 255// 256// Includes - DO NOT REORDER 257// 258#include <EEPROM.h> //EEPROM support for tables 259#include <stdio.h> 260#include <DHT.h> //Digital Humidity/Temp sensor library 261#include <DS1302.h> //RTC library 262#include <IRremote.h> //IR Remote Library 263// 264// These three includes MUST be in this order or wierd "Error compiling for board Arduino Mega or Mega 2560." error 265// Wire.h must load first 266// 267//#include <Wire.h> //I2C Driver 268//#include <LiquidCrystal_I2C.h> //I2C LCD display driver for all LCD's 269// 270#include <LG_Matrix_Print.h> // LED matrix - test works 271// 272// microSD card device 273// 274#include <SPI.h> // SPI interface 275#include <SD.h> // SD Card 276// 277File LogFile; // File object 278// ---------------------------------------------------------------------------- 279// 280#include <SoftwareSerial.h> 281// 282// Define the RX and TX pins to establish UART communication with the MP3 Player Module. 283// 284static int8_t loud[] = {0x31, 0x1E, 0x01}; // 1E (max) volume, Play song 03 285static int8_t wake[] = {0x35, 0x02}; // Wake up device 286static int8_t Reset[] = {0x35, 0x05}; // Reset device 287// 288// Define the Serial MP3 Player Module. 289// 290SoftwareSerial MP3(S1_RX, S1_TX); // Serial1 291// 292// ---------------------------------------------------------------------------- 293// 294// I2C FM radio - test says it works - must be below WIRE.H 295// 296#include <radio.h> // Generic 297#include <TEA5767.h> // Specific - defines terms like RADIO_BAND_FM, etc./ 298// 299// The band that will be tuned by this sketch is FM. 300// 301#define FIX_BAND RADIO_BAND_FM // US 302// 303// Station 107.9 FM 304// 305// #define FIX_STATION 1079 306#define FIX_STATION 1029 307// 308TEA5767 radio; // Create an instance of Class for TEA5767 Chip 309// 310// ---------------------------------------------------------------------------- 311// 312// Start building objects 313// 314// Create 8x8x4 Matrix LED object 315// Number of 8x8 segments 316// 317const int segments = 4; 318// 319LG_Matrix_Print lmd(segments, CSLED); 320// 321// Create a DS1302 RTC object. 322// 323DS1302 rtc(kCePin, kIoPin, kSclkPin); 324// 325// Create humidity/temp object 326// 327//#define DHTTYPE DHT11 // DHT 11 328//DHT dht(DHTPIN, DHTTYPE); // Create Object 329// 330DHT dht(DHTPIN, DHT11); // Create Object 331// 332// IR Remote control object 333// 334IRrecv irrecv(RECV_PIN); // Build IR receiver object 335decode_results results; // Not sure about this, but it works 336// 337// ------------------------- 338// Objects built 339// ------------------------- 340// 341// Global state flags need to come from EEPROM 342// 343// We have to manually, byte by byte figure out what goes where 344// in the EEPROM. We've got 4k to tinker with and are limited to 345// ~100k write operations on any given memory location. Rears 346// are unlimited. So you want to check and only write changes 347// 348// 0000 - 0FFF - EEPROM range. Everything runs on bytes 349// 350int BaseAddr = 0; 351int TopAddr = 4095; 352// 353// ****************************** 354// Stare of EEPROM address pointers 355// 356// define start of each object in EEPROM - ONLY ADD ITEMS AT END 357// 358// Declare stuff from EEPROM 359// 360int clockMode12 = false; 361int AlarmSet = false; 362int tempFC = false; 363int MatrixBright = false; 364int scrollRateMs = false; 365int K2State = false; 366int alarmHr = 11; //Default to 11:00a 367int alarmMin = 00; 368int onbyAlarm = false; 369// 370// Time & date setting vars - might not need all 371// 372int clockDoW; //Day of week 373int clockHr; 374int clockMin; 375int clockDt; 376int clockMon; 377int clockYr; 378// 379int aborted = false; //Return flag from sloChime and Chime 380// 381const int MatrixMax = 15; // Max intensity value 382String MatrixText; // Indeterminate string 383// 384// Temp/Humidity 385// 386float h, f, c; // Humidity, TempF, TempC 387// 388int valx = 0; // variable to store the value read 389// 390int MSH; // Pull TWO bytes for numbers > 255 391int LSH; 392int Frequency; // Radio station 889-1079 393// 394// ============================================ 395// SETUP 396// ============================================ 397// 398// Globalize 399// 400// End of EEPROM address pointers 401// ****************************** 402int thisHr; 403int thisMin; 404int thisSec; 405int thisDate; 406int thisMon; 407int thisYr; 408int thisDay; 409// 410String logName = "logmm-yy.txt\\0"; //Template 411// 412float tmpF; // Working float 413// 414// ================================================= 415// 416// SETUP BEGINS 417// 418void setup() 419{ 420 // 421 // serial is 0/1, s1 is 18/19 - MP3, s2 is 16/17 - radio 422 // 423 Serial.begin(9600); // Warm up comm ports 424 Serial1.begin(9600); // MP3 player 425 Serial2.begin(9600); // SPARE 426 // 427 // Pull config 428 // 429 clockMode12 = EEPROM.read(promClockMode12 ); //Default to 12 hr time, false for 24, 430 AlarmSet = EEPROM.read(promAlarmSet ); // Alarm Set/not, save in EEPROM 431 tempFC = EEPROM.read(promTempFC ); // Farenheit/not celcius 432 MatrixBright = EEPROM.read(promMatrixBright); // Start near dim 433 scrollRateMs = EEPROM.read(promScrollRateMs); // scroll rate, lower is faster 434 alarmHr = EEPROM.read(promAlarmHr ); // Hour 435 alarmMin = EEPROM.read(promAlarmMin ); // Minute 436 LSH = EEPROM.read(promFrequency ); // 889 to 1079 for FM radio 437 MSH = EEPROM.read(promFrequency +1); // 889 to 1079 for FM radio 438 Frequency = word(MSH, LSH); 439 // 440 // Send this to SD card too 441 // 442 Serial.println(F("Stored config:")); 443 Serial.println(F("==============")); 444 Serial.println("AM/PM-24: " + String( clockMode12)); 445 Serial.println("Alarm Set: " + String( AlarmSet)); 446 Serial.println("Temp FC: " + String( tempFC)); 447 Serial.println("Matrix Bright: " + String(MatrixBright)); 448 Serial.println("Scroll Rate (ms): " + String(scrollRateMs)); 449 Serial.println("Alarm Hr: " + String( alarmHr)); 450 Serial.println("Alarm Min: " + String( alarmMin)); 451 Serial.println("FM Radio Preset: " + String( Frequency)); 452 // 453 // Sanity check for uninitialized EEPROM 454 // 455 if (clockMode12 != false ) clockMode12 = true; 456 if (AlarmSet != false ) AlarmSet = true; 457 if (tempFC != false ) tempFC = true; 458 if ((MatrixBright > 15) || (MatrixBright < 0)) MatrixBright = 2; 459 // 460 if ((scrollRateMs > 200) || (scrollRateMs < 25)) 461 { 462 scrollRateMs = 50; 463 LogProm(promScrollRateMs, scrollRateMs); 464 } 465 // 466 // Default alarm 467 // 468 if ((alarmHr > 23) || (alarmHr < 0) ) alarmHr = 11; 469 if ((alarmMin > 59) || (alarmMin < 0) ) alarmMin = 00; 470 // 471 if ((Frequency < 889) || (Frequency > 1079) ) 472 { 473 Serial.println("Frequency defaulted"); 474 Frequency = 1029; // Yes, force local preset 475 } 476 // 477 tweakFreq(Frequency); 478 // 479 // Interesting hardware note. If unpowered, the serial port 480 // BEGIN statement will bring up the digital portion of the knob FM card 481 // just from the serial line - VERY STRANGE 482 // But at least it tells me that I'm wired to the right port 483 // 484 // Fire up RTC 485 // 486 rtc.writeProtect(false); //Gotta unlock before letting it run 487 rtc.halt(false); //Let clock run 488 // 489 Time t = rtc.time(); // Device data type - read RTC 490 thisHr = t.hr; 491 thisMin = t.min; 492 thisSec = t.sec; 493 thisDate = t.date; 494 thisMon = t.mon; 495 thisYr = t.yr; 496 thisDay = t.day; 497 // 498 String tmpStr = "log"; 499 if (thisMon < 10) tmpStr = "log0"; 500 tmpStr += String(thisMon) + "-" + String(thisYr - 2000) + ".txt"; 501 logName = tmpStr + "\\0"; 502 // 503 // DOS FAT 8.3 file names only 504 // 505 Serial.println("Current Log file: " + tmpStr); 506 // 507 // INPUT is default but we need to make sure they don't float with INPUT_PULLUP 508 // Declare all inputs as pullups 509 // 510 pinMode(AckBtn, INPUT_PULLUP); // Alarm acknowledge 511 // 512 // Relay 513 // 514 pinMode(K2, OUTPUT); // Coffee pot 515 digitalWrite(K2, false); // Coffee pot, default off 516 // 517 pinMode(Buzzer, OUTPUT); 518 // 519 // Traffic lights 520 // 521 pinMode(TL_G, OUTPUT); // Heartbeat 522 pinMode(TL_Y, OUTPUT); // Silent 523 pinMode(TL_R, OUTPUT); // Alarm set 524 // 525 digitalWrite(TL_G, LOW); //Turn off 526 digitalWrite(TL_Y, LOW); //Turn off 527 digitalWrite(TL_R, LOW); //Turn off 528 // 529 // Pins all set, anything not listed is a hi-Z input 530 // 531 // ============ 532 // 533 // 8x8x4 LED matrix is cool, readable display 534 // 535 lmd.setEnabled(true); 536 lmd.setIntensity(MatrixBright); // 0 = low, 15 = high - set via pot or LDR or command 537 lmd.clear(); 538 lmd.stopTicker(); //Stop any old message 539 // 540 chime(1); 541 waitTicker("Cindy's Alarm Clock-V" + String(Version)); 542 // 543 // Turn on remote 544 // 545 irrecv.enableIRIn(); 546 // 547 // Crank up humitity/temp sensor 548 // 549 dht.begin(); // Fire up temp/humidity sensor 550 Read_DHT(); // Read temp/humidity to prime vars 551 // 552 // Ok fine, we want to test the SD card reader with this code 553 // 554 if (!SD.begin(sdSel)) // Crank up SD card 555 { 556 Serial.println(F("SD init failed")); 557 } 558 // 559 // Special stuff for I2C radio module 560 // 561 // Initialize the Radio 562 // 563 radio.init(); 564 // 565 // Enable information to the Serial port 566 // 567 radio.debugEnable(); 568 // 569 // Preset to 1079 570 // 571 radio.setBand(FIX_BAND); 572 radio.setFrequency(Frequency); 573 // 574 radio.setVolume(10); // 0-15 575 radio.setMono(false); // No external indicator 576 // 577 // End of radio stuff 578 // 579 append(F("Restart")); 580 // 581 // We should see updated data 582 // 583 // readAfile(logName); // Try to read log file & display - takes forever for long file, 584 // slows init 585 // 586// chime(2); // Let em know we're live 587 // 588 Serial.println("Wake"); 589 cmdMP3(wake, 2); 590 delay(500); 591 // 592 Serial.println("Reset"); 593 cmdMP3(Reset, 2); 594 delay(500); 595 // 596 Serial.println("Loud & play"); 597 cmdMP3(loud, 3); 598 delay(500); 599 // 600 } 601// ============================================ 602// 603// SETUP ends 604// 605// ============================================ 606// ============================================ 607// 608// LOOP BEGINS 609// 610// ============================================ 611// 612// Globals 613// 614String colon = ":"; // Time marker default 615// 616int tmp; // Working var 617String tmpStr; // Working strings 618String IRval; // Reading from remote 619String LastIRCmd; 620int lastSec; 621// 622// Declaring vars inside SWITCH blows up 623// 624// Fall into runtime 625// 626void loop() 627 { 628 Time t = rtc.time(); 629 // 630 // Let LED matrix running until eom 631 // 632 if (!lmd.updateTicker()) lmd.stopTicker(); //Stop at end 633 // 634 // Fast execution items lead 635 // 636 // We need to watch the RTC and trigger when the seconds change 637 // 638 // hard poll IR while waiting 639 // 640 while (thisSec == lastSec) // Wait for clock to tick 641 { 642 t = rtc.time(); 643 thisHr = t.hr; 644 thisMin = t.min; 645 thisSec = t.sec; 646 thisDate = t.date; 647 thisMon = t.mon; 648 thisYr = t.yr; 649 thisDay = t.day; 650 // 651 // IR remote code is big switch. 652 // There are 21 different buttons with unique responses 653 // 654 // IR Remote needs to be shielded from other light sources 655 // Umm dunno how fast we should poll this. Its fast polling now. 656 // but we might need to slow it down 657 // 658 CheckIR(); // Does 21 different functions 659 // 660 // Update status lights in real time 661 // 662 digitalWrite(TL_R, digitalRead(K2)); // Reminder that power relay is on is RED 663 digitalWrite(TL_Y, AlarmSet); // Show if alarm is set amber 664 // 665 if (!lmd.updateTicker()) lmd.stopTicker(); //Stop at end 666 // 667 } 668 // 669 // New second passes 670 // 671 digitalWrite(TL_G, !digitalRead(TL_G)); //Toggle heartbeat on second 672 // 673 lastSec = thisSec; // Note this second 674 // 675 // Alternate : and . as tic-tok on 8x8x4 matrix 676 // 677 colon == ":" ? colon = "." : colon = ":"; 678 // 679 // Display time 680 // 681 formTime(); 682 // 683 // Ok, from here on out we have our activities. 684 // Each looks at the time and does their thing 685 // 686 // Check to see if the coffee pot is still on after an hour 687 // if so, turn it off 688 // 689 int tempHr = alarmHr + 1; 690 if (tempHr > 23) tempHr = tempHr - 24; //Compensate for past midnight 691 // 692 if ( ( (tempHr == thisHr) && 693 (alarmMin == thisMin) ) && onbyAlarm) 694 { 695 digitalWrite(K2, LOW); //Turn off 696 onbyAlarm = false; 697 K2State = false; 698 // 699 Serial.print("K2 Auto off: " + String(tempHr) + " " + String(thisHr) ); 700 blip(); // Little noise to get you to look 701 waitTicker(F("Aux relay auto off")); // Let user know 702 formTime(); // Show time 703 chime(3); // Different 704 } 705 // 706 // Check for alarm time being set 707 // 708 if ( (alarmHr == thisHr) && 709 (alarmMin == thisMin) && 710 (thisSec == 0) && 711 AlarmSet) 712 { 713 // 714 // Kick on coffee pot relay - we should turn this 715 // off automatically after an hour 716 // 717 blip(); // prealarm noise 718 digitalWrite(K2, HIGH); // Load comes on with alarm 719 K2State = true; // Internal state flag - Y not read IO? 720 onbyAlarm = true; // Alarm turned us on 721 // 722 // Wakey Wakey! 723 // 724 waitTicker(F("Wakey! Wakey!")); 725 formTime(); //Show time 726 // 727 sloChime(10); 728 if (!aborted) 729 { 730 waitTicker(F("Get up & PEE! The world's on FIRE!")); 731 formTime(); //Show time 732 // 733 sloChime(10); 734 if (!aborted) 735 { 736 waitTicker(F("Outta bed, sleepy head!")); 737 formTime(); //Show time 738 sloChime(10); 739 } 740 // 741 } 742 // 743 } 744 // 745 // Show temp at 1/4 past minute 746 // 747 if ( (thisSec == 15) && !lmd.updateTicker() ) 748 { 749 Read_DHT(); // Read temp/humidity 750 tempFC ? lmd.ticker(String(f, 1) + "F", scrollRateMs) : 751 lmd.ticker(String(c, 1) + "C", scrollRateMs); 752 // 753 } 754 // 755 // Show Date at 30 - add month names 756 // 757 if ( (thisSec == 30) && !lmd.updateTicker() ) 758 lmd.ticker(String(thisMon) + 759 "/" + String(thisDate) + 760 "/" + String(thisYr).substring(2), scrollRateMs); 761 // 762 // Show RH at 3/4 of minute - use reading from :15 763 // 764 if ( (thisSec == 45) && !lmd.updateTicker() ) 765 lmd.ticker(String(h, 0) + "% RH", scrollRateMs); 766 // 767 // Min = 0 & sec = 0 = hour strike 768 // 769 if ( (thisMin == 0) && (thisSec == 0) ) 770 { 771 blip(); //Little noise to make you look 772 waitTicker(F("Cuckoo! Cuckoo!")); 773 formTime(); // Show time 774 // 775 tmp = thisHr; // Time from globals 776 // 777 if ((tmp > 12) && (clockMode12)) tmp = tmp - 12; //Civilian time 778 // 779 // Start and end times need to be selectable 780 if ((thisHr > 10) && (thisHr < 23)) // Only chime 11A-11P per swmbo 781 { 782 sloChime(tmp); //Change to MP3 "Bong" when I get it installed 783 } 784 // 785 } 786 // 787 // Later in execution overrides time display above 788 // 789 if ((thisHr == 16) && (thisMin == 20) && (thisSec == 0)) 790 { 791 blip(); //Little noise to make you look 792 waitTicker(F("It's 4:20! SMOKE BREAK!")); 793 formTime(); // Show time 794 sloChime(4); 795 // 796 waitTicker(F("It's 4:20! Time to roll a fattie!")); 797 formTime(); // Show time 798 sloChime(2); 799 } 800 // 801 if ((thisHr == 20) && (thisMin == 40) && (thisSec == 0)) 802 { 803 blip(); //Little noise to make you look 804 waitTicker(F("It's 8:40! TIME TO SMOKE!")); 805 formTime(); // Show time 806 sloChime(8); 807 // 808 waitTicker(F("It's 8:40! Time to Relax!")); 809 formTime(); // Show time 810 sloChime(4); 811 } 812 // 813 // Log data on 1/4 hour 814 // 815 if ( ((thisMin == 0) || 816 (thisMin == 15) || 817 (thisMin == 30) || 818 (thisMin == 45)) && (thisSec == 0)) 819 append(""); // Append to log 820 // 821 } // End of LOOP 822// ============================================================================= 823// ============================================================================= 824// Functions 825// ============================================================================= 826// ============================================================================= 827// 828// Function to read and display Temp Humidity from sensor 829// 830void Read_DHT() 831 { 832 // 833 // Reading temperature or humidity takes about 250 milliseconds! 834 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 835 // 836 h = dht.readHumidity(); // Get humidity 837 c = dht.readTemperature(false); // Read temperature as Celsius (the default) 838 f = dht.readTemperature(true); // Read temperature as Fahrenheit (isFahrenheit = true) 839 // 840 } 841// 842// ================================================== 843// 844// Ring the bell very short 845// 846void blip() 847{ 848digitalWrite(Buzzer, true); 849delay(20); 850digitalWrite(Buzzer, false); 851} 852// ================================================== 853// 854// Ring the bell rings times with .1 sec between beeps 855// 856void chime(int rings) 857{ 858if (rings > 12) rings = rings - 12; //Fudge for midnight rollover 859// 860for (int i = 0; i < rings; i++) 861 { 862 if (!digitalRead(AckBtn)) break; 863 // 864 digitalWrite(Buzzer, true); 865 delay(100); 866 digitalWrite(Buzzer, false); 867 if (!digitalRead(AckBtn)) break; 868 // 869 delay(100); 870 } 871// 872} 873// ================================================== 874// 875// Ring the bell rings times with 1 sec between beeps 876// 877void sloChime(int rings) 878{ 879aborted = false; 880// 881if (rings > 12) rings = rings - 12; //Fudge for midnight rollover 882// 883for (int i = 0; i < rings; i++) 884 { 885 if (!digitalRead(AckBtn)) 886 { 887 aborted = true; 888 break; 889 } 890 // 891 // Don't abort in middle of pulse, sound stays on forever 892 // 893 digitalWrite(Buzzer, true); 894 delay(200); 895 digitalWrite(Buzzer, false); 896 if (!digitalRead(AckBtn)) 897 { 898 aborted = true; 899 break; 900 } 901 // 902 delay(800); 903 } 904// 905} 906// ================================================== 907// 908void CheckIR() 909{ 910// 911// This is the master remote control switch. 912// See discussion on button structure near front 913// 914if (irrecv.decode(&results)) 915 { 916 // Display what we got 917 // 918 valx = abs(results.value); // no negatives 919 IRval = String( abs(valx) ); // no negatives 920 IRval.trim(); //Strange Syntax 921 LastIRCmd.trim(); 922 // 923 // Catch value 924 // 925 if ( (valx > 0) && (LastIRCmd != IRval)) 926 { 927 if (IRval != "") 928 { 929 LastIRCmd = IRval; 930 LastIRCmd.trim(); 931 } 932 // 933 } 934 // 935 // Live command when received 936 // 937 Serial.print(F("RXD: = ")); 938 valx = abs(valx); 939 Serial.println(valx); 940 // 941 // Ok, No silly negatives, Each button sends a code, both remotes send 942 // the same code for the same physical button 943 // 944 // ============================= 945 // ============================= 946 // Main control switch on remote command 947 // ============================= 948 // ============================= 949 // 950 if (valx >= 1) // Triple filter out negs 951 { 952 // 953 // At this point all 21 buttons have an 954 // assigned (if not yet fully implemented) function 955 // 956 // ====================== 957 // Radio Alarm AM/PM 958 // On/off Device 24 hr 959 // ---------------------- 960 // Temp Full F/C 961 // Humidity Date 962 // ---------------------- 963 // Dim Bright Set 964 // Clock 965 // ---------------------- 966 // Show Toggle Set 967 // Alarm Alarm Alarm 968 // ---------------------- 969 // Prev Next Vol 970 // Sta Sta Up 971 // ---------------------- 972 // Station Station Vol 973 // "A" "B" Dn 974 // ---------------------- 975 // Set Dim Mute 976 // Sta A/B 977 // ====================== 978 // 979 switch (valx) //Needs integer for switch 980 { 981 // 982 // Button codes in table up front - all tested & work 983 // 984 case Btn_00: 985 Serial.println(F("btn 00")); 986 chime(1); 987 // 988 break; 989 // ================= 990 case Btn_01: 991 Serial.println(F("btn 01")); 992 chime(1); 993 K2State = !K2State; // Toggle state 994 K2State ? MatrixText = "Power ON" : MatrixText = "Power Off"; 995 // 996 onbyAlarm = false; // Manual control, cancel auto flag 997 // 998 // Save for power blip 999 // 1000 digitalWrite(K2, K2State); // Tell hardware 1001 lmd.ticker(MatrixText, scrollRateMs); 1002 // 1003 break; 1004 // ================= 1005 case Btn_02: 1006 Serial.println(F("btn 02")); 1007 chime(1); 1008 // 1009 // Toggle 12/24 hour 1010 // 1011 clockMode12 = !clockMode12; 1012 clockMode12 ? MatrixText = "AM/PM" : MatrixText = "24 hour"; 1013 // 1014 lmd.ticker(MatrixText, scrollRateMs); 1015 LogProm(promClockMode12, clockMode12); 1016 // 1017 break; 1018 // ================= 1019 // 2nd Row 1020 // 1021 case Btn_10: 1022 Serial.println(F("btn 10")); 1023 chime(1); 1024 // 1025 // Display Temperature 1026 // 1027 // Check FC flag to show in C or F 1028 // 1029 tempFC ? MatrixText = String(f, 1) + "F/" : 1030 MatrixText = String(c, 1) + "C/"; 1031 // 1032 lmd.ticker(MatrixText + String(h, 0) + "% RH", scrollRateMs); 1033 // 1034 break; 1035 // ================= 1036 case Btn_11: 1037 Serial.println(F("btn 11")); 1038 chime(1); 1039 // 1040 // Display date - I know there's a smarter way, 1041 // but my C++ skills aren't that sharp about arrays 1042 // 1043 tmpStr = ""; 1044 switch (thisDay) 1045 { 1046 case 1: 1047 tmpStr = "Sun"; 1048 break; 1049 // ========== 1050 case 2: 1051 tmpStr = "Mon"; 1052 break; 1053 // ========== 1054 case 3: 1055 tmpStr = "Tues"; 1056 break; 1057 // ========== 1058 case 4: 1059 tmpStr = "Wednes"; 1060 break; 1061 // ========== 1062 case 5: 1063 tmpStr = "Thurs"; 1064 break; 1065 // ========== 1066 case 6: 1067 tmpStr = "Fri"; 1068 break; 1069 // ========== 1070 case 7: 1071 tmpStr = "Satur"; 1072 break; 1073 // ========== 1074 } 1075 // 1076 lmd.ticker(tmpStr + "day, " + 1077 String(thisMon) + "/" + 1078 String(thisDate) + "/" + 1079 String(thisYr), scrollRateMs); 1080 // 1081 break; 1082 // ================= 1083 case Btn_12: 1084 Serial.println(F("btn 12")); 1085 chime(1); 1086 // 1087 // Toggle F/C 1088 // 1089 tempFC = !tempFC; //Flip flag 1090 tempFC ? lmd.ticker(String(f, 1) + "F", scrollRateMs) : 1091 lmd.ticker(String(c, 1) + "C", scrollRateMs); 1092 // 1093 LogProm(promTempFC, tempFC); 1094 // 1095 break; 1096 // ================= 1097 // 3rd Row 1098 // 1099 case Btn_20: 1100 Serial.println(F("btn 20")); 1101 chime(1); 1102 // 1103 // Dim matrix 1104 // 1105 MatrixBright--; 1106 if (MatrixBright < 0) MatrixBright = 0; 1107 // 1108 lmd.setIntensity(MatrixBright); // 0 = low, 15 = high 1109 LogProm(promMatrixBright, MatrixBright); 1110 // 1111 break; 1112 // ================= 1113 case Btn_21: 1114 Serial.println(F("btn 21")); 1115 chime(1); 1116 // 1117 // Brighten matrix 1118 // 1119 ++MatrixBright; 1120 if (MatrixBright > MatrixMax) MatrixBright = MatrixMax; 1121 // 1122 lmd.setIntensity(MatrixBright); // 0 = low, 15 = high 1123 LogProm(promMatrixBright, MatrixBright); 1124 // 1125 break; 1126 // ================= 1127 case Btn_22: 1128 Serial.println(F("btn 22")); 1129 chime(1); 1130 // 1131 // Need to have a check to prevent going 1132 // thru this needlessly. 1133 // Allow bail out after time set 1134 // don't force date setting 1135 // 1136 waitTicker(F("Are You Sure? 00-No, 01-Yes:")); 1137 tmp = waitForIt(stepsPerYN, "Ok: ", 0, ""); 1138 delay(250); 1139 chime(1); 1140 if (tmp == 1) 1141 { 1142 // 1143 // Ok, set Clock Hour 1144 // 1145 chime(1); 1146 waitTicker(F("Dial Hour:")); 1147 clockHr = waitForIt(stepsPerHr, "", 0, ":xx" ); 1148 chime(1); 1149 // 1150 // Now get minute 1151 // 1152 waitTicker(F("Dial Min:")); 1153 // M is wider than normal, need to lose the : 1154 clockMin = waitForIt(stepsPerMin, String(clockHr) + ":", 0, ""); 1155 chime(1); 1156 // 1157 // Do they wanna bail? 1158 waitTicker(F("Set Date? 00-No, 01-Yes:")); 1159 if (waitForIt(stepsPerYN, "Ok: ", 0, "") == 1) 1160 { 1161 chime(1); 1162 // 1163 // Now get month 1164 // 1165 delay(250); 1166 waitTicker(F("Dial Month:")); 1167 // M is wider than normal, need to lose the : 1168 clockMon = waitForIt(stepsPerMon, "", 1, "/xx"); 1169 chime(1); 1170 delay(250); 1171 // 1172 // Now get date 1173 // 1174 waitTicker(F("Dial Date:")); 1175 clockDt = waitForIt(stepsPerDt, String(clockMon) + "/", 1, ""); 1176 chime(1); 1177 // 1178 // Year = error trap 1179 // 1180 clockYr = 2021; 1181 while (clockYr < 2022) 1182 { 1183 waitTicker(F("Dial Year:")); 1184 clockYr = 2000 + waitForIt(stepsPerYr, "20", 0, ""); 1185 } 1186 // 1187 chime(1); 1188 // 1189 // Now get day of week 1190 // 1191 waitTicker(F("Dial Day, Sun-01, Sat-07:")); 1192 clockDoW = waitForIt(stepsPerDoW, "Day:", 1, ""); 1193 } 1194 else 1195 { 1196 // 1197 // Use current date 1198 // 1199 clockYr = thisYr; 1200 clockMon = thisMon; 1201 clockDt = thisDate; 1202 clockDoW = thisDay; 1203 } 1204 // 1205 // We need to wait for operator to click 1206 // to sync setting. Need to write data 1207 // to RTC after go 1208 // 1209 chime(1); 1210 delay(250); 1211 waitTicker(F("Press to sync ...")); 1212 chime(1); // Ack 1213 lmd.stopTicker(); 1214 lmd.clear(); 1215 lmd.printText(0, "NOW!"); 1216 lmd.display(); 1217 // 1218 while (digitalRead(AckBtn)) 1219 { 1220 // Wait for press 1221 } 1222 // 1223 blip(); 1224 // 1225 // Write time to RTC 1226 // 1227 setRTC(clockYr, clockMon, clockDt, clockHr, clockMin, clockDoW); 1228 // 1229 chime(2); // Ack 1230 // 1231 } 1232 // 1233 // 1234 break; 1235 // ================= 1236 // 4th Row 1237 // 1238 case Btn_30: 1239 Serial.println(F("btn 30")); 1240 chime(1); 1241 // 1242 // Alarm show 1243 // 1244 MatrixText = "Alarm Time: " + String(alarmHr) + ":"; 1245 if (alarmMin < 10) MatrixText += "0"; 1246 MatrixText += String(alarmMin); 1247 // 1248 AlarmSet ? MatrixText += " ON" : MatrixText += " OFF"; 1249 // 1250 lmd.ticker(MatrixText, scrollRateMs); 1251 // 1252 break; 1253 // ================= 1254 case Btn_31: 1255 Serial.println(F("btn 31")); 1256 chime(1); 1257 // 1258 // Alarm on/off 1259 // 1260 AlarmSet = !AlarmSet; 1261 if (AlarmSet) 1262 { 1263 MatrixText = "Alarm Set On: " + String(alarmHr) + ":"; 1264 if (alarmMin < 10) MatrixText += "0"; 1265 MatrixText += String(alarmMin); 1266 } 1267 else 1268 { 1269 MatrixText = "Alarm Off"; 1270 chime(1); // Twice is off - like car alarm 1271 } 1272 // 1273 onbyAlarm = false; 1274 lmd.ticker(MatrixText, scrollRateMs); 1275 LogProm(promAlarmSet, AlarmSet); 1276 // 1277 break; 1278 // ================= 1279 case Btn_32: 1280 Serial.println(F("btn 32")); 1281 chime(1); 1282 // 1283 // Ok, set Alarm Hour 1284 // 1285 waitTicker(F("Dial Hour:")); 1286 alarmHr = waitForIt(stepsPerHr, "", 0, ":xx"); 1287 chime(1); 1288 // 1289 // Now get minute 1290 // 1291 waitTicker(F("Dial Min:")); 1292 alarmMin = waitForIt(stepsPerMin, String(alarmHr) + ":", 0, ""); 1293 chime(1); 1294 delay(250); 1295 // 1296 tmpStr = "Alarm On: " + String(alarmHr) + ":"; 1297 if (alarmMin < 10) tmpStr += "0"; 1298 // 1299 tmpStr += String(alarmMin); 1300 waitTicker(tmpStr); 1301 chime(1); 1302 // 1303 // Save and turn alarm on automatically 1304 // 1305 AlarmSet = true; 1306 onbyAlarm = false; // Clear old state 1307 // 1308 // Retain state 1309 // 1310 LogProm(promAlarmHr, alarmHr); 1311 LogProm(promAlarmMin, alarmMin); 1312 LogProm(promAlarmSet, AlarmSet); 1313 // 1314 chime(2); // Ack 1315 // 1316 break; 1317 // ================= 1318 // 5th Row 1319 // Originally this was for FM radio control 1320 // Since I had no luck getting it to run 1321 // OUT - these buttons can be used for the 1322 // MP3 or other control functions 1323 // 1324 case Btn_40: 1325 Serial.println(F("btn 40")); 1326 chime(1); 1327 // 1328 tmp = radio.getFrequency(); 1329 --tmp; // Dump once 1330 tweakFreq(tmp); 1331 // 1332 break; 1333 // ================= 1334 case Btn_41: 1335 Serial.println(F("btn 41")); 1336 chime(1); 1337 // 1338 tmp = radio.getFrequency(); 1339 ++tmp; // Bump thrice 1340 ++tmp; 1341 ++tmp; 1342 tweakFreq(tmp); 1343 // 1344 break; 1345 // ================= 1346 case Btn_42: 1347 Serial.println(F("btn 42")); 1348 chime(1); 1349 // 1350 // Volume Up doesn't work on this 1351 // particular module. It's a preamp 1352 // so it's always at full blast or muted 1353 // 1354 // Old test function 1355 // Test button for MP3 player 1356 // 1357 Serial.println("Play 3"); 1358 playSong(3); 1359 // 1360 break; 1361 // ================= 1362 // 6th Row 1363 // 1364 case Btn_50: 1365 Serial.println(F("btn 50")); 1366 chime(1); 1367 // 1368 // Saved Station "A" 1369 // 1370// radioCmd = "AT+FRE=" + String(freqA); 1371 // 1372 break; 1373 // ================= 1374 case Btn_51: 1375 Serial.println(F("btn 51")); 1376 chime(1); 1377 // 1378 // Saved Station "B" 1379 // 1380// radioCmd = "AT+FREQ=" + String(freqB); 1381 // 1382 break; 1383 // ================= 1384 case Btn_52: 1385 Serial.println(F("btn 52")); 1386 chime(1); 1387 // 1388 // Volume Down doesn't work on this 1389 // particular module. It's a preamp 1390 // so it's always at full blast or muted 1391 // 1392 break; 1393 // ================= 1394 // 7th and last Row 1395 // 1396 case Btn_60: 1397 Serial.println(F("btn 60")); 1398 chime(1); 1399 // 1400 // This will allow setting of 1401 // the station presets selected 1402 // above at btn_50 and btn_51 1403 // 1404 tmp = waitForIt( 1024/200, "F:", 881, ""); 1405 tweakFreq(tmp); 1406 // 1407 break; 1408 // ================= 1409 case Btn_61: 1410 Serial.println(F("btn 61")); 1411 chime(1); 1412 // 1413 // Toggle matrix 1414 // Dim/restore display 1415 // 1416 (MatrixBright != 0) ? MatrixBright = 0 : 1417 MatrixBright = EEPROM.read(promMatrixBright); 1418 // 1419 lmd.setIntensity(MatrixBright); // 0 = low, 15 = high 1420 // 1421 // Since we didn't update EEPROM the preset 1422 // brightness will restore on next reset 1423 // 1424 break; 1425 // ================= 1426 case Btn_62: 1427 Serial.println(F("btn 62")); 1428 chime(1); 1429 // 1430 // Toggle radio Mute & display frequency 1431 // 1432 radio.setMute(!radio.getMute() ); 1433 // 1434 showFM(); 1435 // 1436 break; 1437 // ================= 1438 // 1439 // SWITCH VAL ENDS 1440 // 1441 } 1442 // 1443 // 1444 } // If Val ends 1445 // 1446 // Resume IR control - not really sure what this does. 1447 // 1448 irrecv.resume(); 1449 } // Decode ends 1450 // 1451} 1452// ================================================== 1453// 1454// Updates given EEPROM *BYTE* address with value, ints > 255 need TWO! 1455// 1456void LogProm(int Addr, int Valu) 1457{ 1458EEPROM.update(Addr, Valu); 1459} 1460// ================================================== 1461// 1462// Keep marquee spinning - no DELAY's allowed 1463// 1464void dillyDally(int mills2wait) 1465{ 1466// 1467int rightNow = millis(); 1468// 1469while (millis() < rightNow + mills2wait) 1470 { 1471 if (!lmd.updateTicker()) 1472 { 1473 lmd.stopTicker(); //Stop at end 1474 lmd.clear(); 1475 } 1476 // 1477 } 1478// 1479} 1480// ================================================== 1481// 1482// Spin hard letting ticker run - data from globals 1483// 1484void waitTicker(String Msg) 1485{ 1486lmd.ticker(Msg, scrollRateMs); 1487// 1488 while (lmd.updateTicker()) 1489 { 1490 if (!digitalRead(AckBtn)) 1491 { 1492 aborted = true; //Pass up food chain 1493 break; 1494 // ========= 1495 } 1496 // 1497 } 1498// 1499} 1500// ================================================== 1501// 1502// Waits for input via pot, ended with ackbtn 1503// 1504// pot input 0-1023 is scaled by steps 1505// input is prompted with cue 1506// 0/1 origin is set with bias 1507// 1508// Scaled value returned 1509// 1510int waitForIt(float steps, String cue, int bias, String Suffix) 1511{ 1512// 1513String tmpCue = cue; 1514int myTmp; //Return var 1515// 1516lmd.stopTicker(); 1517lmd.clear(); 1518// 1519while (digitalRead(AckBtn)) 1520 { 1521 tmpCue = ""; // Unpad for next loop 1522 myTmp = (analogRead(Wiper) / steps); 1523 if (cue == "") 1524 { 1525 // 1st col - pad with blank 1526 if (myTmp < 10) tmpCue = " "; 1527 lmd.printText(0, tmpCue + String(myTmp + bias) + Suffix, true); //0 index 1528 } 1529 else 1530 { 1531 // 2nd col - pad with zero 1532 if (myTmp < 10) tmpCue = "0"; 1533 lmd.printText(0, cue + tmpCue + String(myTmp + bias) + Suffix, true); //0 index 1534 } 1535 // 1536 lmd.display(); 1537 delay(100); //Can't dillydally static display 1538 lmd.clear(); 1539 } 1540// 1541while (!digitalRead(AckBtn)) // Wait on release 1542 { 1543 } 1544// 1545chime(1); 1546return myTmp + bias; 1547// 1548} 1549// ================================================== 1550// 1551void setRTC(int yr, int mo, int dt, int hr, int mn, int dow) 1552{ 1553rtc.writeProtect(false); 1554rtc.halt(true); //Shouldn't this be TRUE? 1555// 1556// Make a new time object to set the date and time. 1557// Sunday, September 22, 2013 at 01:38:50. 1558// 1559// Full spec includes seconds and DoW 1560// 1561// Time t(yr, mo, dt, hr, mn, 00, Time::kTuesday); 1562// 1563// Load the object, will it puke w/o secs & DoW? 1564// 1565Time t(yr, mo, dt, hr, mn, 00, dow); 1566// 1567// Set the time and date on the chip. 1568// 1569rtc.time(t); 1570// 1571rtc.halt(false); //Let clock run 1572rtc.writeProtect(true); //Only protect AFTER letting it run 1573// 1574} 1575// ================================================== 1576// 1577void formTime() 1578{ 1579String outStr; 1580int wrk = thisHr; // Time from globals 1581// 1582if ((wrk > 12) && (clockMode12)) wrk = wrk - 12; //Civillian time 1583// 1584clockMode12 ? outStr = " " : outStr = "0"; // Pad leader 1585// 1586if (wrk >= 10) outStr = ""; // No pad needed 1587// 1588outStr += String(wrk) + colon; // Tick tock symbol 1589// 1590if (thisMin < 10) outStr += "0"; // Pad leading zero on minutes 1591outStr += String(thisMin); 1592// 1593// Send time to 8X8x4 LED matrix display if not busy 1594// 1595if (clockMode12) ((thisHr < 12) ? outStr += "a" : outStr += "p"); 1596// 1597if (!lmd.updateTicker()) 1598 { 1599 lmd.stopTicker(); // Kill scrolling msg (pro forma) 1600 lmd.clear(); // Blank 1601 lmd.printText(0, outStr, true); // 0 index static text 1602 lmd.display(); // Display 1603 } 1604// 1605} 1606// ================================================== 1607// 1608// Clean up 1609// 1610void readAfile(String fileName) 1611{ 1612// 1613// Crack open file and return file handle 1614// 1615int bytes = 0; // Bytes read 1616// 1617// filename is being returned as a number? 1618File aFile = SD.open(String(fileName)); //Returns handle or false on fail 1619if (aFile) // Success! 1620 { 1621 Serial.println("Reading: " + fileName); 1622 // 1623 // read from the file until there's nothing else in it: 1624 // 1625 while (aFile.available()) // not EOF 1626 { 1627 // Byte level copy? 1628 // 1629 Serial.write(aFile.read()); // Copy byte to comm port for visibility 1630 bytes++; // Goose counter 1631 } 1632 // 1633 // close the file 1634 // 1635 aFile.close(); 1636 // 1637 // Summary to serial port 1638 // 1639 Serial.println(String(bytes) + " bytes read"); 1640 // 1641 } 1642// 1643} 1644// ================================================== 1645// 1646// Append to log file 1647// 1648void append(String lineOtext) 1649{ 1650// Pass a line of text. Filename is given 1651// 1652File aFile; 1653Serial.println("Opening: " + logName); 1654aFile = SD.open(logName, FILE_WRITE); //Returns handle or false on fail 1655if (aFile) // Success! 1656 { 1657 // 1658 String Hr = String(thisHr); 1659 if (thisHr < 10) Hr = "0" + Hr; 1660 String Mn = String(thisMin); 1661 if (thisMin < 10) Mn = "0" + Mn; 1662 aFile.println(" D&T: " + String(thisMon) + "/" + String(thisDate) 1663 + " @ " + Hr + ":" + Mn ); 1664 aFile.println("Temp: " + String(f, 1) + "F"); 1665 aFile.println("RH %: " + String(h, 0)); // Data is integer 1666 // 1667 // Only append if not blank 1668 // 1669 if (lineOtext != "") aFile.println("[" + lineOtext + "]"); 1670 // 1671 aFile.close(); 1672 // 1673 Serial.println(F("Log updated")); 1674 } 1675else 1676 { 1677 Serial.println("Pbbbt! Failed file open of " && logName); 1678 } 1679// 1680} 1681// ================================================== 1682// 1683// Send random command to player 1684// 1685void cmdMP3(int8_t command[], int len) 1686{ 1687// 1688// Rewrite to compute length and prefix/suffix automatically 1689// 1690Serial.print("7E "); 1691Serial1.write(0x7E); // Prefix 1692// 1693Serial.print(String(len +1, HEX)); 1694Serial.print(" "); // Pad with blank for readability 1695Serial1.write(len +1); // Bytes to follow including suffix 1696// 1697for(int i = 0; i < len; i++) 1698 { 1699 // 1700 Serial1.write(lowByte( command[i] ) ); // Send byte 1701 Serial.print(String( lowByte( command[i] ), HEX)); // mask LSH to prevent minus extend 1702 Serial.print(" "); // Pad with blank for readability 1703 } 1704// 1705Serial.println("EF"); 1706Serial1.write(0xEF); // Suffix 1707// 1708} 1709// ================================================== 1710// 1711void playSong(int song) 1712{ 1713// 1714// Rewrite to compute length and prefix/suffix automatically 1715// 1716Serial1.write(0x7E); // Prefix 1717Serial1.write(0x04); // Bytes to follow including suffix 1718Serial1.write(0x31); // Set Volume command & play # 1719Serial1.write(0x1E); // Volume to full 1720// 1721Serial1.write(0x01); // Send song # 1722// 1723Serial1.write(0xEF); // Suffix 1724// 1725} 1726// ================================================== 1727// 1728// Display station from radio 1729// 1730void showFM() 1731{ 1732tmpF = radio.getFrequency(); 1733waitTicker("FM " + String(++tmpF / 10, 1) ); 1734} 1735// ================================================== 1736// 1737void tweakFreq(int Freq) 1738{ 1739// 1740// Sanity check 1741// 1742if (Freq < 889) Freq = 889; 1743if (Freq > 1079) Freq = 1079; 1744// 1745Serial.println("Set FM: " + String(Freq)); 1746radio.setFrequency(Freq); // Tell radio 1747LogLong(promFrequency, Freq); // Save in EPROM 1748// 1749showFM(); // Display freq 1750// 1751} 1752// ================================================== 1753// 1754void LogLong(int Addr, int Valu) 1755{ 1756// 1757EEPROM.update(Addr , lowByte( Valu)); 1758EEPROM.update(Addr + 1, highByte(Valu)); 1759} 1760// ================================================== 1761// ================================================== 1762// FIN 1763// ================================================== 1764// ==================================================
Alarm Clock with temp/humidity and EPROM backup
arduino
TOO BIG TO UPLOAD LATEST VERSION! SORRY - MSG ME HERE IF YOU NEED LATEST CODE Remote control alarm clock with 8x8x4 LED matrix display. 12/24 hr, alarm set, Temperature F/C mode, displays humidity, chimes the hour, displays date, auto off coffee relay (on with alarm, auto off hr later) Plays MP3 files randomly for wake up alarm as well as scrolling message and beeps. Ack silences alarm.
1// 2// Cindy's alarm clock - By Mark M. Lambert on February 20th, 2022 3// 4 Copyright Mark M. Lambert - All Rights Reserved 5// May 6 be used or excepted with attribution 7// 8const float Version = 6.19; 9// 10// 11 V6.19 - 18Mar22 - MML - Add radio code per original buttons 12// V6.18 - 17Mar22 13 - MML - Try I2C FM module with antenna! :D 14// V6.17 - 16Mar22 - MML - Swap ararm 15 set and relay on LED's 16// V6.16 - 11Mar22 - MML - Work on MP3 player 17// V6.15 18 - 10Mar22 - MML - Fix bug in alarm on 19// V6.14 - 08Mar22 - MML - Turn off log 20 dump & clean up auto off logic 21// V6.13 - 06Mar22 - MML - Invert Colon 22// 23 V6.12 - 04Mar22 - MML - Install SD card - read data on first compile! :D 24// V6.11 25 - 03Mar22 - MML - Lint 26// V6.10 - Omitted to prevent being mistaken for a large 27 rev 28// V6.09 - 01Mar22 - MML - Tweak display timing 29// V6.08 - 28Feb22 - MML 30 - Indicate power relay state 31// V6.07 - 27Feb22 - MML - Resequence 420 & 840, 32 simplify setting 33// V6.06 - 26Feb22 - MML - Add clock set (after glitching the 34 RTC) 35// V6.05 - 25Feb22 - MML - Wire & rough out radio code - polish 36// V6.04 37 - 24Feb22 - MML - Cleanup & tweak functionality 38// V6.03 - 23Feb22 - MML - Add 39 four digit 7 segment display & RTC 40// V6.02 - 22Feb22 - MML - Rough out command 41 framework. RTC module due today 42// V6.01 - 21Feb22 - MML - LCD, DHT working, 43 8x8x4 matrix & buzzer up, time displaying 44// V6.00 - 20Feb22 - MML - Subset/superset 45 of Rick Box to be custom alarm clock 46// V5.18 - 18Feb22 - MML - Fork from RTC 47 project. See for 'tween versions 48// V1.00 - 06Dec21 - MML - Baseline with LCD 49 - Mega 2650 has built in pullups 50// 51// ---------------------------------------------------------------------------- 52// 53 ---------------------------------------------------------------------------- 54// 55// 56 Device Master List 57// ================== 58// Mega 2560 Processor - 59 Works 60// Screw terminal shield - Works 61// 8x8x4 dot 62 matrix display module MOSI/MISO - Works 63// R/Y/G Traffic Light w/ traffic 64 signal shroud - Works 65// IR remote command in & remote - Works 66// 67 RTC - Works 68// DHT11 Temp/Humidity 69 - Works 70// MP3 player - Serial Control - for rude 71 wake up messages - Sorta works 72// Has own speaker - no relay needed 73// 74 Coffee Pot Relay - Works 75// SD Card with MISO/MOSI 76 - Works 77// Reset Button - 78 Works 79// Ack Button (also Select) - Works 80// Analog 81 pot for random input - Works 82// I2C FM radio module - 83 Works 84// 85// ================================== 86// Start of Pin Constants 87// 88 ================================== 89// 90// Analogs first 91// 92int xx = 93 0; // Placeholder value 94// 95const int Vnoise = A2; // Random 96 number seed is open AI 97const int Vin = A3; // Power supply direct output 98 monitor - NOT USED 99// 100const int I2C_A4 = A4; // RESERVED 101const int 102 I2C_A5 = A5; // RESERVED 103// 104// Float constant 105// 106const float aiSteps 107 = 1024.0; // 10 bit ADC 108const float VoltsPerBit = (5.0 / aiSteps); 109 // Compute bit weight based on +5 Vin max 110const float stepsPerHr = aiSteps 111 / 24.0; // Hours input 112const float stepsPerMin = aiSteps / 60.0; // Minutes 113 input 114const float stepsPerYr = aiSteps / 100.0; // Year input, 20xx presumed 115const 116 float stepsPerMon = aiSteps / 12.0; // Months input 117const float stepsPerDt 118 = aiSteps / 31.0; // Date input 119const float stepsPerDoW = aiSteps / 7.0; 120 // Day input, sat = 1, fri = 7 121const float stepsPerYN = aiSteps / 2.0; 122 // 0/1 123// 124const int Wiper = A15; // Wiper from 5k pot for data 125 entry 126// 127// Analogs end 128// ----------- 129// Now digitals 130// 131// 132 D0 and D1 are rx/tx for serial programming 133// 134// 2-10 sorta spare 135// 136// 137 D11 & 12 reserved for MOSI/MISO 138// D13 is LED_BUILTIN and is used (maybe) by 139 MOSI/MISO devices 140// 141// Comm channel I/O's 142// 143const int S3_TX = 144 14; // ESP-01 WiFi - not wired 145const int S3_RX = 15; 146// 147const int 148 S2_TX = 16; // Knob radio - OUT - See I2C 149const int S2_RX = 17; 150// 151const 152 int S1_TX = 18; // MP3 player 153const int S1_RX = 19; 154// 155// I2C 156 was brought out to buss bars for mass connections - wasn't needed 157// Actually 158 the one I2C device (FM radio) connected thru the SDA/SCL pins up by D13 159// 160const 161 int I2C_SDA = 20; // These are attached to the matching buss bars for bussing 162 to all I2C devices 163const int I2C_SCL = 21; // Pullups are internal to Mega 164 2560 165// 166// 22-25 free 167// 168// RTC I/O pins - Working fine - Use SET_CLOCK 169 project to preset time 170// 171const int kCePin = 26; // Chip Enable - grn 172const 173 int kIoPin = 27; // Input/Output - yel 174const int kSclkPin = 28; // Serial 175 Clock - orn 176// 177// 29-35 free 178// 179// Humidity/temp sensor - working great 180// 181const 182 int DHTPIN = 36; // Digital pin connected to the DHT sensor 183// 184// IR 185 remote control input - noisy - doesn't like LED lighting 186// 187const int RECV_PIN 188 = 37; //IR Receiver input pin 189// 190// On the remote there are seven rows 191 of three buttons each. 192// Each has a unique code. 193// We're going to define 194 the button codes here instead 195// of scattering them in a massive SWITCH. 196// 197// 198 ---------------------- 199// _00 = _RC, 0 indexed 200// 201// All the little IR 202 remotes appear to use the same set of codes 203// Determined empirically: 204// 205const 206 int Btn_00 = 23971; // Top Row, left button - Row 0, Col 0 207const int Btn_01 208 = 25245; // Row 0, Col 1 - 209const int Btn_02 = 7651; // Top Row, right 210 button - Row 0, Col 2 211// 212const int Btn_10 = 8925; // Row 1, col 0 - (red) 213const 214 int Btn_11 = 765; 215const int Btn_12 = 15811; 216// 217const int Btn_20 = 218 8161; 219const int Btn_21 = 22441; 220const int Btn_22 = 28561; 221// 222const 223 int Btn_30 = 26775; 224const int Btn_31 = 26521; 225const int Btn_32 = 20401; 226// 227const 228 int Btn_40 = 12495; 229const int Btn_41 = 6375; 230const int Btn_42 = 31365; 231// 232const 233 int Btn_50 = 4335; 234const int Btn_51 = 14535; 235const int Btn_52 = 23205; 236// 237const 238 int Btn_60 = 17085; 239const int Btn_61 = 19125; 240const int Btn_62 = 21165; 241 // Bottom Row, right button 242// 243// Ordered a differnet brand of IR remote 244 that has a DIFFERENT set of codes! 245// Haven't sussed everything out yet but there 246 is at least SOME overlap 247// I've got half a dozen of these little remotes and 248 this is the first 249// one that isn't a clone. Stay tuned - more to come 250// 251// 252 ---------------------- 253// 254// 38, 39 - SPARE 255// 256// Relay pin 257// 258const 259 int K2 = 40; // Coffee Pot 260// 261// 41-42 SPARE 262// 263const int 264 Buzzer = 43; //Annunciator 265// 266// 44 SPARE 267// 268const int AckBtn 269 = 45; // Acknowledge button to silence alarn 270// 271// Traffic lights are 272 near top end of DOs 273// 274const int TL_R = 46; // Alarm On 275const int 276 TL_Y = 47; // Follows AckBtn 277const int TL_G = 48; // Heartbeat 278// 279// 280 SD card is MOSI/MISO, needs its own CS line 281// 282const int sdSel = 49; // 283 SD card Chip Select 284// 285// 50-53 reserved for MOSI/MISO 286// SPI: 287// 50/25/11 288 (MISO) <<== not needed for output only 289// Needed for SD 290 card 291// 51/24/12 (MOSI) 292// 52/23/13 (SCK)z 293// 53/22/10 (SS) <<== 294 Device Select 295// 296// 11, 12 & 13 Are MISO/MOSI - AKA SPI on UNO 297// 22-25 298 reserved for MOSI/MISO SP1 devices 299// this conflicts with other docs or it may 300 be 301// uno vs mega 2560 302// 303// Initializes the SD library and card. 304// 305 This begins use of the SPI bus 306// pins 11, 12, and 13 on Arduino UNO boards; 307 308// pins 50, 51, and 52 on the Mega 309// and the chip select pin, 310// which 311 defaults to the hardware SS pin 312// pin 10 on Arduino UNO boards, 313// pin 314 53 on the Mega 315// 316// Got dot matrix and 4 digit readouts in 317// The matrix 318 needs MOSI and I think the readouts 319// are I2C, but I won't be sure until they 320 arrive 321// Modules arrived, waiting on cables 322// 323// Mega 2560 pinout is 324 correct - worked on first try 325// 326const int MISOLED = 50; // Needed for 327 8X8 LED matrix comms 328const int MOSILED = 51; 329const int SCKLED = 52; // 330 builtin LED & SPI clock 331const int CSLED = 53; // 8x8 x4 LED matrix CS line 332// 333// 334 End of Digitals 335// 336// ================================== 337// End of Pin 338 Constants 339// ================================== 340// 341// Device Constants 342// 343const 344 unsigned interval = 1200; // Don't overpoll 345// ---------------------------------------------------------------------------- 346// 347 ---------------------------------------------------------------------------- 348// 349// 350 EEPROM image - we need pointers, not variables 351// 352const int promTempFC = 353 0; // Flag - EEPROM BASE - ONLY ADD AT END 354const int promAlarmSet = 355 1; // Flag 356const int promMatrixBright = 2; // Int, 0-15 357const int 358 promClockMode12 = 3; // Flag 359const int promScrollRateMs = 4; // Int 360 50 to 100 typical 361const int promAlarmHr = 5; // Int - 0-23 362const 363 int promAlarmMin = 6; // Int - 0-59 364const int promFrequency = 7; 365 // Int - 889-1079, two BYTES 366// 367// ---------------------------------------------------------------------------- 368// 369 ---------------------------------------------------------------------------- 370// 371// 372 Includes - DO NOT REORDER 373// 374#include <EEPROM.h> //EEPROM support for 375 tables 376#include <stdio.h> 377#include <DHT.h> //Digital Humidity/Temp 378 sensor library 379#include <DS1302.h> //RTC library 380#include <IRremote.h> 381 //IR Remote Library 382// 383// These three includes MUST be in this order 384 or wierd "Error compiling for board Arduino Mega or Mega 2560." error 385// Wire.h 386 must load first 387// 388//#include <Wire.h> //I2C Driver 389//#include 390 <LiquidCrystal_I2C.h> //I2C LCD display driver for all LCD's 391// 392#include 393 <LG_Matrix_Print.h> // LED matrix - test works 394// 395// microSD card device 396// 397#include 398 <SPI.h> // SPI interface 399#include <SD.h> // SD Card 400// 401File 402 LogFile; // File object 403// ---------------------------------------------------------------------------- 404// 405#include 406 <SoftwareSerial.h> 407// 408// Define the RX and TX pins to establish UART communication 409 with the MP3 Player Module. 410// 411static int8_t loud[] = {0x31, 0x1E, 0x01}; 412 // 1E (max) volume, Play song 03 413static int8_t wake[] = {0x35, 0x02}; // 414 Wake up device 415static int8_t Reset[] = {0x35, 0x05}; // Reset device 416// 417// 418 Define the Serial MP3 Player Module. 419// 420SoftwareSerial MP3(S1_RX, S1_TX); 421 // Serial1 422// 423// ---------------------------------------------------------------------------- 424// 425// 426 I2C FM radio - test says it works - must be below WIRE.H 427// 428#include <radio.h> 429 // Generic 430#include <TEA5767.h> // Specific - defines terms like 431 RADIO_BAND_FM, etc./ 432// 433// The band that will be tuned by this sketch is FM. 434// 435#define 436 FIX_BAND RADIO_BAND_FM // US 437// 438// Station 107.9 FM 439// 440// #define 441 FIX_STATION 1079 442#define FIX_STATION 1029 443// 444TEA5767 radio; // Create 445 an instance of Class for TEA5767 Chip 446// 447// ---------------------------------------------------------------------------- 448// 449// 450 Start building objects 451// 452// Create 8x8x4 Matrix LED object 453// Number of 454 8x8 segments 455// 456const int segments = 4; 457// 458LG_Matrix_Print lmd(segments, 459 CSLED); 460// 461// Create a DS1302 RTC object. 462// 463DS1302 rtc(kCePin, kIoPin, 464 kSclkPin); 465// 466// Create humidity/temp object 467// 468//#define DHTTYPE DHT11 469 // DHT 11 470//DHT dht(DHTPIN, DHTTYPE); // Create Object 471// 472DHT dht(DHTPIN, 473 DHT11); // Create Object 474// 475// IR Remote control object 476// 477IRrecv 478 irrecv(RECV_PIN); // Build IR receiver object 479decode_results results; // 480 Not sure about this, but it works 481// 482// ------------------------- 483// Objects 484 built 485// ------------------------- 486// 487// Global state flags need to come 488 from EEPROM 489// 490// We have to manually, byte by byte figure out what goes where 491// 492 in the EEPROM. We've got 4k to tinker with and are limited to 493// ~100k write 494 operations on any given memory location. Rears 495// are unlimited. So you want 496 to check and only write changes 497// 498// 0000 - 0FFF - EEPROM range. Everything 499 runs on bytes 500// 501int BaseAddr = 0; 502int TopAddr = 4095; 503// 504// ****************************** 505// 506 Stare of EEPROM address pointers 507// 508// define start of each object in EEPROM 509 - ONLY ADD ITEMS AT END 510// 511// Declare stuff from EEPROM 512// 513int clockMode12 514 = false; 515int AlarmSet = false; 516int tempFC = false; 517int 518 MatrixBright = false; 519int scrollRateMs = false; 520int K2State = 521 false; 522int alarmHr = 11; //Default to 11:00a 523int alarmMin = 524 00; 525int onbyAlarm = false; 526// 527// Time & date setting vars - might 528 not need all 529// 530int clockDoW; //Day of week 531int clockHr; 532int clockMin; 533int 534 clockDt; 535int clockMon; 536int clockYr; 537// 538int aborted = false; //Return 539 flag from sloChime and Chime 540// 541const int MatrixMax = 15; // Max intensity 542 value 543String MatrixText; // Indeterminate string 544// 545// Temp/Humidity 546// 547float 548 h, f, c; // Humidity, TempF, TempC 549// 550int valx = 0; // variable to store 551 the value read 552// 553int MSH; // Pull TWO bytes for numbers > 255 554int 555 LSH; 556int Frequency; // Radio station 889-1079 557// 558// ============================================ 559// 560 SETUP 561// ============================================ 562// 563// Globalize 564// 565// 566 End of EEPROM address pointers 567// ****************************** 568int thisHr; 569int 570 thisMin; 571int thisSec; 572int thisDate; 573int thisMon; 574int thisYr; 575int 576 thisDay; 577// 578String logName = "logmm-yy.txt\\0"; //Template 579// 580float 581 tmpF; // Working float 582// 583// ================================================= 584// 585// 586 SETUP BEGINS 587// 588void setup() 589{ 590 // 591 // serial is 0/1, s1 is 18/19 592 - MP3, s2 is 16/17 - radio 593 // 594 Serial.begin(9600); // Warm up comm 595 ports 596 Serial1.begin(9600); // MP3 player 597 Serial2.begin(9600); // 598 SPARE 599 // 600 // Pull config 601 // 602 clockMode12 = EEPROM.read(promClockMode12 603 ); //Default to 12 hr time, false for 24, 604 AlarmSet = EEPROM.read(promAlarmSet 605 ); // Alarm Set/not, save in EEPROM 606 tempFC = EEPROM.read(promTempFC 607 ); // Farenheit/not celcius 608 MatrixBright = EEPROM.read(promMatrixBright); 609 // Start near dim 610 scrollRateMs = EEPROM.read(promScrollRateMs); // 611 scroll rate, lower is faster 612 alarmHr = EEPROM.read(promAlarmHr ); 613 // Hour 614 alarmMin = EEPROM.read(promAlarmMin ); // Minute 615 616 LSH = EEPROM.read(promFrequency ); // 889 to 1079 for FM radio 617 618 MSH = EEPROM.read(promFrequency +1); // 889 to 1079 for FM radio 619 620 Frequency = word(MSH, LSH); 621 // 622 // Send this to SD card too 623 // 624 625 Serial.println(F("Stored config:")); 626 Serial.println(F("==============")); 627 628 Serial.println("AM/PM-24: " + String( clockMode12)); 629 Serial.println("Alarm 630 Set: " + String( AlarmSet)); 631 Serial.println("Temp FC: " 632 + String( tempFC)); 633 Serial.println("Matrix Bright: " + String(MatrixBright)); 634 635 Serial.println("Scroll Rate (ms): " + String(scrollRateMs)); 636 Serial.println("Alarm 637 Hr: " + String( alarmHr)); 638 Serial.println("Alarm Min: " 639 + String( alarmMin)); 640 Serial.println("FM Radio Preset: " + String( Frequency)); 641 642 // 643 // Sanity check for uninitialized EEPROM 644 // 645 if (clockMode12 646 != false ) clockMode12 = true; 647 if (AlarmSet != false 648 ) AlarmSet = true; 649 if (tempFC != false ) 650 tempFC = true; 651 if ((MatrixBright > 15) || (MatrixBright < 0)) MatrixBright 652 = 2; 653 // 654 if ((scrollRateMs > 200) || (scrollRateMs < 25)) 655 { 656 657 scrollRateMs = 50; 658 LogProm(promScrollRateMs, scrollRateMs); 659 } 660 661 // 662 // Default alarm 663 // 664 if ((alarmHr > 23) || (alarmHr < 665 0) ) alarmHr = 11; 666 if ((alarmMin > 59) || (alarmMin < 0) ) 667 alarmMin = 00; 668 // 669 if ((Frequency < 889) || (Frequency > 1079) ) 670 671 { 672 Serial.println("Frequency defaulted"); 673 Frequency = 1029; 674 // Yes, force local preset 675 } 676 // 677 tweakFreq(Frequency); 678 // 679 680 // Interesting hardware note. If unpowered, the serial port 681 // BEGIN statement 682 will bring up the digital portion of the knob FM card 683 // just from the serial 684 line - VERY STRANGE 685 // But at least it tells me that I'm wired to the right 686 port 687 // 688 // Fire up RTC 689 // 690 rtc.writeProtect(false); //Gotta 691 unlock before letting it run 692 rtc.halt(false); //Let clock run 693 694 // 695 Time t = rtc.time(); // Device data type - read RTC 696 thisHr 697 = t.hr; 698 thisMin = t.min; 699 thisSec = t.sec; 700 thisDate = t.date; 701 702 thisMon = t.mon; 703 thisYr = t.yr; 704 thisDay = t.day; 705 // 706 707 String tmpStr = "log"; 708 if (thisMon < 10) tmpStr = "log0"; 709 tmpStr 710 += String(thisMon) + "-" + String(thisYr - 2000) + ".txt"; 711 logName = tmpStr 712 + "\\0"; 713 // 714 // DOS FAT 8.3 file names only 715 // 716 Serial.println("Current 717 Log file: " + tmpStr); 718 // 719 // INPUT is default but we need to make sure 720 they don't float with INPUT_PULLUP 721 // Declare all inputs as pullups 722 // 723 724 pinMode(AckBtn, INPUT_PULLUP); // Alarm acknowledge 725 // 726 // Relay 727 728 // 729 pinMode(K2, OUTPUT); // Coffee pot 730 digitalWrite(K2, false); 731 // Coffee pot, default off 732 // 733 pinMode(Buzzer, OUTPUT); 734 // 735 736 // Traffic lights 737 // 738 pinMode(TL_G, OUTPUT); // Heartbeat 739 pinMode(TL_Y, 740 OUTPUT); // Silent 741 pinMode(TL_R, OUTPUT); // Alarm set 742 // 743 digitalWrite(TL_G, 744 LOW); //Turn off 745 digitalWrite(TL_Y, LOW); //Turn off 746 digitalWrite(TL_R, 747 LOW); //Turn off 748 // 749 // Pins all set, anything not listed is a hi-Z 750 input 751 // 752 // ============ 753 // 754 // 8x8x4 LED matrix is cool, readable 755 display 756 // 757 lmd.setEnabled(true); 758 lmd.setIntensity(MatrixBright); 759 // 0 = low, 15 = high - set via pot or LDR or command 760 lmd.clear(); 761 lmd.stopTicker(); 762 //Stop any old message 763 // 764 chime(1); 765 waitTicker("Cindy's 766 Alarm Clock-V" + String(Version)); 767 // 768 // Turn on remote 769 // 770 irrecv.enableIRIn(); 771 772 // 773 // Crank up humitity/temp sensor 774 // 775 dht.begin(); // Fire 776 up temp/humidity sensor 777 Read_DHT(); // Read temp/humidity to prime vars 778 779 // 780 // Ok fine, we want to test the SD card reader with this code 781 // 782 783 if (!SD.begin(sdSel)) // Crank up SD card 784 { 785 Serial.println(F("SD 786 init failed")); 787 } 788 // 789 // Special stuff for I2C radio module 790 791 // 792 // Initialize the Radio 793 // 794 radio.init(); 795 // 796 // Enable 797 information to the Serial port 798 // 799 radio.debugEnable(); 800 // 801 // 802 Preset to 1079 803 // 804 radio.setBand(FIX_BAND); 805 radio.setFrequency(Frequency); 806 807 // 808 radio.setVolume(10); // 0-15 809 radio.setMono(false); // 810 No external indicator 811 // 812 // End of radio stuff 813 // 814 append(F("Restart")); 815 816 // 817 // We should see updated data 818 // 819 // readAfile(logName); // Try 820 to read log file & display - takes forever for long file, 821 // slows init 822 823 // 824// chime(2); // Let em know we're live 825 // 826 Serial.println("Wake"); 827 828 cmdMP3(wake, 2); 829 delay(500); 830 // 831 Serial.println("Reset"); 832 833 cmdMP3(Reset, 2); 834 delay(500); 835 // 836 Serial.println("Loud & play"); 837 838 cmdMP3(loud, 3); 839 delay(500); 840 // 841 } 842// ============================================ 843// 844// 845 SETUP ends 846// 847// ============================================ 848// ============================================ 849// 850// 851 LOOP BEGINS 852// 853// ============================================ 854// 855// 856 Globals 857// 858String colon = ":"; // Time marker default 859// 860int tmp; 861 // Working var 862String tmpStr; // Working strings 863String 864 IRval; // Reading from remote 865String LastIRCmd; 866int lastSec; 867// 868// 869 Declaring vars inside SWITCH blows up 870// 871// Fall into runtime 872// 873void 874 loop() 875 { 876 Time t = rtc.time(); 877 // 878 // Let LED matrix running 879 until eom 880 // 881 if (!lmd.updateTicker()) lmd.stopTicker(); //Stop at end 882 883 // 884 // Fast execution items lead 885 // 886 // We need to watch the RTC 887 and trigger when the seconds change 888 // 889 // hard poll IR while waiting 890 891 // 892 while (thisSec == lastSec) // Wait for clock to tick 893 { 894 t 895 = rtc.time(); 896 thisHr = t.hr; 897 thisMin = t.min; 898 thisSec 899 = t.sec; 900 thisDate = t.date; 901 thisMon = t.mon; 902 thisYr = 903 t.yr; 904 thisDay = t.day; 905 // 906 // IR remote code is big switch. 907 908 // There are 21 different buttons with unique responses 909 // 910 // 911 IR Remote needs to be shielded from other light sources 912 // Umm dunno how 913 fast we should poll this. Its fast polling now. 914 // but we might need to 915 slow it down 916 // 917 CheckIR(); // Does 21 different functions 918 // 919 920 // Update status lights in real time 921 // 922 digitalWrite(TL_R, digitalRead(K2)); 923 // Reminder that power relay is on is RED 924 digitalWrite(TL_Y, AlarmSet); 925 // Show if alarm is set amber 926 // 927 if (!lmd.updateTicker()) 928 lmd.stopTicker(); //Stop at end 929 // 930 } 931 // 932 // New second passes 933 934 // 935 digitalWrite(TL_G, !digitalRead(TL_G)); //Toggle heartbeat on second 936 937 // 938 lastSec = thisSec; // Note this second 939 // 940 // Alternate 941 : and . as tic-tok on 8x8x4 matrix 942 // 943 colon == ":" ? colon = "." : 944 colon = ":"; 945 // 946 // Display time 947 // 948 formTime(); 949 // 950 951 // Ok, from here on out we have our activities. 952 // Each looks at the time 953 and does their thing 954 // 955 // Check to see if the coffee pot is still on 956 after an hour 957 // if so, turn it off 958 // 959 int tempHr = alarmHr + 1; 960 961 if (tempHr > 23) tempHr = tempHr - 24; //Compensate for past midnight 962 // 963 964 if ( ( (tempHr == thisHr) && 965 (alarmMin == thisMin) ) && onbyAlarm) 966 967 { 968 digitalWrite(K2, LOW); //Turn off 969 onbyAlarm = false; 970 971 K2State = false; 972 // 973 Serial.print("K2 Auto off: " + String(tempHr) 974 + " " + String(thisHr) ); 975 blip(); // Little 976 noise to get you to look 977 waitTicker(F("Aux relay auto off")); // Let 978 user know 979 formTime(); // Show time 980 chime(3); 981 // Different 982 } 983 // 984 // Check for alarm 985 time being set 986 // 987 if ( (alarmHr == thisHr) && 988 (alarmMin 989 == thisMin) && 990 (thisSec == 0) && 991 AlarmSet) 992 { 993 994 // 995 // Kick on coffee pot relay - we should turn this 996 // off automatically 997 after an hour 998 // 999 blip(); // prealarm noise 1000 1001 digitalWrite(K2, HIGH); // Load comes on with alarm 1002 K2State = true; 1003 // Internal state flag - Y not read IO? 1004 onbyAlarm = true; // 1005 Alarm turned us on 1006 // 1007 // Wakey Wakey! 1008 // 1009 waitTicker(F("Wakey! 1010 Wakey!")); 1011 formTime(); //Show time 1012 // 1013 sloChime(10); 1014 if 1015 (!aborted) 1016 { 1017 waitTicker(F("Get up & PEE! The world's on FIRE!")); 1018 1019 formTime(); //Show time 1020 // 1021 sloChime(10); 1022 if (!aborted) 1023 1024 { 1025 waitTicker(F("Outta bed, sleepy head!")); 1026 formTime(); 1027 //Show time 1028 sloChime(10); 1029 } 1030 // 1031 } 1032 // 1033 1034 } 1035 // 1036 // Show temp at 1/4 past minute 1037 // 1038 if ( (thisSec 1039 == 15) && !lmd.updateTicker() ) 1040 { 1041 Read_DHT(); // Read temp/humidity 1042 1043 tempFC ? lmd.ticker(String(f, 1) + "F", scrollRateMs) : 1044 lmd.ticker(String(c, 1045 1) + "C", scrollRateMs); 1046 // 1047 } 1048 // 1049 // Show Date 1050 at 30 - add month names 1051 // 1052 if ( (thisSec == 30) && !lmd.updateTicker() 1053 ) 1054 lmd.ticker(String(thisMon) + 1055 "/" + String(thisDate) 1056 + 1057 "/" + String(thisYr).substring(2), scrollRateMs); 1058 // 1059 1060 // Show RH at 3/4 of minute - use reading from :15 1061 // 1062 if ( (thisSec 1063 == 45) && !lmd.updateTicker() ) 1064 lmd.ticker(String(h, 0) + "% RH", 1065 scrollRateMs); 1066 // 1067 // Min = 0 & sec = 0 = hour strike 1068 // 1069 if ( 1070 (thisMin == 0) && (thisSec == 0) ) 1071 { 1072 blip(); //Little 1073 noise to make you look 1074 waitTicker(F("Cuckoo! Cuckoo!")); 1075 formTime(); 1076 // Show time 1077 // 1078 tmp = thisHr; // Time from globals 1079 1080 // 1081 if ((tmp > 12) && (clockMode12)) tmp = tmp - 12; //Civilian time 1082 1083 // 1084 // Start and end times need to be selectable 1085 if ((thisHr > 1086 10) && (thisHr < 23)) // Only chime 11A-11P per swmbo 1087 { 1088 sloChime(tmp); 1089 //Change to MP3 "Bong" when I get it installed 1090 } 1091 // 1092 } 1093 1094 // 1095 // Later in execution overrides time display above 1096 // 1097 if ((thisHr 1098 == 16) && (thisMin == 20) && (thisSec == 0)) 1099 { 1100 blip(); //Little 1101 noise to make you look 1102 waitTicker(F("It's 4:20! SMOKE BREAK!")); 1103 formTime(); 1104 // Show time 1105 sloChime(4); 1106 // 1107 waitTicker(F("It's 1108 4:20! Time to roll a fattie!")); 1109 formTime(); // Show time 1110 1111 sloChime(2); 1112 } 1113 // 1114 if ((thisHr == 20) && (thisMin == 40) && 1115 (thisSec == 0)) 1116 { 1117 blip(); //Little noise to make you look 1118 1119 waitTicker(F("It's 8:40! TIME TO SMOKE!")); 1120 formTime(); // 1121 Show time 1122 sloChime(8); 1123 // 1124 waitTicker(F("It's 8:40! Time to 1125 Relax!")); 1126 formTime(); // Show time 1127 sloChime(4); 1128 } 1129 1130 // 1131 // Log data on 1/4 hour 1132 // 1133 if ( ((thisMin == 0) || 1134 (thisMin 1135 == 15) || 1136 (thisMin == 30) || 1137 (thisMin == 45)) && (thisSec 1138 == 0)) 1139 append(""); // Append to log 1140 // 1141 } // End of 1142 LOOP 1143// ============================================================================= 1144// 1145 ============================================================================= 1146// 1147 Functions 1148// ============================================================================= 1149// 1150 ============================================================================= 1151// 1152// 1153 Function to read and display Temp Humidity from sensor 1154// 1155void Read_DHT() 1156 1157 { 1158 // 1159 // Reading temperature or humidity takes about 250 milliseconds! 1160 1161 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 1162 1163 // 1164 h = dht.readHumidity(); // Get humidity 1165 c = dht.readTemperature(false); 1166 // Read temperature as Celsius (the default) 1167 f = dht.readTemperature(true); 1168 // Read temperature as Fahrenheit (isFahrenheit = true) 1169 // 1170 } 1171// 1172// 1173 ================================================== 1174// 1175// Ring the bell very 1176 short 1177// 1178void blip() 1179{ 1180digitalWrite(Buzzer, true); 1181delay(20); 1182digitalWrite(Buzzer, 1183 false); 1184} 1185// ================================================== 1186// 1187// 1188 Ring the bell rings times with .1 sec between beeps 1189// 1190void chime(int rings) 1191{ 1192if 1193 (rings > 12) rings = rings - 12; //Fudge for midnight rollover 1194// 1195for (int 1196 i = 0; i < rings; i++) 1197 { 1198 if (!digitalRead(AckBtn)) break; 1199 // 1200 1201 digitalWrite(Buzzer, true); 1202 delay(100); 1203 digitalWrite(Buzzer, false); 1204 1205 if (!digitalRead(AckBtn)) break; 1206 // 1207 delay(100); 1208 } 1209// 1210} 1211// 1212 ================================================== 1213// 1214// Ring the bell rings 1215 times with 1 sec between beeps 1216// 1217void sloChime(int rings) 1218{ 1219aborted 1220 = false; 1221// 1222if (rings > 12) rings = rings - 12; //Fudge for midnight rollover 1223// 1224for 1225 (int i = 0; i < rings; i++) 1226 { 1227 if (!digitalRead(AckBtn)) 1228 { 1229 aborted 1230 = true; 1231 break; 1232 } 1233 // 1234 // Don't abort in middle of pulse, sound 1235 stays on forever 1236 // 1237 digitalWrite(Buzzer, true); 1238 delay(200); 1239 digitalWrite(Buzzer, 1240 false); 1241 if (!digitalRead(AckBtn)) 1242 { 1243 aborted = true; 1244 break; 1245 1246 } 1247 // 1248 delay(800); 1249 } 1250// 1251} 1252// ================================================== 1253// 1254void 1255 CheckIR() 1256{ 1257// 1258// This is the master remote control switch. 1259// See 1260 discussion on button structure near front 1261// 1262if (irrecv.decode(&results)) 1263 1264 { 1265 // Display what we got 1266 // 1267 valx = abs(results.value); 1268 // no negatives 1269 IRval = String( abs(valx) ); // no negatives 1270 1271 IRval.trim(); //Strange Syntax 1272 LastIRCmd.trim(); 1273 // 1274 // 1275 Catch value 1276 // 1277 if ( (valx > 0) && (LastIRCmd != IRval)) 1278 { 1279 1280 if (IRval != "") 1281 { 1282 LastIRCmd = IRval; 1283 LastIRCmd.trim(); 1284 1285 } 1286 // 1287 } 1288 // 1289 // Live command when received 1290 // 1291 1292 Serial.print(F("RXD: = ")); 1293 valx = abs(valx); 1294 Serial.println(valx); 1295 1296 // 1297 // Ok, No silly negatives, Each button sends a code, both remotes 1298 send 1299 // the same code for the same physical button 1300 // 1301 // ============================= 1302 1303 // ============================= 1304 // Main control switch on remote command 1305 1306 // ============================= 1307 // ============================= 1308 1309 // 1310 if (valx >= 1) // Triple filter out negs 1311 { 1312 1313 // 1314 // At this point all 21 buttons have an 1315 // assigned 1316 (if not yet fully implemented) function 1317 // 1318 // ====================== 1319 1320 // Radio Alarm AM/PM 1321 // On/off Device 24 hr 1322 // 1323 ---------------------- 1324 // Temp Full F/C 1325 // Humidity 1326 Date 1327 // ---------------------- 1328 // Dim Bright Set 1329 1330 // Clock 1331 // ---------------------- 1332 // 1333 Show Toggle Set 1334 // Alarm Alarm Alarm 1335 // ---------------------- 1336 1337 // Prev Next Vol 1338 // Sta Sta Up 1339 // 1340 ---------------------- 1341 // Station Station Vol 1342 // "A" "B" 1343 Dn 1344 // ---------------------- 1345 // Set Dim Mute 1346 1347 // Sta A/B 1348 // ====================== 1349 // 1350 switch 1351 (valx) //Needs integer for switch 1352 { 1353 // 1354 // 1355 Button codes in table up front - all tested & work 1356 // 1357 case 1358 Btn_00: 1359 Serial.println(F("btn 00")); 1360 chime(1); 1361 1362 // 1363 break; 1364 // ================= 1365 case 1366 Btn_01: 1367 Serial.println(F("btn 01")); 1368 chime(1); 1369 1370 K2State = !K2State; // Toggle state 1371 K2State ? MatrixText 1372 = "Power ON" : MatrixText = "Power Off"; 1373 // 1374 onbyAlarm 1375 = false; // Manual control, cancel auto flag 1376 // 1377 // 1378 Save for power blip 1379 // 1380 digitalWrite(K2, K2State); 1381 // Tell hardware 1382 lmd.ticker(MatrixText, scrollRateMs); 1383 // 1384 1385 break; 1386 // ================= 1387 case 1388 Btn_02: 1389 Serial.println(F("btn 02")); 1390 chime(1); 1391 1392 // 1393 // Toggle 12/24 hour 1394 // 1395 clockMode12 1396 = !clockMode12; 1397 clockMode12 ? MatrixText = "AM/PM" : MatrixText 1398 = "24 hour"; 1399 // 1400 lmd.ticker(MatrixText, scrollRateMs); 1401 1402 LogProm(promClockMode12, clockMode12); 1403 // 1404 break; 1405 1406 // ================= 1407 // 2nd Row 1408 // 1409 case 1410 Btn_10: 1411 Serial.println(F("btn 10")); 1412 chime(1); 1413 1414 // 1415 // Display Temperature 1416 // 1417 // 1418 Check FC flag to show in C or F 1419 // 1420 tempFC ? MatrixText 1421 = String(f, 1) + "F/" : 1422 MatrixText = String(c, 1) + "C/"; 1423 1424 // 1425 lmd.ticker(MatrixText + String(h, 0) + "% RH", scrollRateMs); 1426 1427 // 1428 break; 1429 // ================= 1430 case 1431 Btn_11: 1432 Serial.println(F("btn 11")); 1433 chime(1); 1434 1435 // 1436 // Display date - I know there's a smarter way, 1437 1438 // but my C++ skills aren't that sharp about arrays 1439 // 1440 1441 tmpStr = ""; 1442 switch (thisDay) 1443 { 1444 1445 case 1: 1446 tmpStr = "Sun"; 1447 break; 1448 1449 // ========== 1450 case 2: 1451 tmpStr = "Mon"; 1452 1453 break; 1454 // ========== 1455 case 3: 1456 1457 tmpStr = "Tues"; 1458 break; 1459 // ========== 1460 1461 case 4: 1462 tmpStr = "Wednes"; 1463 break; 1464 1465 // ========== 1466 case 5: 1467 tmpStr = "Thurs"; 1468 1469 break; 1470 // ========== 1471 case 6: 1472 1473 tmpStr = "Fri"; 1474 break; 1475 // ========== 1476 1477 case 7: 1478 tmpStr = "Satur"; 1479 break; 1480 1481 // ========== 1482 } 1483 // 1484 lmd.ticker(tmpStr 1485 + "day, " + 1486 String(thisMon) + "/" + 1487 String(thisDate) 1488 + "/" + 1489 String(thisYr), scrollRateMs); 1490 // 1491 1492 break; 1493 // ================= 1494 case Btn_12: 1495 1496 Serial.println(F("btn 12")); 1497 chime(1); 1498 // 1499 1500 // Toggle F/C 1501 // 1502 tempFC = !tempFC; //Flip 1503 flag 1504 tempFC ? lmd.ticker(String(f, 1) + "F", scrollRateMs) : 1505 1506 lmd.ticker(String(c, 1) + "C", scrollRateMs); 1507 // 1508 1509 LogProm(promTempFC, tempFC); 1510 // 1511 break; 1512 1513 // ================= 1514 // 3rd Row 1515 // 1516 case 1517 Btn_20: 1518 Serial.println(F("btn 20")); 1519 chime(1); 1520 1521 // 1522 // Dim matrix 1523 // 1524 MatrixBright--; 1525 1526 if (MatrixBright < 0) MatrixBright = 0; 1527 // 1528 lmd.setIntensity(MatrixBright); 1529 // 0 = low, 15 = high 1530 LogProm(promMatrixBright, MatrixBright); 1531 1532 // 1533 break; 1534 // ================= 1535 case 1536 Btn_21: 1537 Serial.println(F("btn 21")); 1538 chime(1); 1539 1540 // 1541 // Brighten matrix 1542 // 1543 ++MatrixBright; 1544 1545 if (MatrixBright > MatrixMax) MatrixBright = MatrixMax; 1546 // 1547 1548 lmd.setIntensity(MatrixBright); // 0 = low, 15 = high 1549 LogProm(promMatrixBright, 1550 MatrixBright); 1551 // 1552 break; 1553 // ================= 1554 1555 case Btn_22: 1556 Serial.println(F("btn 22")); 1557 chime(1); 1558 1559 // 1560 // Need to have a check to prevent going 1561 // 1562 thru this needlessly. 1563 // Allow bail out after time set 1564 // 1565 don't force date setting 1566 // 1567 waitTicker(F("Are You 1568 Sure? 00-No, 01-Yes:")); 1569 tmp = waitForIt(stepsPerYN, "Ok: ", 0, 1570 ""); 1571 delay(250); 1572 chime(1); 1573 if (tmp 1574 == 1) 1575 { 1576 // 1577 // Ok, set Clock Hour 1578 1579 // 1580 chime(1); 1581 waitTicker(F("Dial 1582 Hour:")); 1583 clockHr = waitForIt(stepsPerHr, "", 0, ":xx" ); 1584 1585 chime(1); 1586 // 1587 // Now get minute 1588 1589 // 1590 waitTicker(F("Dial Min:")); 1591 // 1592 M is wider than normal, need to lose the : 1593 clockMin = waitForIt(stepsPerMin, 1594 String(clockHr) + ":", 0, ""); 1595 chime(1); 1596 // 1597 1598 // Do they wanna bail? 1599 waitTicker(F("Set Date? 00-No, 1600 01-Yes:")); 1601 if (waitForIt(stepsPerYN, "Ok: ", 0, "") == 1) 1602 1603 { 1604 chime(1); 1605 // 1606 // 1607 Now get month 1608 // 1609 delay(250); 1610 waitTicker(F("Dial 1611 Month:")); 1612 // M is wider than normal, need to lose the : 1613 1614 clockMon = waitForIt(stepsPerMon, "", 1, "/xx"); 1615 chime(1); 1616 1617 delay(250); 1618 // 1619 // Now get 1620 date 1621 // 1622 waitTicker(F("Dial Date:")); 1623 1624 clockDt = waitForIt(stepsPerDt, String(clockMon) + "/", 1, ""); 1625 1626 chime(1); 1627 // 1628 // Year = error 1629 trap 1630 // 1631 clockYr = 2021; 1632 while 1633 (clockYr < 2022) 1634 { 1635 waitTicker(F("Dial 1636 Year:")); 1637 clockYr = 2000 + waitForIt(stepsPerYr, "20", 0, 1638 ""); 1639 } 1640 // 1641 chime(1); 1642 1643 // 1644 // Now get day of week 1645 // 1646 1647 waitTicker(F("Dial Day, Sun-01, Sat-07:")); 1648 clockDoW 1649 = waitForIt(stepsPerDoW, "Day:", 1, ""); 1650 } 1651 else 1652 1653 { 1654 // 1655 // Use current date 1656 1657 // 1658 clockYr = thisYr; 1659 clockMon 1660 = thisMon; 1661 clockDt = thisDate; 1662 clockDoW 1663 = thisDay; 1664 } 1665 // 1666 // We need 1667 to wait for operator to click 1668 // to sync setting. Need to write 1669 data 1670 // to RTC after go 1671 // 1672 chime(1); 1673 1674 delay(250); 1675 waitTicker(F("Press to sync ...")); 1676 1677 chime(1); // Ack 1678 lmd.stopTicker(); 1679 lmd.clear(); 1680 1681 lmd.printText(0, "NOW!"); 1682 lmd.display(); 1683 1684 // 1685 while (digitalRead(AckBtn)) 1686 { 1687 1688 // Wait for press 1689 } 1690 // 1691 1692 blip(); 1693 // 1694 // Write time to RTC 1695 1696 // 1697 setRTC(clockYr, clockMon, clockDt, clockHr, clockMin, 1698 clockDoW); 1699 // 1700 chime(2); // Ack 1701 // 1702 1703 } 1704 // 1705 // 1706 break; 1707 // 1708 ================= 1709 // 4th Row 1710 // 1711 case Btn_30: 1712 1713 Serial.println(F("btn 30")); 1714 chime(1); 1715 // 1716 1717 // Alarm show 1718 // 1719 MatrixText = "Alarm 1720 Time: " + String(alarmHr) + ":"; 1721 if (alarmMin < 10) MatrixText 1722 += "0"; 1723 MatrixText += String(alarmMin); 1724 // 1725 AlarmSet 1726 ? MatrixText += " ON" : MatrixText += " OFF"; 1727 // 1728 lmd.ticker(MatrixText, 1729 scrollRateMs); 1730 // 1731 break; 1732 // ================= 1733 1734 case Btn_31: 1735 Serial.println(F("btn 31")); 1736 chime(1); 1737 1738 // 1739 // Alarm on/off 1740 // 1741 AlarmSet 1742 = !AlarmSet; 1743 if (AlarmSet) 1744 { 1745 MatrixText 1746 = "Alarm Set On: " + String(alarmHr) + ":"; 1747 if (alarmMin < 1748 10) MatrixText += "0"; 1749 MatrixText += String(alarmMin); 1750 } 1751 1752 else 1753 { 1754 MatrixText = "Alarm Off"; 1755 1756 chime(1); // Twice is off - like car alarm 1757 } 1758 1759 // 1760 onbyAlarm = false; 1761 lmd.ticker(MatrixText, 1762 scrollRateMs); 1763 LogProm(promAlarmSet, AlarmSet); 1764 // 1765 1766 break; 1767 // ================= 1768 case Btn_32: 1769 1770 Serial.println(F("btn 32")); 1771 chime(1); 1772 // 1773 1774 // Ok, set Alarm Hour 1775 // 1776 waitTicker(F("Dial 1777 Hour:")); 1778 alarmHr = waitForIt(stepsPerHr, "", 0, ":xx"); 1779 1780 chime(1); 1781 // 1782 // Now get minute 1783 // 1784 1785 waitTicker(F("Dial Min:")); 1786 alarmMin = waitForIt(stepsPerMin, 1787 String(alarmHr) + ":", 0, ""); 1788 chime(1); 1789 delay(250); 1790 1791 // 1792 tmpStr = "Alarm On: " + String(alarmHr) + ":"; 1793 1794 if (alarmMin < 10) tmpStr += "0"; 1795 // 1796 tmpStr 1797 += String(alarmMin); 1798 waitTicker(tmpStr); 1799 chime(1); 1800 1801 // 1802 // Save and turn alarm on automatically 1803 // 1804 1805 AlarmSet = true; 1806 onbyAlarm = false; // Clear 1807 old state 1808 // 1809 // Retain state 1810 // 1811 1812 LogProm(promAlarmHr, alarmHr); 1813 LogProm(promAlarmMin, 1814 alarmMin); 1815 LogProm(promAlarmSet, AlarmSet); 1816 // 1817 1818 chime(2); // Ack 1819 // 1820 break; 1821 // 1822 ================= 1823 // 5th Row 1824 // Originally this was for 1825 FM radio control 1826 // Since I had no luck getting it to run 1827 // 1828 OUT - these buttons can be used for the 1829 // MP3 or other control functions 1830 1831 // 1832 case Btn_40: 1833 Serial.println(F("btn 40")); 1834 1835 chime(1); 1836 // 1837 tmp = radio.getFrequency(); 1838 1839 --tmp; // Dump once 1840 tweakFreq(tmp); 1841 // 1842 1843 break; 1844 // ================= 1845 case Btn_41: 1846 1847 Serial.println(F("btn 41")); 1848 chime(1); 1849 // 1850 1851 tmp = radio.getFrequency(); 1852 ++tmp; // Bump thrice 1853 1854 ++tmp; 1855 ++tmp; 1856 tweakFreq(tmp); 1857 // 1858 1859 break; 1860 // ================= 1861 case 1862 Btn_42: 1863 Serial.println(F("btn 42")); 1864 chime(1); 1865 1866 // 1867 // Volume Up doesn't work on this 1868 // 1869 particular module. It's a preamp 1870 // so it's always at full blast 1871 or muted 1872 // 1873 // Old test function 1874 // 1875 Test button for MP3 player 1876 // 1877 Serial.println("Play 1878 3"); 1879 playSong(3); 1880 // 1881 break; 1882 // 1883 ================= 1884 // 6th Row 1885 // 1886 case Btn_50: 1887 1888 Serial.println(F("btn 50")); 1889 chime(1); 1890 // 1891 1892 // Saved Station "A" 1893 // 1894// radioCmd = 1895 "AT+FRE=" + String(freqA); 1896 // 1897 break; 1898 // 1899 ================= 1900 case Btn_51: 1901 Serial.println(F("btn 1902 51")); 1903 chime(1); 1904 // 1905 // Saved Station 1906 "B" 1907 // 1908// radioCmd = "AT+FREQ=" + String(freqB); 1909 1910 // 1911 break; 1912 // ================= 1913 case 1914 Btn_52: 1915 Serial.println(F("btn 52")); 1916 chime(1); 1917 1918 // 1919 // Volume Down doesn't work on this 1920 // 1921 particular module. It's a preamp 1922 // so it's always at full blast 1923 or muted 1924 // 1925 break; 1926 // ================= 1927 1928 // 7th and last Row 1929 // 1930 case Btn_60: 1931 Serial.println(F("btn 1932 60")); 1933 chime(1); 1934 // 1935 // This will allow 1936 setting of 1937 // the station presets selected 1938 // above 1939 at btn_50 and btn_51 1940 // 1941 tmp = waitForIt( 1024/200, 1942 "F:", 881, ""); 1943 tweakFreq(tmp); 1944 // 1945 break; 1946 1947 // ================= 1948 case Btn_61: 1949 Serial.println(F("btn 1950 61")); 1951 chime(1); 1952 // 1953 // Toggle matrix 1954 1955 // Dim/restore display 1956 // 1957 (MatrixBright 1958 != 0) ? MatrixBright = 0 : 1959 MatrixBright = 1960 EEPROM.read(promMatrixBright); 1961 // 1962 lmd.setIntensity(MatrixBright); 1963 // 0 = low, 15 = high 1964 // 1965 // Since we didn't update 1966 EEPROM the preset 1967 // brightness will restore on next reset 1968 // 1969 1970 break; 1971 // ================= 1972 case Btn_62: 1973 1974 Serial.println(F("btn 62")); 1975 chime(1); 1976 // 1977 1978 // Toggle radio Mute & display frequency 1979 // 1980 radio.setMute(!radio.getMute() 1981 ); 1982 // 1983 showFM(); 1984 // 1985 break; 1986 1987 // ================= 1988 // 1989 // SWITCH VAL ENDS 1990 1991 // 1992 } 1993 // 1994 // 1995 } // If Val ends 1996 1997 // 1998 // Resume IR control - not really sure what this does. 1999 // 2000 2001 irrecv.resume(); 2002 } // Decode ends 2003 // 2004} 2005// ================================================== 2006// 2007// 2008 Updates given EEPROM *BYTE* address with value, ints > 255 need TWO! 2009// 2010void 2011 LogProm(int Addr, int Valu) 2012{ 2013EEPROM.update(Addr, Valu); 2014} 2015// ================================================== 2016// 2017// 2018 Keep marquee spinning - no DELAY's allowed 2019// 2020void dillyDally(int mills2wait) 2021{ 2022// 2023int 2024 rightNow = millis(); 2025// 2026while (millis() < rightNow + mills2wait) 2027 { 2028 2029 if (!lmd.updateTicker()) 2030 { 2031 lmd.stopTicker(); //Stop at end 2032 2033 lmd.clear(); 2034 } 2035 // 2036 } 2037// 2038} 2039// ================================================== 2040// 2041// 2042 Spin hard letting ticker run - data from globals 2043// 2044void waitTicker(String 2045 Msg) 2046{ 2047lmd.ticker(Msg, scrollRateMs); 2048// 2049 while (lmd.updateTicker()) 2050 2051 { 2052 if (!digitalRead(AckBtn)) 2053 { 2054 aborted = true; //Pass up 2055 food chain 2056 break; 2057 // ========= 2058 } 2059 // 2060 } 2061// 2062} 2063// 2064 ================================================== 2065// 2066// Waits for input via 2067 pot, ended with ackbtn 2068// 2069// pot input 0-1023 is scaled by steps 2070// input 2071 is prompted with cue 2072// 0/1 origin is set with bias 2073// 2074// Scaled value 2075 returned 2076// 2077int waitForIt(float steps, String cue, int bias, String Suffix) 2078{ 2079// 2080String 2081 tmpCue = cue; 2082int myTmp; //Return var 2083// 2084lmd.stopTicker(); 2085lmd.clear(); 2086// 2087while 2088 (digitalRead(AckBtn)) 2089 { 2090 tmpCue = ""; // Unpad for next loop 2091 myTmp 2092 = (analogRead(Wiper) / steps); 2093 if (cue == "") 2094 { 2095 // 1st col 2096 - pad with blank 2097 if (myTmp < 10) tmpCue = " "; 2098 lmd.printText(0, 2099 tmpCue + String(myTmp + bias) + Suffix, true); //0 index 2100 } 2101 else 2102 2103 { 2104 // 2nd col - pad with zero 2105 if (myTmp < 10) tmpCue = "0"; 2106 2107 lmd.printText(0, cue + tmpCue + String(myTmp + bias) + Suffix, true); //0 index 2108 2109 } 2110 // 2111 lmd.display(); 2112 delay(100); //Can't dillydally static display 2113 2114 lmd.clear(); 2115 } 2116// 2117while (!digitalRead(AckBtn)) // Wait on release 2118 2119 { 2120 } 2121// 2122chime(1); 2123return myTmp + bias; 2124// 2125} 2126// ================================================== 2127// 2128void 2129 setRTC(int yr, int mo, int dt, int hr, int mn, int dow) 2130{ 2131rtc.writeProtect(false); 2132rtc.halt(true); 2133 //Shouldn't this be TRUE? 2134// 2135// Make a new time object to set the date and 2136 time. 2137// Sunday, September 22, 2013 at 01:38:50. 2138// 2139// Full spec includes 2140 seconds and DoW 2141// 2142// Time t(yr, mo, dt, hr, mn, 00, Time::kTuesday); 2143// 2144// 2145 Load the object, will it puke w/o secs & DoW? 2146// 2147Time t(yr, mo, dt, hr, mn, 2148 00, dow); 2149// 2150// Set the time and date on the chip. 2151// 2152rtc.time(t); 2153// 2154 2155rtc.halt(false); //Let clock run 2156rtc.writeProtect(true); //Only 2157 protect AFTER letting it run 2158// 2159} 2160// ================================================== 2161// 2162void 2163 formTime() 2164{ 2165String outStr; 2166int wrk = thisHr; // Time from globals 2167// 2168if 2169 ((wrk > 12) && (clockMode12)) wrk = wrk - 12; //Civillian time 2170// 2171clockMode12 2172 ? outStr = " " : outStr = "0"; // Pad leader 2173// 2174if (wrk >= 10) outStr 2175 = ""; // No pad needed 2176// 2177outStr += String(wrk) + colon; // Tick tock 2178 symbol 2179// 2180if (thisMin < 10) outStr += "0"; // Pad leading zero on minutes 2181outStr 2182 += String(thisMin); 2183// 2184// Send time to 8X8x4 LED matrix display if not busy 2185// 2186if 2187 (clockMode12) ((thisHr < 12) ? outStr += "a" : outStr += "p"); 2188// 2189if (!lmd.updateTicker()) 2190 2191 { 2192 lmd.stopTicker(); // Kill scrolling msg (pro forma) 2193 lmd.clear(); 2194 // Blank 2195 lmd.printText(0, outStr, true); // 0 index static 2196 text 2197 lmd.display(); // Display 2198 } 2199// 2200} 2201// ================================================== 2202// 2203// 2204 Clean up 2205// 2206void readAfile(String fileName) 2207{ 2208// 2209// Crack open file 2210 and return file handle 2211// 2212int bytes = 0; // Bytes read 2213// 2214// filename 2215 is being returned as a number? 2216File aFile = SD.open(String(fileName)); //Returns 2217 handle or false on fail 2218if (aFile) // Success! 2219 { 2220 Serial.println("Reading: 2221 " + fileName); 2222 // 2223 // read from the file until there's nothing else in 2224 it: 2225 // 2226 while (aFile.available()) // not EOF 2227 { 2228 // Byte 2229 level copy? 2230 // 2231 Serial.write(aFile.read()); // Copy byte to comm 2232 port for visibility 2233 bytes++; // Goose counter 2234 } 2235 // 2236 2237 // close the file 2238 // 2239 aFile.close(); 2240 // 2241 // Summary to serial 2242 port 2243 // 2244 Serial.println(String(bytes) + " bytes read"); 2245 // 2246 } 2247// 2248} 2249// 2250 ================================================== 2251// 2252// Append to log file 2253// 2254void 2255 append(String lineOtext) 2256{ 2257// Pass a line of text. Filename is given 2258// 2259File 2260 aFile; 2261Serial.println("Opening: " + logName); 2262aFile = SD.open(logName, FILE_WRITE); 2263 //Returns handle or false on fail 2264if (aFile) // Success! 2265 { 2266 // 2267 2268 String Hr = String(thisHr); 2269 if (thisHr < 10) Hr = "0" + Hr; 2270 String 2271 Mn = String(thisMin); 2272 if (thisMin < 10) Mn = "0" + Mn; 2273 aFile.println(" 2274 D&T: " + String(thisMon) + "/" + String(thisDate) 2275 + 2276 " @ " + Hr + ":" + Mn ); 2277 aFile.println("Temp: " + String(f, 1) + "F"); 2278 2279 aFile.println("RH %: " + String(h, 0)); // Data is integer 2280 // 2281 // 2282 Only append if not blank 2283 // 2284 if (lineOtext != "") aFile.println("[" 2285 + lineOtext + "]"); 2286 // 2287 aFile.close(); 2288 // 2289 Serial.println(F("Log 2290 updated")); 2291 } 2292else 2293 { 2294 Serial.println("Pbbbt! Failed file open 2295 of " && logName); 2296 } 2297// 2298} 2299// ================================================== 2300// 2301// 2302 Send random command to player 2303// 2304void cmdMP3(int8_t command[], int len) 2305{ 2306// 2307// 2308 Rewrite to compute length and prefix/suffix automatically 2309// 2310Serial.print("7E 2311 "); 2312Serial1.write(0x7E); // Prefix 2313// 2314Serial.print(String(len +1, HEX)); 2315Serial.print(" 2316 "); // Pad with blank for readability 2317Serial1.write(len +1); // Bytes to 2318 follow including suffix 2319// 2320for(int i = 0; i < len; i++) 2321 { 2322 // 2323 2324 Serial1.write(lowByte( command[i] ) ); // Send byte 2325 Serial.print(String( 2326 lowByte( command[i] ), HEX)); // mask LSH to prevent minus extend 2327 Serial.print(" 2328 "); // Pad with blank for readability 2329 } 2330// 2331Serial.println("EF"); 2332Serial1.write(0xEF); 2333 // Suffix 2334// 2335} 2336// ================================================== 2337// 2338void 2339 playSong(int song) 2340{ 2341// 2342// Rewrite to compute length and prefix/suffix 2343 automatically 2344// 2345Serial1.write(0x7E); // Prefix 2346Serial1.write(0x04); 2347 // Bytes to follow including suffix 2348Serial1.write(0x31); // Set Volume 2349 command & play # 2350Serial1.write(0x1E); // Volume to full 2351// 2352Serial1.write(0x01); 2353 // Send song # 2354// 2355Serial1.write(0xEF); // Suffix 2356// 2357} 2358// 2359 ================================================== 2360// 2361// Display station from 2362 radio 2363// 2364void showFM() 2365{ 2366tmpF = radio.getFrequency(); 2367waitTicker("FM 2368 " + String(++tmpF / 10, 1) ); 2369} 2370// ================================================== 2371// 2372void 2373 tweakFreq(int Freq) 2374{ 2375// 2376// Sanity check 2377// 2378if (Freq < 889) Freq 2379 = 889; 2380if (Freq > 1079) Freq = 1079; 2381// 2382Serial.println("Set FM: " + 2383 String(Freq)); 2384radio.setFrequency(Freq); // Tell radio 2385LogLong(promFrequency, 2386 Freq); // Save in EPROM 2387// 2388showFM(); // Display freq 2389// 2390} 2391// 2392 ================================================== 2393// 2394void LogLong(int Addr, 2395 int Valu) 2396{ 2397// 2398EEPROM.update(Addr , lowByte( Valu)); 2399EEPROM.update(Addr 2400 + 1, highByte(Valu)); 2401} 2402// ================================================== 2403// 2404 ================================================== 2405// FIN 2406// ================================================== 2407// 2408 ==================================================
Downloadable files
Traffic Light Display
Traffic Light assembly & wiring drawing. Three color LED's are used as follows: RED - Accessory Power ON YEL - Alarm Set GRN - Heartbeat (hard to see thru red lexan) Mounting includes two optional decorative covers. One vertical, one horizontal, both in classic "Federalist" style.
Traffic Light Display
8x8x4 LED Matrix
8x8x4 LED Matrix assembly drawing for panel mounting. Scrolling LED display is large and easily readable from across the room. Scrolling function allows long messages to be displayed while short static messages can also be shown. Intensity adjustable to 16 levels.
8x8x4 LED Matrix
Buzzer Output Development
Buzzer module.
Buzzer Output Development
IR Receiver Development
38kHz IR receiver module development
IR Receiver Development
LDR Module Assembly Drawing
LDR Mounting, wiring, dimensions, and picture.
LDR Module Assembly Drawing
Traffic Light Display
Traffic Light assembly & wiring drawing. Three color LED's are used as follows: RED - Accessory Power ON YEL - Alarm Set GRN - Heartbeat (hard to see thru red lexan) Mounting includes two optional decorative covers. One vertical, one horizontal, both in classic "Federalist" style.
Traffic Light Display
RGB LED Assembly Drawing
10mm, RGB LED mount, wiring, dimensions, and picture.
RGB LED Assembly Drawing
MP3 Player
MP3 Player with speaker. Uses microSD card with canned phrases/sounds/music for announcing the hours and alarm. Two 3D mounts are needed, one for the player and a second for the 2" speaker.
MP3 Player
1" Piezo Speaker Assembly Drawing
Development of 1" piezo speaker assembly. Shows wiring, dimensions, parts list, and picture of final assembly
1" Piezo Speaker Assembly Drawing
Coffee Pot Relay Circuit
Coffee Pot relay and NEMA 5-15 cord set (Plug & Outlet) Coffee pot relay comes on with alarm and, if ignored, will automagically go off one hour later. The power state can be manually overridden. The relay is peak rated at 10A @ 125VAC, however for safety, its de-rated to an 800W limit.
Coffee Pot Relay Circuit
Micro SD card
Micro SD card assembly and wiring drawing. The microSD card is used for data logging, The temp and humidity are logged every 15 minutes. Additionally the daily highs and lows and their times are logged at midnight. The data file turns over monthly and is named "LOGmm-yy.txt". This one card should hold all the data this system will ever collect.
Micro SD card
RTC Development Drawing
Shows RTC connections and mounting. Clock uses common CR2032 coin cell for time keeping over power down. Clock is sensitive to PS glitches. Turn off power before connecting.
RTC Development Drawing
Wooden Case for Clock
Wooden case for clock. 3/4" x 5" x 40". Two of each piece required. Material & Finish to customer specification. Insert Front Panel BEFORE gluing. Assemble with wood glue. Overall size 5" D x 8-3/4" W x 12-3/4" H
Wooden Case for Clock
Legend and Remote Control Functions
This is the Legend page that explains the symbology conventions used in the rest of the drawings here,. Also show is the remote and the current functions of each button. No scale. All other pages are in alphabetical order. See block diagram in STORY for devices.
Legend and Remote Control Functions
Potentiometer and Button Input
The potentiometer and the button work in conjunction to perform analog numerical input. The user is prompted to adjust the dial to the desired value and press the button to enter that value. This is a fast and intuitive entry method and can be scaled from just two choices to 100 with smooth response.
Potentiometer and Button Input
8x8x4 LED Matrix
8x8x4 LED Matrix assembly drawing for panel mounting. Scrolling LED display is large and easily readable from across the room. Scrolling function allows long messages to be displayed while short static messages can also be shown. Intensity adjustable to 16 levels.
8x8x4 LED Matrix
RTC Development Drawing
Shows RTC connections and mounting. Clock uses common CR2032 coin cell for time keeping over power down. Clock is sensitive to PS glitches. Turn off power before connecting.
RTC Development Drawing
MP3 Player
MP3 Player with speaker. Uses microSD card with canned phrases/sounds/music for announcing the hours and alarm. Two 3D mounts are needed, one for the player and a second for the 2" speaker.
MP3 Player
DHT-11 Sensor Development
DHT-11 Assembly drawing Used to capture temperature and humidity data. Plan is to upgrade to the higher precision DHT-22 in the future.
DHT-11 Sensor Development
IR Receiver Development
38kHz IR receiver module development
IR Receiver Development
Buzzer Output Development
Buzzer module.
Buzzer Output Development
Legend and Remote Control Functions
This is the Legend page that explains the symbology conventions used in the rest of the drawings here,. Also show is the remote and the current functions of each button. No scale. All other pages are in alphabetical order. See block diagram in STORY for devices.
Legend and Remote Control Functions
Micro SD card
Micro SD card assembly and wiring drawing. The microSD card is used for data logging, The temp and humidity are logged every 15 minutes. Additionally the daily highs and lows and their times are logged at midnight. The data file turns over monthly and is named "LOGmm-yy.txt". This one card should hold all the data this system will ever collect.
Micro SD card
RGB LED Assembly Drawing
10mm, RGB LED mount, wiring, dimensions, and picture.
RGB LED Assembly Drawing
1" Piezo Speaker Assembly Drawing
Development of 1" piezo speaker assembly. Shows wiring, dimensions, parts list, and picture of final assembly
1" Piezo Speaker Assembly Drawing
Coffee Pot Relay Circuit
Coffee Pot relay and NEMA 5-15 cord set (Plug & Outlet) Coffee pot relay comes on with alarm and, if ignored, will automagically go off one hour later. The power state can be manually overridden. The relay is peak rated at 10A @ 125VAC, however for safety, its de-rated to an 800W limit.
Coffee Pot Relay Circuit
LDR Module Assembly Drawing
LDR Mounting, wiring, dimensions, and picture.
LDR Module Assembly Drawing
Potentiometer and Button Input
The potentiometer and the button work in conjunction to perform analog numerical input. The user is prompted to adjust the dial to the desired value and press the button to enter that value. This is a fast and intuitive entry method and can be scaled from just two choices to 100 with smooth response.
Potentiometer and Button Input
Wooden Case for Clock
Wooden case for clock. 3/4" x 5" x 40". Two of each piece required. Material & Finish to customer specification. Insert Front Panel BEFORE gluing. Assemble with wood glue. Overall size 5" D x 8-3/4" W x 12-3/4" H
Wooden Case for Clock
Documentation
3D .STL print file - Mount for Velleman VMA317 IR Receiver and VMA319 Buzzer
This is a mounting bracket for the Velleman VMA317 IR remote receiver and for the Velleman VMA319 active buzzer modules. These are three pin modules. The mount has an opening on the front for the IR signal to enter or the sound to exit. The shroud should be printed in a dark PLA to minimize outside light intrusion during operation of the IR receiver. Two #6 thru mounting holes are provided. Module is 1-1/2" x 1" x 9/16". The edges and corners are filleted/rounded for strength. Print at 90% infill for strength.
3D .STL print file - Mount for Velleman VMA317 IR Receiver and VMA319 Buzzer
3D .STL print file - 10mm RGB Mount
Mounts a 10mm LED with two #6 thru holes. LED to be superglued in place.
3D .STL print file - 10mm RGB Mount
3D .STL print file - 1" Piezo Speaker Mount
Mount tiny 1" piezo speaker with this bracket. Speaker snaps into holder and mounts with two #6 thru screw holes. Wire exit provided. Speaker is available from Walmart: https://www.walmart.com/ip/Pack-of-3-MCKP2644SP1F-4748-PIEZO-400HZ-86DB-Transducer-Function-Speaker-Power-Rating-RMS-Impedance-8ohm/986005462 Print 90% infill PLA or PLA+ for strength.
3D .STL print file - 1" Piezo Speaker Mount
3D .STL print file - LDR Module Mount
Used to mount LDR module available from Walmart: https://www.walmart.com/ip/5Pcs-Photosensitive-Resistance-LDR-Light-Intensity-Detection-Sensor-Module/318626091 Mounting hole for module to be tapped 4-40, mount with 4-40 x 1/4 SS screws and #4 red fiber washers to prevent shorts. Mounts to rear of panel via two #6 thru mounting holes. Print at 90% infill for strength.
3D .STL print file - LDR Module Mount
3D .STL print file - microSD memory card slip-in mount
Mount for a microSD card interface. Card slips into mount. Mount attaches to panel with two #6 thru holes. Micro SD card can be removed while module is mounted. Print at 90% infill for strength. 1-15/16" x 2-1/8" x 3/8"
3D .STL print file - microSD memory card slip-in mount
3D .STL print file - Slip on knob for 5/16" shaft potentiometer
Slips on over end of standard 5/16" diameter mini poterntiometers commonly found in Arduino kits. Print 50% infill. Knob includes a fingernail indent for "no look" setting.
3D .STL print file - Slip on knob for 5/16" shaft potentiometer
3D .STL print file - Velleman VMA311 DHT-11 Humidity/Temp Module
Mounts the Velleman VMA311 DHT-11 module. Provides two #6 thru holes for mounting. 1-9/16" x 13/16" x 1/2". Print at 90% infill for strength,
3D .STL print file - Velleman VMA311 DHT-11 Humidity/Temp Module
3D .STL print file - Support bracket for two 1/8" Lexan panels, 4"
Stand off/support for two 1/8" (presumably Lexan, but aluminum would work too) panels. Spacer is 4" x 1/2" x 1/2" and has thru #6 mounting holes on each end as well as two in the long side. Ends are gusseted for strength. Designed to have screw thru matching hole in panel to be held by interior nut. 90% infill for strength.
3D .STL print file - Support bracket for two 1/8" Lexan panels, 4"
3D .STL print file - RTC mount
Allows mounting of MH-Real Time Clock module. Module attaches with two 4-40 screws and is aligned with two posts. The mount has two #6 thru holes for mounting. The completed piece is 1-7/8" x 1-3/4" and elevates the module 1/4". Print at 90% infill for strength.
3D .STL print file - RTC mount
3D .STL print file - 8x8x4 LED matrix display frame
Frames 8x8x4 LED matrix display for panel mounting
3D .STL print file - 8x8x4 LED matrix display frame
3D .STL print file - 2" Speaker mount
MP3 and other cards have small, 2" round speakers with no mounting ears. This item bridges the speaker, holding the magnet in place and snaps on. The bridge ends have two #6 thru mounting pylons.
3D .STL print file - 2" Speaker mount
3D .STL print file - Standoff, #6, 1/4"
Several of the cards have #6 or #4 mounting holes. This is a 1/4" spacer that can be used to support a variety of modules using either #4, #6, or M3 hardware. I know it's a trivial design, but I used almost two dozen on the project. Fast to print. Print at 90% infill for strength. 1/4" x 1/4".
3D .STL print file - Standoff, #6, 1/4"
3D .STL print file - Decorative cover for LED traffic light
It's CUTE. IT slips over the three LED's on the traffic light module (.045" on center). It has "eyebrows" for each LED and a Greek Revival frame. Print at 90% infill for strength. 1-9/16" x 13/16" x 5/16"
3D .STL print file - Decorative cover for LED traffic light
3D .STL print file - MP3 microSD player module slip in mount
Mounting for OPEN-SMART MP3 player module. Module slips into base and microSD card can be accessed while mounted. Print at 90% infill for strength.
3D .STL print file - MP3 microSD player module slip in mount
3D .STL print file - Velleman VMA311 DHT-11 Humidity/Temp Module
Mounts the Velleman VMA311 DHT-11 module. Provides two #6 thru holes for mounting. 1-9/16" x 13/16" x 1/2". Print at 90% infill for strength,
3D .STL print file - Velleman VMA311 DHT-11 Humidity/Temp Module
3D .STL print file - Decorative cover for LED traffic light
It's CUTE. IT slips over the three LED's on the traffic light module (.045" on center). It has "eyebrows" for each LED and a Greek Revival frame. Print at 90% infill for strength. 1-9/16" x 13/16" x 5/16"
3D .STL print file - Decorative cover for LED traffic light
3D .STL print file - Standoff, #6, 1/4"
Several of the cards have #6 or #4 mounting holes. This is a 1/4" spacer that can be used to support a variety of modules using either #4, #6, or M3 hardware. I know it's a trivial design, but I used almost two dozen on the project. Fast to print. Print at 90% infill for strength. 1/4" x 1/4".
3D .STL print file - Standoff, #6, 1/4"
3D .STL print file - 8x8x4 LED matrix display frame
Frames 8x8x4 LED matrix display for panel mounting
3D .STL print file - 8x8x4 LED matrix display frame
3D .STL print file - 2" Speaker mount
MP3 and other cards have small, 2" round speakers with no mounting ears. This item bridges the speaker, holding the magnet in place and snaps on. The bridge ends have two #6 thru mounting pylons.
3D .STL print file - 2" Speaker mount
3D .STL print file - MP3 microSD player module slip in mount
Mounting for OPEN-SMART MP3 player module. Module slips into base and microSD card can be accessed while mounted. Print at 90% infill for strength.
3D .STL print file - MP3 microSD player module slip in mount
3D .STL print file - LDR Module Mount
Used to mount LDR module available from Walmart: https://www.walmart.com/ip/5Pcs-Photosensitive-Resistance-LDR-Light-Intensity-Detection-Sensor-Module/318626091 Mounting hole for module to be tapped 4-40, mount with 4-40 x 1/4 SS screws and #4 red fiber washers to prevent shorts. Mounts to rear of panel via two #6 thru mounting holes. Print at 90% infill for strength.
3D .STL print file - LDR Module Mount
3D .STL print file - 1" Piezo Speaker Mount
Mount tiny 1" piezo speaker with this bracket. Speaker snaps into holder and mounts with two #6 thru screw holes. Wire exit provided. Speaker is available from Walmart: https://www.walmart.com/ip/Pack-of-3-MCKP2644SP1F-4748-PIEZO-400HZ-86DB-Transducer-Function-Speaker-Power-Rating-RMS-Impedance-8ohm/986005462 Print 90% infill PLA or PLA+ for strength.
3D .STL print file - 1" Piezo Speaker Mount
3D .STL print file - Slip on knob for 5/16" shaft potentiometer
Slips on over end of standard 5/16" diameter mini poterntiometers commonly found in Arduino kits. Print 50% infill. Knob includes a fingernail indent for "no look" setting.
3D .STL print file - Slip on knob for 5/16" shaft potentiometer
3D .STL print file - Support bracket for two 1/8" Lexan panels, 4"
Stand off/support for two 1/8" (presumably Lexan, but aluminum would work too) panels. Spacer is 4" x 1/2" x 1/2" and has thru #6 mounting holes on each end as well as two in the long side. Ends are gusseted for strength. Designed to have screw thru matching hole in panel to be held by interior nut. 90% infill for strength.
3D .STL print file - Support bracket for two 1/8" Lexan panels, 4"
3D .STL print file - RTC mount
Allows mounting of MH-Real Time Clock module. Module attaches with two 4-40 screws and is aligned with two posts. The mount has two #6 thru holes for mounting. The completed piece is 1-7/8" x 1-3/4" and elevates the module 1/4". Print at 90% infill for strength.
3D .STL print file - RTC mount
3D .STL print file - 10mm RGB Mount
Mounts a 10mm LED with two #6 thru holes. LED to be superglued in place.
3D .STL print file - 10mm RGB Mount
3D .STL print file - Mount for Velleman VMA317 IR Receiver and VMA319 Buzzer
This is a mounting bracket for the Velleman VMA317 IR remote receiver and for the Velleman VMA319 active buzzer modules. These are three pin modules. The mount has an opening on the front for the IR signal to enter or the sound to exit. The shroud should be printed in a dark PLA to minimize outside light intrusion during operation of the IR receiver. Two #6 thru mounting holes are provided. Module is 1-1/2" x 1" x 9/16". The edges and corners are filleted/rounded for strength. Print at 90% infill for strength.
3D .STL print file - Mount for Velleman VMA317 IR Receiver and VMA319 Buzzer
3D .STL print file - microSD memory card slip-in mount
Mount for a microSD card interface. Card slips into mount. Mount attaches to panel with two #6 thru holes. Micro SD card can be removed while module is mounted. Print at 90% infill for strength. 1-15/16" x 2-1/8" x 3/8"
3D .STL print file - microSD memory card slip-in mount
Comments
Only logged in users can leave comments
madmark2150
0 Followers
•0 Projects
Table of contents
Intro
0
0