├── Colors.h ├── Configuration.h ├── Events.h ├── LICENSE ├── Languages.h ├── LedDriver.cpp ├── LedDriver.h ├── Letters.h ├── MeteoWeather.cpp ├── MeteoWeather.h ├── Modes.h ├── Ntp.cpp ├── Ntp.h ├── Numbers.h ├── Qlockwork.ino ├── Readme.txt ├── Renderer.cpp ├── Renderer.h ├── Settings.cpp ├── Settings.h ├── Syslog.cpp ├── Syslog.h ├── Timezone.cpp ├── Timezone.h ├── Timezones.h ├── WiFiManager.cpp ├── WiFiManager.h ├── Words.h └── misc ├── BOM.txt ├── Clock_45x45.dxf └── Schematic.pdf /Colors.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Colors.h 3 | ******************************************************************************/ 4 | 5 | #ifndef COLORS_H 6 | #define COLORS_H 7 | 8 | enum eColorChange : uint8_t 9 | { 10 | COLORCHANGE_NO, // 0 11 | COLORCHANGE_FIVE, // 1 12 | COLORCHANGE_HOUR, // 2 13 | COLORCHANGE_DAY, // 3 14 | COLORCHANGE_COUNT = COLORCHANGE_DAY 15 | }; 16 | 17 | enum eColor : uint8_t 18 | { 19 | WHITE, 20 | RED, 21 | RED_25, 22 | RED_50, 23 | ORANGE, 24 | YELLOW, 25 | YELLOW_25, 26 | YELLOW_50, 27 | GREENYELLOW, 28 | GREEN, 29 | GREEN_25, 30 | GREEN_50, 31 | MINTGREEN, 32 | CYAN, 33 | CYAN_25, 34 | CYAN_50, 35 | LIGHTBLUE, 36 | BLUE, 37 | BLUE_25, 38 | BLUE_50, 39 | VIOLET, 40 | MAGENTA, 41 | MAGENTA_25, 42 | MAGENTA_50, 43 | PINK, 44 | COLOR_COUNT = PINK 45 | }; 46 | 47 | struct color_s 48 | { 49 | uint8_t red; 50 | uint8_t green; 51 | uint8_t blue; 52 | }; 53 | 54 | const color_s defaultColors[] = 55 | { 56 | { 0xFF, 0xFF, 0xFF }, // 00 WHITE 57 | 58 | { 0xFF, 0x00, 0x00 }, // 01 RED 59 | { 0xFF, 0x40, 0x40 }, // 02 RED_25 60 | { 0xFF, 0x80, 0x80 }, // 03 RED_50 61 | 62 | { 0xFF, 0x7F, 0x00 }, // 04 ORANGE 63 | 64 | { 0xFF, 0xFF, 0x00 }, // 05 YELLOW 65 | { 0xFF, 0xFF, 0x40 }, // 06 YELLOW_25 66 | { 0xFF, 0xFF, 0x80 }, // 07 YELLOW_50 67 | 68 | { 0x7F, 0xFF, 0x00 }, // 08 GREENYELLOW 69 | 70 | { 0x00, 0xFF, 0x00 }, // 09 GREEN 71 | { 0x40, 0xFF, 0x40 }, // 10 GREEN_25 72 | { 0x80, 0xFF, 0x80 }, // 11 GREEN_50 73 | 74 | { 0x00, 0xFF, 0x7F }, // 12 MINTGREEN 75 | 76 | { 0x00, 0xFF, 0xFF }, // 13 CYAN 77 | { 0x40, 0xFF, 0xFF }, // 14 CYAN_25 78 | { 0x80, 0xFF, 0xFF }, // 15 CYAN_50 79 | 80 | { 0x00, 0x7F, 0xFF }, // 16 LIGHTBLUE 81 | 82 | { 0x00, 0x00, 0xFF }, // 17 BLUE 83 | { 0x40, 0x40, 0xFF }, // 18 BLUE_25 84 | { 0x80, 0x80, 0xFF }, // 19 BLUE_50 85 | 86 | { 0x7F, 0x00, 0xFF }, // 20 VIOLET 87 | 88 | { 0xFF, 0x00, 0xFF }, // 21 MAGENTA 89 | { 0xFF, 0x40, 0xFF }, // 22 MAGENTA_25 90 | { 0xFF, 0x80, 0xFF }, // 23 MAGENTA_50 91 | 92 | { 0xFF, 0x00, 0x7F } // 24 PINK 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /Configuration.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // Configuration.h 3 | // See README.txt for help 4 | //***************************************************************************** 5 | 6 | #ifndef CONFIGURATION_H 7 | #define CONFIGURATION_H 8 | 9 | //***************************************************************************** 10 | // Software settings 11 | //***************************************************************************** 12 | 13 | #define HOSTNAME "QLOCKWORK" 14 | #define WEBSITE_TITLE "QLOCKWORKs page" 15 | //#define DEDICATION "The only reason for time is so that everything doesn't happen at once.
(Albert Einstein)" 16 | #define WIFI_SETUP_TIMEOUT 120 17 | #define WIFI_AP_PASS "12345678" 18 | #define OTA_PASS "1234" 19 | #define NTP_SERVER "pool.ntp.org" 20 | #define SHOW_IP 21 | //#define WIFI_BEEPS 22 | 23 | //#define NONE_TECHNICAL_ZERO 24 | #define AUTO_MODECHANGE_TIME 60 // seconds 25 | #define EVENT_TIME 300 // seconds 26 | #define ALARM_LED_COLOR RED 27 | //#define ABUSE_CORNER_LED_FOR_ALARM 28 | 29 | //#define POWERON_SELFTEST 30 | #define SHOW_MODE_AMPM 31 | #define SHOW_MODE_SECONDS 32 | #define SHOW_MODE_WEEKDAY 33 | #define SHOW_MODE_DATE 34 | #define SHOW_MODE_MOONPHASE 35 | //#define SHOW_MODE_SUNRISE_SUNSET // works only if APIKEY is defined 36 | #define SHOW_MODE_TEST 37 | 38 | #define WEATHER // Show weather data 39 | 40 | // Enter the location for which you want the current weather data displayed as latitude and longitude and the time zone. 41 | #define LATITUDE "56.2345678" 42 | #define LONGITUDE "12.123456789" 43 | 44 | #define TIMEZONE "Europe/Berlin" 45 | 46 | //#define FRONTCOVER_EN 47 | #define FRONTCOVER_DE_DE 48 | //#define FRONTCOVER_DE_SW 49 | //#define FRONTCOVER_DE_BA 50 | //#define FRONTCOVER_DE_SA 51 | //#define FRONTCOVER_DE_MKF_DE 52 | //#define FRONTCOVER_DE_MKF_SW 53 | //#define FRONTCOVER_DE_MKF_BA 54 | //#define FRONTCOVER_DE_MKF_SA 55 | //#define FRONTCOVER_D3 56 | //#define FRONTCOVER_CH 57 | //#define FRONTCOVER_CH_GS 58 | //#define FRONTCOVER_ES 59 | //#define FRONTCOVER_FR 60 | //#define FRONTCOVER_IT 61 | //#define FRONTCOVER_NL 62 | //#define FRONTCOVER_BINARY 63 | 64 | //***************************************************************************** 65 | // Timezone 66 | //***************************************************************************** 67 | 68 | //#define TIMEZONE_IDLW // IDLW International Date Line West UTC-12 69 | //#define TIMEZONE_SST // SST Samoa Standard Time UTC-11 70 | //#define TIMEZONE_HST // HST Hawaiian Standard Time UTC-10 71 | //#define TIMEZONE_AKST // AKST Alaska Standard Time UTC-9 72 | //#define TIMEZONE_USPST // USPST Pacific Standard Time (USA) UTC-8 73 | //#define TIMEZONE_USMST // USMST Mountain Standard Time (USA) UTC-7 74 | //#define TIMEZONE_USAZ // USAZ Mountain Standard Time (USA) UTC-7 (no DST) 75 | //#define TIMEZONE_USCST // USCST Central Standard Time (USA) UTC-6 76 | //#define TIMEZONE_USEST // USEST Eastern Standard Time (USA) UTC-5 77 | //#define TIMEZONE_AST // AST Atlantic Standard Time UTC-4 78 | //#define TIMEZONE_BST // BST Eastern Brazil Standard Time UTC-3 79 | //#define TIMEZONE_VTZ // VTZ Greenland Eastern Standard Time UTC-2 80 | //#define TIMEZONE_AZOT // AZOT Azores Time UTC-1 81 | //#define TIMEZONE_GMT // GMT Greenwich Mean Time UTC 82 | #define TIMEZONE_CET // CET Central Europe Time UTC+1 83 | //#define TIMEZONE_EST // EST Eastern Europe Time UTC+2 84 | //#define TIMEZONE_MSK // MSK Moscow Time UTC+3 (no DST) 85 | //#define TIMEZONE_GST // GST Gulf Standard Time UTC+4 86 | //#define TIMEZONE_PKT // PKT Pakistan Time UTC+5 87 | //#define TIMEZONE_BDT // BDT Bangladesh Time UTC+6 88 | //#define TIMEZONE_JT // JT Java Time UTC+7 89 | //#define TIMEZONE_CNST // CNST China Standard Time UTC+8 90 | //#define TIMEZONE_HKT // HKT Hong Kong Time UTC+8 91 | //#define TIMEZONE_PYT // PYT Pyongyang Time (North Korea) UTC+8.5 92 | //#define TIMEZONE_CWT // CWT Central West Time (Australia) UTC+8.75 93 | //#define TIMEZONE_JST // JST Japan Standard Time UTC+9 94 | //#define TIMEZONE_ACST // ACST Australian Central Standard Time UTC+9.5 95 | //#define TIMEZONE_AEST // AEST Australian Eastern Standard Time UTC+10 96 | //#define TIMEZONE_LHST // LHST Lord Howe Standard Time UTC+10.5 97 | //#define TIMEZONE_SBT // SBT Solomon Islands Time UTC+11 98 | //#define TIMEZONE_NZST // NZST New Zealand Standard Time UTC+12 99 | 100 | //***************************************************************************** 101 | // Hardware settings 102 | //***************************************************************************** 103 | 104 | #define SERIAL_SPEED 115200 105 | 106 | #define NUMPIXELS 115 107 | 108 | //#define ONOFF_BUTTON 109 | //#define MODE_BUTTON 110 | //#define TIME_BUTTON 111 | 112 | #define ESP_LED 113 | 114 | #define MIN_BRIGHTNESS 20 115 | #define MAX_BRIGHTNESS 255 116 | #define TEST_BRIGHTNESS 80 117 | 118 | //#define SENSOR_DHT22 119 | #define DHT_TEMPERATURE_OFFSET 0.5 120 | #define DHT_HUMIDITY_OFFSET -2.0 121 | 122 | //#define RTC_BACKUP 123 | #define RTC_TEMPERATURE_OFFSET -1.15 124 | 125 | //#define LDR 126 | //#define LDR_IS_INVERSE 127 | 128 | //#define BUZZER 129 | #define BUZZTIME_ALARM_1 30 130 | #define BUZZTIME_ALARM_2 30 131 | #define BUZZTIME_TIMER 30 132 | 133 | //#define IR_RECEIVER 134 | //#define IR_CODE_ONOFF 16769565 // HX1838 Remote CH+ 135 | //#define IR_CODE_TIME 16753245 // HX1838 Remote CH- 136 | //#define IR_CODE_MODE 16736925 // HX1838 Remote CH 137 | #define IR_CODE_ONOFF 0xFFE01F // CLT2 V1.1 Remote Power 138 | #define IR_CODE_TIME 0xFFA05F // CLT2 V1.1 Remote Time 139 | #define IR_CODE_MODE 0xFF20DF // CLT2 V1.1 Remote Region 140 | 141 | //#define IR_LETTER_OFF 142 | #define IR_LETTER_X 8 143 | #define IR_LETTER_Y 10 144 | 145 | #define LED_LAYOUT_HORIZONTAL_1 146 | //#define LED_LAYOUT_VERTICAL_1 147 | //#define LED_LAYOUT_VERTICAL_2 148 | //#define LED_LAYOUT_VERTICAL_3 149 | 150 | #define NEOPIXEL_RGB 151 | //#define NEOPIXEL_RGBW 152 | 153 | #define NEOPIXEL_TYPE NEO_GRB + NEO_KHZ800 // see Adafruit_NeoPixel.h for help 154 | //#define NEOPIXEL_TYPE NEO_WRGB + NEO_KHZ800 155 | //#define NEOPIXEL_TYPE NEO_GRBW + NEO_KHZ800 156 | 157 | //***************************************************************************** 158 | // Misc 159 | //***************************************************************************** 160 | 161 | //#define DEBUG 162 | //#define DEBUG_WEB 163 | //#define DEBUG_IR 164 | //#define DEBUG_MATRIX 165 | //#define DEBUG_FPS 166 | 167 | //#define SYSLOGSERVER_SERVER "192.168.0.1" 168 | //#define SYSLOGSERVER_PORT 514 169 | 170 | #define UPDATE_INFOSERVER "thorsten-wahl.ch" 171 | #define UPDATE_INFOFILE "/qlockwork/updateinfo.json" 172 | 173 | // ESP8266 174 | #define PIN_IR_RECEIVER 16 // D0 (no interrupt) 175 | //#define PIN_WIRE_SCL 05 // D1 SCL 176 | //#define PIN_WIRE_SDA 04 // D2 SDA 177 | #define PIN_MODE_BUTTON 00 // D3 LOW_Flash 178 | #define PIN_LED 02 // D4 ESP8266_LED 179 | #define PIN_BUZZER 14 // D5 180 | #define PIN_DHT22 12 // D6 181 | #define PIN_LEDS_CLOCK 13 // D7 182 | #define PIN_LEDS_DATA 15 // D8 183 | #define PIN_LDR A0 // ADC 184 | #define PIN_TIME_BUTTON 01 // TXD0 185 | #define PIN_ONOFF_BUTTON 03 // RXD0 186 | // GPIO 06 to GPIO 11 are 187 | // used for flash memory databus 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /Events.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Events.h 3 | ******************************************************************************/ 4 | 5 | #ifndef EVENTS_H 6 | #define EVENTS_H 7 | 8 | struct event_t { 9 | uint8_t month; 10 | uint8_t day; 11 | String text; 12 | uint16_t year; 13 | eColor color; 14 | }; 15 | 16 | event_t events[] = { 17 | { 0, 0, "", 0, WHITE }, // Do not change 18 | { 1, 1, "Happy New Year!", 0, YELLOW_25 }, 19 | { 3, 14, "Albert Einsteins birthday!", 1879, MAGENTA }, 20 | { 12, 24, "It's Christmas!", 0, RED }, 21 | { 3, 12, "Qlockworks birthday!", 2017, MAGENTA } 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Languages.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // Languages.h 3 | //***************************************************************************** 4 | 5 | #ifndef LANGUAGES_H 6 | #define LANGUAGES_H 7 | 8 | #if defined(FRONTCOVER_EN) || defined(FRONTCOVER_BINARY) 9 | const char sWeekday[][2] = { 10 | { ' ', ' ' }, // 00 11 | { 'S', 'U' }, // 01 12 | { 'M', 'O' }, // 02 13 | { 'T', 'U' }, // 03 14 | { 'W', 'E' }, // 04 15 | { 'T', 'H' }, // 05 16 | { 'F', 'R' }, // 06 17 | { 'S', 'A' } // 07 18 | }; 19 | #define LANGSTR "en" 20 | #define TXT_SETTINGS "Settings" 21 | #define TXT_ALARM "Alarm" 22 | #define TXT_ON "on" 23 | #define TXT_OFF "off" 24 | #define TXT_HOURBEEP "Hourly beep" 25 | #define TXT_TIMER "Timer" 26 | #define TXT_MINUTES "minutes" 27 | #endif 28 | 29 | #if defined(FRONTCOVER_DE_DE) || defined(FRONTCOVER_DE_SW) || defined(FRONTCOVER_DE_BA) || defined(FRONTCOVER_DE_SA) || defined(FRONTCOVER_D3) || defined(FRONTCOVER_DE_MKF_DE) || defined(FRONTCOVER_DE_MKF_SW) || defined(FRONTCOVER_DE_MKF_BA) || defined(FRONTCOVER_DE_MKF_SA) || defined(FRONTCOVER_CH) || defined(FRONTCOVER_CH_GS) 30 | const char sWeekday[][2] = { 31 | { ' ', ' ' }, // 00 32 | { 'S', 'O' }, // 01 33 | { 'M', 'O' }, // 02 34 | { 'D', 'I' }, // 03 35 | { 'M', 'I' }, // 04 36 | { 'D', 'O' }, // 05 37 | { 'F', 'R' }, // 06 38 | { 'S', 'A' } // 07 39 | }; 40 | #define LANGSTR "de" 41 | #define TXT_SETTINGS "Einstellungen" 42 | #define TXT_ALARM "Wecker" 43 | #define TXT_ON "ein" 44 | #define TXT_OFF "aus" 45 | #define TXT_HOURBEEP "Stundenalarm" 46 | #define TXT_TIMER "Timer" 47 | #define TXT_MINUTES "Minuten" 48 | #endif 49 | 50 | #if defined(FRONTCOVER_FR) 51 | const char sWeekday[][2] = { 52 | { ' ', ' ' }, // 00 53 | { 'D', 'I' }, // 01 54 | { 'L', 'U' }, // 02 55 | { 'M', 'A' }, // 03 56 | { 'M', 'E' }, // 04 57 | { 'J', 'E' }, // 05 58 | { 'V', 'E' }, // 06 59 | { 'S', 'A' } // 07 60 | }; 61 | #define LANGSTR "fr" 62 | #define TXT_SETTINGS "Param�tres" 63 | #define TXT_ALARM "R�veil" 64 | #define TXT_ON "on" 65 | #define TXT_OFF "off" 66 | #define TXT_HOURBEEP "Alarme heure" 67 | #define TXT_TIMER "Minuteur" 68 | #define TXT_MINUTES "Minutes" 69 | #endif 70 | 71 | #if defined(FRONTCOVER_IT) 72 | const char sWeekday[][2] = { 73 | { ' ', ' ' }, // 00 74 | { 'D', 'O' }, // 01 75 | { 'L', 'U' }, // 02 76 | { 'M', 'A' }, // 03 77 | { 'M', 'E' }, // 04 78 | { 'G', 'I' }, // 05 79 | { 'V', 'E' }, // 06 80 | { 'S', 'A' } // 07 81 | }; 82 | #define LANGSTR "it" 83 | #define TXT_SETTINGS "Settings" 84 | #define TXT_ALARM "Alarm" 85 | #define TXT_ON "on" 86 | #define TXT_OFF "off" 87 | #define TXT_HOURBEEP "Hourly beep" 88 | #define TXT_TIMER "Timer" 89 | #define TXT_MINUTES "minutes" 90 | #endif 91 | 92 | #if defined(FRONTCOVER_ES) 93 | const char sWeekday[][2] = { 94 | { ' ', ' ' }, // 00 95 | { 'D', 'O' }, // 01 96 | { 'L', 'U' }, // 02 97 | { 'M', 'A' }, // 03 98 | { 'M', 'I' }, // 04 99 | { 'J', 'U' }, // 05 100 | { 'V', 'I' }, // 06 101 | { 'S', 'A' } // 07 102 | }; 103 | #define LANGSTR "es" 104 | #define TXT_SETTINGS "Settings" 105 | #define TXT_ALARM "Alarm" 106 | #define TXT_ON "on" 107 | #define TXT_OFF "off" 108 | #define TXT_HOURBEEP "Hourly beep" 109 | #define TXT_TIMER "Timer" 110 | #define TXT_MINUTES "minutes" 111 | #endif 112 | 113 | #if defined(FRONTCOVER_NL) 114 | const char sWeekday[][2] = { 115 | { ' ', ' ' }, // 00 116 | { 'Z', 'O' }, // 01 117 | { 'M', 'A' }, // 02 118 | { 'D', 'I' }, // 03 119 | { 'W', 'O' }, // 04 120 | { 'D', 'O' }, // 05 121 | { 'V', 'R' }, // 06 122 | { 'Z', 'A' } // 07 123 | }; 124 | #define LANGSTR "nl" 125 | #define TXT_SETTINGS "Settings" 126 | #define TXT_ALARM "Alarm" 127 | #define TXT_ON "on" 128 | #define TXT_OFF "off" 129 | #define TXT_HOURBEEP "Hourly beep" 130 | #define TXT_TIMER "Timer" 131 | #define TXT_MINUTES "minutes" 132 | #endif 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /LedDriver.cpp: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // LedDriver.cpp 3 | //***************************************************************************** 4 | 5 | #include "LedDriver.h" 6 | 7 | LedDriver::LedDriver() { 8 | strip = new Adafruit_NeoPixel(NUMPIXELS, PIN_LEDS_DATA, NEOPIXEL_TYPE); 9 | strip->begin(); 10 | } 11 | 12 | LedDriver::~LedDriver() { 13 | } 14 | 15 | void LedDriver::clear() { 16 | strip->clear(); 17 | } 18 | 19 | void LedDriver::show() { 20 | strip->show(); 21 | } 22 | 23 | void LedDriver::setPixel(uint8_t x, uint8_t y, uint8_t color, uint8_t brightness) { 24 | setPixel(x + y * 11, color, brightness); 25 | } 26 | 27 | void LedDriver::setPixel(uint8_t num, uint8_t color, uint8_t brightness) { 28 | #ifdef LED_LAYOUT_HORIZONTAL_1 29 | uint8_t ledMap[] = { 30 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 31 | 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 32 | 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 | 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 34 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 35 | 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 36 | 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 37 | 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 38 | 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 39 | 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 40 | 111, 112, 113, 110, 114 41 | }; 42 | #endif 43 | 44 | #ifdef LED_LAYOUT_VERTICAL_1 45 | uint8_t ledMap[] = { 46 | 1, 21, 22, 41, 42, 61, 62, 81, 82, 101, 103, 47 | 2, 20, 23, 40, 43, 60, 63, 80, 83, 100, 104, 48 | 3, 19, 24, 39, 44, 59, 64, 79, 84, 99, 105, 49 | 4, 18, 25, 38, 45, 58, 65, 78, 85, 98, 106, 50 | 5, 17, 26, 37, 46, 57, 66, 77, 86, 97, 107, 51 | 6, 16, 27, 36, 47, 56, 67, 76, 87, 96, 108, 52 | 7, 15, 28, 35, 48, 55, 68, 75, 88, 95, 109, 53 | 8, 14, 29, 34, 49, 54, 69, 74, 89, 94, 110, 54 | 9, 13, 30, 33, 50, 53, 70, 73, 90, 93, 111, 55 | 10, 12, 31, 32, 51, 52, 71, 72, 91, 92, 112, 56 | 0, 102, 113, 11, 114 57 | }; 58 | #endif 59 | 60 | #ifdef LED_LAYOUT_VERTICAL_2 61 | uint8_t ledMap[] = { 62 | 9, 10, 29, 30, 49, 50, 69, 70, 89, 90, 109, 63 | 8, 11, 28, 31, 48, 51, 68, 71, 88, 91, 108, 64 | 7, 12, 27, 32, 47, 52, 67, 72, 87, 92, 107, 65 | 6, 13, 26, 33, 46, 53, 66, 73, 86, 93, 106, 66 | 5, 14, 25, 34, 45, 54, 65, 74, 85, 94, 105, 67 | 4, 15, 24, 35, 44, 55, 64, 75, 84, 95, 104, 68 | 3, 16, 23, 36, 43, 56, 63, 76, 83, 96, 103, 69 | 2, 17, 22, 37, 42, 57, 62, 77, 82, 97, 102, 70 | 1, 18, 21, 38, 41, 58, 61, 78, 81, 98, 101, 71 | 0, 19, 20, 39, 40, 59, 60, 79, 80, 99, 100, 72 | 112, 110, 114, 113, 111 73 | }; 74 | #endif 75 | 76 | #ifdef LED_LAYOUT_VERTICAL_3 77 | uint8_t ledMap[] = { 78 | 9, 10, 29, 30, 49, 50, 69, 70, 89, 90, 109, 79 | 8, 11, 28, 31, 48, 51, 68, 71, 88, 91, 108, 80 | 7, 12, 27, 32, 47, 52, 67, 72, 87, 92, 107, 81 | 6, 13, 26, 33, 46, 53, 66, 73, 86, 93, 106, 82 | 5, 14, 25, 34, 45, 54, 65, 74, 85, 94, 105, 83 | 4, 15, 24, 35, 44, 55, 64, 75, 84, 95, 104, 84 | 3, 16, 23, 36, 43, 56, 63, 76, 83, 96, 103, 85 | 2, 17, 22, 37, 42, 57, 62, 77, 82, 97, 102, 86 | 1, 18, 21, 38, 41, 58, 61, 78, 81, 98, 101, 87 | 0, 19, 20, 39, 40, 59, 60, 79, 80, 99, 100, 88 | 111, 110, 113, 112, 114 89 | }; 90 | #endif 91 | 92 | uint8_t red = brightness * 0.0039 * defaultColors[color].red; 93 | uint8_t green = brightness * 0.0039 * defaultColors[color].green; 94 | uint8_t blue = brightness * 0.0039 * defaultColors[color].blue; 95 | 96 | 97 | #ifdef NEOPIXEL_RGBW 98 | uint8_t white = 0xFF; 99 | if (red < white) white = red; 100 | if (green < white) white = green; 101 | if (blue < white) white = blue; 102 | strip->setPixelColor(ledMap[num], red - white, green - white, blue - white, white); 103 | #endif 104 | 105 | #ifdef NEOPIXEL_RGB 106 | strip->setPixelColor(ledMap[num], red, green, blue); 107 | #endif 108 | 109 | return; 110 | } 111 | -------------------------------------------------------------------------------- /LedDriver.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // LedDriver.h 3 | //***************************************************************************** 4 | 5 | #ifndef LEDDRIVER_H 6 | #define LEDDRIVER_H 7 | 8 | #include 9 | #include "Configuration.h" 10 | #include "Colors.h" 11 | 12 | class LedDriver { 13 | public: 14 | LedDriver(); 15 | ~LedDriver(); 16 | 17 | void clear(); 18 | void show(); 19 | void setPixel(uint8_t x, uint8_t y, uint8_t color, uint8_t brightness); 20 | void setPixel(uint8_t num, uint8_t color, uint8_t brightness); 21 | 22 | private: 23 | Adafruit_NeoPixel* strip; 24 | 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Letters.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Letters.h 3 | ******************************************************************************/ 4 | 5 | #ifndef LETTERS_H 6 | #define LETTERS_H 7 | 8 | const char letters[][5] = 9 | { 10 | { // 0:A 11 | 0b00001100, 12 | 0b00010010, 13 | 0b00011110, 14 | 0b00010010, 15 | 0b00010010 16 | } 17 | , { // 1:B 18 | 0b00011100, 19 | 0b00010010, 20 | 0b00011100, 21 | 0b00010010, 22 | 0b00011100 23 | } 24 | , { // 2:C 25 | 0b00001110, 26 | 0b00010000, 27 | 0b00010000, 28 | 0b00010000, 29 | 0b00001110 30 | } 31 | , { // 3:D 32 | 0b00011100, 33 | 0b00010010, 34 | 0b00010010, 35 | 0b00010010, 36 | 0b00011100 37 | } 38 | , { // 4:E 39 | 0b00011110, 40 | 0b00010000, 41 | 0b00011100, 42 | 0b00010000, 43 | 0b00011110 44 | } 45 | , { // 5:F 46 | 0b00011110, 47 | 0b00010000, 48 | 0b00011100, 49 | 0b00010000, 50 | 0b00010000 51 | } 52 | , { // 6:G 53 | 0b00001110, 54 | 0b00010000, 55 | 0b00010110, 56 | 0b00010010, 57 | 0b00001100 58 | } 59 | , { // 7:H 60 | 0b00010010, 61 | 0b00010010, 62 | 0b00011110, 63 | 0b00010010, 64 | 0b00010010 65 | } 66 | , { // 8:I 67 | 0b00001110, 68 | 0b00000100, 69 | 0b00000100, 70 | 0b00000100, 71 | 0b00001110 72 | } 73 | , { // 9:J 74 | 0b00011110, 75 | 0b00000010, 76 | 0b00000010, 77 | 0b00010010, 78 | 0b00001100 79 | } 80 | , { // 10:K 81 | 0b00010010, 82 | 0b00010100, 83 | 0b00011000, 84 | 0b00010100, 85 | 0b00010010 86 | } 87 | , { // 11:L 88 | 0b00010000, 89 | 0b00010000, 90 | 0b00010000, 91 | 0b00010000, 92 | 0b00011110 93 | } 94 | , { // 12:M 95 | 0b00010001, 96 | 0b00011011, 97 | 0b00010101, 98 | 0b00010001, 99 | 0b00010001 100 | } 101 | , { // 13:N 102 | 0b00010001, 103 | 0b00011001, 104 | 0b00010101, 105 | 0b00010011, 106 | 0b00010001 107 | } 108 | , { // 14:O 109 | 0b00011110, 110 | 0b00010010, 111 | 0b00010010, 112 | 0b00010010, 113 | 0b00011110 114 | } 115 | , { // 15:P 116 | 0b00011100, 117 | 0b00010010, 118 | 0b00011100, 119 | 0b00010000, 120 | 0b00010000 121 | } 122 | , { // 16:Q 123 | 0b00001100, 124 | 0b00010010, 125 | 0b00010010, 126 | 0b00001100, 127 | 0b00000010 128 | } 129 | , { // 17:R 130 | 0b00011100, 131 | 0b00010010, 132 | 0b00011100, 133 | 0b00010100, 134 | 0b00010010 135 | } 136 | , { // 18:S 137 | 0b00001110, 138 | 0b00010000, 139 | 0b00001100, 140 | 0b00000010, 141 | 0b00011100 142 | } 143 | , { // 19:T 144 | 0b00011111, 145 | 0b00000100, 146 | 0b00000100, 147 | 0b00000100, 148 | 0b00000100 149 | } 150 | , { // 20:U 151 | 0b00010001, 152 | 0b00010001, 153 | 0b00010001, 154 | 0b00010001, 155 | 0b00001110 156 | } 157 | , { // 21:V 158 | 0b00010001, 159 | 0b00010001, 160 | 0b00010001, 161 | 0b00001010, 162 | 0b00000100 163 | } 164 | , { // 22:W 165 | 0b00010001, 166 | 0b00010001, 167 | 0b00010101, 168 | 0b00011011, 169 | 0b00010001 170 | } 171 | , { // 23:X 172 | 0b00010001, 173 | 0b00001010, 174 | 0b00000100, 175 | 0b00001010, 176 | 0b00010001 177 | } 178 | , { // 24:Y 179 | 0b00010001, 180 | 0b00001010, 181 | 0b00000100, 182 | 0b00000100, 183 | 0b00000100 184 | } 185 | , { // 25:Z 186 | 0b00011110, 187 | 0b00000010, 188 | 0b00000100, 189 | 0b00001000, 190 | 0b00011110 191 | } 192 | }; 193 | 194 | const char lettersBig[][7] = 195 | { 196 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ASCII-Code 0x20 => (32) 197 | { 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04 }, // ASCII-Code 0x21 => ! (33) 198 | { 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00 }, // ASCII-Code 0x22 => " (34) 199 | { 0x0a, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x0a }, // ASCII-Code 0x23 => # (35) 200 | { 0x04, 0x0f, 0x14, 0x0e, 0x05, 0x1e, 0x04 }, // ASCII-Code 0x24 => $ (36) 201 | { 0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03 }, // ASCII-Code 0x25 => % (37) 202 | { 0x0c, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0d }, // ASCII-Code 0x26 => & (38) 203 | { 0x18, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00 }, // ASCII-Code 0x27 => ' (39) 204 | { 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02 }, // ASCII-Code 0x28 => ( (40) 205 | { 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10 }, // ASCII-Code 0x29 => ) (41) 206 | { 0x00, 0x04, 0x15, 0x0e, 0x15, 0x04, 0x00 }, // ASCII-Code 0x2A => * (42) 207 | { 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00 }, // ASCII-Code 0x2B => + (43) 208 | { 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x10 }, // ASCII-Code 0x2C => , (44) 209 | { 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00 }, // ASCII-Code 0x2D => - (45) 210 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }, // ASCII-Code 0x2E => . (46) 211 | { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00 }, // ASCII-Code 0x2F => / (47) 212 | #ifdef NONE_TECHNICAL_ZERO 213 | { 0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e }, // ASCII-Code 0x30 => 0 (48) 214 | #else 215 | { 0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e }, // ASCII-Code 0x30 => 0 (48) 216 | #endif 217 | { 0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e }, // ASCII-Code 0x31 => 1 (49) 218 | { 0x0e, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1f }, // ASCII-Code 0x32 => 2 (50) 219 | { 0x1f, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0e }, // ASCII-Code 0x33 => 3 (51) 220 | { 0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02 }, // ASCII-Code 0x34 => 4 (52) 221 | { 0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e }, // ASCII-Code 0x35 => 5 (53) 222 | { 0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e }, // ASCII-Code 0x36 => 6 (54) 223 | { 0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08 }, // ASCII-Code 0x37 => 7 (55) 224 | { 0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e }, // ASCII-Code 0x38 => 8 (56) 225 | { 0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c }, // ASCII-Code 0x39 => 9 (57) 226 | { 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00 }, // ASCII-Code 0x3A => : (58) 227 | { 0x00, 0x18, 0x18, 0x00, 0x18, 0x08, 0x10 }, // ASCII-Code 0x3B => ; (59) 228 | { 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02 }, // ASCII-Code 0x3C => < (60) 229 | { 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00 }, // ASCII-Code 0x3D => = (61) 230 | { 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10 }, // ASCII-Code 0x3E => > (62) 231 | { 0x0e, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04 }, // ASCII-Code 0x3F => ? (63) 232 | { 0x0e, 0x11, 0x01, 0x0d, 0x15, 0x15, 0x0e }, // ASCII-Code 0x40 => @ (64) 233 | { 0x0e, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11 }, // ASCII-Code 0x41 => A (65) 234 | { 0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e }, // ASCII-Code 0x42 => B (66) 235 | { 0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e }, // ASCII-Code 0x43 => C (67) 236 | { 0x1c, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1c }, // ASCII-Code 0x44 => D (68) 237 | { 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f }, // ASCII-Code 0x45 => E (69) 238 | { 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10 }, // ASCII-Code 0x46 => F (70) 239 | { 0x0e, 0x11, 0x10, 0x16, 0x11, 0x11, 0x0e }, // ASCII-Code 0x47 => G (71) 240 | { 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11 }, // ASCII-Code 0x48 => H (72) 241 | { 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e }, // ASCII-Code 0x49 => I (73) 242 | { 0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0c }, // ASCII-Code 0x4A => J (74) 243 | { 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11 }, // ASCII-Code 0x4B => K (75) 244 | { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f }, // ASCII-Code 0x4C => L (76) 245 | { 0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11 }, // ASCII-Code 0x4D => M (77) 246 | { 0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11 }, // ASCII-Code 0x4E => N (78) 247 | { 0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e }, // ASCII-Code 0x4F => O (79) 248 | { 0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10 }, // ASCII-Code 0x50 => P (80) 249 | { 0x0e, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0d }, // ASCII-Code 0x51 => Q (81) 250 | { 0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11 }, // ASCII-Code 0x52 => R (82) 251 | { 0x0e, 0x11, 0x10, 0x0e, 0x01, 0x11, 0x0e }, // ASCII-Code 0x53 => S (83) 252 | { 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, // ASCII-Code 0x54 => T (84) 253 | { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e }, // ASCII-Code 0x55 => U (85) 254 | { 0x11, 0x11, 0x11, 0x11, 0x11, 0x0a, 0x04 }, // ASCII-Code 0x56 => V (86) 255 | { 0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0a }, // ASCII-Code 0x57 => W (87) 256 | { 0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11 }, // ASCII-Code 0x58 => X (88) 257 | { 0x11, 0x11, 0x11, 0x0a, 0x04, 0x04, 0x04 }, // ASCII-Code 0x59 => Y (89) 258 | { 0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f }, // ASCII-Code 0x5A => Z (90) 259 | { 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c }, // ASCII-Code 0x5B => [ (91) � 260 | { 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 }, // ASCII-Code 0x5C => \ (92) � 261 | { 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c }, // ASCII-Code 0x5D => ] (93) � 262 | { 0x04, 0x0a, 0x11, 0x00, 0x00, 0x00, 0x00 }, // ASCII-Code 0x5E => ^ (94) 263 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f }, // ASCII-Code 0x5F => _ (95) 264 | { 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, // ASCII-Code 0x60 => ` (96) 265 | { 0x00, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f }, // ASCII-Code 0x61 => a (97) 266 | { 0x10, 0x10, 0x10, 0x16, 0x19, 0x11, 0x1e }, // ASCII-Code 0x62 => b (98) 267 | { 0x00, 0x00, 0x0e, 0x10, 0x10, 0x11, 0x0e }, // ASCII-Code 0x63 => c (99) 268 | { 0x01, 0x01, 0x01, 0x0d, 0x13, 0x11, 0x0f }, // ASCII-Code 0x64 => d (100) 269 | { 0x00, 0x00, 0x0e, 0x11, 0x1f, 0x10, 0x0e }, // ASCII-Code 0x65 => e (101) 270 | { 0x06, 0x09, 0x08, 0x1c, 0x08, 0x08, 0x08 }, // ASCII-Code 0x66 => f (102) 271 | { 0x00, 0x0f, 0x11, 0x11, 0x0f, 0x01, 0x0e }, // ASCII-Code 0x67 => g (103) 272 | { 0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11 }, // ASCII-Code 0x68 => h (104) 273 | { 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04 }, // ASCII-Code 0x69 => i (105) 274 | { 0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0c }, // ASCII-Code 0x6A => j (106) 275 | { 0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12 }, // ASCII-Code 0x6B => k (107) 276 | { 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e }, // ASCII-Code 0x6C => l (108) 277 | { 0x00, 0x00, 0x1a, 0x15, 0x15, 0x11, 0x11 }, // ASCII-Code 0x6D => m (109) 278 | { 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11 }, // ASCII-Code 0x6E => n (110) 279 | { 0x00, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e }, // ASCII-Code 0x6F => o (111) 280 | { 0x00, 0x00, 0x1e, 0x11, 0x1e, 0x10, 0x10 }, // ASCII-Code 0x70 => p (112) 281 | { 0x00, 0x00, 0x0d, 0x13, 0x0f, 0x01, 0x01 }, // ASCII-Code 0x71 => q (113) 282 | { 0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10 }, // ASCII-Code 0x72 => r (114) 283 | { 0x00, 0x00, 0x0e, 0x10, 0x0e, 0x01, 0x1e }, // ASCII-Code 0x73 => s (115) 284 | { 0x08, 0x08, 0x1c, 0x08, 0x08, 0x08, 0x06 }, // ASCII-Code 0x74 => t (116) 285 | { 0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0d }, // ASCII-Code 0x75 => u (117) 286 | { 0x00, 0x00, 0x11, 0x11, 0x11, 0x0a, 0x04 }, // ASCII-Code 0x76 => v (118) 287 | { 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0a }, // ASCII-Code 0x77 => w (119) 288 | { 0x00, 0x00, 0x11, 0x0a, 0x04, 0x0a, 0x11 }, // ASCII-Code 0x78 => x (120) 289 | { 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0x0e }, // ASCII-Code 0x79 => y (121) 290 | { 0x00, 0x00, 0x1f, 0x02, 0x04, 0x08, 0x1f }, // ASCII-Code 0x7A => z (122) 291 | { 0x04, 0x08, 0x08, 0x10, 0x08, 0x08, 0x04 }, // ASCII-Code 0x7B => { (123) � 292 | { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, // ASCII-Code 0x7C => | (124) � 293 | { 0x10, 0x08, 0x08, 0x04, 0x08, 0x08, 0x10 }, // ASCII-Code 0x7D => } (125) � 294 | { 0x00, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00 } // ASCII-Code 0x7E => ~ (126) � 295 | }; 296 | 297 | #endif 298 | -------------------------------------------------------------------------------- /MeteoWeather.cpp: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // MeteoWeather.cpp - Get weather data from Open-Meteo 3 | //***************************************************************************** 4 | 5 | #include "MeteoWeather.h" 6 | 7 | MeteoWeather::MeteoWeather() { 8 | } 9 | 10 | MeteoWeather::~MeteoWeather() { 11 | } 12 | 13 | uint8_t MeteoWeather::getOutdoorConditions(String lat, String lon, String timezone) { 14 | String response; 15 | WiFiClient client; 16 | JsonDocument doc; 17 | timezone.replace("/","%2F"); 18 | if (client.connect("api.open-meteo.com", 80)) { 19 | String url = "/v1/forecast?latitude=" + String(lat) + "&longitude=" + String(lon) + "¤t=temperature_2m,relative_humidity_2m,surface_pressure&daily=sunrise,sunset&timeformat=unixtime&timezone=" + timezone + "&forecast_days=1"; 20 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: api.open-meteo.com" + "\r\n" + "Connection: close\r\n\r\n"); 21 | unsigned long startMillis = millis(); 22 | while (client.available() == 0) { 23 | if (millis() - startMillis > 5000) { 24 | client.stop(); 25 | return 0; 26 | } 27 | } 28 | 29 | while (client.available()) 30 | response = client.readString(); 31 | #ifdef DEBUG 32 | Serial.println("Weather api response:"); 33 | Serial.println(response); 34 | #endif 35 | 36 | response.trim(); 37 | int first = response.indexOf("{"); // Extract json file content of message. 38 | String extract = response.substring(first); 39 | 40 | // Created with https://arduinojson.org/v7/assistant/ 41 | 42 | DeserializationError error = deserializeJson(doc, extract); 43 | 44 | if (error) { 45 | Serial.print("deserializeJson() failed: "); 46 | Serial.println(error.c_str()); 47 | return 0; 48 | } 49 | 50 | float latitude = doc["latitude"]; // 52.52 51 | double longitude = doc["longitude"]; // 13.419998 52 | double generationtime_ms = doc["generationtime_ms"]; // 0.054001808166503906 53 | int utc_offset_seconds = doc["utc_offset_seconds"]; // 7200 54 | const char* timezone = doc["timezone"]; // "Europe/Berlin" 55 | const char* timezone_abbreviation = doc["timezone_abbreviation"]; // "CEST" 56 | int elevation = doc["elevation"]; // 38 57 | 58 | JsonObject current_units = doc["current_units"]; 59 | const char* current_units_time = current_units["time"]; // "unixtime" 60 | const char* current_units_interval = current_units["interval"]; // "seconds" 61 | const char* current_units_temperature_2m = current_units["temperature_2m"]; // "°C" 62 | const char* current_units_relative_humidity_2m = current_units["relative_humidity_2m"]; // "%" 63 | const char* current_units_surface_pressure = current_units["surface_pressure"]; // "hPa" 64 | 65 | JsonObject current = doc["current"]; 66 | long current_time = current["time"]; // 1725390000 67 | int current_interval = current["interval"]; // 900 68 | float current_temperature_2m = current["temperature_2m"]; // 27.1 69 | int current_relative_humidity_2m = current["relative_humidity_2m"]; // 53 70 | float current_surface_pressure = current["surface_pressure"]; // 1010.1 71 | 72 | JsonObject daily_units = doc["daily_units"]; 73 | const char* daily_units_time = daily_units["time"]; // "unixtime" 74 | const char* daily_units_sunrise = daily_units["sunrise"]; // "unixtime" 75 | const char* daily_units_sunset = daily_units["sunset"]; // "unixtime" 76 | 77 | JsonObject daily = doc["daily"]; 78 | long daily_time_0 = daily["time"][0]; // 1725314400 79 | long daily_sunrise_0 = daily["sunrise"][0]; // 1725337296 80 | long daily_sunset_0 = daily["sunset"][0]; // 1725385761 81 | 82 | temperature = (double)current_temperature_2m; 83 | humidity = (int)current_relative_humidity_2m; 84 | pressure = (int)current_surface_pressure; 85 | sunrise = (int)daily_sunrise_0; // api also provides sunrise / sunset times. Just use them as well. 86 | sunset = (int)daily_sunset_0; 87 | return 1; 88 | } 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /MeteoWeather.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // MeteoWeather.h - Get weather data and sunrise/sunset times from Open-Meteo 3 | //***************************************************************************** 4 | 5 | #ifndef METEOWEATHER_H 6 | #define METEOWEATHER_H 7 | 8 | // #include 9 | #include 10 | #include 11 | 12 | class MeteoWeather { 13 | public: 14 | MeteoWeather(); 15 | ~MeteoWeather(); 16 | 17 | String description; 18 | double temperature; 19 | uint8_t humidity; 20 | uint16_t pressure; 21 | time_t sunrise; 22 | time_t sunset; 23 | 24 | uint8_t getOutdoorConditions(String lat, String lon, String timezone); 25 | 26 | private: 27 | 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Modes.h: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // Modes.h 3 | //****************************************************************************** 4 | 5 | #ifndef MODES_H 6 | #define MODES_H 7 | 8 | typedef enum eMode : uint8_t 9 | { 10 | MODE_TIME, // 0 11 | #ifdef SHOW_MODE_AMPM 12 | MODE_AMPM, // 1 13 | #endif 14 | #ifdef SHOW_MODE_SECONDS 15 | MODE_SECONDS, // 2 if SHOW_MODE_AMPM is set - 1 if not set and so on... 16 | #endif 17 | #ifdef SHOW_MODE_WEEKDAY 18 | MODE_WEEKDAY, // 3 if... 19 | #endif 20 | #ifdef SHOW_MODE_DATE 21 | MODE_DATE, // 4 22 | #endif 23 | #if defined(SHOW_MODE_SUNRISE_SUNSET) && defined(WEATHER) 24 | MODE_SUNRISE, // 5 25 | MODE_SUNSET, // 6 26 | #endif 27 | #ifdef SHOW_MODE_MOONPHASE 28 | MODE_MOONPHASE, // 7 29 | #endif 30 | #if defined(RTC_BACKUP) || defined(SENSOR_DHT22) 31 | MODE_TEMP, // 8 32 | #endif 33 | #ifdef SENSOR_DHT22 34 | MODE_HUMIDITY, // 9 35 | #endif 36 | #ifdef WEATHER 37 | MODE_EXT_TEMP, // 10 38 | MODE_EXT_HUMIDITY, // 11 39 | #endif 40 | #ifdef BUZZER 41 | MODE_TIMER, // 12 42 | #endif 43 | #ifdef SHOW_MODE_TEST 44 | MODE_TEST, // 13 45 | MODE_RED, // 14 46 | MODE_GREEN, // 15 47 | MODE_BLUE, // 16 48 | MODE_WHITE, // 17 49 | #endif 50 | MODE_COUNT, // 18 51 | MODE_BLANK, // 19 52 | MODE_FEED // 20 53 | } Mode; 54 | 55 | // Overload the ControlType++ operator. 56 | inline Mode& operator++(Mode& eDOW, int) 57 | { 58 | const uint8_t i = static_cast(eDOW) + 1; 59 | eDOW = static_cast((i) % MODE_COUNT); 60 | return eDOW; 61 | } 62 | 63 | enum eTransition 64 | { 65 | TRANSITION_NORMAL, // 0 66 | TRANSITION_MOVEUP, // 1 67 | TRANSITION_FADE // 2 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /Ntp.cpp: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // Ntp.cpp - Get UTC time from NTP 3 | //****************************************************************************** 4 | 5 | #include "Ntp.h" 6 | 7 | Ntp::Ntp() { 8 | } 9 | 10 | Ntp::~Ntp() { 11 | } 12 | 13 | time_t Ntp::getTime(char* server) { 14 | uint8_t packetBuffer[49] = {}; 15 | packetBuffer[0] = 0xE3; 16 | packetBuffer[1] = 0x00; 17 | packetBuffer[2] = 0x06; 18 | packetBuffer[3] = 0xEC; 19 | packetBuffer[12] = 0x31; 20 | packetBuffer[13] = 0x4E; 21 | packetBuffer[14] = 0x31; 22 | packetBuffer[15] = 0x34; 23 | WiFiUDP wifiUdp; 24 | wifiUdp.begin(2390); 25 | IPAddress timeServerIP; 26 | WiFi.hostByName(server, timeServerIP); 27 | wifiUdp.beginPacket(timeServerIP, 123); 28 | wifiUdp.write(packetBuffer, 48); 29 | wifiUdp.endPacket(); 30 | uint32_t beginWait = millis(); 31 | while ((millis() - beginWait) < 5000) { 32 | if (wifiUdp.parsePacket() >= 48) { 33 | wifiUdp.read(packetBuffer, 48); 34 | uint32_t ntpTime = (packetBuffer[40] << 24) + (packetBuffer[41] << 16) + (packetBuffer[42] << 8) + packetBuffer[43]; 35 | // NTP time is seconds from 1900, TimeLib.h needs seconds from 1970 36 | ntpTime -= 2208988800; 37 | return ntpTime; 38 | } 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Ntp.h: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // Ntp.h - Get UTC time from NTP 3 | //****************************************************************************** 4 | 5 | #ifndef NTP_H 6 | #define NTP_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class Ntp { 13 | public: 14 | Ntp(); 15 | ~Ntp(); 16 | 17 | time_t getTime(char* server); 18 | 19 | private: 20 | 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /Numbers.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Numbers.h 3 | ******************************************************************************/ 4 | 5 | #ifndef NUMBERS_H 6 | #define NUMBERS_H 7 | 8 | const char numbers[][5] = 9 | { 10 | { // 0 11 | 0b00011110, 12 | 0b00010010, 13 | 0b00010010, 14 | 0b00010010, 15 | 0b00011110 16 | }, 17 | { // 1 18 | 0b00000100, 19 | 0b00001100, 20 | 0b00000100, 21 | 0b00000100, 22 | 0b00001110 23 | }, 24 | { // 2 25 | 0b00011110, 26 | 0b00000010, 27 | 0b00011110, 28 | 0b00010000, 29 | 0b00011110 30 | }, 31 | { // 3 32 | 0b00011110, 33 | 0b00000010, 34 | 0b00001110, 35 | 0b00000010, 36 | 0b00011110 37 | }, 38 | { // 4 39 | 0b00010010, 40 | 0b00010010, 41 | 0b00011110, 42 | 0b00000010, 43 | 0b00000010 44 | }, 45 | { // 5 46 | 0b00011110, 47 | 0b00010000, 48 | 0b00011110, 49 | 0b00000010, 50 | 0b00011110 51 | }, 52 | { // 6 53 | 0b00011110, 54 | 0b00010000, 55 | 0b00011110, 56 | 0b00010010, 57 | 0b00011110 58 | }, 59 | { // 7 60 | 0b00011110, 61 | 0b00000010, 62 | 0b00000100, 63 | 0b00000100, 64 | 0b00000100 65 | }, 66 | { // 8 67 | 0b00011110, 68 | 0b00010010, 69 | 0b00011110, 70 | 0b00010010, 71 | 0b00011110 72 | }, 73 | { // 9 74 | 0b00011110, 75 | 0b00010010, 76 | 0b00011110, 77 | 0b00000010, 78 | 0b00011110 79 | } 80 | }; 81 | 82 | const char numbersBig[][7] = 83 | { 84 | { // 0 85 | #ifdef NONE_TECHNICAL_ZERO 86 | 0b00001110, 87 | 0b00010001, 88 | 0b00010001, 89 | 0b00010001, 90 | 0b00010001, 91 | 0b00010001, 92 | 0b00001110 93 | #else 94 | 0b00001110, 95 | 0b00010001, 96 | 0b00010011, 97 | 0b00010101, 98 | 0b00011001, 99 | 0b00010001, 100 | 0b00001110 101 | #endif 102 | }, 103 | { // 1 104 | 0b00000100, 105 | 0b00001100, 106 | 0b00000100, 107 | 0b00000100, 108 | 0b00000100, 109 | 0b00000100, 110 | 0b00001110 111 | }, 112 | { // 2 113 | 0b00001110, 114 | 0b00010001, 115 | 0b00000001, 116 | 0b00000010, 117 | 0b00000100, 118 | 0b00001000, 119 | 0b00011111 120 | }, 121 | { // 3 122 | 0b00011111, 123 | 0b00000010, 124 | 0b00000100, 125 | 0b00000010, 126 | 0b00000001, 127 | 0b00010001, 128 | 0b00001110 129 | }, 130 | { // 4 131 | 0b00000010, 132 | 0b00000110, 133 | 0b00001010, 134 | 0b00010010, 135 | 0b00011111, 136 | 0b00000010, 137 | 0b00000010 138 | }, 139 | { // 5 140 | 0b00011111, 141 | 0b00010000, 142 | 0b00011110, 143 | 0b00000001, 144 | 0b00000001, 145 | 0b00010001, 146 | 0b00001110 147 | }, 148 | { // 6 149 | 0b00000110, 150 | 0b00001000, 151 | 0b00010000, 152 | 0b00011110, 153 | 0b00010001, 154 | 0b00010001, 155 | 0b00001110 156 | }, 157 | { // 7 158 | 0b00011111, 159 | 0b00000001, 160 | 0b00000010, 161 | 0b00000100, 162 | 0b00001000, 163 | 0b00001000, 164 | 0b00001000 165 | }, 166 | { // 8 167 | 0b00001110, 168 | 0b00010001, 169 | 0b00010001, 170 | 0b00001110, 171 | 0b00010001, 172 | 0b00010001, 173 | 0b00001110 174 | }, 175 | { // 9 176 | 0b00001110, 177 | 0b00010001, 178 | 0b00010001, 179 | 0b00001111, 180 | 0b00000001, 181 | 0b00000010, 182 | 0b00001100 183 | } 184 | }; 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /Qlockwork.ino: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch570512/Qlockwork/61b2f1277fc275595ddf32fdbab3b12437bfc933/Qlockwork.ino -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | ****************************************************************************** 2 | QLOCKWORK 3 | An advanced firmware for a DIY "word-clock". 4 | ****************************************************************************** 5 | 6 | Qlockwork is an ESP8266 (NodeMCU or WeMos D1 mini) firmware (under GPL license) for a so called "word-clock". 7 | 8 | The clock adjusts the time and date once every hour via NTP with a time server on the Internet. 9 | If an RTC is installed, the time of the ESP is also set from the RTC via the SyncProvider. 10 | 11 | At startup the clock performs a short self test. 12 | The sequence of the colors should be: red, green, blue and white. If not, your LED driver setup is wrong. 13 | The clock also shows the local IP address it received via DHCP. 14 | Use this address in a browser to access the clocks web site to set it up. 15 | 16 | WiFi manager: If the clock can not connect to any WLAN at startup, it turns on an access point. 17 | Connect a mobile phone or tablet to the AP and enter the WLAN credentials. A white "WiFi" is shown on the clock. 18 | On success there are three short beeps and "WiFi" will be green. 19 | If no WLAN is connected or the timeout has expired, there is a long beep and "WiFi" turns red. 20 | After the WLAN timeout the clock works without NTP but you can still control it via its AP. 21 | Without WLAN the clock uses the optional RTC to set the time or if no RTC is present has to be set manually. 22 | In either ways the clocks IP is shown as a textfeed. 23 | 24 | Events can be shown every five minutes on a particular day of the year as a textfeed. 25 | You can set them in "Events.h". Expand the array with events as shown in the default values. 26 | You can set a color for every event. Do not change the first entry. 27 | There is no comma behind the last entry. 28 | 29 | Updates of the firmware could be uploaded via USB, OTA or the clocks webserver. 30 | You will find more help and information on how to configure and compile the firmware in "Readme.md" in the zip-archive. 31 | You will also find a circuit diagram, a partslist and some pictures in the "/misc" directory. 32 | All sensors, the RTC and the buzzer are optional. 33 | The clock will run with the ESP8266 module only. No PCB needed. 34 | 35 | Warning: Do not power up the clock from USB only. 36 | This would blow up the ESP or even the USB port because of high power demand of the LED stripe. 37 | Always use an external 5V powersupply with at least 4A. 38 | 39 | Disclaimer: Qlockwork uses lots of third party libraries. 40 | I can not guarantee the integrity of these libraries. 41 | You use the Qlockwork firmware at your own risk. 42 | 43 | You can find the QLOCKWORK web-site here: 44 | http://thorsten-wahl.ch/qlockwork/ 45 | 46 | You can download the latest version of the firmware here: 47 | https://github.com/ch570512/Qlockwork 48 | 49 | Visit this forum for comments, suggestions and bug reports: 50 | http://diskussion.christians-bastel-laden.de/viewtopic.php?f=23&t=2843 51 | 52 | ****************************************************************************** 53 | Top features: 54 | ****************************************************************************** 55 | 56 | Almost no electronics needed. Only an ESP8266 and an LED-stripe. 57 | Optional support for LDR, Buzzer, temperature and humidity sensor, IR-remote and buttons. 58 | Support for NeoPixel (RGB and RGBW) LED-stripes. 59 | Support for various horizontal and vertical LED layouts. 3 layouts included. 60 | Webpage to control and configure the clock via WiFi. 61 | Adaptive brightness control when using an LDR. 62 | 3 transitions for timechange. 63 | Indoor temperature from RTC or temperature and humidity from DHT sensor. 64 | Outdoor temperature and humidity from MeteoWeather. 65 | Visualisation of moonphase. 66 | Show sunrise and sunset times with animation. 67 | Textfeed for events and infos, local and over the web. 68 | Support for 16 frontcovers (Original and DIY) in 6 languages. 69 | 25 Colors. 70 | 99 minute timer. 71 | 2 Alarms with weekday selection. 72 | NTP timesync with timezone support. 73 | Automatic adjustment of daylight saving time. 74 | USB and Over-the-air firmware updates. 75 | 76 | ****************************************************************************** 77 | Pages: 78 | ****************************************************************************** 79 | 80 | Time 81 | AM/PM 82 | Seconds 83 | Weekday 84 | Date 85 | Sunrise (needs MeteoWeather) 86 | Sunset (needs MeteoWeather) 87 | Moonphase 88 | Room temperature (needs RTX or DHT22) 89 | Room humidity (needs DHT22) 90 | Outdoor temperature (needs MeteoWeather) 91 | Outdoor humidity (needs MeteoWeather) 92 | Timer 93 | LED-test 94 | Red 95 | Green 96 | Blue 97 | White 98 | 99 | ****************************************************************************** 100 | Needed libraries: (recommended/tested versions in brackets) 101 | ****************************************************************************** 102 | 103 | Arduino IDE for Windows (1.8.19) 104 | esp8266 by ESP8266 Community (3.0.2) 105 | Arduino_JSON by Arduino (0.1.0) 106 | ArduinoJason by bblanchon (7.1.0) 107 | Adafruit NeoPixel by Adafruit (1.10.4) 108 | Adafruit Unified Sensor by Adafruit (1.1.5) 109 | ArduinoHttpClient by Arduino (0.4.0) 110 | ArduinoOTA by Juraj Andressy (1.0.7) 111 | DHT sensor library by Adafruit (1.4.3) 112 | DS3232RTC by Jack Christensen (2.0.0) 113 | IRremoteESP8266 by Sebastien Warin (2.8.1) 114 | Time by Michael Margolis (1.6.1) 115 | 116 | Included in source is the Timezone library from Jack Christensen 117 | and WiFiManager by AlexT. 118 | 119 | ****************************************************************************** 120 | Compiler-Options: (recommended/tested) 121 | ****************************************************************************** 122 | 123 | Board: "LOLIN(WEMOS) D1 R2 & mini" 124 | CPU Frequency: "80 MHz" 125 | Flash Size: "4M (3M SPIFFS)" 126 | Debug port: "Disabled" 127 | Debug Level: "None" 128 | IwIP Variant: "v2 Lower Memory" 129 | VTables: "Flash" 130 | Exceptions: "Disabled" 131 | Erase Flash: "Only Sketch" 132 | SSL Support: "All SSL ciphers" 133 | 134 | ****************************************************************************** 135 | Misc: 136 | ****************************************************************************** 137 | 138 | For OTA and web-server updates check out: 139 | http://esp8266.github.io/Arduino/versions/2.3.0/doc/ota_updates/readme.html 140 | Don't forget to install Python 2.7 and to select "Add python.exe to path" while installing. 141 | 142 | Call "http://your_clocks_ip/update" to upload a new firmware via webbrowser. 143 | Call "http://your_clocks_ip/reset" to restart the ESP. 144 | 145 | ****************************************************************************** 146 | Operation manual: 147 | ****************************************************************************** 148 | 149 | Press "on/off" to switch the LEDs on and off. 150 | Press "Settings" to configure the clock via web-site. 151 | Press "Mode" to jump to the next page. 152 | Press "Time" to always jump back to the time page. 153 | 154 | *** Modes: ******************************************************************* 155 | 156 | Time: The default mode of the clock. Shows the actual time. :) 157 | Display AM/PM: Indicates whether it is AM or PM. 158 | Seconds: Shows the seconds. 159 | Weekday: Shows the weekday in local language. 160 | Date: Shows day and month. 161 | Sunrise: Time of sunrise. 162 | Sunset: Time of sunset. 163 | Moonphase: Shows the moonphase. 164 | Room temperature: Display of the measured temperature in the room (only with RTC or DHT22). 165 | Room humidity: Display of the measured humidity in the room (only with DHT22). 166 | Outdoor temperature: Display the temperature for your location from MeteoWeather. 167 | Outdoor humidity: Display the humidity for your location from MeteoWeather. 168 | Timer: Display of the remaining time if a timer is set. 169 | LED-Test: Moves a horizontal bar across the display. 170 | Red: Set all LEDs to red. 171 | Green: Set all LEDs to green. 172 | Blue: Set all LEDs to blue. 173 | White: Set all LEDs to white. 174 | 175 | *** Settings: **************************************************************** 176 | 177 | Alarm 1: Enable (on) or disable (off) alarm 1. 178 | Time for alarm 1. 179 | Weekdays on which alarm 1 is active. 180 | Alarm 2: Enable (on) or disable (off) alarm 2. 181 | Time for alarm 2. 182 | Weekdays on which alarm 2 is active. 183 | Hourly beep: Short beep every full hour. 184 | Timer: Sets the minute timer. Set to zero to disable a running timer. 185 | Show temperature: Enable (on) or disable (off) showing the temperature in time view. 186 | ABC: Enable (on) or disable (off) adaptive brightness control. 187 | Brightness will adjust itself in the range of MIN_BRIGHTNESS and brightness. 188 | Brightness: Brightness of the LEDs in percent. The range is MIN_BRIGHTNESS to MAX_BRIGHTNESS. 189 | If ABC is enabled this is the maximum achievable brightness. 190 | Color: Choose one of 25 colors for the LEDs. 191 | Colorchange: Change the color in intervals. 192 | Do not change (off), every 5 minutes (five), every hour (hour), every day (day). 193 | Transition: Choose between fast, move or fade mode transition. 194 | Timeout: Time in seconds to change mode back to time. (0: disabled) 195 | Night off: Set the time the clocks turns itself off at night. 196 | Day on: Set the time the clocks turns itself on at day. 197 | Show "It is": Enable (on) or disable (off) "It is". It will be shown every half and full hour anyway. 198 | Set date/time: Date and time of the clock. The seconds are set to zero if you press save. 199 | 200 | ****************************************************************************** 201 | Configuration.h - Software settings: 202 | ****************************************************************************** 203 | 204 | #define HOSTNAME The name of the clock. 205 | #define WEBSITE_TITLE Title on top of the clocks webpage. 206 | #define WIFI_SETUP_TIMEOUT Time in seconds set up the WiFiManager or search for a WLAN. 207 | If no WLAN is connected the clock enters AP mode. 208 | You can control the clock if you connect your phone or tablet to this accesspoint. 209 | On Android you have to tell the phone that it's ok to have no internet. 210 | #define WIFI_AP_PASS The password for the AP. At least 8 characters. Default is "12345678". 211 | #define OTA_PASS Password for "Over the Air" updates. Default is "1234". 212 | #define NTP_SERVER NTP server to be queried. 213 | #define NTP_TIMEOUT Milliseconds to wait for NTP server to answer. 214 | #define WIFI_BEEPS Beep 3 times if WIFI is conneced, if not, beep one time on startup. 215 | #define SHOW_IP Show local IP at startup. Use this in the browser to access the clocks menue. 216 | #define NONE_TECHNICAL_ZERO Displays the zero without the diagonal line. 217 | #define AUTO_MODECHANGE_TIME Time in seconds to wait between switching from time to temperature. 218 | #define FEED_SPEED Feed delay in milliseconds. 120 is a good start. 219 | #define SUNSET_SUNRISE_SPEED Milliseconds delay between sunrise screen -> sunrise time and sunset screen -> sunset time 220 | #define EVENT_TIME Time in seconds to wait between showing events. Comment to turn off events. 221 | #define ALARM_LED_COLOR Color of the alarm LED. If not defined the display color will be used. 222 | The possible colors are: 223 | WHITE, RED, RED_25, RED_50, ORANGE, YELLOW, YELLOW_25, YELLOW_50, GREENYELLOW, 224 | GREEN, GREEN_25, GREEN_50, MINTGREEN, CYAN, CYAN_25, CYAN_50, LIGHTBLUE, BLUE, 225 | BLUE_25, BLUE_50, VIOLET, MAGENTA, MAGENTA_25, MAGENTA_50, PINK. 226 | #define ABUSE_CORNER_LED_FOR_ALARM Use the upper right minute LED as alarm LED. Only works if ALARM_LED_COLOR is defined. 227 | If no alarm or timer is set the LED is used as expected. 228 | #define DEDICATION Show a text on the clocks webpage. 229 | 230 | #define POWERON_SELFTEST Test LEDs at startup. Colors are: white, red, green, blue. In this order. 231 | #define SHOW_MODE_AMPM Show AM/PM. 232 | #define SHOW_MODE_SECONDS Show seconds. 233 | #define SHOW_MODE_WEEKDAY Show weekday. 234 | #define SHOW_MODE_DATE Show date. 235 | #define SHOW_MODE_MOONPHASE Show moonphase. 236 | #define SHOW_MODE_SUNRISE_SUNSET Show sunrise and sunset times. 237 | #define SHOW_MODE_TEST Show tests. 238 | 239 | #define WEATHER Enable MeteoWeather usage to display weather information from the internet. 240 | #define LATITUDE Your location latitude for MeteoWeather API. 241 | #define LONGITUDE Your location longitude for MeteoWeather API. 242 | #define TIMZONE Your location timezone for MeteoWeather API. 243 | 244 | #define TIMEZONE_* The time zone in which the clock is located. Important for the UTC offset and the 245 | summer/winter time change. 246 | #define FRONTCOVER_* Frontcover of the clock. This also sets the language of the menu and the website. 247 | 248 | ****************************************************************************** 249 | Configuration.h - Hardware settings: 250 | ****************************************************************************** 251 | 252 | #define ESP_LED Displays the function using the LED on the ESP. It flashes once a second. 253 | 254 | #define ONOFF_BUTTON Use a hardware on/off-button. 255 | #define MODE_BUTTON Use a hardware mode-button. 256 | #define TIME_BUTTON Use a hardware time-button. Debug to serial will not work if defined. 257 | 258 | #define SENSOR_DHT22 Use a DHT22 sensor module (not the plain sensor) for room temperature and humidity. 259 | #define DHT_TEMPERATURE_OFFSET Sets how many degrees the measured room temperature (+ or -) should be corrected. 260 | #define DHT_HUMIDITY_OFFSET Sets how many degrees the measured room humidity (+ or -) should be corrected. 261 | 262 | #define RTC_BACKUP Use an RTC as backup and room temperature. 263 | #define RTC_TEMPERATURE_OFFSET Sets how many degrees the measured room temperature (+ or -) should be corrected. 264 | 265 | #define LDR Use an LDR for adaptive brightness control (ABC). 266 | #define LDR_IS_INVERSE Combined with #define LDR inverses the value of the LDR. 267 | #define LDR_HYSTERESIS Brightness control from a deviation in the range from 0 to 1023. Default: 40. 268 | If your display is flickering increase this value. 269 | #define MIN_BRIGHTNESS Minimum brightness of LEDs ranging from 0 to 255. Default: 20. 270 | #define MAX_BRIGHTNESS Maximum brightness of LEDs ranging from 0 to 255. Default 255. 271 | Your powersupply has to support this brightness. 272 | #define BRIGHTNESS_SELFTEST Brightness of the LEDs while in testmode to not overload the powersupply. 273 | 274 | #define BUZZER Use a buzzer to make noise for alarmtime and timer. 275 | If not defined all alarmfunctions are disabled. 276 | #define BUZZTIME_ALARM_1 Maximum time in seconds for alarm 1 to be active when not turned off manually. 277 | #define BUZZTIME_ALARM_2 Maximum time in seconds for alarm 2 to be active when not turned off manually. 278 | #define BUZZTIME_TIMER Maximum time in seconds for the timer alarm to be active when not turned off manually. 279 | 280 | #define IR_REMOTE Use an IR remote control. 281 | #define IR_LETTER_OFF Turns off the LED behind the IR sensor permanently. This improves IR reception. 282 | #define IR_CODE_* Any remote control can be used. 6 keys are supported. 283 | Press a button on the remote control in front of the clock. 284 | Then write the code displayed in the serial console to the file "Configuration.h". 285 | If you see more than one try the code which is changing from button to button. 286 | DEBUG has to be defined to show you the code. 287 | 288 | #define NEOPIXEL_RGB Select if your LEDs are RGB only. 289 | #define NEOPIXEL_RGBW Select if your LEDs have a distinct white channel (RGBW). 290 | 291 | #define NEOPIXEL_TYPE Specifies the NeoPixel driver. 400kHz, 800kHz, GRB, RGB, GRBW, RGBW... 292 | See \libraries\Adafruit_NeoPixel.h for help. 293 | 294 | #define LED_LAYOUT_HORIZONTAL_1 Horizontal and corner and alarm LEDs at the end of the strip. (As seen from the front.) 295 | 296 | 111 114 112 297 | 000 001 002 003 004 005 006 007 008 009 010 298 | 021 020 019 018 017 016 015 014 013 012 011 299 | 022 023 024 025 026 027 028 029 030 031 032 300 | 043 042 041 040 039 038 037 036 035 034 033 301 | 044 045 046 047 048 049 050 051 052 053 054 302 | 065 064 063 062 061 060 059 058 057 056 055 303 | 066 067 068 069 070 071 072 073 074 075 076 304 | 087 086 085 084 083 082 081 080 079 078 077 305 | 088 089 090 091 092 093 094 095 096 097 098 306 | 109 108 107 106 105 104 103 102 101 100 099 307 | 110 113 308 | 309 | #define LED_LAYOUT_VERTICAL_1 Vertical and corner and alarm LEDs (almost) within the strip. (As seen from the front.) 310 | 311 | 000 114 102 312 | 001 021 022 041 042 061 062 081 082 101 103 313 | 002 020 023 040 043 060 063 080 083 100 104 314 | 003 019 024 039 044 059 064 079 084 099 105 315 | 004 018 025 038 045 058 065 078 085 098 106 316 | 005 017 026 037 046 057 066 077 086 097 107 317 | 006 016 027 036 047 056 067 076 087 096 108 318 | 007 015 028 035 048 055 068 075 088 095 109 319 | 008 014 029 034 049 054 069 074 089 094 110 320 | 009 013 030 033 050 053 070 073 090 093 111 321 | 010 012 031 032 051 052 071 072 091 092 112 322 | 011 113 323 | 324 | #define LED_LAYOUT_VERTICAL_2 Vertical and corner and alarm LEDs at the end of the strip. (As seen from the front.) 325 | 326 | 112 111 110 327 | 009 010 029 030 049 050 069 070 089 090 109 328 | 008 011 028 031 048 051 068 071 088 091 108 329 | 007 012 027 032 047 052 067 072 087 092 107 330 | 006 013 026 033 046 053 066 073 086 093 106 331 | 005 014 025 034 045 054 065 074 085 094 105 332 | 004 015 024 035 044 055 064 075 084 095 104 333 | 003 016 023 036 043 056 063 076 083 096 103 334 | 002 017 022 037 042 057 062 077 082 097 102 335 | 001 018 021 038 041 058 061 078 081 098 101 336 | 000 019 020 039 040 059 060 079 080 099 100 337 | 113 114 338 | 339 | #define LED_LAYOUT_VERTICAL_3 Vertical and corner and alarm LEDs at the end of the strip. (As seen from the front.) 340 | 341 | 111 114 110 342 | 009 010 029 030 049 050 069 070 089 090 109 343 | 008 011 028 031 048 051 068 071 088 091 108 344 | 007 012 027 032 047 052 067 072 087 092 107 345 | 006 013 026 033 046 053 066 073 086 093 106 346 | 005 014 025 034 045 054 065 074 085 094 105 347 | 004 015 024 035 044 055 064 075 084 095 104 348 | 003 016 023 036 043 056 063 076 083 096 103 349 | 002 017 022 037 042 057 062 077 082 097 102 350 | 001 018 021 038 041 058 061 078 081 098 101 351 | 000 019 020 039 040 059 060 079 080 099 100 352 | 112 113 353 | 354 | ****************************************************************************** 355 | Configuration.h - Misc: 356 | ****************************************************************************** 357 | 358 | #define DEBUG Show debug infos in the serial console. 359 | #define DEBUG_WEB Show debug infos on the web page. 360 | #define DEBUG_MATRIX Renders the output of the matrix for the German front in the serial console. 361 | #define DEBUG_FPS Show number of loops per second in the serial console. 362 | 363 | #define SYSLOGSERVER Turn logging to a syslogserver on/off. 364 | #define SYSLOGSERVER_SERVER Address of the syslogserver. 365 | #define SYSLOGSERVER_PORT Port of the syslogserver. 366 | 367 | #define UPDATE_INFO_* The update info periodically anonymously checks if there is a firmwareupdate 368 | available. No user data is send to the host. Comment if you do not want this info. 369 | #define UPDATE_INFOSERVER Address of the updateinfo server. 370 | #define UPDATE_INFOFILE Path and name of the updateinfo file. 371 | 372 | #define SERIAL_SPEED Serial port speed for the console. 373 | 374 | ****************************************************************************** 375 | Events.h 376 | ****************************************************************************** 377 | 378 | event_t events[] Display a textfeed on a particular day of the year. 379 | The format of an entry in the array is: 380 | { month, day, "Text to display.", year, color }, 381 | The last entry has no comma at the end. 382 | Year will be used to calculate an age. "present year" - year = age. 383 | '0' will not show an age. 384 | There can only be one event a day. 385 | The possible colors are: 386 | WHITE, RED, RED_25, RED_50, ORANGE, YELLOW, YELLOW_25, YELLOW_50, GREENYELLOW, 387 | GREEN, GREEN_25, GREEN_50, MINTGREEN, CYAN, CYAN_25, CYAN_50, LIGHTBLUE, BLUE, 388 | BLUE_25, BLUE_50, VIOLET, MAGENTA, MAGENTA_25, MAGENTA_50, PINK. 389 | Do not change the first entry. 390 | 391 | ****************************************************************************** 392 | Web-API: 393 | ****************************************************************************** 394 | 395 | http://your_clocks_ip/commitSettings? 396 | a1=0 Alarm 1 on [1] or off [0] 397 | a1t=hh:mm Alarm 1 hour [hh] and minute [mm] 398 | a1w1=2 Set Sunday 399 | a1w2=4 Set Monday 400 | a1w3=8 Set Tuesday 401 | a1w4=16 Set Wednesday 402 | a1w5=32 Set Thursday 403 | a1w6=64 Set Friday 404 | a1w7=128 Set Saturday 405 | a2=0 Alarm 2 on [1] or off [0] 406 | a2t=hh:mm Alarm 2 hour [hh] and minute [mm] 407 | a2w1=2 Set Sunday 408 | a2w2=4 Set Monday 409 | a2w3=8 Set Tuesday 410 | a2w4=16 Set Wednesday 411 | a2w5=32 Set Thursday 412 | a2w6=64 Set Friday 413 | a2w7=128 Set Saturday 414 | hb=0 Hourly beep on [1] or off [0] 415 | ti=0 Timer in minutes 416 | mc=0 Modechange on [1] or off [0] 417 | ab=1 ABC on [1] or off [0] 418 | br=50 Brightness in percent 419 | co=14 Number of the LEDs color. See Colors.h 420 | cc=0 Number of colorchange. See Colors.h 421 | tr=1 Number of transition. See Modes.h 422 | to=15 Timeout in seconds 423 | no=hh:mm Night off hour [hh] and minute [mm] 424 | do=hh:mm Day on hour [hh] and minute [mm] 425 | ii=1 "It is" on [1] or off [0] 426 | st=YYYY-MM-DDThh:mm Set time and date 427 | 428 | http://your_clocks_ip/setEvent? 429 | day=dd Set day of event 430 | month=mm Set month of event 431 | color=0 Color of the eventtext, 0 to 24 (optional) 432 | text=text Set text of event, max. 40 characters 433 | e.g.: http://192.168.1.10/setEvent?day=27&month=10&color=5&text=This%20is%20an%20event. 434 | 435 | http://your_clocks_ip/showText? 436 | buzzer=1 Number of times the buzzer will beep before showing the text (optional) 437 | color=0 Color of the textfeed, 0 to 24 (optional) 438 | text=text Set text of feed, max. 80 characters 439 | e.g.: http://192.168.1.10/showText?buzzer=2&color=1&text=Instant%20text%20on%20Qlockwork! 440 | 441 | http://your_clocks_ip/control? 442 | mode=0 Set clock to mode=0 (time), mode=1 (am/pm), ... 443 | mode=17 (off, if all other modes are enabled) -- see modes.h and count. 444 | e.g.: http://192.168.1.10/control?mode=6 445 | 446 | ****************************************************************************** 447 | Changelog: 448 | ****************************************************************************** 449 | 20240908: 450 | Switch to MeteoWeather API for weather and sunrise/sunset information (API Key no longer required, regestration for API no longer needed). 451 | Beatification of debug output and webcontrol page for sunrise/sunset. 452 | Fixed transitions. 453 | 454 | 20220830: 455 | Fixed the issue that adaptive brightness control (ABC) can not be disabled in settings. 456 | 457 | 20220429: 458 | Moved the web-site from "tmw-it.ch" to "thorsten-wahl.ch" 459 | The UPDATE_INFOSERVER also moved there. Please update your Configuration.h 460 | 461 | 20220411: 462 | Fixed a bug causing the project not to compile in a certain configuration. 463 | 464 | 465 | 20220312: 466 | Clocks brightness from LDR is now transitioning smoothly between values. 467 | Sunrise and sunset now uses global timeout to switch back to time. 468 | Fixed a bug causing the RTC not to work. 469 | Added option to select RBG or RGBW for LedDriver. 470 | Using transition "Move up" in menus. "Fade" was not working too well. 471 | 472 | 20220311: 473 | Fixed a bug preventing compilation using esp8266 by ESP8266 Community (3.0.2). 474 | IDE change from VisualMicro to free Visual Studio Code. 475 | 476 | 20220310: 477 | Mode sunrise and sunset (Thanks to GenosseFlosse). 478 | 479 | 20210422: 480 | Reduced the watchdog resets (Thanks to espuno). 481 | 482 | 20210321: 483 | Fixed openweather bug for more than one weathercondition (Thanks to Manfred). 484 | Setting RTC vom Web should be LT - not UTC (Thanks to Manfred). 485 | Clear all LEDs before exiting test pattern (Thanks to espuno). 486 | Calculate white channel for NEO_WRGB (Thanks to Manfred). 487 | New LED_LAYOUT_VERTICAL_3 (Like vertical 2 but alarm LED = 114). 488 | 489 | 20210224: 490 | WLAN RSSI on WEB page in Debug. 491 | // -30 dBm Ausgezeichnet Dies ist die maximal erreichbare und für jedes Einsatzszenario geeignete Signalstärke. 492 | // -50 dBm Ausgezeichnet Dieser ausgezeichnete Signalpegel ist für alle Netzwerkanwendungen geeignet. 493 | // -65 dBm Sehr gut Empfohlen für die Unterstützung von Smartphones und Tablets. 494 | // -67 dBm Sehr gut Diese Signalstärke reicht für Voice-over-IP und Video-Streaming aus. 495 | // -70 dBm Akzeptabel Diese Stufe ist die minimale Signalstärke um eine zuverlässige Paket-Zustellung zu gewährleisten. 496 | // -80 dBm Schlecht Ermöglicht grundlegende Konnektivität, die Paket-Zustellung ist jedoch unzuverlässig. 497 | // -90 dBm Sehr schlecht Meistens Rauschen, das die meisten Funktionen behindert. 498 | //-100 dBm Am schlechtesten Nur Rauschen. 499 | 500 | 20210218: 501 | Outdoor pressure on WEB page. 502 | Replaced WEB page title HOSTNAME with WEBSITE_TITLE in configuration (Thanks to GenosseFlosse). 503 | 504 | 20200709: 505 | Turn off timer when it is running. 506 | Some localization in settings and weather. 507 | Fixed alarm running 4 times longer than configured. 508 | Set Hostname (Thanks to toto79). 509 | Fixes to Buttons for esp8266 2.7.x (Thanks to toto79). 510 | Fixes to WiFiManager for esp8266 2.7.x (Thanks to toto79). 511 | 512 | 20200112: 513 | WEB API for Clock On/Off. 514 | 515 | 20200107: 516 | Bugfixes. 517 | 518 | 20200101: 519 | Outdoor weather from OpenWeatherMap. 520 | New LED driver with LED array mapping. 521 | Reworked Configuration.h 522 | Switched to lean Arduino_Json.h 523 | 524 | 20191212: 525 | Some housekeeping. 526 | 527 | 20190520: 528 | #define WIFI_BEEPS 529 | Fixed rare flickering in fade transition. 530 | 531 | 20190204: 532 | Maior update of "Readme.txt" 533 | 534 | 20190106: 535 | Removed Yahoo weather. 536 | 537 | 20190105: 538 | Bugfix negative outdoorTemperature. 539 | Bugfix outdoorCode not available. 540 | 541 | 20181213: 542 | No hourly beep if clock is off. 543 | Some small improvements. 544 | 545 | 20181101: 546 | Settings set to defaults! 547 | Hourly beep. 548 | Set color of textfeed from URL. 549 | Set color of events[0].text from URL. 550 | Code cleanup and some minor bugfixes. 551 | 552 | 20181027: 553 | Show textfeed from URL. 554 | 555 | 20181021: 556 | Set events[0] from URL. 557 | Name is back to Qlockwork (from Qlockwork2). 558 | 559 | 20180930: 560 | Use esp8266 by ESP8266 Community Version 2.4.2 561 | Updated included libraries. 562 | Removed legacy support for LPD8806RGBW. 563 | Hardwareflags in debuginfo on webpage. 564 | If NTP-request fails, try again every minute - don't wait for an hour. 565 | More housekeeping. 566 | 567 | 20180929: 568 | Cleaned up libraries. 569 | 570 | 20180130: 571 | Transition "Move up" 572 | Rewrote some code. 573 | Removed FastLED. 574 | FRONTCOVER_BINARY 575 | 576 | 20180120: 577 | Hardware mode-, on/off- and timebutton. 578 | Moved PIN_IR_RECEIVER from D3 to D0. 579 | Tooltips for webbuttons. 580 | Added description of the Web-API in Readme.txt 581 | Cleanup and bugfixes. 582 | 583 | 20171127: 584 | Bugfixes. 585 | 586 | 20171125: 587 | Set weekdays for alarms on web-page. 588 | Set alarm to "on" if alarmtime is changed. 589 | Set time, timeout, "Night off", "Day on" on web-page. 590 | Removed settings from clock-menu which are present on web-page. 591 | AP mode if no WLAN is connected. 592 | "#define DEBUG" and "#define DEBUG_WEB" are back. 593 | Switched from RestClient.h to ArduinoHttpClient.h 594 | Moved setting of frontcover to configuration.h "#define FRONTCOVER_*" 595 | Removed "#define LANGUAGE_*". Now set from "#define FRONTCOVER_*" 596 | Removed experimantal DUAL-support. 597 | Settings set to defaults. 598 | 599 | 20171111 (stable): 600 | Cleanup and bugfixes. 601 | New syslog format. 602 | 603 | 20171019: 604 | Changing automode. 605 | Bugfix for Firefox. 606 | 607 | 20171013: 608 | Settings of alarms, colorchange, automode and show "It is" on Web-Page. 609 | RTC is now on UTC. 610 | 611 | 20171006: 612 | Moonphase. 613 | Color humidity indicator. 614 | Faster Web-GUI. 615 | Better offline behavior. 616 | Reset via URL. 617 | 618 | 20170929: 619 | Adaptive Brightness Control (ABC). 620 | New syslog logging. 621 | Code cleanup and bugfixes. 622 | 623 | 20170312: 624 | Inital release. 625 | -------------------------------------------------------------------------------- /Renderer.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // Renderer.h 3 | //***************************************************************************** 4 | 5 | #ifndef RENDERER_H 6 | #define RENDERER_H 7 | 8 | #include 9 | #include "Configuration.h" 10 | #include "Languages.h" 11 | #include "Letters.h" 12 | #include "Numbers.h" 13 | #include "Words.h" 14 | 15 | enum eTextPos : uint8_t { 16 | TEXT_POS_TOP, 17 | TEXT_POS_MIDDLE = 2, 18 | TEXT_POS_BOTTOM = 5 19 | }; 20 | 21 | class Renderer { 22 | 23 | public: 24 | Renderer(); 25 | 26 | void setHours(uint8_t hours, boolean glatt, uint16_t matrix[]); 27 | void setTime(uint8_t hours, uint8_t minutes, uint16_t matrix[]); 28 | void setCorners(uint8_t minutes, uint16_t matrix[]); 29 | void setAlarmLed(uint16_t matrix[]); 30 | void deactivateAlarmLed(uint16_t matrix[]); 31 | void clearEntryWords(uint16_t matrix[]); 32 | void setSmallText(String menuText, eTextPos textPos, uint16_t matrix[]); 33 | void setAMPM(uint8_t hours, uint16_t matrix[]); 34 | void setPixelInScreenBuffer(uint8_t x, uint8_t y, uint16_t matrix[]); 35 | void unsetPixelInScreenBuffer(uint8_t x, uint8_t y, uint16_t matrix[]); 36 | void clearScreenBuffer(uint16_t matrix[]); 37 | void setAllScreenBuffer(uint16_t matrix[]); 38 | 39 | private: 40 | boolean isNumber(char symbol); 41 | #if defined(FRONTCOVER_FR) 42 | void FR_hours(uint8_t hours, uint16_t matrix[]); 43 | #endif 44 | #if defined(FRONTCOVER_IT) 45 | void IT_hours(uint8_t hours, uint16_t matrix[]); 46 | #endif 47 | #if defined(FRONTCOVER_ES) 48 | void ES_hours(uint8_t hours, uint16_t matrix[]); 49 | #endif 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Settings.cpp: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // Settings.cpp 3 | //***************************************************************************** 4 | 5 | #include "Settings.h" 6 | 7 | Settings::Settings() { 8 | loadFromEEPROM(); 9 | } 10 | 11 | Settings::~Settings() { 12 | } 13 | 14 | // Set all defaults 15 | void Settings::resetToDefault() { 16 | mySettings.magicNumber = SETTINGS_MAGIC_NUMBER; 17 | mySettings.version = SETTINGS_VERSION; 18 | mySettings.useAbc = false; 19 | mySettings.brightness = 50; 20 | mySettings.color = WHITE; 21 | mySettings.colorChange = COLORCHANGE_NO; 22 | mySettings.transition = TRANSITION_FADE; 23 | mySettings.timeout = 10; 24 | mySettings.modeChange = false; 25 | mySettings.itIs = true; 26 | mySettings.alarm1 = false; 27 | mySettings.alarm1Time = 0; 28 | mySettings.alarm1Weekdays = 0b11111110; 29 | mySettings.alarm2 = false; 30 | mySettings.alarm2Time = 0; 31 | mySettings.alarm2Weekdays = 0b11111110; 32 | mySettings.nightOffTime = 3600; 33 | mySettings.dayOnTime = 18000; 34 | mySettings.hourBeep = false; 35 | 36 | saveToEEPROM(); 37 | } 38 | 39 | // Load settings from EEPROM 40 | void Settings::loadFromEEPROM() { 41 | EEPROM.begin(512); 42 | EEPROM.get(0, mySettings); 43 | if ((mySettings.magicNumber != SETTINGS_MAGIC_NUMBER) || (mySettings.version != SETTINGS_VERSION)) 44 | resetToDefault(); 45 | EEPROM.end(); 46 | } 47 | 48 | // Write settings to EEPROM 49 | void Settings::saveToEEPROM() { 50 | Serial.println("Settings saved to EEPROM."); 51 | EEPROM.begin(512); 52 | EEPROM.put(0, mySettings); 53 | //EEPROM.commit(); 54 | EEPROM.end(); 55 | } 56 | -------------------------------------------------------------------------------- /Settings.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // Settings.h 3 | //***************************************************************************** 4 | 5 | #ifndef SETTINGS_H 6 | #define SETTINGS_H 7 | 8 | #include 9 | #include 10 | #include "Colors.h" 11 | #include "Configuration.h" 12 | #include "Languages.h" 13 | #include "Modes.h" 14 | 15 | #define SETTINGS_MAGIC_NUMBER 0x2A 16 | #define SETTINGS_VERSION 25 17 | 18 | class Settings { 19 | public: 20 | Settings(); 21 | ~Settings(); 22 | 23 | struct MySettings { 24 | uint8_t magicNumber; 25 | uint8_t version; 26 | boolean useAbc; 27 | int16_t brightness; 28 | uint8_t color; 29 | uint8_t colorChange; 30 | uint8_t transition; 31 | uint8_t timeout; 32 | boolean modeChange; 33 | boolean itIs; 34 | boolean alarm1; 35 | time_t alarm1Time; 36 | uint8_t alarm1Weekdays; 37 | boolean alarm2; 38 | time_t alarm2Time; 39 | uint8_t alarm2Weekdays; 40 | time_t nightOffTime; 41 | time_t dayOnTime; 42 | boolean hourBeep; 43 | } mySettings; 44 | 45 | void saveToEEPROM(); 46 | 47 | private: 48 | void resetToDefault(); 49 | void loadFromEEPROM(); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Syslog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Syslog.h" 6 | 7 | // Public Methods ////////////////////////////////////////////////////////////// 8 | 9 | Syslog::Syslog(UDP &client, uint8_t protocol) { 10 | this->_client = &client; 11 | this->_protocol = protocol; 12 | this->_server = NULL; 13 | this->_port = 0; 14 | this->_deviceHostname = SYSLOG_NILVALUE; 15 | this->_appName = SYSLOG_NILVALUE; 16 | this->_priDefault = LOG_KERN; 17 | } 18 | 19 | Syslog::Syslog(UDP &client, const char* server, uint16_t port, const char* deviceHostname, const char* appName, uint16_t priDefault, uint8_t protocol) { 20 | this->_client = &client; 21 | this->_protocol = protocol; 22 | this->_server = server; 23 | this->_port = port; 24 | this->_deviceHostname = (deviceHostname == NULL) ? SYSLOG_NILVALUE : deviceHostname; 25 | this->_appName = (appName == NULL) ? SYSLOG_NILVALUE : appName; 26 | this->_priDefault = priDefault; 27 | } 28 | 29 | Syslog::Syslog(UDP &client, IPAddress ip, uint16_t port, const char* deviceHostname, const char* appName, uint16_t priDefault, uint8_t protocol) { 30 | this->_client = &client; 31 | this->_protocol = protocol; 32 | this->_ip = ip; 33 | this->_server = NULL; 34 | this->_port = port; 35 | this->_deviceHostname = (deviceHostname == NULL) ? SYSLOG_NILVALUE : deviceHostname; 36 | this->_appName = (appName == NULL) ? SYSLOG_NILVALUE : appName; 37 | this->_priDefault = priDefault; 38 | } 39 | 40 | Syslog &Syslog::server(const char* server, uint16_t port) { 41 | this->_server = server; 42 | this->_port = port; 43 | return *this; 44 | } 45 | 46 | Syslog &Syslog::server(IPAddress ip, uint16_t port) { 47 | this->_ip = ip; 48 | this->_server = NULL; 49 | this->_port = port; 50 | return *this; 51 | } 52 | 53 | Syslog &Syslog::deviceHostname(const char* deviceHostname) { 54 | this->_deviceHostname = (deviceHostname == NULL) ? SYSLOG_NILVALUE : deviceHostname; 55 | return *this; 56 | } 57 | 58 | Syslog &Syslog::appName(const char* appName) { 59 | this->_appName = (appName == NULL) ? SYSLOG_NILVALUE : appName; 60 | return *this; 61 | } 62 | 63 | Syslog &Syslog::defaultPriority(uint16_t pri) { 64 | this->_priDefault = pri; 65 | return *this; 66 | } 67 | 68 | Syslog &Syslog::logMask(uint8_t priMask) { 69 | this->_priMask = priMask; 70 | return *this; 71 | } 72 | 73 | 74 | bool Syslog::log(uint16_t pri, const __FlashStringHelper *message) { 75 | return this->_sendLog(pri, message); 76 | } 77 | 78 | bool Syslog::log(uint16_t pri, const String &message) { 79 | return this->_sendLog(pri, message.c_str()); 80 | } 81 | 82 | bool Syslog::log(uint16_t pri, const char *message) { 83 | return this->_sendLog(pri, message); 84 | } 85 | 86 | 87 | bool Syslog::vlogf(uint16_t pri, const char *fmt, va_list args) { 88 | char *message; 89 | size_t initialLen; 90 | size_t len; 91 | bool result; 92 | 93 | initialLen = strlen(fmt); 94 | 95 | message = new char[initialLen + 1]; 96 | 97 | len = vsnprintf(message, initialLen + 1, fmt, args); 98 | if (len > initialLen) { 99 | delete[] message; 100 | message = new char[len + 1]; 101 | 102 | vsnprintf(message, len + 1, fmt, args); 103 | } 104 | 105 | result = this->_sendLog(pri, message); 106 | 107 | delete[] message; 108 | return result; 109 | } 110 | 111 | bool Syslog::vlogf_P(uint16_t pri, PGM_P fmt_P, va_list args) { 112 | char *message; 113 | size_t initialLen; 114 | size_t len; 115 | bool result; 116 | 117 | initialLen = strlen_P(fmt_P); 118 | 119 | message = new char[initialLen + 1]; 120 | 121 | len = vsnprintf_P(message, initialLen + 1, fmt_P, args); 122 | if (len > initialLen) { 123 | delete[] message; 124 | message = new char[len + 1]; 125 | 126 | vsnprintf(message, len + 1, fmt_P, args); 127 | } 128 | 129 | result = this->_sendLog(pri, message); 130 | 131 | delete[] message; 132 | return result; 133 | } 134 | 135 | 136 | bool Syslog::logf(uint16_t pri, const char *fmt, ...) { 137 | va_list args; 138 | bool result; 139 | 140 | va_start(args, fmt); 141 | result = this->vlogf(pri, fmt, args); 142 | va_end(args); 143 | return result; 144 | } 145 | 146 | bool Syslog::logf(const char *fmt, ...) { 147 | va_list args; 148 | bool result; 149 | 150 | va_start(args, fmt); 151 | result = this->vlogf(this->_priDefault, fmt, args); 152 | va_end(args); 153 | return result; 154 | } 155 | 156 | bool Syslog::logf_P(uint16_t pri, PGM_P fmt_P, ...) { 157 | va_list args; 158 | bool result; 159 | 160 | va_start(args, fmt_P); 161 | result = this->vlogf_P(pri, fmt_P, args); 162 | va_end(args); 163 | return result; 164 | } 165 | 166 | bool Syslog::logf_P(PGM_P fmt_P, ...) { 167 | va_list args; 168 | bool result; 169 | 170 | va_start(args, fmt_P); 171 | result = this->vlogf_P(this->_priDefault, fmt_P, args); 172 | va_end(args); 173 | return result; 174 | } 175 | 176 | bool Syslog::log(const __FlashStringHelper *message) { 177 | return this->_sendLog(this->_priDefault, message); 178 | } 179 | 180 | bool Syslog::log(const String &message) { 181 | return this->_sendLog(this->_priDefault, message.c_str()); 182 | } 183 | 184 | bool Syslog::log(const char *message) { 185 | return this->_sendLog(this->_priDefault, message); 186 | } 187 | 188 | // Private Methods ///////////////////////////////////////////////////////////// 189 | 190 | inline bool Syslog::_sendLog(uint16_t pri, const char *message) { 191 | int result; 192 | 193 | if ((this->_server == NULL && this->_ip == INADDR_NONE) || this->_port == 0) 194 | return false; 195 | 196 | // Check priority against priMask values. 197 | if ((LOG_MASK(LOG_PRI(pri)) & this->_priMask) == 0) 198 | return true; 199 | 200 | // Set default facility if none specified. 201 | if ((pri & LOG_FACMASK) == 0) 202 | pri = LOG_MAKEPRI(LOG_FAC(this->_priDefault), pri); 203 | 204 | if (this->_server != NULL) { 205 | result = this->_client->beginPacket(this->_server, this->_port); 206 | } else { 207 | result = this->_client->beginPacket(this->_ip, this->_port); 208 | } 209 | 210 | if (result != 1) 211 | return false; 212 | 213 | // IETF Doc: https://tools.ietf.org/html/rfc5424 214 | // BSD Doc: https://tools.ietf.org/html/rfc3164 215 | this->_client->print('<'); 216 | this->_client->print(pri); 217 | if (this->_protocol == SYSLOG_PROTO_IETF) { 218 | this->_client->print(F(">1 - ")); 219 | } else { 220 | this->_client->print(F(">")); 221 | } 222 | this->_client->print(this->_deviceHostname); 223 | this->_client->print(' '); 224 | this->_client->print(this->_appName); 225 | if (this->_protocol == SYSLOG_PROTO_IETF) { 226 | this->_client->print(F(" - - - \xEF\xBB\xBF")); 227 | } else { 228 | this->_client->print(F("[0]: ")); 229 | } 230 | this->_client->print(message); 231 | this->_client->endPacket(); 232 | 233 | return true; 234 | } 235 | 236 | inline bool Syslog::_sendLog(uint16_t pri, const __FlashStringHelper *message) { 237 | int result; 238 | 239 | if ((this->_server == NULL && this->_ip == INADDR_NONE) || this->_port == 0) 240 | return false; 241 | 242 | // Check priority against priMask values. 243 | if ((LOG_MASK(LOG_PRI(pri)) & this->_priMask) == 0) 244 | return true; 245 | 246 | // Set default facility if none specified. 247 | if ((pri & LOG_FACMASK) == 0) 248 | pri = LOG_MAKEPRI(LOG_FAC(this->_priDefault), pri); 249 | 250 | if (this->_server != NULL) { 251 | result = this->_client->beginPacket(this->_server, this->_port); 252 | } else { 253 | result = this->_client->beginPacket(this->_ip, this->_port); 254 | } 255 | 256 | if (result != 1) 257 | return false; 258 | 259 | // IETF Doc: https://tools.ietf.org/html/rfc5424 260 | // BSD Doc: https://tools.ietf.org/html/rfc3164 261 | this->_client->print('<'); 262 | this->_client->print(pri); 263 | if (this->_protocol == SYSLOG_PROTO_IETF) { 264 | this->_client->print(F(">1 - ")); 265 | } else { 266 | this->_client->print(F(">")); 267 | } 268 | this->_client->print(this->_deviceHostname); 269 | this->_client->print(' '); 270 | this->_client->print(this->_appName); 271 | if (this->_protocol == SYSLOG_PROTO_IETF) { 272 | this->_client->print(F(" - - - \xEF\xBB\xBF")); 273 | } else { 274 | this->_client->print(F("[0]: ")); 275 | } 276 | this->_client->print(message); 277 | this->_client->endPacket(); 278 | 279 | 280 | return true; 281 | } 282 | -------------------------------------------------------------------------------- /Syslog.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSLOG_H 2 | #define SYSLOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // undefine ugly logf macro from avr's math.h 11 | // this fix compilation errors on AtmelAVR platforms 12 | #if defined(logf) 13 | #undef logf 14 | #endif 15 | 16 | // compatibility with other platforms 17 | // add missing vsnprintf_P method 18 | #if !defined(ARDUINO_ARCH_AVR) && !defined(ARDUINO_ARCH_ESP8266) && !defined(vsnprintf_P) && !defined(ESP8266) 19 | #define vsnprintf_P(buf, len, fmt, args) vsnprintf((buf), (len), (fmt), (args)) 20 | #endif 21 | 22 | #define SYSLOG_NILVALUE "-" 23 | 24 | // Syslog protocol format 25 | #define SYSLOG_PROTO_IETF 0 // RFC 5424 26 | #define SYSLOG_PROTO_BSD 1 // RFC 3164 27 | 28 | /* 29 | * priorities/facilities are encoded into a single 32-bit quantity, where the 30 | * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility 31 | * (0-big number). Both the priorities and the facilities map roughly 32 | * one-to-one to strings in the syslogd(8) source code. This mapping is 33 | * included in this file. 34 | * 35 | * priorities (these are ordered) 36 | */ 37 | #define LOG_EMERG 0 /* system is unusable */ 38 | #define LOG_ALERT 1 /* action must be taken immediately */ 39 | #define LOG_CRIT 2 /* critical conditions */ 40 | #define LOG_ERR 3 /* error conditions */ 41 | #define LOG_WARNING 4 /* warning conditions */ 42 | #define LOG_NOTICE 5 /* normal but significant condition */ 43 | #define LOG_INFO 6 /* informational */ 44 | #define LOG_DEBUG 7 /* debug-level messages */ 45 | 46 | #define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ 47 | /* extract priority */ 48 | #define LOG_PRI(p) ((p) & LOG_PRIMASK) 49 | #define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) 50 | 51 | /* facility codes */ 52 | #define LOG_KERN (0<<3) /* kernel messages */ 53 | #define LOG_USER (1<<3) /* random user-level messages */ 54 | #define LOG_MAIL (2<<3) /* mail system */ 55 | #define LOG_DAEMON (3<<3) /* system daemons */ 56 | #define LOG_AUTH (4<<3) /* security/authorization messages */ 57 | #define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ 58 | #define LOG_LPR (6<<3) /* line printer subsystem */ 59 | #define LOG_NEWS (7<<3) /* network news subsystem */ 60 | #define LOG_UUCP (8<<3) /* UUCP subsystem */ 61 | #define LOG_CRON (9<<3) /* clock daemon */ 62 | #define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ 63 | #define LOG_FTP (11<<3) /* ftp daemon */ 64 | 65 | /* other codes through 15 reserved for system use */ 66 | #define LOG_LOCAL0 (16<<3) /* reserved for local use */ 67 | #define LOG_LOCAL1 (17<<3) /* reserved for local use */ 68 | #define LOG_LOCAL2 (18<<3) /* reserved for local use */ 69 | #define LOG_LOCAL3 (19<<3) /* reserved for local use */ 70 | #define LOG_LOCAL4 (20<<3) /* reserved for local use */ 71 | #define LOG_LOCAL5 (21<<3) /* reserved for local use */ 72 | #define LOG_LOCAL6 (22<<3) /* reserved for local use */ 73 | #define LOG_LOCAL7 (23<<3) /* reserved for local use */ 74 | 75 | #define LOG_NFACILITIES 24 /* current number of facilities */ 76 | #define LOG_FACMASK 0x03f8 /* mask to extract facility part */ 77 | /* facility of pri */ 78 | #define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) 79 | 80 | #define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */ 81 | #define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */ 82 | 83 | class Syslog { 84 | private: 85 | UDP* _client; 86 | uint8_t _protocol; 87 | IPAddress _ip; 88 | const char* _server; 89 | uint16_t _port; 90 | const char* _deviceHostname; 91 | const char* _appName; 92 | uint16_t _priDefault; 93 | uint8_t _priMask = 0xff; 94 | 95 | bool _sendLog(uint16_t pri, const char *message); 96 | bool _sendLog(uint16_t pri, const __FlashStringHelper *message); 97 | 98 | public: 99 | Syslog(UDP &client, uint8_t protocol = SYSLOG_PROTO_IETF); 100 | Syslog(UDP &client, const char* server, uint16_t port, const char* deviceHostname = SYSLOG_NILVALUE, const char* appName = SYSLOG_NILVALUE, uint16_t priDefault = LOG_KERN, uint8_t protocol = SYSLOG_PROTO_IETF); 101 | Syslog(UDP &client, IPAddress ip, uint16_t port, const char* deviceHostname = SYSLOG_NILVALUE, const char* appName = SYSLOG_NILVALUE, uint16_t priDefault = LOG_KERN, uint8_t protocol = SYSLOG_PROTO_IETF); 102 | 103 | Syslog &server(const char* server, uint16_t port); 104 | Syslog &server(IPAddress ip, uint16_t port); 105 | Syslog &deviceHostname(const char* deviceHostname); 106 | Syslog &appName(const char* appName); 107 | Syslog &defaultPriority(uint16_t pri = LOG_KERN); 108 | 109 | Syslog &logMask(uint8_t priMask); 110 | 111 | bool log(uint16_t pri, const __FlashStringHelper *message); 112 | bool log(uint16_t pri, const String &message); 113 | bool log(uint16_t pri, const char *message); 114 | 115 | bool vlogf(uint16_t pri, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); 116 | bool vlogf_P(uint16_t pri, PGM_P fmt_P, va_list args) __attribute__((format(printf, 3, 0))); 117 | 118 | bool logf(uint16_t pri, const char *fmt, ...) __attribute__((format(printf, 3, 4))); 119 | bool logf(const char *fmt, ...) __attribute__((format(printf, 2, 3))); 120 | 121 | bool logf_P(uint16_t pri, PGM_P fmt_P, ...) __attribute__((format(printf, 3, 4))); 122 | bool logf_P(PGM_P fmt_P, ...) __attribute__((format(printf, 2, 3))); 123 | 124 | bool log(const __FlashStringHelper *message); 125 | bool log(const String &message); 126 | bool log(const char *message); 127 | }; 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /Timezone.cpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------* 2 | * Arduino Timezone Library * 3 | * Jack Christensen Mar 2012 * 4 | * * 5 | * Arduino Timezone Library Copyright (C) 2018 by Jack Christensen and * 6 | * licensed under GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html * 7 | *----------------------------------------------------------------------*/ 8 | 9 | #include "Timezone.h" 10 | 11 | #ifdef __AVR__ 12 | #include 13 | #endif 14 | 15 | /*----------------------------------------------------------------------* 16 | * Create a Timezone object from the given time change rules. * 17 | *----------------------------------------------------------------------*/ 18 | Timezone::Timezone(TimeChangeRule dstStart, TimeChangeRule stdStart) 19 | : m_dst(dstStart), m_std(stdStart) 20 | { 21 | initTimeChanges(); 22 | } 23 | 24 | /*----------------------------------------------------------------------* 25 | * Create a Timezone object for a zone that does not observe * 26 | * daylight time. * 27 | *----------------------------------------------------------------------*/ 28 | Timezone::Timezone(TimeChangeRule stdTime) 29 | : m_dst(stdTime), m_std(stdTime) 30 | { 31 | initTimeChanges(); 32 | } 33 | 34 | #ifdef __AVR__ 35 | /*----------------------------------------------------------------------* 36 | * Create a Timezone object from time change rules stored in EEPROM * 37 | * at the given address. * 38 | *----------------------------------------------------------------------*/ 39 | Timezone::Timezone(int address) 40 | { 41 | readRules(address); 42 | } 43 | #endif 44 | 45 | /*----------------------------------------------------------------------* 46 | * Convert the given UTC time to local time, standard or * 47 | * daylight time, as appropriate. * 48 | *----------------------------------------------------------------------*/ 49 | time_t Timezone::toLocal(time_t utc) 50 | { 51 | // recalculate the time change points if needed 52 | if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc)); 53 | 54 | if (utcIsDST(utc)) 55 | return utc + m_dst.offset * SECS_PER_MIN; 56 | else 57 | return utc + m_std.offset * SECS_PER_MIN; 58 | } 59 | 60 | /*----------------------------------------------------------------------* 61 | * Convert the given UTC time to local time, standard or * 62 | * daylight time, as appropriate, and return a pointer to the time * 63 | * change rule used to do the conversion. The caller must take care * 64 | * not to alter this rule. * 65 | *----------------------------------------------------------------------*/ 66 | time_t Timezone::toLocal(time_t utc, TimeChangeRule **tcr) 67 | { 68 | // recalculate the time change points if needed 69 | if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc)); 70 | 71 | if (utcIsDST(utc)) { 72 | *tcr = &m_dst; 73 | return utc + m_dst.offset * SECS_PER_MIN; 74 | } 75 | else { 76 | *tcr = &m_std; 77 | return utc + m_std.offset * SECS_PER_MIN; 78 | } 79 | } 80 | 81 | /*----------------------------------------------------------------------* 82 | * Convert the given local time to UTC time. * 83 | * * 84 | * WARNING: * 85 | * This function is provided for completeness, but should seldom be * 86 | * needed and should be used sparingly and carefully. * 87 | * * 88 | * Ambiguous situations occur after the Standard-to-DST and the * 89 | * DST-to-Standard time transitions. When changing to DST, there is * 90 | * one hour of local time that does not exist, since the clock moves * 91 | * forward one hour. Similarly, when changing to standard time, there * 92 | * is one hour of local times that occur twice since the clock moves * 93 | * back one hour. * 94 | * * 95 | * This function does not test whether it is passed an erroneous time * 96 | * value during the Local -> DST transition that does not exist. * 97 | * If passed such a time, an incorrect UTC time value will be returned. * 98 | * * 99 | * If passed a local time value during the DST -> Local transition * 100 | * that occurs twice, it will be treated as the earlier time, i.e. * 101 | * the time that occurs before the transistion. * 102 | * * 103 | * Calling this function with local times during a transition interval * 104 | * should be avoided! * 105 | *----------------------------------------------------------------------*/ 106 | time_t Timezone::toUTC(time_t local) 107 | { 108 | // recalculate the time change points if needed 109 | if (year(local) != year(m_dstLoc)) calcTimeChanges(year(local)); 110 | 111 | if (locIsDST(local)) 112 | return local - m_dst.offset * SECS_PER_MIN; 113 | else 114 | return local - m_std.offset * SECS_PER_MIN; 115 | } 116 | 117 | /*----------------------------------------------------------------------* 118 | * Determine whether the given UTC time_t is within the DST interval * 119 | * or the Standard time interval. * 120 | *----------------------------------------------------------------------*/ 121 | bool Timezone::utcIsDST(time_t utc) 122 | { 123 | // recalculate the time change points if needed 124 | if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc)); 125 | 126 | if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz 127 | return false; 128 | else if (m_stdUTC > m_dstUTC) // northern hemisphere 129 | return (utc >= m_dstUTC && utc < m_stdUTC); 130 | else // southern hemisphere 131 | return !(utc >= m_stdUTC && utc < m_dstUTC); 132 | } 133 | 134 | /*----------------------------------------------------------------------* 135 | * Determine whether the given Local time_t is within the DST interval * 136 | * or the Standard time interval. * 137 | *----------------------------------------------------------------------*/ 138 | bool Timezone::locIsDST(time_t local) 139 | { 140 | // recalculate the time change points if needed 141 | if (year(local) != year(m_dstLoc)) calcTimeChanges(year(local)); 142 | 143 | if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz 144 | return false; 145 | else if (m_stdLoc > m_dstLoc) // northern hemisphere 146 | return (local >= m_dstLoc && local < m_stdLoc); 147 | else // southern hemisphere 148 | return !(local >= m_stdLoc && local < m_dstLoc); 149 | } 150 | 151 | /*----------------------------------------------------------------------* 152 | * Calculate the DST and standard time change points for the given * 153 | * given year as local and UTC time_t values. * 154 | *----------------------------------------------------------------------*/ 155 | void Timezone::calcTimeChanges(int yr) 156 | { 157 | m_dstLoc = toTime_t(m_dst, yr); 158 | m_stdLoc = toTime_t(m_std, yr); 159 | m_dstUTC = m_dstLoc - m_std.offset * SECS_PER_MIN; 160 | m_stdUTC = m_stdLoc - m_dst.offset * SECS_PER_MIN; 161 | } 162 | 163 | /*----------------------------------------------------------------------* 164 | * Initialize the DST and standard time change points. * 165 | *----------------------------------------------------------------------*/ 166 | void Timezone::initTimeChanges() 167 | { 168 | m_dstLoc = 0; 169 | m_stdLoc = 0; 170 | m_dstUTC = 0; 171 | m_stdUTC = 0; 172 | } 173 | 174 | /*----------------------------------------------------------------------* 175 | * Convert the given time change rule to a time_t value * 176 | * for the given year. * 177 | *----------------------------------------------------------------------*/ 178 | time_t Timezone::toTime_t(TimeChangeRule r, int yr) 179 | { 180 | uint8_t m = r.month; // temp copies of r.month and r.week 181 | uint8_t w = r.week; 182 | if (w == 0) // is this a "Last week" rule? 183 | { 184 | if (++m > 12) // yes, for "Last", go to the next month 185 | { 186 | m = 1; 187 | ++yr; 188 | } 189 | w = 1; // and treat as first week of next month, subtract 7 days later 190 | } 191 | 192 | // calculate first day of the month, or for "Last" rules, first day of the next month 193 | tmElements_t tm; 194 | tm.Hour = r.hour; 195 | tm.Minute = 0; 196 | tm.Second = 0; 197 | tm.Day = 1; 198 | tm.Month = m; 199 | tm.Year = yr - 1970; 200 | time_t t = makeTime(tm); 201 | 202 | // add offset from the first of the month to r.dow, and offset for the given week 203 | t += ( (r.dow - weekday(t) + 7) % 7 + (w - 1) * 7 ) * SECS_PER_DAY; 204 | // back up a week if this is a "Last" rule 205 | if (r.week == 0) t -= 7 * SECS_PER_DAY; 206 | return t; 207 | } 208 | 209 | /*----------------------------------------------------------------------* 210 | * Read or update the daylight and standard time rules from RAM. * 211 | *----------------------------------------------------------------------*/ 212 | void Timezone::setRules(TimeChangeRule dstStart, TimeChangeRule stdStart) 213 | { 214 | m_dst = dstStart; 215 | m_std = stdStart; 216 | initTimeChanges(); // force calcTimeChanges() at next conversion call 217 | } 218 | 219 | #ifdef __AVR__ 220 | /*----------------------------------------------------------------------* 221 | * Read the daylight and standard time rules from EEPROM at * 222 | * the given address. * 223 | *----------------------------------------------------------------------*/ 224 | void Timezone::readRules(int address) 225 | { 226 | eeprom_read_block((void *) &m_dst, (void *) address, sizeof(m_dst)); 227 | address += sizeof(m_dst); 228 | eeprom_read_block((void *) &m_std, (void *) address, sizeof(m_std)); 229 | initTimeChanges(); // force calcTimeChanges() at next conversion call 230 | } 231 | 232 | /*----------------------------------------------------------------------* 233 | * Write the daylight and standard time rules to EEPROM at * 234 | * the given address. * 235 | *----------------------------------------------------------------------*/ 236 | void Timezone::writeRules(int address) 237 | { 238 | eeprom_write_block((void *) &m_dst, (void *) address, sizeof(m_dst)); 239 | address += sizeof(m_dst); 240 | eeprom_write_block((void *) &m_std, (void *) address, sizeof(m_std)); 241 | } 242 | 243 | #endif 244 | -------------------------------------------------------------------------------- /Timezone.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------* 2 | * Arduino Timezone Library * 3 | * Jack Christensen Mar 2012 * 4 | * * 5 | * Arduino Timezone Library Copyright (C) 2018 by Jack Christensen and * 6 | * licensed under GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html * 7 | *----------------------------------------------------------------------*/ 8 | 9 | #ifndef TIMEZONE_H_INCLUDED 10 | #define TIMEZONE_H_INCLUDED 11 | #if ARDUINO >= 100 12 | #include 13 | #else 14 | #include 15 | #endif 16 | #include // https://github.com/PaulStoffregen/Time 17 | 18 | // convenient constants for TimeChangeRules 19 | enum week_t {Last, First, Second, Third, Fourth}; 20 | enum dow_t {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat}; 21 | enum month_t {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; 22 | 23 | // structure to describe rules for when daylight/summer time begins, 24 | // or when standard time begins. 25 | struct TimeChangeRule 26 | { 27 | char abbrev[6]; // five chars max 28 | uint8_t week; // First, Second, Third, Fourth, or Last week of the month 29 | uint8_t dow; // day of week, 1=Sun, 2=Mon, ... 7=Sat 30 | uint8_t month; // 1=Jan, 2=Feb, ... 12=Dec 31 | uint8_t hour; // 0-23 32 | int offset; // offset from UTC in minutes 33 | }; 34 | 35 | class Timezone 36 | { 37 | public: 38 | Timezone(TimeChangeRule dstStart, TimeChangeRule stdStart); 39 | Timezone(TimeChangeRule stdTime); 40 | Timezone(int address); 41 | time_t toLocal(time_t utc); 42 | time_t toLocal(time_t utc, TimeChangeRule **tcr); 43 | time_t toUTC(time_t local); 44 | bool utcIsDST(time_t utc); 45 | bool locIsDST(time_t local); 46 | void setRules(TimeChangeRule dstStart, TimeChangeRule stdStart); 47 | void readRules(int address); 48 | void writeRules(int address); 49 | 50 | private: 51 | void calcTimeChanges(int yr); 52 | void initTimeChanges(); 53 | time_t toTime_t(TimeChangeRule r, int yr); 54 | TimeChangeRule m_dst; // rule for start of dst or summer time for any year 55 | TimeChangeRule m_std; // rule for start of standard time for any year 56 | time_t m_dstUTC; // dst start for given/current year, given in UTC 57 | time_t m_stdUTC; // std time start for given/current year, given in UTC 58 | time_t m_dstLoc; // dst start for given/current year, given in local time 59 | time_t m_stdLoc; // std time start for given/current year, given in local time 60 | }; 61 | #endif 62 | -------------------------------------------------------------------------------- /Timezones.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Timezones.h 3 | ******************************************************************************/ 4 | 5 | #ifndef TIMEZONES_H 6 | #define TIMEZONES_H 7 | 8 | #ifdef TIMEZONE_IDLW 9 | TimeChangeRule IDLW = { "IDLW", First, Sun, Jan, 1, -720 }; 10 | Timezone timeZone(IDLW, IDLW); 11 | #endif 12 | 13 | #ifdef TIMEZONE_SST 14 | TimeChangeRule SST = { "SST", First, Sun, Jan, 1, -660 }; 15 | Timezone timeZone(SST, SST); 16 | #endif 17 | 18 | #ifdef TIMEZONE_HST 19 | TimeChangeRule HST = { "HST", First, Sun, Jan, 1, -600 }; 20 | Timezone timeZone(HST, HST); 21 | #endif 22 | 23 | #ifdef TIMEZONE_AKST 24 | TimeChangeRule usAKDT = { "AKDT", Second, Sun, Mar, 2, -480 }; 25 | TimeChangeRule usAKST = { "AKST", First, Sun, Nov, 2, -540 }; 26 | Timezone timeZone(usAKDT, usAKST); 27 | #endif 28 | 29 | #ifdef TIMEZONE_USPST 30 | TimeChangeRule usPDT = { "PDT", Second, Sun, Mar, 2, -420 }; 31 | TimeChangeRule usPST = { "PST", First, Sun, Nov, 2, -480 }; 32 | Timezone timeZone(usPDT, usPST); 33 | #endif 34 | 35 | #ifdef TIMEZONE_USMST 36 | TimeChangeRule usMDT = { "MDT", Second, Sun, Mar, 2, -360 }; 37 | TimeChangeRule usMST = { "MST", First, Sun, Nov, 2, -420 }; 38 | Timezone timeZone(usMDT, usMST); 39 | #endif 40 | 41 | #ifdef TIMEZONE_USAZ 42 | TimeChangeRule usMST = { "MST", First, Sun, Nov, 2, -420 }; 43 | Timezone timeZone(usMST, usMST); 44 | #endif 45 | 46 | #ifdef TIMEZONE_USCST 47 | TimeChangeRule usCDT = { "CDT", Second, Sun, Mar, 2, -300 }; 48 | TimeChangeRule usCST = { "CST", First, Sun, Nov, 2, -360 }; 49 | Timezone timeZone(usCDT, usCST); 50 | #endif 51 | 52 | #ifdef TIMEZONE_USEST 53 | TimeChangeRule usEDT = { "EDT", Second, Sun, Mar, 2, -240 }; 54 | TimeChangeRule usEST = { "EST", First, Sun, Nov, 2, -300 }; 55 | Timezone timeZone(usEDT, usEST); 56 | #endif 57 | 58 | #ifdef TIMEZONE_AST 59 | TimeChangeRule AST = { "AST", First, Sun, Jan, 1, -240 }; 60 | Timezone timeZone(AST, AST); 61 | #endif 62 | 63 | #ifdef TIMEZONE_BST 64 | TimeChangeRule BST = { "BST", First, Sun, Jan, 1, -180 }; 65 | Timezone timeZone(BST, BST); 66 | #endif 67 | 68 | #ifdef TIMEZONE_VTZ 69 | TimeChangeRule VTZ = { "VTZ", First, Sun, Jan, 1, -120 }; 70 | Timezone timeZone(VTZ, VTZ); 71 | #endif 72 | 73 | #ifdef TIMEZONE_AZOT 74 | TimeChangeRule AZOT = { "AZOT", First, Sun, Jan, 1, -60 }; 75 | Timezone timeZone(AZOT, AZOT); 76 | #endif 77 | 78 | #ifdef TIMEZONE_GMT 79 | TimeChangeRule BST = { "BST", Last, Sun, Mar, 1, 60 }; 80 | TimeChangeRule GMT = { "GMT", Last, Sun, Oct, 2, 0 }; 81 | Timezone timeZone(BST, GMT); 82 | #endif 83 | 84 | #ifdef TIMEZONE_CET 85 | TimeChangeRule CEST = { "CEST", Last, Sun, Mar, 2, 120 }; 86 | TimeChangeRule CET = { "CET", Last, Sun, Oct, 3, 60 }; 87 | Timezone timeZone(CEST, CET); 88 | #endif 89 | 90 | #ifdef TIMEZONE_EST 91 | TimeChangeRule EST = { "EST", First, Sun, Jan, 1, 120 }; 92 | Timezone timeZone(EST, EST); 93 | #endif 94 | 95 | #ifdef TIMEZONE_MSK 96 | TimeChangeRule MSK = { "MSK", First, Sun, Jan, 1, 180 }; 97 | Timezone timeZone(MSK, MSK); 98 | #endif 99 | 100 | #ifdef TIMEZONE_GST 101 | TimeChangeRule GST = { "GST", First, Sun, Jan, 1, 240 }; 102 | Timezone timeZone(GST, GST); 103 | #endif 104 | 105 | #ifdef TIMEZONE_PKT 106 | TimeChangeRule PKT = { "PKT", First, Sun, Jan, 1, 300 }; 107 | Timezone timeZone(PKT, PKT); 108 | #endif 109 | 110 | #ifdef TIMEZONE_BDT 111 | TimeChangeRule BDT = { "BDT", First, Sun, Jan, 1, 360 }; 112 | Timezone timeZone(BDT, BDT); 113 | #endif 114 | 115 | #ifdef TIMEZONE_JT 116 | TimeChangeRule JT = { "JT", First, Sun, Jan, 1, 420 }; 117 | Timezone timeZone(JT, JT); 118 | #endif 119 | 120 | #ifdef TIMEZONE_CNST 121 | TimeChangeRule CNST = { "CNST", First, Sun, Jan, 1, 480 }; 122 | Timezone timeZone(CNST, CNST); 123 | #endif 124 | 125 | #ifdef TIMEZONE_HKT 126 | TimeChangeRule HKT = { "HKT", First, Sun, Jan, 1, 480 }; 127 | Timezone timeZone(HKT, HKT); 128 | #endif 129 | 130 | #ifdef TIMEZONE_PYT 131 | TimeChangeRule PYT = { "PYT", First, Sun, Jan, 1, 510 }; 132 | Timezone timeZone(PYT, PYT); 133 | #endif 134 | 135 | #ifdef TIMEZONE_CWT 136 | TimeChangeRule CWT = { "CWT", First, Sun, Jan, 1, 525 }; 137 | Timezone timeZone(CWT, CWT); 138 | #endif 139 | 140 | #ifdef TIMEZONE_JST 141 | TimeChangeRule JST = { "JST", First, Sun, Jan, 1, 525 }; 142 | Timezone timeZone(JST, JST); 143 | #endif 144 | 145 | #ifdef TIMEZONE_ACST 146 | TimeChangeRule ACST = { "ACST", First, Sun, Jan, 1, 570 }; 147 | Timezone timeZone(ACST, ACST); 148 | #endif 149 | 150 | #ifdef TIMEZONE_AEST 151 | TimeChangeRule aEDT = { "AEDT", First, Sun, Oct, 2, 660 }; 152 | TimeChangeRule aEST = { "AEST", First, Sun, Apr, 3, 600 }; 153 | Timezone timeZone(aEDT, aEST); 154 | #endif 155 | 156 | #ifdef TIMEZONE_LHST 157 | TimeChangeRule LHST = { "LHST", First, Sun, Jan, 1, 630 }; 158 | Timezone timeZone(LHST, LHST); 159 | #endif 160 | 161 | #ifdef TIMEZONE_SBT 162 | TimeChangeRule SBT = { "SBT", First, Sun, Jan, 1, 660 }; 163 | Timezone timeZone(SBT, SBT); 164 | #endif 165 | 166 | #ifdef TIMEZONE_NZST 167 | TimeChangeRule NZST = { "NZST", First, Sun, Jan, 1, 720 }; 168 | Timezone timeZone(NZST, NZST); 169 | #endif 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /WiFiManager.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/master/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #include "WiFiManager.h" 14 | 15 | WiFiManagerParameter::WiFiManagerParameter(const char *custom) { 16 | _id = NULL; 17 | _placeholder = NULL; 18 | _length = 0; 19 | _value = NULL; 20 | 21 | _customHTML = custom; 22 | } 23 | 24 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length) { 25 | init(id, placeholder, defaultValue, length, ""); 26 | } 27 | 28 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 29 | init(id, placeholder, defaultValue, length, custom); 30 | } 31 | 32 | void WiFiManagerParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 33 | _id = id; 34 | _placeholder = placeholder; 35 | _length = length; 36 | _value = new char[length + 1]; 37 | for (int i = 0; i < length + 1; i++) { 38 | _value[i] = 0; 39 | } 40 | if (defaultValue != NULL) { 41 | strncpy(_value, defaultValue, length); 42 | } 43 | 44 | _customHTML = custom; 45 | } 46 | 47 | WiFiManagerParameter::~WiFiManagerParameter() { 48 | if (_value != NULL) { 49 | delete[] _value; 50 | } 51 | } 52 | 53 | const char* WiFiManagerParameter::getValue() { 54 | return _value; 55 | } 56 | const char* WiFiManagerParameter::getID() { 57 | return _id; 58 | } 59 | const char* WiFiManagerParameter::getPlaceholder() { 60 | return _placeholder; 61 | } 62 | int WiFiManagerParameter::getValueLength() { 63 | return _length; 64 | } 65 | const char* WiFiManagerParameter::getCustomHTML() { 66 | return _customHTML; 67 | } 68 | 69 | 70 | WiFiManager::WiFiManager() { 71 | _max_params = WIFI_MANAGER_MAX_PARAMS; 72 | _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*)); 73 | } 74 | 75 | WiFiManager::~WiFiManager() 76 | { 77 | if (_params != NULL) 78 | { 79 | DEBUG_WM(F("freeing allocated params!")); 80 | free(_params); 81 | } 82 | } 83 | 84 | bool WiFiManager::addParameter(WiFiManagerParameter *p) { 85 | if(_paramsCount + 1 > _max_params) 86 | { 87 | // rezise the params array 88 | _max_params += WIFI_MANAGER_MAX_PARAMS; 89 | DEBUG_WM(F("Increasing _max_params to:")); 90 | DEBUG_WM(_max_params); 91 | WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*)); 92 | if (new_params != NULL) { 93 | _params = new_params; 94 | } else { 95 | DEBUG_WM(F("ERROR: failed to realloc params, size not increased!")); 96 | return false; 97 | } 98 | } 99 | 100 | _params[_paramsCount] = p; 101 | _paramsCount++; 102 | DEBUG_WM(F("Adding parameter")); 103 | DEBUG_WM(p->getID()); 104 | return true; 105 | } 106 | 107 | void WiFiManager::setupConfigPortal() { 108 | dnsServer.reset(new DNSServer()); 109 | server.reset(new ESP8266WebServer(80)); 110 | 111 | DEBUG_WM(F("")); 112 | _configPortalStart = millis(); 113 | 114 | DEBUG_WM(F("Configuring access point... ")); 115 | DEBUG_WM(_apName); 116 | if (_apPassword != NULL) { 117 | if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) { 118 | // fail passphrase to short or long! 119 | DEBUG_WM(F("Invalid AccessPoint password. Ignoring")); 120 | _apPassword = NULL; 121 | } 122 | DEBUG_WM(_apPassword); 123 | } 124 | 125 | //optional soft ip config 126 | if (_ap_static_ip) { 127 | DEBUG_WM(F("Custom AP IP/GW/Subnet")); 128 | WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); 129 | } 130 | 131 | if (_apPassword != NULL) { 132 | WiFi.softAP(_apName, _apPassword);//password option 133 | } else { 134 | WiFi.softAP(_apName); 135 | } 136 | 137 | delay(500); // Without delay I've seen the IP address blank 138 | DEBUG_WM(F("AP IP address: ")); 139 | DEBUG_WM(WiFi.softAPIP()); 140 | 141 | /* Setup the DNS server redirecting all the domains to the apIP */ 142 | dnsServer->setErrorReplyCode(DNSReplyCode::NoError); 143 | dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); 144 | 145 | /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ 146 | server->on(String(F("/")).c_str(), std::bind(&WiFiManager::handleRoot, this)); 147 | server->on(String(F("/wifi")).c_str(), std::bind(&WiFiManager::handleWifi, this, true)); 148 | server->on(String(F("/0wifi")).c_str(), std::bind(&WiFiManager::handleWifi, this, false)); 149 | server->on(String(F("/wifisave")).c_str(), std::bind(&WiFiManager::handleWifiSave, this)); 150 | server->on(String(F("/i")).c_str(), std::bind(&WiFiManager::handleInfo, this)); 151 | server->on(String(F("/r")).c_str(), std::bind(&WiFiManager::handleReset, this)); 152 | //server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check. 153 | server->on(String(F("/fwlink")).c_str(), std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. 154 | server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); 155 | server->begin(); // Web server start 156 | DEBUG_WM(F("HTTP server started")); 157 | } 158 | 159 | boolean WiFiManager::autoConnect() { 160 | String ssid = "ESP" + String(ESP.getChipId()); 161 | return autoConnect(ssid.c_str(), NULL); 162 | } 163 | 164 | boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { 165 | DEBUG_WM(F("")); 166 | DEBUG_WM(F("AutoConnect")); 167 | 168 | // read eeprom for ssid and pass 169 | //String ssid = getSSID(); 170 | //String pass = getPassword(); 171 | 172 | // attempt to connect; should it fail, fall back to AP 173 | WiFi.mode(WIFI_STA); 174 | 175 | if (connectWifi("", "") == WL_CONNECTED) { 176 | DEBUG_WM(F("IP Address:")); 177 | DEBUG_WM(WiFi.localIP()); 178 | //connected 179 | return true; 180 | } 181 | 182 | return startConfigPortal(apName, apPassword); 183 | } 184 | 185 | boolean WiFiManager::configPortalHasTimeout(){ 186 | if(_configPortalTimeout == 0 || wifi_softap_get_station_num() > 0){ 187 | _configPortalStart = millis(); // kludge, bump configportal start time to skew timeouts 188 | return false; 189 | } 190 | return (millis() > _configPortalStart + _configPortalTimeout); 191 | } 192 | 193 | boolean WiFiManager::startConfigPortal() { 194 | String ssid = "ESP" + String(ESP.getChipId()); 195 | return startConfigPortal(ssid.c_str(), NULL); 196 | } 197 | 198 | boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { 199 | 200 | if(!WiFi.isConnected()){ 201 | WiFi.persistent(false); 202 | // disconnect sta, start ap 203 | WiFi.disconnect(); // this alone is not enough to stop the autoconnecter 204 | WiFi.mode(WIFI_AP); 205 | WiFi.persistent(true); 206 | } 207 | else { 208 | //setup AP 209 | WiFi.mode(WIFI_AP_STA); 210 | DEBUG_WM(F("SET AP STA")); 211 | } 212 | 213 | 214 | _apName = apName; 215 | _apPassword = apPassword; 216 | 217 | //notify we entered AP mode 218 | if ( _apcallback != NULL) { 219 | _apcallback(this); 220 | } 221 | 222 | connect = false; 223 | setupConfigPortal(); 224 | 225 | while(1){ 226 | 227 | // check if timeout 228 | if(configPortalHasTimeout()) break; 229 | 230 | //DNS 231 | dnsServer->processNextRequest(); 232 | //HTTP 233 | server->handleClient(); 234 | 235 | if (connect) { 236 | delay(1000); 237 | connect = false; 238 | 239 | // if saving with no ssid filled in, reconnect to ssid 240 | // will not exit cp 241 | if(_ssid == ""){ 242 | DEBUG_WM(F("No ssid, skipping wifi")); 243 | } 244 | else{ 245 | DEBUG_WM(F("Connecting to new AP")); 246 | if (connectWifi(_ssid, _pass) != WL_CONNECTED) { 247 | delay(2000); 248 | // using user-provided _ssid, _pass in place of system-stored ssid and pass 249 | DEBUG_WM(F("Failed to connect.")); 250 | } 251 | else { 252 | //connected 253 | WiFi.mode(WIFI_STA); 254 | //notify that configuration has changed and any optional parameters should be saved 255 | if ( _savecallback != NULL) { 256 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 257 | _savecallback(); 258 | } 259 | break; 260 | } 261 | } 262 | if (_shouldBreakAfterConfig) { 263 | //flag set to exit after config after trying to connect 264 | //notify that configuration has changed and any optional parameters should be saved 265 | if ( _savecallback != NULL) { 266 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 267 | _savecallback(); 268 | } 269 | WiFi.mode(WIFI_STA); // turn off ap 270 | // reconnect to ssid 271 | // int res = WiFi.begin(); 272 | // attempt connect for 10 seconds 273 | DEBUG_WM(F("Waiting for sta (10 secs) .......")); 274 | for(size_t i = 0 ; i<100;i++){ 275 | if(WiFi.status() == WL_CONNECTED) break; 276 | DEBUG_WM("."); 277 | // Serial.println(WiFi.status()); 278 | delay(100); 279 | } 280 | delay(1000); 281 | break; 282 | } 283 | } 284 | yield(); 285 | } 286 | 287 | server.reset(); 288 | dnsServer.reset(); 289 | 290 | return WiFi.status() == WL_CONNECTED; 291 | } 292 | 293 | 294 | int WiFiManager::connectWifi(String ssid, String pass) { 295 | DEBUG_WM(F("Connecting as wifi client...")); 296 | 297 | // check if we've got static_ip settings, if we do, use those. 298 | if (_sta_static_ip) { 299 | DEBUG_WM(F("Custom STA IP/GW/Subnet")); 300 | WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); 301 | DEBUG_WM(WiFi.localIP()); 302 | } 303 | //fix for auto connect racing issue 304 | if (WiFi.status() == WL_CONNECTED && (WiFi.SSID() == ssid)) { 305 | DEBUG_WM(F("Already connected. Bailing out.")); 306 | return WL_CONNECTED; 307 | } 308 | 309 | DEBUG_WM(F("Status:")); 310 | DEBUG_WM(WiFi.status()); 311 | 312 | wl_status_t res; 313 | //check if we have ssid and pass and force those, if not, try with last saved values 314 | if (ssid != "") { 315 | //trying to fix connection in progress hanging 316 | ETS_UART_INTR_DISABLE(); 317 | wifi_station_disconnect(); 318 | ETS_UART_INTR_ENABLE(); 319 | res = WiFi.begin(ssid.c_str(), pass.c_str(),0,NULL,true); 320 | if(res != WL_CONNECTED){ 321 | DEBUG_WM(F("[ERROR] WiFi.begin res:")); 322 | DEBUG_WM(res); 323 | } 324 | } else { 325 | if (WiFi.SSID() != "") { 326 | DEBUG_WM(F("Using last saved values, should be faster")); 327 | //trying to fix connection in progress hanging 328 | ETS_UART_INTR_DISABLE(); 329 | wifi_station_disconnect(); 330 | ETS_UART_INTR_ENABLE(); 331 | res = WiFi.begin(); 332 | } else { 333 | DEBUG_WM(F("No saved credentials")); 334 | } 335 | } 336 | 337 | int connRes = waitForConnectResult(); 338 | DEBUG_WM ("Connection result: "); 339 | DEBUG_WM ( connRes ); 340 | //not connected, WPS enabled, no pass - first attempt 341 | #ifdef NO_EXTRA_4K_HEAP 342 | if (_tryWPS && connRes != WL_CONNECTED && pass == "") { 343 | startWPS(); 344 | //should be connected at the end of WPS 345 | connRes = waitForConnectResult(); 346 | } 347 | #endif 348 | return connRes; 349 | } 350 | 351 | uint8_t WiFiManager::waitForConnectResult() { 352 | if (_connectTimeout == 0) { 353 | return WiFi.waitForConnectResult(); 354 | } else { 355 | DEBUG_WM (F("Waiting for connection result with time out")); 356 | unsigned long start = millis(); 357 | boolean keepConnecting = true; 358 | uint8_t status; 359 | while (keepConnecting) { 360 | status = WiFi.status(); 361 | if (millis() > start + _connectTimeout) { 362 | keepConnecting = false; 363 | DEBUG_WM (F("Connection timed out")); 364 | } 365 | if (status == WL_CONNECTED) { 366 | keepConnecting = false; 367 | } 368 | delay(100); 369 | } 370 | return status; 371 | } 372 | } 373 | 374 | void WiFiManager::startWPS() { 375 | DEBUG_WM(F("START WPS")); 376 | WiFi.beginWPSConfig(); 377 | DEBUG_WM(F("END WPS")); 378 | } 379 | /* 380 | String WiFiManager::getSSID() { 381 | if (_ssid == "") { 382 | DEBUG_WM(F("Reading SSID")); 383 | _ssid = WiFi.SSID(); 384 | DEBUG_WM(F("SSID: ")); 385 | DEBUG_WM(_ssid); 386 | } 387 | return _ssid; 388 | } 389 | String WiFiManager::getPassword() { 390 | if (_pass == "") { 391 | DEBUG_WM(F("Reading Password")); 392 | _pass = WiFi.psk(); 393 | DEBUG_WM("Password: " + _pass); 394 | //DEBUG_WM(_pass); 395 | } 396 | return _pass; 397 | } 398 | */ 399 | String WiFiManager::getConfigPortalSSID() { 400 | return _apName; 401 | } 402 | 403 | void WiFiManager::resetSettings() { 404 | DEBUG_WM(F("settings invalidated")); 405 | DEBUG_WM(F("THIS MAY CAUSE AP NOT TO START UP PROPERLY. YOU NEED TO COMMENT IT OUT AFTER ERASING THE DATA.")); 406 | WiFi.disconnect(true); 407 | //delay(200); 408 | } 409 | void WiFiManager::setTimeout(unsigned long seconds) { 410 | setConfigPortalTimeout(seconds); 411 | } 412 | 413 | void WiFiManager::setConfigPortalTimeout(unsigned long seconds) { 414 | _configPortalTimeout = seconds * 1000; 415 | } 416 | 417 | void WiFiManager::setConnectTimeout(unsigned long seconds) { 418 | _connectTimeout = seconds * 1000; 419 | } 420 | 421 | void WiFiManager::setDebugOutput(boolean debug) { 422 | _debug = debug; 423 | } 424 | 425 | void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 426 | _ap_static_ip = ip; 427 | _ap_static_gw = gw; 428 | _ap_static_sn = sn; 429 | } 430 | 431 | void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 432 | _sta_static_ip = ip; 433 | _sta_static_gw = gw; 434 | _sta_static_sn = sn; 435 | } 436 | 437 | void WiFiManager::setMinimumSignalQuality(int quality) { 438 | _minimumQuality = quality; 439 | } 440 | 441 | void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { 442 | _shouldBreakAfterConfig = shouldBreak; 443 | } 444 | 445 | /** Handle root or redirect to captive portal */ 446 | void WiFiManager::handleRoot() { 447 | DEBUG_WM(F("Handle root")); 448 | if (captivePortal()) { // If caprive portal redirect instead of displaying the page. 449 | return; 450 | } 451 | 452 | String page = FPSTR(HTTP_HEADER); 453 | page.replace("{v}", "Options"); 454 | page += FPSTR(HTTP_SCRIPT); 455 | page += FPSTR(HTTP_STYLE); 456 | page += _customHeadElement; 457 | page += FPSTR(HTTP_HEADER_END); 458 | page += String(F("

")); 459 | page += _apName; 460 | page += String(F("

")); 461 | page += String(F("

WiFiManager

")); 462 | page += FPSTR(HTTP_PORTAL_OPTIONS); 463 | page += FPSTR(HTTP_END); 464 | 465 | server->sendHeader("Content-Length", String(page.length())); 466 | server->send(200, "text/html", page); 467 | 468 | } 469 | 470 | /** Wifi config page handler */ 471 | void WiFiManager::handleWifi(boolean scan) { 472 | 473 | String page = FPSTR(HTTP_HEADER); 474 | page.replace("{v}", "Config ESP"); 475 | page += FPSTR(HTTP_SCRIPT); 476 | page += FPSTR(HTTP_STYLE); 477 | page += _customHeadElement; 478 | page += FPSTR(HTTP_HEADER_END); 479 | 480 | if (scan) { 481 | int n = WiFi.scanNetworks(); 482 | DEBUG_WM(F("Scan done")); 483 | if (n == 0) { 484 | DEBUG_WM(F("No networks found")); 485 | page += F("No networks found. Refresh to scan again."); 486 | } else { 487 | 488 | //sort networks 489 | int indices[n]; 490 | for (int i = 0; i < n; i++) { 491 | indices[i] = i; 492 | } 493 | 494 | // RSSI SORT 495 | 496 | // old sort 497 | for (int i = 0; i < n; i++) { 498 | for (int j = i + 1; j < n; j++) { 499 | if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { 500 | std::swap(indices[i], indices[j]); 501 | } 502 | } 503 | } 504 | 505 | /*std::sort(indices, indices + n, [](const int & a, const int & b) -> bool 506 | { 507 | return WiFi.RSSI(a) > WiFi.RSSI(b); 508 | });*/ 509 | 510 | // remove duplicates ( must be RSSI sorted ) 511 | if (_removeDuplicateAPs) { 512 | String cssid; 513 | for (int i = 0; i < n; i++) { 514 | if (indices[i] == -1) continue; 515 | cssid = WiFi.SSID(indices[i]); 516 | for (int j = i + 1; j < n; j++) { 517 | if (cssid == WiFi.SSID(indices[j])) { 518 | DEBUG_WM("DUP AP: " + WiFi.SSID(indices[j])); 519 | indices[j] = -1; // set dup aps to index -1 520 | } 521 | } 522 | } 523 | } 524 | 525 | //display networks in page 526 | for (int i = 0; i < n; i++) { 527 | if (indices[i] == -1) continue; // skip dups 528 | DEBUG_WM(WiFi.SSID(indices[i])); 529 | DEBUG_WM(WiFi.RSSI(indices[i])); 530 | int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); 531 | 532 | if (_minimumQuality == -1 || _minimumQuality < quality) { 533 | String item = FPSTR(HTTP_ITEM); 534 | String rssiQ; 535 | rssiQ += quality; 536 | item.replace("{v}", WiFi.SSID(indices[i])); 537 | item.replace("{r}", rssiQ); 538 | if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) { 539 | item.replace("{i}", "l"); 540 | } else { 541 | item.replace("{i}", ""); 542 | } 543 | //DEBUG_WM(item); 544 | page += item; 545 | delay(0); 546 | } else { 547 | DEBUG_WM(F("Skipping due to quality")); 548 | } 549 | 550 | } 551 | page += "
"; 552 | } 553 | } 554 | 555 | page += FPSTR(HTTP_FORM_START); 556 | char parLength[5]; 557 | // add the extra parameters to the form 558 | for (int i = 0; i < _paramsCount; i++) { 559 | if (_params[i] == NULL) { 560 | break; 561 | } 562 | 563 | String pitem = FPSTR(HTTP_FORM_PARAM); 564 | if (_params[i]->getID() != NULL) { 565 | pitem.replace("{i}", _params[i]->getID()); 566 | pitem.replace("{n}", _params[i]->getID()); 567 | pitem.replace("{p}", _params[i]->getPlaceholder()); 568 | snprintf(parLength, 5, "%d", _params[i]->getValueLength()); 569 | pitem.replace("{l}", parLength); 570 | pitem.replace("{v}", _params[i]->getValue()); 571 | pitem.replace("{c}", _params[i]->getCustomHTML()); 572 | } else { 573 | pitem = _params[i]->getCustomHTML(); 574 | } 575 | 576 | page += pitem; 577 | } 578 | if (_params[0] != NULL) { 579 | page += "
"; 580 | } 581 | 582 | if (_sta_static_ip) { 583 | 584 | String item = FPSTR(HTTP_FORM_PARAM); 585 | item.replace("{i}", "ip"); 586 | item.replace("{n}", "ip"); 587 | item.replace("{p}", "Static IP"); 588 | item.replace("{l}", "15"); 589 | item.replace("{v}", _sta_static_ip.toString()); 590 | 591 | page += item; 592 | 593 | item = FPSTR(HTTP_FORM_PARAM); 594 | item.replace("{i}", "gw"); 595 | item.replace("{n}", "gw"); 596 | item.replace("{p}", "Static Gateway"); 597 | item.replace("{l}", "15"); 598 | item.replace("{v}", _sta_static_gw.toString()); 599 | 600 | page += item; 601 | 602 | item = FPSTR(HTTP_FORM_PARAM); 603 | item.replace("{i}", "sn"); 604 | item.replace("{n}", "sn"); 605 | item.replace("{p}", "Subnet"); 606 | item.replace("{l}", "15"); 607 | item.replace("{v}", _sta_static_sn.toString()); 608 | 609 | page += item; 610 | 611 | page += "
"; 612 | } 613 | 614 | page += FPSTR(HTTP_FORM_END); 615 | page += FPSTR(HTTP_SCAN_LINK); 616 | 617 | page += FPSTR(HTTP_END); 618 | 619 | server->sendHeader("Content-Length", String(page.length())); 620 | server->send(200, "text/html", page); 621 | 622 | 623 | DEBUG_WM(F("Sent config page")); 624 | } 625 | 626 | /** Handle the WLAN save form and redirect to WLAN config page again */ 627 | void WiFiManager::handleWifiSave() { 628 | DEBUG_WM(F("WiFi save")); 629 | 630 | //SAVE/connect here 631 | _ssid = server->arg("s").c_str(); 632 | _pass = server->arg("p").c_str(); 633 | 634 | //parameters 635 | for (int i = 0; i < _paramsCount; i++) { 636 | if (_params[i] == NULL) { 637 | break; 638 | } 639 | //read parameter 640 | String value = server->arg(_params[i]->getID()).c_str(); 641 | //store it in array 642 | value.toCharArray(_params[i]->_value, _params[i]->_length + 1); 643 | DEBUG_WM(F("Parameter")); 644 | DEBUG_WM(_params[i]->getID()); 645 | DEBUG_WM(value); 646 | } 647 | 648 | if (server->arg("ip") != "") { 649 | DEBUG_WM(F("static ip")); 650 | DEBUG_WM(server->arg("ip")); 651 | //_sta_static_ip.fromString(server->arg("ip")); 652 | String ip = server->arg("ip"); 653 | optionalIPFromString(&_sta_static_ip, ip.c_str()); 654 | } 655 | if (server->arg("gw") != "") { 656 | DEBUG_WM(F("static gateway")); 657 | DEBUG_WM(server->arg("gw")); 658 | String gw = server->arg("gw"); 659 | optionalIPFromString(&_sta_static_gw, gw.c_str()); 660 | } 661 | if (server->arg("sn") != "") { 662 | DEBUG_WM(F("static netmask")); 663 | DEBUG_WM(server->arg("sn")); 664 | String sn = server->arg("sn"); 665 | optionalIPFromString(&_sta_static_sn, sn.c_str()); 666 | } 667 | 668 | String page = FPSTR(HTTP_HEADER); 669 | page.replace("{v}", "Credentials Saved"); 670 | page += FPSTR(HTTP_SCRIPT); 671 | page += FPSTR(HTTP_STYLE); 672 | page += _customHeadElement; 673 | page += FPSTR(HTTP_HEADER_END); 674 | page += FPSTR(HTTP_SAVED); 675 | page += FPSTR(HTTP_END); 676 | 677 | server->sendHeader("Content-Length", String(page.length())); 678 | server->send(200, "text/html", page); 679 | 680 | DEBUG_WM(F("Sent wifi save page")); 681 | 682 | connect = true; //signal ready to connect/reset 683 | } 684 | 685 | /** Handle the info page */ 686 | void WiFiManager::handleInfo() { 687 | DEBUG_WM(F("Info")); 688 | 689 | String page = FPSTR(HTTP_HEADER); 690 | page.replace("{v}", "Info"); 691 | page += FPSTR(HTTP_SCRIPT); 692 | page += FPSTR(HTTP_STYLE); 693 | page += _customHeadElement; 694 | page += FPSTR(HTTP_HEADER_END); 695 | page += F("
"); 696 | page += F("
Chip ID
"); 697 | page += ESP.getChipId(); 698 | page += F("
"); 699 | page += F("
Flash Chip ID
"); 700 | page += ESP.getFlashChipId(); 701 | page += F("
"); 702 | page += F("
IDE Flash Size
"); 703 | page += ESP.getFlashChipSize(); 704 | page += F(" bytes
"); 705 | page += F("
Real Flash Size
"); 706 | page += ESP.getFlashChipRealSize(); 707 | page += F(" bytes
"); 708 | page += F("
Soft AP IP
"); 709 | page += WiFi.softAPIP().toString(); 710 | page += F("
"); 711 | page += F("
Soft AP MAC
"); 712 | page += WiFi.softAPmacAddress(); 713 | page += F("
"); 714 | page += F("
Station MAC
"); 715 | page += WiFi.macAddress(); 716 | page += F("
"); 717 | page += F("
"); 718 | page += FPSTR(HTTP_END); 719 | 720 | server->sendHeader("Content-Length", String(page.length())); 721 | server->send(200, "text/html", page); 722 | 723 | DEBUG_WM(F("Sent info page")); 724 | } 725 | 726 | /** Handle the reset page */ 727 | void WiFiManager::handleReset() { 728 | DEBUG_WM(F("Reset")); 729 | 730 | String page = FPSTR(HTTP_HEADER); 731 | page.replace("{v}", "Info"); 732 | page += FPSTR(HTTP_SCRIPT); 733 | page += FPSTR(HTTP_STYLE); 734 | page += _customHeadElement; 735 | page += FPSTR(HTTP_HEADER_END); 736 | page += F("Module will reset in a few seconds."); 737 | page += FPSTR(HTTP_END); 738 | 739 | server->sendHeader("Content-Length", String(page.length())); 740 | server->send(200, "text/html", page); 741 | 742 | DEBUG_WM(F("Sent reset page")); 743 | delay(5000); 744 | ESP.reset(); 745 | delay(2000); 746 | } 747 | 748 | void WiFiManager::handleNotFound() { 749 | if (captivePortal()) { // If captive portal redirect instead of displaying the error page. 750 | return; 751 | } 752 | String message = "File Not Found\n\n"; 753 | message += "URI: "; 754 | message += server->uri(); 755 | message += "\nMethod: "; 756 | message += ( server->method() == HTTP_GET ) ? "GET" : "POST"; 757 | message += "\nArguments: "; 758 | message += server->args(); 759 | message += "\n"; 760 | 761 | for ( uint8_t i = 0; i < server->args(); i++ ) { 762 | message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n"; 763 | } 764 | server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 765 | server->sendHeader("Pragma", "no-cache"); 766 | server->sendHeader("Expires", "-1"); 767 | server->sendHeader("Content-Length", String(message.length())); 768 | server->send ( 404, "text/plain", message ); 769 | } 770 | 771 | 772 | /** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */ 773 | boolean WiFiManager::captivePortal() { 774 | if (!isIp(server->hostHeader()) ) { 775 | DEBUG_WM(F("Request redirected to captive portal")); 776 | server->sendHeader("Location", String("http://") + toStringIp(server->client().localIP()), true); 777 | server->send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 778 | server->client().stop(); // Stop is needed because we sent no content length 779 | return true; 780 | } 781 | return false; 782 | } 783 | 784 | //start up config portal callback 785 | void WiFiManager::setAPCallback( void (*func)(WiFiManager* myWiFiManager) ) { 786 | _apcallback = func; 787 | } 788 | 789 | //start up save config callback 790 | void WiFiManager::setSaveConfigCallback( void (*func)(void) ) { 791 | _savecallback = func; 792 | } 793 | 794 | //sets a custom element to add to head, like a new style tag 795 | void WiFiManager::setCustomHeadElement(const char* element) { 796 | _customHeadElement = element; 797 | } 798 | 799 | //if this is true, remove duplicated Access Points - defaut true 800 | void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { 801 | _removeDuplicateAPs = removeDuplicates; 802 | } 803 | 804 | 805 | 806 | template 807 | void WiFiManager::DEBUG_WM(Generic text) { 808 | if (_debug) { 809 | Serial.print("*WM: "); 810 | Serial.println(text); 811 | } 812 | } 813 | 814 | int WiFiManager::getRSSIasQuality(int RSSI) { 815 | int quality = 0; 816 | 817 | if (RSSI <= -100) { 818 | quality = 0; 819 | } else if (RSSI >= -50) { 820 | quality = 100; 821 | } else { 822 | quality = 2 * (RSSI + 100); 823 | } 824 | return quality; 825 | } 826 | 827 | /** Is this an IP? */ 828 | boolean WiFiManager::isIp(String str) { 829 | for (size_t i = 0; i < str.length(); i++) { 830 | int c = str.charAt(i); 831 | if (c != '.' && (c < '0' || c > '9')) { 832 | return false; 833 | } 834 | } 835 | return true; 836 | } 837 | 838 | /** IP to String? */ 839 | String WiFiManager::toStringIp(IPAddress ip) { 840 | String res = ""; 841 | for (int i = 0; i < 3; i++) { 842 | res += String((ip >> (8 * i)) & 0xFF) + "."; 843 | } 844 | res += String(((ip >> 8 * 3)) & 0xFF); 845 | return res; 846 | } 847 | -------------------------------------------------------------------------------- /WiFiManager.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/master/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #ifndef WiFiManager_h 14 | #define WiFiManager_h 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern "C" { 22 | #include "user_interface.h" 23 | } 24 | 25 | const char HTTP_HEADER[] PROGMEM = "{v}"; 26 | const char HTTP_STYLE[] PROGMEM = ""; 27 | const char HTTP_SCRIPT[] PROGMEM = ""; 28 | const char HTTP_HEADER_END[] PROGMEM = "
"; 29 | const char HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; 30 | const char HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; 31 | const char HTTP_FORM_START[] PROGMEM = "


"; 32 | const char HTTP_FORM_PARAM[] PROGMEM = "
"; 33 | const char HTTP_FORM_END[] PROGMEM = "
"; 34 | const char HTTP_SCAN_LINK[] PROGMEM = "
"; 35 | const char HTTP_SAVED[] PROGMEM = "
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
"; 36 | const char HTTP_END[] PROGMEM = "
"; 37 | 38 | #ifndef WIFI_MANAGER_MAX_PARAMS 39 | #define WIFI_MANAGER_MAX_PARAMS 10 40 | #endif 41 | 42 | class WiFiManagerParameter { 43 | public: 44 | /** 45 | Create custom parameters that can be added to the WiFiManager setup web page 46 | @id is used for HTTP queries and must not contain spaces nor other special characters 47 | */ 48 | WiFiManagerParameter(const char *custom); 49 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length); 50 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 51 | ~WiFiManagerParameter(); 52 | 53 | const char *getID(); 54 | const char *getValue(); 55 | const char *getPlaceholder(); 56 | int getValueLength(); 57 | const char *getCustomHTML(); 58 | private: 59 | const char *_id; 60 | const char *_placeholder; 61 | char *_value; 62 | int _length; 63 | const char *_customHTML; 64 | 65 | void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 66 | 67 | friend class WiFiManager; 68 | }; 69 | 70 | 71 | class WiFiManager 72 | { 73 | public: 74 | WiFiManager(); 75 | ~WiFiManager(); 76 | 77 | boolean autoConnect(); 78 | boolean autoConnect(char const *apName, char const *apPassword = NULL); 79 | 80 | //if you want to always start the config portal, without trying to connect first 81 | boolean startConfigPortal(); 82 | boolean startConfigPortal(char const *apName, char const *apPassword = NULL); 83 | 84 | // get the AP name of the config portal, so it can be used in the callback 85 | String getConfigPortalSSID(); 86 | 87 | void resetSettings(); 88 | 89 | //sets timeout before webserver loop ends and exits even if there has been no setup. 90 | //useful for devices that failed to connect at some point and got stuck in a webserver loop 91 | //in seconds setConfigPortalTimeout is a new name for setTimeout 92 | void setConfigPortalTimeout(unsigned long seconds); 93 | void setTimeout(unsigned long seconds); 94 | 95 | //sets timeout for which to attempt connecting, useful if you get a lot of failed connects 96 | void setConnectTimeout(unsigned long seconds); 97 | 98 | 99 | void setDebugOutput(boolean debug); 100 | //defaults to not showing anything under 8% signal quality if called 101 | void setMinimumSignalQuality(int quality = 8); 102 | //sets a custom ip /gateway /subnet configuration 103 | void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 104 | //sets config for a static IP 105 | void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 106 | //called when AP mode and config portal is started 107 | void setAPCallback( void (*func)(WiFiManager*) ); 108 | //called when settings have been changed and connection was successful 109 | void setSaveConfigCallback( void (*func)(void) ); 110 | //adds a custom parameter, returns false on failure 111 | bool addParameter(WiFiManagerParameter *p); 112 | //if this is set, it will exit after config, even if connection is unsuccessful. 113 | void setBreakAfterConfig(boolean shouldBreak); 114 | //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) 115 | //TODO 116 | //if this is set, customise style 117 | void setCustomHeadElement(const char* element); 118 | //if this is true, remove duplicated Access Points - defaut true 119 | void setRemoveDuplicateAPs(boolean removeDuplicates); 120 | 121 | private: 122 | std::unique_ptr dnsServer; 123 | std::unique_ptr server; 124 | 125 | //const int WM_DONE = 0; 126 | //const int WM_WAIT = 10; 127 | 128 | //const String HTTP_HEADER = "{v}"; 129 | 130 | void setupConfigPortal(); 131 | void startWPS(); 132 | 133 | const char* _apName = "no-net"; 134 | const char* _apPassword = NULL; 135 | String _ssid = ""; 136 | String _pass = ""; 137 | unsigned long _configPortalTimeout = 0; 138 | unsigned long _connectTimeout = 0; 139 | unsigned long _configPortalStart = 0; 140 | 141 | IPAddress _ap_static_ip; 142 | IPAddress _ap_static_gw; 143 | IPAddress _ap_static_sn; 144 | IPAddress _sta_static_ip; 145 | IPAddress _sta_static_gw; 146 | IPAddress _sta_static_sn; 147 | 148 | int _paramsCount = 0; 149 | int _minimumQuality = -1; 150 | boolean _removeDuplicateAPs = true; 151 | boolean _shouldBreakAfterConfig = false; 152 | boolean _tryWPS = false; 153 | 154 | const char* _customHeadElement = ""; 155 | 156 | //String getEEPROMString(int start, int len); 157 | //void setEEPROMString(int start, int len, String string); 158 | 159 | int status = WL_IDLE_STATUS; 160 | int connectWifi(String ssid, String pass); 161 | uint8_t waitForConnectResult(); 162 | 163 | void handleRoot(); 164 | void handleWifi(boolean scan); 165 | void handleWifiSave(); 166 | void handleInfo(); 167 | void handleReset(); 168 | void handleNotFound(); 169 | void handle204(); 170 | boolean captivePortal(); 171 | boolean configPortalHasTimeout(); 172 | 173 | // DNS server 174 | const byte DNS_PORT = 53; 175 | 176 | //helpers 177 | int getRSSIasQuality(int RSSI); 178 | boolean isIp(String str); 179 | String toStringIp(IPAddress ip); 180 | 181 | boolean connect; 182 | boolean _debug = true; 183 | 184 | void (*_apcallback)(WiFiManager*) = NULL; 185 | void (*_savecallback)(void) = NULL; 186 | 187 | int _max_params; 188 | WiFiManagerParameter** _params; 189 | 190 | template 191 | void DEBUG_WM(Generic text); 192 | 193 | template 194 | auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { 195 | return obj->fromString(s); 196 | } 197 | auto optionalIPFromString(...) -> bool { 198 | DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); 199 | return false; 200 | } 201 | }; 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /Words.h: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // Words.h 3 | //****************************************************************************** 4 | 5 | #ifndef WORDS_H 6 | #define WORDS_H 7 | 8 | #if defined(FRONTCOVER_CH) || defined(FRONTCOVER_CH_GS) 9 | 10 | #define CH_VOR matrix[2] |= 0b0000000011100000 11 | #define CH_AB matrix[3] |= 0b1100000000000000 12 | #define CH_ESISCH matrix[0] |= 0b1101111000000000 13 | #define CH_GSI matrix[9] |= 0b0000000011100000 14 | #define CH_AM matrix[9] |= 0b0000001100000000 15 | #define CH_PM matrix[3] |= 0b0000000001100000 16 | 17 | #define CH_FUEF matrix[0] |= 0b0000000011100000 18 | #define CH_ZAEAE matrix[1] |= 0b0000000011100000 19 | #define CH_VIERTU matrix[1] |= 0b1111110000000000 20 | #define CH_ZWAENZG matrix[2] |= 0b1111110000000000 21 | #define CH_HAUBI matrix[3] |= 0b0001111100000000 22 | 23 | #define CH_H_EIS matrix[4] |= 0b1110000000000000 24 | #define CH_H_ZWOEI matrix[4] |= 0b0001111000000000 25 | #define CH_H_DRUE matrix[4] |= 0b0000000011100000 26 | #define CH_H_VIER matrix[5] |= 0b1111100000000000 27 | #define CH_H_FUEFI matrix[5] |= 0b0000011110000000 28 | #define CH_H_SAECHSI matrix[6] |= 0b1111110000000000 29 | #define CH_H_SIEBNI matrix[6] |= 0b0000001111100000 30 | #define CH_H_ACHTI matrix[7] |= 0b1111100000000000 31 | #define CH_H_NUENI matrix[7] |= 0b0000011110000000 32 | #define CH_H_ZAENI matrix[8] |= 0b1111000000000000 33 | #define CH_H_EUFI matrix[8] |= 0b0000000111100000 34 | #define CH_H_ZWOEUFI matrix[9] |= 0b1111110000000000 35 | 36 | #endif 37 | 38 | #if defined(FRONTCOVER_D3) 39 | 40 | #define D3_ESISCH matrix[0] |= 0b1101111000000000 41 | #define D3_VOR matrix[3] |= 0b0000000011100000 42 | #define D3_NACH matrix[3] |= 0b1111000000000000 43 | #define D3_AM matrix[0] |= 0b1000000000000000 44 | #define D3_PM matrix[0] |= 0b0100000000000000 45 | 46 | #define D3_FUENF matrix[2] |= 0b0000000111100000 47 | #define D3_ZEHN matrix[2] |= 0b1111000000000000 48 | #define D3_VIERTL matrix[1] |= 0b0000111111000000 49 | #define D3_HALB matrix[4] |= 0b1111000000000000 50 | #define D3_DREIVIERTL matrix[1] |= 0b1111111111000000 51 | 52 | #define D3_H_OISE matrix[5] |= 0b1111000000000000 53 | #define D3_H_ZWOIE matrix[6] |= 0b1111100000000000 54 | #define D3_H_DREIE matrix[7] |= 0b1111100000000000 55 | #define D3_H_VIERE matrix[9] |= 0b0000001111100000 56 | #define D3_H_FUENFE matrix[4] |= 0b0000011111000000 57 | #define D3_H_SECHSE matrix[5] |= 0b0011111100000000 58 | #define D3_H_SIEBNE matrix[9] |= 0b1111110000000000 59 | #define D3_H_ACHTE matrix[6] |= 0b0000011111000000 60 | #define D3_H_NEUNE matrix[8] |= 0b0001111100000000 61 | #define D3_H_ZEHNE matrix[8] |= 0b1111100000000000 62 | #define D3_H_ELFE matrix[5] |= 0b0000000111100000 63 | #define D3_H_ZWOELFE matrix[7] |= 0b0000011111100000 64 | 65 | #endif 66 | 67 | #if defined(FRONTCOVER_DE_DE) || defined(FRONTCOVER_DE_SW) || defined(FRONTCOVER_DE_BA) || defined(FRONTCOVER_DE_SA) 68 | 69 | #define DE_VOR matrix[3] |= 0b1110000000000000 70 | #define DE_NACH matrix[3] |= 0b0000000111100000 71 | #define DE_ESIST matrix[0] |= 0b1101110000000000 72 | #define DE_UHR matrix[9] |= 0b0000000011100000 73 | #define DE_AM matrix[5] |= 0b0000011000000000 74 | #define DE_PM matrix[6] |= 0b0000110000000000 75 | 76 | #define DE_FUENF matrix[0] |= 0b0000000111100000 77 | #define DE_ZEHN matrix[1] |= 0b1111000000000000 78 | #define DE_VIERTEL matrix[2] |= 0b0000111111100000 79 | #define DE_ZWANZIG matrix[1] |= 0b0000111111100000 80 | #define DE_HALB matrix[4] |= 0b1111000000000000 81 | #define DE_DREIVIERTEL matrix[2] |= 0b1111111111100000 82 | 83 | #define DE_H_EIN matrix[5] |= 0b1110000000000000 84 | #define DE_H_EINS matrix[5] |= 0b1111000000000000 85 | #define DE_H_ZWEI matrix[5] |= 0b0000000111100000 86 | #define DE_H_DREI matrix[6] |= 0b1111000000000000 87 | #define DE_H_VIER matrix[6] |= 0b0000000111100000 88 | #define DE_H_FUENF matrix[4] |= 0b0000000111100000 89 | #define DE_H_SECHS matrix[7] |= 0b1111100000000000 90 | #define DE_H_SIEBEN matrix[8] |= 0b1111110000000000 91 | #define DE_H_ACHT matrix[7] |= 0b0000000111100000 92 | #define DE_H_NEUN matrix[9] |= 0b0001111000000000 93 | #define DE_H_ZEHN matrix[9] |= 0b1111000000000000 94 | #define DE_H_ELF matrix[4] |= 0b0000011100000000 95 | #define DE_H_ZWOELF matrix[8] |= 0b0000001111100000 96 | 97 | #endif 98 | 99 | #if defined(FRONTCOVER_DE_MKF_DE) || defined(FRONTCOVER_DE_MKF_SW) || defined(FRONTCOVER_DE_MKF_BA) || defined(FRONTCOVER_DE_MKF_SA) 100 | 101 | #define DE_MKF_VOR matrix[3] |= 0b0000001110000000 102 | #define DE_MKF_NACH matrix[3] |= 0b0011110000000000 103 | #define DE_MKF_ESIST matrix[0] |= 0b1101110000000000 104 | #define DE_MKF_UHR matrix[9] |= 0b0000000011100000 105 | #define DE_MKF_AM matrix[0] |= 0b1000000000000000 106 | #define DE_MKF_PM matrix[0] |= 0b0100000000000000 107 | 108 | #define DE_MKF_FUENF matrix[0] |= 0b0000000111100000 109 | #define DE_MKF_ZEHN matrix[1] |= 0b1111000000000000 110 | #define DE_MKF_VIERTEL matrix[2] |= 0b0000111111100000 111 | #define DE_MKF_ZWANZIG matrix[1] |= 0b0000111111100000 112 | #define DE_MKF_HALB matrix[4] |= 0b1111000000000000 113 | #define DE_MKF_DREIVIERTEL matrix[2] |= 0b1111111111100000 114 | 115 | #define DE_MKF_H_EIN matrix[5] |= 0b0011100000000000 116 | #define DE_MKF_H_EINS matrix[5] |= 0b0011110000000000 117 | #define DE_MKF_H_ZWEI matrix[5] |= 0b1111000000000000 118 | #define DE_MKF_H_DREI matrix[6] |= 0b0111100000000000 119 | #define DE_MKF_H_VIER matrix[7] |= 0b0000000111100000 120 | #define DE_MKF_H_FUENF matrix[6] |= 0b0000000111100000 121 | #define DE_MKF_H_SECHS matrix[9] |= 0b0111110000000000 122 | #define DE_MKF_H_SIEBEN matrix[5] |= 0b0000011111100000 123 | #define DE_MKF_H_ACHT matrix[8] |= 0b0111100000000000 124 | #define DE_MKF_H_NEUN matrix[7] |= 0b0001111000000000 125 | #define DE_MKF_H_ZEHN matrix[8] |= 0b0000011110000000 126 | #define DE_MKF_H_ELF matrix[7] |= 0b1110000000000000 127 | #define DE_MKF_H_ZWOELF matrix[4] |= 0b0000011111000000 128 | 129 | #endif 130 | 131 | #if defined(FRONTCOVER_EN) 132 | 133 | #define EN_ITIS matrix[0] |= 0b1101100000000000 134 | #define EN_TIME matrix[0] |= 0b0000000111100000 135 | #define EN_A matrix[1] |= 0b1000000000000000 136 | #define EN_OCLOCK matrix[9] |= 0b0000011111100000 137 | #define EN_AM matrix[0] |= 0b0000000110000000 138 | #define EN_PM matrix[0] |= 0b0000000001100000 139 | 140 | #define EN_QUATER matrix[1] |= 0b0011111110000000 141 | #define EN_TWENTY matrix[2] |= 0b1111110000000000 142 | #define EN_FIVE matrix[2] |= 0b0000001111000000 143 | #define EN_HALF matrix[3] |= 0b1111000000000000 144 | #define EN_TEN matrix[3] |= 0b0000011100000000 145 | #define EN_TO matrix[3] |= 0b0000000001100000 146 | #define EN_PAST matrix[4] |= 0b1111000000000000 147 | 148 | #define EN_H_NINE matrix[4] |= 0b0000000111100000 149 | #define EN_H_ONE matrix[5] |= 0b1110000000000000 150 | #define EN_H_SIX matrix[5] |= 0b0001110000000000 151 | #define EN_H_THREE matrix[5] |= 0b0000001111100000 152 | #define EN_H_FOUR matrix[6] |= 0b1111000000000000 153 | #define EN_H_FIVE matrix[6] |= 0b0000111100000000 154 | #define EN_H_TWO matrix[6] |= 0b0000000011100000 155 | #define EN_H_EIGHT matrix[7] |= 0b1111100000000000 156 | #define EN_H_ELEVEN matrix[7] |= 0b0000011111100000 157 | #define EN_H_SEVEN matrix[8] |= 0b1111100000000000 158 | #define EN_H_TWELVE matrix[8] |= 0b0000011111100000 159 | #define EN_H_TEN matrix[9] |= 0b1110000000000000 160 | 161 | #endif 162 | 163 | #if defined(FRONTCOVER_ES) 164 | 165 | #define ES_SONLAS matrix[0] |= 0b0111011100000000 166 | #define ES_ESLA matrix[0] |= 0b1100011000000000 167 | #define ES_Y matrix[6] |= 0b0000010000000000 168 | #define ES_MENOS matrix[6] |= 0b0000001111100000 169 | #define ES_AM matrix[0] |= 0b1000000000000000 170 | #define ES_PM matrix[0] |= 0b0100000000000000 171 | 172 | #define ES_CINCO matrix[8] |= 0b0000001111100000 173 | #define ES_DIEZ matrix[7] |= 0b0000000111100000 174 | #define ES_CUARTO matrix[9] |= 0b0000011111100000 175 | #define ES_VEINTE matrix[7] |= 0b0111111000000000 176 | #define ES_VEINTICINCO matrix[8] |= 0b1111111111100000 177 | #define ES_MEDIA matrix[9] |= 0b1111100000000000 178 | 179 | #define ES_H_UNA matrix[0] |= 0b0000000011100000 180 | #define ES_H_DOS matrix[1] |= 0b1110000000000000 181 | #define ES_H_TRES matrix[1] |= 0b0000111100000000 182 | #define ES_H_CUATRO matrix[2] |= 0b1111110000000000 183 | #define ES_H_CINCO matrix[2] |= 0b0000001111100000 184 | #define ES_H_SEIS matrix[3] |= 0b1111000000000000 185 | #define ES_H_SIETE matrix[3] |= 0b0000011111000000 186 | #define ES_H_OCHO matrix[4] |= 0b1111000000000000 187 | #define ES_H_NUEVE matrix[4] |= 0b0000111110000000 188 | #define ES_H_DIEZ matrix[5] |= 0b0011110000000000 189 | #define ES_H_ONCE matrix[5] |= 0b0000000111100000 190 | #define ES_H_DOCE matrix[6] |= 0b1111000000000000 191 | 192 | #endif 193 | 194 | #if defined(FRONTCOVER_FR) 195 | 196 | #define FR_TRAIT matrix[8] |= 0b0000010000000000 197 | #define FR_ET matrix[7] |= 0b1100000000000000 198 | #define FR_LE matrix[6] |= 0b0000001100000000 199 | #define FR_MOINS matrix[6] |= 0b1111100000000000 200 | #define FR_ILEST matrix[0] |= 0b1101110000000000 201 | #define FR_HEURE matrix[5] |= 0b0000011111000000 202 | #define FR_HEURES matrix[5] |= 0b0000011111100000 203 | #define FR_AM matrix[7] |= 0b0000000001100000 204 | #define FR_PM matrix[9] |= 0b0000000011000000 205 | 206 | #define FR_CINQ matrix[8] |= 0b0000001111000000 207 | #define FR_DIX matrix[6] |= 0b0000000011100000 208 | #define FR_QUART matrix[7] |= 0b0001111100000000 209 | #define FR_VINGT matrix[8] |= 0b1111100000000000 210 | #define FR_DEMIE matrix[9] |= 0b0001111100000000 211 | 212 | #define FR_H_UNE matrix[2] |= 0b0000111000000000 213 | #define FR_H_DEUX matrix[0] |= 0b0000000111100000 214 | #define FR_H_TROIS matrix[1] |= 0b0000001111100000 215 | #define FR_H_QUATRE matrix[1] |= 0b1111110000000000 216 | #define FR_H_CINQ matrix[3] |= 0b0000000111100000 217 | #define FR_H_SIX matrix[3] |= 0b0000111000000000 218 | #define FR_H_SEPT matrix[2] |= 0b0000000111100000 219 | #define FR_H_HUIT matrix[3] |= 0b1111000000000000 220 | #define FR_H_NEUF matrix[2] |= 0b1111000000000000 221 | #define FR_H_DIX matrix[4] |= 0b0011100000000000 222 | #define FR_H_ONZE matrix[5] |= 0b1111000000000000 223 | #define FR_H_MIDI matrix[4] |= 0b1111000000000000 224 | #define FR_H_MINUIT matrix[4] |= 0b0000011111100000 225 | 226 | #endif 227 | 228 | #if defined(FRONTCOVER_IT) 229 | 230 | #define IT_SONOLE matrix[0] |= 0b1111011000000000 231 | #define IT_LE matrix[0] |= 0b0000011000000000 232 | #define IT_ORE matrix[0] |= 0b0000000011100000 233 | #define IT_E matrix[1] |= 0b1000000000000000 234 | #define IT_AM matrix[0] |= 0b1000000000000000 235 | #define IT_PM matrix[0] |= 0b0100000000000000 236 | 237 | #define IT_H_LUNA matrix[1] |= 0b0011110000000000 238 | #define IT_H_DUE matrix[1] |= 0b0000000111000000 239 | #define IT_H_TRE matrix[2] |= 0b1110000000000000 240 | #define IT_H_OTTO matrix[2] |= 0b0001111000000000 241 | #define IT_H_NOVE matrix[2] |= 0b0000000111100000 242 | #define IT_H_DIECI matrix[3] |= 0b1111100000000000 243 | #define IT_H_UNDICI matrix[3] |= 0b0000011111100000 244 | #define IT_H_DODICI matrix[4] |= 0b1111110000000000 245 | #define IT_H_SETTE matrix[4] |= 0b0000001111100000 246 | #define IT_H_QUATTRO matrix[5] |= 0b1111111000000000 247 | #define IT_H_SEI matrix[5] |= 0b0000000011100000 248 | #define IT_H_CINQUE matrix[6] |= 0b1111110000000000 249 | 250 | #define IT_MENO matrix[6] |= 0b0000000111100000 251 | #define IT_E2 matrix[7] |= 0b1000000000000000 252 | #define IT_UN matrix[7] |= 0b0011000000000000 253 | #define IT_QUARTO matrix[7] |= 0b0000011111100000 254 | #define IT_VENTI matrix[8] |= 0b1111100000000000 255 | #define IT_CINQUE matrix[8] |= 0b0000011111100000 256 | #define IT_DIECI matrix[9] |= 0b1111100000000000 257 | #define IT_MEZZA matrix[9] |= 0b0000001111100000 258 | 259 | #endif 260 | 261 | #if defined(FRONTCOVER_NL) 262 | 263 | #define NL_VOOR matrix[1] |= 0b0000000111100000 264 | #define NL_OVER matrix[2] |= 0b1111000000000000 265 | #define NL_VOOR2 matrix[4] |= 0b1111000000000000 266 | #define NL_OVER2 matrix[3] |= 0b0000000111100000 267 | #define NL_HETIS matrix[0] |= 0b1110110000000000 268 | #define NL_UUR matrix[9] |= 0b0000000011100000 269 | #define NL_AM matrix[0] |= 0b1000000000000000 270 | #define NL_PM matrix[0] |= 0b0100000000000000 271 | 272 | #define NL_VIJF matrix[0] |= 0b0000000111100000 273 | #define NL_TIEN matrix[1] |= 0b1111000000000000 274 | #define NL_KWART matrix[2] |= 0b0000001111100000 275 | #define NL_ZWANZIG matrix[1] |= 0b0000111111100000 276 | #define NL_HALF matrix[3] |= 0b1111000000000000 277 | 278 | #define NL_H_EEN matrix[4] |= 0b0000000111000000 279 | #define NL_H_EENS matrix[4] |= 0b0000000111100000 280 | #define NL_H_TWEE matrix[5] |= 0b1111000000000000 281 | #define NL_H_DRIE matrix[5] |= 0b0000000111100000 282 | #define NL_H_VIER matrix[6] |= 0b1111000000000000 283 | #define NL_H_VIJF matrix[6] |= 0b0000111100000000 284 | #define NL_H_ZES matrix[6] |= 0b0000000011100000 285 | #define NL_H_ZEVEN matrix[7] |= 0b1111100000000000 286 | #define NL_H_ACHT matrix[8] |= 0b1111000000000000 287 | #define NL_H_NEGEN matrix[7] |= 0b0000001111100000 288 | #define NL_H_TIEN matrix[8] |= 0b0000111100000000 289 | #define NL_H_ELF matrix[8] |= 0b0000000011100000 290 | #define NL_H_TWAALF matrix[9] |= 0b1111110000000000 291 | 292 | #endif 293 | 294 | #endif 295 | -------------------------------------------------------------------------------- /misc/BOM.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------- 2 | 3 | 1x WeMos D1 mini 4 | 115x SK6812 or WS2812B RGB(W) LED-Stripe, 30 LEDs per meter 5 | 1x DS3231 RTC Module 6 | 1x DHT22 Module 7 | 1x 145475 LDR A9013 8 | 1x HX1838 IR-Remote 9 | 1x 171085 IR-Receiver TSOP31240 10 | 3x Button 11 | 1x Powersupply 5V, 4A 12 | 13 | -------------------------------------------------------------- 14 | 15 | 1x Baseplate 450 x 450 x 2 mm 16 | 17 | Outer frame: 18 | 2x Bar 450 x 20 x 15 mm 19 | 2x Bar 420 x 20 x 15 mm 20 | 21 | Inner frame: 22 | 2x Bar 355 x 20 x 15 mm 23 | 2x Bar 325 x 20 x 15 mm 24 | 8x Supermagnets 10 x 5 mm 25 | 26 | Light grid: 27 | 12x Bar 325 x 20 x 5 mm 28 | 99x Bar 23 x 20 x 5 mm 29 | 30 | -------------------------------------------------------------- 31 | -------------------------------------------------------------------------------- /misc/Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch570512/Qlockwork/61b2f1277fc275595ddf32fdbab3b12437bfc933/misc/Schematic.pdf --------------------------------------------------------------------------------