daily pastebin goal
80%
SHARE
TWEET

Voltmeter 2019

ElegantAlchemist Jan 27th, 2019 (edited) 1,845 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Voltmeter Clock - 2019
  3.  * A clock using converted analogue 1000v meters and PWM to tell the time
  4.  * Inspired by u/MrMaverick82 (Michael Teeuw) reddit post: https://www.reddit.com/r/DIY/comments/8s1efr/due_to_my_dads_fascination_for_analog_volt_meters/
  5.  * Most of the code here is from above project, with some additions/subtractions
  6.  * Original code and project can be found: https://github.com/MichMich/AnalogVoltMeterClock
  7.  * This project code can be found: https://pastebin.com/gdq0zPUh
  8.  *
  9.  * ADDED: Automatic adjustment for Daylight Savings
  10.  * ADDED: Colour adjustable RGB LEDs for effects (simple here, could be as complex as desired,
  11.  * different colours for AM/PM etc etc)
  12.  *
  13.  * LICENSE: Permission is hereby granted, free of charge, to any person
  14.  * obtaining a copy of this software and associated documentation files
  15.  * (the "Software"). For more info see LICENSE at bottom of this file.
  16.  */
  17.  
  18. #include <DS3232RTC.h>   // https://github.com/PaulStoffregen/DS1307RTC
  19. #include <Timezone.h>    // https://github.com/JChristensen/Timezone
  20. #include <TimeLib.h>
  21. #include "RTClib.h"
  22. #include <Arduino.h>
  23. #include <Wire.h>
  24. #include <Adafruit_NeoPixel.h>
  25. #include <Streaming.h>
  26.  
  27. // Define the Pins we are using.
  28. #define PIN_METER_HOUR 3
  29. #define PIN_METER_MIN 5
  30. #define PIN_METER_SEC 6
  31.  
  32. // Define the minimum and maximum PWM values for all the meters.
  33. // These values can be used to calibrate the meters.
  34. #define MINIMUM_PWM_VALUE_HOUR 18
  35. #define MAXIMUM_PWM_VALUE_HOUR 240
  36. #define MINIMUM_PWM_VALUE_MIN 1
  37. #define MAXIMUM_PWM_VALUE_MIN 221
  38. #define MINIMUM_PWM_VALUE_SEC 5
  39. #define MAXIMUM_PWM_VALUE_SEC 235
  40.  
  41. //Define the neopixel settings
  42. #define PIN 2
  43. #define NUMPIXELS 3
  44.  
  45. Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
  46.  
  47. TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60};        //British Summer Time
  48. TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0};         //Standard Time
  49. Timezone UK(BST, GMT);
  50.  
  51. // If TimeChangeRules are already stored in EEPROM, comment out the three
  52. // lines above and uncomment the line below.
  53. //Timezone myTZ(100);       //assumes rules stored at EEPROM address 100
  54.  
  55. TimeChangeRule *tcr;        //pointer to the time change rule, use to get TZ abbrev
  56. time_t utc, local;
  57.  
  58. void setup()
  59. {
  60.     Serial.begin(115200);
  61.     setSyncProvider(RTC.get);   // the function to get the time from the RTC
  62.     if(timeStatus()!= timeSet)
  63.         Serial.println("Unable to sync with the RTC");
  64.     else
  65.         Serial.println("RTC has set the system time");
  66.  
  67.   // Configure all the pin modes for all connected pins.
  68.   pinMode(PIN_METER_HOUR, OUTPUT);
  69.   pinMode(PIN_METER_MIN, OUTPUT);
  70.   pinMode(PIN_METER_SEC, OUTPUT);
  71.  
  72.   //start the neopixel library
  73.   pixels.begin();
  74.  
  75.   // Initiate the power-on self test by running the start sequence.
  76.   startSequence();
  77. }
  78.  
  79. void loop(void)
  80. {
  81.     Serial.println();
  82.     utc = now();
  83.     printTime(utc, "UTC");
  84.     local = UK.toLocal(utc, &tcr);
  85.     printTime(local, tcr -> abbrev);
  86.     delay(1000);
  87.     static time_t tLast;
  88.     time_t t;
  89.     tmElements_t tm;
  90.  
  91.     //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s
  92.     if (Serial.available() >= 12) {
  93.         //note that the tmElements_t Year member is an offset from 1970,
  94.         //but the RTC wants the last two digits of the calendar year.
  95.         //use the convenience macros from Time.h to do the conversions.
  96.         int y = Serial.parseInt();
  97.         if (y >= 100 && y < 1000)
  98.             Serial << F("Error: Year must be two digits or four digits!") << endl;
  99.         else {
  100.             if (y >= 1000)
  101.                 tm.Year = CalendarYrToTm(y);
  102.             else    //(y < 100)
  103.                 tm.Year = y2kYearToTm(y);
  104.             tm.Month = Serial.parseInt();
  105.             tm.Day = Serial.parseInt();
  106.             tm.Hour = Serial.parseInt();
  107.             tm.Minute = Serial.parseInt();
  108.             tm.Second = Serial.parseInt();
  109.             t = makeTime(tm);
  110.             RTC.set(t);        //use the time_t value to ensure correct weekday is set
  111.             setTime(t);        
  112.             Serial << F("RTC set to: ");
  113.             printTime(t, local);
  114.             Serial << endl;
  115.             //dump any extraneous input
  116.             while (Serial.available() > 0) Serial.read();
  117.         }
  118.     }
  119.    
  120.     t = now();
  121.     if (t != tLast) {
  122.         tLast = t;
  123.         if (second(t) == 0) {
  124.             float c = RTC.temperature() / 4.;
  125.             float f = c * 9. / 5. + 32.;
  126.             Serial << F("  ") << c << F(" C  ") << f << F(" F");
  127.         }
  128.  
  129.    // Update the meters by calling the `displayTime()` method.
  130.     displayTime();
  131.          
  132.         Serial << endl;
  133.        
  134.     }
  135. }
  136.  
  137. // format and print a time_t value, with a time zone appended.
  138. void printDateTime(time_t t, const char *tz)
  139. {
  140.     char buf[32];
  141.     char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
  142.     strcpy(m, monthShortStr(month(t)));
  143.     sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s",
  144.         hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz);
  145.     Serial.println(buf);
  146. }
  147.  
  148. /**
  149.  * Slowly animate one meter to the maximum value and back.
  150.  * This animation is used in the start sequence. Not only does it look
  151.  * cool. It's also a way to test the meters.
  152.  *
  153.  * @param uint8_t pin  The pin of the meter.
  154.  * @param uint8_t min  The meter's minimum PWM value.
  155.  * @param uint8_t max  The meter's maximum PWM value.
  156.  */
  157. void animateMeter(uint8_t pin, uint8_t min, uint8_t max) {
  158.   uint8_t v;
  159.   for (v = min; v <= max; v++) {
  160.     analogWrite(pin, v);
  161.     delay(2);
  162.   }
  163.   delay(100);
  164.   for (v = max; v >= min; v--) {
  165.     analogWrite(pin, v);
  166.     delay(2);
  167.   }
  168.   delay(100);
  169. }
  170.  
  171. /**
  172.  * Run the startup sequence by animating all three meters sequentially.
  173.  */
  174. void startSequence() {
  175.   pixels.setPixelColor(0, pixels.Color(255,51,20));
  176.   pixels.setPixelColor(1, pixels.Color(255,51,20));
  177.   pixels.setPixelColor(2, pixels.Color(255,51,20));
  178.   pixels.show();
  179.   delay(500);
  180.   pixels.setPixelColor(0, pixels.Color(0,0,0));
  181.   pixels.setPixelColor(1, pixels.Color(0,0,0));
  182.   pixels.setPixelColor(2, pixels.Color(0,0,0));
  183.   pixels.show();
  184.   delay(500);
  185.   pixels.setPixelColor(0, pixels.Color(255,51,20));
  186.   pixels.setPixelColor(1, pixels.Color(255,51,20));
  187.   pixels.setPixelColor(2, pixels.Color(255,51,20));
  188.   pixels.show();
  189.   delay(500);
  190.   pixels.setPixelColor(0, pixels.Color(0,0,0));
  191.   pixels.setPixelColor(1, pixels.Color(0,0,0));
  192.   pixels.setPixelColor(2, pixels.Color(0,0,0));
  193.   pixels.show();
  194.   delay(500);
  195.   pixels.setPixelColor(0, pixels.Color(255,51,20));
  196.   pixels.setPixelColor(1, pixels.Color(255,51,20));
  197.   pixels.setPixelColor(2, pixels.Color(255,51,20));
  198.   pixels.show();
  199.   delay(250);
  200.   animateMeter(PIN_METER_HOUR, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR);
  201.   animateMeter(PIN_METER_MIN, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN);
  202.   animateMeter(PIN_METER_SEC, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC);
  203. }
  204.  
  205. /**
  206.  * The method to update the time displayed on the the meter.
  207.  */
  208. void displayTime() {
  209.   // Since the real time clock returns a 24 hour format,
  210.   // we need to convert the hour value to 12 hour format and store in temporary variable 'h'.
  211.   // For minutes and seconds we can just directly use the
  212.   // properties on the 'time(local)' object. No need to store those
  213.   // in a temporary variable.
  214.   int8_t h = (hour(local) == 0 || hour(local) == 12) ? 12 : hour(local) % 12;
  215.  
  216.   // Convert the time values to PWM values by using map ...
  217.   // and set that value as the PWM value using analogWrite.
  218.   analogWrite(PIN_METER_HOUR, map(h, 1, 12, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR));
  219.   analogWrite(PIN_METER_MIN, map(minute(local), 0, 60, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN));
  220.   analogWrite(PIN_METER_SEC, map(second(local), 0, 60, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC));
  221. }
  222.  
  223. //Function to print time with time zone
  224. void printTime(time_t t, char *tz)
  225. {
  226.     sPrintI00(hour(t));
  227.     sPrintDigits(minute(t));
  228.     sPrintDigits(second(t));
  229.     Serial.print(' ');
  230.     Serial.print(dayShortStr(weekday(t)));
  231.     Serial.print(' ');
  232.     sPrintI00(day(t));
  233.     Serial.print(' ');
  234.     Serial.print(monthShortStr(month(t)));
  235.     Serial.print(' ');
  236.     Serial.print(year(t));
  237.     Serial.print(' ');
  238.     Serial.print(tz);
  239.     Serial.println();
  240. }
  241.  
  242. //Print an integer in "00" format (with leading zero).
  243. //Input value assumed to be between 0 and 99.
  244. void sPrintI00(int val)
  245. {
  246.     if (val < 10) Serial.print('0');
  247.     Serial.print(val, DEC);
  248.     return;
  249. }
  250.  
  251. //Print an integer in ":00" format (with leading zero).
  252. //Input value assumed to be between 0 and 99.
  253. void sPrintDigits(int val)
  254. {
  255.     Serial.print(':');
  256.     if(val < 10) Serial.print('0');
  257.     Serial.print(val, DEC);
  258. }
  259.  
  260. /**
  261.  * ORIGINAL CODE Copyright (c) 2018 Michael Teeuw
  262.  * MODIFIED CODE Copyright (c) 2019 Andrew O'Donnell
  263.  *
  264.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  265.  * of this software and associated documentation files (the "Software"), to deal
  266.  * in the Software without restriction, including without limitation the rights
  267.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  268.  * copies of the Software, and to permit persons to whom the Software is
  269.  * furnished to do so, subject to the following conditions:
  270.  *
  271.  * The above copyright notice and this permission notice shall be included in all
  272.  * copies or substantial portions of the Software.
  273.  *
  274.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  275.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  276.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  277.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  278.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  279.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  280.  * SOFTWARE.
  281.  */
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top