最近、沖縄がSIGFOXのエリアになったらしいので、SIGFOXを使ってみようと!
今、東京に来ているので、マルツ 秋葉原本店で、Sigfoxブレークアウトボード BRKWS01 RC3【BRKWS01】を購入(税込み5,162円)して、M5STICK-CとGPS受信機キット 1PPS出力付き 「みちびき」3機受信対応を繋いで、SIGFOX経由で位置情報をサーバに送信してみました。
ハードウェアの詳細
BRKWS01 は、1年間の回線利用料も含まれています。
回線登録の仕方は、こちらを参照してください。
ブレイクアウト基板には、ピンヘッダ4本を半田付けしました。
3.3V,GND,TX,RXの4本だけを使います。電源が3.3Vなので、M5STICK-Cの汎用ポートと接続しています。TXをM5STICK-Cの36、RXをM5STICK-Cの26に繋いでいます。
GROVE端子の電源は5Vなので、こっちにつなぐと壊れるかも!
GPSに関しては、5Vでも駆動するので、GROVE端子と接続しています。
SIGFOX ConsoleのCALLBACK設定
SIGFOXのゲートウェイから、自前のサーバにデータを送信するために、CALLBACKという設定を行います。
SIGFOXは最大12バイトしか送信できないので、位置情報(緯度、経度)は、バイナリで送信するしかないので、Custom payload configを設定する必要があります。HEXの文字列のままでもいいと言う人は、設定しなくてもOKです。
経度(4バイト)緯度(4バイト)で送るので、
lng::float:32 lat::float:32
を設定しています。
Content typeは、JSONで送りたいので、application/jsonにして、BODY部で、フォーマットを規定します。
{“device” : “{device}”,”data” : “{data}”,”time” : {time},”lng”:{customData#lng},”lat”:{customData#lat}}
ここで、customData#っていうのが、Custom payload configで設定した変数になります。
※customDataが付かない、lngやlatだけの変数も用意されていますが、これは、SIGFOXで取得した位置情報を入れることが出来ますが、今月から利用できなくなったようです。実際取得すると、整数部しか入ってこないので,使い物になりません(笑)
Arduinoのプログラム
// Sigfoxブレークアウトボード BRKWS01 RC3とGPSをM5STICK-Cに繋いで、位置情報を送信する
// Programed by Kazuyuki Eguchi
#include <M5StickC.h>
#include <TinyGPS++.h>
HardwareSerial MODEM_SERIAL(1);
HardwareSerial GPS_SERIAL(2);
TinyGPSPlus gps;
char replybuffer[255];
int count = 0;
void setup() {
M5.begin();
M5.Axp.ScreenBreath(8); // バックライトの明るさ(7-15)
M5.Lcd.setRotation(1);
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(TFT_YELLOW);
M5.Lcd.setCursor(0, 0);
MODEM_SERIAL.begin(9600, SERIAL_8N1, 36, 26);
GPS_SERIAL.begin(9600,SERIAL_8N1, 33, 32);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
readline(1000);
readline(1000);
readline(1000);
Serial.println("Connect to the Sigfox Breakout board...");
Serial.print("Device ID : ");
MODEM_SERIAL.print("AT$I=10\r");
if(readline(1000)){
Serial.print(replybuffer);
}
}
void loop() {
char hex[32];
char data[8];
if (GPS_SERIAL.available()) {
int inByte = GPS_SERIAL.read();
if(gps.encode(inByte)){
if (gps.location.isValid())
{
float lng = gps.location.lng();
float lat = gps.location.lat();
count++;
if(count == 1)
{
int lng_i = *( ( int* )&lng );
int lat_i = *( ( int* )&lat );
data[0] = (lng_i >> 24) & 0xff;
data[1] = (lng_i >> 16) & 0xff;
data[2] = (lng_i >> 8) & 0xff;
data[3] = lng_i & 0xff;
data[4] = (lat_i >> 24) & 0xff;
data[5] = (lat_i >> 16) & 0xff;
data[6] = (lat_i >> 8) & 0xff;
data[7] = lat_i & 0xff;
sprintf(hex,"AT$SF=%02x%02x%02x%02x%02x%02x%02x%02x\r",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
Serial.println(hex);
MODEM_SERIAL.print(hex);
if(readline(30000))
{
Serial.print(replybuffer);
}else
{
Serial.println("readline Timeout");
}
}
if(count > 5000)
{
count = 0;
}
}
displayInfo();
}
}
}
uint8_t readline(uint16_t timeout) {
uint16_t replyidx = 0;
while (timeout--) {
if (replyidx >= 254) {
break;
}
while(MODEM_SERIAL.available()) {
char c = MODEM_SERIAL.read();
if (c == '\r') continue;
if (c == 0xA) {
if (replyidx == 0)
continue;
}
replybuffer[replyidx] = c;
replyidx++;
}
if (timeout == 0) {
break;
}
delay(1);
}
replybuffer[replyidx] = 0;
return replyidx;
}
void displayInfo()
{
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.print(F("Location: "));
if (gps.location.isValid())
{
M5.Lcd.print(gps.location.lat(), 6);
M5.Lcd.print(F(","));
M5.Lcd.print(gps.location.lng(), 6);
}
else
{
M5.Lcd.print(F("INVALID"));
}
M5.Lcd.print(F(" Date/Time: "));
if (gps.date.isValid())
{
M5.Lcd.print(gps.date.month());
M5.Lcd.print(F("/"));
M5.Lcd.print(gps.date.day());
M5.Lcd.print(F("/"));
M5.Lcd.print(gps.date.year());
}
else
{
M5.Lcd.print(F("INVALID"));
}
M5.Lcd.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) {
M5.Lcd.print(F("0"));
}
M5.Lcd.print(gps.time.hour());
M5.Lcd.print(F(":"));
if (gps.time.minute() < 10) {
M5.Lcd.print(F("0"));
}
M5.Lcd.print(gps.time.minute());
M5.Lcd.print(F(":"));
if (gps.time.second() < 10) {
M5.Lcd.print(F("0"));
}
M5.Lcd.print(gps.time.second());
M5.Lcd.print(F("."));
if (gps.time.centisecond() < 10) {
M5.Lcd.print(F("0"));
}
M5.Lcd.print(gps.time.centisecond());
}
else
{
M5.Lcd.print(F("INVALID"));
}
}
サーバでデータを受信してみたら
受信側のPHPのプログラムはこんな感じ
<?php
$body = file_get_contents('php://input');
error_log(date("Y/m/d H:i:s") . "," . $body . print_r(apache_request_headers(),true) . "\n",3,"./debug.log");
echo "O";
?>
注意:位置情報は、改ざんしています。
2019/06/22 13:40:34,{“device” : “7390CA”,”data” : “430bxxxx420exxxx”,”time” : 1561178432,”lng”:139.80000,”lat”:35.700000}
Array
(
[Accept-Charset] => UTF-8;q=0.9,*;q=0.7
[User-Agent] => SIGFOX
[Content-Type] => application/json
[Accept-Language] => fr
[Content-Length] => 101
[Connection] => close
[X-File-Type] => normal
[X-Ua-Device] => pc
[X-Failure-Cache-Time] => 60
[X-Accel-Expires] => 60
[X-Wp-Access] => 0
[X-Server-Address] => 183.90.243.23
[X-Real-Ip] => 185.110.97.11
[X-Forwarded-Ssl] => on
[X-Forwarded-Port] => 443
[X-Forwarded-Host] => eguchi.jp
[X-Forwarded-Proto] => https
[X-Forwarded-For] => 185.110.97.11
[Host] => eguchi.jp
)
以上、ご参考までに