/*******************************************************************************
* Copyright (c) 2013-2015 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Zebra Technologies - initial API and implementation
* Sierra Wireless, - initial API and implementation
* Bosch Software Innovations GmbH, - initial API and implementation
*******************************************************************************/
package org.eclipse.leshan.client.demo;
import static org.eclipse.leshan.LwM2mId.*;
import static org.eclipse.leshan.client.object.Security.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Scanner;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.LwM2m;
import org.eclipse.leshan.client.californium.LeshanClient;
import org.eclipse.leshan.client.californium.LeshanClientBuilder;
import org.eclipse.leshan.client.object.Server;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ObjectLoader;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.request.BindingMode;
import org.eclipse.leshan.util.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LeshanClientDemo {
private static final Logger LOG = LoggerFactory.getLogger(LeshanClientDemo.class);
private final static String[] modelPaths = new String[] { "3303.xml" };
private static final int OBJECT_ID_TEMPERATURE_SENSOR = 3303;
private final static String DEFAULT_ENDPOINT = "LeshanClientDemo";
private final static String USAGE = "java -jar leshan-client-demo.jar [OPTION]";
private static MyLocation locationInstance;
public static void main(final String[] args) {
// Define options for command line tools
Options options = new Options();
options.addOption("h", "help", false, "Display help information.");
options.addOption("n", true, String.format(
"Set the endpoint name of the Client.\nDefault: the local hostname or '%s' if any.", DEFAULT_ENDPOINT));
options.addOption("b", false, "If present use bootstrap.");
options.addOption("lh", true, "Set the local CoAP address of the Client.\n Default: any local address.");
options.addOption("lp", true,
"Set the local CoAP port of the Client.\n Default: A valid port value is between 0 and 65535.");
options.addOption("slh", true, "Set the secure local CoAP address of the Client.\nDefault: any local address.");
options.addOption("slp", true,
"Set the secure local CoAP port of the Client.\nDefault: A valid port value is between 0 and 65535.");
options.addOption("u", true, String.format("Set the LWM2M or Bootstrap server URL.\nDefault: localhost:%d.",
LwM2m.DEFAULT_COAP_PORT));
options.addOption("i", true,
"Set the LWM2M or Bootstrap server PSK identity in ascii.\nUse none secure mode if not set.");
options.addOption("p", true,
"Set the LWM2M or Bootstrap server Pre-Shared-Key in hexa.\nUse none secure mode if not set.");
options.addOption("pos", true,
"Set the initial location (latitude, longitude) of the device to be reported by the Location object. Format: lat_float:long_float");
options.addOption("sf", true, "Scale factor to apply when shifting position. Default is 1.0.");
HelpFormatter formatter = new HelpFormatter();
formatter.setOptionComparator(null);
// Parse arguments
CommandLine cl;
try {
cl = new DefaultParser().parse(options, args);
} catch (ParseException e) {
System.err.println("Parsing failed. Reason: " + e.getMessage());
formatter.printHelp(USAGE, options);
return;
}
// Print help
if (cl.hasOption("help")) {
formatter.printHelp(USAGE, options);
return;
}
// Abort if unexpected options
if (cl.getArgs().length > 0) {
System.err.println("Unexpected option or arguments : " + cl.getArgList());
formatter.printHelp(USAGE, options);
return;
}
// Abort if we have not identity and key for psk.
if ((cl.hasOption("i") && !cl.hasOption("p")) || !cl.hasOption("i") && cl.hasOption("p")) {
System.err.println("You should precise identity and Pre-Shared-Key if you want to connect in PSK");
formatter.printHelp(USAGE, options);
return;
}
// Get endpoint name
String endpoint;
if (cl.hasOption("n")) {
endpoint = cl.getOptionValue("n");
} else {
try {
endpoint = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
endpoint = DEFAULT_ENDPOINT;
}
}
// Get server URI
String serverURI;
if (cl.hasOption("u")) {
if (cl.hasOption("i"))
serverURI = "coaps://" + cl.getOptionValue("u");
else
serverURI = "coap://" + cl.getOptionValue("u");
} else {
if (cl.hasOption("i"))
serverURI = "coaps://localhost:" + LwM2m.DEFAULT_COAP_SECURE_PORT;
else
serverURI = "coap://localhost:" + LwM2m.DEFAULT_COAP_PORT;
}
// get security info
byte[] pskIdentity = null;
byte[] pskKey = null;
if (cl.hasOption("i") && cl.hasOption("p")) {
pskIdentity = cl.getOptionValue("i").getBytes();
pskKey = Hex.decodeHex(cl.getOptionValue("p").toCharArray());
}
// get local address
String localAddress = null;
int localPort = 0;
if (cl.hasOption("lh")) {
localAddress = cl.getOptionValue("lh");
}
if (cl.hasOption("lp")) {
localPort = Integer.parseInt(cl.getOptionValue("lp"));
}
// get secure local address
String secureLocalAddress = null;
int secureLocalPort = 0;
if (cl.hasOption("slh")) {
secureLocalAddress = cl.getOptionValue("slh");
}
if (cl.hasOption("slp")) {
secureLocalPort = Integer.parseInt(cl.getOptionValue("slp"));
}
Float latitude = null;
Float longitude = null;
Float scaleFactor = 1.0f;
// get initial Location
if (cl.hasOption("pos")) {
try {
String pos = cl.getOptionValue("pos");
int colon = pos.indexOf(':');
if (colon == -1 || colon == 0 || colon == pos.length() - 1) {
System.err.println("Position must be a set of two floats separated by a colon, e.g. 48.131:11.459");
formatter.printHelp(USAGE, options);
return;
}
latitude = Float.valueOf(pos.substring(0, colon));
longitude = Float.valueOf(pos.substring(colon + 1));
} catch (NumberFormatException e) {
System.err.println("Position must be a set of two floats separated by a colon, e.g. 48.131:11.459");
formatter.printHelp(USAGE, options);
return;
}
}
if (cl.hasOption("sf")) {
try {
scaleFactor = Float.valueOf(cl.getOptionValue("sf"));
} catch (NumberFormatException e) {
System.err.println("Scale factor must be a float, e.g. 1.0 or 0.01");
formatter.printHelp(USAGE, options);
return;
}
}
createAndStartClient(endpoint, localAddress, localPort, secureLocalAddress, secureLocalPort, cl.hasOption("b"),
serverURI, pskIdentity, pskKey, latitude, longitude, scaleFactor);
}
public static void createAndStartClient(String endpoint, String localAddress, int localPort,
String secureLocalAddress, int secureLocalPort, boolean needBootstrap, String serverURI, byte[] pskIdentity,
byte[] pskKey, Float latitude, Float longitude, float scaleFactor) {
locationInstance = new MyLocation(latitude, longitude, scaleFactor);
// Initialize model
List<ObjectModel> models = ObjectLoader.loadDefault();
models.addAll(ObjectLoader.loadDdfResources("/models", modelPaths));
// Initialize object list
ObjectsInitializer initializer = new ObjectsInitializer(new LwM2mModel(models));
if (needBootstrap) {
if (pskIdentity == null)
initializer.setInstancesForObject(SECURITY, noSecBootstap(serverURI));
else
initializer.setInstancesForObject(SECURITY, pskBootstrap(serverURI, pskIdentity, pskKey));
} else {
if (pskIdentity == null) {
initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123));
initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
} else {
initializer.setInstancesForObject(SECURITY, psk(serverURI, 123, pskIdentity, pskKey));
initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
}
}
initializer.setClassForObject(DEVICE, MyDevice.class);
initializer.setInstancesForObject(LOCATION, locationInstance);
initializer.setInstancesForObject(OBJECT_ID_TEMPERATURE_SENSOR, new RandomTemperatureSensor());
List<LwM2mObjectEnabler> enablers = initializer.create(SECURITY, SERVER, DEVICE, LOCATION,
OBJECT_ID_TEMPERATURE_SENSOR);
// Create client
LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
builder.setLocalAddress(localAddress, localPort);
builder.setLocalSecureAddress(secureLocalAddress, secureLocalPort);
builder.setObjects(enablers);
builder.setNetworkConfig(NetworkConfig.getStandard());
final LeshanClient client = builder.build();
LOG.info("Press 'w','a','s','d' to change reported Location ({},{}).", locationInstance.getLatitude(),
locationInstance.getLongitude());
// Start the client
client.start();
// De-register on shutdown and stop client.
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
client.destroy(true); // send de-registration request before destroy
}
});
// Change the location through the Console
try (Scanner scanner = new Scanner(System.in)) {
while (scanner.hasNext()) {
String nextMove = scanner.next();
locationInstance.moveLocation(nextMove);
}
}
}
}