├── README.md ├── LICENSE └── TwichtelgeschenkUselessBox.ino /README.md: -------------------------------------------------------------------------------- 1 | # TwichtelgeschenkUselessBox 2 | Hackbare UselessBox mit Signallichtern, Piepern und ESP8266. 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /TwichtelgeschenkUselessBox.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | unsigned long ulReqcount; 10 | unsigned long ulReconncount; 11 | 12 | // WiFi settings 13 | const char* ssid = "vspace.one"; 14 | const char* password = "12345678"; 15 | 16 | extern "C" { 17 | #include 18 | } 19 | 20 | // Notes 21 | #define NOTE_B0 31 22 | #define NOTE_C1 33 23 | #define NOTE_CS1 35 24 | #define NOTE_D1 37 25 | #define NOTE_DS1 39 26 | #define NOTE_E1 41 27 | #define NOTE_F1 44 28 | #define NOTE_FS1 46 29 | #define NOTE_G1 49 30 | #define NOTE_GS1 52 31 | #define NOTE_A1 55 32 | #define NOTE_AS1 58 33 | #define NOTE_B1 62 34 | #define NOTE_C2 65 35 | #define NOTE_CS2 69 36 | #define NOTE_D2 73 37 | #define NOTE_DS2 78 38 | #define NOTE_E2 82 39 | #define NOTE_F2 87 40 | #define NOTE_FS2 93 41 | #define NOTE_G2 98 42 | #define NOTE_GS2 104 43 | #define NOTE_A2 110 44 | #define NOTE_AS2 117 45 | #define NOTE_B2 123 46 | #define NOTE_C3 131 47 | #define NOTE_CS3 139 48 | #define NOTE_D3 147 49 | #define NOTE_DS3 156 50 | #define NOTE_E3 165 51 | #define NOTE_F3 175 52 | #define NOTE_FS3 185 53 | #define NOTE_G3 196 54 | #define NOTE_GS3 208 55 | #define NOTE_A3 220 56 | #define NOTE_AS3 233 57 | #define NOTE_B3 247 58 | #define NOTE_C4 262 59 | #define NOTE_CS4 277 60 | #define NOTE_D4 294 61 | #define NOTE_DS4 311 62 | #define NOTE_E4 330 63 | #define NOTE_F4 349 64 | #define NOTE_FS4 370 65 | #define NOTE_G4 392 66 | #define NOTE_GS4 415 67 | #define NOTE_A4 440 68 | #define NOTE_AS4 466 69 | #define NOTE_B4 494 70 | #define NOTE_C5 523 71 | #define NOTE_CS5 554 72 | #define NOTE_D5 587 73 | #define NOTE_DS5 622 74 | #define NOTE_E5 659 75 | #define NOTE_F5 698 76 | #define NOTE_FS5 740 77 | #define NOTE_G5 784 78 | #define NOTE_GS5 831 79 | #define NOTE_A5 880 80 | #define NOTE_AS5 932 81 | #define NOTE_B5 988 82 | #define NOTE_C6 1047 83 | #define NOTE_CS6 1109 84 | #define NOTE_D6 1175 85 | #define NOTE_DS6 1245 86 | #define NOTE_E6 1319 87 | #define NOTE_F6 1397 88 | #define NOTE_FS6 1480 89 | #define NOTE_G6 1568 90 | #define NOTE_GS6 1661 91 | #define NOTE_A6 1760 92 | #define NOTE_AS6 1865 93 | #define NOTE_B6 1976 94 | #define NOTE_C7 2093 95 | #define NOTE_CS7 2217 96 | #define NOTE_D7 2349 97 | #define NOTE_DS7 2489 98 | #define NOTE_E7 2637 99 | #define NOTE_F7 2794 100 | #define NOTE_FS7 2960 101 | #define NOTE_G7 3136 102 | #define NOTE_GS7 3322 103 | #define NOTE_A7 3520 104 | #define NOTE_AS7 3729 105 | #define NOTE_B7 3951 106 | #define NOTE_C8 4186 107 | #define NOTE_CS8 4435 108 | #define NOTE_D8 4699 109 | #define NOTE_DS8 4978 110 | 111 | #define PLAYSPEED 133 //= 15000/113 BPM 112 | #define TONEDURATION 0.9 //Add little gap between the notes 113 | #define LED_COUNT 1 //Only one Neopixel is used 114 | 115 | //Hardware pins 116 | #define NEOPIXELPIN 0 117 | #define SERVO_POWER 2 118 | #define SERVO_CONTROL 4 119 | #define SPEAKER 5 120 | #define MULTICOLOUR_R 12 121 | #define MULTICOLOUR_G 13 122 | #define MULTICOLOUR_B 14 123 | #define MULTICOLOUR_TONE 15 124 | #define CURRENTLY_UNUSED 16 125 | 126 | //Machinestates 127 | #define STATE_STARTUP 0 128 | #define STATE_DEEPSLEEP 1 129 | #define STATE_PLAY 2 130 | #define STATE_TURN_OFF1 3 131 | #define STATE_GO_SLEEP1 4 132 | #define STATE_SLEEP1 5 133 | #define STATE_TURN_OFF2 6 134 | #define STATE_GO_SLEEP2 7 135 | #define STATE_SLEEP2 8 136 | #define STATE_TURN_OFF 9 137 | #define STATE_KEEP_OFF 10 138 | #define STATE_GO_SLEEP 11 139 | #define STATE_SLEEP 12 140 | 141 | //Variables 142 | uint8_t state = STATE_STARTUP; 143 | uint8_t state_old = -1; 144 | uint8_t timeout = 23; 145 | bool switch_state = false; 146 | int8_t connection = -1; 147 | 148 | //Config servo and neopixel 149 | Servo myservo; 150 | Adafruit_NeoPixel strip(LED_COUNT, NEOPIXELPIN, NEO_GRBW + NEO_KHZ800); 151 | 152 | //Config timer interrupts 153 | Ticker Tick; 154 | Ticker Music; 155 | Ticker RgbCycle; 156 | 157 | //Send message to telegram via telegramiotbot.com 158 | bool telegram(String Message = "", String Token = "59c3dc1a8b797") { 159 | int c; 160 | String Send = ""; 161 | for (int i = 0; i < Message.length(); i++) { 162 | c = Message.charAt(i); 163 | if ( ('a' <= c && c <= 'z') 164 | || ('A' <= c && c <= 'Z') 165 | || ('0' <= c && c <= '9') ) { 166 | Send += char(c); 167 | } else { 168 | if (c <= 0x0F) { 169 | Send += "%0" + String(c, HEX); 170 | } else { 171 | Send += "%" + String(c, HEX); 172 | } 173 | } 174 | } 175 | 176 | HTTPClient http; 177 | http.begin("http://telegramiotbot.com/api/notify?token=" + Token + "&message=" + Send); 178 | int httpCode = http.GET(); 179 | return httpCode != HTTP_CODE_OK; 180 | } 181 | 182 | //Every 50 ms; 20x per second 183 | void tick() { 184 | if (timeout != 0) { 185 | timeout--; 186 | } 187 | } 188 | 189 | //Rickroll 190 | int8_t music = 0; 191 | void musicplayer() { // Plays music in 1/16 Notes 192 | if (music > 0 ) { 193 | switch (music) { 194 | case 1: tone(SPEAKER, NOTE_C4, 6 * PLAYSPEED * TONEDURATION); break; 195 | case 7: tone(SPEAKER, NOTE_D4, 6 * PLAYSPEED * TONEDURATION); break; 196 | case 13: tone(SPEAKER, NOTE_G3, 4 * PLAYSPEED * TONEDURATION); break; 197 | case 17: tone(SPEAKER, NOTE_D4, 6 * PLAYSPEED * TONEDURATION); break; 198 | case 23: tone(SPEAKER, NOTE_E4, 6 * PLAYSPEED * TONEDURATION); break; 199 | case 29: tone(SPEAKER, NOTE_G4, 1 * PLAYSPEED * TONEDURATION); break; 200 | case 30: tone(SPEAKER, NOTE_F4, 1 * PLAYSPEED * TONEDURATION); break; 201 | case 31: tone(SPEAKER, NOTE_E4, 1 * PLAYSPEED * TONEDURATION); break; 202 | case 32: tone(SPEAKER, NOTE_C4, 7 * PLAYSPEED * TONEDURATION); break; 203 | case 39: tone(SPEAKER, NOTE_D4, 6 * PLAYSPEED * TONEDURATION); break; 204 | case 45: tone(SPEAKER, NOTE_G3, 10 * PLAYSPEED * TONEDURATION); break; 205 | // 55 PAUSE 4 206 | case 59: tone(SPEAKER, NOTE_G3, 1 * PLAYSPEED * TONEDURATION); break; 207 | case 60: tone(SPEAKER, NOTE_G3, 1 * PLAYSPEED * TONEDURATION); break; 208 | case 61: tone(SPEAKER, NOTE_A3, 1 * PLAYSPEED * TONEDURATION); break; 209 | case 62: tone(SPEAKER, NOTE_C4, 1 * PLAYSPEED * TONEDURATION); break; 210 | case 63: tone(SPEAKER, NOTE_A3, 1 * PLAYSPEED * TONEDURATION); break; 211 | case 64: tone(SPEAKER, NOTE_C4, 1 * PLAYSPEED * TONEDURATION); break; 212 | case 70: music = -2; break; 213 | } 214 | music++; 215 | } 216 | } 217 | 218 | //Fading Neopixel 219 | uint16_t fading = 0; 220 | void rgbcycle() { 221 | if (fading != 0) { 222 | uint16_t pos = fading / 256; 223 | uint16_t fade = fading % 256; 224 | uint8_t r, g, b; 225 | switch (pos) { 226 | case 0: 227 | r = fade; 228 | g = 0; 229 | b = 0; 230 | break; 231 | case 1: 232 | r = 255; 233 | g = fade; 234 | b = 0; 235 | break; 236 | case 2: 237 | r = 255 - fade; 238 | g = 255; 239 | b = 0; 240 | break; 241 | case 3: 242 | r = 0; 243 | g = 255; 244 | b = fade; 245 | break; 246 | case 4: 247 | r = 0; 248 | g = 255 - fade; 249 | b = 255; 250 | break; 251 | case 5: 252 | r = fade; 253 | g = 0; 254 | b = 255; 255 | break; 256 | case 6: 257 | r = 255; 258 | g = 0; 259 | b = 255 - fade; 260 | break; 261 | case 7: 262 | fading = 255; 263 | break; 264 | } 265 | fading ++; 266 | strip.setPixelColor(0, strip.Color(r, g, b)); 267 | strip.show(); 268 | } 269 | } 270 | 271 | //Setup WLAN 272 | void WiFiStart() { 273 | ulReconncount++; 274 | 275 | // Connect to WiFi network 276 | Serial.print("Connecting to "); 277 | Serial.println(ssid); 278 | 279 | WiFi.hostname("UselessBox"); 280 | WiFi.begin(ssid, password); 281 | while (WiFi.status() != WL_CONNECTED) { 282 | delay(100); 283 | Serial.print("."); 284 | } 285 | // WiFi.config(IPAddress(192, 168, 2, 81), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0), IPAddress(192, 168, 2, 1)); 286 | 287 | Serial.println("WiFi connected"); 288 | 289 | telegram("UselessBox:\nWiFi connected!\nTry: " + String(ulReconncount)); 290 | 291 | // Print the IP address 292 | Serial.println(WiFi.localIP()); 293 | } 294 | 295 | //Startup 296 | void setup() { 297 | // put your setup code here, to run once: 298 | Serial.begin(115200); 299 | Serial.print("Started"); 300 | 301 | pinMode(MULTICOLOUR_TONE, OUTPUT); 302 | pinMode(MULTICOLOUR_R, OUTPUT); 303 | pinMode(MULTICOLOUR_G, OUTPUT); 304 | pinMode(MULTICOLOUR_B, OUTPUT); 305 | pinMode(SPEAKER, OUTPUT); 306 | pinMode(SERVO_POWER, OUTPUT); 307 | digitalWrite(SERVO_POWER, HIGH); 308 | 309 | strip.setBrightness(255); // Set BRIGHTNESS to about 1/5 (max = 255) 310 | strip.begin(); 311 | strip.show(); 312 | 313 | WiFi.mode(WIFI_STA); 314 | 315 | 316 | Music.attach_ms(PLAYSPEED, musicplayer); 317 | Tick.attach_ms(50, tick); 318 | RgbCycle.attach_ms(2, rgbcycle); 319 | 320 | digitalWrite(MULTICOLOUR_R, 1); 321 | digitalWrite(MULTICOLOUR_G, 0); 322 | digitalWrite(MULTICOLOUR_B, 0); 323 | strip.setPixelColor(0, strip.Color(0, 0, 0)); 324 | strip.show(); 325 | myservo.attach(SERVO_CONTROL); 326 | digitalWrite(SERVO_POWER, LOW); 327 | myservo.write(50); 328 | } 329 | 330 | //Main loop 331 | void loop() { 332 | // put your main code here, to run repeatedly: 333 | if (WiFi.status() != WL_CONNECTED){//Restart WLAN connection if needed 334 | // WiFiStart(); 335 | } 336 | if (analogRead(A0) < 512) {//read switch state 337 | if (switch_state == false){//detect change 338 | switch_state = true; 339 | telegram("Switched on!"); 340 | } 341 | if (state == STATE_STARTUP or state == STATE_DEEPSLEEP) { 342 | state = STATE_PLAY; 343 | fading = 0; 344 | music = 1; 345 | digitalWrite(MULTICOLOUR_R, 0); 346 | digitalWrite(MULTICOLOUR_G, 1); 347 | digitalWrite(MULTICOLOUR_B, 0); 348 | strip.setPixelColor(0, strip.Color(0, 0, 0, 255)); 349 | strip.show(); 350 | } else if (music <= 0 and state != STATE_TURN_OFF1 and state != STATE_TURN_OFF2 and state != STATE_TURN_OFF) { 351 | if (state == STATE_GO_SLEEP or state == STATE_SLEEP or state == STATE_GO_SLEEP2 or state == STATE_SLEEP2 or state == STATE_KEEP_OFF){ 352 | state = STATE_TURN_OFF; 353 | } else if (state == STATE_GO_SLEEP1 or state == STATE_SLEEP1){ 354 | state = STATE_TURN_OFF2; 355 | } else { 356 | state = STATE_TURN_OFF1; 357 | } 358 | fading = 0; 359 | myservo.attach(SERVO_CONTROL); 360 | digitalWrite(SERVO_POWER, LOW); 361 | myservo.write(180); 362 | digitalWrite(MULTICOLOUR_R, 0); 363 | digitalWrite(MULTICOLOUR_G, 0); 364 | digitalWrite(MULTICOLOUR_B, 1); 365 | strip.setPixelColor(0, strip.Color(0, 0, 0, 255)); 366 | strip.show(); 367 | } 368 | timeout = 73; 369 | } else { 370 | if (switch_state == true){//detect change 371 | switch_state = false; 372 | telegram("Switched off!"); 373 | } 374 | 375 | if (fading == 0) { 376 | fading = 1; 377 | } 378 | 379 | if (state == STATE_PLAY or state == STATE_TURN_OFF1 or state == STATE_TURN_OFF2 or (state == STATE_KEEP_OFF and timeout == 0)){ 380 | if (state == STATE_PLAY){ 381 | state = STATE_DEEPSLEEP; 382 | music = 0; 383 | noTone(SPEAKER); 384 | } else if (state == STATE_TURN_OFF1) { 385 | state = STATE_GO_SLEEP1; 386 | } else if (state == STATE_TURN_OFF2) { 387 | state = STATE_GO_SLEEP2; 388 | } else { 389 | state = STATE_GO_SLEEP; 390 | } 391 | digitalWrite(MULTICOLOUR_R, 1); 392 | digitalWrite(MULTICOLOUR_G, 0); 393 | digitalWrite(MULTICOLOUR_B, 0); 394 | strip.setPixelColor(0, strip.Color(0, 0, 0)); 395 | myservo.write(50); 396 | strip.show(); 397 | timeout = 23; 398 | } 399 | 400 | if (state == STATE_TURN_OFF){ 401 | state = STATE_KEEP_OFF; 402 | digitalWrite(MULTICOLOUR_R, 1); 403 | digitalWrite(MULTICOLOUR_G, 1); 404 | digitalWrite(MULTICOLOUR_B, 0); 405 | myservo.attach(SERVO_CONTROL); 406 | digitalWrite(SERVO_POWER, LOW); 407 | myservo.write(120); 408 | timeout = 42; 409 | } 410 | 411 | if (timeout == 0){ 412 | if (state == STATE_STARTUP){ 413 | state = STATE_DEEPSLEEP; 414 | myservo.detach(); 415 | digitalWrite(SERVO_POWER, HIGH); 416 | } else if (state == STATE_GO_SLEEP1 or state == STATE_GO_SLEEP2 or state == STATE_GO_SLEEP) { 417 | if (state == STATE_GO_SLEEP1){ 418 | state = STATE_SLEEP1; 419 | } else if (state == STATE_GO_SLEEP2){ 420 | state = STATE_SLEEP2; 421 | } else { 422 | state = STATE_SLEEP; 423 | } 424 | myservo.detach(); 425 | digitalWrite(SERVO_POWER, HIGH); 426 | timeout = 73; 427 | } else if(state == STATE_SLEEP1 or state == STATE_SLEEP2 or state == STATE_SLEEP) { 428 | state = STATE_DEEPSLEEP; 429 | } 430 | } 431 | } 432 | } 433 | --------------------------------------------------------------------------------