このページは機械翻訳を使用して翻訳されました。最新版の英語を参照するには、ここをクリックします。
The Things Networkで農業データを収集
この例では、LoRa® 無線を備えたマイクロプロセッサ ボードに接続された 3 つのセンサーからのデータ収集を設定する方法を示します。
この構成により、広いエリアに分散されたセンサーのネットワークを構築できます。センサーはデータをThe Things Networkに送信し、そのデータは解析と可視化のために ThingSpeak ™ に転送されます。この例では、プロトタイプデバイスを構築し、 The Things Networkに接続し、ThingSpeak を使用してデータ収集を統合します。ここに示すデバイスは、温度、土壌水分、GPS データを収集します。

概要
この例は 3 つの主要なステップで構成されています。The Things Network の統合は、さらにいくつかのサブステップに分かれています。最も複雑なステップはデバイスの構築です。例を完了するには、ThingSpeak アカウントとThe Things Networkのアカウントが必要です。ThingSpeak で、新しいチャネルを作成します。Things Network では、アプリケーションを作成し、デバイスを登録します。次に、ペイロード デコーダーを作成し、データを ThingSpeak に転送する統合を追加します。
1) データ収集用のThingSpeakチャネルを設定する
2) The Things Networkを設定する
アプリケーションを作成する
デバイスを登録する
ペイロード形式の作成
統合を追加
3) デバイスを作成する
センサーノードを作成するために使用されるハードウェア
回路図と接続
4) プログラムデバイス
プログラミングのセットアップ
コード
データ収集のためのThingSpeakチャネルの設定
1) 「新しいチャネルでデータを収集する」に示すように、ThingSpeakチャネルを作成します。新しいチャネルの書き込み API キーとチャネルID を記録します。
2) チャネル設定ページに移動します。フィールドラベルを次のように設定します。
フィールド1 —
Counterフィールド2—
Soil Moistureフィールド3 —
Temperature F
3) 下部にある チャネルを保存 をクリックして設定を保存します。
The Things Networkアプリケーションを構成する
The Things Network でアカウントを作成し、 The Things Networkコンソール にログインします。
アプリケーションを作成する
1) アプリケーションを選択します。

2) アプリケーションの追加を選択します。

3) アプリケーション ID を作成し、説明 を追加します。あなたの所在地に基づいてハンドラー登録を選択します。

デバイスを登録する
1) Devices タブをクリックしてデバイスを登録します。詳細については、「デバイス登録」を参照してください。
2) デバイスIDを作成します。デバイスにデバイス EUI がある場合はそれを入力します。そうでない場合は、デバイス EUI フィールドの左側にあるボタンを選択して、EUI を自動的に生成します。

3) 登録をクリックします。ブラウザは 概要 タブに戻ります。
4) 設定タブを選択します。

5) 設定で、アクティベーション方法として ABP を選択します。デバッグを容易にするために、オプションでページの下部にある フレーム カウンター チェック を無効にすることができます。

6) デバイス アドレス、ネットワーク セッション キー、アプリ セッション キー を記録します。この情報はデバイス コードに必要です。
ペイロードフォーマッタを作成する
ペイロード フォーマッタは、ゲートウェイからアプリケーションに送信されたバイトを使用してメッセージを組み立てます。この例では、目的のペイロード メッセージは、ThingSpeak に送信される JSON エンコードされたオブジェクトです。
1) 上部のナビゲーション メニューを使用してアプリケーション ビューに戻ります。次に、ペイロード形式タブをクリックします。

2) decoder インターフェースで、デバイスから送信されたバイトを JSON オブジェクトに変換して ThingSpeak に書き込むコードを作成します。lat および lon の条件コードは、正または負の値の可能性を処理します。
function Decoder(b, port) {
var counter = b[0] << 8) | b[1];
var moisture = b[2] | b[3] << 8;
var temp= ( b[4] | b[5] << 8 )/100;
var lat = ( b[6] | b[7] << 8 | b[8] << 16 | (b[8] & 0x80 ? 0xFF << 24 : 0)) / 10000;
var lon = ( b[9] | b[10] << 8 | b[11] << 16 | (b[11] & 0x80 ? 0xFF << 24 : 0)) / 10000;
return {
field1: counter,
field2: moisture,
field3: temp,
latitude: lat,
longitude: lon
}
}
統合を追加
ThingSpeak にデータを転送するには、登録済みのデバイスとペイロード フォーマッタを備えた Things Network 上のアプリケーションが必要です。データを転送するための ThingSpeak 統合を作成します。
1) The Things Network Console にログインします。
2) アプリケーション を選択し、ThingSpeak にデータを転送するアプリケーションを選択します。

3) 統合タブをクリックします。

4) ThingSpeakを選択します。

5) 「プロセス ID」フィールドで、統合に名前を付けます。
6) 「承認」フィールドに、データを保存するチャネルの書き込み API キーを入力します。API キーは、ThingSpeakチャネルの API キー タブから入手できます。
7) 「チャネルID」フィールドに、データを転送する ThingSpeakチャネルのチャネルID を入力します。チャネルID は、ThingSpeak チャンネルのページで確認できます。

デバイスを作成
センサーノードを作成するために使用されるハードウェア
The Things Networkに接続するために、LoRaWan プロトコルをサポートするさまざまな LoRa デバイスを使用できます。この例では、次のハードウェア設定を使用した手順を示します。
アダフルーツ フェザー M0
Adafruit Ultimate GPS FeatherWing
土壌モニター(例:Sparkfun Moisture Sensor SEN 13322)
DHT22
ヘッダーとワイヤー
GPSアンテナ W14Q5A-y
トグルスイッチ
LiPoバッテリー 500mAh
回路図と接続
回路図に示すようにセンサーを接続します。写真は、プロジェクト ボックス内のセンサーの可能な構成を示しています。この構成では、ボックス内の温度センサーが外気温を正確に反映しない可能性があります。LoRa 無線に アンテナを追加する必要があります。
1) GPS センサーと温度センサーの電源とアースを接続します。湿度センサーに電源を接続しないでください。
2) 土壌水分センサーの出力を A0 のアナログ入力に接続します。
3) 使用していないときは湿度センサーの電源がオフになるようにシステムを設定します。湿度センサーの電源ピンは、フェザー M0 の GPIO ピン 11 に接続されています。使用していないときに電源をオフにすると、センサーの寿命が延びます。
4) DH-22 センサー データ ピンを Feather M0 の PA-15 (Arduino® スケッチのピン 5) に接続します。
5) GPS ボードの場合、Feather M0 の TX を RX に接続し、RX を TX に接続します。
6) Feather M0 の PA20 (ピン 29、GPIO 6) をグランドに接続して、LoRa 無線を有効にします。
7) En ピンからグランドにスイッチを接続して電源スイッチを作成します。


プログラムデバイス
プログラミングのセットアップ
1) 最新の Arduino IDE をダウンロードします。
2) Adafruit GPS ライブラリ をダウンロードするか、ライブラリ マネージャーで Adafruit_GPS ライブラリを追加します。Sketch > Include Library > Manage Libraries を選択します。Adafruit_GPS を検索して、インストールしたライブラリに追加します。
3) Arduino 環境用の LoraWan-in-C ライブラリ をダウンロードするか、ライブラリ マネージャーで lmic ライブラリと hal/hal ライブラリを追加します。Sketch > Include Library > Manage Libraries を選択します。lmic を検索し、MCCI LoRaWAN LMIC library を選択して、インストールしたライブラリに追加します。MCCI Arduino LoRaWan Library to the library manager も追加します。
4) アプリケーションを作成します。Arduino IDE で新しいウィンドウを開き、ファイルを保存します。コードセクションで提供されているコードを追加します。
コード
1) まず、適切なライブラリをインクルードし、変数を初期化します。
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include "DHT.h"
#include <Adafruit_GPS.h>
#define DHTPIN 5
#define GPSSerial Serial1
#define SOIL_PIN 14
#define SOIL_POWER_PIN 11
#define GPSECHO false // Set to 'true' if you want to debug and listen to the raw GPS sentences
#define PAYLOAD_SIZE 13 // Number of bytes sent plus 2
// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = {0x98, 0xEB, 0x1A, 0xC5, 0xF9, 0x20, 0x15, 0xCD, 0x12, 0xE5, 0x72, 0xFF, 0xCD, 0xE2, 0x94, 0x46};
// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = {0x50, 0x28, 0x4D, 0xAE, 0xEA, 0x41, 0x53, 0x7E, 0xCA, 0x70, 0xD2, 0x26, 0xCC, 0x14, 0x66, 0x19};
// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x26021115;
// Callbacks are only used in over-the-air activation. Leave these variables empty unless you use over the air activation.
void os_getArtEui(u1_t *buf) {}
void os_getDevEui(u1_t *buf) {}
void os_getDevKey(u1_t *buf) {}
// Payload to send to TTN gateway
static uint8_t payload[PAYLOAD_SIZE];
static osjob_t sendjob;
// Schedule TX at least this many seconds
const unsigned TX_INTERVAL = 60; //was 30
// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
.nss = 8,
.rxtx = LMIC_UNUSED_PIN,
.rst = 4,
.dio = {3, 6, LMIC_UNUSED_PIN},
.rxtx_rx_active = 0,
.rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB.
.spi_freq = 8000000,
};
Adafruit_GPS GPS(&GPSSerial); // Connect to the GPS on the hardware port.
DHT dht(DHTPIN, DHT22); // Connect to the temperature sensor.
uint16_t counter = 0;
int32_t myLatitude = -12345; // Initialize for testing before GPS finds a lock.
int32_t myLongitude = 54321; // Initialize for testing.
int myMoisture = 0; // 10 bit ADC value.
float temperatureF = 1111;
2) setup 関数を使用して、温度センサー、GPS、LoRa 無線を起動します。
void setup()
{
Serial.begin(115200);
dht.begin();
Serial.println("Start");
// Set the power pin for the moisture sensor
pinMode(SOIL_POWER_PIN,OUTPUT);
digitalWrite(SOIL_POWER_PIN, LOW);
GPS.begin(9600); // 9600 NMEA is the default baud rate.
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // Set a 1 Hz update rate.
delay(1000); // Wait for GPS to initialize.
// Ask for firmware version
GPSSerial.println(PMTK_Q_RELEASE);
// Initialize the LMIC.
os_init();
// Reset the MAC state. Resetting discards the session and pending data transfers.
LMIC_reset();
// Set static session parameters.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession(0x13, DEVADDR, nwkskey, appskey);
LMIC_selectSubBand(1);
// Only use the correct The Things Network channels, disable the others.
for (int c = 0; c < 72; c++)
{
if ((c < 8) || (c > 15))
{
LMIC_disableChannel(c);
}
}
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF7, 14);
// Start job.
processJob(&sendjob);
}
3) loop 関数を使用して LoRa プロセスを開始し、GPS データを解析します。
void loop() // Run over and over again
{
os_runloop_once();
char c = GPS.read();
if (GPSECHO)
{
if (c){
Serial.print(c);
}
}
// If a sentence is received, parse it
if (GPS.newNMEAreceived())
{
if (!GPS.parse(GPS.lastNMEA())) // Also sets the newNMEAreceived() flag to false
return;
}
}
4) GetSensorData 関数は、水分センサーの電源をオンにしてデータを読み取り、その後電源をオフにします。また、温度センサーを読み取り、GPS デバイスからの情報を確認します。GPS の位置が判明した場合、この機能は位置情報を更新します。
void GetSensorData()
{
digitalWrite(SOIL_POWER_PIN, HIGH);
delay(1000);
myMoisture = analogRead(SOIL_PIN);
digitalWrite(SOIL_POWER_PIN, LOW);
temperatureF = dht.readTemperature( true );
Serial.println("moisture " + String( myMoisture ) + " temp " + String( temperatureF ));
if (GPS.fix)
{
Serial.print( "Location: " );
Serial.print( GPS.latitudeDegrees * 100, 4 );
Serial.print( " break " );
Serial.print( GPS.lat );
Serial.print( ", " );
Serial.print( GPS.longitudeDegrees * 100 , 4 );
Serial.println( GPS.lon );
myLatitude = GPS.latitudeDegrees * 10000;
myLongitude = GPS.longitudeDegrees * 10000;
}
}
5) onEvent 関数を使用して、LoRa 無線からのイベントを処理します。この関数は、シリアル モニターを更新し、次の送信をスケジュールし、メッセージを受信します。
void onEvent(ev_t ev)
{
Serial.print(os_getTime());
Serial.print(": ");
switch (ev)
{
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen)
{
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned)ev);
break;
}
}
6) processJob 関数は、センサー データを LoRa 無線経由で送信されるビットに変換します。
void processJob(osjob_t *j)
{
getSensorData();
if (LMIC.opmode & OP_TXRXPEND) // Check if there is a current TX/RX job running.
{
Serial.println(F("OP_TXRXPEND, not sending"));
}
else
{
payload[0] = byte(counter);
payload[1] = counter >>8;
payload[2] = byte(myMoisture);
payload[3] = myMoisture >> 8;
int shiftTemp = int(temperatureF * 100); // Convert temperature float to integer for sending and save two places.
payload[4] = byte(shiftTemp);
payload[5] = shiftTemp >> 8;
payload[6] = byte(myLatitude);
payload[7] = myLatitude >> 8;
payload[8] = myLatitude >> 16;
payload[9] = byte(myLongitude);
payload[10] = myLongitude >> 8;
payload[11] = myLongitude >> 16;
LMIC_setTxData2(1, payload, sizeof(payload) - 1, 0); // Prepare upstream data transmission at the next possible time.
counter++;
Serial.println(String(counter));
}
// Next TX is scheduled after TX_COMPLETE event.
ThingSpeakチャネルで詳細な可視化ダッシュボードを作成する方法については、「カスタマイズされた ThingSpeakチャネルビューを作成する」を参照してください。