Arduino MKR1000 & Environment Click で実現するリアルタイム環境モニタリング
必要な部品と材料
- Arduino MKR1000 × 1
- MikroE Environment Click (BME680搭載) × 1
必要な工具
- Adafruit メス-メス ジャンパーワイヤー
使用するアプリとオンラインサービス
- Arduino IDE
- WolkAbout IoT Platform
プロジェクト概要
Environment Clickセンサー (温度・湿度・気圧・ガス抵抗・高度) をArduino MKR1000に接続し、WolkAbout IoT Platformで可視化するプロジェクト。1分ごとに測定、15分ごとに送信。送信失敗時はフラッシュメモリに蓄積 (最大96回/日、書き込み寿命10,000回を考慮) し、次回送信時にリトライする堅牢な設計です。
ハードウェア接続
Environment ClickをI2Cピン (MKR1000の11=SDA, 12=SCL)、VCC、GNDに接続するだけ。
ソフトウェア構成
以下のライブラリをArduino IDEのライブラリマネージャーからインストール、またはGitHubからZIPダウンロードして追加:
- WiFi101
- Adafruit Unified Sensor Driver
- Adafruit BME680 Library
- RTCZero
- FlashStorage
- WolkConnect
スケッチの主な機能:
- 循環バッファ構造で送信待ちデータを管理
- FlashStorageライブラリで不揮発性保存
- RTCZeroで定期実行 (測定・送信スケジュール)
- 起動時にWolkAboutへPing送信し、現在エポック時刻を取得してRTCに設定
- 割り込みでフラグ制御、メインループで実処理実行
- WiFi低電力モード、MKR1000低電力モード、センサー自動スリープで省電力化
スケッチ修正箇所
// WiFi認証情報 (33-34行目)
const char* ssid = "<*YOUR SSID*>";
const char* wifi_pass = "<*YOUR WIFI PASSWORD*>";
// WolkAboutデバイス認証情報
const char *device_key = "device_key";
const char *device_password = "device_password";
WolkAbout IoT Platformでのデバイス作成
- 添付の
Environment click-deviceType.jsonをダウンロード - WolkAboutにログインし、デバイス管理 > デバイスタイプ管理 で「アップロード」からJSONをインポート
- デバイス作成: 名前入力、接続タイプ MQTT、デフォルトセマンティック作成 にチェック
- 表示されるデバイスキー・パスワードをスケッチに入力
ダッシュボード作成
- 可視化と監視 > ダッシュボード追加 で新規作成、スコープをデバイス名に設定
- ウィジェット追加: トレンド で温度・湿度・気圧、リーディング で高度、カード でガス抵抗
- レイアウト調整して完成
結論
MKR1000 + Environment Click + WolkAboutで、省電力・堅牢なリモート環境モニタリングが実現できます。WolkAboutのルールエンジンを使えば、閾値超過時の通知 (メール、SMS、Webhook等) もノーコードで設定可能です。詳細は ユーザーガイド を参照。
コード
Environment monitoring sketch (Arduino)
#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; // 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) {
data.head = 0; data.tail = 0; data.empty = true; data.full = false;
}
}
bool _push(outbound_message_t* msg) {
if (data.full) increase_pointer(&data.head);
memcpy(&data.outbound_messages[data.tail], msg, sizeof(outbound_message_t));
increase_pointer(&data.tail);
data.empty = false;
data.full = (data.tail == data.head);
return true;
}
bool _peek(outbound_message_t* msg) {
memcpy(msg, &data.outbound_messages[data.head], sizeof(outbound_message_t));
return true;
}
bool _pop(outbound_message_t* msg) {
memcpy(msg, &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) {
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
[
{
"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", "reference": "T", "unit": { "name": "CELSIUS", "guid": "..." } },
{ "name": "Humidity", "reference": "H", "unit": { "name": "HUMIDITY_PERCENT", "guid": "..." } },
{ "name": "Pressure", "reference": "P", "unit": { "name": "MILLIBAR", "guid": "..." } },
{ "name": "Gas Resistance", "reference": "GR", "unit": { "name": "OHM", "guid": "..." } },
{ "name": "Altitude", "reference": "A", "unit": { "name": "METRE", "guid": "..." } }
],
"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 }
]
}
]
関連リポジトリ・ライブラリ
- WolkAbout Environment Monitoring (スケッチ本体)
- Arduino WiFi101 Shield
- Adafruit Unified Sensor Driver
- Adafruit BME680 Library
- RTC Library for Arduino (SAMD21)
- FlashStorage library
- WolkConnect-Arduino
回路図

製造プロセス
- Bluetooth操作のArduinoスパイボットを自作する
- K30 CO2センサで室内空気質をリアルタイム監視する
- FlickMote:ジェスチャー操作のIRリモコンでスマートホームを制御
- 自作Arduino TV-B-Gone:全テレビ対応の万能リモコン
- 12メートル先から見える大型LEDマスタークロック(アラーム機能付き)を自作しよう
- ArduinoとBluetoothで作るスマート紛失防止タグ「Find Me」
- Arduinoプロジェクトのための最適化電源ソリューション
- Arduino三目並べ:MAX7219 LEDマトリクスと段ボールケースで自作
- スマートArduino四足歩行ロボットの製作:ステップバイステップガイド
- 非接触温度スクリーニングゲート:Arduino MKR1000で迅速・高精度な検温
- リアルタイム森林火災監視システム: SMSアラート機能付き