Bei dem letzten Versuch in diesem Advent geht es wieder etwas weihnachtlicher zu. Wir basteln eine wiederverwendbare Geschenkbox, mit der Sie Ihre Verwandten beglücken können. Jedes Mal wenn jemand das Geschenk öffnet, wird der Inhalt in einer individuellen Farbe beleuchtet und ein Weihnachtssound ertönt.

Hinter dem heutigen Türchen befindet sich eine Reflexlichtschranke. Es handelt sich dabei eigentlich um zwei Bauteile, einer IR-Sendediode und einem Phototransitor. Wie genau Sie die Elemente gepolt werden müssen ist nicht ganz einfach zu erkennen. Deswegen stecken Sie am besten die Lichtschranke nach dem unteren Vorbild mit dem Verbindungskabeln zusammen. Dann können Sie die Polung nicht so leicht vertauschen.

So schließen Sie die Reflexlichtschranke an
So schließen Sie die Reflexlichtschranke an

Der Aufbau des heutigen Tages enthält heute viele Bauteile, weswegen alles auf den ersten Blick ein bisschen verwirrend aussieht Neben der Reflexlichtschranke, die uns als Sensor zum Erkennen des Öffnen des Paketes dient, kommen noch die RGB-Diode und der Piezosummer zum Einsatz.

day24_present2_steckplatine
Der letzte Aufbau des Adventskalenders
Das Programm: A16_P24_MQTT_Present.ino
/*
  MQTT Present
  Change SSID and PASSWORD.
*/

#include <NanoESP.h>
#include <NanoESP_MQTT.h>
#include <SoftwareSerial.h>

#include <RGBLED.h>
#include <RGBColor.h>

#include "pitches.h"
#include "songs.h"

#define SSID "YourSSID"
#define PASSWORD "YourPassword"

#define LED_WLAN 13
#define DEBUG true

#define RED 3
#define GREEN 5
#define BLUE 6
#define GND 4
#define BUTTON 7

#define PIEZO 8

#define IR A1
#define PHOTO A0

NanoESP nanoesp = NanoESP();
NanoESP_MQTT mqtt = NanoESP_MQTT(nanoesp);

RGBLED rgbLED = RGBLED(RED, GREEN, BLUE, 0, 3, 0);

String ip, mqttId;

RGBColor newColor = RGBColor(0, 0, 0);
RGBColor offColor = RGBColor(0, 0, 0);
int curSong;
bool isOpen = true;

mqtt_msg opened = {"", "Opened", 0, true};

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);

  pinMode(GND, OUTPUT);
  digitalWrite(GND, LOW);

  pinMode(IR, OUTPUT);

  Serial.begin(19200);

  nanoesp.init();

  //Station Mode
  nanoesp.configWifiMode(STATION);

//  nanoesp.configWifiStation(SSID, PASSWORD);

  if (nanoesp.wifiConnected()) {
    Serial.println(F("Wifi Connected"));
    digitalWrite(LED_WLAN, HIGH);
  }
  else {
    Serial.println(F("Wifi not Connected"));
  }


  //Print IP in Terminal
  nanoesp.getIpMac( ip,  mqttId);
  Serial.println("My IP: " + ip);

  //Print MQTTid in Terminal
  mqttId.replace(":", "");
  Serial.println("My MQTT ID: " + mqttId+"\n");

  if (mqtt.connect(0, "broker.fkainka.de", 1883, mqttId)) {
    Serial.println(F("Connected to Broker"));

    Serial.println(F("My personal Topic is:"));
    Serial.println("NanoESP/" + mqttId + "/\n");

    if (mqtt.subscribe(0, "NanoESP/" + mqttId + "/present", 2, newPresent)) Serial.println(F("Subscribed to present")); else Serial.println(F("Error Subscribe to present"));
  }
  else {
    Serial.println(F("error connecting"));
  }
  setSongs();
}

void loop() {
  int id, len;

  if (nanoesp.recvData(id, len)) {
    mqtt.recvMQTT(id, len); //auto hanlder mit Funktionen
  }

  mqtt.stayConnected(0);

//Present opened?
  if  (!isOpen) {
    if (checkIsOpen()) {
      isOpen = true;
      Serial.println("Open");
      mqtt.publish(0, &opened);
      rgbLED.crossfade(newColor);
      play(curSong);
    }
  }
  else { //Present closed?
    if (!checkIsOpen()) {
      isOpen = false;
      Serial.println("Closed");
      rgbLED.crossfade(offColor);
    }
  }
}


bool checkIsOpen()
{
  int high; int low;

  digitalWrite(IR, HIGH);
  delay(1);
  high = analogRead(PHOTO);
  digitalWrite(IR, LOW);
  delay(1);
  low = analogRead(PHOTO);

  digitalWrite(IR, HIGH);
  delay(1);
  high += analogRead(PHOTO);
  digitalWrite(IR, LOW);
  delay(1);
  low += analogRead(PHOTO);

  if (high > (2 * low)) {
    return false;
  }
  else {
    return true;
  }
}

String oldTopic;

void newPresent(String value) {
  Serial.println("New Present for " + value);
  if (opened.topic != "") {
    mqtt.unsubscribe(0, opened.topic + "/color");
    Serial.println(F("Unsubscribed old color"));

    mqtt.unsubscribe(0, opened.topic + "/song");
    Serial.println(F("Unsubscribed old song"));
  }

  opened.topic = "NanoESP/" + mqttId + "/present/" + value;
  mqtt.subscribe(0, opened.topic + "/color", 2, gotnewColor); Serial.println(F("Subscribed new Color"));

  // Recieve retained msg before subscribing next
  int id, len;
  for (int i = 0; i <= 250; i++) {
    if (nanoesp.recvData(id, len)) {
      if (mqtt.recvMQTT(id, len)) {
        break; //auto hanlder mit Funktionen
      }
    }
    delay(10);
  }
  mqtt.subscribe(0, opened.topic + "/song", 2, gotnewSong); Serial.println(F("Subscribed new Song"));
}


void gotnewColor(String value) {
  Serial.println("New color: " + value);

  value = value.substring(value.indexOf('(') + 1); //255,23,226)
  int red = value.substring(0, value.indexOf(',')).toInt();

  value = value.substring(value.indexOf(',' ) + 1); //23,226)
  int green = value.substring(0, value.indexOf(',')).toInt();

  value = value.substring(value.indexOf(',') + 1); //226)
  int blue = value.substring(0, value.indexOf(')')).toInt();

  newColor   = RGBColor(red, green, blue);

  //for direct change
  //analogWrite(RED, red); analogWrite(GREEN, green); analogWrite(BLUE, blue);
}

void gotnewSong(String value) {
  Serial.println("New Song: " + value);
  curSong = value.toInt();
}

void setSongs() {
  //Configuration for songs, you may change some songs
  int numTunes = 5;

  tunes[0] = {weWish, weWishDurations, sizeof(weWish) / sizeof(int), 80, N_C6, N_C5};
  tunes[1] = {alleJahre, alleJahreDurations, sizeof(alleJahre) / sizeof(int), 80, N_C6, N_C5};
  tunes[2] = {jingleBells, jingleBellsDurations, sizeof(jingleBells) / sizeof(int), 60, 784, 523};
  tunes[3] = {firstNoel, firstNoelDurations, sizeof(firstNoel) / sizeof(int), 60, 523, 262};
  //tunes[3] = {oHolyNight, oHolyNightDurations, sizeof(oHolyNight) / sizeof(int), 100, 659, 262};
  tunes[4] = {whatChild, whatChildDurations, sizeof(whatChild) / sizeof(int), 100, 587, 247};
  tunes[5] = {weThreeKings, weThreeKingsDurations, sizeof(weThreeKings) / sizeof(int), 100, 587, 294};
  
}

void play(int tuneNum) {

  int randomOffset = random(32);

  int numNotes = tunes[tuneNum].numCount;
  int tempo = tunes[tuneNum].tempo;
  for (int thisNote = 0; thisNote < numNotes; thisNote++) {

    int freq = pgm_read_word_near(tunes[tuneNum].melody + thisNote) * 2;
    int noteDuration =   tempo *  pgm_read_byte_near(tunes[tuneNum].durations + thisNote);

    if (freq > 0) {
      int n = (map(freq, tunes[tuneNum].low, tunes[tuneNum].high, 1, 31) + randomOffset) % 31 + 1;
      tone(PIEZO, freq, noteDuration);

    } else {
      // REST
      delay(noteDuration);
    }

    delay(noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 0.30;
    delay(pauseBetweenNotes);

    noTone(PIEZO);
  }
}

(Die frühere Einbettung über Arduino Create ist nicht mehr verfügbar; der Code stammt aus dem Download aller Programme.)

Nachdem Sie das heutige Programm auf den Controller geladen habe, gehen Sie erneut auf die http://www.hivemq.com/try-out/ Seite und verbinden sich mit dem Broker broker.hivemq.com. Dort können Sie nun beginnen, den Personen die Sie beschenken wollen ein Topic zu widmen, und zwar nach folgendem Schema:

NanoESP/mqttId/present/person/color

NanoESP/mqttId/present/person/song

Wobei Sie mqttId durch Ihre persönliche ID und person durch die Person die Sie beschenken wollen ersetzen. In dem Topic color publishen Sie ein Farbe nach dem bekannten Schema rgb(X,X,X) und ins Topic song eine Nummer zwischen 0 und 5 die für einen vordefinierten Song steht. Beide Nachrichten müssen mit dem Retain-Flag versehen werden. Für drei Personen sähe dies nun beispielsweise so aus:

TopicValueRetain
NanoESP/mqttId/present/mutter/color

rgb(255,255,0) | X || NanoESP/mqttId/present/mutter/song |

2 | X || NanoESP/mqttId/present/vater/color |

rgb(0,0,255) | X || NanoESP/mqttId/present/vater/song |

1 | X || NanoESP/mqttId/present/schwester/color |

rgb(255,0,255) | X || NanoESP/mqttId/present/schwester/song |

4 | X |

Nun können Sie zwischen diesen Personen umschalten, indem Sie die Person in dem Topic

NanoESP/mqttId/present

veröffentlichen. Tragen Sie dort nun beispielsweise schwester ein (genaue Schreibweise beachten), werden die Einstellungen für Ihre Schwester geladen, und beim Öffnen der Box verwendet. Nach der Entnahme des Geschenks legen Sie das nächste hinein, schließen die Box wieder und laden die nächste Einstellung durch Publishen der nächsten Person. Zu Testzwecken können Sie den Sensor vor ein weißes Blatt halten, was das Schließen der Box simuliert. Das restliche Tageslicht muss dabei abgeschirmt werden. Nehmen Sie das Blatt weg, wird die Box als geöffnet erkannt.

Zum Bauen der Geschenkbox benötigen Sie nun nur noch einen Schuh- oder vergleichbaren Pappkarton. Das Board können Sie einfach mit dem auf der Unterseite des Boards befestigten Klebestreifens an einer Seite des Kartons befestigen. Es hat sich als besonders praktisch erwiesen, den Piezzosummer zwischen Steckboard und Karton zu stecken. Auch überschüssiges Kabel von der Reflexlichtschranke können Sie mit ankleben, wichtig ist nur, dass die Refelexlichtschranke genau bis zum Rand des Kartons reicht. Befestigen Sie ihn dort mit Klebeband.

img_20161223_152027-2
Das System in einem Schuhkarton

Eine zusätzliche Pappe, die einfach in den Karton geklemmt werden kann, verdeckt das Board und den Kabelsalat. Ein kleines Loch muss allerdings noch in diese Trennwand gestochen werden, sodass die RGB-LED durchschaut und das innere des Kartons beleuchten kann. Zum Schluss können Sie, nach Bedarf, den Karton noch innen und außen mit weihnachtlichen Geschenkpapier verkleben. Schon ist die Geschenkbox fertig.

Eine Trennwand verdeckt den Kabelsalat
Eine Trennwand verdeckt den Kabelsalat