BLE to Ethernet Thin Gateway 만들기

Posted by 카이젠8501 카이젠8501
2016.11.24 14:04 IoT/BLE Module

본 포스팅에서는 BLE(Bluetooth Low Energy)로 수집된 데이터를 Ethernet을 통해 Cloud Server에 전달하기 위한 Data Collector를 구현하는 방법에 대해 설명한다.

시스템 구성

본 시스템은 아래 그림과 같이 Data Sender, Data Collector, Cloud Server로 구성되어 있다. Data Sender는 Heart Rate(심장박동)과 Battery Level을 측정하여 Data Collector로 전달하는 역할을 한다.

Data Sender의 Software는 Nordic에서 제공하는 ble_app_hrs_s110 예제를 변경 없이 사용하였으며 측정되는 Heart Rate와 Battery Level은 가상으로 만든 자료 이다.

Data Collector는 Data Sender가 송신하는 데이터를 수집하고 수집된 데이터를 Cloud Service(본 예제에서는 dweet.io를 사용함)에 전달하는 역할을 한다. Data Collector의 Software는 Nordic에서 제공하는 ble_app_hrs_c_s120 예제를 기반으로 W5500을 사용하기 위한 코드와 Cloud Service에 데이터를 송신하는 코드를 추가 하였다.

Cloud Service는 dweet.io를 이용하였으며, dweet.io에 대한 자세한 내용은 아래 링크를 참고 하기 바란다.
http://dweet.io/

20160111_162525

하드웨어 구성

Data Sender

Data Collector

Debugging Log를 확인 하기 위한 UART to USB Module과 Ethernet을 사용하기 위한 WIZ550io를 아래 그림과 같이 연결한다.

20160111_182139

nRF51 DK Pin WIZ550io Pin
P0.01 J1.3 MOSI
P0.03 J1.4 MISO
P0.04 J1.5 SCLK
P0.02 J1.6 SCSn
VDD J1.7 VDD(3.3V)
GND J1.1 GND

소프트웨어 구성

Download nRF51 SDK

https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v10.x.x/
nRF51 SDK 개발환경 설정에 대한 자세한 내용은 링크를 참고 하기 바란다.

Github Repository에는 Data Sender와 Data Collector에 대한 Eclipse Project 및 소스 파일들이 공유 되어 있다. Github Repository에서 nRF51_SDK10.0.0_Example을 다운로드 한 후,해당 파일들을 아래 경로로 복사 한다.

ble_app_hrs : <SDK>/examples/ble_peripheral
ble_app_hrs_c_with_W5500 : <SDK>/examples/ble_central

Data Sender

(1) 개발 환경 설정

Import Existing Project

  • [import]-[Existing Projects into Workspace]
  • Select root directory
<SDK>/examples/ble_peripheral/ble_app_hrs/pca10028/s110/armgcc

(2) Upload SoftDevice

20160112_105834

(3) Upload Application

20160112_105849

Data Collector

(1) 개발 환경 설정

Import Existing Project

  • [import]-[Existing Projects into Workspace]
  • Select root directory
<SDK>/examples/ble_central/ble_app_hrs_c_with_W5500/pca10028/s120/armgcc

(2) Upload SoftDevice

20160112_105310

(3) Upload Application

20160112_105337

주요 코드 설명(Data Collector)

#define PUBLISH_INTERVAL                 APP_TIMER_TICKS(300, APP_TIMER_PRESCALER)

int main(void)
{
    bool erase_bonds;
    uint32_t err_code;

    // Initialize.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, NULL);

    buttons_leds_init(&erase_bonds);
    uart_init();
    printf("Heart rate collector example\r\n");

    spi0_master_init();
    user_ethernet_init();

    app_mailbox_create(&hr_data_mailbox);
    app_mailbox_create(&bas_data_mailbox);

    ble_stack_init();
    device_manager_init(erase_bonds);
    db_discovery_init();

    hrs_c_init();
    bas_c_init();


    // Start scanning for peripherals and initiate connection
    // with devices that advertise Heart Rate UUID.
    scan_start();

    err_code = app_timer_create(&m_publish_data_timer_id, APP_TIMER_MODE_REPEATED, publish_data_handler);
    APP_ERROR_CHECK(err_code);
    err_code = app_timer_start(m_publish_data_timer_id,PUBLISH_INTERVAL,NULL);
    APP_ERROR_CHECK(err_code);


    for (;; )
    {
        power_manage();
    }
}
#define HR_EVT_MAILBOX_QUEUE_SIZE     10
#define BAS_EVT_MAILBOX_QUEUE_SIZE    10

typedef struct
{
    uint16_t evt_data;
    uint16_t dummy_data;
}hrs_c_evt_data;

typedef struct
{
    uint16_t battery_level;
    uint16_t dummy_data;
}bas_c_evt_data;

APP_MAILBOX_DEF(hr_data_mailbox, HR_EVT_MAILBOX_QUEUE_SIZE, sizeof(hrs_c_evt_data));
APP_MAILBOX_DEF(bas_data_mailbox, BAS_EVT_MAILBOX_QUEUE_SIZE, sizeof(bas_c_evt_data));

static any_port = 50000;
uint8_t dweet_io_ip[4] = {54,172,56,193};
uint16_t dest_port = 80;
#define THING         "Ble2Eth"
#define HEART_RATE     "heart_rate"
#define BATTERY     "battery"
static void publish_data_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    uint8_t sn = 0;
    uint32_t ret;
    uint8_t eth_data[512];
    hrs_c_evt_data hr_data;
    bas_c_evt_data batt_data;

    // Connect to server
    if(app_mailbox_length_get(&hr_data_mailbox) || app_mailbox_length_get(&bas_data_mailbox))
    {
        if(getSn_SR(sn) != SOCK_CLOSED)
        {
            close(sn);
            disconnect(sn);
        }
        while(getSn_SR(sn) != SOCK_CLOSED);

        if( ret = socket(sn, Sn_MR_TCP, any_port++, 0x00) != sn )
        {
            APPL_LOG("[PUBLISH]: Socket open failed, reason %d\r\n", ret);
            return;
        }

        if( ret = connect(sn, dweet_io_ip, dest_port) != SOCK_OK )
        {
            APPL_LOG("[PUBLISH]: Socket Connection failed, reason %d\r\n", ret);
            return;
        }
    }
    else    return;

    // Publish collected data
    while( app_mailbox_length_get(&hr_data_mailbox) != 0)
    {
        app_mailbox_get(&hr_data_mailbox,&hr_data);
        sprintf(eth_data,"GET /dweet/for/%s?%s=%d HTTP/1.1\r\nHost: dweet. io\r\n\r\n",THING,HEART_RATE,hr_data.evt_data);
        send(sn,eth_data,strlen((uint8_t*)eth_data));
    }

    while( app_mailbox_length_get(&bas_data_mailbox) != 0)
    {
        app_mailbox_get(&bas_data_mailbox,&batt_data);
        sprintf(eth_data,"GET /dweet/for/%s?%s=%d HTTP/1.1\r\nHost: dweet. io\r\n\r\n",THING,BATTERY,batt_data.battery_level);
        send(sn,eth_data,strlen((uint8_t*)eth_data));
    }

    close(sn);
    disconnect(sn);
}

APP_TIMER_DEF(m_publish_data_timer_id);                                                /**< Publish data timer. */
/**@brief Heart Rate Collector Handler.
 */
static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt)
{
    uint32_t err_code;
    uint32_t test;
    hrs_c_evt_data hrs_c_data;

    switch (p_hrs_c_evt->evt_type)
    {
        case BLE_HRS_C_EVT_DISCOVERY_COMPLETE:

            // Heart rate service discovered. Enable notification of Heart Rate Measurement.
            err_code = ble_hrs_c_hrm_notif_enable(p_hrs_c);
            APP_ERROR_CHECK(err_code);

            printf("Heart rate service discovered \r\n");
            break;

        case BLE_HRS_C_EVT_HRM_NOTIFICATION:
        {
            APPL_LOG("[APPL]: HR Measurement received %d \r\n", p_hrs_c_evt->params.hrm.hr_value);
            hrs_c_data.evt_data = p_hrs_c_evt->params.hrm.hr_value;
            app_mailbox_put(&hr_data_mailbox,&hrs_c_data);
            break;
        }

        default:
            break;
    }
}


/**@brief Battery levelCollector Handler.
 */
static void bas_c_evt_handler(ble_bas_c_t * p_bas_c, ble_bas_c_evt_t * p_bas_c_evt)
{
    uint32_t err_code;
    bas_c_evt_data bas_data;

    switch (p_bas_c_evt->evt_type)
    {
        case BLE_BAS_C_EVT_DISCOVERY_COMPLETE:
            // Batttery service discovered. Enable notification of Battery Level.
            APPL_LOG("[APPL]: Battery Service discovered. \r\n");

            APPL_LOG("[APPL]: Reading battery level. \r\n");

            err_code = ble_bas_c_bl_read(p_bas_c);
            APP_ERROR_CHECK(err_code);


            APPL_LOG("[APPL]: Enabling Battery Level Notification. \r\n");
            err_code = ble_bas_c_bl_notif_enable(p_bas_c);
            APP_ERROR_CHECK(err_code);

            break;

        case BLE_BAS_C_EVT_BATT_NOTIFICATION:
        {
            APPL_LOG("[APPL]: Battery Level received %d %%\r\n", p_bas_c_evt->params.battery_level);
            bas_data.battery_level = p_bas_c_evt->params.battery_level;
            app_mailbox_put(&bas_data_mailbox,&bas_data);
            break;
        }

        case BLE_BAS_C_EVT_BATT_READ_RESP:
        {
            APPL_LOG("[APPL]: Battery Level Read as %d %%\r\n", p_bas_c_evt->params.battery_level);
            break;
        }

        default:
            break;
    }
}

Cloud Service(dweet.io)에서 데이터 확인하기

무료 버전의 dweet.io는 디바이스로 부터 수신한 데이터를 별도의 데이터베이스에 저장하지 않고 웹 브라우저에 출력하는 구조로 동작한다.
때문에 별도의 설정이나 Key 값이 없이도 아래 그림과 같은 데이터를 확인 할 수 있다.
아래와 같은 데이터를 확인하기 위한 URL은 https://dweet.io/follow/Ble2Eth 이다. https://dweet.io/follow/ 뒤에 위 코드에서 설정한 THING 주소를 기입하면 된다.

20160112_125136

dweet.io에 대한 자세한 설명은 링크를 참고 하기 바란다.

저작자 표시
신고

'IoT > BLE Module' 카테고리의 다른 글

BLE to Ethernet Thin Gateway 만들기  (0) 2016.11.24
nRF51 SDK Eclipse 개발환경 구축  (0) 2016.11.24
이 댓글을 비밀 댓글로

SNS을 이용한 개인용 화재 경보 시스템 만들기

Posted by 카이젠8501 카이젠8501
2014.10.15 10:25 IT 개발/DIY 프로젝트

SNS을 이용한 개인용 화재 경보 시스템 만들기

본 포스팅에서는 집 안 온도가 임계치 이상으로 올라가면 구조 요청 메시지를 Facebook으로 올리는 개인용 화재 경보 시스템을 만드는 방법을 설명한다.

시스템 구성

본 포스팅의 화재 경보 시스템의 구성요소는 아래와 같다.

  • Sensor Device

    • 집 안 온도를 측정 하여 Cloud Server에 송신
    • KL-25Z ( MCU Board, mbed enabled )+WIZ550io(Ethernet) + DS18B20(온도센서)로 구성
  • Cloud Server ( Xively )

    • Sensor Device로 부터 수집된 정보를 수집하고, 측정 값이 임계치 이상이면 Trigger를 발생하여 Proxy Server에게 전달
  • Proxy Server ( Zapier )

    • Cloud Server로 부터 Trigger 정보를 받으면, 등록된 Service로 Message를 Publish 함.
  • User Service

    • 본 포스팅에서는 Facebook을 이용하였지만, Zapier를 이용하면 gmail, twitter, evernote, tumblr, github등 다양한 Service를 이용 할 수 있음.

아래 그림은 위에서 설명한 요소들로 구성한 전체직인 시스템 Diagram이다.




Sensor Device

1. KL-25Z(mbed enabled MCU) + WIZ550io ( W5500 )

WIZ550io는 Arduino Board와 호환 되도록 설계 되어 있으며, KL-25Z 또한 Arduino Shield와 호환 되도록 설계 되어 있는 mbed Platform Board 이다.
이런 이유로, KL-25Z에서 WIZ550io를 이용하여 ethernet을 사용하기 위해서는 아래 그림과 같이 커넥터로 연결만 하면 된다.

커넥터 연결을 위한 자세한 설명은 [FRDM-KL25Z]WIZ550 ioShield-A Porting Guide를 참고 하기 바란다.

센서 보드의 연결을 위해 WIZ550io의 Shield 에 Female 커넥터를 아래 그림과 같이 부착 하였다.




2. DS18B20 ( Temperature Sensor )

온도 센서 DS18B20의 스펙은 아래와 같다.

  • Digital temperature conversion and output
  • Advanced single-bus data communication
  • Maximum 12-bit resolution, accuracy up to ±0.5 degrees Celsius
  • Parasitic mode available
  • Temperature detection range: -55 ° C ~ +125 ° C (-67 ° F ~ +257 ° F)
  • Built-in EEPROM and temperature limit

  • Supply Voltage: 3.3V to 5V

  • Temperature range :-55 °C ~ +125 °C
  • Interface: Digital
  • Size:22x32mm


위 사진은 DS18B20을 사용한 온도센서 모듈 사진이며, KL25Z + WIZ550io와는 아래 그림과 같이 연결 하면 된다.

  • 붉은선 : 3.3V VCC
  • 검은선 : GND
  • 녹색선 : D3



Xively Server 설정

Xively Server를 설정하기 위한 방법은 [Arduino Uno WiFi Shield]WizFi250과 Xively를 이용하여 온도 센서 모니터링 하기 (2/2)
2014/02]
를 참고 하기 바란다.

Sensor Device로 부터 수신 된 데이터 중 온도가 28ºC 이상이면, Facebook에 메시지를 전달하기 위해 Trigger를 아래와 같이 추가한다.
생성된 HTTP POST URL은 zapier 설정 시 사용해야 하므로, 잘 메모해 두길 바란다.



zapier 설정

  1. Login to zapier
  2. Make a New Zap
  3. Choose a trigger and action
    • When this Happens 카테고리에 Web Hook와 Catch Hook를 선택
    • Do This 카테고리에 Facebook과 Post to Timeline 선택
      • 다른 SNS를 사용하고 싶은 경우 Facebook 대신 다른 SNS Service를 선택하면 됨
  4. Select a Web Hook account
    • Xively에서 발급 받은 HTTP POST URL을 기입
  5. Facebook 계정 연결



  6. Trigger 발생 시, Facebook에 올릴 메시지 기입

  7. Test this Zap은 무시해도 무관하다.
  8. Name and turn this Zap on
    생성한 zap의 이름을 지정하고, Turn Zap on 버튼틀 클릭하여 zap을 활성화 시킨다.

    위 과정이 성공적으로 끝나면, 아래 사진과 같은 화면을 볼 수 있다.

Download Firmware

  1. Connect to mbed site and run mbed web compiler
  2. Import WIZ550io_Xively_Demo Example to mbed web compiler
    • WIZ550io_Xively_Demo Example 검색 후, Import program 버튼 클릭
    • WIZ550io_Xively_Demo Example를 Compiler의 Program workspace에 추가
       
  3. Xively에서 발급 받은 FEED ID와 API Key를 Source Code에 입력

    #define XI_FEED_ID xxxxxxxxxxxxxx // set Xively Feed ID (numerical, no quoutes)
    #define XI_API_KEY "xxxxxxxxxxx" // set Xively API key (double-quoted string)
    

    추가로, Xively Server에서 설정한 Channel ID의 값과 아래 코드에서 설정한 datastream_id 값은 동일 해야 한다.
    (본 예제에서는 Channel ID를 “Channel_Test1”으로 설정 함.)

    feed.datastreams[0].datapoint_count = 1;
    xi_datastream_t* orientation_datastream = &feed.datastreams[0];
    strcpy( orientation_datastream->datastream_id, "Channel_Test1" );
    xi_datapoint_t* current_orientation = &orientation_datastream->datapoints[0];
    
  4. Compile Source Code
    web compiler에서 compile을 클릭하면, 해당 Example에 대한 바이너리 파일이 아래와 같이 생성 된다.

  5. Download binary file to KL25Z board
    생성된 바이너리를 KL25Z Board의 Driver에 복사하면 Firmware Download가 완료 된다.
    자세한 내용은 자세한 내용은 [mbed]2.NUCLEO Board 구동하기 2/2 참고

Run Application

Sensor Board에 LAN Cable을 연결하고 전원을 인가하면, 온도 센서를 이용하여 온도를 측정 한 후, Xively Server에 데이터를 송신하는 과정을 Serial Terminal로 확인 할 수 있다.


Xively Server에서 데이터를 수신하면 아래 사진과 같이 Request Log로 Feed 값이 갱신 되는 것을 볼 수 있다.

또한 앞에 Trigger에서 설정한 것과 같이 온도가 28ºC 이상이 되면 zapier Server에 그 정보를 알리고, zapier는 등록된 서비스인 Facebook을 이용하여 메시지를 송신 한다.


저작자 표시
신고
이 댓글을 비밀 댓글로

[FRDM-KL25Z]WIZ550 ioShield-A Porting Guide

Posted by 카이젠8501 카이젠8501
2014.08.20 20:25 IT 개발/mbed


1. Hardware
WIZ550 ioShield-A는 Arduino Board에 호환되도록 설계되어 있는 Shield 형태의 WIZ550io Interface Board이다.
FRDM-KL25Z Board 역시, 기존의 Arduino Shield 들을 FRDM-KL25Z Board에서 그대로 사용할 수 있도록 Arduino Board의 Pin Map과 유사하게 설계되어 있으며, WIZ550 ioShield-A 역시 FRDM-KL25Z에 Shield 형태로 장착 하면 된다.

여기서 약간의 문제가 있는데..
Arduino Board의 경우 Board 하단에 6개의 핀(N_RESET, SCK, MISO, GND, MOSI, +5V)이 존재한다. WIZ550 ioShield-A의 SPI Pin들(MOSI,MISO,SCK 등)은 Board 하단에만 패턴이 연결되어 있다. 
이런 문제로 FRDM-KL25Z에 장착하기 위해서는 아래 그림과 같은 작업을 해야 한다. ( 곧, WIZ550 ioShield-A는 Revision 될 예정 임 )



위 작업을 마친 후, 아래 그림과 같이 FRDM-KL25Z 와 WIZ550 ioShield-A를 연결하면, FRDM-KL25Z Board에서 Ethernet을 사용 할 수 있다.


LG Electronics | LG-F320S | Center-weighted average | 1/30sec | F/2.4 | 0.00 EV | 4.0mm | ISO-50 | Flash did not fire | 2014:08:20 20:43:33



2. Software
이미 WIZ550io의 Library가 준비되어 있기 때문에, mbed Board에서 쉽게 사용 할 수 있다.

첫번째 단계로 mbed web Compiler에서 새로운 프로젝트를 생성한다.




다음 단계로, 생성된 프로젝트에 mbed Library를 추가 한다. ( mbed library는 FRDM-KL25Z를 구동하기 위한 Driver들이 구현되어 있다.)






다음 단계로, WIZ550 ioShield-A를 위한 W5500 Library를 내 프로젝트에 Import 한다.
Import를 위한 방법은 아래와 같다.

▼ mbed 홈페에지의 검색창에 W5500을 검색한다.



▼ 검색된 내용 중, W5500-Ethernet-Interface Makers 팀의 W5500Interface를 클릭한다.



▼ W5500Interface 페지이에서, Import this library를 클릭하면, Library를 추가할 프로젝트 리스트를 볼 수 있다.



▼ 출력된 리스트 중, 조금 전 생성한 프로젝트를 Target Path로 설정한 후 확인 버튼을 클릭 한다.







WIZ550 ioShield-A로 간단한 예제를 구동하기 위해 WebSocketClient library를 Import 하였다. import 방법은 W5500 Library와 동일 하다.







아래와 같이, 프로젝트에 main.cpp 파일을 생성하고 코드를 구현하면 끝.





아래는 main.cpp 파일의 내용이다. 



mbed Web Compiler에서 컴파일 후, 생성된 바이너리를 Board에 다운로드 하면 아래와 같이 mbed에서 제공하는 websocket 데모용 페이지에 데이터를 송/수신 하는 것을 확인 할 수 있다.




저작자 표시
신고
이 댓글을 비밀 댓글로