Day01-sigfox開啟全球一個網的物聯網世界



title: sigfox開啟全球一個網的物聯網世界

-利用Arduino MKRZERO x UnaMKR開發物聯網創新應用
圖1:全世界1個物聯網(Sigfox提供)

一、前言

Sigfox是專為物聯網裝置設計的低功耗廣域網路(Low Power Wide Area Network,簡稱LPWAN),具有長距離、低功耗、低成本等特性,十分符合需要超長續航力與網路連線能力的物聯網裝置的需求。優納比公司(UnaBiz)是負責台灣與新加坡Sigfox營運的電信商,於2017年6月15日取得由台灣國家通訊委員會所核發的第1張物聯網網路營業職照後,就積極在全台各地建置Sigfox網路,並於同年10月12日舉辦的UnaDay活動中,正式宣佈啟動台灣Sigfox網路服務。而截至2019年9月服務範圍已可以涵蓋全國95%的人口數,Sigfox在全球網路的覆蓋也達到65個國家的基礎建設布建,預定2019年底將逹到66個國家,逐步達到全世界1個物聯網真正的0G境界。
圖2: 服務範圍全台95%人口數

本文要介紹的Sigfox UnaMKR是由Sigfox物聯網通訊技術的台灣營運商UnaBiz與LiteOn共同研發推出的Sigfox通訊、感應器多功能模組,其最大的特色就是支援Sigfox Monarch全球通用規範,能夠讓物聯網裝置在全球自動連上當地的Sigfox網路。

二、Sigfox Monarch全球單一網特色

要介紹UnaMKR多功能模組之前,我們先來瞭解什麼是Sigfox Monarch,Monarch是Sigfox網路的一個獨特功能,可為物聯網設備提供跨全球無縫移動和通信的能力。Monarch通訊運作模式解決了裝置在全球移動的障礙,同時保持了LPWAN的功能(低電池消耗,簡單性和成本效益)。 此種單一網路的通訊架構可以使任何類型的物聯網設備均可暢行無阻於全球無遠弗屆運作,包含各項移動式裝置:物流、貨運、設備資產(如行李)全球追蹤及監控,無論是空運或海運均可跨越全球;對於銷售及出口到多個國家不同物聯網裝置,更能簡化產品的製造及銷售,包括消費性電子產品和大型家用電器廠商可使用單一個物聯網通訊硬體設計,就可以將產品銷往全球,實現Sigfox一個網路、一個通訊合約於一台物聯網設備。
Sigfox Monarch提供獨特的無線電通訊模組識別服務,其獨特的內建自動調頻讓設備管理無線電頻率變化,讓裝置能自動辨別所在區域頻率,發送行動定位訊息,不需Wi-Fi或GPS追蹤定位硬體,耗電量相當低。
Sigfox已宣布推出Sigfox Monarch認證服務,允許物聯網設備辨認並自動適應本地通信標準,從而提供全球無縫連接服務。因此,即使在具有不同無線電規則的國家之間移動,單個設備也可以在Sigfox網絡上合法通信,Monarch透明而簡單的架構,讓設備自動選擇合適的通訊頻段配置,無需人工切換,Monarch透過Sigfox網路的基地站發射廣播的信標(Beacons),讓裝置接收後可自動選擇當地適用的無線通訊頻率運作,因此進入由Monarch兼容基站廣播本地信標信息的區域,Sigfox設備就可以自動切換全球RC 區域(RC1至RC6),自動接入當地的Sigfox頻段,無縫連接全球Sigfox網路和地理定位服務,目前這些基站已開始廣設於各主要運輸地點,如機場,海港,火車站,物流樞紐等。
您可透過Sigfox 後台查看Sigfox Monarch服務區域的最新地圖。
(https://backend.sigfox.com/ ==> SERVICE MAPS ==>MONARCH COVERAGE MAP)
圖3:Sigfox Monarch服務區域最新地圖 (Sigfox後台提供)

三、UnaMKR sigfox 模組功能介紹

UnaMKR是一款適用於Sigfox和藍牙的多功能低功耗開發套件,提供混合短距離(BLE-Beacon)和長距離(Sigfox)超低功耗模式裝置開發,更可透過UnaConnect 平台蒐集大數據。與Arduino相容的擴充模組,直接支援Arduino MKRZERO 積木式擴充,其最大的特色就是支援Sigfox Monarch規範,當裝置進入全球超過60個國家的Sigfox網路範圍後,系統會自動辨識並自動切換當地所使用的無線通訊頻段(RCZ1~RCZ6),加上Sigfox原本就提供全球漫遊的服務,因此更適合用來打造跨國使用的Sigfox 0G網路的物聯網裝置。
圖4:UnaBiz UnaMKR Sigfox 模組(UnaBiz提供)

圖5:Arduino MKRZERO(Arduino.cc提供)
圖6:Arduino MKRZERO+UnaMKR 積木組合(UnaBiz提供)
UnaMKR也加入藍牙通訊能力,且支援藍牙網狀網路(Bluetooth Mesh)、藍牙信標(Bluetooth Beacon)等功能,不但方便在維護裝置時讀寫大量資料,也能激發更多創意應用。此外UnaMKR還內建溫度、濕度、氣壓、天然氣/ VOC、加速規、磁力計、磁簧開關、環境光等感應器,適合在開發階段製造各種驗證性試作機。其中氣壓感應的靈敏度甚至可以感應到數10公分的高度落差,可以應用於辨別樓層與室內導航等應用。
UnaMKR 是一塊內建Sigfox Monarch全頻段RC Zone的sigfox開發板,可自動切換當地Sigfox頻段,RC1 (Europe)、RC2 (US)、RC3 (Japan)、RC4 (APAC)、RC5 (Korea)、RC6 (Indi),通訊無縫接軌物聯網裝置。模組提供三種使用模式:UnaMKR Modem Mode (AT command mode)、 UnaMKR Arduino Mode、 UnaMKR Embed mode。
UnaMKR Modem Mode (AT command)可透過模組提供的Micro USB連接PC或具USB介面的嵌入式裝置,利用標準通訊埠軟體連接,或以模組提供的UART Pin腳(UnaMKR TX pin:D13,UnaMKR RX pin:D14)連接具UART通訊介面的嵌入式裝置或MCU(Micro Control Unit),以模組提供的AT command連接UnaMKR後進行通訊設定及傳輸資料。

圖7:Sigfox全球6個通訊區域地圖(RC1~RC6)

UnaMKR Arduino Mode:可將將UnaMKR模組直接插到Arduino MKRZERO使用,並以Arduino IDE 開發各種應用,也可直接以UnaMKR提供的 Arduino 範例程式控制模組內建的溫度、濕度、氣壓、天然氣/ VOC、加速規、磁力計、磁簧開關、環境光等8種感應器。

開始使用Arduio MKRZERO+UnaMKR為開發環境前,應先將為Arduino Mode,
如下圖15:跳接設定。

並安裝好UnaMKR所提供的天線,連接方式如下:
下圖16:Sigfox天線:將IPEX連接到SMA電纜連接到UnaMKR,然後將天線擰到SMA連接器上。

下圖17:藍牙天線:將貼片式藍牙天線的IPEX連接到UnaMKR

Demo Code

/*
 *  Demo code:
 *      Read all sensors on UnaMKR
 *      Sigfox uplink
 *      Trigger methods: Button, Reed switch, Timer
 * 
 *  Development kit: UnaMKR
 *
 *  Author: UnaBiz
 *  *******************************************************
 *  Arduino Boards Manager -> Search 'MKRZERO' -> Install
 */
#include <UnaMKR.h>
#include <Adafruit_BME680.h>
#include <bme680.h>
#include <bme680_defs.h>
#include <LSM303AGR_ACC_Sensor.h>
#include <LSM303AGR_MAG_Sensor.h>
#include <TSL2540.h>
#include <Adafruit_ZeroTimer.h>

/* Options */
#define  PUBLIC_KEY_USAGE       (false)         // set 'true' to enable public key (Emulator)
#define  LOG_MESSAGE_DISPLAY    (true)          // set 'true' to enable displaying all message on serial port

/* Components */
UnaMKR  my_mkr;
Adafruit_BME680 my_bme;
LSM303AGR_ACC_Sensor *Acc;
LSM303AGR_MAG_Sensor *Mag;
TSL2540  tsl;
Adafruit_ZeroTimer *zt4;

/* Definitions */
#define  TIMER_PERIODIC         (2400)          // timer trigger uplink, unit: second
#define  TIMER_SAMPLING         (30)            // timer trigger asynchronous sampling, unit: second
#define  TIME_WAIT_RESPONSE     (1000)          // timeout for response, unit: milli-second
#define  TIME_WAIT_UPLINK       (15000)         // // timeout for uplink, unit: milli-second

/* Variables */
volatile bool button_pressed = false;
volatile bool reed_detect    = false;
volatile bool timer_detect   = false;
volatile bool timer_sampling = false;
volatile uint32_t timer_count;

/* Interrupt callback */
void reedInterrupt() {
  reed_detect = true;
}

void buttonInterrupt() {
  button_pressed = true;
}

void timerInterrupt() {
    ++timer_count;
    if ((timer_count % (1000*TIMER_SAMPLING)) == 0) {
        timer_sampling = true;
    }
    if (timer_count >= (1000*TIMER_PERIODIC)) {
        timer_detect = true;
        timer_count  = 0;
    }
}

void clearInterrupt() {
  button_pressed = false;
  reed_detect    = false;
  timer_detect   = false;
}

/* Timer handler, please do not remove it */
void TC4_Handler()
{
  Adafruit_ZeroTimer::timerHandler(4);
}

/* Arduino Setup */
void setup() {

    // BME608 Sensor
    my_bme.begin();
    my_bme.setTemperatureOversampling(BME680_OS_8X);
    my_bme.setHumidityOversampling(BME680_OS_2X);
    my_bme.setPressureOversampling(BME680_OS_4X);
    my_bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
    my_bme.setGasHeater(320, 150); // 320*C for 150 ms
    my_bme.performReading();

    // LSM303AGR
    Acc = new LSM303AGR_ACC_Sensor(&Wire);
    Mag = new LSM303AGR_MAG_Sensor(&Wire);
    Acc->SetFS(2.0);    // 2g
    Acc->SetODR(25.0);  // 25Hz
    Mag->SetFS(2.0);    // 2g
    Mag->SetODR(10.0);  // 10Hz
    delay(500);
    Acc->Enable();
    Mag->Enable();

    // TSL2540
    tsl.begin();

    // Reed switch
    pinMode(PIN_REED_INT, INPUT_PULLUP);
    attachInterrupt(PIN_REED_INT, reedInterrupt, FALLING);

    // Button
    pinMode(PIN_BUTTON, INPUT_PULLUP);
    attachInterrupt(PIN_BUTTON, buttonInterrupt, FALLING);

    // Variable
    clearInterrupt();
    timer_count = 0;

    // Serial port for Arduino UART over USB
    Serial.begin(115200);

    // Initialize component
    my_mkr.begin(PUBLIC_KEY_USAGE);

    // Print response data
    my_mkr.logEnable(LOG_MESSAGE_DISPLAY);

    // Timer
    zt4 = new Adafruit_ZeroTimer(4);
    zt4->configure(TC_CLOCK_PRESCALER_DIV1,   // prescaler
                TC_COUNTER_SIZE_16BIT,        // bit width of timer/counter
                TC_WAVE_GENERATION_MATCH_PWM  // match style
                );
    zt4->setPeriodMatch(48000, 24000, 0);     // 1 match, channel 0, unit: ms
    zt4->setCallback(true, TC_CALLBACK_CC_CHANNEL0, timerInterrupt);
    zt4->enable(true);

    // Delay 5 seconds before loop entry
    delay(5000);
}

/* Arduino Main Loop */
void loop() {

    static int loop_count = 0;
    static bool bme680_state = true;
    char response[12];
    char str[128];
    int  resp_len;
    float tmp, hmd, prs, gas;
    uint8_t zone;
    int32_t acc[3], mag[3];
    uint16_t vsb, ir;
    bool  rs;

    // Asynchronous sampling for BME680
    if (timer_sampling) {
      bme680_state = my_bme.performReading();
      timer_sampling = false;
    }

    // Check interrupt status
    if (!button_pressed && !reed_detect && !timer_detect) {
        return;
    }

    Serial.print("Interrupt detected: ");
    if (button_pressed)
      Serial.println("Button ");
    if (reed_detect)
      Serial.println("Reed Switch ");
    if (timer_detect)
      Serial.println("Timer ");

    // Wake-up UnaMKR
    my_mkr.wakeup();

    // Get RC zone
    my_mkr.getZone();
    my_mkr.getData(response, &resp_len, TIME_WAIT_RESPONSE);
    zone = atoi(response);
    if (zone < RCZ_1 || zone > RCZ_6) {
        Serial.println("Invalid RC");
        zone = 0xFF;
    }

    // Update sensors
    tmp = my_bme.temperature;
    hmd = my_bme.humidity;
    prs = my_bme.pressure;
    gas = my_bme.gas_resistance;
    vsb = tsl.readVisible();
    ir  = tsl.readIR();
    rs  = (digitalRead(PIN_REED_INT) == HIGH) ? false : true;

    rs |= reed_detect;
    Acc->GetAxes(acc);
    Mag->GetAxes(mag);

    // Setup message (payload)
    UnaMkrMessage msg;
    msg.clear();
    msg.setTimeout(TIME_WAIT_UPLINK);

    msg.addField_Acceletometer(acc);
    msg.addField_Magnetometer(mag);

    if (bme680_state) {
      msg.addField_Temperature(tmp);
      msg.addField_Humidity(hmd);
      msg.addField_Pressure(prs);
      msg.addField_IndoorAirQuality(gas);
    } else {
      Serial.println(" BME680: Failed to perform reading :(");
    }

    msg.addField_LightSensor(vsb);
    msg.addField_InfraredSensor(ir);
    msg.addField_ReedSwitch(rs);
    msg.addField_RCZone(zone);

    // Print all status of sensors
    Serial.print("  * RC = ");
    Serial.println(zone, DEC);

    Serial.print("  * Temperature = ");
    Serial.print(tmp);
    Serial.println(" *C");

    Serial.print("  * Humidity = ");
    Serial.print(hmd);
    Serial.println(" %");

    Serial.print("  * Pressure = ");
    Serial.print(prs/100);
    Serial.println(" hPa");

    Serial.print("  * Air Quality = ");
    Serial.print(gas/1000);
    Serial.println(" kOhms");

    sprintf(str, "  * Acc (X,Y,Z)[mg] = (%5d,%5d,%5d)", acc[0],acc[1],acc[2]);
    Serial.println((const char*)str);

    sprintf(str, "  * Mag (X,Y,Z)[mGauss] = (%5d,%5d,%5d)",mag[0],mag[1],mag[2]);
    Serial.println((const char*)str);

    Serial.print("  * Visible: ");
    Serial.println(vsb, DEC);

    Serial.print("  * Infrared: ");
    Serial.println(ir, DEC);

    Serial.print("  * Reed Switch: ");
    Serial.println(rs, BIN);

    // Print payloads
    Serial.print("\r\n");
    msg.print_msg();

    // Uplink with message type of payload
    Serial.println("Sigfox uplink... ");
    my_mkr.uplink(&msg);

    // Wait response
    my_mkr.getData_CheckOk(TIME_WAIT_UPLINK);

    // Increase counter
    loop_count++;

    // Sleep mode
    my_mkr.sleep();
    my_mkr.getData_CheckOk(TIME_WAIT_RESPONSE);

    // Done
    Serial.println("\r\nDone");
    clearInterrupt();

    // Flush serial port
    Serial.flush();
}

6.部份程式說明:
// 宣告UnaMKR支援各項感測器程式庫物件
/* Components */
UnaMKR  my_mkr;
Adafruit_BME680 my_bme;
LSM303AGR_ACC_Sensor *Acc;
LSM303AGR_MAG_Sensor *Mag;
TSL2540  tsl;
Adafruit_ZeroTimer *zt4;
…
// 啟用BME608 Sensor
my_bme.begin();
…
// 啟用LSM303AGR
Acc = new LSM303AGR_ACC_Sensor(&Wire);
Mag = new LSM303AGR_MAG_Sensor(&Wire);
…
// 啟用TSL2540
tsl.begin();
…
// 啟用Initialize UnaMKR component
my_mkr.begin(PUBLIC_KEY_USAGE);
…
// 啟用Arduin MKRZERO Timer
zt4 = new Adafruit_ZeroTimer(4);
…
// Wake-up UnaMKR喚醒模組Sigfox 及晶片
my_mkr.wakeup();
…
// Get RC zone 讀取RC Zone
my_mkr.getZone();
…
// Update sensors 讀取感測器值
tmp = my_bme.temperature;
hmd = my_bme.humidity;
prs = my_bme.pressure;
gas = my_bme.gas_resistance;
…
// Setup message (payload)將資料填入Payload
UnaMkrMessage msg;
msg.clear();
msg.setTimeout(TIME_WAIT_UPLINK);
msg.addField_Acceletometer(acc);
msg.addField_Magnetometer(mag);
…
// Uplink with message type of payload上傳資訊
Serial.println("Sigfox uplink... ");
my_mkr.uplink(&msg);
…
// Sleep mode 將Sigfox 晶片進入睡眠模入
my_mkr.sleep();
//等待模組回應 "OK\r\n",TIME_WAIT_RESPONSE: timeout 時間(ms)
my_mkr.getData_CheckOk(TIME_WAIT_RESPONSE);
…
// Done結束程式廻圈並清除中斷旗標
Serial.println("\r\nDone");
clearInterrupt();

※更多說明請參考UnaBiz提供的UnaMKR Arduino 文件連結網站:https://unabiz.github.io/UnaMKR/#/30-Arduino

UnaMKR評測心得分享

感謝負責台灣與新加坡Sigfox營運的電信商優納比公司(UnaBiz)提供UnaMKR全頻段sigfox開發板供測試,一拿到所就迫不及待開箱,並乘著中秋連假開始不眠不休的玩。
這塊可結合Maker最易入手的Arduino MKRZERO開發板,輕易以積木式架構將UnaMKR完美組合,並以Arduino IDE加上精心提供的範例程式庫,跑完全部範例程式,真的只有3個字可以形容:”太棒了”。
因為篇幅的關係,更完整的應用範例介紹及結合短距BLE+長距Sigfox的混合應用,只能留等下一篇介紹。
親愛的Maker、物聯網開發商、Sigfox的愛用者,以及所有支持MAKERPRO社群及柯大創客屋的好朋友們,在此鄭重推薦Arduino MKRZERO + UnaMKR ,將是您實現物聯網創意的最完整套件開發組合。

#IoT #物聯網 #sigfox #LPWAN #KODA






你可能感興趣的文章

GraphQL Summit 2019 與會分享

GraphQL Summit 2019 與會分享

k-means Clustering 介紹

k-means Clustering 介紹

Day1它被稱為終端機

Day1它被稱為終端機






留言討論