データをフィールドからクラウド(インターネット)まで無線で飛ばし、オフィスからデータにアクセスできれば、これ以上のことはありません。これまで、この無線通信には3G(少し前の携帯電話回線)を使うことが多かったのですが、近年はLPWA(Low Power Wide Area)ネットワークというものが注目されています。もちろん4Gや5Gを使うことも技術的に可能でしょうが、我々がフィールドから送りたいデータは、たとえば間隙水圧や変位の値など、データ量としてはごく小さいものです。LPWAの長所は、名前が示す通り非常に省電力であり、また第三者のサービスを利用する場合、通信料が非常に安いということです。

 

Sigfox

 LPWAというのは低電力・広域ネットワークの総称で、いくつかの規格があります。これについては他のサイトにまとめられているので、適当に検索して読んで下さい。特に有名なのがSigfoxとLoRaです。LoRaはあくまで通信規格であり、送信機・受信機(ゲートウェイ)を自身で設置する必要があります(2020年現在の話です)。一方、Sigfoxはサービスまで含んでおり、基地局が世界各地にすでにあるため、携帯電話と同じように、端末だけ用意し、オペレータに料金を払えば基地局を通してインターネット上にデータを転送することができます。Sigfoxの利用は敷居が低いので、今日はSigfoxを使ったデータの無線転送方法を説明します。

 

 まず、Sigfoxの現在のサービスの概要です。一回に送れるデータは12バイト(0, 1, 2, …, a, b, …, fの16進数を24桁)で、これを1日に2/50/100/140回送れます(それぞれ年間通信料700/800/900/1000円+消費税)。送られた24桁(文字)のテキストはSigfox Backendのサイトからタイムスタンプとともに確認することができ、csvで出力することも可能です。通信圏は基地局から約60kmですが、山間部・丘陵地帯には届きません。カバーエリアは以下から確認できます。

https://www.kccs-iot.jp/area/

カバーエリアが円形になっているので、これを見るとどこに基地局があるかだいたいわかります。私がいる北海道では、函館・室蘭・苫小牧・札幌・小樽・留萌・旭川・滝川・帯広・釧路・根室・北見・網走・紋別・名寄・中標津といったところにあるようです。この近郊で地形が許すところで使えます(京セラの方々、読んでいたら、私の観測サイトがある黒松内にも基地局建ててください)。

 

 Sigfoxというのはフランスの会社ですが、日本では京セラコミュニケーションシステムが運営しています。

https://www.kccs-iot.jp/service/

上記HPは日本語で書かれていますが、実際にライセンスを購入したり、クラウド上のデータを扱うサイト(バックエンドと呼ばれています)は全て英語です。また、言語は抜きにしても、チュートリアルがなく、ライセンスアクティベーションのシステムがはっきりしない(2年くらい使っていますが、いまだにバックエンドの使い方がよくわからない)など、率直にいってかなりわかりづらい部分があります。これを使うほぼ唯一の手がかりとなるのが、Gaku Hibiさんという方(Sigfoxの社員なのでしょうか?)のQiita上のブログです。今日紹介するモジュールの使い方も、この方のブログがほぼ唯一の手がかりです。

 

Sigfox送信モジュール

 日本で手に入るSigfoxモジュールとして主に以下の二つがあります。

・BRKWS01 RC3

韓国のWisolという会社のマイコンを積んでいます。今日はこれを使います。スイッチサイエンスのウェブサイトなどで購入できます。5000円強です。1年間の通信ライセンスを含んでいます(140回/日のものだったように記憶しています。アクティベーションに期限があるので注意。アクティベートしてから1年使えます)。

https://www.switch-science.com/

 

 

・KCCS-UNASHIELD-V2S

Arduino Unoのシールドの形状に実装されています。これも1年のライセンスが含まれています。2018年にスイッチサイエンスから1つ買いましたが、その後、ずっと入荷未定になっており、手に入るかわかりません。

 

 

 上記の通り、BRKWS01 RC3の使い方を紹介します。ブレークアウトボードに加え、アンテナとおまけのピンヘッダが同封されています。静電気保護袋に貼ってあるラベルにはモジュールのIDとPACが書かれているので、少なくともアクティベーションまではこれを捨てないでください。IDとPACはマイコン内のメモリに入っているので、シリアル通信で読み出せますが、面倒です。

 

 

 ボードにはいろいろピンが出ていますが、実質上使うのは4つ(+, -, TX, RXのシルクがある部分)だけです。ピンヘッダ―もここだけつければOKです。使い方は簡単で、Arduinoなどのマイコンから3.3V印加します(5Vでも大丈夫かもしれません)。つまり、Arduinoなら3.3Vピン・GNDピンをBRKWS01 RC3の+・-にそれぞれつなぎます。TX・RXとあることからわかるように、マイコンとはシリアル(UART)通信でコマンドをやりとりします(UARTについては第29回参照)。ArduinoとPCの間でハードウェアシリアルを使った通信をしながら(つまり、動作状況をArduino IDEのシリアルモニタで確認しながら)使いたいので、ArduinoとこのBRKWS01 RC3の通信にはソフトウェアシリアルを使いたいと思います(第29回参照)。Arduino UnoやPro MiniなどAtmega328Pを使ったマイコンでは、たとえばピン2・3が使えます(他にも使えるピンはあります)。以下のような接続になります。

 

 

この装置を使って、例えばクラウドに「0123456789abcdef01234567」という24字のメッセージを送ってみます。スケッチは以下のようになります。

 

 

#include <SoftwareSerial.h>

#include <Time.h>

#include <TimeLib.h>

 

SoftwareSerial mySerial(2, 3); // 2 - RX, 3 - TX

 

void setup()

{

    /* Hardwar serial: Arduino - PC */

    Serial.begin(9600);

 

    /* Software serial: Arduino - BRKWS01 RC3 */

    mySerial.begin(9600);

 

    /* AT commandの例 */

    //Serial.println("Connecting to the Sigfox Breakout board...");

    //Serial.println("AT$I=10 : get Device ID");

    //Serial.println("AT$I=11 : get PAC");

    //Serial.println("AT$T? : get Temperature");

    //Serial.println("AT$V? : get Voltages");

    //Serial.println("AT$P=unit : set Power mode (unit = 0:software reset 1:sleep 2:deep_sleep)");

    //Serial.println("AT$TR=unit : set Transmit repeat (unit = 0..2)");

    //Serial.println("AT$WR : save config");

    //Serial.println("AT$SF=[payload] : SEND SIGFOX MESSAGE");

  

    mySerial.print("AT$I=10\r"); //BRKWS01 RC3にDevice IDを返すようコマンドを送る

}

 

void loop()

{

    /* Creat a sigfox message */

    char dataline[31]="AT$SF=0123456789abcdef012345678";

    dataline[30]='\r'; //最後の1文字は改行文字(リターン)に置き換える

 

    Serial.println(dataline); //PCのシリアルモニタに確認のため送信メッセ―ジを表示

    Serial.print("Device ID : "); //PCのシリアルモニタに"Device ID:"と記す

       

    /* Send Sigfox message */

    mySerial.print(dataline);

    int flg=0;

    int minute0 = minute();

    int second0 = second();

   

    while(flg==0)

    {

      if (mySerial.available()) { // BRKWS01 RC3からメッセージが返っていれば

        Serial.write(mySerial.read()); // そのメッセージをPCに送りシリアルモニタ上に表示(まず最初に、要求していたDevice IDが返ってくる)

      }

      if (Serial.available()) { //シリアルモニタからメッセージが入力されたなら

        mySerial.write(Serial.read()); // BRKWS01 RC3にそのメッセージを送る

      }

 

      //10sec経過すると送受信のルーチンを終了

      if((second0>=50)&&(second()>(second0+10-60))&&(second()<50))

      {

        flg=1; 

      }

      else if((second0<50)&&(second()>(second0+10)))

      {

        flg=1; 

      }

    }

   

    Serial.println("After sigfox routine");

 

    delay(300000); //5分間停止

}

 

 

スケッチについていくつか説明です。

・BRKWS01 RC3にはATコマンドというものを送ります。例えば、"AT$I=10\r"という文字列をUARTでBRKWS01 RC3に送ると、ArduinoにはID(先ほど、袋のラベルに書いてあると記したもの)を返します。その他、コメントアウトしている文に、PACを要求するコマンドなど書いてあります。温度や電圧も計測できるようです(使うことはあまりないと思いますが)。"AT$SF=[payload]”の[payload]のところに24字(24桁)の文字を入れると、それをLPWAで基地局まで送信することになります。

・mySerialというのは、Arduino – BRKWS01 RC3間のソフトウェアシリアル、SerialというのはArduino – PC間のハードウェアシリアルのことです。ArudinoのTX・RXをBRKWS01 RC3のRX・TXというように、互い違いに接続することに注意して下さい(第12・29回参照)

・通信がうまくいかない場合に最後のほうのwhileのルーチンで無限ループに入ると(フィールド観測の場合)無駄にバッテリーを消費するので、10秒経ってうまく行かなければ諦めることにします(フィールド観測の場合、この後にたとえばスリープに入る、あるいは電源装置に終了の信号を送るといった省電過程に入ります:第13・14回参照)。

 

BRKWS01 RC3にアンテナをぱちっとはめれば、これでハードウェアは完了です。マイコン(Arduino)に電源を入れれば、10秒以内にメッセージがクラウドに送信されます。ただ、これとは別にSigfox Backendでこのモジュールを登録しなければなりません。以下のウェブサイトに行ってください。

https://backend.sigfox.com/auth/login

アカウントをつくってログインしたら、モジュールを登録します。この方法ですが、最初からライセンス込みのモジュールを買った場合は比較的簡単です(それらしいところをクリックしていけばできるはずなのでやってみてください)。ライセンスがない、あるいは切れたモジュールに対し、別途購入したライセンス(「token」と呼びます。以下から買えます:https://buy.sigfox.com/)をあてがうのは、なかなかわかりづらいです。イメージとしては、tokenをためておき、device groupに結び付け、このdevice groupにtransferした新しいdeviceから最初の信号が送られるとtokenが消費されるとともにアクティベーション(購入から1年以内にアクティベートしないといけません)が完了する、といった構図のようです。とにかく、サイトを30分くらいクリックしまくればなんとかなります。

 

データの確認

アクティベーションが完了すると、メッセージがバックエンドに届くようになります。メッセ―ジは、「DEVICE」のページから該当するモジュールのIDをクリックし、左に現れる「MESSAGES」をクリックすると現れます。上記の通り接続しスケッチをいれてもうまく行かない場合はtokenの登録がうまくいっていないことなどが考えられます。しかし、私の経験上、メッセージが現れない原因として一番多いのは、単に装置が圏外にあったということです(1~2時間かけてさんざん配線やバックエンド設定を確認したが原因がわからず、場所をちょっと動かしたらうまくいった、ということは何度もあります)。LPWAの電波は障害物に弱いので、屋内ではうまくいかないことが多いです。札幌の街の真ん中にある我が家のベランダでも失敗することがあります。そもそも場所が圏内であることを確認したうえで、見通しのよい場所で試してみて下さい。

 

 

 

以下の画面は別の例からとってきたので送信メッセージ(Data/Decodingの欄)が0123456789abcdef01234567になっていませんが、上のスケッチを走らせればそうなるはずです。

 

 

センサー値をテキストデータにして送信

 実際の応用では、センサーの値などをこの24桁を使って送信することになります。10進法を16進法にすれば多少圧縮できますが(たとえば2341mVは10進法では4桁ですが、16進法にすれば92cで3桁に収まります)、その必要がなければ10進法のままでもいいです。

 

 ここでは例として、アナログピンA0-A4の5本を使って電圧を読み込み(mV単位ではなく、ビット数0-1023のままとします)、最初の20桁を使って4桁の電圧(mV)を5チャネル送信し、残りの4桁は0にするスケッチを示します。先ほどと異なる箇所を赤字で示します。

 

 

#include <SoftwareSerial.h>

#include <Time.h>

#include <TimeLib.h>

 

SoftwareSerial mySerial(2, 3); // 2 - RX, 3 - TX

 

const int apins[5]={A0, A1, A2, A3, A4};

 

void setup()

{

    /* Hardwar serial: Arduino - PC */

    Serial.begin(9600);

 

    /* Software serial: Arduino - BRKWS01 RC3 */

    mySerial.begin(9600);

 

    /* AT commandの例 */

    //Serial.println("Connecting to the Sigfox Breakout board...");

    //Serial.println("AT$I=10 : get Device ID");

    //Serial.println("AT$I=11 : get PAC");

    //Serial.println("AT$T? : get Temperature");

    //Serial.println("AT$V? : get Voltages");

    //Serial.println("AT$P=unit : set Power mode (unit = 0:software reset 1:sleep 2:deep_sleep)");

    //Serial.println("AT$TR=unit : set Transmit repeat (unit = 0..2)");

    //Serial.println("AT$WR : save config");

    //Serial.println("AT$SF=[payload] : SEND SIGFOX MESSAGE");

  

    mySerial.print("AT$I=10\r"); //BRKWS01 RC3にDevice IDを返すようコマンドを送る

}

 

void loop()

{

    /* Creat a sigfox message */

    int ainput;

    int cnt;

    int digit1000, digit100, digit10;

    char dataline[31]="0000000000000000000000000000000";

    dataline[0]='A';dataline[1]='T';dataline[2]='$';dataline[3]='S';dataline[4]='F'; dataline[5]='=';

    dataline[30]='\r'; //最後の1文字は改行文字(リターン)

      

    for(cnt=0;cnt<5;cnt++)

    {

      // 電圧を読む(ビット数のまま:0-1023)

      ainput=analogRead(apins[cnt]);

      // 1000の位

      digit1000=int(ainput/1000); dataline[6+4*cnt]='0'+ digit1000;

      // 100の位

      digit100=int((ainput-1000*digit1000)/100); dataline[7+4*cnt]='0'+ digit100;

      // 10の位

      digit10=int((ainput-1000*digit1000-100*digit100)/10); dataline[8+4*cnt]='0'+ digit10;

      // 1の位

      dataline[9+4*cnt]='0'+int((ainput)%10);

 

      // PC上のシリアルモニタに表示

      Serial.print("Analog input CH"); Serial.print(cnt); Serial.print(": "); Serial.print(ainput); Serial.println(" (bit)");

    }

   

    Serial.println(dataline); //PCのシリアルモニタに確認のため送信メッセ―ジを表示

   

    /* Send Sigfox message */

    mySerial.print(dataline);

    int flg=0;

    int minute0 = minute();

    int second0 = second();

 

    Serial.print("Device ID : "); //PCのシリアルモニタに"Device ID:"と記す

   

    while(flg==0)

    {

      if (mySerial.available()) { // BRKWS01 RC3からメッセージが返っていれば

        Serial.write(mySerial.read()); // そのメッセージをPCに送りシリアルモニタ上に表示(まず最初に、要求していたDevice IDが返ってくる)

      }

      if (Serial.available()) { //シリアルモニタからメッセージが入力されたなら

        mySerial.write(Serial.read()); // BRKWS01 RC3にそのメッセージを送る

      }

 

      //10sec経過すると送受信のルーチンを終了

      if((second0>=50)&&(second()>(second0+10-60))&&(second()<50))

      {

        flg=1; 

      }

      else if((second0<50)&&(second()>(second0+10)))

      {

        flg=1; 

      }

    }

   

    Serial.println("After sigfox routine");

 

    delay(300000); //5分間停止

}

 

 

この例をいじれば、電圧に限らず、温度でも水圧でも、なんでも送信できるはずです。