Create an external action for IoTool using Bluetooth

When adding new actions to the IoTool application, it is encouraged to crate new extension rather than modifying the application itself. This document will help you create your own actions. This document will cover internal actions on your device.

General things

Before we start developing, we need to address that this document will only go briefly over the over the basics on how to create new extension. For more details on how to program such extension, please look at the document located in this link. In general extension only contains 2 types classes (provider and multiple receivers). Additionally it also contains JSON file. This file is use to link UI elements with parameters. This example is meant to be bundled with sensor extension. For more information please follow this link.

Libraries

This example uses 2 libraries made by us:

  • IoToolLibraryBase.arr

  • IoToolLibraryAction.arr

Classes

This particular example uses "Arduino" as a ServiceID. It contains a receiver class and a provider class.

Note: Sections marked with "//TODO" indicate that you may need to change that part of the code.

"IoToolActionProviderArduino.java"

In this example, when the function is triggered, it calls a phone number set by the user.

package io.senlab.iotoolservicearduino.action;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.io.OutputStream;

import io.senlab.iotool.library.actions.IoToolActionReceiver;
import io.senlab.iotoolservicearduino.Bluetooth.BluetoothLEManager;
import io.senlab.iotoolservicearduino.Bluetooth.BluetoothManager;
import io.senlab.iotoolservicearduino.R;

/**
 * Created by marko on 8/31/16.
 */
public class IoToolActionProviderArduino extends IoToolActionReceiver {
    @Override
    //TODO function that returns names of the parameters. The names are also set here.
    protected String[] getInputParamNames(String... requiredParameters) {
        return new String[] {"id"};
    }


    @Override
    //TODO write the code to execute when conditions are fulfilled
    protected void onActionExecute(Context context, Bundle args, Bundle extras) {
        Log.d("Action receiver", args.getString("id"));

        /* Send action ID to the arduino. Arduino will execute corresponding callback. */
        String actionString = "#" + args.getString("id") + ";";
        byte action[] = actionString.getBytes();

        //TODO this is meant to be used with sensor extension
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        boolean useLE = sp.getBoolean(context.getString(R.string.preference_key_bt_le), false);

        if (useLE) {
           if (!executeActionLE(action)) notifyFailure(context);
        } else {
            if (!executeAction(action)) notifyFailure(context);
        }
    }

    private boolean executeActionLE(byte action[]) {
        BluetoothLEManager m = BluetoothLEManager.getInstance();

        if (m.isConnected()) {
            m.write(action);
            return true;
        } else {
            return false;
        }
    }

    private boolean executeAction(byte action[]) {
        BluetoothManager m = BluetoothManager.getInstance();

        if (m.isConnected()) {
            OutputStream outputStream = BluetoothManager.getInstance().getOutputStream();

            if (outputStream != null) {
                try {
                    outputStream.write(action);
                } catch (IOException e) {
                    Log.d("ActionReceiver", e.toString());
                    return false;
                }
            }

            return true;
        } else {
            return false;
        }
    }

    private void notifyFailure(Context context) {
        Log.d("ActionReceiver", "Could not execute action");
        Toast.makeText(context,
                "Could not execute action. Is device connected? If testing actions, connect to your device via service preferences.",
                Toast.LENGTH_LONG).show();
    }
}

"ArduinoActionProvider.java"

Used to feed JSON file to the application

package io.senlab.iotoolservicearduino.action;

import io.senlab.iotool.library.actions.IoToolActionProvider;
import io.senlab.iotoolservicearduino.R;

/**
 * Created by marko on 8/31/16.
 */
public class ArduinoActionProvider extends IoToolActionProvider {
    @Override
    protected int getActionsRawResourceId() {
        return R.raw.actions;
    }
}

"raw/actions.json"

Example on how to make JSON. This file will most likely be needed to be changed.

{
  "package": "io.senlab.iotoolservicearduino",
  "description": "Arduino actions",
  "developer": "SenLab",
  "actions": [
    {
      "classname": "action.IoToolActionProviderArduino",
      "description": "Execute by ID",
      "params": [
        {
          "type": "io.senlab.iotool.actions.input.ActionInputString",
          "description": "Action ID (defined in Arduino sketch)"
        }
      ]
    }
  ]
}