Main Content

このページは機械翻訳を使用して翻訳されました。最新版の英語を参照するには、ここをクリックします。

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) «Collect Data in a New Channel»に示すように、 ThingSpeakチャネルを作成します。新しいチャネルの書き込み API キーとチャネルID を記録します。

2) 「チャネル設定」ページに移動します。フィールドラベルを次のように設定します。

  • フィールド 1— Counter

  • フィールド 2— Soil Moisture

  • フィールド 3— Temperature F

3) 下部にある「チャネルを保存」をクリックして設定を保存します。

The Things Networkアプリケーションの構成

The Things Network«,» でアカウントを作成し、 The Things Network Consoleにログインします。

アプリケーションの作成

1) 「アプリケーション」を選択します。

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

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

デバイスを登録する

1) 《デバイス》タブをクリックし、デバイスを登録します。詳細については、 「 Device Registration 」を参照してください。

2) デバイスIDを作成します。デバイスにデバイス EUI がある場合は、デバイス EUI を入力します。そうでない場合は、«Device EUI» フィールドの左側にあるボタンを選択して、EUI を自動的に生成します。

3) 「登録」をクリックします。ブラウザは「概要」タブに戻ります。

4) 「設定」タブを選択します。

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

6) 「デバイス アドレス」、「ネットワーク セッション キー」、および「アプリ セッション キー」を記録します。この情報はデバイスコードに必要です。

ペイロード フォーマッタの作成

ペイロード フォーマッタは、ゲートウェイからアプリケーションに送信されたバイトを使用してメッセージを組み立てます。この例では、目的のペイロード メッセージは、 ThingSpeakに送信される JSON エンコードされたオブジェクトです。

1) 上部のナビゲーション メニューを使用してアプリケーション ビューに戻ります。次に、「ペイロード形式」タブをクリックします。

2) decoderインターフェイスで、デバイスから送信されたバイトをThingSpeakに書き込む JSON オブジェクトに変換するコードを作成します。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チャネルのページで確認できます。

デバイスの作成

センサーノードの作成に使用されるハードウェア

LoRaWan プロトコルをサポートするさまざまな LoRa デバイスを使用して、 The Things Networkに接続できます。この例では、次のハードウェア設定を使用した手順を示します。

回路図と接続

回路図に示すようにセンサーを接続します。写真は、プロジェクト ボックス内のセンサーの可能な構成を示しています。この構成では、ボックス内の温度センサーが外部温度を正確に反映しない可能性があります。LoRa 無線にadd an antennaする必要があります。

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 libraryをダウンロードするか、ライブラリ マネージャーにAdafruit_GPSライブラリを追加します。[Sketch > Include Library > Manage Librariesを選択します。Adafruit_GPSを検索して、インストールされているライブラリに追加します。

3) Arduino 環境用のLoraWan-in-C libraryをダウンロードするか、ライブラリ マネージャーに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); // Convet 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チャネルで詳細な視覚化ダッシュボードを作成する方法については、 Create Customized ThingSpeak Channel Viewを参照してください。