Components and supplies
8 channel relay board
5V, 5A (switching) power supply
WS2812 RGB LED
LED dot matrix with MAX7219 control IC
Raspberry Pi 3 Model B
Arduino Nano R3
Level Shifter Board
Arduino Mega Proto Shield
Arduino Mega 2560
Arduino MKR1000
Tools and machines
Soldering iron (generic)
Jigsaw
Drill
Apps and platforms
openweathermap.org
TelegramBot Api
timezonedb.com
Project description
Code
Telegram_Bot_xmas.ino
arduino
Code for the Arduino MKR1000.
1#define TEXT_SERIAL 1 2#define WATCHDOG 1 3#define DEBUG 0 4 5#include <Arduino.h> 6#include <Time.h> 7#include <TimeLib.h> 8#include <WiFi101.h> 9//#include <WiFiUdp.h> 10#include <SPI.h> 11#include <TelegramBot.h> 12//#include <time.h> 13//#include <RTCZero.h> 14 15#if TEXT_SERIAL 16#include <wiring_private.h> 17#endif 18 19#if WATCHDOG 20#include <Adafruit_SleepyDog.h> 21#endif 22 23#if TEXT_SERIAL 24Uart textSerial (&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0); 25 26void SERCOM3_Handler() // Interrupt handler for SERCOM3 27{ 28 textSerial.IrqHandler(); 29} 30#endif 31 32#define ledPin 6 33#define RBUFFSIZE 1000 34 35#define MAX_MESSAGES 16 36 37#define TIME 1 38#define TEXT 2 39#define WEATHER 3 40#define STATS 4 41 42/* 43 #define BEER_NAME 0 44 #define BEER_ID 1 45*/ 46 47char responseBuffer[RBUFFSIZE]; 48int rbindex = 0; 49 50boolean startCapture; 51unsigned long lastTimeSentTime, lastTextSent, currentTime, lastClockSent; 52 53// Initialize Wifi connection 54 55const char ssid[] = ""; // network SSID 56const char pass[] = ""; // network key 57 58// Initialize Telegram BOT 59 60const char BotToken[] = ""; 61 62char server[] = "api.openweathermap.org"; 63 64String eingabe; //Nachrichten[128]; 65char Nachrichten[MAX_MESSAGES][100]; 66byte numMessages, messageIndex, sendMessageIndex; 67 68WiFiSSLClient client; 69WiFiClient clienthttp; 70 71TelegramBot bot(BotToken, client); 72 73//RTCZero rtc; 74 75//TelegramKeyboard keyboardStart; 76/* 77const char* row1Start[] = {"/help", "/wlan"}; 78const char* row2Start[] = {"/ip", "/signal"}; 79//const char* row3Start[] = {"/alloff"}; 80*/ 81 82time_t tClock = 0; 83 84 85void setup() { 86 87 delay(3000); 88 89#if TEXT_SERIAL 90 textSerial.begin(9600); // Begin Uart for sending text to LED matrix 91#endif 92 93 Serial.begin(9600); 94 95#if TEXT_SERIAL 96 pinPeripheral(0, PIO_SERCOM); // Assign pins 0 & 1 SERCOM functionality 97 pinPeripheral(1, PIO_SERCOM); 98#endif 99 100#if WATCHDOG 101 Watchdog.enable(10000); 102#endif 103 104 // attempt to connect to Wifi network: 105#if DEBUG 106 Serial.print(F("Verbine mit WLAN: ")); 107 Serial.println(ssid); 108#endif 109 110 while (WiFi.begin(ssid, pass) != WL_CONNECTED) { 111 delay(500); 112 } 113 114#if DEBUG 115 Serial.println(F("Mit WLAN verbunden.")); 116#endif 117/* 118 byte counterT = 0; 119 while (tClock == 0 && counterT < 6) { 120 delay(1000); 121 counterT++; 122 123 tClock = WiFi.getTime(); 124 125 } 126 Serial.println(tClock); 127 */ 128 getCurrentTime(); 129 130 if (tClock != 0) { 131 textSerial.write(TIME); 132 textSerial.write(hour(tClock)); 133 textSerial.write(minute(tClock)); 134 textSerial.write(second(tClock)); 135 } 136 tClock = 0; 137 138 lastClockSent = millis(); 139 140 bot.begin(); 141 142 pinMode(ledPin, OUTPUT); 143 digitalWrite(ledPin, LOW); 144/* 145 keyboardStart.addRow(row1Start, 2); 146 keyboardStart.addRow(row2Start, 2); 147 //keyboardStart.addRow(row3Start, 1); 148 */ 149 150 message m = bot.getUpdates(); 151} 152 153void loop() { 154#if WATCHDOG 155 Watchdog.reset(); 156#endif 157 158 if ( WiFi.status() != WL_CONNECTED) { 159 //WiFi.disconnect(); 160 while (WiFi.begin(ssid, pass) != WL_CONNECTED) { 161#if DEBUG 162 Serial.print("."); 163#endif 164 delay(1000); 165 } 166 } 167 currentTime = millis(); 168 169 if (numMessages > 0 && currentTime - lastTextSent > 20000) { 170 textSerial.write(TEXT); 171 textSerial.print(String(Nachrichten[sendMessageIndex])); 172 lastTextSent = currentTime; 173 sendMessageIndex++; 174 numMessages--; 175 if (sendMessageIndex >= MAX_MESSAGES) sendMessageIndex = 0; 176 } 177 178 if (currentTime - lastTextSent > 120000) { 179 textSerial.write(TEXT); 180 textSerial.print("To send custom text, open/download the 'Telegram' App and add: TannenbaumBot."); 181 lastTextSent = currentTime; 182 } 183 184 if (currentTime - lastClockSent > 600000) { 185 tClock = 0; 186 187 getCurrentTime(); 188 /* 189 byte counterT = 0; 190 while (tClock == 0 && counterT < 6) { 191 counterT++; 192 delay(500); 193 tClock = WiFi.getTime(); 194 } 195 */ 196 if (tClock != 0) { 197 textSerial.write(TIME); 198 textSerial.write(hour(tClock)); 199 textSerial.write(minute(tClock)); 200 textSerial.write(second(tClock)); 201 } 202 203 204 /* 205 textSerial.write(rtc.getHours()); 206 textSerial.write(rtc.getMinutes()); 207 textSerial.write(rtc.getSeconds()); 208 */ 209 210 lastClockSent = currentTime; 211 } 212 213 message m = bot.getUpdates(); 214 /* 215 if(millis() - lastTimeSentTime > 600000) { 216 textSerial.write(TIME); 217 textSerial.print(String(rtc.getEpoch()) + "\ 218"); 219 lastTimeSentTime = millis(); 220 } 221 */ 222 223 if (Serial.available() > 0) { 224 eingabe = Serial.readStringUntil('\ 225'); 226 if (!eingabe.equalsIgnoreCase("i")) { 227 bot.sendMessage("", eingabe); 228 eingabe = ""; 229 } 230 } 231 232 else if (eingabe.equalsIgnoreCase("i")) { 233 if (WL_CONNECTED) { 234 Serial.println(F("Mit WLAN verbunden")); 235 IPAddress ip = WiFi.localIP(); 236 Serial.print(F("IP Address: ")); 237 Serial.println(ip); 238 239 // print the received signal strength: 240 long rssi = WiFi.RSSI(); 241 Serial.print(F("signal strength (RSSI):")); 242 Serial.print(rssi); 243 Serial.println(F(" dBm")); 244 eingabe = ""; 245 } 246 else Serial.println(F("KEINE Verbindung zum WLAN")); 247 eingabe = ""; 248 } 249 250 if ( m.chat_id != 0 ) { 251 if (1) { // if a message is received from unique Chats m.sender.equals("xxxxx") 252 253 //Serial.println("Location: " + m.location.lon + ", " + m.location.lat); 254 //Serial.println("Name: " + m.first_name); 255 //Serial.println(m.chat_id); 256 //Serial.println(m.sender); 257 258#if DEBUG 259 time_t t = m.date.toInt(); 260 t = t + 1 * 60 * 60; 261 262 Serial.print(m.sender); 263 Serial.print(F(" hat um ")); 264 Serial.print(hour(t)); 265 Serial.print(":"); 266 Serial.print(minute(t)); 267 268 Serial.print(F(" folgendes gesendet: ")); 269 Serial.println(m.text); 270#endif 271 272 if (m.location.lon.length() != 0) { 273 bot.sendMessage(m.chat_id, "Requesting weather data..."); 274#if DEBUG 275 Serial.println(F("Verbinde zu api.openweathermap.org")); 276#endif 277 278 weatherHttpRequest(m.location.lat, m.location.lon, m.chat_id); 279 280 } 281 282 if (m.text.equalsIgnoreCase("/help")) { 283 bot.sendMessage(m.chat_id, "To send custom text, type: /text and your message. For example: '/text Santa rocks!'. To display the current weather in your area, simply send your location."); 284 285 286 } 287/* 288 else if (m.text.equalsIgnoreCase("/watchdog")) { 289 while (1); 290 } 291*/ 292 else if (m.text.equalsIgnoreCase("/start")) { 293 bot.sendMessage(m.chat_id, "Welcome " + m.first_name + "! Send /help for more information."); 294 295 } 296 297 else if (m.text.startsWith("/text") || m.text.startsWith("/Text")) { 298 m.text.remove(0, 6); 299 m.text += "\ 300"; 301 302 if (m.text.length() <= 2) { 303 bot.sendMessage(m.chat_id, "Sorry, your text is too short. Please send at least 2 characters."); 304 } 305 else if (m.text.length() >= 75) { 306 bot.sendMessage(m.chat_id, "Sorry, your text is too long. The maxmimal text length is 74 characters."); 307 } 308 else if (numMessages == MAX_MESSAGES) { 309 bot.sendMessage(m.chat_id, "Sorry, there are currently too many people sending messages to Santa. Try again later."); 310 } 311 else { 312 if (m.first_name.length() >= 21) m.first_name.remove(20); 313 eingabe = m.first_name + ": " + m.text; 314 eingabe.toCharArray(Nachrichten[messageIndex], 100); 315 eingabe = ""; 316 numMessages++; 317 messageIndex++; 318 if (messageIndex >= MAX_MESSAGES) messageIndex = 0; 319 bot.sendMessage(m.chat_id, "Your text is on position " + String(numMessages) + " in the pipeline. It will be displayed in approximately " + String((numMessages) * 20) + " seconds."); 320 } 321 322#if DEBUG 323 Serial.println("Der reine Text lautet: " + m.text); 324 325#endif 326 327 } 328 /* 329 else if (m.text.startsWith("/bierID")) { 330 m.text.remove(0, 7); 331 m.text.trim(); 332 beerHttpRequest(BEER_ID, m.text, m.chat_id); 333 } 334 335 else if (m.text.startsWith("/bier") || m.text.startsWith("/Bier")) { 336 m.text.remove(0, 6); 337 m.text.trim(); 338 beerHttpRequest(BEER_NAME, m.text, m.chat_id); 339 } 340 */ 341 /* 342 else if (m.text.equalsIgnoreCase("/wlan")) { 343 bot.sendMessage(m.chat_id, ssid); 344 345 } 346 else if (m.text.equalsIgnoreCase("/ip")) { 347 IPAddress ip = WiFi.localIP(); 348 bot.sendMessage(m.chat_id, String(ip[0]) + String(".") + \\ 349 String(ip[1]) + String(".") + \\ 350 String(ip[2]) + String(".") + \\ 351 String(ip[3])); 352 } 353 else if (m.text.equalsIgnoreCase("/signal")) { 354 long rssi = WiFi.RSSI(); 355 bot.sendMessage(m.chat_id, String(rssi) + " dBm"); 356 } 357 */ 358 } 359 360 else { 361 bot.sendMessage(m.chat_id, "Sie sind nicht befugt diesen Befehl zu verwenden."); 362 363 Serial.println(m.chat_id); 364 Serial.println(m.sender); 365 } 366 } 367} 368 369int findText(String needle, String haystack) { 370 int foundpos = -1; 371 for (int i = 0; i <= haystack.length() - needle.length(); i++) { 372 if (haystack.substring(i, needle.length() + i) == needle) { 373 foundpos = i; 374 } 375 } 376 return foundpos; 377} 378 379void weatherHttpRequest(String lat, String lon, String chatId) { 380 if (clienthttp.connect(server, 80)) { 381#if DEBUG 382 Serial.println(F("Verbunden zum Server")); 383#endif 384 385 clienthttp.println("GET /data/2.5/weather?lat=" + lat + "&lon=" + lon + "&APPID=**yourapikey** HTTP/1.1"); 386 clienthttp.println("Host: api.openweathermap.org"); 387 clienthttp.println("Connection: close"); 388 clienthttp.println(); 389 390 responseBuffer[0] = '\\0'; 391 rbindex = 0; 392 393 startCapture = false; 394 } 395 396 else { 397 bot.sendMessage(chatId, "Cannot connect to weather server."); 398 return; 399 } 400 401 char c; 402 unsigned long startTime = millis(); 403 while (clienthttp.connected() && millis() - startTime < 7000) { 404 if (clienthttp.available()) { 405 c = clienthttp.read(); 406 if (c == '{') { 407 startCapture = true; 408 } 409 if (startCapture && rbindex < RBUFFSIZE) { 410 responseBuffer[rbindex] = c; 411 rbindex++; 412 } 413 } 414 } 415 416 417 if (clienthttp.connected()) { 418 clienthttp.stop(); 419 clienthttp.flush(); 420#if DEBUG 421 Serial.println(F("Client won't disconnect")); 422#endif 423 bot.sendMessage(chatId, "Data couldn't be recieved."); 424 return; 425 } 426 427#if DEBUG 428 Serial.println(F("Received bytes.")); 429 //Serial.print(strlen(responseBuffer)); 430 Serial.println(F("Disconnecting.")); 431#endif 432 433 clienthttp.stop(); 434 clienthttp.flush(); 435 436 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 437 438 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 439 440 if (!root.success()) { 441#if DEBUG 442 Serial.println(F("parseObject() fehlgeschlagen")); 443#endif 444 445 bot.sendMessage(chatId, "Datenverarbeitung fehlgeschlagen."); 446 } 447 else { 448 char bufferw[20]; 449 char bufferc[30]; 450 root["weather"][0]["description"].prettyPrintTo(bufferw, sizeof(bufferw)); 451 root["name"].prettyPrintTo(bufferc, sizeof(bufferc)); 452 453#if DEBUG 454 Serial.println("Schnee: " + String((float)root["snow"]["3h"])); 455#endif 456 //bot.sendMessage(m.chat_id, "Aktuelle Wetter fr " + String(bufferc) + ":"); 457 textSerial.write(TEXT); 458 eingabe = "Current weather in " + String(bufferc) + ": " + String(bufferw) + " at " + String(((double)root["main"]["temp"]) - 273.15, 1) + " C"; 459 textSerial.print(eingabe); 460 lastTextSent = millis(); 461 eingabe = ""; 462 463 bot.sendMessage(chatId, "The current weather in your region will be displayed soon."); 464 465#if DEBUG 466 Serial.print(F("Aktuelle Temperatur: ")); 467 Serial.print(((double)root["main"]["temp"]) - 273.15); 468 Serial.println(F(" C")); 469 470 Serial.print(F("Beschreibung: ")); 471 Serial.println(bufferw); 472#endif 473 } 474} 475void getCurrentTime() { 476 if (clienthttp.connect("api.timezonedb.com", 80)) { 477 clienthttp.println("GET /v2/get-time-zone?key=**yourapikey**&format=json&by=zone&zone=Europe/London HTTP/1.1"); 478 clienthttp.println("Host: api.timezonedb.com"); 479 clienthttp.println("Connection: close"); 480 clienthttp.println(); 481 482 responseBuffer[0] = '\\0'; 483 rbindex = 0; 484 485 startCapture = false; 486 } 487 488 else { 489 Serial.println("Verbindung zum Zeitserver fehlgeschlagen"); 490 return; 491 } 492 493 char c; 494 unsigned long startTime = millis(); 495 496 while (clienthttp.connected() && millis() - startTime < 7000) { 497 if (clienthttp.available()) { 498 c = clienthttp.read(); 499 if (c == '{') { 500 startCapture = true; 501 } 502 if (startCapture && rbindex < RBUFFSIZE) { 503 responseBuffer[rbindex] = c; 504 rbindex++; 505 } 506 } 507 } 508 509 if (clienthttp.connected()) { 510 clienthttp.stop(); 511 clienthttp.flush(); 512 #if DEBUG 513 Serial.println(F("Client won't disconnect")); 514 #endif 515 return; 516 } 517 518 519 #if DEBUG 520 Serial.println(F("Received bytes.")); 521 //Serial.print(strlen(responseBuffer)); 522 Serial.println(F("Disconnecting.")); 523 #endif 524 525 clienthttp.stop(); 526 clienthttp.flush(); 527 528 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 529 530 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 531 532 if (!root.success()) { 533 #if DEBUG 534 Serial.println(F("parseObject() fehlgeschlagen")); 535 #endif 536 537 } 538 else { 539 tClock = root["timestamp"]; 540 Serial.println(tClock); 541 } 542} 543//wanted to implement the brewery db but couldn't make it work so fart 544/* 545 void beerHttpRequest(boolean type, String request, String chatId) { 546 if (clienthttp.connect("api.brewerydb.com", 80)) { 547 #if DEBUG 548 Serial.println(F("Verbunden zum Server")); 549 #endif 550 551 if (type == BEER_NAME) clienthttp.println("GET /v2/search?q=" + request + "&type=beer&key=**yourapikey**&format=json HTTP/1.1"); 552 else clienthttp.println("GET /v2/beer/" + request + "?key=**yourapikey**&format=json HTTP/1.1"); 553 clienthttp.println("Host: api.brewerydb.com"); 554 clienthttp.println("Connection: close"); 555 clienthttp.println(); 556 557 responseBuffer[0] = '\\0'; 558 rbindex = 0; 559 560 startCapture = false; 561 562 } 563 564 else { 565 bot.sendMessage(chatId, "Verbindung zur Brewery Databse nicht mglich."); 566 return; 567 } 568 569 char c; 570 unsigned long startTime = millis(); 571 572 while (clienthttp.connected() && millis() - startTime < 7000) { 573 if (clienthttp.available()) { 574 c = clienthttp.read(); 575 if (c == '{') { 576 startCapture = true; 577 } 578 if (startCapture && rbindex < RBUFFSIZE) { 579 responseBuffer[rbindex] = c; 580 rbindex++; 581 } 582 } 583 } 584 585 if (clienthttp.connected()) { 586 clienthttp.stop(); 587 clienthttp.flush(); 588 #if DEBUG 589 Serial.println(F("Client won't disconnect")); 590 #endif 591 bot.sendMessage(chatId, "Daten konnten nicht empfangen werden."); 592 return; 593 } 594 595 596 #if DEBUG 597 Serial.println(F("Received bytes.")); 598 //Serial.print(strlen(responseBuffer)); 599 Serial.println(F("Disconnecting.")); 600 #endif 601 602 clienthttp.stop(); 603 clienthttp.flush(); 604 605 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 606 607 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 608 609 if (!root.success()) { 610 #if DEBUG 611 Serial.println(F("parseObject() fehlgeschlagen")); 612 #endif 613 614 bot.sendMessage(chatId, "Datenverarbeitung fehlgeschlagen."); 615 } 616 else { 617 618 if (type == BEER_NAME) { 619 char bufferName[10][50]; // char bufferName[10][50]; 620 char bufferID[10][9]; //char bufferID[10][6]; 621 int results = root["totalResults"]; // int results = atoi(&root["totalResults"]); 622 if (results > 10) results = 10; 623 for (byte i = 0; i < results; i++) { 624 625 root["data"][i]["id"].prettyPrintTo(bufferID[i], sizeof(bufferID[i])); 626 root["data"][i]["name"].prettyPrintTo(bufferName[i], sizeof(bufferName[i])); 627 } 628 629 String beerMessage; 630 631 if (results > 0) { 632 beerMessage = "Hier die ersten " + String(results) + " Treffer. Meintest du:"; 633 for (byte i = 0; i < results; i++) { 634 beerMessage += '\ 635'; 636 beerMessage += String(bufferName[i]); 637 beerMessage += ": /bierID"; 638 String IDtemp = String(bufferID[i]); 639 IDtemp.remove(0, 1); 640 IDtemp.remove(6, 1); 641 beerMessage += IDtemp; 642 } 643 } 644 645 else beerMessage = "Zu diesem Suchbegriff gab es leider keine Treffer."; 646 647 bot.sendMessage(chatId, beerMessage); 648 #if DEBUG 649 Serial.println(F("test")); 650 #endif 651 } 652 else { 653 char bufferDescription[1000]; 654 char bufferStyle[50]; 655 656 if (root["data"]["description"] != NULL) { 657 root["data"]["description"].prettyPrintTo(bufferDescription, sizeof(bufferDescription)); 658 bot.sendMessage(chatId, bufferDescription); 659 #if DEBUG 660 Serial.println(bufferDescription); 661 #endif 662 } 663 if (root["data"]["style"]["description"] != NULL) { 664 root["data"]["style"]["description"].prettyPrintTo(bufferDescription, sizeof(bufferDescription)); 665 root["data"]["style"]["name"].prettyPrintTo(bufferStyle, sizeof(bufferStyle)); 666 667 bot.sendMessage(chatId, "Es handelt sich um ein: " + String(bufferStyle) + ".'\ 668'" + String(bufferDescription)); 669 #if DEBUG 670 Serial.println("Es handelt sich um ein: " + String(bufferStyle) + ".'\ 671'" + String(bufferDescription)); 672 #endif 673 } 674 } 675 } 676 } 677*/ 678 679
Serial_Data_Read.ino
arduino
Code for the "main" Arduino Mega. Reads data from pi and controls all LEDs and devices.
1#include "FastLED.h" 2#include "leds_lookup_table.h" 3#include <EEPROM.h> 4 5#define DEBUG 0 6 7#define READY_PIN 28 8#define SANTA_PIN 5 9#define TRAIN_PIN 39 //relay 3 10#define LIGHT_CHAIN_PIN 35 //relay 1 11#define SPOT_LIGHT_PIN 37 12#define FRONT_LIGHT_PIN 41 13#define LAP_COUNT_PIN 6 14 15 16#define NUM_LEDS 55 //number of total P9823's 17#define DATA_PIN 2 18#define FADE_DELAY 50 19#define FADE_TIME 2000 20#define CHANCE_SANTA_SOLO 20 //chance of a santa solo in percent 21 22#define PiSerial Serial1 23#define DebugSerial Serial 24 25//status bytes knnen werte von 1 bis 191 haben (0 = undefined) 26#define LED_START 1 27#define LED_END 55 28#define TEXT_EINGABE 124 29#define TWERKING_SANTA 69 30#define TRAIN 56 31#define LIGHT_CHAIN 57 32#define SPARKLING 58 33#define ANIMATIONS 59 34#define TREE_BLACKOUT 60 35 36//info/data bytes von 192 bis 254 37#define OFF 192 38#define ON 193 39#define FARBEN_START 194 40#define FARBEN_END 210 41 42#define DATA_ERROR 255 43 44struct ledStepStruct { 45 int rStep, gStep, bStep; 46 boolean fade; 47}; 48 49byte data[2], rndLED, hueTemp; 50char text[31]; 51boolean newText, santaFlag, trainFlag, lightChainFlag, sparklingFlag, sparkleOn, santaSoloFlag, pinActive = true; 52const unsigned int fadeSteps = FADE_TIME / FADE_DELAY; 53unsigned long currentMillis, lastFadeTime, santaTime, trainTime, lightChainTime, sparklingTime, lastSparkleTime, lastLapCount, currentTime, trainActionTime, lastTrainAction; 54unsigned int lapCounter; 55 56CRGB leds[NUM_LEDS], ledsAim[NUM_LEDS], ledBefore; 57 58ledStepStruct ledsStep[NUM_LEDS]; 59 60void setup() { 61 PiSerial.begin(9600); 62 63 DebugSerial.begin(9600); 64 65 pinMode(READY_PIN, OUTPUT); 66 pinMode(SANTA_PIN, OUTPUT); 67 pinMode(TRAIN_PIN, OUTPUT); 68 pinMode(LIGHT_CHAIN_PIN, OUTPUT); 69 pinMode(SPOT_LIGHT_PIN, OUTPUT); 70 pinMode(FRONT_LIGHT_PIN, OUTPUT); 71 pinMode(LAP_COUNT_PIN, INPUT_PULLUP); 72 73 74 FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS); 75 FastLED.setBrightness(70); 76 FastLED.clear(); 77 FastLED.show(); 78 79 digitalWrite(READY_PIN, HIGH); 80 digitalWrite(SANTA_PIN, LOW); 81 digitalWrite(TRAIN_PIN, LOW); 82 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 83 digitalWrite(SPOT_LIGHT_PIN, LOW); 84 digitalWrite(FRONT_LIGHT_PIN, HIGH); 85 86 lightChainFlag = true; 87 88 //lapCounter = 200; //add counts up to now, since eeprom wasnt' implemented yet 89 //EEPROM.put(0, lapCounter); 90 EEPROM.get(0, lapCounter); 91 92} 93 94void loop() { 95 96 handleSerialCommunication(); 97 handleData(); 98 handleColorFade(); 99 handleControl(); 100 handleSparkling(); 101 handleLapCount(); 102 103} 104 105void handleLapCount() { 106 currentTime = millis(); 107 if (!digitalRead(LAP_COUNT_PIN) && pinActive && currentTime - trainActionTime > 100) { 108 lapCounter++; 109 pinActive = false; 110 lastLapCount = currentTime; 111 PiSerial.print(lapCounter); 112 PiSerial.flush(); 113 EEPROM.put(0, lapCounter); 114 //Serial.println(lapCounter); 115 } 116 117 if (digitalRead(LAP_COUNT_PIN) && currentTime - lastLapCount > 2000) { 118 pinActive = true; 119 } 120} 121 122void handleSparkling() { 123 if (sparklingFlag) { 124 if (millis() - sparklingTime > 20000) { 125 sparklingFlag = false; 126 leds[rndLED] = ledBefore; 127 FastLED.show(); 128 sparkleOn = false; 129 } 130 else if (!sparkleOn && millis() - lastSparkleTime > 100) { 131 rndLED = random8(NUM_LEDS); 132 ledBefore = leds[rndLED]; 133 leds[rndLED] += CRGB::White; 134 FastLED.show(); 135 sparkleOn = true; 136 lastSparkleTime = millis(); 137 } 138 else if (sparkleOn && millis() - lastSparkleTime > 50) { 139 leds[rndLED] = ledBefore; 140 FastLED.show(); 141 sparkleOn = false; 142 lastSparkleTime = millis(); 143 } 144 } 145} 146 147void handleControl() { 148 if (santaFlag) { 149 if (santaTime == 0) { 150 digitalWrite(SANTA_PIN, HIGH); 151 santaTime = millis(); 152 } 153 else if (millis() - santaTime > 20000) { 154 digitalWrite(SANTA_PIN, LOW); 155 santaTime = 0; 156 santaFlag = false; 157 } 158 } 159 160 else if (santaSoloFlag) { 161 162 if (trainFlag) { 163 trainFlag = false; 164 digitalWrite(TRAIN_PIN, LOW); 165 } 166 if (lightChainFlag) { 167 digitalWrite(LIGHT_CHAIN_PIN, LOW); 168 } 169 FastLED.clear(); 170 FastLED.show(); 171 172 digitalWrite(FRONT_LIGHT_PIN, LOW); 173 FastLED.delay(1000); 174 digitalWrite(SPOT_LIGHT_PIN, HIGH); 175 FastLED.delay(500); 176 digitalWrite(SANTA_PIN, HIGH); 177 FastLED.delay(50); 178 digitalWrite(SANTA_PIN, LOW); 179 180 /* 181 for (int i; i < 500; i++) { 182 fill_rainbow(leds, NUM_LEDS, hueTemp, 1); 183 FastLED.show(); 184 hueTemp++; 185 FastLED.delay(25); 186 } 187 FastLED.clear(); 188 FastLED.show(); 189 */ 190 for ( int k = 0; k < 20; k++ ) { 191 triangle(); 192 } 193 194 195 digitalWrite(SPOT_LIGHT_PIN, LOW); 196 197 digitalWrite(SANTA_PIN, HIGH); 198 FastLED.delay(50); 199 digitalWrite(SANTA_PIN, LOW); 200 201 FastLED.delay(1000); 202 203 digitalWrite(FRONT_LIGHT_PIN, HIGH); 204 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 205 lightChainFlag = true; 206 207 for (byte i = 0; i < NUM_LEDS; i++) { 208 leds[i] = ledsAim[i]; 209 } 210 FastLED.show(); 211 santaSoloFlag = false; 212 digitalWrite(READY_PIN, HIGH); 213 } 214 215 if (trainFlag) { 216 if (millis() - trainTime > 30000) { 217 trainFlag = false; 218 digitalWrite(TRAIN_PIN, LOW); 219 } 220 } 221 222 if (!lightChainFlag) { 223 if (millis() - lightChainTime > 60000) { 224 lightChainFlag = true; 225 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 226 } 227 } 228} 229 230void handleColorFade() { 231 currentMillis = millis(); 232 if (currentMillis - lastFadeTime >= FADE_DELAY) { 233 234 for (byte i = 0; i < NUM_LEDS; i++) { 235 if (ledsStep[i].fade) { 236 ledsStep[i].fade = false; 237 if (leds[i].r != ledsAim[i].r) { 238 ledsStep[i].fade = true; 239 int rTemp = (int)leds[i].r + (int)ledsStep[i].rStep; 240 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; 241 else leds[i].r = rTemp; 242 243 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; 244 } 245 if (leds[i].g != ledsAim[i].g) { 246 ledsStep[i].fade = true; 247 int gTemp = (int)leds[i].g + (int)ledsStep[i].gStep; 248 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; 249 else leds[i].g = gTemp; 250 } 251 if (leds[i].b != ledsAim[i].b) { 252 ledsStep[i].fade = true; 253 int bTemp = (int)leds[i].b + (int)ledsStep[i].bStep; 254 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; 255 else leds[i].b = bTemp; 256 } 257 258 } 259 } 260 FastLED.show(); 261 lastFadeTime = currentMillis; 262 } 263 264 265} 266 267void handleSerialCommunication() { 268 if (PiSerial.available() > 0) { //if there's any serial data 269 /* 270 if (data[0] == TEXT_EINGABE) { //if the upcoming data is a text; indicated by first data byte = 124 271 //inputString = PiSerial.readString(); 272 273 for (byte textIndex = 0; textIndex < (data[1] - 193); textIndex++) { //194 = textlnge 1, ..., 224 = textlnge 30 274 text[textIndex] = PiSerial.read(); 275 } 276 text[data[1] - 193] = '\\0'; 277 278 newText = true; //text saved 279 data[0] = 0; 280 data[1] = 0; 281 282 } 283 */ 284 //else if !!!!!!! wenn oben auskommentiert 285 286 if (PiSerial.peek() >= 1 && PiSerial.peek() <= 191) { //if first data byte is valid 287 PiSerial.readBytes(data, 2); 288 //if (data[0] == TEXT_EINGABE) digitalWrite(READY_PIN, LOW); 289#if DEBUG 290 DebugSerial.println("Empfangen: " + (String)data[0] + ", " + (String)data[1]); 291#endif 292 } 293 else { //else; first data byte is invalid (0 or greater than 191) 294 byte errorMessage = PiSerial.read(); 295 //PiSerial.print(DATA_ERROR); 296 //PiSerial.print(errorMessage); 297#if DEBUG 298 DebugSerial.print("DATA_ERROR: "); 299 DebugSerial.println(errorMessage); 300#endif 301 } 302 } 303} 304 305void handleData() { 306 if (data[0] >= LED_START && data[0] <= LED_END) { //if data is LED data 307 if (data[1] < OFF || data[1] > FARBEN_END) { //if second data byte has invalid color 308 //invalid color/data byte 309 //PiSerial.print(DATA_ERROR); 310 //PiSerial.print(data[1]); 311#if DEBUG 312 DebugSerial.print("DATA_ERROR_INVALID_COLOR: "); 313 DebugSerial.println(data[1]); 314#endif 315 316 } 317 else { //color value is valid 318 //led mit farbe (in data[1]) ansteuern 319 byte i = data[0] - 1; 320 321 if (data[1] == OFF) ledsAim[i] = CRGB::Black; 322 else if (data[1] == ON) ledsAim[i] = CRGB::White; //hier warmwei einfgen 323 else ledsAim[i].setHue((data[1] - 194) * 16); //set aim color for led to chosen value 324 325 setLEDFade(i); 326 327 } 328 data[0] = 0; 329 data[1] = 0; 330 } 331 332 else if (data[0] == TWERKING_SANTA) { 333 334 335 if (!santaFlag) { 336 digitalWrite(READY_PIN, LOW); 337 338 if (random8(100) > CHANCE_SANTA_SOLO - 1) { 339 santaFlag = true; 340 digitalWrite(READY_PIN, HIGH); 341 } 342 else santaSoloFlag = true; 343 } 344 345 data[0] = 0; 346 data[1] = 0; 347 348 } 349 350 else if ( data[0] == TRAIN) { 351 currentTime = millis(); 352 if (currentTime - lastTrainAction > 1000) { 353 if (data[1] == OFF && trainFlag) { 354 trainActionTime = currentTime; 355 lastTrainAction = trainActionTime; 356 digitalWrite(TRAIN_PIN, LOW); 357 trainFlag = false; 358 } 359 360 else if (data[1] == ON && !trainFlag) { 361 trainActionTime = currentTime; 362 lastTrainAction = trainActionTime; 363 digitalWrite(TRAIN_PIN, HIGH); 364 trainFlag = true; 365 trainTime = millis(); 366 } 367 } 368 data[0] = 0; 369 data[1] = 0; 370 371 372 } 373 374 else if (data[0] == LIGHT_CHAIN) { 375 if (data[1] == OFF && lightChainFlag) { 376 digitalWrite(LIGHT_CHAIN_PIN, LOW); 377 lightChainFlag = false; 378 lightChainTime = millis(); 379 } 380 381 else if (data[1] == ON && !lightChainFlag) { 382 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 383 lightChainFlag = true; 384 } 385 data[0] = 0; 386 data[1] = 0; 387 } 388 389 else if (data[0] == SPARKLING) { 390 if (data[1] == ON && !sparklingFlag) { 391 sparklingFlag = true; 392 sparklingTime = millis(); 393 } 394 395 else if (data[1] == OFF && sparklingFlag) { 396 sparklingFlag = false; 397 } 398 399 data[0] = 0; 400 data[1] = 0; 401 } 402 403 else if (data[0] == ANIMATIONS) { 404 digitalWrite(READY_PIN, LOW); 405 animations(); 406 digitalWrite(READY_PIN, HIGH); 407 data[0] = 0; 408 data[1] = 0; 409 } 410 411 else if (data[0] == TREE_BLACKOUT) { 412 413 for (byte i = 0; i < NUM_LEDS; i++) { 414 ledsAim[i] = CRGB::Black; 415 setLEDFade(i); 416 } 417 418 data[0] = 0; 419 data[1] = 0; 420 } 421 422 423 /* 424 if (newText) { //handle text entry 425 //inputString.toCharArray(text, 31); 426 427 #if DEBUG 428 DebugSerial.println(text); //debug 429 DebugSerial.flush(); 430 #endif 431 digitalWrite(READY_PIN, HIGH); 432 //text anzeigen 433 newText = false; 434 } 435 */ 436} 437 438void animations() { 439 fillSpiralCCW(); 440 fillSpiralCW(); 441 fillSpiralCCW(); 442 fillSpiralCW(); 443 444 for (byte i = 0; i < NUM_LEDS; i++) { 445 leds[i] = ledsAim[i]; 446 } 447 FastLED.show(); 448} 449 450void setLEDFade(byte i) { 451 if (leds[i] != ledsAim[i]) { 452 ledsStep[i].fade = true; 453 454 if (ledsAim[i].r != leds[i].r) { 455 ledsStep[i].rStep = ((int)ledsAim[i].r - (int)leds[i].r) / (int)fadeSteps; 456 if (ledsStep[i].rStep == 0) { 457 if (ledsAim[i].r > leds[i].r) ledsStep[i].rStep = 1; 458 else ledsStep[i].rStep = -1; 459 } 460#if DEBUG 461 DebugSerial.println("rStep: " + (String)ledsStep[i].rStep); //debug 462#endif 463 } 464 if (ledsAim[i].g != leds[i].g) { 465 ledsStep[i].gStep = ((int)ledsAim[i].g - (int)leds[i].g) / (int)fadeSteps; 466 if (ledsStep[i].gStep == 0) { 467 if (ledsAim[i].g > leds[i].g) ledsStep[i].gStep = 1; 468 else ledsStep[i].gStep = -1; 469 } 470#if DEBUG 471 DebugSerial.println("gStep: " + (String)ledsStep[i].gStep); //debug 472#endif 473 } 474 if (ledsAim[i].b != leds[i].b) { 475 ledsStep[i].bStep = ((int)ledsAim[i].b - (int)leds[i].b) / (int)fadeSteps; 476 if (ledsStep[i].bStep == 0) { 477 if (ledsAim[i].b > leds[i].b) ledsStep[i].bStep = 1; 478 else ledsStep[i].bStep = -1; 479 } 480#if DEBUG 481 DebugSerial.println("bStep: " + (String)ledsStep[i].bStep); //debug 482#endif 483 } 484 485 } 486} 487 488 489void fillSpiralCCW() { 490 491 FastLED.clear(); 492 FastLED.show(); 493 494 for (byte i = 0; i < (sizeof(spiralCCW) / sizeof(byte)); i++) { 495 leds[spiralCCW[i]].setHue(hueTemp); 496 FastLED.show(); 497 FastLED.delay(30); 498 hueTemp += 2; 499 } 500 501 for (byte i = (sizeof(spiralCCW) / sizeof(byte)) - 1; i > 0; i--) { 502 leds[spiralCCW[i]] = CRGB::Black; 503 FastLED.show(); 504 FastLED.delay(30); 505 } 506} 507 508void fillSpiralCW() { 509 510 FastLED.clear(); 511 FastLED.show(); 512 513 for (byte i = 0; i < (sizeof(spiralCW) / sizeof(byte)); i++) { 514 leds[spiralCW[i]].setHue(hueTemp); 515 FastLED.show(); 516 FastLED.delay(30); 517 hueTemp += 2; 518 } 519 520 for (byte i = (sizeof(spiralCW) / sizeof(byte)) - 1; i > 0; i--) { 521 leds[spiralCW[i]] = CRGB::Black; 522 FastLED.show(); 523 FastLED.delay(30); 524 } 525} 526 527 528void frameMarquee() { 529 FastLED.clear(); 530 FastLED.show(); 531 532 for (int j = 0; j < 400; j++) { 533 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 534 leds[frame[i]].setHue(hueTemp); 535 hueTemp += 2; 536 } 537 hueTemp = 2 * j; 538 FastLED.show(); 539 FastLED.delay(40); 540 } 541 FastLED.clear(); 542 FastLED.show(); 543} 544 545void innerFrame() { 546 for (int j = 0; j < 15; j++) { 547 548 hueTemp += 40; 549 550 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 551 leds[frame[i]].setHue(hueTemp); 552 } 553 FastLED.show(); 554 FastLED.delay(200); 555 556 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 557 leds[frame[i]] = CRGB::Black; 558 } 559 560 hueTemp += 40; 561 562 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); i++) { 563 leds[inner[i]].setHue(hueTemp); 564 } 565 FastLED.show(); 566 FastLED.delay(200); 567 568 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); i++) { 569 leds[inner[i]] = CRGB::Black; 570 } 571 } 572 FastLED.clear(); 573 FastLED.show(); 574} 575 576void triangle() { 577 hueTemp += 16; 578 for (byte i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 579 leds[triangle1[i]].setHue(hueTemp); 580 } 581 FastLED.show(); 582 FastLED.delay(150); 583 for (byte i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 584 leds[triangle1[i]] = CRGB::Black; 585 } 586 hueTemp += 16; 587 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 588 leds[triangle2[i]].setHue(hueTemp); 589 } 590 FastLED.show(); 591 FastLED.delay(150); 592 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 593 leds[triangle2[i]] = CRGB::Black; 594 } 595 hueTemp += 16; 596 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); i++) { 597 leds[triangle3[i]].setHue(hueTemp); 598 } 599 FastLED.show(); 600 FastLED.delay(150); 601 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); i++) { 602 leds[triangle3[i]] = CRGB::Black; 603 } 604 hueTemp += 16; 605 for (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 606 leds[triangle4[i]].setHue(hueTemp); 607 } 608 FastLED.show(); 609 FastLED.delay(150); 610 for (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 611 leds[triangle4[i]] = CRGB::Black; 612 } 613 614} 615 616
Parola_Fonts_data.h
arduino
Fonts for the dot matrix to allow umlaute etc.
1// Data file for UTF-8 example user defined fonts 2#ifndef FONTS_DATA_H 3#define FONTS_DATA_H 4 5MD_MAX72XX::fontType_t ExtASCII[] PROGMEM = 6{ 7 0, // 0 - 'Unused' 8 0, // 1 - 'Unused' 9 0, // 2 - 'Unused' 10 0, // 3 - 'Unused' 11 0, // 4 - 'Unused' 12 0, // 5 - 'Unused' 13 0, // 6 - 'Unused' 14 0, // 7 - 'Unused' 15 0, // 8 - 'Unused' 16 0, // 9 - 'Unused' 17 0, // 10 - 'Unused' 18 0, // 11 - 'Unused' 19 0, // 12 - 'Unused' 20 0, // 13 - 'Unused' 21 0, // 14 - 'Unused' 22 0, // 15 - 'Unused' 23 0, // 16 - 'Unused' 24 0, // 17 - 'Unused' 25 0, // 18 - 'Unused' 26 0, // 19 - 'Unused' 27 0, // 20 - 'Unused' 28 0, // 21 - 'Unused' 29 0, // 22 - 'Unused' 30 0, // 23 - 'Unused' 31 0, // 24 - 'Unused' 32 0, // 25 - 'Unused' 33 0, // 26 - 'Unused' 34 0, // 27 - 'Unused' 35 0, // 28 - 'Unused' 36 0, // 29 - 'Unused' 37 0, // 30 - 'Unused' 38 0, // 31 - 'Unused' 39 2, 0, 0, // 32 - 'Space' 40 1, 95, // 33 - '!' 41 3, 7, 0, 7, // 34 - '"' 42 5, 20, 127, 20, 127, 20, // 35 - '#' 43 5, 36, 42, 127, 42, 18, // 36 - '$' 44 5, 35, 19, 8, 100, 98, // 37 - '%' 45 5, 54, 73, 86, 32, 80, // 38 - '&' 46 2, 4, 3, // 39 47 3, 28, 34, 65, // 40 - '(' 48 3, 65, 34, 28, // 41 - ')' 49 5, 42, 28, 127, 28, 42, // 42 - '*' 50 5, 8, 8, 62, 8, 8, // 43 - '+' 51 2, 128, 96, // 44 - ',' 52 5, 8, 8, 8, 8, 8, // 45 - '-' 53 2, 96, 96, // 46 - '.' 54 5, 32, 16, 8, 4, 2, // 47 - '/' 55 5, 62, 81, 73, 69, 62, // 48 - '0' 56 3, 66, 127, 64, // 49 - '1' 57 5, 114, 73, 73, 73, 70, // 50 - '2' 58 5, 33, 65, 73, 77, 51, // 51 - '3' 59 5, 24, 20, 18, 127, 16, // 52 - '4' 60 5, 39, 69, 69, 69, 57, // 53 - '5' 61 5, 60, 74, 73, 73, 49, // 54 - '6' 62 5, 65, 33, 17, 9, 7, // 55 - '7' 63 5, 54, 73, 73, 73, 54, // 56 - '8' 64 5, 70, 73, 73, 41, 30, // 57 - '9' 65 1, 20, // 58 - ':' 66 2, 128, 104, // 59 - ';' 67 4, 8, 20, 34, 65, // 60 - '<' 68 5, 20, 20, 20, 20, 20, // 61 - '=' 69 4, 65, 34, 20, 8, // 62 - '>' 70 5, 2, 1, 89, 9, 6, // 63 - '?' 71 5, 62, 65, 93, 89, 78, // 64 - '@' 72 5, 124, 18, 17, 18, 124, // 65 - 'A' 73 5, 127, 73, 73, 73, 54, // 66 - 'B' 74 5, 62, 65, 65, 65, 34, // 67 - 'C' 75 5, 127, 65, 65, 65, 62, // 68 - 'D' 76 5, 127, 73, 73, 73, 65, // 69 - 'E' 77 5, 127, 9, 9, 9, 1, // 70 - 'F' 78 5, 62, 65, 65, 81, 115, // 71 - 'G' 79 5, 127, 8, 8, 8, 127, // 72 - 'H' 80 3, 65, 127, 65, // 73 - 'I' 81 5, 32, 64, 65, 63, 1, // 74 - 'J' 82 5, 127, 8, 20, 34, 65, // 75 - 'K' 83 5, 127, 64, 64, 64, 64, // 76 - 'L' 84 5, 127, 2, 28, 2, 127, // 77 - 'M' 85 5, 127, 4, 8, 16, 127, // 78 - 'N' 86 5, 62, 65, 65, 65, 62, // 79 - 'O' 87 5, 127, 9, 9, 9, 6, // 80 - 'P' 88 5, 62, 65, 81, 33, 94, // 81 - 'Q' 89 5, 127, 9, 25, 41, 70, // 82 - 'R' 90 5, 38, 73, 73, 73, 50, // 83 - 'S' 91 5, 3, 1, 127, 1, 3, // 84 - 'T' 92 5, 63, 64, 64, 64, 63, // 85 - 'U' 93 5, 31, 32, 64, 32, 31, // 86 - 'V' 94 5, 63, 64, 56, 64, 63, // 87 - 'W' 95 5, 99, 20, 8, 20, 99, // 88 - 'X' 96 5, 3, 4, 120, 4, 3, // 89 - 'Y' 97 5, 97, 89, 73, 77, 67, // 90 - 'Z' 98 3, 127, 65, 65, // 91 - '[' 99 5, 2, 4, 8, 16, 32, // 92 - '\\' 100 3, 65, 65, 127, // 93 - ']' 101 5, 4, 2, 1, 2, 4, // 94 - '^' 102 5, 64, 64, 64, 64, 64, // 95 - '_' 103 2, 3, 4, // 96 - '`' 104 5, 32, 84, 84, 120, 64, // 97 - 'a' 105 5, 127, 40, 68, 68, 56, // 98 - 'b' 106 5, 56, 68, 68, 68, 40, // 99 - 'c' 107 5, 56, 68, 68, 40, 127, // 100 - 'd' 108 5, 56, 84, 84, 84, 24, // 101 - 'e' 109 4, 8, 126, 9, 2, // 102 - 'f' 110 5, 24, 164, 164, 156, 120, // 103 - 'g' 111 5, 127, 8, 4, 4, 120, // 104 - 'h' 112 3, 68, 125, 64, // 105 - 'i' 113 4, 64, 128, 128, 122, // 106 - 'j' 114 4, 127, 16, 40, 68, // 107 - 'k' 115 3, 65, 127, 64, // 108 - 'l' 116 5, 124, 4, 120, 4, 120, // 109 - 'm' 117 5, 124, 8, 4, 4, 120, // 110 - 'n' 118 5, 56, 68, 68, 68, 56, // 111 - 'o' 119 5, 252, 24, 36, 36, 24, // 112 - 'p' 120 5, 24, 36, 36, 24, 252, // 113 - 'q' 121 5, 124, 8, 4, 4, 8, // 114 - 'r' 122 5, 72, 84, 84, 84, 36, // 115 - 's' 123 4, 4, 63, 68, 36, // 116 - 't' 124 5, 60, 64, 64, 32, 124, // 117 - 'u' 125 5, 28, 32, 64, 32, 28, // 118 - 'v' 126 5, 60, 64, 48, 64, 60, // 119 - 'w' 127 5, 68, 40, 16, 40, 68, // 120 - 'x' 128 5, 76, 144, 144, 144, 124, // 121 - 'y' 129 5, 68, 100, 84, 76, 68, // 122 - 'z' 130 3, 8, 54, 65, // 123 - '{' 131 1, 119, // 124 - '|' 132 3, 65, 54, 8, // 125 - '}' 133 5, 2, 1, 2, 4, 2, // 126 - '~' 134 0, // 127 - 'Unused' 135 6, 20, 62, 85, 85, 65, 34, // 128 - 'Euro sign' 136 5, 28, 62, 124, 62, 28, // 129 - 'Heart' costum char!!! 137 2, 128, 96, // 130 - 'Single low 9 quotation mark' 138 5, 192, 136, 126, 9, 3, // 131 - 'f with hook' 139 4, 128, 96, 128, 96, // 132 - 'Single low 9 quotation mark' 140 8, 96, 96, 0, 96, 96, 0, 96, 96, // 133 - 'Horizontal ellipsis' 141 3, 4, 126, 4, // 134 - 'Dagger' 142 3, 20, 126, 20, // 135 - 'Double dagger' 143 4, 2, 1, 1, 2, // 136 - 'Modifier circumflex' 144 7, 35, 19, 104, 100, 2, 97, 96, // 137 - 'Per mille sign' 145 5, 72, 85, 86, 85, 36, // 138 - 'S with caron' 146 3, 8, 20, 34, // 139 - '< quotation' 147 6, 62, 65, 65, 127, 73, 73, // 140 - 'OE' 148 0, // 141 - 'Not used' 149 5, 68, 101, 86, 77, 68, // 142 - 'z with caron' 150 0, // 143 - 'Not used' 151 0, // 144 - 'Not used' 152 2, 3, 4, // 145 - 'Left single quote mark' 153 2, 4, 3, // 146 - 'Right single quote mark' 154 4, 3, 4, 3, 4, // 147 - 'Left double quote marks' 155 4, 4, 3, 4, 3, // 148 - 'Right double quote marks' 156 4, 0, 24, 60, 24, // 149 - 'Bullet Point' 157 3, 8, 8, 8, // 150 - 'En dash' 158 5, 8, 8, 8, 8, 8, // 151 - 'Em dash' 159 4, 2, 1, 2, 1, // 152 - 'Small ~' 160 7, 1, 15, 1, 0, 15, 2, 15, // 153 - 'TM' 161 5, 72, 85, 86, 85, 36, // 154 - 's with caron' 162 3, 34, 20, 8, // 155 - '> quotation' 163 7, 56, 68, 68, 124, 84, 84, 8, // 156 - 'oe' 164 0, // 157 - 'Not used' 165 5, 68, 101, 86, 77, 68, // 158 - 'z with caron' 166 5, 12, 17, 96, 17, 12, // 159 - 'Y diaresis' 167 2, 0, 0, // 160 - 'Non-breaking space' 168 1, 125, // 161 - 'Inverted !' 169 5, 60, 36, 126, 36, 36, // 162 - 'Cent sign' 170 5, 72, 126, 73, 65, 102, // 163 - 'Pound sign' 171 5, 34, 28, 20, 28, 34, // 164 - 'Currency sign' 172 5, 43, 47, 252, 47, 43, // 165 - 'Yen' 173 1, 119, // 166 - '|' 174 4, 102, 137, 149, 106, // 167 - 'Section sign' 175 3, 1, 0, 1, // 168 - 'Spacing diaresis' 176 7, 62, 65, 93, 85, 85, 65, 62, // 169 - 'Copyright' 177 3, 13, 13, 15, // 170 - 'Feminine Ordinal Ind.' 178 5, 8, 20, 42, 20, 34, // 171 - '<<' 179 5, 8, 8, 8, 8, 56, // 172 - 'Not sign' 180 0, // 173 - 'Soft Hyphen' 181 7, 62, 65, 127, 75, 117, 65, 62, // 174 - 'Registered Trademark' 182 5, 1, 1, 1, 1, 1, // 175 - 'Spacing Macron Overline' 183 3, 2, 5, 2, // 176 - 'Degree' 184 5, 68, 68, 95, 68, 68, // 177 - '+/-' 185 3, 25, 21, 19, // 178 - 'Superscript 2' 186 3, 17, 21, 31, // 179 - 'Superscript 3' 187 2, 2, 1, // 180 - 'Acute accent' 188 4, 252, 64, 64, 60, // 181 - 'micro (mu)' 189 5, 6, 9, 127, 1, 127, // 182 - 'Paragraph Mark' 190 2, 24, 24, // 183 - 'Middle Dot' 191 3, 128, 128, 96, // 184 - 'Spacing sedilla' 192 2, 2, 31, // 185 - 'Superscript 1' 193 4, 6, 9, 9, 6, // 186 - 'Masculine Ordinal Ind.' 194 5, 34, 20, 42, 20, 8, // 187 - '>>' 195 6, 64, 47, 16, 40, 52, 250, // 188 - '1/4' 196 6, 64, 47, 16, 200, 172, 186, // 189 - '1/2' 197 6, 85, 53, 31, 40, 52, 250, // 190 - '3/4' 198 5, 48, 72, 77, 64, 32, // 191 - 'Inverted ?' 199 5, 120, 20, 21, 22, 120, // 192 - 'A grave' 200 5, 120, 22, 21, 20, 120, // 193 - 'A acute' 201 5, 122, 21, 21, 21, 122, // 194 - 'A circumflex' 202 5, 120, 22, 21, 22, 121, // 195 - 'A tilde' 203 5, 120, 21, 20, 21, 120, // 196 - 'A diaresis' 204 5, 120, 20, 21, 20, 120, // 197 - 'A ring above' 205 6, 124, 10, 9, 127, 73, 73, // 198 - 'AE' 206 5, 30, 161, 161, 97, 18, // 199 - 'C sedilla' 207 4, 124, 85, 86, 68, // 200 - 'E grave' 208 4, 124, 86, 85, 68, // 201 - 'E acute' 209 4, 126, 85, 85, 70, // 202 - 'E circumflex' 210 4, 124, 85, 84, 69, // 203 - 'E diaresis' 211 3, 68, 125, 70, // 204 - 'I grave' 212 3, 68, 126, 69, // 205 - 'I acute' 213 3, 70, 125, 70, // 206 - 'I circumplex' 214 3, 69, 124, 69, // 207 - 'I diaresis' 215 6, 4, 127, 69, 65, 65, 62, // 208 - 'Capital Eth' 216 5, 124, 10, 17, 34, 125, // 209 - 'N tilde' 217 5, 56, 68, 69, 70, 56, // 210 - 'O grave' 218 5, 56, 70, 69, 68, 56, // 211 - 'O acute' 219 5, 58, 69, 69, 69, 58, // 212 - 'O circumflex' 220 5, 56, 70, 69, 70, 57, // 213 - 'O tilde' 221 5, 56, 69, 68, 69, 56, // 214 - 'O diaresis' 222 5, 34, 20, 8, 20, 34, // 215 - 'Multiplication sign' 223 7, 64, 62, 81, 73, 69, 62, 1, // 216 - 'O slashed' 224 5, 60, 65, 66, 64, 60, // 217 - 'U grave' 225 5, 60, 64, 66, 65, 60, // 218 - 'U acute' 226 5, 58, 65, 65, 65, 58, // 219 - 'U circumflex' 227 5, 60, 65, 64, 65, 60, // 220 - 'U diaresis' 228 5, 12, 16, 98, 17, 12, // 221 - 'Y acute' 229 4, 127, 18, 18, 12, // 222 - 'Capital thorn' 230 4, 254, 37, 37, 26, // 223 - 'Small letter sharp S' 231 5, 32, 84, 85, 122, 64, // 224 - 'a grave' 232 5, 32, 84, 86, 121, 64, // 225 - 'a acute' 233 5, 34, 85, 85, 121, 66, // 226 - 'a circumflex' 234 5, 32, 86, 85, 122, 65, // 227 - 'a tilde' 235 5, 32, 85, 84, 121, 64, // 228 - 'a diaresis' 236 5, 32, 84, 85, 120, 64, // 229 - 'a ring above' 237 7, 32, 84, 84, 124, 84, 84, 8, // 230 - 'ae' 238 5, 24, 36, 164, 228, 40, // 231 - 'c sedilla' 239 5, 56, 84, 85, 86, 88, // 232 - 'e grave' 240 5, 56, 84, 86, 85, 88, // 233 - 'e acute' 241 5, 58, 85, 85, 85, 90, // 234 - 'e circumflex' 242 5, 56, 85, 84, 85, 88, // 235 - 'e diaresis' 243 3, 68, 125, 66, // 236 - 'i grave' 244 3, 68, 126, 65, // 237 - 'i acute' 245 3, 70, 125, 66, // 238 - 'i circumflex' 246 3, 69, 124, 65, // 239 - 'i diaresis' 247 4, 48, 75, 74, 61, // 240 - 'Small eth' 248 4, 122, 9, 10, 113, // 241 - 'n tilde' 249 5, 56, 68, 69, 70, 56, // 242 - 'o grave' 250 5, 56, 70, 69, 68, 56, // 243 - 'o acute' 251 5, 58, 69, 69, 69, 58, // 244 - 'o circumflex' 252 5, 56, 70, 69, 70, 57, // 245 - 'o tilde' 253 5, 56, 69, 68, 69, 56, // 246 - 'o diaresis' 254 5, 8, 8, 42, 8, 8, // 247 - 'Division sign' 255 6, 64, 56, 84, 76, 68, 58, // 248 - 'o slashed' 256 5, 60, 65, 66, 32, 124, // 249 - 'u grave' 257 5, 60, 64, 66, 33, 124, // 250 - 'u acute' 258 5, 58, 65, 65, 33, 122, // 251 - 'u circumflex' 259 5, 60, 65, 64, 33, 124, // 252 - 'u diaresis' 260 4, 156, 162, 161, 124, // 253 - 'y acute' 261 4, 252, 72, 72, 48, // 254 - 'small thorn' 262 4, 157, 160, 160, 125, // 255 - 'y diaresis' 263}; 264 265#endif 266
TelegramBot.h
arduino
Adapt to changed *.cpp
1// Copyright Casa Jasmina 2016 2// LGPL License 3// 4// TelegramBot library 5// https://github.com/CasaJasmina/TelegramBot-Library 6 7#ifndef TelegramBot_h 8#define TelegramBot_h 9 10#include <Arduino.h> 11#include <ArduinoJson.h> 12#include <Client.h> 13#include <TelegramKeyboard.h> 14 15#define HOST "api.telegram.org" 16#define SSL_PORT 443 17#define JSON_BUFF_SIZE 10000 18 19struct locationStruct{ 20 String lon; 21 String lat; 22}; 23 24struct message{ 25 String text; 26 String chat_id; 27 String sender; 28 String first_name; 29 String date; 30 locationStruct location; 31}; 32 33 34class TelegramBot 35{ 36 public: 37 TelegramBot(const char* token, Client &client); 38 void begin(); 39 String sendMessage(String chat_id, String text); 40 String sendMessage(String chat_id, String text, TelegramKeyboard &keyboard_markup, bool one_time_keyboard = true, bool resize_keyboard = true); 41 String postMessage(String msg); 42 message getUpdates(); 43 44 45 private: 46 String readPayload(); 47 String convertText(String unicodeStr); 48 const char* token; 49 50 int last_message_recived; 51 52 Client *client; 53}; 54 55#endif 56
TelegramBot.cpp
arduino
I made some changes to the TelegramBot library to get the first name and location of the user. And also a function to convert utf16 to extended ascii for use with the dot matrix.
1#include "TelegramBot.h" 2 3TelegramBot::TelegramBot(const char* token, Client &client) { 4 this->client = &client; 5 this->token=token; 6} 7 8 9void TelegramBot::begin() { 10 if(!client->connected()){ 11 client->connect(HOST, SSL_PORT); 12 } 13} 14 15/************************************************************************************ 16 * GetUpdates - function to receive messages from telegram as a Json and parse them * 17 ************************************************************************************/ 18message TelegramBot::getUpdates() { 19 begin(); 20 21 //Send your request to api.telegram.org 22 String getRequest = "GET /bot"+String(token)+"/getUpdates?limit=1&offset="+String(last_message_recived)+" HTTP/1.1"; 23 client->println(getRequest); 24 client->println("User-Agent: curl/7.37.1"); 25 client->println("Host: api.telegram.org"); 26 client->println("Accept: */*"); 27 client->println(); 28 29 String payload = readPayload(); 30 if (payload != "") { 31 message m; 32 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 33 JsonObject & root = jsonBuffer.parseObject(payload); 34 35 36 37 if(root.success()){ 38 39 int update_id = root["result"][0]["update_id"]; 40 update_id = update_id+1; 41 42 if(last_message_recived != update_id ){ 43 String sender = root["result"][0]["message"]["from"]["username"]; 44 String text = root["result"][0]["message"]["text"]; 45 String chat_id = root["result"][0]["message"]["chat"]["id"]; 46 String date = root["result"][0]["message"]["date"]; 47 String first_name = root["result"][0]["message"]["from"]["first_name"]; 48 String lon = root["result"][0]["message"]["location"]["longitude"]; 49 String lat = root["result"][0]["message"]["location"]["latitude"]; 50 51 m.sender = sender; 52 m.text = text; 53 m.chat_id = chat_id; 54 m.date = date; 55 m.first_name = first_name; 56 m.location.lon = lon; 57 m.location.lat = lat; 58 59 last_message_recived=update_id; 60 return m; 61 }else{ 62 m.chat_id = ""; 63 return m; 64 } 65 } 66 else{ 67 Serial.println(""); 68 Serial.println("Message too long, skipped."); 69 Serial.println(""); 70 int update_id_first_digit=0; 71 int update_id_last_digit=0; 72 for(int a =0; a<3; a++){ 73 update_id_first_digit= payload.indexOf(':',update_id_first_digit+1); 74 } 75 for(int a =0; a<2; a++){ 76 update_id_last_digit= payload.indexOf(',',update_id_last_digit+1); 77 } 78 last_message_recived = payload.substring(update_id_first_digit+1,update_id_last_digit).toInt() +1; 79 } 80 } 81 } 82 83// send message function 84// send a simple text message to a telegram char 85String TelegramBot::sendMessage(String chat_id, String text) { 86 if(chat_id!="0" && chat_id!=""){ 87 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 88 JsonObject& buff = jsonBuffer.createObject(); 89 buff["chat_id"] = chat_id; 90 buff["text"] = text; 91 92 String msg; 93 buff.printTo(msg); 94 return postMessage(msg); 95 } else { 96 Serial.println("Chat_id not defined"); 97 } 98} 99 100// send a message to a telegram chat with a reply markup 101String TelegramBot::sendMessage(String chat_id, String text, TelegramKeyboard &keyboard_markup, bool one_time_keyboard, bool resize_keyboard) { 102 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 103 JsonObject& buff = jsonBuffer.createObject(); 104 buff["chat_id"] = chat_id; 105 buff["text"] = text; 106 107 JsonObject& reply_markup = buff.createNestedObject("reply_markup"); 108 JsonArray& keyboard = reply_markup.createNestedArray("keyboard"); 109 110 for (int a = 1 ; a <= keyboard_markup.length() ; a++){ 111 JsonArray& row = keyboard.createNestedArray(); 112 for( int b = 1; b <= keyboard_markup.rowSize(a) ; b++){ 113 row.add(keyboard_markup.getButton(a,b)); 114 } 115 } 116 117 reply_markup.set<bool>("one_time_keyboard", one_time_keyboard); 118 reply_markup.set<bool>("resize_keyboard", resize_keyboard); 119 reply_markup.set<bool>("selective", false); 120 121 String msg; 122 buff.printTo(msg); 123 // Serial.println(msg); 124 return postMessage(msg); 125} 126 127// gets the telegram json string 128// posts the message to telegram 129// returns the payload 130String TelegramBot::postMessage(String msg) { 131 begin(); 132 133 client->println("POST /bot"+String(token)+"/sendMessage"+" HTTP/1.1"); 134 client->println("Host: api.telegram.org"); 135 client->println("Content-Type: application/json"); 136 client->println("Connection: close"); 137 client->print("Content-Length: "); 138 client->println(msg.length()); 139 client->println(); 140 client->println(msg); 141 142 return readPayload(); 143} 144 145// reads the payload coming from telegram server 146// returns the payload string 147String TelegramBot::readPayload(){ 148 char c; 149 String payload=""; 150 //Read the answer and save it in String payload 151 while (client->connected()) { 152 payload = client->readStringUntil('\ 153'); 154 if (payload == "\ ") { 155 break; 156 } 157 } 158 payload = client->readStringUntil('\ '); 159 // Serial.println(payload); 160 return convertText(payload); 161} 162 163String TelegramBot::convertText(String unicodeStr){ //converts UTF-16 Unicode to extended Ascii. Emojis not supported 164 String out = ""; 165 int len = unicodeStr.length(); 166 char iChar; 167 char* error; 168 for (int i = 0; i < len; i++){ 169 iChar = unicodeStr[i]; 170 if(iChar == '\\\\'){ // got escape char 171 iChar = unicodeStr[++i]; 172 if(iChar == 'u'){ // got unicode hex 173 char unicode[6]; 174 unicode[0] = '0'; 175 unicode[1] = 'x'; 176 for (int j = 0; j < 4; j++){ 177 iChar = unicodeStr[++i]; 178 unicode[j + 2] = iChar; 179 } 180 long unicodeVal = strtol(unicode, &error, 16); //convert the string 181 if (unicodeVal == 0x20AC) unicodeVal = 0x80; // euro sign 182 //Serial.print("strtol: "); 183 //Serial.println(unicodeVal, HEX); 184 out += (char)unicodeVal; 185 } else if(iChar == '/'){ 186 out += iChar; 187 } else if(iChar == 'n'){ 188 out += '\ 189'; 190 } 191 } else if (iChar == '<' && unicodeStr[i + 1] == '3') { //convert "<3" to costum set 'heart' char, ascii: 0x81 192 long charTemp = 0x81; 193 out += (char)charTemp; 194 i++; 195 } else { 196 out += iChar; 197 } 198 } 199 return out; 200}
TelegramBot.cpp
arduino
I made some changes to the TelegramBot library to get the first name and location of the user. And also a function to convert utf16 to extended ascii for use with the dot matrix.
1#include "TelegramBot.h" 2 3TelegramBot::TelegramBot(const char* token, Client &client) { 4 this->client = &client; 5 this->token=token; 6} 7 8 9void TelegramBot::begin() { 10 if(!client->connected()){ 11 client->connect(HOST, SSL_PORT); 12 } 13} 14 15/************************************************************************************ 16 * GetUpdates - function to receive messages from telegram as a Json and parse them * 17 ************************************************************************************/ 18message TelegramBot::getUpdates() { 19 begin(); 20 21 //Send your request to api.telegram.org 22 String getRequest = "GET /bot"+String(token)+"/getUpdates?limit=1&offset="+String(last_message_recived)+" HTTP/1.1"; 23 client->println(getRequest); 24 client->println("User-Agent: curl/7.37.1"); 25 client->println("Host: api.telegram.org"); 26 client->println("Accept: */*"); 27 client->println(); 28 29 String payload = readPayload(); 30 if (payload != "") { 31 message m; 32 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 33 JsonObject & root = jsonBuffer.parseObject(payload); 34 35 36 37 if(root.success()){ 38 39 int update_id = root["result"][0]["update_id"]; 40 update_id = update_id+1; 41 42 if(last_message_recived != update_id ){ 43 String sender = root["result"][0]["message"]["from"]["username"]; 44 String text = root["result"][0]["message"]["text"]; 45 String chat_id = root["result"][0]["message"]["chat"]["id"]; 46 String date = root["result"][0]["message"]["date"]; 47 String first_name = root["result"][0]["message"]["from"]["first_name"]; 48 String lon = root["result"][0]["message"]["location"]["longitude"]; 49 String lat = root["result"][0]["message"]["location"]["latitude"]; 50 51 m.sender = sender; 52 m.text = text; 53 m.chat_id = chat_id; 54 m.date = date; 55 m.first_name = first_name; 56 m.location.lon = lon; 57 m.location.lat = lat; 58 59 last_message_recived=update_id; 60 return m; 61 }else{ 62 m.chat_id = ""; 63 return m; 64 } 65 } 66 else{ 67 Serial.println(""); 68 Serial.println("Message too long, skipped."); 69 Serial.println(""); 70 int update_id_first_digit=0; 71 int update_id_last_digit=0; 72 for(int a =0; a<3; a++){ 73 update_id_first_digit= payload.indexOf(':',update_id_first_digit+1); 74 } 75 for(int a =0; a<2; a++){ 76 update_id_last_digit= payload.indexOf(',',update_id_last_digit+1); 77 } 78 last_message_recived = payload.substring(update_id_first_digit+1,update_id_last_digit).toInt() +1; 79 } 80 } 81 } 82 83// send message function 84// send a simple text message to a telegram char 85String TelegramBot::sendMessage(String chat_id, String text) { 86 if(chat_id!="0" && chat_id!=""){ 87 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 88 JsonObject& buff = jsonBuffer.createObject(); 89 buff["chat_id"] = chat_id; 90 buff["text"] = text; 91 92 String msg; 93 buff.printTo(msg); 94 return postMessage(msg); 95 } else { 96 Serial.println("Chat_id not defined"); 97 } 98} 99 100// send a message to a telegram chat with a reply markup 101String TelegramBot::sendMessage(String chat_id, String text, TelegramKeyboard &keyboard_markup, bool one_time_keyboard, bool resize_keyboard) { 102 StaticJsonBuffer<JSON_BUFF_SIZE> jsonBuffer; 103 JsonObject& buff = jsonBuffer.createObject(); 104 buff["chat_id"] = chat_id; 105 buff["text"] = text; 106 107 JsonObject& reply_markup = buff.createNestedObject("reply_markup"); 108 JsonArray& keyboard = reply_markup.createNestedArray("keyboard"); 109 110 for (int a = 1 ; a <= keyboard_markup.length() ; a++){ 111 JsonArray& row = keyboard.createNestedArray(); 112 for( int b = 1; b <= keyboard_markup.rowSize(a) ; b++){ 113 row.add(keyboard_markup.getButton(a,b)); 114 } 115 } 116 117 reply_markup.set<bool>("one_time_keyboard", one_time_keyboard); 118 reply_markup.set<bool>("resize_keyboard", resize_keyboard); 119 reply_markup.set<bool>("selective", false); 120 121 String msg; 122 buff.printTo(msg); 123 // Serial.println(msg); 124 return postMessage(msg); 125} 126 127// gets the telegram json string 128// posts the message to telegram 129// returns the payload 130String TelegramBot::postMessage(String msg) { 131 begin(); 132 133 client->println("POST /bot"+String(token)+"/sendMessage"+" HTTP/1.1"); 134 client->println("Host: api.telegram.org"); 135 client->println("Content-Type: application/json"); 136 client->println("Connection: close"); 137 client->print("Content-Length: "); 138 client->println(msg.length()); 139 client->println(); 140 client->println(msg); 141 142 return readPayload(); 143} 144 145// reads the payload coming from telegram server 146// returns the payload string 147String TelegramBot::readPayload(){ 148 char c; 149 String payload=""; 150 //Read the answer and save it in String payload 151 while (client->connected()) { 152 payload = client->readStringUntil('\n'); 153 if (payload == "\ ") { 154 break; 155 } 156 } 157 payload = client->readStringUntil('\r'); 158 // Serial.println(payload); 159 return convertText(payload); 160} 161 162String TelegramBot::convertText(String unicodeStr){ //converts UTF-16 Unicode to extended Ascii. Emojis not supported 163 String out = ""; 164 int len = unicodeStr.length(); 165 char iChar; 166 char* error; 167 for (int i = 0; i < len; i++){ 168 iChar = unicodeStr[i]; 169 if(iChar == '\\\\'){ // got escape char 170 iChar = unicodeStr[++i]; 171 if(iChar == 'u'){ // got unicode hex 172 char unicode[6]; 173 unicode[0] = '0'; 174 unicode[1] = 'x'; 175 for (int j = 0; j < 4; j++){ 176 iChar = unicodeStr[++i]; 177 unicode[j + 2] = iChar; 178 } 179 long unicodeVal = strtol(unicode, &error, 16); //convert the string 180 if (unicodeVal == 0x20AC) unicodeVal = 0x80; // euro sign 181 //Serial.print("strtol: "); 182 //Serial.println(unicodeVal, HEX); 183 out += (char)unicodeVal; 184 } else if(iChar == '/'){ 185 out += iChar; 186 } else if(iChar == 'n'){ 187 out += '\n'; 188 } 189 } else if (iChar == '<' && unicodeStr[i + 1] == '3') { //convert "<3" to costum set 'heart' char, ascii: 0x81 190 long charTemp = 0x81; 191 out += (char)charTemp; 192 i++; 193 } else { 194 out += iChar; 195 } 196 } 197 return out; 198}
dot_matrix_scrolling_text_test.ino
arduino
Code for the Arduino Nano to run the dot matrix.
1#include <MD_Parola.h> 2#include <MD_MAX72xx.h> 3#include <SPI.h> 4#include <Time.h> 5#include <TimeLib.h> 6#include "Parola_Fonts_data.h" 7 8#define MAX_DEVICES 8 9#define CLK_PIN 13 10#define DATA_PIN 11 11#define CS_PIN 10 12 13#define TIME 1 14#define TEXT 2 15#define WEATHER 3 16#define STATS 4 17 18#define NUM_TIMEZONES 8 19 20MD_Parola P = MD_Parola(CS_PIN, MAX_DEVICES); 21 22uint8_t scrollSpeed = 30; // default frame delay value 23textEffect_t scrollEffect = PA_SCROLL_LEFT; 24textPosition_t scrollAlign = PA_CENTER; 25uint16_t scrollPause = 0; // in milliseconds 26 27#define BUF_SIZE 100 28char curMessage[BUF_SIZE] = "www.steuermeinentannenbaum.de"; //{0x01}; 29char newMessage[BUF_SIZE]; 30String newMessageString = ""; 31bool newMessageAvailable = false, showClock = false; 32unsigned long lastNewMessageTime; 33byte dataByte = 0, zoneIndex, timeBuffer[3]; 34 35struct timeZonesStruct { 36 int GMT; 37 String name; 38}; 39 40timeZonesStruct timeZones[NUM_TIMEZONES] = { 41 {1, "Berlin"}, 42 {0, "UK"}, 43 { -8, "LA"}, 44 { -6, "Texas"}, 45 { -5, "NYC"}, 46 {11, "Sydney"}, 47 {9, "Tokyo"}, 48 {3, "Russia"} 49}; 50 51/* 52 void readSerial(void) 53 { 54 static char *cp = newMessage; 55 56 while (Serial1.available()) 57 { 58 cp = (char)Serial1.read(); 59 if ((*cp == '\n') || (cp - newMessage >= BUF_SIZE-2)) // end of message character or full buffer 60 { 61 cp = '\\0'; // end the string 62 // restart the index for next filling spree and flag we have a message waiting 63 cp = newMessage; 64 newMessageAvailable = true; 65 Serial.println(cp); 66 //Serial.flush(); 67 } 68 else // move char pointer to next position 69 cp++; 70 } 71 } 72*/ 73 74void readSerial(void) { 75 if (Serial.available()) { 76 if (dataByte == 0) dataByte = Serial.read(); 77 else if (dataByte == TEXT) { 78 newMessageString = Serial.readStringUntil('\n'); 79 newMessageString.toCharArray(newMessage, BUF_SIZE); 80 newMessageAvailable = true; 81 showClock = false; 82 lastNewMessageTime = millis(); 83 dataByte = 0; 84 } 85 else if (dataByte == TIME) { 86 Serial.readBytes(timeBuffer, 3); 87 setTime(timeBuffer[0], timeBuffer[1], timeBuffer[2], day(), month(), year()); 88 dataByte = 0; 89 } 90 } 91} 92 93 94 95void setup() 96{ 97 Serial.begin(9600); 98 99 randomSeed(analogRead(0)); 100 101 102 P.begin(); 103 P.setFont(ExtASCII); 104 P.displayClear(); 105 P.displaySuspend(false); 106 107 //P.setScrollSpacing(1); 108 109 lastNewMessageTime = millis(); 110 111 P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect); 112 113 //newMessage[0] = '\\0'; 114} 115 116void loop() 117{ 118 readSerial(); 119 120 if (millis() - lastNewMessageTime > 30000) showClock = true; 121 122 if (P.displayAnimate()) 123 { 124 if (showClock) { 125 P.setTextEffect(PA_SCROLL_DOWN, PA_SCROLL_DOWN); 126 P.setPause(5000); 127 128 newMessageString = timeZones[zoneIndex].name + ": "; 129 newMessageString += returnLocalTime(zoneIndex); 130 131 zoneIndex++; 132 if (zoneIndex >= NUM_TIMEZONES) zoneIndex = 0; 133 134 newMessageString.toCharArray(newMessage, BUF_SIZE); 135 strcpy(curMessage, newMessage); 136 newMessageString = ""; 137 138 P.displayReset(); 139 } 140 else if (newMessageAvailable) 141 { 142 P.setTextEffect(PA_SCROLL_LEFT, PA_SCROLL_LEFT); 143 P.setPause(0); 144 145 strcpy(curMessage, newMessage); 146 newMessageAvailable = false; 147 newMessageString = ""; 148 } 149 P.displayReset(); 150 } 151} 152 153String returnLocalTime(byte index) { 154 String temp; 155 int hourInt = hour() + timeZones[index].GMT; 156 157 if (hourInt < 0) hourInt = 24 + hourInt; 158 else if (hourInt > 23) hourInt -= 24; 159 160 if (hourInt < 10) temp += "0"; 161 temp += String(hourInt) + ":"; 162 if (minute() < 10) temp += "0"; 163 temp += String(minute()); 164 165 return temp; 166} 167 168
Telegram_Bot_xmas.ino
arduino
Code for the Arduino MKR1000.
1#define TEXT_SERIAL 1 2#define WATCHDOG 1 3#define DEBUG 0 4 5#include <Arduino.h> 6#include <Time.h> 7#include <TimeLib.h> 8#include <WiFi101.h> 9//#include <WiFiUdp.h> 10#include <SPI.h> 11#include <TelegramBot.h> 12//#include <time.h> 13//#include <RTCZero.h> 14 15#if TEXT_SERIAL 16#include <wiring_private.h> 17#endif 18 19#if WATCHDOG 20#include <Adafruit_SleepyDog.h> 21#endif 22 23#if TEXT_SERIAL 24Uart textSerial (&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0); 25 26void SERCOM3_Handler() // Interrupt handler for SERCOM3 27{ 28 textSerial.IrqHandler(); 29} 30#endif 31 32#define ledPin 6 33#define RBUFFSIZE 1000 34 35#define MAX_MESSAGES 16 36 37#define TIME 1 38#define TEXT 2 39#define WEATHER 3 40#define STATS 4 41 42/* 43 #define BEER_NAME 0 44 #define BEER_ID 1 45*/ 46 47char responseBuffer[RBUFFSIZE]; 48int rbindex = 0; 49 50boolean startCapture; 51unsigned long lastTimeSentTime, lastTextSent, currentTime, lastClockSent; 52 53// Initialize Wifi connection 54 55const char ssid[] = ""; // network SSID 56const char pass[] = ""; // network key 57 58// Initialize Telegram BOT 59 60const char BotToken[] = ""; 61 62char server[] = "api.openweathermap.org"; 63 64String eingabe; //Nachrichten[128]; 65char Nachrichten[MAX_MESSAGES][100]; 66byte numMessages, messageIndex, sendMessageIndex; 67 68WiFiSSLClient client; 69WiFiClient clienthttp; 70 71TelegramBot bot(BotToken, client); 72 73//RTCZero rtc; 74 75//TelegramKeyboard keyboardStart; 76/* 77const char* row1Start[] = {"/help", "/wlan"}; 78const char* row2Start[] = {"/ip", "/signal"}; 79//const char* row3Start[] = {"/alloff"}; 80*/ 81 82time_t tClock = 0; 83 84 85void setup() { 86 87 delay(3000); 88 89#if TEXT_SERIAL 90 textSerial.begin(9600); // Begin Uart for sending text to LED matrix 91#endif 92 93 Serial.begin(9600); 94 95#if TEXT_SERIAL 96 pinPeripheral(0, PIO_SERCOM); // Assign pins 0 & 1 SERCOM functionality 97 pinPeripheral(1, PIO_SERCOM); 98#endif 99 100#if WATCHDOG 101 Watchdog.enable(10000); 102#endif 103 104 // attempt to connect to Wifi network: 105#if DEBUG 106 Serial.print(F("Verbine mit WLAN: ")); 107 Serial.println(ssid); 108#endif 109 110 while (WiFi.begin(ssid, pass) != WL_CONNECTED) { 111 delay(500); 112 } 113 114#if DEBUG 115 Serial.println(F("Mit WLAN verbunden.")); 116#endif 117/* 118 byte counterT = 0; 119 while (tClock == 0 && counterT < 6) { 120 delay(1000); 121 counterT++; 122 123 tClock = WiFi.getTime(); 124 125 } 126 Serial.println(tClock); 127 */ 128 getCurrentTime(); 129 130 if (tClock != 0) { 131 textSerial.write(TIME); 132 textSerial.write(hour(tClock)); 133 textSerial.write(minute(tClock)); 134 textSerial.write(second(tClock)); 135 } 136 tClock = 0; 137 138 lastClockSent = millis(); 139 140 bot.begin(); 141 142 pinMode(ledPin, OUTPUT); 143 digitalWrite(ledPin, LOW); 144/* 145 keyboardStart.addRow(row1Start, 2); 146 keyboardStart.addRow(row2Start, 2); 147 //keyboardStart.addRow(row3Start, 1); 148 */ 149 150 message m = bot.getUpdates(); 151} 152 153void loop() { 154#if WATCHDOG 155 Watchdog.reset(); 156#endif 157 158 if ( WiFi.status() != WL_CONNECTED) { 159 //WiFi.disconnect(); 160 while (WiFi.begin(ssid, pass) != WL_CONNECTED) { 161#if DEBUG 162 Serial.print("."); 163#endif 164 delay(1000); 165 } 166 } 167 currentTime = millis(); 168 169 if (numMessages > 0 && currentTime - lastTextSent > 20000) { 170 textSerial.write(TEXT); 171 textSerial.print(String(Nachrichten[sendMessageIndex])); 172 lastTextSent = currentTime; 173 sendMessageIndex++; 174 numMessages--; 175 if (sendMessageIndex >= MAX_MESSAGES) sendMessageIndex = 0; 176 } 177 178 if (currentTime - lastTextSent > 120000) { 179 textSerial.write(TEXT); 180 textSerial.print("To send custom text, open/download the 'Telegram' App and add: TannenbaumBot."); 181 lastTextSent = currentTime; 182 } 183 184 if (currentTime - lastClockSent > 600000) { 185 tClock = 0; 186 187 getCurrentTime(); 188 /* 189 byte counterT = 0; 190 while (tClock == 0 && counterT < 6) { 191 counterT++; 192 delay(500); 193 tClock = WiFi.getTime(); 194 } 195 */ 196 if (tClock != 0) { 197 textSerial.write(TIME); 198 textSerial.write(hour(tClock)); 199 textSerial.write(minute(tClock)); 200 textSerial.write(second(tClock)); 201 } 202 203 204 /* 205 textSerial.write(rtc.getHours()); 206 textSerial.write(rtc.getMinutes()); 207 textSerial.write(rtc.getSeconds()); 208 */ 209 210 lastClockSent = currentTime; 211 } 212 213 message m = bot.getUpdates(); 214 /* 215 if(millis() - lastTimeSentTime > 600000) { 216 textSerial.write(TIME); 217 textSerial.print(String(rtc.getEpoch()) + "\ 218"); 219 lastTimeSentTime = millis(); 220 } 221 */ 222 223 if (Serial.available() > 0) { 224 eingabe = Serial.readStringUntil('\n'); 225 if (!eingabe.equalsIgnoreCase("i")) { 226 bot.sendMessage("", eingabe); 227 eingabe = ""; 228 } 229 } 230 231 else if (eingabe.equalsIgnoreCase("i")) { 232 if (WL_CONNECTED) { 233 Serial.println(F("Mit WLAN verbunden")); 234 IPAddress ip = WiFi.localIP(); 235 Serial.print(F("IP Address: ")); 236 Serial.println(ip); 237 238 // print the received signal strength: 239 long rssi = WiFi.RSSI(); 240 Serial.print(F("signal strength (RSSI):")); 241 Serial.print(rssi); 242 Serial.println(F(" dBm")); 243 eingabe = ""; 244 } 245 else Serial.println(F("KEINE Verbindung zum WLAN")); 246 eingabe = ""; 247 } 248 249 if ( m.chat_id != 0 ) { 250 if (1) { // if a message is received from unique Chats m.sender.equals("xxxxx") 251 252 //Serial.println("Location: " + m.location.lon + ", " + m.location.lat); 253 //Serial.println("Name: " + m.first_name); 254 //Serial.println(m.chat_id); 255 //Serial.println(m.sender); 256 257#if DEBUG 258 time_t t = m.date.toInt(); 259 t = t + 1 * 60 * 60; 260 261 Serial.print(m.sender); 262 Serial.print(F(" hat um ")); 263 Serial.print(hour(t)); 264 Serial.print(":"); 265 Serial.print(minute(t)); 266 267 Serial.print(F(" folgendes gesendet: ")); 268 Serial.println(m.text); 269#endif 270 271 if (m.location.lon.length() != 0) { 272 bot.sendMessage(m.chat_id, "Requesting weather data..."); 273#if DEBUG 274 Serial.println(F("Verbinde zu api.openweathermap.org")); 275#endif 276 277 weatherHttpRequest(m.location.lat, m.location.lon, m.chat_id); 278 279 } 280 281 if (m.text.equalsIgnoreCase("/help")) { 282 bot.sendMessage(m.chat_id, "To send custom text, type: /text and your message. For example: '/text Santa rocks!'. To display the current weather in your area, simply send your location."); 283 284 285 } 286/* 287 else if (m.text.equalsIgnoreCase("/watchdog")) { 288 while (1); 289 } 290*/ 291 else if (m.text.equalsIgnoreCase("/start")) { 292 bot.sendMessage(m.chat_id, "Welcome " + m.first_name + "! Send /help for more information."); 293 294 } 295 296 else if (m.text.startsWith("/text") || m.text.startsWith("/Text")) { 297 m.text.remove(0, 6); 298 m.text += "\ 299"; 300 301 if (m.text.length() <= 2) { 302 bot.sendMessage(m.chat_id, "Sorry, your text is too short. Please send at least 2 characters."); 303 } 304 else if (m.text.length() >= 75) { 305 bot.sendMessage(m.chat_id, "Sorry, your text is too long. The maxmimal text length is 74 characters."); 306 } 307 else if (numMessages == MAX_MESSAGES) { 308 bot.sendMessage(m.chat_id, "Sorry, there are currently too many people sending messages to Santa. Try again later."); 309 } 310 else { 311 if (m.first_name.length() >= 21) m.first_name.remove(20); 312 eingabe = m.first_name + ": " + m.text; 313 eingabe.toCharArray(Nachrichten[messageIndex], 100); 314 eingabe = ""; 315 numMessages++; 316 messageIndex++; 317 if (messageIndex >= MAX_MESSAGES) messageIndex = 0; 318 bot.sendMessage(m.chat_id, "Your text is on position " + String(numMessages) + " in the pipeline. It will be displayed in approximately " + String((numMessages) * 20) + " seconds."); 319 } 320 321#if DEBUG 322 Serial.println("Der reine Text lautet: " + m.text); 323 324#endif 325 326 } 327 /* 328 else if (m.text.startsWith("/bierID")) { 329 m.text.remove(0, 7); 330 m.text.trim(); 331 beerHttpRequest(BEER_ID, m.text, m.chat_id); 332 } 333 334 else if (m.text.startsWith("/bier") || m.text.startsWith("/Bier")) { 335 m.text.remove(0, 6); 336 m.text.trim(); 337 beerHttpRequest(BEER_NAME, m.text, m.chat_id); 338 } 339 */ 340 /* 341 else if (m.text.equalsIgnoreCase("/wlan")) { 342 bot.sendMessage(m.chat_id, ssid); 343 344 } 345 else if (m.text.equalsIgnoreCase("/ip")) { 346 IPAddress ip = WiFi.localIP(); 347 bot.sendMessage(m.chat_id, String(ip[0]) + String(".") + \\ 348 String(ip[1]) + String(".") + \\ 349 String(ip[2]) + String(".") + \\ 350 String(ip[3])); 351 } 352 else if (m.text.equalsIgnoreCase("/signal")) { 353 long rssi = WiFi.RSSI(); 354 bot.sendMessage(m.chat_id, String(rssi) + " dBm"); 355 } 356 */ 357 } 358 359 else { 360 bot.sendMessage(m.chat_id, "Sie sind nicht befugt diesen Befehl zu verwenden."); 361 362 Serial.println(m.chat_id); 363 Serial.println(m.sender); 364 } 365 } 366} 367 368int findText(String needle, String haystack) { 369 int foundpos = -1; 370 for (int i = 0; i <= haystack.length() - needle.length(); i++) { 371 if (haystack.substring(i, needle.length() + i) == needle) { 372 foundpos = i; 373 } 374 } 375 return foundpos; 376} 377 378void weatherHttpRequest(String lat, String lon, String chatId) { 379 if (clienthttp.connect(server, 80)) { 380#if DEBUG 381 Serial.println(F("Verbunden zum Server")); 382#endif 383 384 clienthttp.println("GET /data/2.5/weather?lat=" + lat + "&lon=" + lon + "&APPID=**yourapikey** HTTP/1.1"); 385 clienthttp.println("Host: api.openweathermap.org"); 386 clienthttp.println("Connection: close"); 387 clienthttp.println(); 388 389 responseBuffer[0] = '\\0'; 390 rbindex = 0; 391 392 startCapture = false; 393 } 394 395 else { 396 bot.sendMessage(chatId, "Cannot connect to weather server."); 397 return; 398 } 399 400 char c; 401 unsigned long startTime = millis(); 402 while (clienthttp.connected() && millis() - startTime < 7000) { 403 if (clienthttp.available()) { 404 c = clienthttp.read(); 405 if (c == '{') { 406 startCapture = true; 407 } 408 if (startCapture && rbindex < RBUFFSIZE) { 409 responseBuffer[rbindex] = c; 410 rbindex++; 411 } 412 } 413 } 414 415 416 if (clienthttp.connected()) { 417 clienthttp.stop(); 418 clienthttp.flush(); 419#if DEBUG 420 Serial.println(F("Client won't disconnect")); 421#endif 422 bot.sendMessage(chatId, "Data couldn't be recieved."); 423 return; 424 } 425 426#if DEBUG 427 Serial.println(F("Received bytes.")); 428 //Serial.print(strlen(responseBuffer)); 429 Serial.println(F("Disconnecting.")); 430#endif 431 432 clienthttp.stop(); 433 clienthttp.flush(); 434 435 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 436 437 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 438 439 if (!root.success()) { 440#if DEBUG 441 Serial.println(F("parseObject() fehlgeschlagen")); 442#endif 443 444 bot.sendMessage(chatId, "Datenverarbeitung fehlgeschlagen."); 445 } 446 else { 447 char bufferw[20]; 448 char bufferc[30]; 449 root["weather"][0]["description"].prettyPrintTo(bufferw, sizeof(bufferw)); 450 root["name"].prettyPrintTo(bufferc, sizeof(bufferc)); 451 452#if DEBUG 453 Serial.println("Schnee: " + String((float)root["snow"]["3h"])); 454#endif 455 //bot.sendMessage(m.chat_id, "Aktuelle Wetter fr " + String(bufferc) + ":"); 456 textSerial.write(TEXT); 457 eingabe = "Current weather in " + String(bufferc) + ": " + String(bufferw) + " at " + String(((double)root["main"]["temp"]) - 273.15, 1) + " C"; 458 textSerial.print(eingabe); 459 lastTextSent = millis(); 460 eingabe = ""; 461 462 bot.sendMessage(chatId, "The current weather in your region will be displayed soon."); 463 464#if DEBUG 465 Serial.print(F("Aktuelle Temperatur: ")); 466 Serial.print(((double)root["main"]["temp"]) - 273.15); 467 Serial.println(F(" C")); 468 469 Serial.print(F("Beschreibung: ")); 470 Serial.println(bufferw); 471#endif 472 } 473} 474void getCurrentTime() { 475 if (clienthttp.connect("api.timezonedb.com", 80)) { 476 clienthttp.println("GET /v2/get-time-zone?key=**yourapikey**&format=json&by=zone&zone=Europe/London HTTP/1.1"); 477 clienthttp.println("Host: api.timezonedb.com"); 478 clienthttp.println("Connection: close"); 479 clienthttp.println(); 480 481 responseBuffer[0] = '\\0'; 482 rbindex = 0; 483 484 startCapture = false; 485 } 486 487 else { 488 Serial.println("Verbindung zum Zeitserver fehlgeschlagen"); 489 return; 490 } 491 492 char c; 493 unsigned long startTime = millis(); 494 495 while (clienthttp.connected() && millis() - startTime < 7000) { 496 if (clienthttp.available()) { 497 c = clienthttp.read(); 498 if (c == '{') { 499 startCapture = true; 500 } 501 if (startCapture && rbindex < RBUFFSIZE) { 502 responseBuffer[rbindex] = c; 503 rbindex++; 504 } 505 } 506 } 507 508 if (clienthttp.connected()) { 509 clienthttp.stop(); 510 clienthttp.flush(); 511 #if DEBUG 512 Serial.println(F("Client won't disconnect")); 513 #endif 514 return; 515 } 516 517 518 #if DEBUG 519 Serial.println(F("Received bytes.")); 520 //Serial.print(strlen(responseBuffer)); 521 Serial.println(F("Disconnecting.")); 522 #endif 523 524 clienthttp.stop(); 525 clienthttp.flush(); 526 527 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 528 529 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 530 531 if (!root.success()) { 532 #if DEBUG 533 Serial.println(F("parseObject() fehlgeschlagen")); 534 #endif 535 536 } 537 else { 538 tClock = root["timestamp"]; 539 Serial.println(tClock); 540 } 541} 542//wanted to implement the brewery db but couldn't make it work so fart 543/* 544 void beerHttpRequest(boolean type, String request, String chatId) { 545 if (clienthttp.connect("api.brewerydb.com", 80)) { 546 #if DEBUG 547 Serial.println(F("Verbunden zum Server")); 548 #endif 549 550 if (type == BEER_NAME) clienthttp.println("GET /v2/search?q=" + request + "&type=beer&key=**yourapikey**&format=json HTTP/1.1"); 551 else clienthttp.println("GET /v2/beer/" + request + "?key=**yourapikey**&format=json HTTP/1.1"); 552 clienthttp.println("Host: api.brewerydb.com"); 553 clienthttp.println("Connection: close"); 554 clienthttp.println(); 555 556 responseBuffer[0] = '\\0'; 557 rbindex = 0; 558 559 startCapture = false; 560 561 } 562 563 else { 564 bot.sendMessage(chatId, "Verbindung zur Brewery Databse nicht mglich."); 565 return; 566 } 567 568 char c; 569 unsigned long startTime = millis(); 570 571 while (clienthttp.connected() && millis() - startTime < 7000) { 572 if (clienthttp.available()) { 573 c = clienthttp.read(); 574 if (c == '{') { 575 startCapture = true; 576 } 577 if (startCapture && rbindex < RBUFFSIZE) { 578 responseBuffer[rbindex] = c; 579 rbindex++; 580 } 581 } 582 } 583 584 if (clienthttp.connected()) { 585 clienthttp.stop(); 586 clienthttp.flush(); 587 #if DEBUG 588 Serial.println(F("Client won't disconnect")); 589 #endif 590 bot.sendMessage(chatId, "Daten konnten nicht empfangen werden."); 591 return; 592 } 593 594 595 #if DEBUG 596 Serial.println(F("Received bytes.")); 597 //Serial.print(strlen(responseBuffer)); 598 Serial.println(F("Disconnecting.")); 599 #endif 600 601 clienthttp.stop(); 602 clienthttp.flush(); 603 604 StaticJsonBuffer<RBUFFSIZE> jsonBuffer; 605 606 JsonObject& root = jsonBuffer.parseObject(responseBuffer); 607 608 if (!root.success()) { 609 #if DEBUG 610 Serial.println(F("parseObject() fehlgeschlagen")); 611 #endif 612 613 bot.sendMessage(chatId, "Datenverarbeitung fehlgeschlagen."); 614 } 615 else { 616 617 if (type == BEER_NAME) { 618 char bufferName[10][50]; // char bufferName[10][50]; 619 char bufferID[10][9]; //char bufferID[10][6]; 620 int results = root["totalResults"]; // int results = atoi(&root["totalResults"]); 621 if (results > 10) results = 10; 622 for (byte i = 0; i < results; i++) { 623 624 root["data"][i]["id"].prettyPrintTo(bufferID[i], sizeof(bufferID[i])); 625 root["data"][i]["name"].prettyPrintTo(bufferName[i], sizeof(bufferName[i])); 626 } 627 628 String beerMessage; 629 630 if (results > 0) { 631 beerMessage = "Hier die ersten " + String(results) + " Treffer. Meintest du:"; 632 for (byte i = 0; i < results; i++) { 633 beerMessage += '\n'; 634 beerMessage += String(bufferName[i]); 635 beerMessage += ": /bierID"; 636 String IDtemp = String(bufferID[i]); 637 IDtemp.remove(0, 1); 638 IDtemp.remove(6, 1); 639 beerMessage += IDtemp; 640 } 641 } 642 643 else beerMessage = "Zu diesem Suchbegriff gab es leider keine Treffer."; 644 645 bot.sendMessage(chatId, beerMessage); 646 #if DEBUG 647 Serial.println(F("test")); 648 #endif 649 } 650 else { 651 char bufferDescription[1000]; 652 char bufferStyle[50]; 653 654 if (root["data"]["description"] != NULL) { 655 root["data"]["description"].prettyPrintTo(bufferDescription, sizeof(bufferDescription)); 656 bot.sendMessage(chatId, bufferDescription); 657 #if DEBUG 658 Serial.println(bufferDescription); 659 #endif 660 } 661 if (root["data"]["style"]["description"] != NULL) { 662 root["data"]["style"]["description"].prettyPrintTo(bufferDescription, sizeof(bufferDescription)); 663 root["data"]["style"]["name"].prettyPrintTo(bufferStyle, sizeof(bufferStyle)); 664 665 bot.sendMessage(chatId, "Es handelt sich um ein: " + String(bufferStyle) + ".'\n'" + String(bufferDescription)); 666 #if DEBUG 667 Serial.println("Es handelt sich um ein: " + String(bufferStyle) + ".'\n'" + String(bufferDescription)); 668 #endif 669 } 670 } 671 } 672 } 673*/ 674 675
leds_lookup_table.h
arduino
Look up table for the LEDs on the tree.
1byte frame[] = {52, 51, 43, 42, 32, 31, 19, 18, 0, 1, 2, 3, 4, 5, 6, 7, 2 8, 9, 25, 26, 38, 39, 47, 48, 54, 53}; 3 4byte inner[] = {50, 49, 44, 45, 46, 5 41, 40, 33, 34, 35, 36, 37, 30, 29, 28, 27, 20, 21, 22, 23, 24, 17, 16, 15, 14, 6 13, 12, 11, 10}; 7 8byte spiralCCW[] = {52, 51, 43, 32, 18, 0, 1, 2, 3, 4, 5, 9 6, 7, 8, 9, 38, 47, 48, 54, 53, 50, 44, 42, 33, 31, 19, 17, 10 16, 11 15, 14, 13, 12, 11, 10, 25, 26, 37, 39, 46, 49, 45, 41, 34, 30, 20, 21, 22, 23, 12 24, 13 27, 36, 40, 35, 29, 28, 35}; 14byte spiralCW[] = {52, 15 53, 54, 48, 47, 38, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 18, 32, 43, 51, 50, 49, 46, 39, 16 37, 26, 25, 10, 11, 12, 13, 14, 15, 16, 17, 19, 31, 17 33, 42, 18 44, 45, 40, 36, 27, 24, 23, 22, 21, 20, 30, 34, 41, 35, 28, 29}; 19 20byte triangle1[] 21 = {35, 29, 28}; 22 23byte triangle2[] = {45, 41, 34, 30, 20, 21, 22, 23, 24, 27, 24 36, 40}; 25 26byte triangle3[] = {53, 50, 44, 42, 33, 31, 19, 17, 16, 15, 14, 27 13, 12, 11, 10, 25, 26, 37, 39, 46, 49}; 28 29byte triangle4[] = {52, 51, 43, 30 32, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 38, 47, 48, 54}; 31 32 33
Serial_Data_Read.ino
arduino
Code for the "main" Arduino Mega. Reads data from pi and controls all LEDs and devices.
1#include "FastLED.h" 2#include "leds_lookup_table.h" 3#include 4 <EEPROM.h> 5 6#define DEBUG 0 7 8#define READY_PIN 28 9#define SANTA_PIN 10 5 11#define TRAIN_PIN 39 //relay 3 12#define LIGHT_CHAIN_PIN 35 //relay 1 13#define 14 SPOT_LIGHT_PIN 37 15#define FRONT_LIGHT_PIN 41 16#define LAP_COUNT_PIN 6 17 18 19#define 20 NUM_LEDS 55 //number of total P9823's 21#define DATA_PIN 2 22#define FADE_DELAY 23 50 24#define FADE_TIME 2000 25#define CHANCE_SANTA_SOLO 20 //chance of a santa 26 solo in percent 27 28#define PiSerial Serial1 29#define DebugSerial Serial 30 31//status 32 bytes knnen werte von 1 bis 191 haben (0 = undefined) 33#define LED_START 1 34#define 35 LED_END 55 36#define TEXT_EINGABE 124 37#define TWERKING_SANTA 69 38#define TRAIN 39 56 40#define LIGHT_CHAIN 57 41#define SPARKLING 58 42#define ANIMATIONS 59 43#define 44 TREE_BLACKOUT 60 45 46//info/data bytes von 192 bis 254 47#define OFF 192 48#define 49 ON 193 50#define FARBEN_START 194 51#define FARBEN_END 210 52 53#define DATA_ERROR 54 255 55 56struct ledStepStruct { 57 int rStep, gStep, bStep; 58 boolean fade; 59}; 60 61byte 62 data[2], rndLED, hueTemp; 63char text[31]; 64boolean newText, santaFlag, trainFlag, 65 lightChainFlag, sparklingFlag, sparkleOn, santaSoloFlag, pinActive = true; 66const 67 unsigned int fadeSteps = FADE_TIME / FADE_DELAY; 68unsigned long currentMillis, 69 lastFadeTime, santaTime, trainTime, lightChainTime, sparklingTime, lastSparkleTime, 70 lastLapCount, currentTime, trainActionTime, lastTrainAction; 71unsigned int lapCounter; 72 73CRGB 74 leds[NUM_LEDS], ledsAim[NUM_LEDS], ledBefore; 75 76ledStepStruct ledsStep[NUM_LEDS]; 77 78void 79 setup() { 80 PiSerial.begin(9600); 81 82 DebugSerial.begin(9600); 83 84 pinMode(READY_PIN, 85 OUTPUT); 86 pinMode(SANTA_PIN, OUTPUT); 87 pinMode(TRAIN_PIN, OUTPUT); 88 pinMode(LIGHT_CHAIN_PIN, 89 OUTPUT); 90 pinMode(SPOT_LIGHT_PIN, OUTPUT); 91 pinMode(FRONT_LIGHT_PIN, OUTPUT); 92 93 pinMode(LAP_COUNT_PIN, INPUT_PULLUP); 94 95 96 FastLED.addLeds<WS2812B, DATA_PIN, 97 RGB>(leds, NUM_LEDS); 98 FastLED.setBrightness(70); 99 FastLED.clear(); 100 101 FastLED.show(); 102 103 digitalWrite(READY_PIN, HIGH); 104 digitalWrite(SANTA_PIN, 105 LOW); 106 digitalWrite(TRAIN_PIN, LOW); 107 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 108 109 digitalWrite(SPOT_LIGHT_PIN, LOW); 110 digitalWrite(FRONT_LIGHT_PIN, HIGH); 111 112 113 lightChainFlag = true; 114 115 //lapCounter = 200; //add counts up to now, since 116 eeprom wasnt' implemented yet 117 //EEPROM.put(0, lapCounter); 118 EEPROM.get(0, 119 lapCounter); 120 121} 122 123void loop() { 124 125 handleSerialCommunication(); 126 127 handleData(); 128 handleColorFade(); 129 handleControl(); 130 handleSparkling(); 131 132 handleLapCount(); 133 134} 135 136void handleLapCount() { 137 currentTime = millis(); 138 139 if (!digitalRead(LAP_COUNT_PIN) && pinActive && currentTime - trainActionTime 140 > 100) { 141 lapCounter++; 142 pinActive = false; 143 lastLapCount = currentTime; 144 145 PiSerial.print(lapCounter); 146 PiSerial.flush(); 147 EEPROM.put(0, lapCounter); 148 149 //Serial.println(lapCounter); 150 } 151 152 if (digitalRead(LAP_COUNT_PIN) 153 && currentTime - lastLapCount > 2000) { 154 pinActive = true; 155 } 156} 157 158void 159 handleSparkling() { 160 if (sparklingFlag) { 161 if (millis() - sparklingTime 162 > 20000) { 163 sparklingFlag = false; 164 leds[rndLED] = ledBefore; 165 166 FastLED.show(); 167 sparkleOn = false; 168 } 169 else if (!sparkleOn 170 && millis() - lastSparkleTime > 100) { 171 rndLED = random8(NUM_LEDS); 172 173 ledBefore = leds[rndLED]; 174 leds[rndLED] += CRGB::White; 175 FastLED.show(); 176 177 sparkleOn = true; 178 lastSparkleTime = millis(); 179 } 180 else 181 if (sparkleOn && millis() - lastSparkleTime > 50) { 182 leds[rndLED] = ledBefore; 183 184 FastLED.show(); 185 sparkleOn = false; 186 lastSparkleTime = millis(); 187 188 } 189 } 190} 191 192void handleControl() { 193 if (santaFlag) { 194 if 195 (santaTime == 0) { 196 digitalWrite(SANTA_PIN, HIGH); 197 santaTime = 198 millis(); 199 } 200 else if (millis() - santaTime > 20000) { 201 digitalWrite(SANTA_PIN, 202 LOW); 203 santaTime = 0; 204 santaFlag = false; 205 } 206 } 207 208 209 else if (santaSoloFlag) { 210 211 if (trainFlag) { 212 trainFlag = false; 213 214 digitalWrite(TRAIN_PIN, LOW); 215 } 216 if (lightChainFlag) { 217 digitalWrite(LIGHT_CHAIN_PIN, 218 LOW); 219 } 220 FastLED.clear(); 221 FastLED.show(); 222 223 digitalWrite(FRONT_LIGHT_PIN, 224 LOW); 225 FastLED.delay(1000); 226 digitalWrite(SPOT_LIGHT_PIN, HIGH); 227 228 FastLED.delay(500); 229 digitalWrite(SANTA_PIN, HIGH); 230 FastLED.delay(50); 231 232 digitalWrite(SANTA_PIN, LOW); 233 234 /* 235 for (int i; i < 500; 236 i++) { 237 fill_rainbow(leds, NUM_LEDS, hueTemp, 1); 238 FastLED.show(); 239 240 hueTemp++; 241 FastLED.delay(25); 242 } 243 FastLED.clear(); 244 245 FastLED.show(); 246 */ 247 for ( int k = 0; k < 20; k++ ) { 248 triangle(); 249 250 } 251 252 253 digitalWrite(SPOT_LIGHT_PIN, LOW); 254 255 digitalWrite(SANTA_PIN, 256 HIGH); 257 FastLED.delay(50); 258 digitalWrite(SANTA_PIN, LOW); 259 260 FastLED.delay(1000); 261 262 263 digitalWrite(FRONT_LIGHT_PIN, HIGH); 264 digitalWrite(LIGHT_CHAIN_PIN, HIGH); 265 266 lightChainFlag = true; 267 268 for (byte i = 0; i < NUM_LEDS; i++) { 269 270 leds[i] = ledsAim[i]; 271 } 272 FastLED.show(); 273 santaSoloFlag 274 = false; 275 digitalWrite(READY_PIN, HIGH); 276 } 277 278 if (trainFlag) { 279 280 if (millis() - trainTime > 30000) { 281 trainFlag = false; 282 digitalWrite(TRAIN_PIN, 283 LOW); 284 } 285 } 286 287 if (!lightChainFlag) { 288 if (millis() - lightChainTime 289 > 60000) { 290 lightChainFlag = true; 291 digitalWrite(LIGHT_CHAIN_PIN, 292 HIGH); 293 } 294 } 295} 296 297void handleColorFade() { 298 currentMillis = 299 millis(); 300 if (currentMillis - lastFadeTime >= FADE_DELAY) { 301 302 for 303 (byte i = 0; i < NUM_LEDS; i++) { 304 if (ledsStep[i].fade) { 305 ledsStep[i].fade 306 = false; 307 if (leds[i].r != ledsAim[i].r) { 308 ledsStep[i].fade 309 = true; 310 int rTemp = (int)leds[i].r + (int)ledsStep[i].rStep; 311 if 312 ((ledsStep[i].rStep > 0 && rTemp > ledsAim[i].r) || (ledsStep[i].rStep < 0 && rTemp 313 < ledsAim[i].r) || rTemp > 255 || rTemp < 0) leds[i].r = ledsAim[i].r; 314 else 315 leds[i].r = rTemp; 316 317 if ((ledsStep[i].rStep > 0 && leds[i].r > ledsAim[i].r) 318 || (ledsStep[i].rStep < 0 && leds[i].r < ledsAim[i].r)) leds[i].r = ledsAim[i].r; 319 320 } 321 if (leds[i].g != ledsAim[i].g) { 322 ledsStep[i].fade 323 = true; 324 int gTemp = (int)leds[i].g + (int)ledsStep[i].gStep; 325 if 326 ((ledsStep[i].gStep > 0 && gTemp > ledsAim[i].g) || (ledsStep[i].gStep < 0 && gTemp 327 < ledsAim[i].g) || gTemp > 255 || gTemp < 0) leds[i].g = ledsAim[i].g; 328 else 329 leds[i].g = gTemp; 330 } 331 if (leds[i].b != ledsAim[i].b) { 332 333 ledsStep[i].fade = true; 334 int bTemp = (int)leds[i].b + (int)ledsStep[i].bStep; 335 336 if ((ledsStep[i].bStep > 0 && bTemp > ledsAim[i].b) || (ledsStep[i].bStep 337 < 0 && bTemp < ledsAim[i].b) || bTemp > 255 || bTemp < 0) leds[i].b = ledsAim[i].b; 338 339 else leds[i].b = bTemp; 340 } 341 342 } 343 } 344 FastLED.show(); 345 346 lastFadeTime = currentMillis; 347 } 348 349 350} 351 352void handleSerialCommunication() 353 { 354 if (PiSerial.available() > 0) { //if there's any serial data 355 /* 356 357 if (data[0] == TEXT_EINGABE) { //if the upcoming data is a text; indicated 358 by first data byte = 124 359 //inputString = PiSerial.readString(); 360 361 362 for (byte textIndex = 0; textIndex < (data[1] - 193); textIndex++) { //194 363 = textlnge 1, ..., 224 = textlnge 30 364 text[textIndex] = PiSerial.read(); 365 366 } 367 text[data[1] - 193] = '\\0'; 368 369 newText = true; //text 370 saved 371 data[0] = 0; 372 data[1] = 0; 373 374 } 375 */ 376 //else 377 if !!!!!!! wenn oben auskommentiert 378 379 if (PiSerial.peek() >= 1 && PiSerial.peek() 380 <= 191) { //if first data byte is valid 381 PiSerial.readBytes(data, 2); 382 383 //if (data[0] == TEXT_EINGABE) digitalWrite(READY_PIN, LOW); 384#if DEBUG 385 386 DebugSerial.println("Empfangen: " + (String)data[0] + ", " + (String)data[1]); 387#endif 388 389 } 390 else { //else; first data byte is invalid (0 or greater than 191) 391 392 byte errorMessage = PiSerial.read(); 393 //PiSerial.print(DATA_ERROR); 394 395 //PiSerial.print(errorMessage); 396#if DEBUG 397 DebugSerial.print("DATA_ERROR: 398 "); 399 DebugSerial.println(errorMessage); 400#endif 401 } 402 } 403} 404 405void 406 handleData() { 407 if (data[0] >= LED_START && data[0] <= LED_END) { //if data 408 is LED data 409 if (data[1] < OFF || data[1] > FARBEN_END) { //if second data 410 byte has invalid color 411 //invalid color/data byte 412 //PiSerial.print(DATA_ERROR); 413 414 //PiSerial.print(data[1]); 415#if DEBUG 416 DebugSerial.print("DATA_ERROR_INVALID_COLOR: 417 "); 418 DebugSerial.println(data[1]); 419#endif 420 421 } 422 else { 423 //color value is valid 424 //led mit farbe (in data[1]) ansteuern 425 byte 426 i = data[0] - 1; 427 428 if (data[1] == OFF) ledsAim[i] = CRGB::Black; 429 430 else if (data[1] == ON) ledsAim[i] = CRGB::White; //hier warmwei einfgen 431 432 else ledsAim[i].setHue((data[1] - 194) * 16); //set aim color for led to 433 chosen value 434 435 setLEDFade(i); 436 437 } 438 data[0] = 0; 439 data[1] 440 = 0; 441 } 442 443 else if (data[0] == TWERKING_SANTA) { 444 445 446 if (!santaFlag) 447 { 448 digitalWrite(READY_PIN, LOW); 449 450 if (random8(100) > CHANCE_SANTA_SOLO 451 - 1) { 452 santaFlag = true; 453 digitalWrite(READY_PIN, HIGH); 454 455 } 456 else santaSoloFlag = true; 457 } 458 459 data[0] = 0; 460 461 data[1] = 0; 462 463 } 464 465 else if ( data[0] == TRAIN) { 466 currentTime 467 = millis(); 468 if (currentTime - lastTrainAction > 1000) { 469 if (data[1] 470 == OFF && trainFlag) { 471 trainActionTime = currentTime; 472 lastTrainAction 473 = trainActionTime; 474 digitalWrite(TRAIN_PIN, LOW); 475 trainFlag 476 = false; 477 } 478 479 else if (data[1] == ON && !trainFlag) { 480 trainActionTime 481 = currentTime; 482 lastTrainAction = trainActionTime; 483 digitalWrite(TRAIN_PIN, 484 HIGH); 485 trainFlag = true; 486 trainTime = millis(); 487 } 488 489 } 490 data[0] = 0; 491 data[1] = 0; 492 493 494 } 495 496 else if 497 (data[0] == LIGHT_CHAIN) { 498 if (data[1] == OFF && lightChainFlag) { 499 digitalWrite(LIGHT_CHAIN_PIN, 500 LOW); 501 lightChainFlag = false; 502 lightChainTime = millis(); 503 } 504 505 506 else if (data[1] == ON && !lightChainFlag) { 507 digitalWrite(LIGHT_CHAIN_PIN, 508 HIGH); 509 lightChainFlag = true; 510 } 511 data[0] = 0; 512 data[1] 513 = 0; 514 } 515 516 else if (data[0] == SPARKLING) { 517 if (data[1] == ON && 518 !sparklingFlag) { 519 sparklingFlag = true; 520 sparklingTime = millis(); 521 522 } 523 524 else if (data[1] == OFF && sparklingFlag) { 525 sparklingFlag 526 = false; 527 } 528 529 data[0] = 0; 530 data[1] = 0; 531 } 532 533 else 534 if (data[0] == ANIMATIONS) { 535 digitalWrite(READY_PIN, LOW); 536 animations(); 537 538 digitalWrite(READY_PIN, HIGH); 539 data[0] = 0; 540 data[1] = 0; 541 } 542 543 544 else if (data[0] == TREE_BLACKOUT) { 545 546 for (byte i = 0; i < NUM_LEDS; 547 i++) { 548 ledsAim[i] = CRGB::Black; 549 setLEDFade(i); 550 } 551 552 553 data[0] = 0; 554 data[1] = 0; 555 } 556 557 558 /* 559 if (newText) 560 { //handle text entry 561 //inputString.toCharArray(text, 31); 562 563 #if 564 DEBUG 565 DebugSerial.println(text); //debug 566 DebugSerial.flush(); 567 568 #endif 569 digitalWrite(READY_PIN, HIGH); 570 //text anzeigen 571 newText 572 = false; 573 } 574 */ 575} 576 577void animations() { 578 fillSpiralCCW(); 579 580 fillSpiralCW(); 581 fillSpiralCCW(); 582 fillSpiralCW(); 583 584 for (byte 585 i = 0; i < NUM_LEDS; i++) { 586 leds[i] = ledsAim[i]; 587 } 588 FastLED.show(); 589} 590 591void 592 setLEDFade(byte i) { 593 if (leds[i] != ledsAim[i]) { 594 ledsStep[i].fade = 595 true; 596 597 if (ledsAim[i].r != leds[i].r) { 598 ledsStep[i].rStep = ((int)ledsAim[i].r 599 - (int)leds[i].r) / (int)fadeSteps; 600 if (ledsStep[i].rStep == 0) { 601 if 602 (ledsAim[i].r > leds[i].r) ledsStep[i].rStep = 1; 603 else ledsStep[i].rStep 604 = -1; 605 } 606#if DEBUG 607 DebugSerial.println("rStep: " + (String)ledsStep[i].rStep); 608 //debug 609#endif 610 } 611 if (ledsAim[i].g != leds[i].g) { 612 ledsStep[i].gStep 613 = ((int)ledsAim[i].g - (int)leds[i].g) / (int)fadeSteps; 614 if (ledsStep[i].gStep 615 == 0) { 616 if (ledsAim[i].g > leds[i].g) ledsStep[i].gStep = 1; 617 else 618 ledsStep[i].gStep = -1; 619 } 620#if DEBUG 621 DebugSerial.println("gStep: 622 " + (String)ledsStep[i].gStep); //debug 623#endif 624 } 625 if (ledsAim[i].b 626 != leds[i].b) { 627 ledsStep[i].bStep = ((int)ledsAim[i].b - (int)leds[i].b) 628 / (int)fadeSteps; 629 if (ledsStep[i].bStep == 0) { 630 if (ledsAim[i].b 631 > leds[i].b) ledsStep[i].bStep = 1; 632 else ledsStep[i].bStep = -1; 633 634 } 635#if DEBUG 636 DebugSerial.println("bStep: " + (String)ledsStep[i].bStep); 637 //debug 638#endif 639 } 640 641 } 642} 643 644 645void fillSpiralCCW() { 646 647 648 FastLED.clear(); 649 FastLED.show(); 650 651 for (byte i = 0; i < (sizeof(spiralCCW) 652 / sizeof(byte)); i++) { 653 leds[spiralCCW[i]].setHue(hueTemp); 654 FastLED.show(); 655 656 FastLED.delay(30); 657 hueTemp += 2; 658 } 659 660 for (byte i = (sizeof(spiralCCW) 661 / sizeof(byte)) - 1; i > 0; i--) { 662 leds[spiralCCW[i]] = CRGB::Black; 663 664 FastLED.show(); 665 FastLED.delay(30); 666 } 667} 668 669void fillSpiralCW() 670 { 671 672 FastLED.clear(); 673 FastLED.show(); 674 675 for (byte i = 0; i < (sizeof(spiralCW) 676 / sizeof(byte)); i++) { 677 leds[spiralCW[i]].setHue(hueTemp); 678 FastLED.show(); 679 680 FastLED.delay(30); 681 hueTemp += 2; 682 } 683 684 for (byte i = (sizeof(spiralCW) 685 / sizeof(byte)) - 1; i > 0; i--) { 686 leds[spiralCW[i]] = CRGB::Black; 687 FastLED.show(); 688 689 FastLED.delay(30); 690 } 691} 692 693 694void frameMarquee() { 695 FastLED.clear(); 696 697 FastLED.show(); 698 699 for (int j = 0; j < 400; j++) { 700 for (byte i = 701 0; i < (sizeof(frame) / sizeof(byte)); i++) { 702 leds[frame[i]].setHue(hueTemp); 703 704 hueTemp += 2; 705 } 706 hueTemp = 2 * j; 707 FastLED.show(); 708 709 FastLED.delay(40); 710 } 711 FastLED.clear(); 712 FastLED.show(); 713} 714 715void 716 innerFrame() { 717 for (int j = 0; j < 15; j++) { 718 719 hueTemp += 40; 720 721 722 for (byte i = 0; i < (sizeof(frame) / sizeof(byte)); i++) { 723 leds[frame[i]].setHue(hueTemp); 724 725 } 726 FastLED.show(); 727 FastLED.delay(200); 728 729 for (byte i = 730 0; i < (sizeof(frame) / sizeof(byte)); i++) { 731 leds[frame[i]] = CRGB::Black; 732 733 } 734 735 hueTemp += 40; 736 737 for (byte i = 0; i < (sizeof(inner) / 738 sizeof(byte)); i++) { 739 leds[inner[i]].setHue(hueTemp); 740 } 741 FastLED.show(); 742 743 FastLED.delay(200); 744 745 for (byte i = 0; i < (sizeof(inner) / sizeof(byte)); 746 i++) { 747 leds[inner[i]] = CRGB::Black; 748 } 749 } 750 FastLED.clear(); 751 752 FastLED.show(); 753} 754 755void triangle() { 756 hueTemp += 16; 757 for (byte 758 i = 0; i < (sizeof(triangle1) / sizeof(byte)); i++) { 759 leds[triangle1[i]].setHue(hueTemp); 760 761 } 762 FastLED.show(); 763 FastLED.delay(150); 764 for (byte i = 0; i < (sizeof(triangle1) 765 / sizeof(byte)); i++) { 766 leds[triangle1[i]] = CRGB::Black; 767 } 768 hueTemp 769 += 16; 770 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 771 772 leds[triangle2[i]].setHue(hueTemp); 773 } 774 FastLED.show(); 775 FastLED.delay(150); 776 777 for (byte i = 0; i < (sizeof(triangle2) / sizeof(byte)); i++) { 778 leds[triangle2[i]] 779 = CRGB::Black; 780 } 781 hueTemp += 16; 782 for (byte i = 0; i < (sizeof(triangle3) 783 / sizeof(byte)); i++) { 784 leds[triangle3[i]].setHue(hueTemp); 785 } 786 FastLED.show(); 787 788 FastLED.delay(150); 789 for (byte i = 0; i < (sizeof(triangle3) / sizeof(byte)); 790 i++) { 791 leds[triangle3[i]] = CRGB::Black; 792 } 793 hueTemp += 16; 794 for 795 (byte i = 0; i < (sizeof(triangle4) / sizeof(byte)); i++) { 796 leds[triangle4[i]].setHue(hueTemp); 797 798 } 799 FastLED.show(); 800 FastLED.delay(150); 801 for (byte i = 0; i < (sizeof(triangle4) 802 / sizeof(byte)); i++) { 803 leds[triangle4[i]] = CRGB::Black; 804 } 805 806} 807 808
Parola_Fonts_data.h
arduino
Fonts for the dot matrix to allow umlaute etc.
1// Data file for UTF-8 example user defined fonts 2#ifndef FONTS_DATA_H 3#define 4 FONTS_DATA_H 5 6MD_MAX72XX::fontType_t ExtASCII[] PROGMEM = 7{ 8 0, // 9 0 - 'Unused' 10 0, // 1 - 'Unused' 11 0, // 2 - 'Unused' 12 0, // 13 3 - 'Unused' 14 0, // 4 - 'Unused' 15 0, // 5 - 'Unused' 16 0, // 17 6 - 'Unused' 18 0, // 7 - 'Unused' 19 0, // 8 - 'Unused' 20 0, // 21 9 - 'Unused' 22 0, // 10 - 'Unused' 23 0, // 11 - 'Unused' 24 0, // 25 12 - 'Unused' 26 0, // 13 - 'Unused' 27 0, // 14 - 'Unused' 28 0, // 29 15 - 'Unused' 30 0, // 16 - 'Unused' 31 0, // 17 - 'Unused' 32 0, // 33 18 - 'Unused' 34 0, // 19 - 'Unused' 35 0, // 20 - 'Unused' 36 0, // 37 21 - 'Unused' 38 0, // 22 - 'Unused' 39 0, // 23 - 'Unused' 40 0, // 41 24 - 'Unused' 42 0, // 25 - 'Unused' 43 0, // 26 - 'Unused' 44 0, // 45 27 - 'Unused' 46 0, // 28 - 'Unused' 47 0, // 29 - 'Unused' 48 0, // 49 30 - 'Unused' 50 0, // 31 - 'Unused' 51 2, 0, 0, // 32 - 'Space' 52 1, 53 95, // 33 - '!' 54 3, 7, 0, 7, // 34 - '"' 55 5, 20, 127, 20, 127, 20, // 56 35 - '#' 57 5, 36, 42, 127, 42, 18, // 36 - '$' 58 5, 35, 19, 8, 100, 98, // 59 37 - '%' 60 5, 54, 73, 86, 32, 80, // 38 - '&' 61 2, 4, 3, // 39 62 3, 63 28, 34, 65, // 40 - '(' 64 3, 65, 34, 28, // 41 - ')' 65 5, 42, 28, 127, 66 28, 42, // 42 - '*' 67 5, 8, 8, 62, 8, 8, // 43 - '+' 68 2, 128, 96, // 69 44 - ',' 70 5, 8, 8, 8, 8, 8, // 45 - '-' 71 2, 96, 96, // 46 - '.' 72 73 5, 32, 16, 8, 4, 2, // 47 - '/' 74 5, 62, 81, 73, 69, 62, // 48 - '0' 75 76 3, 66, 127, 64, // 49 - '1' 77 5, 114, 73, 73, 73, 70, // 50 - '2' 78 79 5, 33, 65, 73, 77, 51, // 51 - '3' 80 5, 24, 20, 18, 127, 16, // 52 - 81 '4' 82 5, 39, 69, 69, 69, 57, // 53 - '5' 83 5, 60, 74, 73, 73, 49, // 84 54 - '6' 85 5, 65, 33, 17, 9, 7, // 55 - '7' 86 5, 54, 73, 73, 73, 54, // 87 56 - '8' 88 5, 70, 73, 73, 41, 30, // 57 - '9' 89 1, 20, // 58 - ':' 90 91 2, 128, 104, // 59 - ';' 92 4, 8, 20, 34, 65, // 60 - '<' 93 5, 20, 94 20, 20, 20, 20, // 61 - '=' 95 4, 65, 34, 20, 8, // 62 - '>' 96 5, 2, 97 1, 89, 9, 6, // 63 - '?' 98 5, 62, 65, 93, 89, 78, // 64 - '@' 99 5, 124, 100 18, 17, 18, 124, // 65 - 'A' 101 5, 127, 73, 73, 73, 54, // 66 - 'B' 102 103 5, 62, 65, 65, 65, 34, // 67 - 'C' 104 5, 127, 65, 65, 65, 62, // 68 - 105 'D' 106 5, 127, 73, 73, 73, 65, // 69 - 'E' 107 5, 127, 9, 9, 9, 1, // 70 108 - 'F' 109 5, 62, 65, 65, 81, 115, // 71 - 'G' 110 5, 127, 8, 8, 8, 127, // 111 72 - 'H' 112 3, 65, 127, 65, // 73 - 'I' 113 5, 32, 64, 65, 63, 1, // 74 114 - 'J' 115 5, 127, 8, 20, 34, 65, // 75 - 'K' 116 5, 127, 64, 64, 64, 64, // 117 76 - 'L' 118 5, 127, 2, 28, 2, 127, // 77 - 'M' 119 5, 127, 4, 8, 16, 127, // 120 78 - 'N' 121 5, 62, 65, 65, 65, 62, // 79 - 'O' 122 5, 127, 9, 9, 9, 6, // 123 80 - 'P' 124 5, 62, 65, 81, 33, 94, // 81 - 'Q' 125 5, 127, 9, 25, 41, 70, // 126 82 - 'R' 127 5, 38, 73, 73, 73, 50, // 83 - 'S' 128 5, 3, 1, 127, 1, 3, // 129 84 - 'T' 130 5, 63, 64, 64, 64, 63, // 85 - 'U' 131 5, 31, 32, 64, 32, 31, // 132 86 - 'V' 133 5, 63, 64, 56, 64, 63, // 87 - 'W' 134 5, 99, 20, 8, 20, 99, // 135 88 - 'X' 136 5, 3, 4, 120, 4, 3, // 89 - 'Y' 137 5, 97, 89, 73, 77, 67, // 138 90 - 'Z' 139 3, 127, 65, 65, // 91 - '[' 140 5, 2, 4, 8, 16, 32, // 92 - 141 '\\' 142 3, 65, 65, 127, // 93 - ']' 143 5, 4, 2, 1, 2, 4, // 94 - '^' 144 145 5, 64, 64, 64, 64, 64, // 95 - '_' 146 2, 3, 4, // 96 - '`' 147 5, 32, 148 84, 84, 120, 64, // 97 - 'a' 149 5, 127, 40, 68, 68, 56, // 98 - 'b' 150 151 5, 56, 68, 68, 68, 40, // 99 - 'c' 152 5, 56, 68, 68, 40, 127, // 100 - 153 'd' 154 5, 56, 84, 84, 84, 24, // 101 - 'e' 155 4, 8, 126, 9, 2, // 102 156 - 'f' 157 5, 24, 164, 164, 156, 120, // 103 - 'g' 158 5, 127, 8, 4, 4, 120, // 159 104 - 'h' 160 3, 68, 125, 64, // 105 - 'i' 161 4, 64, 128, 128, 122, // 162 106 - 'j' 163 4, 127, 16, 40, 68, // 107 - 'k' 164 3, 65, 127, 64, // 108 165 - 'l' 166 5, 124, 4, 120, 4, 120, // 109 - 'm' 167 5, 124, 8, 4, 4, 120, // 168 110 - 'n' 169 5, 56, 68, 68, 68, 56, // 111 - 'o' 170 5, 252, 24, 36, 36, 24, // 171 112 - 'p' 172 5, 24, 36, 36, 24, 252, // 113 - 'q' 173 5, 124, 8, 4, 4, 8, // 174 114 - 'r' 175 5, 72, 84, 84, 84, 36, // 115 - 's' 176 4, 4, 63, 68, 36, // 177 116 - 't' 178 5, 60, 64, 64, 32, 124, // 117 - 'u' 179 5, 28, 32, 64, 32, 28, // 180 118 - 'v' 181 5, 60, 64, 48, 64, 60, // 119 - 'w' 182 5, 68, 40, 16, 40, 68, // 183 120 - 'x' 184 5, 76, 144, 144, 144, 124, // 121 - 'y' 185 5, 68, 100, 84, 76, 186 68, // 122 - 'z' 187 3, 8, 54, 65, // 123 - '{' 188 1, 119, // 124 - 189 '|' 190 3, 65, 54, 8, // 125 - '}' 191 5, 2, 1, 2, 4, 2, // 126 - '~' 192 193 0, // 127 - 'Unused' 194 6, 20, 62, 85, 85, 65, 34, // 128 - 'Euro sign' 195 196 5, 28, 62, 124, 62, 28, // 129 - 'Heart' costum char!!! 197 2, 128, 96, // 198 130 - 'Single low 9 quotation mark' 199 5, 192, 136, 126, 9, 3, // 131 - 'f 200 with hook' 201 4, 128, 96, 128, 96, // 132 - 'Single low 9 quotation mark' 202 203 8, 96, 96, 0, 96, 96, 0, 96, 96, // 133 - 'Horizontal ellipsis' 204 3, 4, 205 126, 4, // 134 - 'Dagger' 206 3, 20, 126, 20, // 135 - 'Double dagger' 207 208 4, 2, 1, 1, 2, // 136 - 'Modifier circumflex' 209 7, 35, 19, 104, 100, 2, 210 97, 96, // 137 - 'Per mille sign' 211 5, 72, 85, 86, 85, 36, // 138 - 'S 212 with caron' 213 3, 8, 20, 34, // 139 - '< quotation' 214 6, 62, 65, 65, 127, 215 73, 73, // 140 - 'OE' 216 0, // 141 - 'Not used' 217 5, 68, 101, 86, 77, 218 68, // 142 - 'z with caron' 219 0, // 143 - 'Not used' 220 0, // 144 221 - 'Not used' 222 2, 3, 4, // 145 - 'Left single quote mark' 223 2, 4, 3, // 224 146 - 'Right single quote mark' 225 4, 3, 4, 3, 4, // 147 - 'Left double quote 226 marks' 227 4, 4, 3, 4, 3, // 148 - 'Right double quote marks' 228 4, 0, 24, 229 60, 24, // 149 - 'Bullet Point' 230 3, 8, 8, 8, // 150 - 'En dash' 231 5, 232 8, 8, 8, 8, 8, // 151 - 'Em dash' 233 4, 2, 1, 2, 1, // 152 - 'Small ~' 234 235 7, 1, 15, 1, 0, 15, 2, 15, // 153 - 'TM' 236 5, 72, 85, 86, 85, 36, // 237 154 - 's with caron' 238 3, 34, 20, 8, // 155 - '> quotation' 239 7, 56, 68, 240 68, 124, 84, 84, 8, // 156 - 'oe' 241 0, // 157 - 'Not used' 242 5, 68, 243 101, 86, 77, 68, // 158 - 'z with caron' 244 5, 12, 17, 96, 17, 12, // 159 245 - 'Y diaresis' 246 2, 0, 0, // 160 - 'Non-breaking space' 247 1, 125, // 248 161 - 'Inverted !' 249 5, 60, 36, 126, 36, 36, // 162 - 'Cent sign' 250 5, 251 72, 126, 73, 65, 102, // 163 - 'Pound sign' 252 5, 34, 28, 20, 28, 34, // 253 164 - 'Currency sign' 254 5, 43, 47, 252, 47, 43, // 165 - 'Yen' 255 1, 119, // 256 166 - '|' 257 4, 102, 137, 149, 106, // 167 - 'Section sign' 258 3, 1, 0, 1, // 259 168 - 'Spacing diaresis' 260 7, 62, 65, 93, 85, 85, 65, 62, // 169 - 'Copyright' 261 262 3, 13, 13, 15, // 170 - 'Feminine Ordinal Ind.' 263 5, 8, 20, 42, 20, 34, // 264 171 - '<<' 265 5, 8, 8, 8, 8, 56, // 172 - 'Not sign' 266 0, // 173 - 'Soft 267 Hyphen' 268 7, 62, 65, 127, 75, 117, 65, 62, // 174 - 'Registered Trademark' 269 270 5, 1, 1, 1, 1, 1, // 175 - 'Spacing Macron Overline' 271 3, 2, 5, 2, // 272 176 - 'Degree' 273 5, 68, 68, 95, 68, 68, // 177 - '+/-' 274 3, 25, 21, 19, // 275 178 - 'Superscript 2' 276 3, 17, 21, 31, // 179 - 'Superscript 3' 277 2, 2, 278 1, // 180 - 'Acute accent' 279 4, 252, 64, 64, 60, // 181 - 'micro (mu)' 280 281 5, 6, 9, 127, 1, 127, // 182 - 'Paragraph Mark' 282 2, 24, 24, // 183 - 283 'Middle Dot' 284 3, 128, 128, 96, // 184 - 'Spacing sedilla' 285 2, 2, 31, // 286 185 - 'Superscript 1' 287 4, 6, 9, 9, 6, // 186 - 'Masculine Ordinal Ind.' 288 289 5, 34, 20, 42, 20, 8, // 187 - '>>' 290 6, 64, 47, 16, 40, 52, 250, // 291 188 - '1/4' 292 6, 64, 47, 16, 200, 172, 186, // 189 - '1/2' 293 6, 85, 53, 294 31, 40, 52, 250, // 190 - '3/4' 295 5, 48, 72, 77, 64, 32, // 191 - 'Inverted 296 ?' 297 5, 120, 20, 21, 22, 120, // 192 - 'A grave' 298 5, 120, 22, 21, 20, 299 120, // 193 - 'A acute' 300 5, 122, 21, 21, 21, 122, // 194 - 'A circumflex' 301 302 5, 120, 22, 21, 22, 121, // 195 - 'A tilde' 303 5, 120, 21, 20, 21, 120, // 304 196 - 'A diaresis' 305 5, 120, 20, 21, 20, 120, // 197 - 'A ring above' 306 307 6, 124, 10, 9, 127, 73, 73, // 198 - 'AE' 308 5, 30, 161, 161, 97, 18, // 309 199 - 'C sedilla' 310 4, 124, 85, 86, 68, // 200 - 'E grave' 311 4, 124, 86, 312 85, 68, // 201 - 'E acute' 313 4, 126, 85, 85, 70, // 202 - 'E circumflex' 314 315 4, 124, 85, 84, 69, // 203 - 'E diaresis' 316 3, 68, 125, 70, // 204 - 317 'I grave' 318 3, 68, 126, 69, // 205 - 'I acute' 319 3, 70, 125, 70, // 320 206 - 'I circumplex' 321 3, 69, 124, 69, // 207 - 'I diaresis' 322 6, 4, 127, 323 69, 65, 65, 62, // 208 - 'Capital Eth' 324 5, 124, 10, 17, 34, 125, // 209 325 - 'N tilde' 326 5, 56, 68, 69, 70, 56, // 210 - 'O grave' 327 5, 56, 70, 69, 328 68, 56, // 211 - 'O acute' 329 5, 58, 69, 69, 69, 58, // 212 - 'O circumflex' 330 331 5, 56, 70, 69, 70, 57, // 213 - 'O tilde' 332 5, 56, 69, 68, 69, 56, // 333 214 - 'O diaresis' 334 5, 34, 20, 8, 20, 34, // 215 - 'Multiplication sign' 335 336 7, 64, 62, 81, 73, 69, 62, 1, // 216 - 'O slashed' 337 5, 60, 65, 66, 64, 338 60, // 217 - 'U grave' 339 5, 60, 64, 66, 65, 60, // 218 - 'U acute' 340 341 5, 58, 65, 65, 65, 58, // 219 - 'U circumflex' 342 5, 60, 65, 64, 65, 60, // 343 220 - 'U diaresis' 344 5, 12, 16, 98, 17, 12, // 221 - 'Y acute' 345 4, 127, 346 18, 18, 12, // 222 - 'Capital thorn' 347 4, 254, 37, 37, 26, // 223 - 'Small 348 letter sharp S' 349 5, 32, 84, 85, 122, 64, // 224 - 'a grave' 350 5, 32, 84, 351 86, 121, 64, // 225 - 'a acute' 352 5, 34, 85, 85, 121, 66, // 226 - 'a circumflex' 353 354 5, 32, 86, 85, 122, 65, // 227 - 'a tilde' 355 5, 32, 85, 84, 121, 64, // 356 228 - 'a diaresis' 357 5, 32, 84, 85, 120, 64, // 229 - 'a ring above' 358 7, 359 32, 84, 84, 124, 84, 84, 8, // 230 - 'ae' 360 5, 24, 36, 164, 228, 40, // 361 231 - 'c sedilla' 362 5, 56, 84, 85, 86, 88, // 232 - 'e grave' 363 5, 56, 364 84, 86, 85, 88, // 233 - 'e acute' 365 5, 58, 85, 85, 85, 90, // 234 - 'e 366 circumflex' 367 5, 56, 85, 84, 85, 88, // 235 - 'e diaresis' 368 3, 68, 125, 369 66, // 236 - 'i grave' 370 3, 68, 126, 65, // 237 - 'i acute' 371 3, 70, 372 125, 66, // 238 - 'i circumflex' 373 3, 69, 124, 65, // 239 - 'i diaresis' 374 375 4, 48, 75, 74, 61, // 240 - 'Small eth' 376 4, 122, 9, 10, 113, // 241 377 - 'n tilde' 378 5, 56, 68, 69, 70, 56, // 242 - 'o grave' 379 5, 56, 70, 69, 380 68, 56, // 243 - 'o acute' 381 5, 58, 69, 69, 69, 58, // 244 - 'o circumflex' 382 383 5, 56, 70, 69, 70, 57, // 245 - 'o tilde' 384 5, 56, 69, 68, 69, 56, // 385 246 - 'o diaresis' 386 5, 8, 8, 42, 8, 8, // 247 - 'Division sign' 387 6, 64, 388 56, 84, 76, 68, 58, // 248 - 'o slashed' 389 5, 60, 65, 66, 32, 124, // 249 390 - 'u grave' 391 5, 60, 64, 66, 33, 124, // 250 - 'u acute' 392 5, 58, 65, 65, 393 33, 122, // 251 - 'u circumflex' 394 5, 60, 65, 64, 33, 124, // 252 - 'u 395 diaresis' 396 4, 156, 162, 161, 124, // 253 - 'y acute' 397 4, 252, 72, 72, 398 48, // 254 - 'small thorn' 399 4, 157, 160, 160, 125, // 255 - 'y diaresis' 400}; 401 402#endif 403
leds_lookup_table.h
arduino
Look up table for the LEDs on the tree.
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
TelegramBot.h
arduino
Adapt to changed *.cpp
1// Copyright Casa Jasmina 2016 2// LGPL License 3// 4// TelegramBot library 5// https://github.com/CasaJasmina/TelegramBot-Library 6 7#ifndef TelegramBot_h 8#define TelegramBot_h 9 10#include <Arduino.h> 11#include <ArduinoJson.h> 12#include <Client.h> 13#include <TelegramKeyboard.h> 14 15#define HOST "api.telegram.org" 16#define SSL_PORT 443 17#define JSON_BUFF_SIZE 10000 18 19struct locationStruct{ 20 String lon; 21 String lat; 22}; 23 24struct message{ 25 String text; 26 String chat_id; 27 String sender; 28 String first_name; 29 String date; 30 locationStruct location; 31}; 32 33 34class TelegramBot 35{ 36 public: 37 TelegramBot(const char* token, Client &client); 38 void begin(); 39 String sendMessage(String chat_id, String text); 40 String sendMessage(String chat_id, String text, TelegramKeyboard &keyboard_markup, bool one_time_keyboard = true, bool resize_keyboard = true); 41 String postMessage(String msg); 42 message getUpdates(); 43 44 45 private: 46 String readPayload(); 47 String convertText(String unicodeStr); 48 const char* token; 49 50 int last_message_recived; 51 52 Client *client; 53}; 54 55#endif 56
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.
Comments
Only logged in users can leave comments
tlauxtermann
0 Followers
•0 Projects
Table of contents
Intro
14
0