THETA V Bluetooth API Access Using Web Bluetooth API

After struggling with the Bluetooth API of the THETA V, I found this article in Japanese that explains how to use Web Bluetooth API to connect to the THETA V and take pictures. I haven’t been following the Web Bluetooth API standard and was surprised to see that there was decent compatibility in Chrome 56+ experimental. Firefox does not appear to support it yet.

The RICOH THETA Bluetooth API is well-documented, but I’ve been hesitant to experiment with it. Due to the lack of a getting started page.

Here’s a machine translation of the the getting started article by sakanasoft.


RICOH THETA V is compatible with BLE from the previous THETA series, and the range of application development has expanded more. Also, since Bluetooth API specifications are released by Bluetooth Reference API & SDK | RICOH THETA Developers , we will use this to shoot.

Web Bluetooth API

Platforms that can easily test Bluetooth devices, especially desktop PCs are unexpectedly small, and in Windows it seems that it is a fairly developing field because it seems that Windows API barely exists in UWP.

In this time, if it is Chrome of macOS, I found sample Web based on Web Bluetooth API as standard. It seems that Chrome (Google OS / macOS / Android / Linux) is compatible with Web Bluetooth API (as of January 2018). The implementation status of each browser can be checked by web - bluetooth / implementation - status.md at master - WebBluetoothCG / web - bluetooth .

By the way Android Chrome tried it on Nexus 5 this time but we could pair it up but after that the connection did not go well so we may choose the device too. If you have succeeded, it is loosing information.

https Required

It seems that https is required to operate Web Bluetooth API. This time using Github Pages, if you publish it, https comes along without leakage and you can easily realize it, so create a scripted index.html. Please refer to the sample for Web Bluetooth API Sample for THETA V , source code is published in thetav-web-ble / index.html .

Sample code

I could write only elementary JS code, but I also try to use Vue.js as a study. The value is displayed reactively by referring to the connection status of the BLE device and the battery level.

View

<div id="app">
    <p><label>Device Name: <input v-model="deviceName"></label></p>
    <p><label>Auth UUID: <input v-model="authUUID"></label></p>
    <p>
        <button v-on:click="connect">Connect</button>
        <button v-on:click="takePicture">Take Picture</button>
        <button v-on:click="disconnect">Disconnect</button>
    </p>
    <p v-if="bluetooth.device">
        Device Status: Name: {{bluetooth.device.name}},
        Connected: {{bluetooth.device.gatt.connected}},
        Battery Level: {{deviceBatteryLevel}}
        </p>
    <p>{{message}}</p>
</div>

script

const BLUETOOTH_CONTROL_SERVICE = '0f291746-0c80-4726-87a7-3c501fd3b4b6'
const AUTH_BLUETOOTH_DEVICE_CHARACTERISTIC = 'ebafb2f0-0e0f-40a2-a84f-e2f098dc13c3'
const SHOOTING_STATUS_SERVICE = '8af982b1-f1ff-4d49-83f0-a56db4c431a7'
const BATTERY_LEVEL_CHARACTERISTIC = '875fc41d-4980-434c-a653-fd4a4d4410c4'
const SHOOTING_CONTROL_SERVICE = '1d0f3602-8dfb-4340-9045-513040dad991'
const TAKE_PICTURE_CHARACTERISTIC = 'fec1805c-8905-4477-b862-ba5e447528a5'

let bluetooth = window.navigator.bluetooth
let app = new Vue({
    el: '#app',
    data: {
        deviceName: '',
        deviceBatteryLevel: 0,
        authUUID: AUTH_BLUETOOTH_DEVICE_CHARACTERISTIC,
        bluetooth: {},
        message: ''
    },
    methods: {
        connect: async () => {
            let device = app.bluetooth.device = await bluetooth.requestDevice({
                filters: [
                    {name: app.deviceName}
                ],
                optionalServices: [
                    BLUETOOTH_CONTROL_SERVICE,
                    SHOOTING_STATUS_SERVICE,
                    SHOOTING_CONTROL_SERVICE
                ]
            })
            let server = app.bluetooth.server =
                await device.gatt.connect()
            let bluetooth_control_service =
                await server.getPrimaryService(BLUETOOTH_CONTROL_SERVICE)
            let auth_bluetooth_device_chacharacteristic =
                await bluetooth_control_service.getCharacteristic(AUTH_BLUETOOTH_DEVICE_CHARACTERISTIC)
            await auth_bluetooth_device_chacharacteristic.writeValue(new TextEncoder().encode(app.authUUID))
            app.message = `Device "${app.deviceName}" is connected.`
            let shooting_status_service =
                await server.getPrimaryService(SHOOTING_STATUS_SERVICE)
            let battery_level_characteristic = app.bluetooth.device.battery_level_characteristic =
                await shooting_status_service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC)
            let battery_level = await battery_level_characteristic.readValue()
            app.deviceBatteryLevel = battery_level.getUint8(0)
        },
        disconnect: async () => {
            await app.bluetooth.device.gatt.disconnect()
            app.message = `Device "${app.deviceName}" is disconnected.`
        },
        takePicture: async () => {
            let server = app.bluetooth.server
            let shooting_control_service =
                await server.getPrimaryService(SHOOTING_CONTROL_SERVICE)
            let take_picture_characteristic =
                await shooting_control_service.getCharacteristic(TAKE_PICTURE_CHARACTERISTIC)
            await take_picture_characteristic.writeValue(new Uint8Array([1]))
            app.message = "Take Picture is succeed."
        }
    }
})

Read the web Bluetooth API until shooting

I will explain the implementation of the Web Bluetooth API part until shooting.

window.navigator.bluetooth

let bluetooth = window.navigator.bluetooth

If the browser supports Web Bluetooth API, window.navigator.bluetooth exists.

requestDevice

let device = app.bluetooth.device = await bluetooth.requestDevice({
    filters: [
        {name: app.deviceName}
    ],
    optionalServices: [
        BLUETOOTH_CONTROL_SERVICE,
        SHOOTING_STATUS_SERVICE,
        SHOOTING_CONTROL_SERVICE
    ]
})

requestDevice prompts the user for device permissions. The pair setup dialog of the device detected by filters appears. In THETA V, name is specified by the 8-digit part of the serial number without alphabetic characters.

optionalServices specifies the service for which you want permission. Without this you can not read and write Characteristic, so you need to specify the Service to which the Characteristic to use in advance.

connect

 let server = app.bluetooth.server =
            await device.gatt.connect()

Connect to the Bluetooth device. GATT is the communication regulation of BLE by reading and writing Characteristic in Service and operating the device. Both Service and Characteristic identifiers are defined by UUID.

getPrimaryService

let shooting_control_service =
    await server.getPrimaryService(SHOOTING_CONTROL_SERVICE)

Browse the service. To get all services, call getPrimaryServices ().

getCharacteristic

let take_picture_characteristic =
    await shooting_control_service.getCharacteristic(TAKE_PICTURE_CHARACTERISTIC)

Refer to characteristic. If you want to refer to all the characteristic of the service, call getCharacteristics ().

readValue / writeValue

let battery_level = await battery_level_characteristic.readValue()
app.deviceBatteryLevel = battery_level.getUint8(0)

await take_picture_characteristic.writeValue(new Uint8Array([1]))

Read and write character restrictions. The value is treated as a byte string. If the string is THETA V, convert it to a byte string with utf 8s. Example when writing a device name:

await chacharacteristic.writeValue(new TextEncoder().encode(string))

Try THETA V by tapping on the Web Bluetooth API

Since BLE’s communication protocol itself is a simple mechanism of reading and writing binary strings character-richly, I thought that it would be difficult to implement until actually doing it, but if I could take a picture relatively smoothly It was possible to arrive at. Three APIs for USB MTP, Wi-Fi OSCv 2, BLE GATT were provided for THETA V, but I think that the ease of sticking is positioned between MTP and OSC.

Also, unfortunately with the THETA V’s Bluetooth API, it is necessary to turn on the power to shoot, but THETA V has sleep. Of course it is impossible to shoot in that state, but BLE seems to be able to connect and it seems that the API specification to wake up the camera body from here is not released yet. It seems that it happens in the official smartphone application, so it seems that the API exists and the appeal of BLE at the time is reduced by half, so I hope to have a prompt release as soon as possible.

2 Likes