GATT clientのサンプルコードを書き換えて、前回作成したGATT serverに接続して、notifを取得できました。
方法を共有します。
使ったもの
- ESP32モジュール2つ
- esp-idfをインストールしたPC
- シリアルモニタプログラム
ログの確認に使いました。
ubuntuのscreenコマンドを利用しました
GATT server
前回の投稿で作成したプログラムを利用しています。詳しくはこちらをご覧ください。
プログラム: esp32-idf-samples/gatt_server_notif_switch/main/gatt_server_notif_switch.c
記事: ESP32からBLE GATTのnotifを発信し、nodejs(noble)で受信する方法
GATT client
利用したプログラムはこちらです。esp32-idf-samples/gatt_client_listen_notif_then_output_to_led/main/gattc_demo.c
このプログラムは、esp-idfのgatt clientに関するサンプルプログラムの一部を変更したものです。
変更内容を説明します。
通知を受け取るGATT serverに合わせて設定変更
device_name, service_id, characteristic_idをそれぞれGATT serverとして利用するデバイスに合わせます。今回は下記デバイスのnotifを受信します。
自作デバイスのnotif発信情報
device_name: ESP_GATTS_SWITCH
service_id: 0xff
characteristic_id: 0xff01
上記の設定を反映するために、編集を定義・編集します。
static esp_gatt_srvc_id_t alert_service_id = { .. .uuid = {.uuid16 = 0xff,}, //origin: 0x1811 .. }; static uint16_t listen_char_id = 0xff01; static const char device_name[] = "ESP_GATTS_SWITCH"; //origin: "Alert Notification"
gatt_profile_a_event_handlerの内容を、先程定義した変数に変更します。
static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { .. case ESP_GATTC_GET_CHAR_EVT: .. if (p_data->get_char.char_id.uuid.uuid.uuid16 == listen_char_id ) { //origin: 0x2a46 .. .. }
これで、自作したデバイスのnotifを受信できるようになりました。
受け取った通知の内容に応じて、LEDを光らせるための変更
ログを確認しなくても通知の受信を確認したいので、下記のように動作させとうと思います。通知の値が0: LEDをON
通知の値が1: LEDをOFF
GPIOを使うためのライブラリと定数を宣言します。
#include "esp_system.h" #define GPIO_OUTPUT_IO_0 2 // for LED #define GPIO_OUTPUT_IO_1 19 #define GPIO_OUTPUT_PIN_SEL ((1<<GPIO_OUTPUT_IO_0) | (1<<GPIO_OUTPUT_IO_1))
初期化とLEDの操作のための関数を定義します。
static void init_led() { gpio_config_t io_conf; //disable interrupt io_conf.intr_type = GPIO_PIN_INTR_DISABLE; //set as output mode io_conf.mode = GPIO_MODE_OUTPUT; //bit mask of the pins that you want to set io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //disable pull-down mode io_conf.pull_down_en = 0; //disable pull-up mode io_conf.pull_up_en = 0; //configure GPIO with the given settings gpio_config(&io_conf); printf("led initlalized"); } static void switch_led(bool value) { int out_value = 0; if (value) { out_value = 1; } printf("out value %d\n", out_value); gpio_set_level(GPIO_OUTPUT_IO_0, out_value); }
通知がきたら、値に応じてLEDの光り方を変化させます。
static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { .. case ESP_GATTC_NOTIFY_EVT: switch_led(0 == (*(uint32_t *)p_data->notify.value % 2)); .. }
定義した初期化の関数をmainで呼びます。
void app_main() { .. init_led(); }
これで、受信した通知の値によってLEDの光り方が変わるようになりました。
プログラムの書き込み
GATT clientとして動作させたいESP32をPCに接続して、下記のコマンドでプログラムを書き込みます。cd [this gatt client project directory] make flash
動作確認
それぞれのデバイスを単体で動作させると、何が起きているのか分かりにくいので、うまく動かない時はログを見ながら動作確認することをお勧めします。ubuntu環境下では、ターミナルを2つ立ち上げ、それぞれでscreenコマンドを起動すると、2つのESP32からのログを確認できます。
ターミナルで下記のコマンドを実行します。
screen /dev/ttyUSB0
別ターミナルで下記のコマンドを実行します。
screen /dev/ttyUSB1
GATT接続が成功した時のログはこのような感じです。
左がGATT client、右がGATT serverです。
GATT serverのスイッチを押すと、双方のログが更新されると共に、GATT clientのLEDが点灯します。
共有する情報は以上です。
参考
how to send BLE notification to clientGATT SERVER API: esp_ble_gatts_send_indicate
変更履歴
2017.04.26デバイス名比較に関する修正が反映されたので、それに関する記述を削除しました。
参考にさせて頂いています。どうもありがとうございます。
返信削除タクトスイッチ以外で、条件でClientのLEDを点灯させるのに
以下のような文で動作させようとしましたが、コンパイルはできても動作はしませんでした。
if (adc1_get_voltage(ADC1_TEST_CHANNEL) > 3000) {
ble_indicate(1);
}
どのような文にすればいいか教えていただけませんか?
宜しくお願いします。
コメントありがとうございます。
削除原因は分かりませんが、自分だったら下記の確認をしてみます。
1. adc1_get_voltageは期待する値を取得しているのでしょうか?
adcとして期待する値が取れていないのかもしれません。
下記のような記述でadcの値をprintして、シリアルモニタで確認してみてください。
printf("adc_value: %d\n", adc1_get_voltage(ADC1_TEST_CHANNEL));
2. adc1のピンは合っていますか?
adc1は(2017/8/24時点では)下記のように、不規則にピンが割り当てられているようです。
ACD1_CHANNEL: GPIO
0: 36
1: 37
2: 38
3: 39
4: 32
5: 33
6: 34
7: 35
参考: esp-idf: Analog to Digital Converter #adc1_channel_t
どうでしょう?
ご回答どうもありがとうございました。
削除説明が不足しておりました。
IO_32に3.3Vを接続したところ
The adc1 value:4095..
と表示されますので、期待される値(>3000)を取得しているようです。
それよりも、BLE Sever側から BLE Client側のIO_2のLEDを光らせるトリガーの呼び出しがうまくいかないようです。
ble_indicate(1);
ではClient側のLEDは光らせられないのでしょうか?
gpio_task;
でも
237:3: error: statement with no effect [-Werror=unused-value]
gpio_task;
^
cc1.exe: some warnings being treated as errors
のようなエラーがでてコンパイルできませんでした。
宜しくお願いします。
電圧は期待通り計測できているようで良かったです。
削除gpio_taskは引数を1つ取る関数なので、「gpio_task(true);」のように記述すると、コンパイルはできると思います。
しかし、想定していない呼び出し方なので期待通りに動くかは分かりません。
この記事はgatt_serverから信号を送り、gatt_clientのLEDを光らせますが、それができないということですよね?
先程自分が公開している下記のコードの組み合わせで記事の内容を実現しようとしたところ、esp-idfのアップデートに対応していなくて動きませんでした。
(具体的にはGATTとして接続出来ませんでした。)
gatt_server_gpio_notif
gatt_client_listen_notif_then_output_to_led
修正を試みましたが、思っていたよりも比較する項目が多く、すぐには対応できません。
そのため、自分の修正を気長にお待ちいただくか、ご自身で試行錯誤される必要がありそうです。
(お急ぎでしたら、技術支援の業務として自分にプログラムの修正を依頼するという手もあります。)
お手数をおかけします。
ご回答どうもありがとうございます。
返信削除gatt_server側でADCからのデータを受信して、そのデータが所定の数値を超えていたら、gatt_client側のLEDを光らせたいと思いました。
最初の書き込みで
ble_indicate(1);
と書いていましたが、考えてみると、IO_0はたくとスイッチでGNDに接続されていましたので、ONは「1」ではなく、「0」ではないかと思い
ble_indicate(0);
と書き込んだところ、無事LEDは光りました。どうもありがとうございました。
わからないところがありましたら、また質問させていただくことがあると思いますが、よろしくおねがいします。
期待通りに動いたようで良かったです。
削除自分の知っていることや、30分位の調査で分かることでしたら、お答えしますので、よろしくお願いします。
了解しました。ご回答どうもありがとうございました。
返信削除先日、無事gatt serverからclientにスイッチ信号を送れて、目的は達成したのですが、今度はclientからのスイッチ信号をserver側に送りたいという要望を受けました。
返信削除esp_ble_gatts_send_indicateはserver側の関数であり、client側の関数を探しましたが、見つかりませんでした。ご存知でしたらお教え願います。
宜しくお願いします。
下記のプログラムを使い、「PCのnodejsプログラムをclient」「ESP32をserver」としてclientからserverの情報送信をしたことはあります。
削除そのため、「clientでwrite」「serverでwriteされた値の読み取り」をすれば、期待する動作を実現できると思います。
write-and-listen.js
gatt_server_gpio_notif.c
上記のnodejsのプログラムでしているwriteをESP32にさせればよいのですが、ここで問題になるのが、clientのwriteに関する関数の使い方がよく分からないことです。
下記のドキュメントにwrite関数は示されているのですが、esp-idfのexamplesをザックリ探してみてもwriteをしている箇所が見つからないため、使い方に関する試行錯誤が必要になりそうです。
GATT_CLEINT_API
自分の持っている情報は以上です。
いかがでしょう?
ご回答どうもありがとうございます。
削除以下のサイトの
https://github.com/asukiaaa/esp32-idf-samples/tree/master/gatt_client_car_controller
gattc_demo.c
の中にある。
esp_ble_gattc_write_char(
gattc_if_to_write,
conn_id_to_write,
&srvc_id_to_write,
&write_descr_id,
sizeof(sending_values),
(uint8_t *) sending_values,
ESP_GATT_WRITE_TYPE_RSP,
ESP_GATT_AUTH_REQ_NONE);
は参考にならないでしょうか?
情報ありがとうございます。
削除自分が書いたプログラムなのに、すっかり忘れていました。
はい、そのプログラムのように、接続したBLEデバイスの情報を変数として保持し、esp_ble_gattc_write_charで利用すれば、clientからserverに対して情報を渡せます。
自分はそのプラグラムでラジコンのコントローラを作りました。
なにか似ているなぁと思ったら、asukiさんが書かれたプログラムでしたか、納得です。
削除参考にさせていただきます。どうもありがとうございました。
うまくいくと良いですね。
削除(雰囲気が似ているのはesp-idfのサンプルコードをベースに作っているからかもしれません。)
asuki 様
削除「MPU9250_asukiaaa.h」
が見つからないようなのですが、どのようなファイルかご存知でしたらお教え願います。
宜しくお願いします。
ここにあります。
削除gatt_server_car/main
しかし、それはMPU9250という9軸センサを操作するためのプログラムなので、該当する部分を削除して実行されるのが良いと思います。
ご回答どうもありがとうございました。
削除ところで3軸センサというのは聞いたことがありますが、9軸センサーというのは初耳です。前後左右上下+ヨーイング+ローリング+ピッチングですか?
加速度3軸(前後左右上下)+ ジャイロ3軸(ヨーイング、ローリング、ピッチング)+ 磁気センサ3軸のようです。
削除mpu9250 - Google検索
なるほど、磁気センサも含まれていましたか、
返信削除ちなみに本日、ESP32の双方向プログラムのタタキ台ができました。
ご助言どうもありがとうございました。
それは良かったです。
削除