Für diese Projekt setzen wir voraus, dass eine C Entwicklungsumgebung eingerichtet ist und ein grundsätzliches Verständnis der C Programmiersprache vorhanden ist.
Falls dies nicht der Fall ist sollte hier begonnen werden. Informationen über die Tinkerforge API sind dann hier zu finden.
Wir setzen uns folgende Ziele für dieses Projekt:
Da dieses Projekt wahrscheinlich 24/7 laufen wird, wollen wir sicherstellen, dass das Programm möglichst robust gegen externe Einflüsse ist. Das Programm sollte weiterhin funktionieren falls
Im Folgenden werden wir Schritt für Schritt zeigen wie diese Ziele erreicht werden können.
Als Erstes legen wir fest wohin unser Programm sich verbinden soll:
#define HOST "localhost"
#define PORT 4223
Falls eine WIFI Extension verwendet wird, oder der Brick Daemon auf einem anderen PC läuft, dann muss "localhost" durch die IP Adresse oder den Hostnamen der WIFI Extension oder des anderen PCs ersetzt werden.
Nach dem Start des Programms müssen der IPCON_CALLBACK_ENUMERATE
Callback
und der IPCON_CALLBACK_CONNECTED
Callback registriert und ein erstes
Enumerate ausgelöst werden:
typedef struct {
IPConnection ipcon;
} WeatherStation;
int main() {
WeatherStation ws;
ipcon_create(&ws.ipcon);
ipcon_connect(&ws.ipcon, HOST, PORT);
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_ENUMERATE,
(void *)cb_enumerate,
(void *)&ws);
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_CONNECTED,
(void *)cb_connected,
(void *)&ws);
ipcon_enumerate(&ws.ipcon);
return 0;
}
Der Enumerate Callback wird ausgelöst wenn ein Brick per USB angeschlossen wird
oder wenn die ipcon_enumerate()
Funktion aufgerufen wird. Dies ermöglicht es die
Bricks und Bricklets im Stapel zu erkennen ohne im Voraus ihre UIDs kennen zu
müssen.
Der Connected Callback wird ausgelöst wenn die Verbindung zur WIFI Extension oder zum Brick Daemon hergestellt wurde. In diesem Callback muss wiederum ein Enumerate angestoßen werden, wenn es sich um ein Auto-Reconnect handelt:
void cb_connected(uint8_t connected_reason, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(connected_reason == IPCON_CONNECT_REASON_AUTO_RECONNECT) {
ipcon_enumerate(&ws->ipcon);
}
}
Ein Auto-Reconnect bedeutet, dass die Verbindung zur WIFI Extension oder zum Brick Daemon verloren gegangen ist und automatisch wiederhergestellt werden konnte. In diesem Fall kann es sein, dass die Bricklets ihre Konfiguration verloren haben und wir sie neu konfigurieren müssen. Da die Konfiguration beim Enumerate (siehe unten) durchgeführt wird, lösen wir einfach noch ein Enumerate aus.
Schritt 1 zusammengefügt:
typedef struct {
IPConnection ipcon;
} WeatherStation;
void cb_connected(uint8_t connected_reason, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(connected_reason == IPCON_CONNECT_REASON_AUTO_RECONNECT) {
ipcon_enumerate(&ws->ipcon);
}
}
int main() {
WeatherStation ws;
ipcon_create(&ws.ipcon);
ipcon_connect(&ws.ipcon, HOST, PORT);
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_ENUMERATE,
(void *)cb_enumerate,
(void *)&ws);
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_CONNECTED,
(void *)cb_connected,
(void *)&ws);
ipcon_enumerate(&ws.ipcon);
return 0;
}
Während des Enumerierungsprozesse sollen alle messenden Bricklets konfiguriert werden. Dadurch ist sichergestellt, dass sie neu konfiguriert werden nach einem Verbindungsabbruch oder einer Unterbrechung der Stromversorgung.
Die Konfiguration soll beim ersten Start (IPCON_ENUMERATION_TYPE_CONNECTED
)
durchgeführt werden und auch bei jedem extern ausgelösten Enumerate
(IPCON_ENUMERATION_TYPE_AVAILABLE
):
void cb_enumerate(const char *uid, const char *connected_uid,
char position, uint8_t hardware_version[3],
uint8_t firmware_version[3], uint16_t device_identifier,
uint8_t enumeration_type, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(enumeration_type == IPCON_ENUMERATION_TYPE_CONNECTED ||
enumeration_type == IPCON_ENUMERATION_TYPE_AVAILABLE) {
Die Konfiguration des LCD 20x4 ist einfach, wir löschen den aktuellen Inhalt des Displays und schalten das Backlight ein:
if(device_identifier == LCD_20X4_DEVICE_IDENTIFIER) {
lcd_20x4_create(&ws->lcd, uid, &ws->ipcon);
lcd_20x4_clear_display(&ws->lcd);
lcd_20x4_backlight_on(&ws->lcd);
}
Das Ambient Light, Humidity und Barometer Bricklet werden so eingestellt, dass sie uns ihre jeweiligen Messwerte höchsten mit einer Periode von 1000ms (1s) mitteilen:
else if(device_identifier == AMBIENT_LIGHT_DEVICE_IDENTIFIER) {
ambient_light_create(&ws->ambient_light, uid, &ws->ipcon);
ambient_light_set_illuminance_callback_period(&ws->ambient_light, 1000);
ambient_light_register_callback(&ws->ambient_light,
AMBIENT_LIGHT_CALLBACK_ILLUMINANCE,
(void *)cb_illuminance,
(void *)ws);
} else if(device_identifier == HUMIDITY_DEVICE_IDENTIFIER) {
humidity_create(&ws->humidity, uid, &ws->ipcon);
humidity_set_humidity_callback_period(&ws->humidity, 1000);
humidity_register_callback(&ws->humidity,
HUMIDITY_CALLBACK_HUMIDITY,
(void *)cb_humidity,
(void *)ws);
} else if(device_identifier == BAROMETER_DEVICE_IDENTIFIER) {
barometer_create(&ws->barometer, uid, &ws->ipcon);
barometer_set_air_pressure_callback_period(&ws->barometer, 1000);
barometer_register_callback(&ws->barometer,
BAROMETER_CALLBACK_AIR_PRESSURE,
(void *)cb_air_pressure,
(void *)ws);
}
Dies bedeutet, dass die Bricklets die cb_illuminance
, cb_humidity
und cb_air_pressure
Callback-Funktionen immer dann aufrufen wenn sich der
Messwert verändert hat, aber höchsten alle 1000ms.
Schritt 2 zusammengefügt:
void cb_enumerate(const char *uid, const char *connected_uid,
char position, uint8_t hardware_version[3],
uint8_t firmware_version[3], uint16_t device_identifier,
uint8_t enumeration_type, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(enumeration_type == IPCON_ENUMERATION_TYPE_CONNECTED ||
enumeration_type == IPCON_ENUMERATION_TYPE_AVAILABLE) {
if(device_identifier == LCD_20X4_DEVICE_IDENTIFIER) {
lcd_20x4_create(&ws->lcd, uid, &ws->ipcon);
lcd_20x4_clear_display(&ws->lcd);
lcd_20x4_backlight_on(&ws->lcd);
} else if(device_identifier == AMBIENT_LIGHT_DEVICE_IDENTIFIER) {
ambient_light_create(&ws->ambient_light, uid, &ws->ipcon);
ambient_light_set_illuminance_callback_period(&ws->ambient_light, 1000);
ambient_light_register_callback(&ws->ambient_light,
AMBIENT_LIGHT_CALLBACK_ILLUMINANCE,
(void *)cb_illuminance,
(void *)ws);
} else if(device_identifier == HUMIDITY_DEVICE_IDENTIFIER) {
humidity_create(&ws->humidity, uid, &ws->ipcon);
humidity_set_humidity_callback_period(&ws->humidity, 1000);
humidity_register_callback(&ws->humidity,
HUMIDITY_CALLBACK_HUMIDITY,
(void *)cb_humidity,
(void *)ws);
} else if(device_identifier == BAROMETER_DEVICE_IDENTIFIER) {
barometer_create(&ws->barometer, uid, &ws->ipcon);
barometer_set_air_pressure_callback_period(&ws->barometer, 1000);
barometer_register_callback(&ws->barometer,
BAROMETER_CALLBACK_AIR_PRESSURE,
(void *)cb_air_pressure,
(void *)ws);
}
}
}
Wir wollen eine hübsche Darstellung der Messwerte auf dem Display. Zum Beispiel:
Illuminanc 137.39 lx
Humidity 34.10 %
Air Press 987.70 mb
Temperature 22.64 °C
Die Dezimaltrennzeichen und die Einheiten sollen in jeweils einer Spalte übereinander stehen. Daher verwenden wird zwei Zeichen für jede Einheit, zwei Nachkommastellen und kürzen die Namen so, dass sie in den restlichen Platz der jeweiligen Zeile passen. Das ist auch der Grund, warum dem "Illuminanc" das letzte "e" fehlt.
sprintf(text, "%6.2f", value);
Der obige Ausdruck wandelt eine Fließkommazahl in eine Zeichenkette um, gemäß der gegebenen Formatspezifikation. Das Ergebnis ist dann mindestens 6 Zeichen lang mit 2 Nachkommastellen. Fall es weniger als 6 Zeichen sind wird von Links mit Leerzeichen aufgefüllt.
void cb_illuminance(uint16_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Illuminanc %6.2f lx", illuminance/10.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
}
void cb_humidity(uint16_t humidity, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Humidity %6.2f %%", humidity/10.0);
lcd_20x4_write_line(&ws->lcd, 1, 0, text);
}
void cb_air_pressure(int32_t air_pressure, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Air Press %7.2f mb", air_pressure/1000.0);
lcd_20x4_write_line(&ws->lcd, 2, 0, text);
}
Es fehlt noch die Temperatur. Das Barometer Bricklet kann auch die Temperatur
messen, aber es hat dafür keinen Callback. Als einfacher Workaround können wir
die Temperatur in der cb_air_pressure
Callback-Funktion abfragen:
void cb_air_pressure(int32_t air_pressure, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Air Press %7.2f mb", air_pressure/1000.0);
lcd_20x4_write_line(&ws->lcd, 2, 0, text);
int16_t temperature;
barometer_get_chip_temperature(&ws->barometer, &temperature);
memset(text, '\0', sizeof(text));
sprintf(text, "Temperature %5.2f %cC", temperature/100.0, 0xDF);
lcd_20x4_write_line(&ws->lcd, 3, 0, text);
}
Schritt 3 zusammengefügt:
void cb_illuminance(uint16_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Illuminanc %6.2f lx", illuminance/10.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
}
void cb_humidity(uint16_t humidity, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Humidity %6.2f %%", humidity/10.0);
lcd_20x4_write_line(&ws->lcd, 1, 0, text);
}
void cb_air_pressure(int32_t air_pressure, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
char text[30] = {'\0'};
sprintf(text, "Air Press %7.2f mb", air_pressure/1000.0);
lcd_20x4_write_line(&ws->lcd, 2, 0, text);
int16_t temperature;
barometer_get_chip_temperature(&ws->barometer, &temperature);
memset(text, '\0', sizeof(text));
// 0xDF == ° on LCD 20x4 charset
sprintf(text, "Temperature %5.2f %cC", temperature/100.0, 0xDF);
lcd_20x4_write_line(&ws->lcd, 3, 0, text);
}
Das ist es. Wenn wir diese drei Schritte zusammen in eine Datei kopieren und ausführen, dann hätten wir jetzt eine funktionierenden Wetterstation.
Es gibt einige offensichtliche Möglichkeiten die Ausgabe der Messdaten noch zu
verbessern. Die Namen könnten dynamisch exakt gekürzt werden, abhängig vom
aktuell freien Raum der jeweiligen Zeile. Auch könnten die Namen können noch
ins Deutsche übersetzt werden. Ein anderes Problem ist die Abfrage der
Temperatur in der cb_air_pressure
Callback-Funktion. Wenn sich der Luftdruck
nicht ändert dann wird auch die Anzeige der Temperatur nicht aktualisiert, auch
wenn sich diese eigentlich geändert hat. Es wäre besser die Temperatur jede Sekunde in einem eigenen Thread anzufragen.
Aber wir wollen das Programm für den Anfang einfach halten.
Wie dem auch sei, wir haben noch nicht alle Ziele erreicht. Das Programm ist noch nicht robust genug. Was passiert wenn die Verbindung beim Start des Programms nicht hergestellt werden kann, oder wenn das Enumerate nach einem Auto-Reconnect nicht funktioniert?
Wir brauchen noch Fehlerbehandlung!
Beim Start des Programms versuchen wir solange die Verbindung herzustellen, bis es klappt:
while(true) {
int rc = ipcon_connect(&ws.ipcon, HOST, PORT);
if(rc < 0) {
fprintf(stderr, "Could not connect to brickd: %d\n", rc);
// TODO: sleep 1s
continue;
}
break;
}
und es wird solange versucht ein Enumerate zu starten bis auch dis geklappt hat:
while(true) {
int rc = ipcon_enumerate(&ws.ipcon);
if(rc < 0) {
fprintf(stderr, "Could not enumerate: %d\n", rc);
// TODO: sleep 1s
continue;
}
break;
}
Es gibt keine portable Sleep Funktion in C. Auf Windows deklariert windows.h`
eine Sleep
Funktion die die Wartedauer in Millisekunden übergeben bekommt.
Auf POSIX Systemen wie Linux und macOS gibt es eine sleep
Funktion
deklariert in unistd.h
die die Wartedauer in Sekunden übergeben bekommt.
Mit diesen Änderungen kann das Programm schon gestartet werden bevor die Wetterstation angeschlossen ist.
Es muss auch sichergestellt werden, dass wir nur auf das LCD schreiben nachdem es initialisiert wurde:
void cb_illuminance(uint16_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Illuminanc %6.2f lx", illuminance/10.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
printf("Write to line 0: %s\n", text);
}
}
und es müssen mögliche Fehler während des Enumerierungsprozesses behandelt werden:
if(device_identifier == AMBIENT_LIGHT_DEVICE_IDENTIFIER) {
ambient_light_create(&ws->ambient_light, uid, &ws->ipcon);
ambient_light_register_callback(&ws->ambient_light,
AMBIENT_LIGHT_CALLBACK_ILLUMINANCE,
(void *)cb_illuminance,
(void *)ws);
int rc = ambient_light_set_illuminance_callback_period(&ws->ambient_light, 1000);
if(rc < 0) {
fprintf(stderr, "Ambient Light init failed: %d\n", rc);
} else {
printf("Ambient Light initialized\n");
}
}
Zusätzlich wollen wir noch ein paar Logausgaben einfügen. Diese ermöglichen es später herauszufinden was ein Problem ausgelöst hat, wenn die Wetterstation nach einer Weile möglicherweise nicht mehr funktioniert wie erwartet.
Zum Beispiel, wenn die Wetterstation über WLAN angebunden ist und häufig Auto-Reconnects auftreten, dann ist wahrscheinlich die WLAN Verbindung nicht sehr stabil.
Jetzt sind alle für diese Projekt gesteckten Ziele erreicht.
Das gesamte Programm für die Wetterstation (download):
#include <stdio.h>
#include "ip_connection.h"
#include "bricklet_lcd_20x4.h"
#include "bricklet_ambient_light.h"
#include "bricklet_ambient_light_v2.h"
#include "bricklet_ambient_light_v3.h"
#include "bricklet_humidity.h"
#include "bricklet_humidity_v2.h"
#include "bricklet_barometer.h"
#include "bricklet_barometer_v2.h"
#define HOST "localhost"
#define PORT 4223
typedef struct {
IPConnection ipcon;
LCD20x4 lcd;
bool lcd_created;
AmbientLight ambient_light;
AmbientLightV2 ambient_light_v2;
AmbientLightV3 ambient_light_v3;
Humidity humidity;
HumidityV2 humidity_v2;
Barometer barometer;
BarometerV2 barometer_v2;
} WeatherStation;
void cb_illuminance(uint16_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Illuminanc %6.2f lx", illuminance / 10.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
printf("Write to line 0: %s\n", text);
}
}
void cb_illuminance_v2(uint32_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Illumina %8.2f lx", illuminance / 100.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
printf("Write to line 0: %s\n", text);
}
}
void cb_illuminance_v3(uint32_t illuminance, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Illumina %8.2f lx", illuminance / 100.0);
lcd_20x4_write_line(&ws->lcd, 0, 0, text);
printf("Write to line 0: %s\n", text);
}
}
void cb_humidity(uint16_t humidity, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Humidity %6.2f %%", humidity/10.0);
lcd_20x4_write_line(&ws->lcd, 1, 0, text);
printf("Write to line 1: %s\n", text);
}
}
void cb_humidity_v2(uint16_t humidity, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Humidity %6.2f %%", humidity/100.0);
lcd_20x4_write_line(&ws->lcd, 1, 0, text);
printf("Write to line 1: %s\n", text);
}
}
void cb_air_pressure(int32_t air_pressure, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Air Press %7.2f mb", air_pressure / 1000.0);
lcd_20x4_write_line(&ws->lcd, 2, 0, text);
printf("Write to line 2: %s\n", text);
int16_t temperature;
int rc = barometer_get_chip_temperature(&ws->barometer, &temperature);
if(rc < 0) {
fprintf(stderr, "Could not get temperature: %d\n", rc);
return;
}
memset(text, '\0', sizeof(text));
// 0xDF == ° on LCD 20x4 charset.
sprintf(text, "Temperature %5.2f %cC", temperature / 100.0, 0xDF);
lcd_20x4_write_line(&ws->lcd, 3, 0, text);
sprintf(text, "Temperature %5.2f °C", temperature / 100.0);
printf("Write to line 3: %s\n", text);
}
}
void cb_air_pressure_v2(int32_t air_pressure, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(ws->lcd_created) {
char text[30] = {'\0'};
sprintf(text, "Air Press %7.2f mb", air_pressure / 1000.0);
lcd_20x4_write_line(&ws->lcd, 2, 0, text);
printf("Write to line 2: %s\n", text);
int32_t temperature;
int rc = barometer_v2_get_temperature(&ws->barometer, &temperature);
if(rc < 0) {
fprintf(stderr, "Could not get temperature: %d\n", rc);
return;
}
memset(text, '\0', sizeof(text));
// 0xDF == ° on LCD 20x4 charset.
sprintf(text, "Temperature %5.2f %cC", temperature / 100.0, 0xDF);
lcd_20x4_write_line(&ws->lcd, 3, 0, text);
sprintf(text, "Temperature %5.2f °C", temperature / 100.0);
printf("Write to line 3: %s\n", text);
}
}
void cb_connected(uint8_t connected_reason, void *user_data) {
WeatherStation *ws = (WeatherStation *)user_data;
if(connected_reason == IPCON_CONNECT_REASON_AUTO_RECONNECT) {
printf("Auto Reconnect\n");
while(true) {
int rc = ipcon_enumerate(&ws->ipcon);
if(rc < 0) {
fprintf(stderr, "Could not enumerate: %d\n", rc);
// TODO: sleep 1s.
continue;
}
break;
}
}
}
void cb_enumerate(const char *uid, const char *connected_uid,
char position, uint8_t hardware_version[3],
uint8_t firmware_version[3], uint16_t device_identifier,
uint8_t enumeration_type, void *user_data) {
int rc;
WeatherStation *ws = (WeatherStation *)user_data;
// Avoid unused parameter warning.
(void)position;
(void)connected_uid;
(void)hardware_version;
(void)firmware_version;
if(enumeration_type == IPCON_ENUMERATION_TYPE_CONNECTED ||
enumeration_type == IPCON_ENUMERATION_TYPE_AVAILABLE) {
if(device_identifier == LCD_20X4_DEVICE_IDENTIFIER) {
lcd_20x4_create(&ws->lcd, uid, &ws->ipcon);
lcd_20x4_clear_display(&ws->lcd);
lcd_20x4_backlight_on(&ws->lcd);
ws->lcd_created = true;
printf("LCD 20x4 initialized\n");
} else if(device_identifier == AMBIENT_LIGHT_DEVICE_IDENTIFIER) {
ambient_light_create(&ws->ambient_light, uid, &ws->ipcon);
ambient_light_register_callback(&ws->ambient_light,
AMBIENT_LIGHT_CALLBACK_ILLUMINANCE,
(void (*)(void))cb_illuminance,
(void *)ws);
rc = ambient_light_set_illuminance_callback_period(&ws->ambient_light, 1000);
if(rc < 0) {
fprintf(stderr, "Ambient Light init failed: %d\n", rc);
} else {
printf("Ambient Light initialized\n");
}
} else if(device_identifier == AMBIENT_LIGHT_V2_DEVICE_IDENTIFIER) {
ambient_light_v2_create(&ws->ambient_light_v2, uid, &ws->ipcon);
ambient_light_v2_register_callback(&ws->ambient_light_v2,
AMBIENT_LIGHT_V2_CALLBACK_ILLUMINANCE,
(void (*)(void))cb_illuminance_v2,
(void *)ws);
rc = ambient_light_v2_set_configuration(&ws->ambient_light_v2,
AMBIENT_LIGHT_V2_ILLUMINANCE_RANGE_64000LUX,
AMBIENT_LIGHT_V2_INTEGRATION_TIME_200MS);
if(rc < 0) {
fprintf(stderr, "Ambient Light 2.0 init step 1 failed: %d\n", rc);
} else {
rc = ambient_light_v2_set_illuminance_callback_period(&ws->ambient_light_v2, 1000);
if(rc < 0) {
fprintf(stderr, "Ambient Light 2.0 init step 2 failed: %d\n", rc);
} else {
printf("Ambient Light 2.0 initialized\n");
}
}
} else if(device_identifier == AMBIENT_LIGHT_V3_DEVICE_IDENTIFIER) {
ambient_light_v3_create(&ws->ambient_light_v3, uid, &ws->ipcon);
ambient_light_v3_register_callback(&ws->ambient_light_v3,
AMBIENT_LIGHT_V3_CALLBACK_ILLUMINANCE,
(void (*)(void))cb_illuminance_v3,
(void *)ws);
rc = ambient_light_v3_set_configuration(&ws->ambient_light_v3,
AMBIENT_LIGHT_V3_ILLUMINANCE_RANGE_64000LUX,
AMBIENT_LIGHT_V3_INTEGRATION_TIME_200MS);
if(rc < 0) {
fprintf(stderr, "Ambient Light 3.0 init step 1 failed: %d\n", rc);
} else {
rc = ambient_light_v3_set_illuminance_callback_configuration(&ws->ambient_light_v3, 1000, false, 'x', 0, 0);
if(rc < 0) {
fprintf(stderr, "Ambient Light 3.0 init step 2 failed: %d\n", rc);
} else {
printf("Ambient Light 3.0 initialized\n");
}
}
} else if(device_identifier == HUMIDITY_DEVICE_IDENTIFIER) {
humidity_create(&ws->humidity, uid, &ws->ipcon);
humidity_register_callback(&ws->humidity,
HUMIDITY_CALLBACK_HUMIDITY,
(void (*)(void))cb_humidity,
(void *)ws);
rc = humidity_set_humidity_callback_period(&ws->humidity, 1000);
if(rc < 0) {
fprintf(stderr, "Humidity init failed: %d\n", rc);
} else {
printf("Humidity initialized\n");
}
} else if(device_identifier == HUMIDITY_V2_DEVICE_IDENTIFIER) {
humidity_v2_create(&ws->humidity_v2, uid, &ws->ipcon);
humidity_v2_register_callback(&ws->humidity_v2,
HUMIDITY_V2_CALLBACK_HUMIDITY,
(void (*)(void))cb_humidity_v2,
(void *)ws);
rc = humidity_v2_set_humidity_callback_configuration(&ws->humidity_v2, 1000, true, 'x', 0, 0);
if(rc < 0) {
fprintf(stderr, "Humidity 2.0 init failed: %d\n", rc);
} else {
printf("Humidity 2.0 initialized\n");
}
} else if(device_identifier == BAROMETER_DEVICE_IDENTIFIER) {
barometer_create(&ws->barometer, uid, &ws->ipcon);
barometer_register_callback(&ws->barometer,
BAROMETER_CALLBACK_AIR_PRESSURE,
(void (*)(void))cb_air_pressure,
(void *)ws);
rc = barometer_set_air_pressure_callback_period(&ws->barometer, 1000);
if(rc < 0) {
fprintf(stderr, "Barometer init failed: %d\n", rc);
} else {
printf("Barometer initialized\n");
}
} else if(device_identifier == BAROMETER_V2_DEVICE_IDENTIFIER) {
barometer_v2_create(&ws->barometer, uid, &ws->ipcon);
barometer_v2_register_callback(&ws->barometer,
BAROMETER_V2_CALLBACK_AIR_PRESSURE,
(void (*)(void))cb_air_pressure_v2,
(void *)ws);
rc = barometer_v2_set_air_pressure_callback_configuration(&ws->barometer, 1000, false, 'x', 0, 0);
if(rc < 0) {
fprintf(stderr, "Barometer 2.0 init failed: %d\n", rc);
} else {
printf("Barometer 2.0 initialized\n");
}
}
}
}
int main() {
WeatherStation ws;
ws.lcd_created = false;
ipcon_create(&ws.ipcon);
while(true) {
int rc = ipcon_connect(&ws.ipcon, HOST, PORT);
if(rc < 0) {
fprintf(stderr, "Could not connect to brickd: %d\n", rc);
// TODO: sleep 1s
continue;
}
break;
}
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_ENUMERATE,
(void (*)(void))cb_enumerate,
(void *)&ws);
ipcon_register_callback(&ws.ipcon,
IPCON_CALLBACK_CONNECTED,
(void (*)(void))cb_connected,
(void *)&ws);
while(true) {
int rc = ipcon_enumerate(&ws.ipcon);
if(rc < 0) {
fprintf(stderr, "Could not enumerate: %d\n", rc);
// TODO: sleep 1s
continue;
}
break;
}
printf("Press key to exit\n");
getchar();
ipcon_destroy(&ws.ipcon);
return 0;
}