iBeacons konfigurieren

iBeacons sind eine spannende Technology um die Position von Menschen oder Objekten in Innenräumen festzustellen. Im Prinzip handelt es sich im Bluetooth-Low-Energy Geräte, die in periodischen Intervallen eine eindeutige Identifikation versenden. Auf Basis der empfangenen Daten kann der Empfänger sogar die Entfernung zum iBeacon errechnen.

Für die Berechnung der Position in einer Wohnung sind selbst die günstigsten iBeacons perfekt geeignet. Die kurze Reichweite kommt dem sogar entgegen, weil bei mehreren iBeacons, die in der Wohnung verteilt werden nicht immer alle in Reichweite alle iBeacons sind und damit eine grobe Positionsbestimmung selbst ohne Triangulation möglich ist.

Da die meisten iBeacons auf einem Texas-Instruments Chip basieren, sind sie selbst als Direktimport aus China nicht extrem günstig. Unter 10€ sind iBeacons kaum zu bekommen. Allerdings benötigt man selbst für grosse Wohnungen kaum mehr als 5-6 Stück.

Ein beliebter iBeacon ist der Ghostyu. Er besteht aus einer kleinen Leiterplatte mit einer grossen Battery auf der Rückseite.

ghostyu

Wenn man nun nur einen iBeacon nutzt, muss man eigentlich nichts weiter tun. Allerdings wird man irgendwann feststellen, dass das Smartphone der Meinung ist, man wäre zu Hause, obwohl man unterwegs ist. Warum? Alle diese Beacons kommen mit der gleichen ID. Diese sieht wie folgt aus:

UUID: E2C56DB5-DFFB-48D2-B060-D0F5A71096E0
Major: 0
Minor: 0

iBeacons benutzen eine 3-teilige ID. Je nach Applikation können Major und Minor ID ignoriert werden, aber die UUID wird immer genutzt.

Daher empfehle ich generell, UUID. Major und Minor anzupassen. Die UUID ist eine 128-bit ID. Man kann einfach zufällig einen 128-bit Wert generieren und ist praktisch sicher, dass niemand sonst diesen Wert nutzt (solange er wirklich zufällig generiert wurde). Die einfachste Variant um eine zufällige UUID zu erzeugen ist ein online UUID Generator.

Aber wie kann man die UUID ändern? Für den Ghostyu gibt es eine iOS-App (andere iBeacons bringen nur Android-Apps mit, das kann u.U. problematisch sein, wenn man kein Android-Smartphone besitzt). Leider gibt es die App LightBeacon nur in Chinesisch. Mit etwas Herumklicken sollte sich der Konfigurationsdialog aber doch recht einfach finden lassen. Dieser sieht wie folgt aus:

lightbeacon

Hier kann man jetzt nicht nur UUID, major und minor ID ändern, sondern auch das Sendeintervall. Für die meisten Anwendungsfälle reicht es durchaus aus, wenn der Beacon alle 4 Sekunden sendet. Das verlängert die Batterielebensdauer deutlich. Jetzt noch speichern und der iBeacon startet neu und meldet sich mit den neu konfigurierten IDs.

Batteriebetriebener Sensor auf ESP8266-Basis

Der ESP8266 ist ein leistungsfähiger und günstiger Mikrocontroller. Während früher noch oft proprietäre Funkprotokolle wie z.B. nRF24-basierte Chips genutzt wurden, kann man viele heute für viele Anwendungsfälle gleich auf WLAN setzen. Es gibt allerdings ein grosses Problem mit WiFi: der Stromverbrauch.

Wenn der ESP8266 mit einem WiFi-Netzwerk verbunden ist, verbraucht er mindestens 70mA, teilweise sogar deutlich mehr. Wenn man nur ein System mit einem 2400mAh-Akku betreiben will, ist dieser nach spätestens einem Tag leer. Und niemand möchte wohl für Sensoranwendungen eine Autobatterie nutzen.

Glücklicherweise müssen Sensoranwendungen in vielen Fällen nur selten Daten übertragen. Selbst Messungen müssen oftmals nicht ständig erfolgen. Das heisst, die meiste Zeit kann der Chip einfach schlafen. Um dies umzusetzen, geht man wie folgt vor:

  1. Daten sammeln. Das sollte geschehen, bevor das WLAN-Modul aktiviert wird (ausser, die Datenabfrage benötigt nur wenige Millisekunden)
  2. Mit dem WLAN verbinden
  3. Daten senden
  4. In den “Deep sleep”-Modus wechseln. Hierfür nutzt man die ESP.deepSleep() Funktion.

Bei der ESP.deepSleep() Funktion gibt es im übrigen einige Dinge zu beachten:

  1. Damit der Mikrocontroller nach der entsprechenden Zeitspanne wieder aufwacht, mit GPIO16 des ESP8266 mit dem RESET-Pin verbunden sein. Ansonsten schläft der Controller ewig.
  2. Der delay-Parameter ist in Mikrosekunden anzugeben. Wenn sich der ESP8266 also scheinbar nie schlafen legt, könnte es sein, dass man die Zeit versehentlich in Sekunden oder Millisekunden angegeben hat.
  3. Es gibt einen zweiten – optionalen – Parameter, der 4 Werte annehmen kann: WAKE_RF_DEFAULT, WAKE_RFCAL,WAKE_NO_RFCAL, WAKE_RF_DISABLED. Der Wert WAKE_RF_DISABLED sieht auf den ersten Blick vielversprechend aus, denn irgendwie sollte das WiFi-Modul ja abgeschaltet werden. Allerdings bezieht sich dieses Argument auf die Funktion nach dem Aufwachen. Übergibt man hier also WAKE_RF_DISABLED , ist der ESP8266 nach dem Aufwachen nicht mehr in der Lage über WLAN zu kommunizieren.

Hier noch ein paar zusätzliche Tips zum Stromsparen:

  1. LEDs als optische Signalisierung sollten nur sehr kurz eingeschaltet werden. Einige Millisekunden reichen i.d.R. aus, damit der Benutzer das Aufblitzen wahrnimmt.
  2. Müssen die LEDs etwas länger eingeschaltet bleiben, sollten sie gedimmt werden. Mit der analogWrite Funktion kann man das einfach umsetzen.

Hier ist ein einfaches Beispiel, das die Daten vom Analogeingang des Controllers liest und an einen MQTT-Broker übermittelt:

#include         // Generic ESP8266 WiFi routines
#include        // MQTT client
#include           // Local DNS Server used for redirecting all requests to the configuration portal
#include    // Local WebServer used to serve the configuration portal
#include         // WiFi Configuration Magic


const char* mqtt_server = "192.168.1.88";
const char* mqtt_channel_up = "active";
const char* mqtt_channel_data = "sensor/%d/adc";

const int pin_red = 15;
const int pin_green = 12;
const int pin_blue = 13;
const int pin_button = 4;
const int analog_ldr = 0;

const int sleepSeconds = 60 * 15;

WiFiManager wifiManager;
WiFiClient espClient;
PubSubClient client(espClient);


void send_sensor_data(void) {
  Serial.println("Sending sensor data\n");
  int data = analogRead(A0);
  char s_channel[50];
  char s_id[10];
  char s_data[10];
  sprintf(s_channel, mqtt_channel_data, ESP.getChipId());
  sprintf(s_id, "%d", ESP.getChipId());
  sprintf(s_data, "%d", data);

  digitalWrite(pin_blue, HIGH);
  client.connect("ESP8266Client");
  digitalWrite(pin_blue, LOW);
  if (! client.connected()) {
    Serial.println("Could not connect to MQTT broker, doing nothing");
  } else {
    digitalWrite(pin_green, HIGH);
    client.publish(mqtt_channel_up, s_id); // show that this device is up
    client.publish(s_channel, s_data); // send sensor data
    digitalWrite(pin_green, LOW);
  }
}

void setup() {
  delay(500); // This makes it easier to upload new firmware and/or press the "clean" button

  pinMode(pin_red, OUTPUT);
  pinMode(pin_green, OUTPUT);
  pinMode(pin_blue, OUTPUT);

  digitalWrite(pin_red, HIGH);

  // Setup Serial interface for debugging
  Serial.begin(115200);

  //  Bring up WLAN
  WiFiManager wifiManager;

  //sets timeout until configuration portal gets turned off
  //useful to make it all retry or go to sleep
  //in seconds
  wifiManager.setTimeout(60);

  WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
  wifiManager.addParameter(&custom_mqtt_server);

  if (digitalRead(pin_button) == 0) {
    // reset settings
    wifiManager.resetSettings();
  }

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect()) {
    Serial.println("failed to connect and hit timeout");
    delay(100);
    // do nothing: deep sleep, but longer than usual. Something might be wrong and
    // we should save power
    ESP.deepSleep(sleepSeconds * 10 * 1000000, WAKE_RF_DISABLED);
  }

  mqtt_server = custom_mqtt_server.getValue();

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Setup MQTT client
  client.setServer(mqtt_server, 1883);

  digitalWrite(pin_red, LOW);
}

void loop(void) {
  send_sensor_data();
  Serial.printf("Sleeping deep for %i seconds...", sleepSeconds);
  ESP.deepSleep(sleepSeconds * 1000000);
  delay(100);
}

Innovation begins at home

Andy Stanford-Clark, IBM Distinguished Engineer for the Internet of Things, will explain how his hobby of home automation and his passion for energy saving converges with the Internet of Things.
This has led to projects that have helped alleviate energy poverty in social housing, and are helping commuters from the Isle of Wight check if the ferries are running on time.
Andy will explain that “it’s all about the data” and how these solutions are built from instrumented, interconnected, intelligent devices. He will illustrate his talk with examples from his home, including his twittering mouse traps!

Click on the image to view the video on Vimeo.

Screenshot 2016-05-17 09.22.36