Basic IoT app development for SkyCase

Method of writing a simple IoT application and deploying it to the App Store is explained in this page. For sake of easier understanding of the procedure instead of a complex demo, the example application is designed to do a very basic task of XORing of two inputs to drive an output. Though minimal in functionality, it will cover both the monitoring and controlling aspects of the device interaction.

Application Development

Developer can start the development with the Eclipse IDE. Make sure you are comfortable with the concepts mentioned in IoT App Development as well as the basic requirements mentioned are met before starting the development.

Create a new java application with any name suitable to the functionality say in this case - DigitalXOR with the following sequence of steps.

Select New Project from Eclipse Menu

Creating New Project with Eclipse

Choose Java Project as the type.

Java Project in Eclipse

Set the name of the project.

Set Project Name

Now a new project will be created and necessary files created automatically. Using the Project Properties option, import the SkyCase library to the project.

Importing SkyCase library to project

Create a class "SkyCaseApp" (in SkyCaseApp.java) within a package "skycase.main" which must extended from "skycase.app.Application". It is important that the name must be as given here and in the same package as mentioned. Step by step process of the same is given below.

Create a package inside the src directory with name skycase.main.

Creating Package

Create a class in the name SkyCaseApp inside that package.

Creating Main Class

Now the file will looks like as follows.

App file on creation

Extend the created class using the Application class imported from the SkyCase API library.

Extending with Application class

Now the stubs will be created automatically upon which it will look like.

Stub class

In the constructor of the class, add initialization of user configure resources like AppPort, AppSetting, AppEvent, AppStatus, etc. In our DigitalXOR example, we will initialize the two digital inputs and one digital output app ports.

private static final String APP_PORT_ID_DIG_INPUT1 = "xor_input1";
private static final String APP_PORT_ID_DIG_INPUT2 = "xor_input2";
private static final String APP_PORT_ID_DIG_OUTPUT = "xor_output";
public SkyCaseApp() {
/* Application device ports initialization */
addAppPort(new AppPort (APP_PORT_ID_DIG_INPUT1, "Digital Input 1", IPSO.OBJECT_ID_DIGITAl_INPUT, false));
addAppPort(new AppPort (APP_PORT_ID_DIG_INPUT2, "Digital Input 2", IPSO.OBJECT_ID_DIGITAl_INPUT, false));
addAppPort(new AppPort (APP_PORT_ID_DIG_OUTPUT, "Digital Output", IPSO.OBJECT_ID_DIGITAl_OUTPUT, true));
}
In the above code, we have created 3 unique IDs (xor_input1, xor_input2 and xor_output)which will be used internally for accessing the ports and for maintaining compatibility across versions.

Add one app setting for execution interval that will mention how fast the XOR computation must be done.
private static final String APP_SETTING_ID_INTERVAL = "xor_interval";
/* Application user settings initialization */
addAppSetting(new AppSetting(APP_SETTING_ID_INTERVAL, "Update Interval", AppSetting.APP_SETTING_TYPE_LONG, 5, 30, "Seconds", (AppSetting.APP_SETTING_PROP_READ_WRITE | AppSetting.APP_SETTING_PROP_EDIT_WHEN_STOP)));
Add one app status for runtime status that will send applications runtime status to user.
private static final String APP_STATUS_ID_OUTPUT = "xor_status";
...
/* Application status initialization */
addAppStatus(new AppStatus(APP_STATUS_ID_OUTPUT, "XOR Output State", ""));
private static final int APP_EVENT_ID_VALUE_TOGGLED = 1;
And also add one app event for digital output toggled notification to notify communicating devices of changes in output state.
....
/* Application events initialization */
AppEvent tempChangedEvent = new AppEvent(APP_EVENT_ID_VALUE_TOGGLED, AppEvent.EVENT_TYPE_NOTIFICATION, "Digital XOR Changed", "Digital Inputs");
tempChangedEvent.setEnabled(true);
tempChangedEvent.setParameters("0", "XOR Value");
addEvent(tempChangedEvent);
}

In the onStart method, load the value of app setting configuration using getUserSetting method and also do the other memory related initializations. For DigitalXOR, we initialize the interval time with the app setting. Also we are creating 2 data requests asking for the values of the Digital inputs to be updated once every 5 seconds. The same are to be queued to be processed.
@Override
public int onStart(int arg0) {
try {
lInterval = getUserSettingLong(APP_SETTING_ID_INTERVAL);
} catch (Exception e) {
logInfo(TAG, "Error - while parsing user setting interval " + e.toString());
return 1;
}
digInputReadRequest1 = new DataRequest(this, APP_PORT_ID_DIG_INPUT1, IPSO.RES_ID_DIGITAl_INPUT_STATE);
digInputReadRequest1.setReadUpdateInterval(5l, true);
QueueDataRequest(digInputReadRequest1);
digInputReadRequest2 = new DataRequest(this, APP_PORT_ID_DIG_INPUT2, IPSO.RES_ID_DIGITAl_INPUT_STATE);
digInputReadRequest2.setReadUpdateInterval(5l, true);
QueueDataRequest(digInputReadRequest2);
return 0;
}

Developer can setup the applications execution wakeup time in terms of milliseconds. In our example, we returning the interval time in the method getSleepTime().
public long getSleepTime() {
return lInterval;
}

Developer can send the applications runtime status to user. In our example we returning the digital output state in the method getStatusValue().
public String getStatusValue(String strStatusId) {
if (strStatusId.compareTo(APP_STATUS_ID_OUTPUT) == 0) {
return (m_bOutputStatus) ? "On" : "Off";
}
return null;
}

Developer can perform execution logic in onExecute method. For DigitalXOR, we will read the two digital input ports and perform XOR operation and write the output on digital output port.
@Override
public int onExecute() {
boolean bOutput, bInput1, bInput2;
//Wait for valid inputs
if (!digInputReadRequest1.isSucceeded () || !digInputReadRequest1.isSucceeded ()) {
return 0;
}
//Read the values
if (digInputReadRequest1.getValue().compareTo("1") == 0)
bInput1 = true;
else
bInput1 = false;
if (digInputReadRequest2.getValue().compareTo("1") == 0)
bInput2 = true;
else
bInput2 = false;
//Calculate output
bOutput = bInput1 ^ bInput2;
//Update only on change
if (bOutput != m_bLastOutputStatus) {
m_bLastOutputStatus = bOutput;
//Delete previous requests if any
if (digOutputWriteRequest != null) {
CancelDataRequest(digOutputWriteRequest);
digOutputWriteRequest = null;
}
//Create a write request
digOutputWriteRequest = new DataRequest(this, APP_PORT_ID_DIG_OUTPUT, IPSO.RES_ID_DIGITAl_OUTPUT_STATE, m_bLastOutputStatus ? "1" : "0");
digOutputWriteRequest.setBacklog(DataRequest.REQUEST_BACKLOG_NONE);
//Queue it to be sent to the device
QueueDataRequest(digOutputWriteRequest);
//Notify the user
notifyEvent(APP_EVENT_ID_VALUE_TOGGLED);
}
return 0;
}

Resource de-allocation functionalities are to be done in the method onStop.
@Override
public int onStop(int arg0) {
CancelDataRequest(digInputReadRequest1);
CancelDataRequest(digInputReadRequest2);
CancelDataRequest(digOutputWriteRequest);
}

Compilation steps

Upon writing the code as explained above, build the project using the menu option. But more likely Eclipse will auto build the project.

Building Project in Eclipse

Finally export the project as a JAR library with the following steps. Right click the project and select export item.

Exporting Project in Eclipse

Select export type as JAR file.

Exporting as Java Project in Eclipse

Set the name of the output in the desired path. Here we will use the name DigitalXOR.jar.

Exporting Path for SkyCase project

Now that we have the SkyCase application as a JAR file, follow steps described in SkyCase App deployment section to publish it in the app store for use.

The full buildable example code for this application is available from our downloads section.