Components and supplies
ir distance sensor
NEMA 17 Stepper Motor
433Mhz transmitter and receiver with transistor
Arduino UNO
SparkFun Power Cell - LiPo Charger/Booster
Arduino Nano R3
Stepper motor driver board A4988
Raspberry Pi 3 Model B
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Raspbian
Project description
Code
Main Arduino Mega 2560 code
arduino
1#include "FastLED.h" 2#include "leds_lookup_table.h" 3#include <EEPROM.h> 4 5#define DEBUG 0 6#define SEND_RESPONSE 0 7 8#define READY_PIN 28 9#define SANTA_PIN 8 10#define DANCING_TREE_PIN 5 11#define TRAIN_PIN 39 //relay 3 12#define LIGHT_CHAIN_PIN 35 //relay 1 13#define SPOT_LIGHT_PIN 37 14#define FRONT_LIGHT_PIN 41 15#define LAP_COUNT_PIN 6 16#define BUS_GO_PIN 3 17#define BALLOON_PIN 9 18#define BUS_CHARGING_PIN 11 19 20 21#define NUM_LEDS 55 //number of total P9823's 22#define DATA_PIN 2 23#define FADE_DELAY 50 24#define FADE_TIME 2000 25#define CHANCE_SANTA_SOLO 20 //chance of a santa solo in percent 26 27#define PiSerial Serial1 28#define DebugSerial Serial 29 30//status bytes knnen werte von 1 bis 189 haben (0 = undefined) 31#define LED_START 1 32#define LED_END 55 33#define TEXT_EINGABE 124 34#define TWERKING_SANTA 69 35#define TRAIN 56 36#define LIGHT_CHAIN 57 37#define SPARKLING 58 38#define ANIMATIONS 59 39#define TREE_BLACKOUT 60 40#define DANCING_TREE 61 41#define BALLOON 62 42#define BUS 63 43 44#define LAP_COUNTER 190 45 46//info/data bytes von 192 bis 247 47#define OFF 192 48#define ON 193 49#define FARBEN_START 194 50#define FARBEN_END 210 51 52// response data bytes to PI in case of conflicts or errors 53#define OK 249 54#define BEREITS_AN 250 55#define BEREITS_AUS 251 56#define SPAM_SCHUTZ 252 //lnger warten zwischen befehlen 57#define CHARGING 253 58#define NOT_CHARGING 248 59 60#define DATA_ERROR_FIRST_BYTE 254 61#define DATA_ERROR_COLOR 255 62 63struct ledStepStruct { 64 int rStep, gStep, bStep; 65 boolean fade; 66}; 67 68byte data[2], responseData[2], rndLED, hueTemp; 69char text[31]; 70boolean newText, santaFlag, trainFlag, busFlag, lightChainFlag, sparklingFlag, sparkleOn, santaSoloFlag, pinActive = true, dancingTreeFlag, balloonFlag, balloonPinReseted = true, busCharging; 71const unsigned int fadeSteps = FADE_TIME / FADE_DELAY; 72unsigned long currentMillis, lastStatiUpdate, lastFadeTime, santaTime, trainTime, busTime, balloonTime, lightChainTime, sparklingTime, lastSparkleTime, lastLapCount, currentTime, trainActionTime, lastTrainAction, busActionTime, lastBusAction, dancingTreeTime; 73unsigned int lapCounter; 74 75CRGB leds[NUM_LEDS], ledsAim[NUM_LEDS], ledBefore; 76 77ledStepStruct ledsStep[NUM_LEDS]; 78 79void setup() { 80 PiSerial.begin(9600); 81 82 DebugSerial.begin(9600); 83 84 pinMode(READY_PIN, OUTPUT); 85 pinMode(SANTA_PIN, OUTPUT); 86 pinMode(TRAIN_PIN, OUTPUT); 87 pinMode(LIGHT_CHAIN_PIN, OUTPUT); 88 pinMode(SPOT_LIGHT_PIN, OUTPUT); 89 pinMode(FRONT_LIGHT_PIN, OUTPUT); 90 pinMode(LAP_COUNT_PIN, INPUT_PULLUP); 91 pinMode(DANCING_TREE_PIN, OUTPUT); 92 pinMode(BUS_GO_PIN, OUTPUT); 93 pinMode(BALLOON_PIN, OUTPUT); 94 pinMode(BUS_CHARGING_PIN, INPUT); 95 96 97 FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS); 98 FastLED.setBrightness(70); 99 FastLED.clear(); 100 FastLED.show(); 101 102 digitalWrite(READY_PIN, HIGH); 103 digitalWrite(SANTA_PIN, LOW); 104 digitalWrite(TRAIN_PIN, LOW); 105 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 106 digitalWrite(SPOT_LIGHT_PIN, LOW); 107 digitalWrite(FRONT_LIGHT_PIN, HIGH); 108 digitalWrite(DANCING_TREE_PIN, LOW); 109 digitalWrite(BUS_GO_PIN, LOW); 110 digitalWrite(BALLOON_PIN, LOW); 111 112 lightChainFlag = true; 113 //!!!!!!!!!!!!!!!!!!!!!!!! UNCOMMENT AFTER START OF PROJECT !!!!!!!!!!!!!!!!!!!!!! 114 lapCounter = 0; 115 EEPROM.put(0, lapCounter); 116 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 117 118 EEPROM.get(0, lapCounter); 119 Serial.println(lapCounter); 120} 121 122void loop() { 123 124 handleSerialCommunication(); 125 handleData(); 126 handleColorFade(); 127 handleControl(); 128 handleSparkling(); 129 handleLapCount(); 130 handleBusCharging(); 131 updateStati(); 132} 133 134void updateStati() { 135 if (millis() - lastStatiUpdate > 600000) { 136 lastStatiUpdate = millis(); 137 if (trainFlag) { 138 responseData[0] = TRAIN; 139 responseData[1] = ON; 140 PiSerial.write(responseData, 2); 141 PiSerial.flush(); 142 } 143 else { 144 responseData[0] = TRAIN; 145 responseData[1] = OFF; 146 PiSerial.write(responseData, 2); 147 PiSerial.flush(); 148 } 149 150 if (balloonFlag) { 151 responseData[0] = BALLOON; 152 responseData[1] = ON; 153 PiSerial.write(responseData, 2); 154 PiSerial.flush(); 155 } 156 else { 157 responseData[0] = BALLOON; 158 responseData[1] = OFF; 159 PiSerial.write(responseData, 2); 160 PiSerial.flush(); 161 } 162 163 if (busFlag) { 164 responseData[0] = BUS; 165 responseData[1] = ON; 166 PiSerial.write(responseData, 2); 167 PiSerial.flush(); 168 } 169 else { 170 responseData[0] = BUS; 171 responseData[1] = OFF; 172 PiSerial.write(responseData, 2); 173 PiSerial.flush(); 174 } 175 176 if (charging) { 177 responseData[0] = BUS; 178 responseData[1] = CHARGING; 179 PiSerial.write(responseData, 2); 180 PiSerial.flush(); 181 } 182 else { 183 responseData[0] = BUS; 184 responseData[1] = NOT_CHARGING; 185 PiSerial.write(responseData, 2); 186 PiSerial.flush(); 187 } 188 189 if (santaFlag) { 190 responseData[0] = TWERKING_SANTA; 191 responseData[1] = ON; 192 PiSerial.write(responseData, 2); 193 PiSerial.flush(); 194 } 195 else { 196 responseData[0] = TWERKING_SANTA; 197 responseData[1] = OFF; 198 PiSerial.write(responseData, 2); 199 PiSerial.flush(); 200 } 201 202 if (dancingTreeFlag) { 203 responseData[0] = DANCING_TREE; 204 responseData[1] = ON; 205 PiSerial.write(responseData, 2); 206 PiSerial.flush(); 207 } 208 else { 209 responseData[0] = DANCING_TREE; 210 responseData[1] = OFF; 211 PiSerial.write(responseData, 2); 212 PiSerial.flush(); 213 } 214 215 if (lightChainFlag) { 216 responseData[0] = LIGHT_CHAIN; 217 responseData[1] = ON; 218 PiSerial.write(responseData, 2); 219 PiSerial.flush(); 220 } 221 else { 222 responseData[0] = LIGHT_CHAIN; 223 responseData[1] = OFF; 224 PiSerial.write(responseData, 2); 225 PiSerial.flush(); 226 } 227 } 228} 229 230void handleBusCharging() { 231 //busCharging = false; 232 233 if (!digitalRead(BUS_CHARGING_PIN) && !busCharging) { 234 busCharging = true; 235 responseData[0] = BUS; 236 responseData[1] = CHARGING; 237 PiSerial.write(responseData, 2); 238 PiSerial.flush(); 239 } 240 else if (digitalRead(BUS_CHARGING_PIN) && busCharging) { 241 busCharging = false; 242 responseData[0] = BUS; 243 responseData[1] = NOT_CHARGING; 244 PiSerial.write(responseData, 2); 245 PiSerial.flush(); 246 } 247} 248 249void handleLapCount() { 250 currentTime = millis(); 251 if (!digitalRead(LAP_COUNT_PIN) && pinActive && currentTime - trainActionTime > 100) { 252 lapCounter++; 253 pinActive = false; 254 lastLapCount = currentTime; 255 PiSerial.print("LAP_COUNTER," + String(lapCounter)); 256 PiSerial.flush(); 257 EEPROM.put(0, lapCounter); 258 //Serial.println(lapCounter); 259 } 260 261 if (digitalRead(LAP_COUNT_PIN) && currentTime - lastLapCount > 2000) { 262 pinActive = true; 263 } 264} 265 266void handleSparkling() { 267 if (sparklingFlag) { 268 if (millis() - sparklingTime > 20000) { 269 sparklingFlag = false; 270 leds[rndLED] = ledBefore; 271 FastLED.show(); 272 sparkleOn = false; 273 } 274 else if (!sparkleOn && millis() - lastSparkleTime > 100) { 275 rndLED = random8(NUM_LEDS); 276 ledBefore = leds[rndLED]; 277 leds[rndLED] += CRGB::White; 278 FastLED.show(); 279 sparkleOn = true; 280 lastSparkleTime = millis(); 281 } 282 else if (sparkleOn && millis() - lastSparkleTime > 50) { 283 leds[rndLED] = ledBefore; 284 FastLED.show(); 285 sparkleOn = false; 286 lastSparkleTime = millis(); 287 } 288 } 289} 290 291void handleControl() { 292 293 if (dancingTreeFlag) { 294 if (dancingTreeTime == 0) { 295 //Serial.println("Set dancing tree pin high"); 296 responseData[0] = DANCING_TREE; 297 responseData[1] = ON; 298 PiSerial.write(responseData, 2); 299 PiSerial.flush(); 300 digitalWrite(DANCING_TREE_PIN, HIGH); 301 dancingTreeTime = millis(); 302 } 303 else if (millis() - dancingTreeTime > 18000) { 304 digitalWrite(DANCING_TREE_PIN, LOW); 305 dancingTreeTime = 0; 306 dancingTreeFlag = false; 307 responseData[0] = DANCING_TREE; 308 responseData[1] = OFF; 309 PiSerial.write(responseData, 2); 310 PiSerial.flush(); 311 } 312 } 313 314 if (balloonFlag) { 315 if (balloonTime == 0) { 316 responseData[0] = BALLOON; 317 responseData[1] = ON; 318 PiSerial.write(responseData, 2); 319 PiSerial.flush(); 320 digitalWrite(BALLOON_PIN, HIGH); 321 balloonPinReseted = false; 322 balloonTime = millis(); 323 } 324 else if (millis() - balloonTime > 50000) { 325 balloonTime = 0; 326 balloonFlag = false; 327 responseData[0] = BALLOON; 328 responseData[1] = OFF; 329 PiSerial.write(responseData, 2); 330 PiSerial.flush(); 331 } 332 else if (millis() - balloonTime > 1000 && !balloonPinReseted) { 333 balloonPinReseted = true; 334 digitalWrite(BALLOON_PIN, LOW); 335 } 336 } 337 338 if (santaFlag) { 339 if (santaTime == 0) { 340 responseData[0] = TWERKING_SANTA; 341 responseData[1] = ON; 342 PiSerial.write(responseData, 2); 343 PiSerial.flush(); 344 digitalWrite(SANTA_PIN, HIGH); 345 santaTime = millis(); 346 } 347 else if (millis() - santaTime > 20000) { 348 digitalWrite(SANTA_PIN, LOW); 349 santaTime = 0; 350 santaFlag = false; 351 responseData[0] = TWERKING_SANTA; 352 responseData[1] = OFF; 353 PiSerial.write(responseData, 2); 354 PiSerial.flush(); 355 } 356 } 357 358 else if (santaSoloFlag) { 359 360 if (trainFlag) { 361 trainFlag = false; 362 digitalWrite(TRAIN_PIN, LOW); 363 responseData[0] = TRAIN; 364 responseData[1] = OFF; 365 PiSerial.write(responseData, 2); 366 PiSerial.flush(); 367 368 } 369 if (lightChainFlag) { 370 lightChainFlag = false; 371 digitalWrite(LIGHT_CHAIN_PIN, LOW); 372 } 373 if (busFlag) { 374 busFlag = false; 375 digitalWrite(BUS_GO_PIN, LOW); 376 responseData[0] = BUS; 377 responseData[1] = OFF; 378 PiSerial.write(responseData, 2); 379 PiSerial.flush(); 380 } 381 if (dancingTreeFlag) { 382 dancingTreeFlag = false; 383 digitalWrite(DANCING_TREE_PIN, LOW); 384 } 385 responseData[0] = DANCING_TREE; 386 responseData[1] = OFF; 387 PiSerial.write(responseData, 2); 388 PiSerial.flush(); 389 390 FastLED.clear(); 391 FastLED.show(); 392 393 digitalWrite(FRONT_LIGHT_PIN, LOW); 394 FastLED.delay(1000); 395 digitalWrite(SPOT_LIGHT_PIN, HIGH); 396 FastLED.delay(500); 397 398 digitalWrite(SANTA_PIN, HIGH); 399 FastLED.delay(50); 400 digitalWrite(SANTA_PIN, LOW); 401 402 403 /* 404 for (int i; i < 500; i++) { 405 fill_rainbow(leds, NUM_LEDS, hueTemp, 1); 406 FastLED.show(); 407 hueTemp++; 408 FastLED.delay(25); 409 } 410 FastLED.clear(); 411 FastLED.show(); 412 */ 413 for ( int k = 0; k < 20; k++ ) { 414 triangle(); 415 } 416 417 418 digitalWrite(SPOT_LIGHT_PIN, LOW); 419 420 dancingTreeTime = 0; 421 422 digitalWrite(SANTA_PIN, HIGH); 423 FastLED.delay(50); 424 digitalWrite(SANTA_PIN, LOW); 425 santaFlag = false; 426 santaTime = 0; 427 428 responseData[0] = TWERKING_SANTA; 429 responseData[1] = OFF; 430 PiSerial.write(responseData, 2); 431 PiSerial.flush(); 432 433 FastLED.delay(1000); //1000 434 435 digitalWrite(FRONT_LIGHT_PIN, HIGH); 436 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 437 lightChainFlag = true; 438 responseData[0] = LIGHT_CHAIN; 439 responseData[1] = ON; 440 PiSerial.write(responseData, 2); 441 PiSerial.flush(); 442 443 444 for (byte i = 0; i < NUM_LEDS; i++) { 445 leds[i] = ledsAim[i]; 446 } 447 FastLED.show(); 448 santaSoloFlag = false; 449 digitalWrite(READY_PIN, HIGH); 450 } 451 452 if (trainFlag) { 453 if (millis() - trainTime > 30000) { 454 trainFlag = false; 455 digitalWrite(TRAIN_PIN, LOW); 456 responseData[0] = TRAIN; 457 responseData[1] = OFF; 458 PiSerial.write(responseData, 2); 459 PiSerial.flush(); 460 } 461 } 462 463 if (busFlag) { 464 if (millis() - busTime > 30000) { 465 busFlag = false; 466 digitalWrite(BUS_GO_PIN, LOW); 467 responseData[0] = BUS; 468 responseData[1] = OFF; 469 PiSerial.write(responseData, 2); 470 PiSerial.flush(); 471 } 472 } 473 474 if (!lightChainFlag) { 475 if (millis() - lightChainTime > 60000) { 476 lightChainFlag = true; 477 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 478 responseData[0] = LIGHT_CHAIN; 479 responseData[1] = ON; 480 PiSerial.write(responseData, 2); 481 PiSerial.flush(); 482 } 483 } 484 485 486} 487 488void handleColorFade() { 489 currentMillis = millis(); 490 if (currentMillis - lastFadeTime >= FADE_DELAY) { 491 492 for (byte i = 0; i < NUM_LEDS; i++) { 493 if (ledsStep[i].fade) { 494 ledsStep[i].fade = false; 495 if (leds[i].r != ledsAim[i].r) { 496 ledsStep[i].fade = true; 497 int rTemp = (int)leds[i].r + (int)ledsStep[i].rStep; 498 if ((ledsStep[i].rStep > 0 && rTemp > ledsAim[i].r) || (ledsStep[i].rStep < 0 && rTemp < ledsAim[i].r) || rTemp > 255 || rTemp < 0) leds[i].r = ledsAim[i].r; 499 else leds[i].r = rTemp; 500 501 if ((ledsStep[i].rStep > 0 && leds[i].r > ledsAim[i].r) || (ledsStep[i].rStep < 0 && leds[i].r < ledsAim[i].r)) leds[i].r = ledsAim[i].r; 502 } 503 if (leds[i].g != ledsAim[i].g) { 504 ledsStep[i].fade = true; 505 int gTemp = (int)leds[i].g + (int)ledsStep[i].gStep; 506 if ((ledsStep[i].gStep > 0 && gTemp > ledsAim[i].g) || (ledsStep[i].gStep < 0 && gTemp < ledsAim[i].g) || gTemp > 255 || gTemp < 0) leds[i].g = ledsAim[i].g; 507 else leds[i].g = gTemp; 508 } 509 if (leds[i].b != ledsAim[i].b) { 510 ledsStep[i].fade = true; 511 int bTemp = (int)leds[i].b + (int)ledsStep[i].bStep; 512 if ((ledsStep[i].bStep > 0 && bTemp > ledsAim[i].b) || (ledsStep[i].bStep < 0 && bTemp < ledsAim[i].b) || bTemp > 255 || bTemp < 0) leds[i].b = ledsAim[i].b; 513 else leds[i].b = bTemp; 514 } 515 516 } 517 } 518 FastLED.show(); 519 lastFadeTime = currentMillis; 520 } 521 522 523} 524 525void handleSerialCommunication() { 526 if (PiSerial.available() > 0) { //if there's any serial data 527 528 529 if (PiSerial.peek() >= 1 && PiSerial.peek() <= 191) { //if first data byte is valid 530 PiSerial.readBytes(data, 2); 531#if DEBUG 532 DebugSerial.println("Empfangen: " + (String)data[0] + ", " + (String)data[1]); 533#endif 534 } 535 else { //else; first data byte is invalid (0 or greater than 191) 536 byte errorMessage = PiSerial.read(); 537 538#if SEND_RESPONSE 539 responseData[0] = DATA_ERROR_FIRST_BYTE; 540 responseData[1] = errorMessage; 541 PiSerial.write(responseData, 2); 542#endif 543 544 545#if DEBUG 546 DebugSerial.print("DATA_ERROR_FIRST_BYTE: "); 547 DebugSerial.println(errorMessage); 548#endif 549 } 550 } 551} 552 553void handleData() { 554 if (data[0] >= LED_START && data[0] <= LED_END) { //if data is LED data 555 if (data[1] < OFF || data[1] > FARBEN_END) { //if second data byte has invalid color 556 //invalid color/data byte 557 558#if SEND_RESPONSE 559 responseData[0] = DATA_ERROR_COLOR; 560 responseData[1] = data[1]; 561 PiSerial.write(responseData, 2); 562#endif 563 564#if DEBUG 565 DebugSerial.print("DATA_ERROR_INVALID_COLOR: "); 566 DebugSerial.println(data[1]); 567#endif 568 569 } 570 else { //color value is valid 571 //led mit farbe (in data[1]) ansteuern 572 573 byte i = data[0] - 1; 574 575 if (data[1] == OFF) ledsAim[i] = CRGB::Black; 576 else if (data[1] == ON) ledsAim[i] = CRGB::White; //hier warmwei einfgen 577 else ledsAim[i].setHue((data[1] - 194) * 16); //set aim color for led to chosen value 578 579 setLEDFade(i); 580 581 } 582 data[0] = 0; 583 data[1] = 0; 584 } 585 586 else if (data[0] == TWERKING_SANTA) { 587 588 589 if (!santaFlag) { 590 digitalWrite(READY_PIN, LOW); 591 592 if (random8(100) > CHANCE_SANTA_SOLO - 1) { 593 santaFlag = true; 594 digitalWrite(READY_PIN, HIGH); 595 596 } 597 else santaSoloFlag = true; 598 } 599#if SEND_RESPONSE 600 else { 601 responseData[0] = TWERKING_SANTA; 602 responseData[1] = BEREITS_AN; 603 PiSerial.write(responseData, 2); 604 } 605#endif 606 607 data[0] = 0; 608 data[1] = 0; 609 610 } 611 612 else if (data[0] == BALLOON) { 613 if (!balloonFlag) { 614 balloonFlag = true; 615 } 616 data[0] = 0; 617 data[1] = 0; 618 } 619 620 else if (data[0] == DANCING_TREE) { 621 622 if (!dancingTreeFlag) { 623 dancingTreeFlag = true; 624 } 625#if SEND_RESPONSE 626 else { 627 responseData[0] = DANCING_TREE; 628 responseData[1] = BEREITS_AN; 629 PiSerial.write(responseData, 2); 630 } 631#endif 632 633 data[0] = 0; 634 data[1] = 0; 635 636 } 637 638 else if ( data[0] == BUS) { 639 currentTime = millis(); 640 if (currentTime - lastBusAction > 1000) { 641 if (data[1] == OFF && busFlag && digitalRead(BUS_CHARGING_PIN)) { 642 busActionTime = currentTime; 643 lastBusAction = busActionTime; 644 digitalWrite(BUS_GO_PIN, LOW); 645 busFlag = false; 646 responseData[0] = BUS; 647 responseData[1] = OFF; 648 PiSerial.write(responseData, 2); 649 PiSerial.flush(); 650 } 651 652 else if (data[1] == ON && !busFlag && digitalRead(BUS_CHARGING_PIN)) { 653 busActionTime = currentTime; 654 lastBusAction = busActionTime; 655 digitalWrite(BUS_GO_PIN, HIGH); 656 busFlag = true; 657 busTime = millis(); 658 responseData[0] = BUS; 659 responseData[1] = ON; 660 PiSerial.write(responseData, 2); 661 PiSerial.flush(); 662 } 663 } 664 data[0] = 0; 665 data[1] = 0; 666 } 667 668 else if ( data[0] == TRAIN) { 669 currentTime = millis(); 670 if (currentTime - lastTrainAction > 1000) { 671 if (data[1] == OFF && trainFlag) { 672 trainActionTime = currentTime; 673 lastTrainAction = trainActionTime; 674 digitalWrite(TRAIN_PIN, LOW); 675 trainFlag = false; 676 responseData[0] = TRAIN; 677 responseData[1] = OFF; 678 PiSerial.write(responseData, 2); 679 PiSerial.flush(); 680 } 681 682 else if (data[1] == ON && !trainFlag) { 683 trainActionTime = currentTime; 684 lastTrainAction = trainActionTime; 685 digitalWrite(TRAIN_PIN, HIGH); 686 trainFlag = true; 687 trainTime = millis(); 688 responseData[0] = TRAIN; 689 responseData[1] = ON; 690 PiSerial.write(responseData, 2); 691 PiSerial.flush(); 692 } 693#if SEND_RESPONSE 694 else if (data[1] == ON && trainFlag) { 695 responseData[0] = TRAIN; 696 responseData[1] = BEREITS_AN; 697 PiSerial.write(responseData, 2); 698 } 699 else if (data[1] == OFF && !trainFlag) { 700 responseData[0] = TRAIN; 701 responseData[1] = BEREITS_AUS; 702 PiSerial.write(responseData, 2); 703 } 704#endif 705 } 706#if SEND_RESPONSE 707 else { 708 responseData[0] = TRAIN; 709 responseData[1] = SPAM_SCHUTZ; 710 PiSerial.write(responseData, 2); 711 } 712#endif 713 data[0] = 0; 714 data[1] = 0; 715 716 717 } 718 719 else if (data[0] == LIGHT_CHAIN) { 720 if (data[1] == OFF && lightChainFlag) { 721 digitalWrite(LIGHT_CHAIN_PIN, LOW); 722 lightChainFlag = false; 723 lightChainTime = millis(); 724 responseData[0] = LIGHT_CHAIN; 725 responseData[1] = OFF; 726 PiSerial.write(responseData, 2); 727 PiSerial.flush(); 728 } 729 730 else if (data[1] == ON && !lightChainFlag) { 731 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 732 lightChainFlag = true; 733 responseData[0] = LIGHT_CHAIN; 734 responseData[1] = ON; 735 PiSerial.write(responseData, 2); 736 PiSerial.flush(); 737 } 738#if SEND_RESPONSE 739 else if (data[1] == ON && lightChainFlag) { 740 responseData[0] = LIGHT_CHAIN; 741 responseData[1] = BEREITS_AN; 742 PiSerial.write(responseData, 2); 743 } 744 else if (data[1] == OFF && !lightChainFlag) { 745 responseData[0] = LIGHT_CHAIN; 746 responseData[1] = BEREITS_AUS; 747 PiSerial.write(responseData, 2); 748 } 749#endif 750 751 data[0] = 0; 752 data[1] = 0; 753 } 754 755 else if (data[0] == SPARKLING) { 756 if (data[1] == ON && !sparklingFlag) { 757 sparklingFlag = true; 758 sparklingTime = millis(); 759 } 760 761 else if (data[1] == OFF && sparklingFlag) { 762 sparklingFlag = false; 763 } 764#if SEND_RESPONSE 765 else if (data[1] == ON && sparklingFlag) { 766 responseData[0] = SPARKLING; 767 responseData[1] = BEREITS_AN; 768 PiSerial.write(responseData, 2); 769 } 770 else if (data[1] == OFF && !sparklingFlag) { 771 responseData[0] = SPARKLING; 772 responseData[1] = BEREITS_AUS; 773 PiSerial.write(responseData, 2); 774 } 775#endif 776 777 data[0] = 0; 778 data[1] = 0; 779 } 780 781 else if (data[0] == ANIMATIONS) { 782 digitalWrite(READY_PIN, LOW); 783 animations(); 784 digitalWrite(READY_PIN, HIGH); 785 data[0] = 0; 786 data[1] = 0; 787 } 788 789 else if (data[0] == TREE_BLACKOUT) { 790 791 for (byte i = 0; i < NUM_LEDS; i++) { 792 ledsAim[i] = CRGB::Black; 793 setLEDFade(i); 794 } 795 796 data[0] = 0; 797 data[1] = 0; 798 } 799} 800 801void animations() { 802 fillSpiralCCW(); 803 fillSpiralCW(); 804 fillSpiralCCW(); 805 fillSpiralCW(); 806 807 for (byte i = 0; i < NUM_LEDS; i++) { 808 leds[i] = ledsAim[i]; 809 } 810 FastLED.show(); 811} 812 813void setLEDFade(byte i) { 814 if (leds[i] != ledsAim[i]) { 815 ledsStep[i].fade = true; 816 817 if (ledsAim[i].r != leds[i].r) { 818 ledsStep[i].rStep = ((int)ledsAim[i].r - (int)leds[i].r) / (int)fadeSteps; 819 if (ledsStep[i].rStep == 0) { 820 if (ledsAim[i].r > leds[i].r) ledsStep[i].rStep = 1; 821 else ledsStep[i].rStep = -1; 822 } 823#if DEBUG 824 DebugSerial.println("rStep: " + (String)ledsStep[i].rStep); //debug 825#endif 826 } 827 if (ledsAim[i].g != leds[i].g) { 828 ledsStep[i].gStep = ((int)ledsAim[i].g - (int)leds[i].g) / (int)fadeSteps; 829 if (ledsStep[i].gStep == 0) { 830 if (ledsAim[i].g > leds[i].g) ledsStep[i].gStep = 1; 831 else ledsStep[i].gStep = -1; 832 } 833#if DEBUG 834 DebugSerial.println("gStep: " + (String)ledsStep[i].gStep); //debug 835#endif 836 } 837 if (ledsAim[i].b != leds[i].b) { 838 ledsStep[i].bStep = ((int)ledsAim[i].b - (int)leds[i].b) / (int)fadeSteps; 839 if (ledsStep[i].bStep == 0) { 840 if (ledsAim[i].b > leds[i].b) ledsStep[i].bStep = 1; 841 else ledsStep[i].bStep = -1; 842 } 843#if DEBUG 844 DebugSerial.println("bStep: " + (String)ledsStep[i].bStep); //debug 845#endif 846 } 847 848 } 849} 850 851 852void fillSpiralCCW() { 853 854 FastLED.clear(); 855 FastLED.show(); 856 857 for (byte i = 0; i < (sizeof(spiralCCW) / sizeof(byte)); i++) { 858 leds[spiralCCW[i]].setHue(hueTemp); 859 FastLED.show(); 860 FastLED.delay(30); 861 hueTemp += 2; 862 } 863 864 for (byte i = (sizeof(spiralCCW) / sizeof(byte)) - 1; i > 0; i--) { 865 leds[spiralCCW[i]] = CRGB::Black; 866 FastLED.show(); 867 FastLED.delay(30); 868 } 869} 870 871void fillSpiralCW() { 872 873 FastLED.clear(); 874 FastLED.show(); 875 876 for (byte i = 0; i < (sizeof(spiralCW) / sizeof(byte)); i++) { 877 leds[spiralCW[i]].setHue(hueTemp); 878 FastLED.show(); 879 FastLED.delay(30); 880 hueTemp += 2; 881 } 882 883 for (byte i = (sizeof(spiralCW) / sizeof(byte)) - 1; i > 0; i--) { 884 leds[spiralCW[i]] = CRGB::Black; 885 FastLED.show(); 886 FastLED.delay(30); 887 } 888} 889 890 891void frameMarquee() { 892 FastLED.clear(); 893 FastLED.show(); 894 895 for (int j = 0; j < 400; j++) { 896 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 897 leds[frame[i]].setHue(hueTemp); 898 hueTemp += 2; 899 } 900 hueTemp = 2 * j; 901 FastLED.show(); 902 FastLED.delay(40); 903 } 904 FastLED.clear(); 905 FastLED.show(); 906} 907 908void innerFrame() { 909 for (int j = 0; j < 15; j++) { 910 911 hueTemp += 40; 912 913 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 914 leds[frame[i]].setHue(hueTemp); 915 } 916 FastLED.show(); 917 FastLED.delay(200); 918 919 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 920 leds[frame[i]] = CRGB::Black; 921 } 922 923 hueTemp += 40; 924 925 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); i++) { 926 leds[inner[i]].setHue(hueTemp); 927 } 928 FastLED.show(); 929 FastLED.delay(200); 930 931 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); i++) { 932 leds[inner[i]] = CRGB::Black; 933 } 934 } 935 FastLED.clear(); 936 FastLED.show(); 937} 938 939void triangle() { 940 hueTemp += 16; 941 for (byte i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 942 leds[triangle1[i]].setHue(hueTemp); 943 } 944 FastLED.show(); 945 FastLED.delay(150); 946 for (byte i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 947 leds[triangle1[i]] = CRGB::Black; 948 } 949 hueTemp += 16; 950 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 951 leds[triangle2[i]].setHue(hueTemp); 952 } 953 FastLED.show(); 954 FastLED.delay(150); 955 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 956 leds[triangle2[i]] = CRGB::Black; 957 } 958 hueTemp += 16; 959 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); i++) { 960 leds[triangle3[i]].setHue(hueTemp); 961 } 962 FastLED.show(); 963 FastLED.delay(150); 964 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); i++) { 965 leds[triangle3[i]] = CRGB::Black; 966 } 967 hueTemp += 16; 968 for (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 969 leds[triangle4[i]].setHue(hueTemp); 970 } 971 FastLED.show(); 972 FastLED.delay(150); 973 for (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 974 leds[triangle4[i]] = CRGB::Black; 975 } 976 977} 978 979
Telegram Bot Pyhton code
python
1import time 2import telepot 3from telepot.loop import MessageLoop 4import requests 5import datetime 6import pickle 7import os 8import ftplib 9import serial 10import struct 11import emoji 12 13 14TOKEN = "###ENTER_YOUR_BOT_TOKEN_HERE###" 15 16 17t = datetime.datetime.now() 18 19ser = serial.Serial ("/dev/serial0") #Open named port on pi 3 you need to activate serial and disable bluetooth 20ser.baudrate = 9600 21 22#### Load Files #### 23 24if os.path.isfile("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log"): 25 text_log = pickle.load(open("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log", "rb")) 26else: 27 text_log = [] 28 29#### 30 31if os.path.isfile("logs/stats.log"): 32 stats = pickle.load(open("logs/stats.log", "rb")) 33 #print(stats) 34else: 35 stats = {"users": 0, "messages": 0, "locations": 0} 36 37#### 38 39if os.path.isfile("logs/chat_ids.log"): 40 chat_ids = pickle.load(open("logs/chat_ids.log", "rb")) 41else: 42 chat_ids = [] 43 44#### 45 46if os.path.isfile("logs/block_list.log"): 47 block_list = pickle.load(open("logs/block_list.log", "rb")) 48else: 49 block_list = [] 50 51#### 52 53messages_buffer = ["www.ControlMyXMasTree.com\ 54"] 55last_text_sent = 0 56last_clock_sent = -600 57 58admins = [] ######ENTER ALL ADMIN CHAT_IDs HERE 59 60stream_delay = 5 61 62def remove_emoji(text): 63 return emoji.get_emoji_regexp().sub(u'', text) 64 65def log_to_txt(date): 66 if os.path.isfile("logs/" + str(date) + ".log"): 67 temp_log = pickle.load(open("logs/" + str(date) + ".log", "rb")) 68 txt_file = open("**logs-location-locally**" + str(date) + ".txt", "w") 69 for line in temp_log: 70 txt_file.write(str(line) + "\ 71") 72 txt_file.close() 73 return "SUCCESS" 74 75def handle_telegram(msg): 76 global messages_buffer 77 global stream_delay 78 global text_log 79 global stats 80 global chat_ids 81 global admins 82 global block_list 83 global t 84 85 t = datetime.datetime.now() 86 content_type, chat_type, chat_id = telepot.glance(msg) 87 #print(content_type, chat_type, chat_id) 88 89 if content_type == 'text': 90 #bot.sendMessage(chat_id, msg['text']) 91 92 ############ START ############ 93 if msg['text'] == "/start": 94 bot.sendMessage(chat_id, " Hey there, " + msg["chat"]["first_name"] + ".\ 95Send /help for information" 96 " on how to use this bot.") 97 if chat_id not in chat_ids: 98 chat_ids.append(chat_id) 99 pickle.dump(chat_ids, open("logs/chat_ids.log", "wb")) 100 stats["users"] += 1 101 pickle.dump(stats, open("logs/stats.log", "wb")) 102 103 ############ HELP ############ 104 elif msg['text'] == "/help": 105 bot.sendMessage(chat_id, "\ 106To send text to the display, " 107 "use: /text followed by your Message (for example: /text Santa rocks!).\ 108" 109 "To display the current weather in your area, simply send me your location " 110 "(Only on mobile, click paper-clip icon on bottom left).") 111 112 ############ TEXT ############ 113 elif (msg['text'].startswith("/text") or msg['text'].startswith("/Text")) and chat_id not in block_list: 114 msg['text'] = msg['text'][6:] 115 116 msg['text'] = remove_emoji(msg['text']) 117 118 if len(msg['text']) >= 2 and len(msg['text']) <= 75: 119 display_name = msg["chat"]["first_name"] 120 if len(display_name) > 20: 121 display_name = display_name[:20] + "." 122 123 display_text = display_name + ": " + msg['text'] 124 message_time = datetime.datetime.fromtimestamp(msg['date']) 125 time = message_time.strftime("%H:%M:%S") 126 #print(time) 127 print(display_text) 128 messages_buffer.append(display_text + "\ 129") 130 131 bot.sendMessage(chat_id, " Your message will be displayed in approx. " 132 + str((len(messages_buffer) - 1) * 20 + stream_delay) + " seconds.", 133 reply_to_message_id=msg["message_id"]) 134 135 try: 136 username = msg["chat"]["username"] 137 except: 138 username = "" 139 140 try: 141 last_name = msg["chat"]["last_name"] 142 except: 143 last_name = "" 144 145 if not os.path.isfile("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log"): 146 text_log = [] 147 148 text_log.append({"time": time, "chat_id": chat_id, "username": username, 149 "first_name": msg["chat"]["first_name"], "last_name": last_name, 150 "text": msg['text']}) 151 pickle.dump(text_log, open("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year)+ ".log", "wb")) 152 153 stats["messages"] += 1 154 pickle.dump(stats, open("logs/stats.log", "wb")) 155 156 elif len(msg['text']) < 2: 157 bot.sendMessage(chat_id, "Ooops.. Your message is too short. Please send at least two characters.") 158 159 elif len(msg['text']) > 75: 160 bot.sendMessage(chat_id, "Ooops.. Your message is too long. Please send a maximum of 75 characters.") 161 162 163 ############ ADMIN COMMANDS ############ 164 elif chat_id in admins: 165 166 ############ LOG ############ 167 if msg['text'].startswith("/log"): 168 msg['text'] = msg['text'][5:] 169 if not log_to_txt(msg["text"]) == "SUCCESS": 170 bot.sendMessage(chat_id, "No log file for this day available.") 171 return 172 ftp = ftplib.FTP('***ftp-server***', '***user-name***', '***password***') 173 try: 174 ftp.cwd("**directory**") 175 except: 176 bot.sendMessage(chat_id, "Can't reach ftp directory.") 177 return 178 179 f = open('***logs-location-locally***' + msg["text"] + ".txt", 'rb') 180 ftp.storbinary('STOR ' + msg["text"] + ".txt", f) 181 f.close() 182 ftp.quit() 183 bot.sendMessage(chat_id, "***logs-location***" + msg['text'] + ".txt") 184 185 ############ BULK ############ 186 elif msg['text'].startswith("/bulk"): 187 msg['text'] = msg['text'][6:] 188 for n in chat_ids: 189 bot.sendMessage(n, msg['text']) 190 191 ############ STATS ############ 192 elif msg['text'] == "/stats": 193 bot.sendMessage(chat_id, stats) 194 195 ############ MESSAGE TO SPCECIFIC CHAT_ID ############ 196 elif msg['text'].startswith("/message"): 197 msg['text'] = msg['text'][9:] 198 temp_chat_id, msg['text'] = msg['text'].split('#') 199 try: 200 bot.sendMessage(temp_chat_id, msg['text']) 201 except: 202 bot.sendMessage(chat_id, "Unable to send message.") 203 return 204 205 bot.sendMessage(chat_id, "Message send.") 206 207 ############ BLOCK LIST ############ 208 elif msg['text'] == "/block_list": 209 bot.sendMessage(chat_id, block_list) 210 211 ############ BLOCK ############ 212 elif msg['text'].startswith("/block"): 213 msg['text'] = msg['text'][7:] 214 215 try: 216 bot.sendMessage(int(msg['text']), " You've temporarily been blocked by an admin from sending " 217 "messages.") 218 except: 219 bot.sendMessage(chat_id, msg['text'] + " wrong chat_id!!!") 220 return 221 222 block_list.append(int(msg['text'])) 223 pickle.dump(block_list, open("logs/block_list.log", "wb")) 224 bot.sendMessage(chat_id, msg['text'] + " has been blocked!") 225 226 ############ UNBLOCK ############ 227 elif msg['text'].startswith("/unblock"): 228 msg['text'] = msg['text'][9:] 229 try: 230 block_list.remove(int(msg['text'])) 231 except: 232 bot.sendMessage(chat_id, "Chat ID not in block list.") 233 return 234 235 pickle.dump(block_list, open("logs/block_list.log", "wb")) 236 bot.sendMessage(chat_id, msg['text'] + " has been UN-blocked!") 237 238 ############ NO PERMISSION / INVALID COMMAND ############ 239 else: 240 bot.sendMessage(chat_id, " Not a valid command or you don't have permission to use it.") 241 242 ############ LOCATION / WEATHER ############ 243 elif content_type == "location": 244 #print("Location send.") 245 location_data = {'lat': msg['location']['latitude'], 'lon': msg['location']['longitude'], 246 'APPID': 'ENTER_YOUR_APP_ID'} 247 server = "http://api.openweathermap.org/data/2.5/weather" 248 r = requests.get(server, params=location_data).json() 249 #print(r) 250 celsius = r["main"]["temp"] - 273.2 251 252 weather_string = "Current weather in " + r["name"] + ": " + r["weather"][0]["description"].capitalize() + " at %.1f C" % (celsius) 253 messages_buffer.append(weather_string + "\ 254") 255 256 bot.sendPhoto(chat_id, 257 "http://www.controlmyxmastree.com/ui/weather_conditions/{}.png".format(r["weather"][0]["icon"]), 258 r["weather"][0]["description"].capitalize() + " in " + r["name"] + " at %.1f C" % (celsius)) 259 bot.sendMessage(chat_id, "This is the current weather at your location. It will also be displayed in the " 260 "live stream in aprox. " + str((len(messages_buffer)) * 20 + stream_delay) + 261 " seconds.") 262 263 stats["locations"] += 1 264 pickle.dump(stats, open("logs/stats.log", "wb")) 265 266def handle_serial(): 267 while(1): 268 global messages_buffer 269 global last_text_sent 270 global last_clock_sent 271 current_time = time.time() 272 273 if len(messages_buffer) > 0 and (current_time - last_text_sent > 20): #change to 20 274 ser.write(struct.pack('>B', 2)) 275 ser.write(str.encode(messages_buffer[0])) 276 last_text_sent = current_time 277 messages_buffer.pop(0) 278 279 if current_time - last_text_sent > 60: # change to 60 280 ser.write(struct.pack('>B', 2)) 281 ser.write(str.encode("To send custom text, open/download the 'Telegram' App and add: " 282 "@CMXT_Bot.\ 283")) 284 last_text_sent = current_time 285 286 if current_time - last_clock_sent > 600: ##change to 600 287 global t 288 t = datetime.datetime.now() 289 ser.write(struct.pack('>B', 1)) 290 ser.write(struct.pack('>B', t.hour)) 291 ser.write(struct.pack('>B', t.minute)) 292 ser.write(struct.pack('>B', t.second)) 293 last_clock_sent = current_time 294 295 296bot = telepot.Bot(TOKEN) 297MessageLoop(bot, handle_telegram).run_as_thread() 298print('Listening ...') 299 300# Keep the program running. 301handle_serial()
LEDs lookup table for animations
arduino
1byte frame[] = {52, 51, 43, 42, 32, 31, 19, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 25, 26, 38, 39, 47, 48, 54, 53}; 2 3byte inner[] = {50, 49, 44, 45, 46, 41, 40, 33, 34, 35, 36, 37, 30, 29, 28, 27, 20, 21, 22, 23, 24, 17, 16, 15, 14, 13, 12, 11, 10}; 4 5byte spiralCCW[] = {52, 51, 43, 32, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 38, 47, 48, 54, 53, 50, 44, 42, 33, 31, 19, 17, 6 16, 15, 14, 13, 12, 11, 10, 25, 26, 37, 39, 46, 49, 45, 41, 34, 30, 20, 21, 22, 23, 24, 7 27, 36, 40, 35, 29, 28, 35}; 8byte spiralCW[] = {52, 53, 54, 48, 47, 38, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 18, 32, 43, 51, 50, 49, 46, 39, 37, 26, 25, 10, 11, 12, 13, 14, 15, 16, 17, 19, 31, 9 33, 42, 44, 45, 40, 36, 27, 24, 23, 22, 21, 20, 30, 34, 41, 35, 28, 29}; 10 11byte triangle1[] = {35, 29, 28}; 12 13byte triangle2[] = {45, 41, 34, 30, 20, 21, 22, 23, 24, 27, 36, 40}; 14 15byte triangle3[] = {53, 50, 44, 42, 33, 31, 19, 17, 16, 15, 14, 13, 12, 11, 10, 25, 26, 37, 39, 46, 49}; 16 17byte triangle4[] = {52, 51, 43, 32, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 38, 47, 48, 54}; 18 19 20
Charging station code
arduino
1#include <RCSwitch.h> 2#include <Servo.h> 3#include <EEPROM.h> 4 5#define SERVO_PIN 6 6#define PHOTO_SENSOR_PIN 7 7#define RC_PIN 10 8 9#define CONTROL_PIN 2 10#define CHARGING_PIN 3 11 12#define ON_COMMAND 6247872 13#define OFF_COMMAND 6247728 14 15#define OPEN_POS 100 16#define CLOSED_POS 155 17 18#define SERVO_DELAY 250 19#define BUS_DELAY 200 20#define CHARGING_TIME 60000 21#define LAPS_UNTIL_CHARGE 10 22 23boolean charging, driving, lapCountPinSet, busInFrontOfStation; 24unsigned long lastActionTime, driveToChargeStart, lapCountPinTime, lastLapCount; 25unsigned int counter, chargingCounter, lastChargingLaps; 26 27RCSwitch rcSwitch = RCSwitch(); 28Servo myServo; 29 30void setup() { 31 Serial.begin(9600); 32 rcSwitch.enableTransmit(RC_PIN); 33 34 pinMode(PHOTO_SENSOR_PIN, INPUT); 35 pinMode(CONTROL_PIN, INPUT); 36 pinMode(CHARGING_PIN, OUTPUT); 37 38 digitalWrite(CHARGING_PIN, HIGH); 39 40 myServo.attach(SERVO_PIN); 41 myServo.write(OPEN_POS); 42 delay(SERVO_DELAY); 43 myServo.detach(); 44 45 //!!!!!!!!!!!!!!!!!!!!!!!! UNCOMMENT AFTER START OF PROJECT !!!!!!!!!!!!!!!!!!!!!! 46 //EEPROM.put(0, counter); 47 //EEPROM.put(sizeof(int), chargingCounter); 48 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 49 50 EEPROM.get(0, counter); 51 Serial.println("Laps: " + String(counter)); 52 53 EEPROM.get(sizeof(int), chargingCounter); 54 Serial.println("Charging cycles: " + String(chargingCounter)); 55 56 lastChargingLaps = counter; 57 Serial.println(digitalRead(PHOTO_SENSOR_PIN)); 58} 59 60void loop() { 61 62 handleLapCount(); 63 handleCharging(); 64 handleControl(); 65 66} 67 68void handleControl() { 69 if (digitalRead(CONTROL_PIN) && !driving) { 70 delay(20); 71 if (digitalRead(CONTROL_PIN)) { 72 Serial.println("ON COMMAND!"); 73 rcSwitch.send(ON_COMMAND, 24); 74 //delay(100); //COMMENT!!!! 75 driving = true; 76 lastActionTime = millis(); 77 } 78 } 79 else if (!digitalRead(CONTROL_PIN) && driving) { 80 delay(20); 81 if (!digitalRead(CONTROL_PIN)) { 82 Serial.println("OFF COMMAND!"); 83 rcSwitch.send(OFF_COMMAND, 24); 84 //delay(100); //COMMENT 85 driving = false; 86 lastActionTime = millis(); 87 } 88 } 89} 90 91void handleCharging() { 92 if (counter - lastChargingLaps >= LAPS_UNTIL_CHARGE && millis() - lastActionTime > 5000 && !driving) { 93 charging = true; 94 Serial.println("DRIVE TO CHARGING!"); 95 digitalWrite(CHARGING_PIN, LOW); 96 rcSwitch.send(ON_COMMAND, 24); 97 driving = true; 98 while (!digitalRead(PHOTO_SENSOR_PIN)); 99 driveToChargeStart = millis(); 100 while (digitalRead(PHOTO_SENSOR_PIN) && millis() - driveToChargeStart < 30000); 101 delay(80); 102 rcSwitch.send(OFF_COMMAND, 24); 103 if (!digitalRead(PHOTO_SENSOR_PIN)) { 104 delay(BUS_DELAY); 105 106 myServo.attach(SERVO_PIN); 107 myServo.write(CLOSED_POS); 108 109 delay(CHARGING_TIME); 110 111 myServo.write(OPEN_POS); 112 delay(SERVO_DELAY); 113 myServo.detach(); 114 115 rcSwitch.send(ON_COMMAND, 24); 116 delay(2000); 117 rcSwitch.send(OFF_COMMAND, 24); 118 119 chargingCounter++; 120 lastChargingLaps = counter; 121 EEPROM.put(sizeof(int), chargingCounter); 122 Serial.println("CHARGING CYCLES: " + String(chargingCounter)); 123 } 124 125 charging = false; 126 digitalWrite(CHARGING_PIN, HIGH); 127 driving = false; 128 } 129} 130 131void handleLapCount() { 132 if (busInFrontOfStation && digitalRead(PHOTO_SENSOR_PIN)) busInFrontOfStation = false; 133 134 if (!digitalRead(PHOTO_SENSOR_PIN) && !charging && (millis() - lastLapCount) > 2000 && !busInFrontOfStation) { 135 busInFrontOfStation = true; 136 //Serial.println("LAP COUNT DELTA: " + String(millis() - lastLapCount)); 137 lastLapCount = millis(); 138 counter++; 139 //digitalWrite(CHARGING_PIN, LOW); 140 lapCountPinTime = millis(); 141 lapCountPinSet = true; 142 143 EEPROM.put(0, counter); 144 Serial.println("LAPS: " + String(counter)); 145 } 146 if (lapCountPinSet && millis() - lapCountPinTime > 100) { 147 //digitalWrite(CHARGING_PIN, HIGH); 148 lapCountPinSet = false; 149 } 150} 151 152
LEDs lookup table for animations
arduino
1byte frame[] = {52, 51, 43, 42, 32, 31, 19, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 25, 26, 38, 39, 47, 48, 54, 53}; 2 3byte inner[] = {50, 49, 44, 45, 46, 41, 40, 33, 34, 35, 36, 37, 30, 29, 28, 27, 20, 21, 22, 23, 24, 17, 16, 15, 14, 13, 12, 11, 10}; 4 5byte spiralCCW[] = {52, 51, 43, 32, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 38, 47, 48, 54, 53, 50, 44, 42, 33, 31, 19, 17, 6 16, 15, 14, 13, 12, 11, 10, 25, 26, 37, 39, 46, 49, 45, 41, 34, 30, 20, 21, 22, 23, 24, 7 27, 36, 40, 35, 29, 28, 35}; 8byte spiralCW[] = {52, 53, 54, 48, 47, 38, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 18, 32, 43, 51, 50, 49, 46, 39, 37, 26, 25, 10, 11, 12, 13, 14, 15, 16, 17, 19, 31, 9 33, 42, 44, 45, 40, 36, 27, 24, 23, 22, 21, 20, 30, 34, 41, 35, 28, 29}; 10 11byte triangle1[] = {35, 29, 28}; 12 13byte triangle2[] = {45, 41, 34, 30, 20, 21, 22, 23, 24, 27, 36, 40}; 14 15byte triangle3[] = {53, 50, 44, 42, 33, 31, 19, 17, 16, 15, 14, 13, 12, 11, 10, 25, 26, 37, 39, 46, 49}; 16 17byte triangle4[] = {52, 51, 43, 32, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 38, 47, 48, 54}; 18 19 20
Telegram Bot Pyhton code
python
1import time 2import telepot 3from telepot.loop import MessageLoop 4import requests 5import datetime 6import pickle 7import os 8import ftplib 9import serial 10import struct 11import emoji 12 13 14TOKEN = "###ENTER_YOUR_BOT_TOKEN_HERE###" 15 16 17t = datetime.datetime.now() 18 19ser = serial.Serial ("/dev/serial0") #Open named port on pi 3 you need to activate serial and disable bluetooth 20ser.baudrate = 9600 21 22#### Load Files #### 23 24if os.path.isfile("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log"): 25 text_log = pickle.load(open("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log", "rb")) 26else: 27 text_log = [] 28 29#### 30 31if os.path.isfile("logs/stats.log"): 32 stats = pickle.load(open("logs/stats.log", "rb")) 33 #print(stats) 34else: 35 stats = {"users": 0, "messages": 0, "locations": 0} 36 37#### 38 39if os.path.isfile("logs/chat_ids.log"): 40 chat_ids = pickle.load(open("logs/chat_ids.log", "rb")) 41else: 42 chat_ids = [] 43 44#### 45 46if os.path.isfile("logs/block_list.log"): 47 block_list = pickle.load(open("logs/block_list.log", "rb")) 48else: 49 block_list = [] 50 51#### 52 53messages_buffer = ["www.ControlMyXMasTree.com\ 54"] 55last_text_sent = 0 56last_clock_sent = -600 57 58admins = [] ######ENTER ALL ADMIN CHAT_IDs HERE 59 60stream_delay = 5 61 62def remove_emoji(text): 63 return emoji.get_emoji_regexp().sub(u'', text) 64 65def log_to_txt(date): 66 if os.path.isfile("logs/" + str(date) + ".log"): 67 temp_log = pickle.load(open("logs/" + str(date) + ".log", "rb")) 68 txt_file = open("**logs-location-locally**" + str(date) + ".txt", "w") 69 for line in temp_log: 70 txt_file.write(str(line) + "\ 71") 72 txt_file.close() 73 return "SUCCESS" 74 75def handle_telegram(msg): 76 global messages_buffer 77 global stream_delay 78 global text_log 79 global stats 80 global chat_ids 81 global admins 82 global block_list 83 global t 84 85 t = datetime.datetime.now() 86 content_type, chat_type, chat_id = telepot.glance(msg) 87 #print(content_type, chat_type, chat_id) 88 89 if content_type == 'text': 90 #bot.sendMessage(chat_id, msg['text']) 91 92 ############ START ############ 93 if msg['text'] == "/start": 94 bot.sendMessage(chat_id, " Hey there, " + msg["chat"]["first_name"] + ".\ 95Send /help for information" 96 " on how to use this bot.") 97 if chat_id not in chat_ids: 98 chat_ids.append(chat_id) 99 pickle.dump(chat_ids, open("logs/chat_ids.log", "wb")) 100 stats["users"] += 1 101 pickle.dump(stats, open("logs/stats.log", "wb")) 102 103 ############ HELP ############ 104 elif msg['text'] == "/help": 105 bot.sendMessage(chat_id, "\ 106To send text to the display, " 107 "use: /text followed by your Message (for example: /text Santa rocks!).\ 108" 109 "To display the current weather in your area, simply send me your location " 110 "(Only on mobile, click paper-clip icon on bottom left).") 111 112 ############ TEXT ############ 113 elif (msg['text'].startswith("/text") or msg['text'].startswith("/Text")) and chat_id not in block_list: 114 msg['text'] = msg['text'][6:] 115 116 msg['text'] = remove_emoji(msg['text']) 117 118 if len(msg['text']) >= 2 and len(msg['text']) <= 75: 119 display_name = msg["chat"]["first_name"] 120 if len(display_name) > 20: 121 display_name = display_name[:20] + "." 122 123 display_text = display_name + ": " + msg['text'] 124 message_time = datetime.datetime.fromtimestamp(msg['date']) 125 time = message_time.strftime("%H:%M:%S") 126 #print(time) 127 print(display_text) 128 messages_buffer.append(display_text + "\ 129") 130 131 bot.sendMessage(chat_id, " Your message will be displayed in approx. " 132 + str((len(messages_buffer) - 1) * 20 + stream_delay) + " seconds.", 133 reply_to_message_id=msg["message_id"]) 134 135 try: 136 username = msg["chat"]["username"] 137 except: 138 username = "" 139 140 try: 141 last_name = msg["chat"]["last_name"] 142 except: 143 last_name = "" 144 145 if not os.path.isfile("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year) + ".log"): 146 text_log = [] 147 148 text_log.append({"time": time, "chat_id": chat_id, "username": username, 149 "first_name": msg["chat"]["first_name"], "last_name": last_name, 150 "text": msg['text']}) 151 pickle.dump(text_log, open("logs/" + str(t.day) + "_" + str(t.month) + "_" + str(t.year)+ ".log", "wb")) 152 153 stats["messages"] += 1 154 pickle.dump(stats, open("logs/stats.log", "wb")) 155 156 elif len(msg['text']) < 2: 157 bot.sendMessage(chat_id, "Ooops.. Your message is too short. Please send at least two characters.") 158 159 elif len(msg['text']) > 75: 160 bot.sendMessage(chat_id, "Ooops.. Your message is too long. Please send a maximum of 75 characters.") 161 162 163 ############ ADMIN COMMANDS ############ 164 elif chat_id in admins: 165 166 ############ LOG ############ 167 if msg['text'].startswith("/log"): 168 msg['text'] = msg['text'][5:] 169 if not log_to_txt(msg["text"]) == "SUCCESS": 170 bot.sendMessage(chat_id, "No log file for this day available.") 171 return 172 ftp = ftplib.FTP('***ftp-server***', '***user-name***', '***password***') 173 try: 174 ftp.cwd("**directory**") 175 except: 176 bot.sendMessage(chat_id, "Can't reach ftp directory.") 177 return 178 179 f = open('***logs-location-locally***' + msg["text"] + ".txt", 'rb') 180 ftp.storbinary('STOR ' + msg["text"] + ".txt", f) 181 f.close() 182 ftp.quit() 183 bot.sendMessage(chat_id, "***logs-location***" + msg['text'] + ".txt") 184 185 ############ BULK ############ 186 elif msg['text'].startswith("/bulk"): 187 msg['text'] = msg['text'][6:] 188 for n in chat_ids: 189 bot.sendMessage(n, msg['text']) 190 191 ############ STATS ############ 192 elif msg['text'] == "/stats": 193 bot.sendMessage(chat_id, stats) 194 195 ############ MESSAGE TO SPCECIFIC CHAT_ID ############ 196 elif msg['text'].startswith("/message"): 197 msg['text'] = msg['text'][9:] 198 temp_chat_id, msg['text'] = msg['text'].split('#') 199 try: 200 bot.sendMessage(temp_chat_id, msg['text']) 201 except: 202 bot.sendMessage(chat_id, "Unable to send message.") 203 return 204 205 bot.sendMessage(chat_id, "Message send.") 206 207 ############ BLOCK LIST ############ 208 elif msg['text'] == "/block_list": 209 bot.sendMessage(chat_id, block_list) 210 211 ############ BLOCK ############ 212 elif msg['text'].startswith("/block"): 213 msg['text'] = msg['text'][7:] 214 215 try: 216 bot.sendMessage(int(msg['text']), " You've temporarily been blocked by an admin from sending " 217 "messages.") 218 except: 219 bot.sendMessage(chat_id, msg['text'] + " wrong chat_id!!!") 220 return 221 222 block_list.append(int(msg['text'])) 223 pickle.dump(block_list, open("logs/block_list.log", "wb")) 224 bot.sendMessage(chat_id, msg['text'] + " has been blocked!") 225 226 ############ UNBLOCK ############ 227 elif msg['text'].startswith("/unblock"): 228 msg['text'] = msg['text'][9:] 229 try: 230 block_list.remove(int(msg['text'])) 231 except: 232 bot.sendMessage(chat_id, "Chat ID not in block list.") 233 return 234 235 pickle.dump(block_list, open("logs/block_list.log", "wb")) 236 bot.sendMessage(chat_id, msg['text'] + " has been UN-blocked!") 237 238 ############ NO PERMISSION / INVALID COMMAND ############ 239 else: 240 bot.sendMessage(chat_id, " Not a valid command or you don't have permission to use it.") 241 242 ############ LOCATION / WEATHER ############ 243 elif content_type == "location": 244 #print("Location send.") 245 location_data = {'lat': msg['location']['latitude'], 'lon': msg['location']['longitude'], 246 'APPID': 'ENTER_YOUR_APP_ID'} 247 server = "http://api.openweathermap.org/data/2.5/weather" 248 r = requests.get(server, params=location_data).json() 249 #print(r) 250 celsius = r["main"]["temp"] - 273.2 251 252 weather_string = "Current weather in " + r["name"] + ": " + r["weather"][0]["description"].capitalize() + " at %.1f C" % (celsius) 253 messages_buffer.append(weather_string + "\ 254") 255 256 bot.sendPhoto(chat_id, 257 "http://www.controlmyxmastree.com/ui/weather_conditions/{}.png".format(r["weather"][0]["icon"]), 258 r["weather"][0]["description"].capitalize() + " in " + r["name"] + " at %.1f C" % (celsius)) 259 bot.sendMessage(chat_id, "This is the current weather at your location. It will also be displayed in the " 260 "live stream in aprox. " + str((len(messages_buffer)) * 20 + stream_delay) + 261 " seconds.") 262 263 stats["locations"] += 1 264 pickle.dump(stats, open("logs/stats.log", "wb")) 265 266def handle_serial(): 267 while(1): 268 global messages_buffer 269 global last_text_sent 270 global last_clock_sent 271 current_time = time.time() 272 273 if len(messages_buffer) > 0 and (current_time - last_text_sent > 20): #change to 20 274 ser.write(struct.pack('>B', 2)) 275 ser.write(str.encode(messages_buffer[0])) 276 last_text_sent = current_time 277 messages_buffer.pop(0) 278 279 if current_time - last_text_sent > 60: # change to 60 280 ser.write(struct.pack('>B', 2)) 281 ser.write(str.encode("To send custom text, open/download the 'Telegram' App and add: " 282 "@CMXT_Bot.\ 283")) 284 last_text_sent = current_time 285 286 if current_time - last_clock_sent > 600: ##change to 600 287 global t 288 t = datetime.datetime.now() 289 ser.write(struct.pack('>B', 1)) 290 ser.write(struct.pack('>B', t.hour)) 291 ser.write(struct.pack('>B', t.minute)) 292 ser.write(struct.pack('>B', t.second)) 293 last_clock_sent = current_time 294 295 296bot = telepot.Bot(TOKEN) 297MessageLoop(bot, handle_telegram).run_as_thread() 298print('Listening ...') 299 300# Keep the program running. 301handle_serial()
Charging station code
arduino
1#include <RCSwitch.h> 2#include <Servo.h> 3#include <EEPROM.h> 4 5#define 6 SERVO_PIN 6 7#define PHOTO_SENSOR_PIN 7 8#define RC_PIN 10 9 10#define CONTROL_PIN 11 2 12#define CHARGING_PIN 3 13 14#define ON_COMMAND 6247872 15#define OFF_COMMAND 16 6247728 17 18#define OPEN_POS 100 19#define CLOSED_POS 155 20 21#define SERVO_DELAY 22 250 23#define BUS_DELAY 200 24#define CHARGING_TIME 60000 25#define LAPS_UNTIL_CHARGE 26 10 27 28boolean charging, driving, lapCountPinSet, busInFrontOfStation; 29unsigned 30 long lastActionTime, driveToChargeStart, lapCountPinTime, lastLapCount; 31unsigned 32 int counter, chargingCounter, lastChargingLaps; 33 34RCSwitch rcSwitch = RCSwitch(); 35Servo 36 myServo; 37 38void setup() { 39 Serial.begin(9600); 40 rcSwitch.enableTransmit(RC_PIN); 41 42 43 pinMode(PHOTO_SENSOR_PIN, INPUT); 44 pinMode(CONTROL_PIN, INPUT); 45 pinMode(CHARGING_PIN, 46 OUTPUT); 47 48 digitalWrite(CHARGING_PIN, HIGH); 49 50 myServo.attach(SERVO_PIN); 51 52 myServo.write(OPEN_POS); 53 delay(SERVO_DELAY); 54 myServo.detach(); 55 56 57 //!!!!!!!!!!!!!!!!!!!!!!!! UNCOMMENT AFTER START OF PROJECT !!!!!!!!!!!!!!!!!!!!!! 58 59 //EEPROM.put(0, counter); 60 //EEPROM.put(sizeof(int), chargingCounter); 61 62 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 63 64 65 EEPROM.get(0, counter); 66 Serial.println("Laps: " + String(counter)); 67 68 69 EEPROM.get(sizeof(int), chargingCounter); 70 Serial.println("Charging cycles: 71 " + String(chargingCounter)); 72 73 lastChargingLaps = counter; 74 Serial.println(digitalRead(PHOTO_SENSOR_PIN)); 75} 76 77void 78 loop() { 79 80 handleLapCount(); 81 handleCharging(); 82 handleControl(); 83 84} 85 86void 87 handleControl() { 88 if (digitalRead(CONTROL_PIN) && !driving) { 89 delay(20); 90 91 if (digitalRead(CONTROL_PIN)) { 92 Serial.println("ON COMMAND!"); 93 94 rcSwitch.send(ON_COMMAND, 24); 95 //delay(100); //COMMENT!!!! 96 driving 97 = true; 98 lastActionTime = millis(); 99 } 100 } 101 else if (!digitalRead(CONTROL_PIN) 102 && driving) { 103 delay(20); 104 if (!digitalRead(CONTROL_PIN)) { 105 Serial.println("OFF 106 COMMAND!"); 107 rcSwitch.send(OFF_COMMAND, 24); 108 //delay(100); //COMMENT 109 110 driving = false; 111 lastActionTime = millis(); 112 } 113 } 114} 115 116void 117 handleCharging() { 118 if (counter - lastChargingLaps >= LAPS_UNTIL_CHARGE && millis() 119 - lastActionTime > 5000 && !driving) { 120 charging = true; 121 Serial.println("DRIVE 122 TO CHARGING!"); 123 digitalWrite(CHARGING_PIN, LOW); 124 rcSwitch.send(ON_COMMAND, 125 24); 126 driving = true; 127 while (!digitalRead(PHOTO_SENSOR_PIN)); 128 driveToChargeStart 129 = millis(); 130 while (digitalRead(PHOTO_SENSOR_PIN) && millis() - driveToChargeStart 131 < 30000); 132 delay(80); 133 rcSwitch.send(OFF_COMMAND, 24); 134 if (!digitalRead(PHOTO_SENSOR_PIN)) 135 { 136 delay(BUS_DELAY); 137 138 myServo.attach(SERVO_PIN); 139 myServo.write(CLOSED_POS); 140 141 142 delay(CHARGING_TIME); 143 144 myServo.write(OPEN_POS); 145 delay(SERVO_DELAY); 146 147 myServo.detach(); 148 149 rcSwitch.send(ON_COMMAND, 24); 150 delay(2000); 151 152 rcSwitch.send(OFF_COMMAND, 24); 153 154 chargingCounter++; 155 lastChargingLaps 156 = counter; 157 EEPROM.put(sizeof(int), chargingCounter); 158 Serial.println("CHARGING 159 CYCLES: " + String(chargingCounter)); 160 } 161 162 charging = false; 163 164 digitalWrite(CHARGING_PIN, HIGH); 165 driving = false; 166 } 167} 168 169void 170 handleLapCount() { 171 if (busInFrontOfStation && digitalRead(PHOTO_SENSOR_PIN)) 172 busInFrontOfStation = false; 173 174 if (!digitalRead(PHOTO_SENSOR_PIN) && !charging 175 && (millis() - lastLapCount) > 2000 && !busInFrontOfStation) { 176 busInFrontOfStation 177 = true; 178 //Serial.println("LAP COUNT DELTA: " + String(millis() - lastLapCount)); 179 180 lastLapCount = millis(); 181 counter++; 182 //digitalWrite(CHARGING_PIN, 183 LOW); 184 lapCountPinTime = millis(); 185 lapCountPinSet = true; 186 187 EEPROM.put(0, 188 counter); 189 Serial.println("LAPS: " + String(counter)); 190 } 191 if (lapCountPinSet 192 && millis() - lapCountPinTime > 100) { 193 //digitalWrite(CHARGING_PIN, HIGH); 194 195 lapCountPinSet = false; 196 } 197} 198 199
Main Arduino Mega 2560 code
arduino
1#include "FastLED.h" 2#include "leds_lookup_table.h" 3#include 4 <EEPROM.h> 5 6#define DEBUG 0 7#define SEND_RESPONSE 0 8 9#define READY_PIN 10 28 11#define SANTA_PIN 8 12#define DANCING_TREE_PIN 5 13#define TRAIN_PIN 39 14 //relay 3 15#define LIGHT_CHAIN_PIN 35 //relay 1 16#define SPOT_LIGHT_PIN 37 17#define 18 FRONT_LIGHT_PIN 41 19#define LAP_COUNT_PIN 6 20#define BUS_GO_PIN 3 21#define 22 BALLOON_PIN 9 23#define BUS_CHARGING_PIN 11 24 25 26#define NUM_LEDS 55 //number 27 of total P9823's 28#define DATA_PIN 2 29#define FADE_DELAY 50 30#define FADE_TIME 31 2000 32#define CHANCE_SANTA_SOLO 20 //chance of a santa solo in percent 33 34#define 35 PiSerial Serial1 36#define DebugSerial Serial 37 38//status bytes knnen werte 39 von 1 bis 189 haben (0 = undefined) 40#define LED_START 1 41#define LED_END 55 42#define 43 TEXT_EINGABE 124 44#define TWERKING_SANTA 69 45#define TRAIN 56 46#define LIGHT_CHAIN 47 57 48#define SPARKLING 58 49#define ANIMATIONS 59 50#define TREE_BLACKOUT 60 51#define 52 DANCING_TREE 61 53#define BALLOON 62 54#define BUS 63 55 56#define LAP_COUNTER 57 190 58 59//info/data bytes von 192 bis 247 60#define OFF 192 61#define ON 193 62#define 63 FARBEN_START 194 64#define FARBEN_END 210 65 66// response data bytes to PI in 67 case of conflicts or errors 68#define OK 249 69#define BEREITS_AN 250 70#define 71 BEREITS_AUS 251 72#define SPAM_SCHUTZ 252 //lnger warten zwischen befehlen 73#define 74 CHARGING 253 75#define NOT_CHARGING 248 76 77#define DATA_ERROR_FIRST_BYTE 254 78#define 79 DATA_ERROR_COLOR 255 80 81struct ledStepStruct { 82 int rStep, gStep, bStep; 83 84 boolean fade; 85}; 86 87byte data[2], responseData[2], rndLED, hueTemp; 88char 89 text[31]; 90boolean newText, santaFlag, trainFlag, busFlag, lightChainFlag, sparklingFlag, 91 sparkleOn, santaSoloFlag, pinActive = true, dancingTreeFlag, balloonFlag, balloonPinReseted 92 = true, busCharging; 93const unsigned int fadeSteps = FADE_TIME / FADE_DELAY; 94unsigned 95 long currentMillis, lastStatiUpdate, lastFadeTime, santaTime, trainTime, busTime, 96 balloonTime, lightChainTime, sparklingTime, lastSparkleTime, lastLapCount, currentTime, 97 trainActionTime, lastTrainAction, busActionTime, lastBusAction, dancingTreeTime; 98unsigned 99 int lapCounter; 100 101CRGB leds[NUM_LEDS], ledsAim[NUM_LEDS], ledBefore; 102 103ledStepStruct 104 ledsStep[NUM_LEDS]; 105 106void setup() { 107 PiSerial.begin(9600); 108 109 DebugSerial.begin(9600); 110 111 112 pinMode(READY_PIN, OUTPUT); 113 pinMode(SANTA_PIN, OUTPUT); 114 pinMode(TRAIN_PIN, 115 OUTPUT); 116 pinMode(LIGHT_CHAIN_PIN, OUTPUT); 117 pinMode(SPOT_LIGHT_PIN, OUTPUT); 118 119 pinMode(FRONT_LIGHT_PIN, OUTPUT); 120 pinMode(LAP_COUNT_PIN, INPUT_PULLUP); 121 122 pinMode(DANCING_TREE_PIN, OUTPUT); 123 pinMode(BUS_GO_PIN, OUTPUT); 124 pinMode(BALLOON_PIN, 125 OUTPUT); 126 pinMode(BUS_CHARGING_PIN, INPUT); 127 128 129 FastLED.addLeds<WS2812B, 130 DATA_PIN, RGB>(leds, NUM_LEDS); 131 FastLED.setBrightness(70); 132 FastLED.clear(); 133 134 FastLED.show(); 135 136 digitalWrite(READY_PIN, HIGH); 137 digitalWrite(SANTA_PIN, 138 LOW); 139 digitalWrite(TRAIN_PIN, LOW); 140 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 141 142 digitalWrite(SPOT_LIGHT_PIN, LOW); 143 digitalWrite(FRONT_LIGHT_PIN, HIGH); 144 145 digitalWrite(DANCING_TREE_PIN, LOW); 146 digitalWrite(BUS_GO_PIN, LOW); 147 digitalWrite(BALLOON_PIN, 148 LOW); 149 150 lightChainFlag = true; 151 //!!!!!!!!!!!!!!!!!!!!!!!! UNCOMMENT 152 AFTER START OF PROJECT !!!!!!!!!!!!!!!!!!!!!! 153 lapCounter = 0; 154 EEPROM.put(0, 155 lapCounter); 156 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 157 158 159 EEPROM.get(0, lapCounter); 160 Serial.println(lapCounter); 161} 162 163void loop() 164 { 165 166 handleSerialCommunication(); 167 handleData(); 168 handleColorFade(); 169 170 handleControl(); 171 handleSparkling(); 172 handleLapCount(); 173 handleBusCharging(); 174 175 updateStati(); 176} 177 178void updateStati() { 179 if (millis() - lastStatiUpdate 180 > 600000) { 181 lastStatiUpdate = millis(); 182 if (trainFlag) { 183 responseData[0] 184 = TRAIN; 185 responseData[1] = ON; 186 PiSerial.write(responseData, 2); 187 188 PiSerial.flush(); 189 } 190 else { 191 responseData[0] = TRAIN; 192 193 responseData[1] = OFF; 194 PiSerial.write(responseData, 2); 195 PiSerial.flush(); 196 197 } 198 199 if (balloonFlag) { 200 responseData[0] = BALLOON; 201 responseData[1] 202 = ON; 203 PiSerial.write(responseData, 2); 204 PiSerial.flush(); 205 } 206 207 else { 208 responseData[0] = BALLOON; 209 responseData[1] = OFF; 210 211 PiSerial.write(responseData, 2); 212 PiSerial.flush(); 213 } 214 215 216 if (busFlag) { 217 responseData[0] = BUS; 218 responseData[1] = ON; 219 220 PiSerial.write(responseData, 2); 221 PiSerial.flush(); 222 } 223 else 224 { 225 responseData[0] = BUS; 226 responseData[1] = OFF; 227 PiSerial.write(responseData, 228 2); 229 PiSerial.flush(); 230 } 231 232 if (charging) { 233 responseData[0] 234 = BUS; 235 responseData[1] = CHARGING; 236 PiSerial.write(responseData, 237 2); 238 PiSerial.flush(); 239 } 240 else { 241 responseData[0] = 242 BUS; 243 responseData[1] = NOT_CHARGING; 244 PiSerial.write(responseData, 245 2); 246 PiSerial.flush(); 247 } 248 249 if (santaFlag) { 250 responseData[0] 251 = TWERKING_SANTA; 252 responseData[1] = ON; 253 PiSerial.write(responseData, 254 2); 255 PiSerial.flush(); 256 } 257 else { 258 responseData[0] = 259 TWERKING_SANTA; 260 responseData[1] = OFF; 261 PiSerial.write(responseData, 262 2); 263 PiSerial.flush(); 264 } 265 266 if (dancingTreeFlag) { 267 responseData[0] 268 = DANCING_TREE; 269 responseData[1] = ON; 270 PiSerial.write(responseData, 271 2); 272 PiSerial.flush(); 273 } 274 else { 275 responseData[0] = 276 DANCING_TREE; 277 responseData[1] = OFF; 278 PiSerial.write(responseData, 279 2); 280 PiSerial.flush(); 281 } 282 283 if (lightChainFlag) { 284 responseData[0] 285 = LIGHT_CHAIN; 286 responseData[1] = ON; 287 PiSerial.write(responseData, 288 2); 289 PiSerial.flush(); 290 } 291 else { 292 responseData[0] = 293 LIGHT_CHAIN; 294 responseData[1] = OFF; 295 PiSerial.write(responseData, 296 2); 297 PiSerial.flush(); 298 } 299 } 300} 301 302void handleBusCharging() 303 { 304 //busCharging = false; 305 306 if (!digitalRead(BUS_CHARGING_PIN) && !busCharging) 307 { 308 busCharging = true; 309 responseData[0] = BUS; 310 responseData[1] 311 = CHARGING; 312 PiSerial.write(responseData, 2); 313 PiSerial.flush(); 314 315 } 316 else if (digitalRead(BUS_CHARGING_PIN) && busCharging) { 317 busCharging 318 = false; 319 responseData[0] = BUS; 320 responseData[1] = NOT_CHARGING; 321 322 PiSerial.write(responseData, 2); 323 PiSerial.flush(); 324 } 325} 326 327void 328 handleLapCount() { 329 currentTime = millis(); 330 if (!digitalRead(LAP_COUNT_PIN) 331 && pinActive && currentTime - trainActionTime > 100) { 332 lapCounter++; 333 334 pinActive = false; 335 lastLapCount = currentTime; 336 PiSerial.print("LAP_COUNTER," 337 + String(lapCounter)); 338 PiSerial.flush(); 339 EEPROM.put(0, lapCounter); 340 341 //Serial.println(lapCounter); 342 } 343 344 if (digitalRead(LAP_COUNT_PIN) 345 && currentTime - lastLapCount > 2000) { 346 pinActive = true; 347 } 348} 349 350void 351 handleSparkling() { 352 if (sparklingFlag) { 353 if (millis() - sparklingTime 354 > 20000) { 355 sparklingFlag = false; 356 leds[rndLED] = ledBefore; 357 358 FastLED.show(); 359 sparkleOn = false; 360 } 361 else if (!sparkleOn 362 && millis() - lastSparkleTime > 100) { 363 rndLED = random8(NUM_LEDS); 364 365 ledBefore = leds[rndLED]; 366 leds[rndLED] += CRGB::White; 367 FastLED.show(); 368 369 sparkleOn = true; 370 lastSparkleTime = millis(); 371 } 372 else 373 if (sparkleOn && millis() - lastSparkleTime > 50) { 374 leds[rndLED] = ledBefore; 375 376 FastLED.show(); 377 sparkleOn = false; 378 lastSparkleTime = millis(); 379 380 } 381 } 382} 383 384void handleControl() { 385 386 if (dancingTreeFlag) { 387 388 if (dancingTreeTime == 0) { 389 //Serial.println("Set dancing tree pin 390 high"); 391 responseData[0] = DANCING_TREE; 392 responseData[1] = ON; 393 394 PiSerial.write(responseData, 2); 395 PiSerial.flush(); 396 digitalWrite(DANCING_TREE_PIN, 397 HIGH); 398 dancingTreeTime = millis(); 399 } 400 else if (millis() - 401 dancingTreeTime > 18000) { 402 digitalWrite(DANCING_TREE_PIN, LOW); 403 dancingTreeTime 404 = 0; 405 dancingTreeFlag = false; 406 responseData[0] = DANCING_TREE; 407 408 responseData[1] = OFF; 409 PiSerial.write(responseData, 2); 410 PiSerial.flush(); 411 412 } 413 } 414 415 if (balloonFlag) { 416 if (balloonTime == 0) { 417 responseData[0] 418 = BALLOON; 419 responseData[1] = ON; 420 PiSerial.write(responseData, 421 2); 422 PiSerial.flush(); 423 digitalWrite(BALLOON_PIN, HIGH); 424 balloonPinReseted 425 = false; 426 balloonTime = millis(); 427 } 428 else if (millis() - balloonTime 429 > 50000) { 430 balloonTime = 0; 431 balloonFlag = false; 432 responseData[0] 433 = BALLOON; 434 responseData[1] = OFF; 435 PiSerial.write(responseData, 436 2); 437 PiSerial.flush(); 438 } 439 else if (millis() - balloonTime > 440 1000 && !balloonPinReseted) { 441 balloonPinReseted = true; 442 digitalWrite(BALLOON_PIN, 443 LOW); 444 } 445 } 446 447 if (santaFlag) { 448 if (santaTime == 0) { 449 450 responseData[0] = TWERKING_SANTA; 451 responseData[1] = ON; 452 PiSerial.write(responseData, 453 2); 454 PiSerial.flush(); 455 digitalWrite(SANTA_PIN, HIGH); 456 santaTime 457 = millis(); 458 } 459 else if (millis() - santaTime > 20000) { 460 digitalWrite(SANTA_PIN, 461 LOW); 462 santaTime = 0; 463 santaFlag = false; 464 responseData[0] 465 = TWERKING_SANTA; 466 responseData[1] = OFF; 467 PiSerial.write(responseData, 468 2); 469 PiSerial.flush(); 470 } 471 } 472 473 else if (santaSoloFlag) 474 { 475 476 if (trainFlag) { 477 trainFlag = false; 478 digitalWrite(TRAIN_PIN, 479 LOW); 480 responseData[0] = TRAIN; 481 responseData[1] = OFF; 482 PiSerial.write(responseData, 483 2); 484 PiSerial.flush(); 485 486 } 487 if (lightChainFlag) { 488 lightChainFlag 489 = false; 490 digitalWrite(LIGHT_CHAIN_PIN, LOW); 491 } 492 if (busFlag) 493 { 494 busFlag = false; 495 digitalWrite(BUS_GO_PIN, LOW); 496 responseData[0] 497 = BUS; 498 responseData[1] = OFF; 499 PiSerial.write(responseData, 2); 500 501 PiSerial.flush(); 502 } 503 if (dancingTreeFlag) { 504 dancingTreeFlag 505 = false; 506 digitalWrite(DANCING_TREE_PIN, LOW); 507 } 508 responseData[0] 509 = DANCING_TREE; 510 responseData[1] = OFF; 511 PiSerial.write(responseData, 512 2); 513 PiSerial.flush(); 514 515 FastLED.clear(); 516 FastLED.show(); 517 518 519 digitalWrite(FRONT_LIGHT_PIN, LOW); 520 FastLED.delay(1000); 521 digitalWrite(SPOT_LIGHT_PIN, 522 HIGH); 523 FastLED.delay(500); 524 525 digitalWrite(SANTA_PIN, HIGH); 526 527 FastLED.delay(50); 528 digitalWrite(SANTA_PIN, LOW); 529 530 531 /* 532 533 for (int i; i < 500; i++) { 534 fill_rainbow(leds, NUM_LEDS, hueTemp, 535 1); 536 FastLED.show(); 537 hueTemp++; 538 FastLED.delay(25); 539 540 } 541 FastLED.clear(); 542 FastLED.show(); 543 */ 544 for 545 ( int k = 0; k < 20; k++ ) { 546 triangle(); 547 } 548 549 550 digitalWrite(SPOT_LIGHT_PIN, 551 LOW); 552 553 dancingTreeTime = 0; 554 555 digitalWrite(SANTA_PIN, HIGH); 556 557 FastLED.delay(50); 558 digitalWrite(SANTA_PIN, LOW); 559 santaFlag = false; 560 561 santaTime = 0; 562 563 responseData[0] = TWERKING_SANTA; 564 responseData[1] 565 = OFF; 566 PiSerial.write(responseData, 2); 567 PiSerial.flush(); 568 569 570 FastLED.delay(1000); //1000 571 572 digitalWrite(FRONT_LIGHT_PIN, HIGH); 573 574 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 575 lightChainFlag = true; 576 responseData[0] 577 = LIGHT_CHAIN; 578 responseData[1] = ON; 579 PiSerial.write(responseData, 580 2); 581 PiSerial.flush(); 582 583 584 for (byte i = 0; i < NUM_LEDS; i++) 585 { 586 leds[i] = ledsAim[i]; 587 } 588 FastLED.show(); 589 santaSoloFlag 590 = false; 591 digitalWrite(READY_PIN, HIGH); 592 } 593 594 if (trainFlag) { 595 596 if (millis() - trainTime > 30000) { 597 trainFlag = false; 598 digitalWrite(TRAIN_PIN, 599 LOW); 600 responseData[0] = TRAIN; 601 responseData[1] = OFF; 602 PiSerial.write(responseData, 603 2); 604 PiSerial.flush(); 605 } 606 } 607 608 if (busFlag) { 609 if 610 (millis() - busTime > 30000) { 611 busFlag = false; 612 digitalWrite(BUS_GO_PIN, 613 LOW); 614 responseData[0] = BUS; 615 responseData[1] = OFF; 616 PiSerial.write(responseData, 617 2); 618 PiSerial.flush(); 619 } 620 } 621 622 if (!lightChainFlag) { 623 624 if (millis() - lightChainTime > 60000) { 625 lightChainFlag = true; 626 627 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 628 responseData[0] = LIGHT_CHAIN; 629 630 responseData[1] = ON; 631 PiSerial.write(responseData, 2); 632 PiSerial.flush(); 633 634 } 635 } 636 637 638} 639 640void handleColorFade() { 641 currentMillis = millis(); 642 643 if (currentMillis - lastFadeTime >= FADE_DELAY) { 644 645 for (byte i = 0; 646 i < NUM_LEDS; i++) { 647 if (ledsStep[i].fade) { 648 ledsStep[i].fade 649 = false; 650 if (leds[i].r != ledsAim[i].r) { 651 ledsStep[i].fade 652 = true; 653 int rTemp = (int)leds[i].r + (int)ledsStep[i].rStep; 654 if 655 ((ledsStep[i].rStep > 0 && rTemp > ledsAim[i].r) || (ledsStep[i].rStep < 0 && rTemp 656 < ledsAim[i].r) || rTemp > 255 || rTemp < 0) leds[i].r = ledsAim[i].r; 657 else 658 leds[i].r = rTemp; 659 660 if ((ledsStep[i].rStep > 0 && leds[i].r > ledsAim[i].r) 661 || (ledsStep[i].rStep < 0 && leds[i].r < ledsAim[i].r)) leds[i].r = ledsAim[i].r; 662 663 } 664 if (leds[i].g != ledsAim[i].g) { 665 ledsStep[i].fade 666 = true; 667 int gTemp = (int)leds[i].g + (int)ledsStep[i].gStep; 668 if 669 ((ledsStep[i].gStep > 0 && gTemp > ledsAim[i].g) || (ledsStep[i].gStep < 0 && gTemp 670 < ledsAim[i].g) || gTemp > 255 || gTemp < 0) leds[i].g = ledsAim[i].g; 671 else 672 leds[i].g = gTemp; 673 } 674 if (leds[i].b != ledsAim[i].b) { 675 676 ledsStep[i].fade = true; 677 int bTemp = (int)leds[i].b + (int)ledsStep[i].bStep; 678 679 if ((ledsStep[i].bStep > 0 && bTemp > ledsAim[i].b) || (ledsStep[i].bStep 680 < 0 && bTemp < ledsAim[i].b) || bTemp > 255 || bTemp < 0) leds[i].b = ledsAim[i].b; 681 682 else leds[i].b = bTemp; 683 } 684 685 } 686 } 687 FastLED.show(); 688 689 lastFadeTime = currentMillis; 690 } 691 692 693} 694 695void handleSerialCommunication() 696 { 697 if (PiSerial.available() > 0) { //if there's any serial data 698 699 700 701 if (PiSerial.peek() >= 1 && PiSerial.peek() <= 191) { //if first data byte 702 is valid 703 PiSerial.readBytes(data, 2); 704#if DEBUG 705 DebugSerial.println("Empfangen: 706 " + (String)data[0] + ", " + (String)data[1]); 707#endif 708 } 709 else 710 { //else; first data byte is invalid (0 or greater than 191) 711 byte errorMessage 712 = PiSerial.read(); 713 714#if SEND_RESPONSE 715 responseData[0] = DATA_ERROR_FIRST_BYTE; 716 717 responseData[1] = errorMessage; 718 PiSerial.write(responseData, 2); 719#endif 720 721 722#if 723 DEBUG 724 DebugSerial.print("DATA_ERROR_FIRST_BYTE: "); 725 DebugSerial.println(errorMessage); 726#endif 727 728 } 729 } 730} 731 732void handleData() { 733 if (data[0] >= LED_START && data[0] 734 <= LED_END) { //if data is LED data 735 if (data[1] < OFF || data[1] > FARBEN_END) 736 { //if second data byte has invalid color 737 //invalid color/data byte 738 739#if 740 SEND_RESPONSE 741 responseData[0] = DATA_ERROR_COLOR; 742 responseData[1] 743 = data[1]; 744 PiSerial.write(responseData, 2); 745#endif 746 747#if DEBUG 748 749 DebugSerial.print("DATA_ERROR_INVALID_COLOR: "); 750 DebugSerial.println(data[1]); 751#endif 752 753 754 } 755 else { //color value is valid 756 //led mit farbe (in data[1]) 757 ansteuern 758 759 byte i = data[0] - 1; 760 761 if (data[1] == OFF) ledsAim[i] 762 = CRGB::Black; 763 else if (data[1] == ON) ledsAim[i] = CRGB::White; //hier 764 warmwei einfgen 765 else ledsAim[i].setHue((data[1] - 194) * 16); //set aim 766 color for led to chosen value 767 768 setLEDFade(i); 769 770 } 771 data[0] 772 = 0; 773 data[1] = 0; 774 } 775 776 else if (data[0] == TWERKING_SANTA) { 777 778 779 780 if (!santaFlag) { 781 digitalWrite(READY_PIN, LOW); 782 783 if (random8(100) 784 > CHANCE_SANTA_SOLO - 1) { 785 santaFlag = true; 786 digitalWrite(READY_PIN, 787 HIGH); 788 789 } 790 else santaSoloFlag = true; 791 } 792#if SEND_RESPONSE 793 794 else { 795 responseData[0] = TWERKING_SANTA; 796 responseData[1] = 797 BEREITS_AN; 798 PiSerial.write(responseData, 2); 799 } 800#endif 801 802 803 data[0] = 0; 804 data[1] = 0; 805 806 } 807 808 else if (data[0] == BALLOON) 809 { 810 if (!balloonFlag) { 811 balloonFlag = true; 812 } 813 data[0] 814 = 0; 815 data[1] = 0; 816 } 817 818 else if (data[0] == DANCING_TREE) { 819 820 821 if (!dancingTreeFlag) { 822 dancingTreeFlag = true; 823 } 824#if SEND_RESPONSE 825 826 else { 827 responseData[0] = DANCING_TREE; 828 responseData[1] = BEREITS_AN; 829 830 PiSerial.write(responseData, 2); 831 } 832#endif 833 834 data[0] = 0; 835 836 data[1] = 0; 837 838 } 839 840 else if ( data[0] == BUS) { 841 currentTime 842 = millis(); 843 if (currentTime - lastBusAction > 1000) { 844 if (data[1] 845 == OFF && busFlag && digitalRead(BUS_CHARGING_PIN)) { 846 busActionTime = 847 currentTime; 848 lastBusAction = busActionTime; 849 digitalWrite(BUS_GO_PIN, 850 LOW); 851 busFlag = false; 852 responseData[0] = BUS; 853 responseData[1] 854 = OFF; 855 PiSerial.write(responseData, 2); 856 PiSerial.flush(); 857 858 } 859 860 else if (data[1] == ON && !busFlag && digitalRead(BUS_CHARGING_PIN)) 861 { 862 busActionTime = currentTime; 863 lastBusAction = busActionTime; 864 865 digitalWrite(BUS_GO_PIN, HIGH); 866 busFlag = true; 867 busTime 868 = millis(); 869 responseData[0] = BUS; 870 responseData[1] = ON; 871 872 PiSerial.write(responseData, 2); 873 PiSerial.flush(); 874 } 875 876 } 877 data[0] = 0; 878 data[1] = 0; 879 } 880 881 else if ( data[0] 882 == TRAIN) { 883 currentTime = millis(); 884 if (currentTime - lastTrainAction 885 > 1000) { 886 if (data[1] == OFF && trainFlag) { 887 trainActionTime 888 = currentTime; 889 lastTrainAction = trainActionTime; 890 digitalWrite(TRAIN_PIN, 891 LOW); 892 trainFlag = false; 893 responseData[0] = TRAIN; 894 responseData[1] 895 = OFF; 896 PiSerial.write(responseData, 2); 897 PiSerial.flush(); 898 899 } 900 901 else if (data[1] == ON && !trainFlag) { 902 trainActionTime 903 = currentTime; 904 lastTrainAction = trainActionTime; 905 digitalWrite(TRAIN_PIN, 906 HIGH); 907 trainFlag = true; 908 trainTime = millis(); 909 responseData[0] 910 = TRAIN; 911 responseData[1] = ON; 912 PiSerial.write(responseData, 913 2); 914 PiSerial.flush(); 915 } 916#if SEND_RESPONSE 917 else if 918 (data[1] == ON && trainFlag) { 919 responseData[0] = TRAIN; 920 responseData[1] 921 = BEREITS_AN; 922 PiSerial.write(responseData, 2); 923 } 924 else 925 if (data[1] == OFF && !trainFlag) { 926 responseData[0] = TRAIN; 927 responseData[1] 928 = BEREITS_AUS; 929 PiSerial.write(responseData, 2); 930 } 931#endif 932 933 } 934#if SEND_RESPONSE 935 else { 936 responseData[0] = TRAIN; 937 responseData[1] 938 = SPAM_SCHUTZ; 939 PiSerial.write(responseData, 2); 940 } 941#endif 942 943 data[0] = 0; 944 data[1] = 0; 945 946 947 } 948 949 else if (data[0] == 950 LIGHT_CHAIN) { 951 if (data[1] == OFF && lightChainFlag) { 952 digitalWrite(LIGHT_CHAIN_PIN, 953 LOW); 954 lightChainFlag = false; 955 lightChainTime = millis(); 956 responseData[0] 957 = LIGHT_CHAIN; 958 responseData[1] = OFF; 959 PiSerial.write(responseData, 960 2); 961 PiSerial.flush(); 962 } 963 964 else if (data[1] == ON && !lightChainFlag) 965 { 966 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 967 lightChainFlag = true; 968 969 responseData[0] = LIGHT_CHAIN; 970 responseData[1] = ON; 971 PiSerial.write(responseData, 972 2); 973 PiSerial.flush(); 974 } 975#if SEND_RESPONSE 976 else if (data[1] 977 == ON && lightChainFlag) { 978 responseData[0] = LIGHT_CHAIN; 979 responseData[1] 980 = BEREITS_AN; 981 PiSerial.write(responseData, 2); 982 } 983 else if 984 (data[1] == OFF && !lightChainFlag) { 985 responseData[0] = LIGHT_CHAIN; 986 987 responseData[1] = BEREITS_AUS; 988 PiSerial.write(responseData, 2); 989 990 } 991#endif 992 993 data[0] = 0; 994 data[1] = 0; 995 } 996 997 else 998 if (data[0] == SPARKLING) { 999 if (data[1] == ON && !sparklingFlag) { 1000 sparklingFlag 1001 = true; 1002 sparklingTime = millis(); 1003 } 1004 1005 else if (data[1] 1006 == OFF && sparklingFlag) { 1007 sparklingFlag = false; 1008 } 1009#if SEND_RESPONSE 1010 1011 else if (data[1] == ON && sparklingFlag) { 1012 responseData[0] = SPARKLING; 1013 1014 responseData[1] = BEREITS_AN; 1015 PiSerial.write(responseData, 2); 1016 1017 } 1018 else if (data[1] == OFF && !sparklingFlag) { 1019 responseData[0] 1020 = SPARKLING; 1021 responseData[1] = BEREITS_AUS; 1022 PiSerial.write(responseData, 1023 2); 1024 } 1025#endif 1026 1027 data[0] = 0; 1028 data[1] = 0; 1029 } 1030 1031 1032 else if (data[0] == ANIMATIONS) { 1033 digitalWrite(READY_PIN, LOW); 1034 animations(); 1035 1036 digitalWrite(READY_PIN, HIGH); 1037 data[0] = 0; 1038 data[1] = 0; 1039 } 1040 1041 1042 else if (data[0] == TREE_BLACKOUT) { 1043 1044 for (byte i = 0; i < NUM_LEDS; 1045 i++) { 1046 ledsAim[i] = CRGB::Black; 1047 setLEDFade(i); 1048 } 1049 1050 1051 data[0] = 0; 1052 data[1] = 0; 1053 } 1054} 1055 1056void animations() { 1057 1058 fillSpiralCCW(); 1059 fillSpiralCW(); 1060 fillSpiralCCW(); 1061 fillSpiralCW(); 1062 1063 1064 for (byte i = 0; i < NUM_LEDS; i++) { 1065 leds[i] = ledsAim[i]; 1066 } 1067 1068 FastLED.show(); 1069} 1070 1071void setLEDFade(byte i) { 1072 if (leds[i] != ledsAim[i]) 1073 { 1074 ledsStep[i].fade = true; 1075 1076 if (ledsAim[i].r != leds[i].r) { 1077 1078 ledsStep[i].rStep = ((int)ledsAim[i].r - (int)leds[i].r) / (int)fadeSteps; 1079 1080 if (ledsStep[i].rStep == 0) { 1081 if (ledsAim[i].r > leds[i].r) ledsStep[i].rStep 1082 = 1; 1083 else ledsStep[i].rStep = -1; 1084 } 1085#if DEBUG 1086 DebugSerial.println("rStep: 1087 " + (String)ledsStep[i].rStep); //debug 1088#endif 1089 } 1090 if (ledsAim[i].g 1091 != leds[i].g) { 1092 ledsStep[i].gStep = ((int)ledsAim[i].g - (int)leds[i].g) 1093 / (int)fadeSteps; 1094 if (ledsStep[i].gStep == 0) { 1095 if (ledsAim[i].g 1096 > leds[i].g) ledsStep[i].gStep = 1; 1097 else ledsStep[i].gStep = -1; 1098 1099 } 1100#if DEBUG 1101 DebugSerial.println("gStep: " + (String)ledsStep[i].gStep); 1102 //debug 1103#endif 1104 } 1105 if (ledsAim[i].b != leds[i].b) { 1106 ledsStep[i].bStep 1107 = ((int)ledsAim[i].b - (int)leds[i].b) / (int)fadeSteps; 1108 if (ledsStep[i].bStep 1109 == 0) { 1110 if (ledsAim[i].b > leds[i].b) ledsStep[i].bStep = 1; 1111 else 1112 ledsStep[i].bStep = -1; 1113 } 1114#if DEBUG 1115 DebugSerial.println("bStep: 1116 " + (String)ledsStep[i].bStep); //debug 1117#endif 1118 } 1119 1120 } 1121} 1122 1123 1124void 1125 fillSpiralCCW() { 1126 1127 FastLED.clear(); 1128 FastLED.show(); 1129 1130 for (byte 1131 i = 0; i < (sizeof(spiralCCW) / sizeof(byte)); i++) { 1132 leds[spiralCCW[i]].setHue(hueTemp); 1133 1134 FastLED.show(); 1135 FastLED.delay(30); 1136 hueTemp += 2; 1137 } 1138 1139 1140 for (byte i = (sizeof(spiralCCW) / sizeof(byte)) - 1; i > 0; i--) { 1141 leds[spiralCCW[i]] 1142 = CRGB::Black; 1143 FastLED.show(); 1144 FastLED.delay(30); 1145 } 1146} 1147 1148void 1149 fillSpiralCW() { 1150 1151 FastLED.clear(); 1152 FastLED.show(); 1153 1154 for (byte 1155 i = 0; i < (sizeof(spiralCW) / sizeof(byte)); i++) { 1156 leds[spiralCW[i]].setHue(hueTemp); 1157 1158 FastLED.show(); 1159 FastLED.delay(30); 1160 hueTemp += 2; 1161 } 1162 1163 1164 for (byte i = (sizeof(spiralCW) / sizeof(byte)) - 1; i > 0; i--) { 1165 leds[spiralCW[i]] 1166 = CRGB::Black; 1167 FastLED.show(); 1168 FastLED.delay(30); 1169 } 1170} 1171 1172 1173void 1174 frameMarquee() { 1175 FastLED.clear(); 1176 FastLED.show(); 1177 1178 for (int j 1179 = 0; j < 400; j++) { 1180 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); 1181 i++) { 1182 leds[frame[i]].setHue(hueTemp); 1183 hueTemp += 2; 1184 } 1185 1186 hueTemp = 2 * j; 1187 FastLED.show(); 1188 FastLED.delay(40); 1189 } 1190 1191 FastLED.clear(); 1192 FastLED.show(); 1193} 1194 1195void innerFrame() { 1196 for 1197 (int j = 0; j < 15; j++) { 1198 1199 hueTemp += 40; 1200 1201 for (byte i = 0; 1202 i < (sizeof(frame) / sizeof(byte)); i++) { 1203 leds[frame[i]].setHue(hueTemp); 1204 1205 } 1206 FastLED.show(); 1207 FastLED.delay(200); 1208 1209 for (byte i = 1210 0; i < (sizeof(frame) / sizeof(byte)); i++) { 1211 leds[frame[i]] = CRGB::Black; 1212 1213 } 1214 1215 hueTemp += 40; 1216 1217 for (byte i = 0; i < (sizeof(inner) / 1218 sizeof(byte)); i++) { 1219 leds[inner[i]].setHue(hueTemp); 1220 } 1221 FastLED.show(); 1222 1223 FastLED.delay(200); 1224 1225 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); 1226 i++) { 1227 leds[inner[i]] = CRGB::Black; 1228 } 1229 } 1230 FastLED.clear(); 1231 1232 FastLED.show(); 1233} 1234 1235void triangle() { 1236 hueTemp += 16; 1237 for (byte 1238 i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 1239 leds[triangle1[i]].setHue(hueTemp); 1240 1241 } 1242 FastLED.show(); 1243 FastLED.delay(150); 1244 for (byte i = 0; i < (sizeof(triangle1) 1245 / sizeof(byte)); i++) { 1246 leds[triangle1[i]] = CRGB::Black; 1247 } 1248 hueTemp 1249 += 16; 1250 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 1251 1252 leds[triangle2[i]].setHue(hueTemp); 1253 } 1254 FastLED.show(); 1255 FastLED.delay(150); 1256 1257 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 1258 leds[triangle2[i]] 1259 = CRGB::Black; 1260 } 1261 hueTemp += 16; 1262 for (byte i = 0; i < (sizeof(triangle3) 1263 / sizeof(byte)); i++) { 1264 leds[triangle3[i]].setHue(hueTemp); 1265 } 1266 FastLED.show(); 1267 1268 FastLED.delay(150); 1269 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); 1270 i++) { 1271 leds[triangle3[i]] = CRGB::Black; 1272 } 1273 hueTemp += 16; 1274 for 1275 (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 1276 leds[triangle4[i]].setHue(hueTemp); 1277 1278 } 1279 FastLED.show(); 1280 FastLED.delay(150); 1281 for (byte i = 0; i < (sizeof(triangle4) 1282 / sizeof(byte)); i++) { 1283 leds[triangle4[i]] = CRGB::Black; 1284 } 1285 1286} 1287 1288
Downloadable files
Basic connections and data exchange.
Our basic concept of how this whole mess works.
Basic connections and data exchange.
Basic connections and data exchange.
Our basic concept of how this whole mess works.
Basic connections and data exchange.
Documentation
The arm for the gripper
The arm to hold the gripper in the right position to charge the bus
The arm for the gripper
The roof of the bus stop
The roof of the bus stop
Bus stop base
The base of the busstop with the compartment for the ir distance sensor.
Bus stop base
The roof of the bus stop
The roof of the bus stop
The arm for the gripper
The arm to hold the gripper in the right position to charge the bus
The arm for the gripper
Comments
Only logged in users can leave comments
wotanzero
0 Followers
•0 Projects
Table of contents
Intro
4
0