Commit db71796f authored by andrei's avatar andrei

Releasing boilerplate project.

parent 808035fd
# Lab IoT Course 2016-10-06
# IoT Course: Lab 2016-10-06
This project contains the programs for the lab session http://www.emse.fr/~picard/cours/iot/application-layer-protocols/
This project contains the boilerplate code for the lab session http://www.emse.fr/~picard/cours/iot/application-layer-protocols/
Group `fr.emse.iotcourse`
Group `fr.emse.iotcourse`:
- module `iot-lab-app` contains the boilerplate code to develop the smart home application;
- module `iot-lab-coap-emulator` contains the emulated CoAP presence and light sensors.
# Setup
The goal of this application is to automatically manage the lighting in an IoT environment based on the readings from an outside light sensor and a presence sensor.
To run your application, you are going to use:
- the Philips Hue light bulb that was allocated to your group in the previous exercises;
- the CoRE Resource Directory used in the previous exercises;
- the CoAP device emulator used in the previous exercises.
The CoRE Resource Directory and the CoAP device emulator run on different machines on the same local network. Therefore, in this application you are using a WoT enviornment deployed on your local network that consists of:
- a Philips Hue light bulb accessed via a bridge;
- a constrained RESTful environment (CoRE) distributed across two machines; the entry point in this environment is the URI of the CoRE Resource Directory.
The boilerplate code handles for you the discovery of resources in the CoRE.
# Task
In this exercise, you are mostly concerned with the `iot-lab-app` module. Your task is to complete all the `TODOs` in the following Java classes:
- `fr.emse.ci.iotcourse.MyIoTApp`
- `fr.emse.ci.iotcourse.env.PhilipsHueLightBulb`
- `fr.emse.ci.iotcourse.control.SmartLightingController`
We recommend that you proceed in the above order.
# Get started
These is a modular [Maven](http://maven.apache.org/) project.
This is a modular [Maven](http://maven.apache.org/) project.
To run a specific class, you can use the Maven plugin in your favorite java IDE, or run the following command:
To run a specific class, you can use the Maven plugin in your favorite Java IDE, or run the following command:
```
mvn exec:java -Dexec.mainClass="com.example.Main"
```
To run the entire setup on your own:
- to deploy a CoRE Resource Directory, you can use Cf-RD from the [Californium Tools](https://github.com/eclipse/californium.tools) repository;
- to build and run the CoAP device emulator, you can use the following commands inside the `iot-lab-coap-emulator` directory (you will build a stand-alone "fat" jar):
```
mvn clean compile assembly:single
java -jar target/iot-b-coap-emulator-1.0-SNAPSHOT-jar-with-dependencies.jar
```
- register the resources to the deployed resource directory, for instance using the [Copper Firefox plugin](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) or the console client from the [Californium Tools](https://github.com/eclipse/californium.tools) repository (see the [CoRE Resource Directory](https://tools.ietf.org/html/draft-ietf-core-resource-directory-08) working draft for more details on resource registration); *note:* make sure you register the `con` and `rt` attributes.
# Contact
- andrei.ciortea@emse.fr
......
package fr.emse.ci.iotcourse;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapObserveRelation;
import fr.emse.ci.iotcourse.control.LightSensorHandler;
import fr.emse.ci.iotcourse.control.PresenceSensorHandler;
import fr.emse.ci.iotcourse.control.SmartLightingController;
import fr.emse.ci.iotcourse.env.Environment;
import fr.emse.ci.iotcourse.env.ResourceDirectory;
public class MyIoTApp {
public static void main(String[] args) throws Exception {
// TODO: Set the resource directory URI.
// This URI is the application's entry point in the constrained RESTful environment (CoRE).
ResourceDirectory resourceDirectory = new ResourceDirectory("<DIRECTORY_URI>");
// TODO: Set the resource type URIs.
// These URIs are used to discover resources in the CoRE based on their semantic type.
String lightSensorUri = resourceDirectory.getResourceUriByType("<RESOURCE_TYPE_URI>");
String presenceSensorUri = resourceDirectory.getResourceUriByType("<RESOURCE_TYPE_URI>");
// Check that the URIs of the light and presence sensors have been discovered.
if (lightSensorUri == null) {
System.out.println("Light sensor not found! Exiting application...");
System.exit(1);
}
if (presenceSensorUri == null) {
System.out.println("Presence sensor not found! Exiting application...");
System.exit(1);
}
// Observe the two resources
CoapObserveRelation lightObserveRelation =
new CoapClient(lightSensorUri).observeAndWait(new LightSensorHandler());
CoapObserveRelation presenceObserveRelation =
new CoapClient(presenceSensorUri).observeAndWait(new PresenceSensorHandler());
// Application loop: check the state of the environment every 3s and invoke the smart lighting logic.
while (true) {
// Get the environment
Environment env = Environment.getInstance();
// Print the state of the environment for debugging purposes
System.out.println(env);
// Invoke the smart lighting control logic
SmartLightingController.controlLights(env.isPresenceDetected(), env.getLightLevel());
// Refresh the observe relations if necessary
if (lightObserveRelation.isCanceled()) {
lightObserveRelation.reregister();
}
if (presenceObserveRelation.isCanceled()) {
presenceObserveRelation.reregister();
}
// Time to sleep
Thread.sleep(3000);
}
}
}
package fr.emse.ci.iotcourse.control;
import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import fr.emse.ci.iotcourse.env.Environment;
public class LightSensorHandler implements CoapHandler {
public void onLoad(CoapResponse response) {
if (response.getCode() == ResponseCode.CONTENT) {
try {
JSONParser parser = new JSONParser();
JSONObject state = (JSONObject) parser.parse(response.getResponseText());
Environment.getInstance().setLightLevel((Long) state.get("level"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public void onError() {
System.out.println("Request timed out or rejected by the server!");
}
}
package fr.emse.ci.iotcourse.control;
import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import fr.emse.ci.iotcourse.env.Environment;
public class PresenceSensorHandler implements CoapHandler {
public void onLoad(CoapResponse response) {
if (response.getCode() == ResponseCode.CONTENT) {
try {
JSONParser parser = new JSONParser();
JSONObject state = (JSONObject) parser.parse(response.getResponseText());
Boolean presenceDetected = (Boolean) state.get("presence");
if (presenceDetected != null) {
if (presenceDetected == true) {
Environment.getInstance().setPresence(true);
} else {
Environment.getInstance().setPresence(false);
}
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public void onError() {
System.out.println("Request timed out or rejected by the server!");
}
}
package fr.emse.ci.iotcourse.control;
import fr.emse.ci.iotcourse.env.PhilipsHueLightBulb;
public class SmartLightingController {
public static void controlLights(boolean presenceDetected, long lightLevel) {
// TODO: Set your light bulb id
int lightBulbId = -1;
PhilipsHueLightBulb lightBulb = new PhilipsHueLightBulb(lightBulbId);
// TODO: implement the smart lights logic as follows:
// - if presence is detected and the light level is below 100 (lux), turn on the light bulb
// - otherwise, turn if off the light bulb (if it is turned on)
}
}
package fr.emse.ci.iotcourse.env;
public class Environment {
private static Environment environmemt;
private boolean presenceDetected;
private long lightLevel;
private Environment() {
presenceDetected = false;
lightLevel = -1;
}
public static synchronized Environment getInstance() {
if (environmemt == null) {
environmemt = new Environment();
}
return environmemt;
}
public void setPresence(boolean value) {
presenceDetected = value;
}
public void setLightLevel(long level) {
lightLevel = level;
}
public boolean isPresenceDetected() {
return presenceDetected;
}
public long getLightLevel() {
return lightLevel;
}
@Override
public String toString() {
return "[Env State] light level: " + getLightLevel() + ", presence: " + isPresenceDetected();
}
}
package fr.emse.ci.iotcourse.env;
import org.apache.http.HttpStatus;
public class PhilipsHueLightBulb {
private String hubAddress = "192.168.0.100";
private String relativePath = "/api/bhBWRz2DWOEqjSwR9cmDBeZgVfV3pWvjrdYdpocw/lights/";
private String lightBulbStateUri;
public PhilipsHueLightBulb(int lighBulbId) {
this.lightBulbStateUri = "http://" + hubAddress + relativePath + lighBulbId + "/state";
}
public void turnOn() {
// TODO: Set the payload for the HTTP request issued to turn on the light bulb.
String jsonPayload = "<PAYLOAD>";
setState(jsonPayload);
}
public void turnOff() {
// TODO: Set the payload for the HTTP request issued to turn off the light bulb.
String jsonPayload = "<PAYLOAD>";
setState(jsonPayload);
}
private void setState(String state) {
try {
// TODO: Use an HTTP client to issue a request that sets the state of the light bulb.
// Hint: You can use the Apache HTTP client (Maven dependency already added).
// Hint: The URI that denotes the light bulb's state is already set in the lightBulbStateUri variable.
// TODO: Retrieve the real status code from the received HTTP response.
int responseCode = HttpStatus.SC_BAD_REQUEST;
if (responseCode != HttpStatus.SC_OK) {
System.out.println("HTTP request to update the state of the light bulb failed. Status code: " + responseCode);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package fr.emse.ci.iotcourse.env;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.WebLink;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.coap.LinkFormat;
public class ResourceDirectory {
private Map<String,String> resources;
String directoryUri;
public ResourceDirectory(String uri) {
directoryUri = uri;
resources = new HashMap<String,String>();
discoverResources();
}
public String getResourceUriByType(String resourceTypeUri) {
return resources.get(resourceTypeUri);
}
private void discoverResources() {
String lookupUri = (directoryUri.endsWith("/")) ? directoryUri + "rd-lookup/res" : directoryUri + "/rd-lookup/res";
CoapClient client = new CoapClient(lookupUri);
CoapResponse response = client.get();
if (response != null && (response.getCode() == ResponseCode.CONTENT)) {
resources = extractTypedResources(response.getResponseText());
}
}
private Map<String, String> extractTypedResources(String payload) {
Map<String, String> resources = new HashMap<String, String>();
Set<WebLink> links = LinkFormat.parse(payload);
for (WebLink link : links) {
List<String> resourceTypes = link.getAttributes().getResourceTypes();
if (resourceTypes != null && !resourceTypes.isEmpty()) {
List<String> cons = link.getAttributes().getAttributeValues("con");
// If a context was registered, build the correct URI
if (cons != null && !cons.isEmpty()) {
String context = cons.get(0);
try {
URI registeredUri = new URI(link.getURI());
String resourcePath = registeredUri.getPath();
resources.put(resourceTypes.get(0), context + resourcePath);
} catch (URISyntaxException e) {
resources.put(resourceTypes.get(0), link.getURI());
}
} else {
resources.put(resourceTypes.get(0), link.getURI());
}
}
}
return resources;
}
}
......@@ -13,6 +13,24 @@
<description>Code to emulate the CoaP presence and light sensors</description>
<url>http://www.emse.fr/~picard/cours/iot/application-layer-protocols/</url>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fr.emse.ci.iotcourse.DeviceEmulator</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.californium</groupId>
......
package fr.emse.ci.iotcourse;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
public class DeviceEmulator {
static int PORT = 60000;
public static void main(String[] args) throws Exception {
try {
if (args.length == 2 && args[0].equalsIgnoreCase("-port")) {
PORT = Integer.parseInt(args[1]);
}
} catch (NumberFormatException e) {
System.out.println("Supplied argument is not a valid port.");
}
CoapServer server = new CoapServer(PORT);
CoapResource presenceSensor = new PresenceSensorResource("presence_sensor");
presenceSensor.setObservable(true);
CoapResource lightSensor = new LightSensorResource("light_sensor");
lightSensor.setObservable(true);
server.add(presenceSensor);
server.add(lightSensor);
server.start();
}
}
package fr.emse.ci.iotcourse;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.server.resources.CoapExchange;
public class LightSensorResource extends CoapResource {
private int lightLevel;
public LightSensorResource(String name) {
super(name);
lightLevel = 80;
simulateLightChange();
}
@Override
public void handleGET(CoapExchange exchange) {
Response response = new Response(ResponseCode.CONTENT);
response.setPayload("{ \"level\" : " + lightLevel + " }");
exchange.respond(response);
}
private void simulateLightChange() {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(
new Runnable() {
public void run() {
/* if(Math.random() > 0.5) {
lightLevel = 80;
} else {
lightLevel = 120;
}*/
lightLevel = (lightLevel == 80) ? 120 : 80;
changed();
}
}, 3, 3, TimeUnit.SECONDS);
}
}
package fr.emse.ci.iotcourse;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.server.resources.CoapExchange;
public class PresenceSensorResource extends CoapResource {
private boolean presence;
public PresenceSensorResource(String name) {
super(name);
presence = false;
simulatePresenceDetection();
}
@Override
public void handleGET(CoapExchange exchange) {
Response response = new Response(ResponseCode.CONTENT);
response.setPayload("{ \"presence\" : " + presence + " }");
exchange.respond(response);
}
private void simulatePresenceDetection() {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(
new Runnable() {
public void run() {
if(Math.random() > 0.5) {
presence = true;
} else {
presence = false;
}
changed();
}
}, 3, 3, TimeUnit.SECONDS);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment