October 29, 2020 THETA Plug-in IFTTT

Time Recording with THETA Plug-in and IFTTT (Introductory Edition)

Time Recording with THETA Plug-in and IFTTT (Introductory Edition)

Introduction

Hello, this is @yomura_ from RICOH.

I’ve made a simple time recording mechanism with the RICOH THETA plug-in and IFTTT.

I’m starting with an introductory edition.

IFTTT

About RICOH THETA Plug-ins

For those who are not familiar with THETA plug-ins, please see here.

About IFTTT

IFTTT is a service that connects external services in the form of IF This Then That, and handles a variety of services from SNS to IoT devices.

In this article, This is called a trigger, That is called an action, and the combination of two is called an applet.

I have created an applet that performs the action of adding a new row to Google Sheets, by using the Webhooks service as a trigger.

Creating an Applet

An applet is created following the steps below.

  • Create a new applet from https://ifttt.com/create
  • Select this (trigger) in Webhooks
    • Select Receive a web request and input Event Name
    • This time, I used theta_button_pressed (This name will be used later.)
  • Select  Google Sheets for that (action)
  • Select Add row to spreadsheet, and input each item (Formatted rows will be mentioned later)

This completes the creation of an applet that adds a row to the spreadsheet when sending POST to the specified URL.

add row

About Formatted Rows

The format of a row to be recorded can be changed. In addition, the following 5 variables can be embedded.

  • OccurredAt: Event occurrence time (recording this is the purpose of this blog.)
  • EventName: Event name when creating a Webhook trigger.
  • Value1: arbitrary value
  • Value2: arbitrary value
  • Value3: arbitrary value

formatted row

Implementation

This time, I used POST to the URL which triggers the IFTTT applet and the action to execute.

The sample source code for this plug-in is available on GitHub.

WebhookTast

WebhookTast.kt

package com.theta360.iftttsample.task

import android.util.Log

import com.google.gson.Gson
import com.google.gson.JsonObject
import okhttp3.*

import java.net.HttpURLConnection.HTTP_OK

class WebhookTask(private val url: String) {

    private val httpClient = OkHttpClient()

    fun request(): Boolean {

        val body = JsonObject().apply {
            addProperty("value1", "hoge")
            addProperty("value2", "fuga")
            addProperty("value3", "piyo")
        }

        val requestBody = RequestBody.create(
                MediaType.parse("application/json; charset=UTF-8"), GSON.toJson(body))
        val request = Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("Accept", "application/json")
                .addHeader("X-XSRF-Protected", "1")
                .build()

        Log.d(TAG, "START - http request")
        val response = httpClient.newCall(request).execute()
        Log.d(TAG, "FINISH - http request")

        Log.d(TAG, "Status code: ${response.code()}")
        val responseBody = response.body()
        if (responseBody != null)
            Log.d(TAG, responseBody.string())
        return response.code() == HTTP_OK
    }

    companion object {
        private val TAG: String = WebhookTask::class.java.simpleName
        private val GSON = Gson()
    }
}

Add Arbitrary Character String

A character string in the spreadsheet can be recorded by specifying the character string in value1, value2, value3 keys in JSON in the request body.

I couldn’t think of a good way to use this, so it looks like this.

val body = JsonObject().apply {
    addProperty("value1", "hoge")
    addProperty("value2", "fuga")
    addProperty("value3", "piyo")
}

MainActivity

MainActivity.java

package com.theta360.iftttsample;

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import com.theta360.iftttsample.task.TakePictureTask;
import com.theta360.iftttsample.task.TakePictureTask.Callback;
import com.theta360.iftttsample.task.WebhookTask;
import com.theta360.pluginlibrary.activity.PluginActivity;
import com.theta360.pluginlibrary.callback.KeyCallback;
import com.theta360.pluginlibrary.receiver.KeyReceiver;
import com.theta360.pluginlibrary.values.LedColor;
import com.theta360.pluginlibrary.values.LedTarget;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class MainActivity extends PluginActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final String WEBHOOK_KEY = "write ifttt webhook key here";
    private static final String WEBHOOK_EVENT_NAME = "write ifttt webhook event name here";
    private static final String WEBHOOK_URL = "https://maker.ifttt.com/trigger/" + WEBHOOK_EVENT_NAME + "/with/key/" + WEBHOOK_KEY;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private AtomicBoolean isProceeding = new AtomicBoolean();
    private WebhookTask webhookTask = new WebhookTask(WEBHOOK_URL);

    private TakePictureTask.Callback mTakePictureTaskCallback = new Callback() {
        @Override
        public void onTakePicture(String fileUrl) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Set enable to close by pluginlibrary, If you set false, please call close() after finishing your end processing.
        setAutoClose(true);
        // Set a callback when a button operation event is acquired.
        setKeyCallback(new KeyCallback() {
            @Override
            public void onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
                    /*
                     * To take a static picture, use the takePicture method.
                     * You can receive a fileUrl of the static picture in the callback.
                     */
//                    new TakePictureTask(mTakePictureTaskCallback).execute();
                    if (isProceeding.get()) {
                        Log.d(TAG, "Skip to post webhook.");
                        return;
                    }
                    executor.submit(() -> {
                        isProceeding.set(true);
                        notificationAudioOpen();
                        try {
                            if (webhookTask.request()) {
                                Log.d(TAG, "Succeeded to post webhook.");
                                notificationAudioClose();
                            }
                        } catch (Exception e) {
                            Log.e(TAG, "Failed to post webhook.", e);
                            notificationAudioWarning();
                        } finally {
                            isProceeding.set(false);
                        }
                    });
                }
            }

            @Override
            public void onKeyUp(int keyCode, KeyEvent event) {
                /**
                 * You can control the LED of the camera.
                 * It is possible to change the way of lighting, the cycle of blinking, the color of light emission.
                 * Light emitting color can be changed only LED3.
                 */
                notificationLedBlink(LedTarget.LED3, LedColor.BLUE, 1000);
            }

            @Override
            public void onKeyLongPress(int keyCode, KeyEvent event) {

            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (isApConnected()) {

        }
    }

    @Override
    protected void onPause() {
        // Do end processing
        //close();

        super.onPause();
    }
}

Webhook Key and Event Name Setting

It is necessary to include the IFTTT Webhook key and Webhook event name in the URL.

For WEBHOOK_EVENT_NAME, enter the Event Name that was set when the applet was created.

WEBHOOK_KEY can be verified from Documentation at https://ifttt.com/maker_webhooks

private static final String WEBHOOK_KEY = "write ifttt webhook key here";
private static final String WEBHOOK_EVENT_NAME = "write ifttt webhook event name here";

Executing a Task

Executors.newSingleThreadExecutor() was used for asynchronous processing.

Generate another thread with this executor and execute asynchronous processing.

import java.util.concurrent.ExecutorService;

public class MainActivity extends PluginActivity {
     private ExecutorService executor = Executors.newSingleThreadExecutor();
     ...

The created WebhookTask is executed inside the onKeyDown method.

With this, when the THETA shutter button is pressed, a POST request is sent to the specified URL.

executor.submit(() -> {
    isProceeding.set(true);
    notificationAudioOpen();
    try {
        if (webhookTask.request()) {
            Log.d(TAG, "Succeeded to post webhook.");
            notificationAudioClose();
        }
    } catch (Exception e) {
        Log.e(TAG, "Failed to post webhook.", e);
        notificationAudioWarning();
    } finally {
        isProceeding.set(false);
    }
});

Check During Task Execution

The AtomicBoolean type variable isProceeding is used as a flag to indicate that it is being processed. Because of this, if the KEYCODE_CAMERA event occurs before the task is completed, it will skip proceeding.

if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
    if (isProceeding.get()) {
        Log.d(TAG, "Skip to post webhook.");
        return;
    }
    ...

Execution Result

When THETA plug-in is activated and the shutter button is pressed, a row is added to the spreadsheet.

new row

Conclusion

In this blog, I have introduced pressing the THETA shutter button directly to record a new row in a spreadsheet.

My next challenge will be to find a different way from pressing the shutter button directly to record a new row in a spreadsheet.

Application 1: Combination with OpenCV

Because the image processing library OpenCV can be used with THETA, it would be convenient if it could detect the movement of people and record it to a spreadsheet.

If pictures are timed and used with motion detection to recognize people, it may be possible to easily manage entry and exit of a room.

More information here.

Application 2: Combination with the Bluetooth button

BLE (Bluetooth Low Energy) radio waves can be received by the THETA plug-in.

It appears that it can be used in various ways, such as recording when a smartphone is nearby.

More information here (in Japanese).