Real-time Omgevingsmonitoring met Arduino MKR1000 & Environment Click Sensoren
Onderdelen en Benodigdheden
| Onderdeel | Aantal |
|---|---|
| Arduino MKR1000 | 1 |
| MikroE Environment Click | 1 |
Benodigde Tools en Machines
- Adafruit Female/Female Jumper Draadjes
Apps en Online Services
- Arduino IDE
- WolkAbout IoT Platform
Over dit Project
Inleiding
We hadden enkele Environment Click sensoren liggen, dus we besloten ze aan de Arduino MKR1000 te koppelen en de data te visualiseren op het WolkAbout IoT Platform. Het idee was om elke minuut een meting te doen en de resultaten elke 15 minuten te publiceren. Als het publiceren mislukt (door een drukke netwerk of ander probleem), worden de resultaten bewaard in het Flash-geheugen van het apparaat. Met een potentiële maximum van 96 schrijfoperaties per dag, minimaliseren we de kans op een verkeerde toestand van het Flash-geheugen (Arduino garandeert 10.000 schrijfcycli).
Hardware Setup
De Environment Click sensor is aangesloten op de I2C-communicatiepinnen (naamelijk 11 en 12 op de MKR1000), Vcc en ground.
Software Setup
We gebruikten een paar bibliotheken, allemaal installeerbaar via Arduino IDE's Library Manager of als .zip van de GitHub repositories in de bijlagen:
- WiFi101
- Adafruit Unified Sensor Driver
- Adafruit BME680 Library
- RTCZero
- FlashStorage
- WolkConnect
Na installatie van alle benodigde bibliotheken, kopieer de inhoud van de Environment monitoring sketch uit de bijlagen naar Arduino IDE.
De sketch implementeert een circulair buffer-structuur om meetresultaten op te slaan. Er is ook een implementatie om die structuur in Flash-geheugen op te slaan met de FlashStorage bibliotheek. Tijdgebaseerde lezing en publicatie van data worden gerealiseerd met de RTCZero bibliotheek. Initieel, na verbinding met WiFi, sturen we een ping naar WolkAbout IoT Platform om de huidige epoch te krijgen die in de RTC bibliotheek wordt geladen zodat sensormetingen correct getimestamped kunnen worden.
Een alarm-interrupt verandert vlaggen voor taken die gedaan moeten worden (lezen en publiceren) en de rest wordt in de loop-functie afgehandeld. We checken of we moeten lezen of publiceren. Voor minimaal stroomverbruik staat WiFi in low-power mode, net als de MKR1000. De sensor op de Environment Click gaat automatisch in low-power modus totdat een meting wordt aangevraagd.
Aanpassingen in de sketch:
- WiFi credentials op regel 33 en 34:
const char* ssid = "<*YOUR SSID*>"; const char* wifi_pass = "<*YOUR WIFI PASSWORD*>"; - Apparaatcredentials van WolkAbout IoT Platform.
Om deze credentials te krijgen, moet je eerst een apparaat aanmaken met een apparaattype. Het apparaattype voor dit project, Environment click-deviceType.json, is beschikbaar in de projectbijlagen. Maak een kopie. Log in of maak een account aan op WolkAbout IoT Platform en open de Device Management applicatie.
- Selecteer tab Device Type Management en druk op + > Upload, navigeer naar je lokale kopie van het apparaattype.
- Nu het apparaattype beschikbaar is, maak een apparaat aan via Create device.
- Geef je apparaat een naam, zet Connectivity Type op MQTT en vink Create Default Semantic aan (noodzakelijk voor widgets op je dashboard).
- Druk Save. Het formulier met apparaatcredentials wordt getoond. Bewaar deze en vul ze in je sketch in Arduino IDE:
const char *device_key = "device_key"; const char *device_password = "device_password";
Nu kun je de sketch verifiëren en uploaden naar je bord. Je hebt nog een manier nodig om de ontvangen sensordata weer te geven.
Ga naar Visualisation and Monitoring op WolkAbout IoT Platform en maak een nieuw dashboard aan via + Add dashboard. Geef een naam en stel de scope in op de apparaatnaam. Voeg widgets toe via Add widget.
- Selecteer Trending > Temperature van je apparaat.
- Herhaal voor Pressure en Humidity.
- Maak een widget type Reading voor Altitude.
- Maak een kaart-widget voor Gas Resistance.
- Rangschik widgets naar wens.
Na het toevoegen van widgets voor alle verwachte sensorwaarden is het dashboard klaar om data van je apparaat te ontvangen. Implementeer het apparaat in de gekozen omgeving en monitor de omstandigheden op afstand.
Conclusie
Door Arduino MKR1000 en Environment Click te koppelen aan WolkAbout IoT Platform, creëer je een energiezuinige manier om de omgevingsomstandigheden van de gewenste locatie op afstand te monitoren. Deze oplossing kan uitgebreid worden via de regel-engine van WolkAbout IoT Platform, waarmee je verschillende typen notificaties kunt ontvangen als een waarde een door jou gedefinieerde drempel overschrijdt.
Voor meer informatie over de regel-engine en andere WolkAbout IoT Platform features, bezoek de User Guides pagina.
Code
Environment Monitoring Sketch (Arduino)
Importeer deze sketch in Arduino IDE en bewerk de WiFi credentials en apparaatcredentials.
#include
#include
#include
#include
#include
#include
#include
#include "WolkConn.h"
#include "MQTTClient.h"
#define STORAGE_SIZE 32
#define SEALEVELPRESSURE_HPA (1013.25)
typedef struct {
boolean valid;
outbound_message_t outbound_messages[STORAGE_SIZE];
uint32_t head;
uint32_t tail;
boolean empty;
boolean full;
} Messages;
static Messages data;
const char* ssid = "ssid";
const char* wifi_pass = "wifi_pass";
const char *device_key = "device_key";
const char *device_password = "device_password";
const char* hostname = "api-demo.wolkabout.com";
int portno = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
static wolk_ctx_t wolk;
FlashStorage(flash_store, Messages);
Adafruit_BME680 bme;
RTCZero rtc;
bool read;
const byte readEvery = 1;
bool publish;
const byte publishEvery = 10;
byte publishMin;
void _flash_store() {
data.valid = true;
flash_store.write(data);
}
void increase_pointer(uint32_t* pointer) {
if ((*pointer) == (STORAGE_SIZE - 1)) (*pointer) = 0;
else (*pointer)++;
}
void _init() {
data = flash_store.read();
if (data.valid == false) {
data.head = 0; data.tail = 0; data.empty = true; data.full = false;
}
}
bool _push(outbound_message_t* outbound_message) {
if (data.full) increase_pointer(&data.head);
memcpy(&data.outbound_messages[data.tail], outbound_message, sizeof(outbound_message_t));
increase_pointer(&data.tail);
data.empty = false;
data.full = (data.tail == data.head);
return true;
}
bool _peek(outbound_message_t* outbound_message) {
memcpy(outbound_message, &data.outbound_messages[data.head], sizeof(outbound_message_t));
return true;
}
bool _pop(outbound_message_t* outbound_message) {
memcpy(outbound_message, &data.outbound_messages[data.head], sizeof(outbound_message_t));
increase_pointer(&data.head);
data.full = false;
data.empty = (data.tail == data.head);
return true;
}
bool _is_empty() { return data.empty; }
void init_wifi() {
if (WiFi.status() != WL_CONNECTED) {
while (WiFi.begin(ssid, wifi_pass) != WL_CONNECTED) delay(1000);
}
}
void setup_wifi() {
delay(10);
if (WiFi.status() != WL_CONNECTED) {
int numAttempts = 0;
while (WiFi.begin(ssid, wifi_pass) != WL_CONNECTED) {
numAttempts++;
if (numAttempts == 10) { Serial.println("Couldn't reach WiFi!"); break; }
delay(1000);
}
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
_init();
init_wifi();
wolk_init(&wolk, NULL, NULL, NULL, NULL, device_key, device_password, &client, hostname, portno, PROTOCOL_JSON_SINGLE, NULL, NULL);
wolk_init_custom_persistence(&wolk, _push, _peek, _pop, _is_empty);
if (!bme.begin()) digitalWrite(LED_BUILTIN, HIGH);
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150);
delay(200);
read = true; publish = true;
wolk_connect(&wolk);
delay(100);
wolk_update_epoch(&wolk);
while (!(wolk.pong_received)) { wolk_process(&wolk); digitalWrite(LED_BUILTIN, HIGH); delay(1000); }
digitalWrite(LED_BUILTIN, LOW);
wolk_disconnect(&wolk);
rtc.begin();
rtc.setEpoch(wolk.epoch_time);
rtc.setAlarmTime(rtc.getHours(), (rtc.getMinutes() + readEvery) % 60, rtc.getSeconds());
rtc.enableAlarm(rtc.MATCH_MMSS);
rtc.attachInterrupt(alarmMatch);
publishMin = (rtc.getMinutes() + publishEvery) % 60;
WiFi.lowPowerMode();
}
void loop() {
if (read) {
read = false;
if (!bme.performReading()) digitalWrite(LED_BUILTIN, HIGH);
wolk_add_numeric_sensor_reading(&wolk, "T", bme.temperature, rtc.getEpoch());
wolk_add_numeric_sensor_reading(&wolk, "H", bme.humidity, rtc.getEpoch());
wolk_add_numeric_sensor_reading(&wolk, "P", bme.pressure / 100.0, rtc.getEpoch());
wolk_add_numeric_sensor_reading(&wolk, "GR", bme.gas_resistance, rtc.getEpoch());
wolk_add_numeric_sensor_reading(&wolk, "A", bme.readAltitude(SEALEVELPRESSURE_HPA), rtc.getEpoch());
int alarmMin = (rtc.getMinutes() + readEvery) % 60;
rtc.setAlarmMinutes(alarmMin);
delay(100);
}
if (publish) {
publish = false;
setup_wifi();
wolk_connect(&wolk);
if (!wolk.is_connected) _flash_store();
delay(100);
if (wolk_publish(&wolk) == W_TRUE) _flash_store();
publishMin = (rtc.getMinutes() + publishEvery) % 60;
delay(100);
wolk_disconnect(&wolk);
delay(100);
}
delay(100);
}
void alarmMatch() {
read = true;
if (publishMin == rtc.getMinutes()) publish = true;
}
Environment click-deviceType.json (JSON)
Apparaattype om een apparaat aan te maken op WolkAbout IoT Platform.
[
{
"name": "Environment click",
"description": "Device type for the BME680 sensor on MikroElektronika's board Environment Click",
"guid": "def68ff6-63c5-4f9c-a066-bcc944b7bd2d",
"deviceType": "STANDARD",
"protocol": "JSON",
"connectivityType": null,
"firmwareUpdateType": null,
"feeds": [
{ "name": "Temperature", "description": null, "reference": "T", "unit": { "name": "CELSIUS", "guid": "7c805d10-a879-11e9-83cd-0a0027000005" } },
{ "name": "Humidity", "description": null, "reference": "H", "unit": { "name": "HUMIDITY_PERCENT", "guid": "7c8080a3-a879-11e9-83cd-0a0027000005" } },
{ "name": "Pressure", "description": null, "reference": "P", "unit": { "name": "MILLIBAR", "guid": "7c807980-a879-11e9-83cd-0a0027000005" } },
{ "name": "Gas Resistance", "description": null, "reference": "GR", "unit": { "name": "OHM", "guid": "7c805890-a879-11e9-83cd-0a0027000005" } },
{ "name": "Altitude", "description": null, "reference": "A", "unit": { "name": "METRE", "guid": "7c805a59-a879-11e9-83cd-0a0027000005" } }
],
"actuators": [],
"alarms": [],
"configs": [],
"attributes": [
{ "name": "CONNECTIVITY_TYPE", "dataType": "ENUM", "validationRegex": "^(MQTT|HTTP)$", "options": ["MQTT", "HTTP"], "defaultValue": "MQTT", "required": true, "readOnly": true },
{ "name": "FIRMWARE_UPDATE_ENABLED", "dataType": "BOOLEAN", "validationRegex": "^(true|false)$", "options": null, "defaultValue": null, "required": false, "readOnly": true },
{ "name": "FIRMWARE_VERSION", "dataType": "STRING", "validationRegex": null, "options": null, "defaultValue": null, "required": false, "readOnly": true },
{ "name": "FILE_DIRECT_DOWNLOAD_ENABLED", "dataType": "BOOLEAN", "validationRegex": "^(true|false)$", "options": null, "defaultValue": null, "required": false, "readOnly": true },
{ "name": "FILE_URL_DOWNLOAD_ENABLED", "dataType": "BOOLEAN", "validationRegex": "^(true|false)$", "options": null, "defaultValue": null, "required": false, "readOnly": true }
]
}
]
Nuttige Links
- WolkAbout Environment Monitoring Repository – Bevat de Arduino sketch van dit project.
- Arduino WiFi 101 Shield Library
- Adafruit Unified Sensor Driver
- Adafruit BME680 Library
- RTC Library voor Arduino
- FlashStorage Library voor Arduino
- WolkConnect-Arduino Library
Schema
Zie het schakelschema voor de verbinding tussen Arduino MKR1000 en Environment Click sensor.
Productieproces
- Bluetooth-gecontroleerde Arduino Spybot bouwen
- K30 CO2-sensor: Real-time binnenluchtkwaliteitmonitoring met Arduino
- FlickMote: Gebarengecontroleerde IR-afstandsbediening voor Slimme Huizen
- DIY Arduino TV-B-Gone: Universele TV-uit-schakelaar
- Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
- Find Me: Slimme Item Locator met Arduino en Bluetooth
- Geoptimaliseerde Voedingsoplossingen voor Arduino Projecten
- Arduino Boter-Kaas-Eieren met MAX7219 LED Matrix en Kartonnen Behuizing
- Bouw een Slimme Arduino Vierpotige Robot: Stap-voor-Stap Handleiding
- Contactloze temperatuurgate voor snelle, accurate screening
- Real-time Bosbrandbewakingssysteem met SMS-alarmen