2020/08/24
[第6回]温度・湿度センサーの情報をThingSpeakにアップロードしてみよう
概要
前回は、センサー情報のアップロード先であるThingSpeakの設定を行いました。
今回は、前回までの総まとめになります。以下のような内容を実施します。
- DHT11(温度・湿度センサー)とLoRa Mini Devを繋ぎます
- LoRa Mini DevからLoRa通信を使って、LG01にデータを送信します
- LG01はデータを受信すると、ThingSpeakにデータをアップするサーバーとして動作させます
LoRa Clientの設定
DHT11とLoRa Mini Devの接続
以下のようにして端子を合わせて接続します。
LoRa Mini Dev 端子 | DHT 11端子 |
---|---|
3.3V | VCC |
GND | GND |
A0 | DATA |
Arduino IDEの設定
- Arduino IDEを立ち上げます
プログラムを書くまえに、必要なライブラリをインストールしておく必要があります。
ライブラリ名 | 用途 | インストール方法 |
---|---|---|
ThingSpeak | ThingSpeakアップロード用のライブラリ | ライブラリマネージャーからインストール |
DHT sensor library | DHT操作用のライブラリ | ライブラリマネージャーからインストール |
Adafruit Unified Sensor required | DHTライブラリが使うライブラリ | DHT sensor libraryをインストールすると、自動でインストールできる |
RadioHead | LoRa通信用のライブラリ | https://github.com/dragino/RadioHead/archive/master.zipをダウンロード&解凍して、Arduino IDEのlibrariesフォルダに格納 |
※ RadioHead については、第4回で既にインストール済なので、他のライブラリがインストールされていなければ
このタイミングでインストールする必要があります。
温度・湿度送信プログラムのデプロイ
- Arduino IDEを立ち上げます
- ボードを
Arduino Uno
を選択します - ポートを LoRa Mini Devが繋がれた、USBのポート (画像では、
/dev/cu.usbserial-14430
)を選択します
選択できたら、以下のプログラムを使います。
/*
Upload Data to IoT Server ThingSpeak (https://thingspeak.com/):
Support Devices: LoRa Shield + Arduino
Example sketch showing how to read Temperature and Humidity from DHT11 sensor,
Then send the value to LoRa Server, the LoRa Server will send the value to the
IoT server
It is designed to work with the other sketch dht11_server.
modified 24 11 2016
by Edwin Chen <[email protected]>
Dragino Technology Co., Limited
*/
#include <SPI.h>
#include <RH_RF95.h>
#include <String.h>
#include "DHT.h"
RH_RF95 rf95;
#define dht_dpin A0 // Use A0 pin as Data pin for DHT11.
#define DHTTYPE DHT11 // DHT 11
byte bGlobalErr;
char dht_dat[5]; // Store Sensor Data
String stringOne;
float frequency = 923.6;
//float frequency = 868.0;
DHT dht(dht_dpin, DHTTYPE);
void setup()
{
Serial.begin(9600);
while(!Serial);
if (!rf95.init())
Serial.println("init failed");
// Setup ISM frequency
rf95.setFrequency(frequency);
// Setup Power,dBm
rf95.setTxPower(13);
// キャリアセンス
rf95.setCADTimeout((unsigned long)5);
dht.begin();
Serial.println("Humidity and temperature\n\n");
}
uint16_t calcByte(uint16_t crc, uint8_t b)
{
uint32_t i;
crc = crc ^ (uint32_t)b << 8;
for ( i = 0; i < 8; i++)
{
if ((crc & 0x8000) == 0x8000)
crc = crc << 1 ^ 0x1021;
else
crc = crc << 1;
}
return crc & 0xffff;
}
uint16_t CRC16(uint8_t *pBuffer,uint32_t length)
{
uint16_t wCRC16=0;
uint32_t i;
if (( pBuffer==0 )||( length==0 ))
{
return 0;
}
for ( i = 0; i < length; i++)
{
wCRC16 = calcByte(wCRC16, pBuffer[i]);
}
return wCRC16;
}
void loop()
{
float h = dht.readHumidity();
float t = dht.readTemperature();
char data[50] = {0} ;
// Use data[0], data[1],data[2] as Node ID
data[0] = 1 ;
data[1] = 1 ;
data[2] = 1 ;
data[3] = h ;//dht_dat[0];//Get Humidity
data[4] = t ;//dht_dat[2];//Get Temperature
//data[3] = (int)random(0, 100);//
//data[4] = (int)random(10, 30);//
switch (bGlobalErr)
{
case 0:
Serial.print("Current humdity = ");
Serial.print(data[3], DEC);//Show humidity
Serial.print(".");
Serial.print(dht_dat[1], DEC);//Show humidity
Serial.print("% ");
Serial.print("temperature = ");
Serial.print(data[4], DEC);//Show temperature
Serial.print(".");
Serial.print(dht_dat[3], DEC);//Show temperature
Serial.println("C ");
break;
case 1:
Serial.println("Error 1: DHT start condition 1 not met.");
break;
case 2:
Serial.println("Error 2: DHT start condition 2 not met.");
break;
case 3:
Serial.println("Error 3: DHT checksum error.");
break;
default:
Serial.println("Error: Unrecognized code encountered.");
break;
}
int dataLength = strlen(data);//CRC length for LoRa Data
//Serial.println(dataLength);
uint16_t crcData = CRC16((unsigned char*)data,dataLength);//get CRC DATA
//Serial.println(crcData);
unsigned char sendBuf[50]={0};
int i;
for(i = 0;i < 8;i++)
{
sendBuf[i] = data[i] ;
}
sendBuf[dataLength] = (unsigned char)crcData; // Add CRC to LoRa Data
//Serial.println( sendBuf[dataLength] );
sendBuf[dataLength+1] = (unsigned char)(crcData>>8); // Add CRC to LoRa Data
//Serial.println( sendBuf[dataLength+1] );
rf95.send(sendBuf, strlen((char*)sendBuf));//Send LoRa Data
//Serial.print(strlen((char*)sendBuf));
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];//Reply data array
uint8_t len = sizeof(buf);//reply data length
if (rf95.waitAvailableTimeout(3000))// Check If there is reply in 3 seconds.
{
// Should be a reply message for us now
if (rf95.recv(buf, &len))//check if reply message is correct
{
if(buf[0] == 1||buf[1] == 1||buf[2] ==1) // Check if reply message has the our node ID
{
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
Serial.print("got reply: ");//print reply
Serial.println((char*)buf);
delay(400);
digitalWrite(4, LOW);
//Serial.print("RSSI: "); // print RSSI
//Serial.println(rf95.lastRssi(), DEC);
}
}
else
{
Serial.println("recv failed");//
rf95.send(sendBuf, strlen((char*)sendBuf));//resend if no reply
}
}
else
{
Serial.println("No reply, is rf95_server running?");//No signal reply
Serial.println("test??");
Serial.println((char*)sendBuf);
rf95.send(sendBuf, strlen((char*)sendBuf));//resend data
}
Serial.println("test?");
delay(3); // Send sensor data every 30 seconds
}
プログラムの中身
923.0
の周波数でLoRa通信を行います。- DHT11(湿度・温度センサー)からのデータを読み取り、LoRa通信を使って、Serverに送信します
スケッチ > マイコンボードに書き込む で先ほどのプログラムをアップロードします。
これでClient側の設定は完了になります。これが完了すると、湿度・温度を一定の間隔でLoRa通信を使って送信し続けるようになります。
LoRa Serverの設定
- Arduino IDEを立ち上げます
- ボードを
Dragino Yun + UNO or LG01/OLG01
を選択します - ポートは LG01 のローカルIPアドレスであるネットワークポートを選択します
選択できたら、以下のプログラムを使います。
/*
Upload Data to IoT Server ThingSpeak (https://thingspeak.com/):
Support Devices: LG01
Example sketch showing how to get data from remote LoRa node,
Then send the value to IoT Server
It is designed to work with the other sketch dht11_client.
modified 24 11 2016
by Edwin Chen <[email protected]>
Dragino Technology Co., Limited
*/
#include <SPI.h>
#include <RH_RF95.h>
//#include <Console.h>
#include "ThingSpeak.h"
#include "YunClient.h"
YunClient client;
RH_RF95 rf95;
//If you use Dragino IoT Mesh Firmware, uncomment below lines.
//For product: LG01.
#define BAUDRATE 115200
unsigned long myChannelNumber = 0000000;
const char * myWriteAPIKey = "XXXXXXXXXXXXXXXX";
uint16_t crcdata = 0;
uint16_t recCRCData = 0;
float frequency = 923.6;
//float frequency = 868.0;
void setup()
{
Bridge.begin(BAUDRATE);
// Console.begin();// Don't use Console here, since it is conflict with the ThinkSpeak library.
// while(!Console);
ThingSpeak.begin(client);
if (!rf95.init())
// Console.println("init failed")
;
// Setup ISM frequency
rf95.setFrequency(frequency);
// Setup Power,dBm
rf95.setTxPower(13);
// �L�����A�Z���X
rf95.setCADTimeout((unsigned long)5);
// Console.println("Start Listening ");
}
uint16_t calcByte(uint16_t crc, uint8_t b)
{
uint32_t i;
crc = crc ^ (uint32_t)b << 8;
for ( i = 0; i < 8; i++)
{
if ((crc & 0x8000) == 0x8000)
crc = crc << 1 ^ 0x1021;
else
crc = crc << 1;
}
return crc & 0xffff;
}
uint16_t CRC16(uint8_t *pBuffer, uint32_t length)
{
uint16_t wCRC16 = 0;
uint32_t i;
if (( pBuffer == 0 ) || ( length == 0 ))
{
return 0;
}
for ( i = 0; i < length; i++)
{
wCRC16 = calcByte(wCRC16, pBuffer[i]);
}
return wCRC16;
}
uint16_t recdata( unsigned char* recbuf, int Length)
{
crcdata = CRC16(recbuf, Length - 2); //Get CRC code
recCRCData = recbuf[Length - 1]; //Calculate CRC Data
recCRCData = recCRCData << 8; //
recCRCData |= recbuf[Length - 2];
}
void loop()
{
if (rf95.waitAvailableTimeout(2000))// Listen Data from LoRa Node
{
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];//receive data buffer
uint8_t len = sizeof(buf);//data buffer length
if (rf95.recv(buf, &len))//Check if there is incoming data
{
recdata( buf, len);
if(crcdata == recCRCData) //Check if CRC is correct
{
// Console.println("Get Data from LoRa Node");
// Console.print(buf[0]);Console.print(buf[1]);Console.println(buf[2]);
if(buf[0] == 1||buf[1] == 1||buf[2] ==1) //Check if the ID match the LoRa Node ID
{
uint8_t data[] = " Server ACK";//Reply
data[0] = buf[0];
data[1] = buf[1];
data[2] = buf[2];
// Console.print(data[0]);Console.print(data[1]);Console.println(data[2]);
rf95.send(data, sizeof(data));// Send Reply to LoRa Node
rf95.waitPacketSent();
int newData[4] = {0, 0, 0, 0}; //Store Sensor Data here
for (int i = 0; i < 2; i++)
{
newData[i] = buf[i + 3];
}
float h = newData[0];
float t = newData[1];
// Console.print("h:");Console.println(h);
// Console.print("t:");Console.println(t);
ThingSpeak.setField(2,h); //
ThingSpeak.setField(1,t);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); // Send Data to IoT Server.
}
}
}
else
{
// Console.println("recv failed");
;
}
}
}
myChannelNumber
や myWriteAPIKey
はご自身のThingSpeakのChannelのIDと書き込み用のAPI Keyを使う必要があります。
unsigned long myChannelNumber = 0000000;
const char * myWriteAPIKey = "XXXXXXXXXXXXXXXX";
スケッチ > マイコンボードに書き込む で先ほどのプログラムをアップロードします。
これが完了すると、Clientから送信された湿度や温度がThingSpeakのChannelにアップロードされていきます。
ThingSpeakのWeb View画面にいき、無事アップロードされていることが確認できました。
最後に
プログラムを一から書くことがなく、動作しているものをそのまま流用できたので、一連の作業自体は2日かからず全て完了しました。
Arduino IDEの使い方や、Wifiの設定などでややハマってしまった感はあるので、慣れていればよりスムーズだったかなと思います。
ただ、流用しているがために、特にあまり考えなくてもできてしまったため、あまり身についていない部分もあるかなというのは正直あります。
ここら辺は独自の応用例を挑戦してみて(ハマりポイントにハマって)身につけていこうと思います。
とはいえ、IOT系の開発の一連の作業フローや考え方が少し分かったので、そこはとても良かったと思っています。
開発手順のおさらい
以下のような手順で実施しました。
- LG01(Gateway)のwifiの設定 <= 第2回の記事で紹介
- Arduino IDEを使って、LG01の動作確認 <= 第3回の記事で紹介
- Arduino IDEを使って、LoRa Mini DevとLG01の通信を検証 <= 第4回の記事で紹介
- ThingSpeakのアカウントの作成 <= 第5回の記事で紹介
- DHT11(湿度・温度センサー)とLoRa Mini Devをつなぎ、LG01を経由してThingSpeakにデータをアップロードする <= 今回の記事のスコープ
以上です。
関連する記事
[第1回]LoRa IoT入門シリーズの概要
LoRaを使ったIoTの入門シリーズでやる内容の概要を説明します。
[第2回]LoRa GatewayであるDragino LG01のwifiを設定
LoRa GatewayであるDragino LG01のwifiを設定して、LG01からインターネットアクセスできるようにしてみましょう
[第3回]LoRa GatewayであるDragino LG01のLEDを点灯させてみよう
LoRa GatewayであるDragino LG01にプログラムをアップロードして、LEDを点灯してみましょう
[第4回]LoRa ClientとServerでLoRaの通信を試してみよう
LoRa Mini Dev(LoRa Client)とLG01(LoRa Server)間の通信を試してみましょう
[第5回]ThingSpeakのアカウントの作成して、データを書き込んでみよう
ThingSpeakのアカウントの作成して、HTTP APIを使って、データを書き込んでみましょう
[第6回]温度・湿度センサーの情報をThingSpeakにアップロードしてみよう
DHT11(湿度・温度センサー)とLoRa Mini Devをつなぎ、LG01を経由してThingSpeakにデータをアップロードしてみましょう