LoginSignup
4
3

More than 5 years have passed since last update.

QtアプリからIFTTT Webhooksのトリガを実行する

Last updated at Posted at 2018-05-06

1. 初めに

Qtアプリ(Qt5/C++)からIFTTTのWebhooksを叩いて、スマホにプッシュ通知するサンプルを紹介します。

IFTTTのWebhooksに関して、参考にしたサイトはこちらです。
クライアントであるQtアプリからHTTP POSTを実行するサンプルを作ってみたくて作成しました。
ソースコードはgithubに置いてあります。
IFTTTに関しては、元ネタ記事をほぼ同じですが、1つの記事に完結していたほうが読みやすいと思ったので、キャプチャをペタペタ貼って説明しています。

<-- 2018/05/07 追記 start -->
Qtのサンプルに関して
投稿して1日経ち、やはりvalue1()などにデフォルト実装がないのはおかしい(value1だけ設定してvalue2やvalue3を使用しない場合を考慮できていない)為、デフォルト実装を入れるよう実装を変えました。
混乱させてしまい申し訳ありません。
<-- 2018/05/07 追記 end -->

1.1. 動作確認環境

2. 動作

IFTTTやプログラムの説明をする前に、動作の説明をします。
Qtアプリを実行すると、
qt_ifttt_app.png
という画面が立ち上がります。
このアプリの「POST Request」ボタンを押下すると、
qt_ifttt_app2.png

が表示され、その後、POSTリクエストが正常に終了すると、

qt_ifttt_app3.png

が表示されます。
スマホ側では、Notificationで、
eventOccurred.png
のように通知されます。
「hello」というイベントが発生し、Value1、Value2、Value3にそれぞれ、test1、test2、test3というパラメータが設定されているのが確認できます。

3. IFTTTの設定

ブラウザを開きます。(Internet ExplorerはNGのようです。本記事の操作はGoogle Chromeを使用しています)
IFTTTにSign Inして、アプレットの作成を行います。

3.1. アプレット作成

メニューの「My Applets」から、「New Applet」(スマホアプリだと「+」ボタン)を押下します。
すると、下記のような画面が表示されます。
ifttt_newapplet.png

3.1.1. トリガ(this)

まず、thisを選択し、検索バーで「web」を入力して、
ifttt_webhooks.png

を選択します。
次に、
ifttt_webhooks2.png

を選択します。

すると、イベント名を入力する画面になりますので、入力します。
ここでは、元ネタ記事と同じように「hello」とします。

ifttt_event_name.png

入力後、「Create trigger」を押下します。

3.1.2. アクション(that)

thatを選択後、検索バーで「noti」を入力し、

ifttt_notifications.png

を選択します。
次に、

ifttt_notifications2.png

を選択します。
次に、

ifttt_notifications3.png

の画面で、Messageを下記のように入力します。

ifttt_notification4.png

使用できるパラメータは、「Add ingredient」ボタンを押下して入力するのが確実です。
入力後「Create action」ボタンを押下します。
その後、「Finish」ボタンを押下すればアプレット作成完了です。

3.2. IFTTT webhooksの動作確認

作成したアプレットを選択し、左上のマークを押下します。

webhooks1.png

次に、右上の「Documentation」ボタンを押下します。

webhooks2.png

すると、次の表示されます。

この画面は、どうやってWeb APIを叩いてよいのかの全てが説明され、試しに動作確認までできる、かなりわかりやすいページです。

webhooks3.png

Webhooks APIのURLに設定する要素は下記の5つです。

  • イベント名
  • アクセスKey
  • value1
  • value2
  • value3

※IFTTTのアプレット作成画面だとvalue1はValue1と表示されていますが、URLのパラメータとしては全部小文字の名前になります。

Your Key isのところにアクセスキーが記述されていますので、これをメモっておきます。(Qtのプログラムで使用します。)
ついでに、アプレットの動作確認をします。
赤字の部分に各パラメータに設定したい値を入力し、「Test It」ボタンを押下します。
すると、Qtアプリの代わりに、トリガが発生します。
アクションが実行されたことをスマホで確認したら、ブラウザ上での操作は終了です。

4. Qtアプリの実装

IFTTTにアクセスするクラスをして作成したのは、

  • IftttAccessManagerクラス
  • IftttTestクラス(IftttAccessManagerクラスの子クラス)

の2つです。

4.1. IftttAccessManagerクラス

IFTTT Webhooksにアクセスする仕組みを定義したクラスです。
IftttAccessManagerクラス自身では、下記コードのように、QNetworkAccessManagerを使用してPOSTしています。

プロジェクトファイルに

IftttSample.pro
QT += network

の設定をすれば使用できるようになります。

ifttttest.cpp
IftttAccessManager::IftttAccessManager(QObject *parent) : QObject(parent)
{
    m_networkManager = new QNetworkAccessManager(this);
}

void IftttAccessManager::requestPost()
{
    QUrl url("https://maker.ifttt.com/trigger/" + eventName()
             + "/with/key/" + webhooksKey());
    QUrlQuery postData;
    QString value1Str = value1();
    if (!value1Str.isEmpty()) {
        postData.addQueryItem("value1", value1Str);
    }
    QString value2Str = value2();
    if (!value2Str.isEmpty()) {
        postData.addQueryItem("value2", value2Str);
    }
    QString value3Str = value3();
    if (!value3Str.isEmpty()) {
        postData.addQueryItem("value3", value3Str);
    }
    url.setQuery(postData);
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader,
        "application/x-www-form-urlencoded");
    m_networkReply = m_networkManager->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());
    connect(m_networkReply, &QNetworkReply::finished, this,
            [=](){
        if (m_networkReply->error()) {
            emit postFinished((m_networkReply->errorString()));
        } else {
            emit postFinished("POST finished");
        }
        m_networkReply->deleteLater();
    });

カスタマイズできる5つのパラメータについては、デザインパターンのTemplate Methodパターンで、子クラスに設定させます。

ifttttest.h
protected:
    virtual QString value1();
    virtual QString value2();
    virtual QString value3();
    virtual QString webhooksKey() = 0;
    virtual QString eventName() = 0;

※Template Methodパターンについて補足
Template Methodパターンでは子クラスに設定させる要素を必ずしもpure virtualにしなければならないわけではありません。virtualだけ付けて( =0 を付けずに)、親クラスでデフォルト設定を記述しておく場合もあります。今回の例ではvalue1()関数などがそれに当たります。(value1Str.isEmpty()で判定する為にデフォルト実装で空文字を返します)
Template Methodパターンは、必ずpure virtualにしなければならないと勘違いしている人(というかソースコード)を見かけたことがあるので、もしそういう人が近くにいたら教えてあげてほしいです。
pure virtual関数をOverrideした子クラスの関数の中身が全て同じだったという悲しいコードはあまり見たくないです。。。

4.2. IftttTestクラス

今回動作確認用のパラメータを記述したクラスです。
webhooksKey()は、3.2.項でメモっておいたKeyを設定してください。

ifttttest.cpp
QString IftttTest::value1()
{
    return "test1";
}

QString IftttTest::value2()
{
    return "test2";
}

QString IftttTest::value3()
{
    return "test3";
}

QString IftttTest::webhooksKey()
{
    return "Your Key";
}


QString IftttTest::eventName()
{
    return "hello";
}

4.3. コードを記述している時に気づいたこと

QNetworkAccessManager周りはQt4→Qt5に移行している内に仕様が変わったようです。
2点気づいたことがあります。

1つ目は、パラメータを設定する為のQUrl::addQueryItem()がDuplicatedになっており、Qt5.10.1ではビルドすら通らないことです。
代わりに、QUrlQuery::addQueryItem()を使用するようです。
詳しくは、Stack Overflowの記事を参照してください。

2つ目は、エラーハンドリングについてです。
最初、QNetworkAccessManager::finish()シグナルをキャッチし、引数のQUrlQuery *replyから
reply->error()でエラーかどうかを判断するつもりだったのですが、判断できませんでした。
「https」を「htps」に変更してエラー処理の動作確認を行いましたが、No Errorが返ってきます。
ここを見る限りできそうだったのですが、仕様が変わったのでしょうか?

そこで、本サンプルのようにpost()関数の返り値であるQNetworkReplyから判断します。
このpost()関数の返り値で返ってきたQNetworkReplyは自分でdeleteする必要がある為、エラーかどうかを確認後、QNetworkReply::deleteLater()を呼んでいます。

5. 最後に

いかがでしたでしょうか。
QNetworkAccessManagerを使用すれば、わりと簡単にクライアント側のPOSTのコードを書け、IFTTTを使用すれば、サーバ側の動作も簡単に実装することができることがわかりました。
ネットワークプログラムというと、どうしても(特にクライアントサイドのプログラムを書いている人には)ハードルが高いというイメージがありますが、作ってみればそう難しいことではないと思います。
Gitに登録してから、

  • 可変パラメータは全て画面で設定できるようにしておけば、もっとかっこいいサンプルになったとか
  • よく考えれば、value1、value2、value3はpure virtualにしなくてよくね?ということに気づいたりとか・・・

まあ、この辺りで勘弁してくださいm(_ _"m)

読者様の参考になれば幸いです。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3