Remote bluetooth camera trigger for phone

Published

I would like to build a camera trigger for my phone by simulating a BLE keyboard that sends the Volume Up key to the phone connected by Bluetooth. I want this because I want to trigger the native Camera app, and not an embedded camera view.

I’m agnostic about technology used but ideally for simplicity I’d like it to be a command line utility in my Macbook, with something like Go or Node.js.

I’ve looked into Noble for Node.js, which doesn’t seem to be oriented at emitting, and found projects for arduino, and found a couple of StackOverflow questions asking the same, but nothing definitive yet.

Apparently the Bleno project for Node.js could be better suited, but apparently it’s very outdated.

Would someone please point me in the right direction?

Thank you

Edit

I was able to use Bleno to emit 0xEA and 0xE9 (Volume Up and Volume Down apparently), and using the LightBlue app I’m able to inspect that receive those messages, however, connecting to the MacBook through the phone’s bluetooth does not increase/decrease volume.

var keypress = require('keypress');
var bleno = require('bleno-mac');

var events = require('events'),
    util = require('util');


// Volume
var Volume = function() {};
util.inherits(Volume, events.EventEmitter);

Volume.prototype.up = function() {
    this.emit('levelUp');
};

Volume.prototype.down = function() {
    this.emit('levelDown');
};

// VolumeService
var BlenoPrimaryService = bleno.PrimaryService;

function VolumeService(volume) {
  VolumeService.super_.call(this, {
      uuid: 'f1f3c6d0-8193-487e-a931-16017119cffe',
      characteristics: [
          new VolumeCharacteristic(volume)
      ]
  });
}

util.inherits(VolumeService, BlenoPrimaryService);


// Volume Characteristic
var BlenoCharacteristic = bleno.Characteristic;

const VOLUME_DECREMENT = 0xEA // 234 - Volume up 
const VOLUME_INCREMENT = 0xE9 // 233 - Volume down

var VolumeCharacteristic = function(volume) {
    VolumeCharacteristic.super_.call(this, {
        uuid: 'f1f3c6d1-8193-487e-a931-16017119cffe',
        properties: ['read', 'write', 'writeWithoutResponse', 'notify']
    });

    this._volume = volume;

    this._volume.on('levelUp', this.onVolumeUp.bind(this));
    this._volume.on('levelDown', this.onVolumeDown.bind(this));
};
util.inherits(VolumeCharacteristic, BlenoCharacteristic);

VolumeCharacteristic.prototype.onVolumeDown = function(level) {
    console.log("Volume down");
    if (this.updateValueCallback) {
        this.updateValueCallback(new Buffer.alloc(1, 234));
    }
};

VolumeCharacteristic.prototype.onVolumeUp = function(level) {
    console.log("Volume up");
    if (this.updateValueCallback) {
        this.updateValueCallback(new Buffer.alloc(1, 233));
    }
};

VolumeCharacteristic.prototype.onReadRequest = function(offset, callback) {
    callback(this.RESULT_SUCCESS, new Buffer.alloc(1, 234));
};

VolumeCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
    var level = data.readUInt8(0);

    this._volume.setLevel(level, function() {
        callback(this.RESULT_SUCCESS);
    }.bind(this));
};


var volume = new Volume();

// Bleno service
var volumeService = new VolumeService(volume);

bleno.on('stateChange', function(state) {
    console.log('on -> stateChange: ' + state);

    if (state === 'poweredOn') {
        bleno.startAdvertising('VolumeService', [volumeService.uuid]);
    } else {
        bleno.stopAdvertising();
    }
});

bleno.on('advertisingStart', function(error) {
    console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
    
    if (!error) {
        bleno.setServices([volumeService]);
        console.log('Adjust the volume with the up and down arrow keys');
        console.log('or connect with your phone and set via bluetooth.');
    } 
});

// Keypresses adjusts volume
keypress(process.stdin);    

process.stdin.on('keypress', function (ch, key) {
    if (key && key.name === 'up') {
        volume.up();
    } else if (key && key.name === 'down') {
        volume.down();
    } else if (key && key.name === 'c' && key.ctrl === true) {
        // TODO disconnect bluetooth
        process.exit();
    }
});

process.stdin.setRawMode(true);
process.stdin.resume();

Edit
Found this outdated project written in Swift 3 for reference

Source: Swift

Published
Categorised as bluetooth, hid, node.js, python, swift

Answers

You should be able to use the terminal for that. Eg. in Windows, you can start the camera app using start microsoft.windows:camera

Something similar should be available even in Mac. Try that out. Otherwise, go to the root directory where the camera app is stored. And then trigger that from code.


Prof. Grady Emmerich

Leave a Reply

Your email address will not be published. Required fields are marked *

Still Have Questions?


Our dedicated development team is here for you!

We can help you find answers to your question for as low as 5$.

Contact Us
faq