adding new device type: drone analyzer

This commit is contained in:
GPrathap 2016-06-06 06:31:04 +05:30
parent 5da3c09a18
commit 25844c8c60
101 changed files with 42227 additions and 0 deletions

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api;
import org.homeautomation.droneanalyzer.api.dto.DeviceJSON;
import org.wso2.carbon.apimgt.annotations.api.API;
import org.wso2.carbon.apimgt.annotations.api.Permission;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Path;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.PUT;
import javax.ws.rs.DELETE;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* This is the API which is used to control and manage device type functionality
*/
@SuppressWarnings("NonJaxWsWebServices")
@API(name = "drone", version = "1.0.0", context = "/drone", tags = "drone")
@DeviceType(value = "drone")
public interface DroneAnalyzerService {
/**
* @param agentInfo device owner,id
* @return true if device instance is added to map
*/
@Path("device/register")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/user/register"})
Response registerDevice(final DeviceJSON agentInfo);
/**
* Retrieve Sensor data for the given time period
* @param deviceId unique identifier for given device type instance
* @param from starting time
* @param to ending time
* @return response with List<SensorRecord> object which includes sensor data which is requested
*/
@Path("device/stats/{deviceId}")
@GET
@Consumes("application/json")
@Produces("application/json")
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/stats"})
Response getSensorStats(@PathParam("deviceId") String deviceId, @QueryParam("from") long from,
@QueryParam("to") long to);
/**
* Remove device type instance using device id
* @param deviceId unique identifier for given device type instance
*/
@Path("/device/{device_id}")
@DELETE
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/removeDevice"})
Response removeDevice(@PathParam("device_id") String deviceId);
/**
* Update device instance name
* @param deviceId unique identifier for given device type instance
* @param name new name for the device type instance
*/
@Path("/device/{device_id}")
@PUT
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/updateDevice"})
Response updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name);
/**
* To get device information
* @param deviceId unique identifier for given device type instance
* @return
*/
@Path("/device/{device_id}")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/updateDevice"})
Response getDevice(@PathParam("device_id") String deviceId);
/**
* Get all device type instance which belongs to user
* @return Array of devices which includes device's information
*/
@Path("/devices")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/devices"})
Response getAllDevices();
/**
* To download device type agent source code as zip file
* @param deviceName name for the device type instance
* @param sketchType folder name where device type agent was installed into server
* @return Agent source code as zip file
*/
@Path("/device/download")
@GET
@Produces("application/zip")
@Permission(scope = "drone_user", permissions = {"/permission/admin/device-mgt/download"})
Response downloadSketch(@QueryParam("deviceName") String deviceName, @QueryParam("sketchType") String sketchType);
}

View File

@ -0,0 +1,382 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api;
import org.homeautomation.droneanalyzer.api.dto.DeviceJSON;
import org.homeautomation.droneanalyzer.api.dto.SensorRecord;
import org.homeautomation.droneanalyzer.api.util.APIUtil;
import org.homeautomation.droneanalyzer.api.util.ZipUtil;
import org.homeautomation.droneanalyzer.plugin.constants.DroneAnalyzerConstants;
import org.homeautomation.droneanalyzer.api.DroneAnalyzerService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.analytics.dataservice.commons.SORT;
import org.wso2.carbon.analytics.dataservice.commons.SortByField;
import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException;
import org.wso2.carbon.apimgt.annotations.api.API;
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature;
import org.wso2.carbon.device.mgt.iot.util.ZipArchive;
import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import org.wso2.carbon.user.api.UserStoreException;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Path;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.PUT;
import javax.ws.rs.DELETE;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
/**
* This is the API which is used to control and manage device type functionality
*/
@SuppressWarnings("NonJaxWsWebServices")
@API(name = "drone", version = "1.0.0", context = "/drone", tags = "drone")
@DeviceType(value = "drone")
public class DroneAnalyzerServiceImpl implements DroneAnalyzerService {
private static final String KEY_TYPE = "PRODUCTION";
private static Log log = LogFactory.getLog(DroneAnalyzerService.class);
private static ApiApplicationKey apiApplicationKey;
private ConcurrentHashMap<String, DeviceJSON> deviceToIpMap = new ConcurrentHashMap<>();
private static String shortUUID() {
UUID uuid = UUID.randomUUID();
long l = ByteBuffer.wrap(uuid.toString().getBytes(StandardCharsets.UTF_8)).getLong();
return Long.toString(l, Character.MAX_RADIX);
}
/**
* @param agentInfo device owner,id
* @return true if device instance is added to map
*/
@Path("device/register")
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response registerDevice(final DeviceJSON agentInfo) {
String deviceId = agentInfo.deviceId;
if ((agentInfo.deviceId != null) && (agentInfo.owner != null)) {
deviceToIpMap.put(deviceId, agentInfo);
return Response.status(Response.Status.OK).build();
}
return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
/**
* Retrieve Sensor data for the given time period
* @param deviceId unique identifier for given device type instance
* @param from starting time
* @param to ending time
* @return response with List<SensorRecord> object which includes sensor data which is requested
*/
@Path("device/stats/{deviceId}")
@GET
@Consumes("application/json")
@Produces("application/json")
public Response getSensorStats(@PathParam("deviceId") String deviceId, @QueryParam("from") long from,
@QueryParam("to") long to) {
String fromDate = String.valueOf(from);
String toDate = String.valueOf(to);
String query = "meta_deviceId:" + deviceId + " AND meta_deviceType:" +
DroneAnalyzerConstants.DEVICE_TYPE + " AND meta_time : [" + fromDate + " TO " + toDate + "]";
String sensorTableName = DroneAnalyzerConstants.SENSOR_EVENT_TABLE;
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
DroneAnalyzerConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
if (sensorTableName != null) {
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField("meta_time", SORT.ASC, false);
sortByFields.add(sortByField);
List<SensorRecord> sensorRecords = APIUtil.getAllEventsForDevice(sensorTableName, query, sortByFields);
return Response.status(Response.Status.OK.getStatusCode()).entity(sensorRecords).build();
}
} catch (AnalyticsException e) {
String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query;
log.error(errorMsg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.status(Response.Status.BAD_REQUEST).build();
}
/**
* Remove device type instance using device id
* @param deviceId unique identifier for given device type instance
*/
@Path("/device/{device_id}")
@DELETE
public Response removeDevice(@PathParam("device_id") String deviceId) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(DroneAnalyzerConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
boolean removed = APIUtil.getDeviceManagementService().disenrollDevice(
deviceIdentifier);
if (removed) {
return Response.ok().build();
} else {
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
/**
* Update device instance name
* @param deviceId unique identifier for given device type instance
* @param name new name for the device type instance
*/
@Path("/device/{device_id}")
@PUT
public Response updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(DroneAnalyzerConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
device.setDeviceIdentifier(deviceId);
device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime());
device.setName(name);
device.setType(DroneAnalyzerConstants.DEVICE_TYPE);
boolean updated = APIUtil.getDeviceManagementService().modifyEnrollment(device);
if (updated) {
return Response.ok().build();
} else {
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
/**
* To get device information
* @param deviceId unique identifier for given device type instance
* @return
*/
@Path("/device/{device_id}")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response getDevice(@PathParam("device_id") String deviceId) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(DroneAnalyzerConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
return Response.ok().entity(device).build();
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
/**
* Get all device type instance which belongs to user
* @return Array of devices which includes device's information
*/
@Path("/devices")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response getAllDevices() {
try {
List<Device> userDevices =
APIUtil.getDeviceManagementService().getDevicesOfUser(APIUtil.getAuthenticatedUser());
ArrayList<Device> userDevicesforFirealarm = new ArrayList<>();
for (Device device : userDevices) {
if (device.getType().equals(DroneAnalyzerConstants.DEVICE_TYPE) &&
device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) {
userDevicesforFirealarm.add(device);
}
}
Device[] devices = userDevicesforFirealarm.toArray(new Device[]{});
return Response.ok().entity(devices).build();
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
/**
* To download device type agent source code as zip file
* @param deviceName name for the device type instance
* @param sketchType folder name where device type agent was installed into server
* @return Agent source code as zip file
*/
@Path("/device/download")
@GET
@Produces("application/zip")
public Response downloadSketch(@QueryParam("deviceName") String deviceName,
@QueryParam("sketchType") String sketchType) {
try {
ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType);
Response.ResponseBuilder response = Response.ok(FileUtils.readFileToByteArray(zipFile.getZipFile()));
response.status(Response.Status.OK);
response.type("application/zip");
response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\"");
Response resp = response.build();
zipFile.getZipFile().delete();
return resp;
} catch (IllegalArgumentException ex) {
return Response.status(400).entity(ex.getMessage()).build();//bad request
} catch (DeviceManagementException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (JWTClientException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (APIManagerException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (UserStoreException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
}
}
/**
* Register device into device management service
* @param deviceId unique identifier for given device type instance
* @param name name for the device type instance
* @return check whether device is installed into cdmf
*/
private boolean register(String deviceId, String name) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(DroneAnalyzerConstants.DEVICE_TYPE);
if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) {
return false;
}
Device device = new Device();
device.setDeviceIdentifier(deviceId);
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
enrolmentInfo.setDateOfEnrolment(new Date().getTime());
enrolmentInfo.setDateOfLastUpdate(new Date().getTime());
enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE);
enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD);
device.setName(name);
device.setType(DroneAnalyzerConstants.DEVICE_TYPE);
enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser());
device.setEnrolmentInfo(enrolmentInfo);
boolean added = APIUtil.getDeviceManagementService().enrollDevice(device);
if (added) {
APIUtil.registerApiAccessRoles(APIUtil.getAuthenticatedUser());
}
return added;
} catch (DeviceManagementException e) {
log.error(e.getMessage(), e);
return false;
}
}
private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType)
throws DeviceManagementException, JWTClientException, APIManagerException,
UserStoreException {
//create new device id
String deviceId = shortUUID();
if (apiApplicationKey == null) {
String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm()
.getRealmConfiguration().getAdminUserName();
applicationUsername = applicationUsername + "@" + APIUtil.getAuthenticatedUserTenantDomain();
APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
String[] tags = {DroneAnalyzerConstants.DEVICE_TYPE};
apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
DroneAnalyzerConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true);
}
JWTClient jwtClient = APIUtil.getJWTClientManagerService().getJWTClient();
String scopes = "device_type_" + DroneAnalyzerConstants.DEVICE_TYPE + " device_" + deviceId;
AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(),
apiApplicationKey.getConsumerSecret(), owner + "@" + APIUtil.getAuthenticatedUserTenantDomain(), scopes);
//create token
String accessToken = accessTokenInfo.getAccessToken();
String refreshToken = accessTokenInfo.getRefreshToken();
boolean status = register(deviceId, deviceName);
if (!status) {
String msg = "Error occurred while registering the device with " + "id: " + deviceId + " owner:" + owner;
throw new DeviceManagementException(msg);
}
ZipUtil ziputil = new ZipUtil();
ZipArchive zipFile = ziputil.createZipFile(owner, APIUtil.getTenantDomainOftheUser(), sketchType,
deviceId, deviceName, accessToken, refreshToken);
return zipFile;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.dto;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* These information are sent by agent in each request to server
*/
@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
public class DeviceJSON {
@XmlElement(required = true)
public String owner;
@XmlElement(required = true)
public String deviceId;
@XmlElement(required = true)
public Float sensorValue;
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.dto;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* This stores sensor event data for drone.
*/
@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
public class SensorRecord {
@XmlElementWrapper(required = true, name = "values")
private Map<String, Object> values;
/**
* The id.
*/
@XmlElement(required = false, name = "id")
private String id;
/**
* Gets the values.
* @return the values
*/
public Map<String, Object> getValues() {
return values;
}
/**
* Sets the values.
* @param values the values
*/
public void setValues(Map<String, Object> values) {
this.values = values;
}
/**
* Gets the id.
* @return the id
*/
public String getId() {
return id;
}
/**
* Sets the id.
* @param id the new id
*/
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
List<String> valueList = new ArrayList<String>();
for (Map.Entry<String, Object> entry : values.entrySet()) {
valueList.add(entry.getKey() + ":" + entry.getValue());
}
return valueList.toString();
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.exception;
public class DroneAnalyzerException extends Exception {
private static final long serialVersionUID = 2736466230451105441L;
private String errorMessage;
public DroneAnalyzerException(String msg, DroneAnalyzerException nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public DroneAnalyzerException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public DroneAnalyzerException(String msg) {
super(msg);
setErrorMessage(msg);
}
public DroneAnalyzerException() {
super();
}
public DroneAnalyzerException(Throwable cause) {
super(cause);
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

View File

@ -0,0 +1,221 @@
package org.homeautomation.droneanalyzer.api.util;
import org.homeautomation.droneanalyzer.api.dto.SensorRecord;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterService;
import org.wso2.carbon.analytics.api.AnalyticsDataAPI;
import org.wso2.carbon.analytics.dataservice.core.AnalyticsDataServiceUtils;
import org.wso2.carbon.analytics.dataservice.commons.AnalyticsDataResponse;
import org.wso2.carbon.analytics.dataservice.commons.SearchResultEntry;
import org.wso2.carbon.analytics.dataservice.commons.SortByField;
import org.wso2.carbon.analytics.datasource.commons.Record;
import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException;
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class provides utility functions used by REST-API.
*/
public class APIUtil {
private static Log log = LogFactory.getLog(APIUtil.class);
public static String getAuthenticatedUser() {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
String username = threadLocalCarbonContext.getUsername();
String tenantDomain = threadLocalCarbonContext.getTenantDomain();
if (username.endsWith(tenantDomain)) {
return username.substring(0, username.lastIndexOf("@"));
}
return username;
}
public static DeviceManagementProviderService getDeviceManagementService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null);
if (deviceManagementProviderService == null) {
String msg = "Device Management service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceManagementProviderService;
}
public static APIManagementProviderService getAPIManagementProviderService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
APIManagementProviderService apiManagementProviderService =
(APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null);
if (apiManagementProviderService == null) {
String msg = "API management provider service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return apiManagementProviderService;
}
public static JWTClientManagerService getJWTClientManagerService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
JWTClientManagerService jwtClientManagerService =
(JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null);
if (jwtClientManagerService == null) {
String msg = "JWT Client manager service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return jwtClientManagerService;
}
public static String getTenantDomainOftheUser() {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
return threadLocalCarbonContext.getTenantDomain();
}
public static UserStoreManager getUserStoreManager() {
RealmService realmService;
UserStoreManager userStoreManager;
try {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
if (realmService == null) {
String msg = "Realm service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
int tenantId = ctx.getTenantId();
userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
} catch (UserStoreException e) {
String msg = "Error occurred while retrieving current user store manager";
log.error(msg, e);
throw new IllegalStateException(msg);
}
return userStoreManager;
}
public static void registerApiAccessRoles(String user) {
UserStoreManager userStoreManager = null;
try {
userStoreManager = getUserStoreManager();
String[] userList = new String[]{user};
if (userStoreManager != null) {
String rolesOfUser[] = userStoreManager.getRoleListOfUser(user);
if (!userStoreManager.isExistingRole(Constants.DEFAULT_ROLE_NAME)) {
userStoreManager.addRole(Constants.DEFAULT_ROLE_NAME, userList, Constants.DEFAULT_PERMISSION);
} else if (rolesOfUser != null && Arrays.asList(rolesOfUser).contains(Constants.DEFAULT_ROLE_NAME)) {
return;
} else {
userStoreManager.updateUserListOfRole(Constants.DEFAULT_ROLE_NAME, new String[0], userList);
}
}
} catch (UserStoreException e) {
log.error("Error while creating a role and adding a user for virtual_firealarm.", e);
}
}
public static DeviceAccessAuthorizationService getDeviceAccessAuthorizationService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
(DeviceAccessAuthorizationService) ctx.getOSGiService(DeviceAccessAuthorizationService.class, null);
if (deviceAccessAuthorizationService == null) {
String msg = "Device Authorization service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceAccessAuthorizationService;
}
public static List<SensorRecord> getAllEventsForDevice(String tableName, String query,
List<SortByField> sortByFields) throws AnalyticsException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI();
int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query);
if (eventCount == 0) {
return null;
}
List<SearchResultEntry> resultEntries = analyticsDataAPI.search(tenantId, tableName, query, 0, eventCount,
sortByFields);
List<String> recordIds = getRecordIds(resultEntries);
AnalyticsDataResponse response = analyticsDataAPI.get(tenantId, tableName, 1, null, recordIds);
Map<String, SensorRecord> sensorDatas = createSensorData(AnalyticsDataServiceUtils.listRecords(
analyticsDataAPI, response));
List<SensorRecord> sortedSensorData = getSortedSensorData(sensorDatas, resultEntries);
return sortedSensorData;
}
public static List<SensorRecord> getSortedSensorData(Map<String, SensorRecord> sensorDatas,
List<SearchResultEntry> searchResults) {
List<SensorRecord> sortedRecords = new ArrayList<>();
for (SearchResultEntry searchResultEntry : searchResults) {
sortedRecords.add(sensorDatas.get(searchResultEntry.getId()));
}
return sortedRecords;
}
private static List<String> getRecordIds(List<SearchResultEntry> searchResults) {
List<String> ids = new ArrayList<>();
for (SearchResultEntry searchResult : searchResults) {
ids.add(searchResult.getId());
}
return ids;
}
public static Map<String, SensorRecord> createSensorData(List<Record> records) {
Map<String, SensorRecord> sensorDatas = new HashMap<>();
for (Record record : records) {
SensorRecord sensorData = createSensorData(record);
sensorDatas.put(sensorData.getId(), sensorData);
}
return sensorDatas;
}
public static SensorRecord createSensorData(Record record) {
SensorRecord recordBean = new SensorRecord();
recordBean.setId(record.getId());
recordBean.setValues(record.getValues());
return recordBean;
}
public static AnalyticsDataAPI getAnalyticsDataAPI() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
AnalyticsDataAPI analyticsDataAPI =
(AnalyticsDataAPI) ctx.getOSGiService(AnalyticsDataAPI.class, null);
if (analyticsDataAPI == null) {
String msg = "Analytics api service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return analyticsDataAPI;
}
public static String getAuthenticatedUserTenantDomain() {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
return threadLocalCarbonContext.getTenantDomain();
}
public static OutputEventAdapterService getOutputEventAdapterService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
OutputEventAdapterService outputEventAdapterService =
(OutputEventAdapterService) ctx.getOSGiService(OutputEventAdapterService.class, null);
if (outputEventAdapterService == null) {
String msg = "Device Authorization service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return outputEventAdapterService;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.util;
import org.wso2.carbon.user.core.Permission;
/**
* This hold the constants related to the device type.
*/
public class Constants {
public static final String DEFAULT_PERMISSION_RESOURCE = "/permission/admin/device-mgt/drone/user";
public static final String DEFAULT_ROLE_NAME = "drone_user";
public static final Permission DEFAULT_PERMISSION[]
= new Permission[]{new Permission(Constants.DEFAULT_PERMISSION_RESOURCE, "ui.execute")};
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.util;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class ResponsePayload {
private int statusCode;
private String messageFromServer;
private Object responseContent;
public static ResponsePayloadBuilder statusCode(int statusCode) {
ResponsePayload message = new ResponsePayload();
return message.getBuilder().statusCode(statusCode);
}
public static ResponsePayloadBuilder messageFromServer(
String messageFromServer) {
ResponsePayload message = new ResponsePayload();
return message.getBuilder().messageFromServer(messageFromServer);
}
public static ResponsePayloadBuilder responseContent(String responseContent) {
ResponsePayload message = new ResponsePayload();
return message.getBuilder().responseContent(responseContent);
}
@XmlElement
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
@XmlElement
public String getMessageFromServer() {
return messageFromServer;
}
public void setMessageFromServer(String messageFromServer) {
this.messageFromServer = messageFromServer;
}
@XmlElement
public Object getResponseContent() {
return responseContent;
}
public void setResponseContent(Object responseContent) {
this.responseContent = responseContent;
}
private ResponsePayloadBuilder getBuilder() {
return new ResponsePayloadBuilder();
}
public class ResponsePayloadBuilder {
private int statusCode;
private String messageFromServer;
private Object responseContent;
public ResponsePayloadBuilder statusCode(int statusCode) {
this.statusCode = statusCode;
return this;
}
public ResponsePayloadBuilder messageFromServer(String messageFromServer) {
this.messageFromServer = messageFromServer;
return this;
}
public ResponsePayloadBuilder responseContent(String responseContent) {
this.responseContent = responseContent;
return this;
}
public ResponsePayload build() {
ResponsePayload payload = new ResponsePayload();
payload.setStatusCode(statusCode);
payload.setMessageFromServer(messageFromServer);
payload.setResponseContent(responseContent);
return payload;
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.util;
import org.homeautomation.droneanalyzer.plugin.constants.DroneAnalyzerConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublisherConfigurationException;
import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
/**
* This can be used to publish data to DAS for given stream definition
*/
public class ServiceUtils {
private static final Log log = LogFactory.getLog(ServiceUtils.class);
/**
* Sensor data are published to DAS
*
* @param deviceId unique identifier of the device
* @param sensorValue current value of sensor which is set at agent side
* @return
*/
public static boolean publishToDAS(String deviceId, float sensorValue) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
EventsPublisherService deviceAnalyticsService = (EventsPublisherService) ctx.getOSGiService(
EventsPublisherService.class, null);
String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
Object metdaData[] = {owner, DroneAnalyzerConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()};
Object payloadData[] = {sensorValue};
try {
deviceAnalyticsService.publishEvent(DroneAnalyzerConstants.SENSOR_STREAM_DEFINITION,
DroneAnalyzerConstants.SENSOR_STREAM_DEFINITION_VERSION, metdaData, new Object[0], payloadData);
} catch (DataPublisherConfigurationException e) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.homeautomation.droneanalyzer.api.util;
import org.homeautomation.droneanalyzer.plugin.mqtt.MqttConfig;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.iot.util.Utils;
import org.wso2.carbon.device.mgt.iot.util.ZipArchive;
import org.wso2.carbon.utils.CarbonUtils;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* This is used to create a zip file that includes the necessary configuration required for the agent.
*/
public class ZipUtil {
private static final String HTTPS_PORT_PROPERTY = "httpsPort";
private static final String HTTP_PORT_PROPERTY = "httpPort";
private static final String LOCALHOST = "localhost";
private static final String HTTPS_PROTOCOL_APPENDER = "https://";
private static final String HTTP_PROTOCOL_APPENDER = "http://";
public ZipArchive createZipFile(String owner, String tenantDomain, String deviceType,
String deviceId, String deviceName, String token,
String refreshToken) throws DeviceManagementException {
String sketchFolder = "repository" + File.separator + "resources" + File.separator + "sketches";
String archivesPath = CarbonUtils.getCarbonHome() + File.separator + sketchFolder + File.separator + "archives" +
File.separator + deviceId;
String templateSketchPath = sketchFolder + File.separator + deviceType;
String iotServerIP;
try {
iotServerIP = Utils.getServerUrl();
String httpsServerPort = System.getProperty(HTTPS_PORT_PROPERTY);
String httpServerPort = System.getProperty(HTTP_PORT_PROPERTY);
String httpsServerEP = HTTPS_PROTOCOL_APPENDER + iotServerIP + ":" + httpsServerPort;
String httpServerEP = HTTP_PROTOCOL_APPENDER + iotServerIP + ":" + httpServerPort;
String apimEndpoint = httpsServerEP;
String mqttEndpoint = MqttConfig.getInstance().getBrokerEndpoint();
if (mqttEndpoint.contains(LOCALHOST)) {
mqttEndpoint = mqttEndpoint.replace(LOCALHOST, iotServerIP);
}
Map<String, String> contextParams = new HashMap<>();
contextParams.put("SERVER_NAME", APIUtil.getTenantDomainOftheUser());
contextParams.put("DEVICE_OWNER", owner);
contextParams.put("DEVICE_ID", deviceId);
contextParams.put("DEVICE_NAME", deviceName);
contextParams.put("HTTPS_EP", httpsServerEP);
contextParams.put("HTTP_EP", httpServerEP);
contextParams.put("APIM_EP", apimEndpoint);
contextParams.put("MQTT_EP", mqttEndpoint);
contextParams.put("DEVICE_TOKEN", token);
contextParams.put("DEVICE_REFRESH_TOKEN", refreshToken);
ZipArchive zipFile;
zipFile = Utils.getSketchArchive(archivesPath, templateSketchPath, contextParams, deviceName);
return zipFile;
} catch (IOException e) {
throw new DeviceManagementException("Zip File Creation Failed", e);
}
}
}

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<!-- This file contains the list of permissions that are associated with URL end points
of the web app. Each permission should contain the name, permission path ,API path
(URL) , HTTP method and OAUTH2 authorization scope (not-required).
When defining dynamic paths for APIs, path variables are denoted by '*' notation.
NOTE: All the endpoints of the web app should be available in this file. Otherwise
it will result 403 error at the runtime.
-->
<PermissionConfiguration>
<APIVersion></APIVersion>
<!-- Device related APIs -->
<Permission>
<name>Get device</name>
<path>/device-mgt/drone/user</path>
<url>/device/*</url>
<method>GET</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Remove device</name>
<path>/device-mgt/drone/user</path>
<url>/device/*</url>
<method>DELETE</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Download device</name>
<path>/device-mgt/drone/user</path>
<url>/device/download</url>
<method>GET</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Update device</name>
<path>/device-mgt/drone/user</path>
<url>/device/*</url>
<method>POST</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Get Devices</name>
<path>/device-mgt/drone/user</path>
<url>/device</url>
<method>GET</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Register Device</name>
<path>/device-mgt/drone/user</path>
<url>/device/register</url>
<method>POST</method>
<scope>drone_device</scope>
</Permission>
<Permission>
<name>Control Sensor</name>
<path>/device-mgt/drone/user</path>
<url>/device/*/change-status</url>
<method>POST</method>
<scope>drone_user</scope>
</Permission>
<Permission>
<name>Get Stats</name>
<path>/device-mgt/drone/user</path>
<url>/device/stats/*</url>
<method>GET</method>
<scope>drone_device</scope>
</Permission>
</PermissionConfiguration>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
~ Copyright 2005-2013 WSO2, Inc. (http://wso2.com)
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!--
This file defines class loading policy of the whole container. But this behaviour can be overridden by individual webapps by putting this file into the META-INF/ directory.
-->
<Classloading xmlns="http://wso2.org/projects/as/classloading">
<!-- Parent-first or child-first. Default behaviour is child-first.-->
<ParentFirst>false</ParentFirst>
<!--
Default environments that contains provides to all the webapps. This can be overridden by individual webapps by specifing required environments
Tomcat environment is the default and every webapps gets it even if they didn't specify it.
e.g. If a webapps requires CXF, they will get both Tomcat and CXF.
-->
<Environments>CXF,Carbon</Environments>
</Classloading>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<jaxrs:server id="drone" address="/">
<jaxrs:serviceBeans>
<bean id="DroneAnalyzerService"
class="org.homeautomation.droneanalyzer.api.DroneAnalyzerServiceImpl">
</bean>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
</beans>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
metadata-complete="true">
<display-name>WSO2 IoT Server</display-name>
<description>WSO2 IoT Server</description>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>isAdminService</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>doAuthentication</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>isSharedWithAllTenants</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>providerTenantDomain</param-name>
<param-value>carbon.super</param-value>
</context-param>
<!--publish to apim-->
<context-param>
<param-name>managed-api-enabled</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>managed-api-owner</param-name>
<param-value>admin</param-value>
</context-param>
</web-app>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.homeautomation</groupId>
<artifactId>droneanalyzer-component</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>${project-base-package}.ui</artifactId>
<name>${project-base-package}.ui</name>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven-assembly-plugin.version}</version>
<configuration>
<finalName>${project.artifactId}-1.0.0</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/src.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>create-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>src</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<baseDirectory>${basedir}/src</baseDirectory>
<fileSets>
<fileSet>
<directory>${basedir}/src/main/resources/jaggeryapps/devicemgt</directory>
<outputDirectory>/</outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,55 @@
<span id="drone-details" data-devices="{{devices}}" data-devicename="{{device.name}}"
data-deviceid="{{device.deviceIdentifier}}"
data-appcontext="{{@app.context}}"></span>
<div id="drone-div-chart" data-backend-api-url= {{backendApiUrl}}>
<div class="chartWrapper" id="chartWrapper-battery">
<span id="span-title">Battery</span>
<div id="y_axis-battery" class="custom_y_axis"></div>
<div class="legend_container">
<div id="smoother-battery" title="Smoothing"></div>
<div id="legend-battery"></div>
</div>
<div id="chart-battery" class="custom_rickshaw_graph" ></div>
<div id="x_axis-battery" class="custom_x_axis"></div>
<div id="slider-battery" class="custom_slider"></div>
</div>
<div class="chartWrapper" id="chartWrapper-heading">
<span id="span-title">Heading</span>
<div id="y_axis-heading" class="custom_y_axis"></div>
<div class="legend_container">
<div id="smoother-heading" title="Smoothing"></div>
<div id="legend-heading"></div>
</div>
<div id="chart-heading" class="custom_rickshaw_graph" ></div>
<div id="x_axis-heading" class="custom_x_axis"></div>
<div id="slider-heading" class="custom_slider"></div>
</div>
<div class="chartWrapper" id="chartWrapper-bank">
<span id="span-title">Bank</span>
<div id="y_axis-bank" class="custom_y_axis"></div>
<div class="legend_container">
<div id="smoother-bank" title="Smoothing"></div>
<div id="legend-bank"></div>
</div>
<div id="chart-bank" class="custom_rickshaw_graph" ></div>
<div id="x_axis-bank" class="custom_x_axis"></div>
<div id="slider-bank" class="custom_slider"></div>
</div>
<div class="chartWrapper" id="chartWrapper-attitude">
<span id="span-title">Attitude</span>
<div id="y_axis-attitude" class="custom_y_axis"></div>
<div class="legend_container">
<div id="smoother-attitude" title="Smoothing"></div>
<div id="legend-attitude"></div>
</div>
<div id="chart-attitude" class="custom_rickshaw_graph" ></div>
<div id="x_axis-attitude" class="custom_x_axis"></div>
<div id="slider-attitude" class="custom_slider"></div>
</div>
</div>
{{#zone "bottomJs"}}
{{js "js/drone.js"}}
{{/zone}}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function onRequest(context) {
var devices = context.unit.params.devices;
var deviceType = context.uriParams.deviceType;
var deviceId = request.getParameter("deviceId");
if (devices) {
return {
"devices": stringify(devices),
"backendApiUrl": devicemgtProps["httpsURL"] + "/"+deviceType+"/device/stats/"
};
} else if (deviceType != null && deviceType != undefined && deviceId != null && deviceId != undefined) {
var deviceModule = require("/app/modules/device.js").deviceModule;
var device = deviceModule.viewDevice(deviceType, deviceId);
if (device && device.status != "error") {
return {
"device": device,
"backendApiUrl": devicemgtProps["httpsURL"] + "/"+deviceType+"/device/stats/" + deviceId
};
} else {
response.sendError(404, "Device Id " + deviceId + " of type " + deviceType + " cannot be found!");
exit();
}
}
}

View File

@ -0,0 +1,470 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* graph */
.rickshaw_graph {
position: relative;
}
.rickshaw_graph svg {
display: block;
overflow: hidden;
}
/* ticks */
.rickshaw_graph .x_tick {
position: absolute;
top: 0;
bottom: 0;
width: 0;
border-left: 1px dotted rgba(0, 0, 0, 0.2);
pointer-events: none;
}
.rickshaw_graph .x_tick .title {
position: absolute;
font-size: 12px;
font-family: Arial, sans-serif;
opacity: 0.5;
white-space: nowrap;
margin-left: 3px;
bottom: -20px;
height: auto;
border-bottom: none;
}
/* annotations */
.rickshaw_annotation_timeline {
height: 1px;
border-top: 1px solid #e0e0e0;
margin-top: 10px;
position: relative;
}
.rickshaw_annotation_timeline .annotation {
position: absolute;
height: 6px;
width: 6px;
margin-left: -2px;
top: -3px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.25);
}
.rickshaw_graph .annotation_line {
position: absolute;
top: 0;
bottom: -6px;
width: 0;
border-left: 2px solid rgba(0, 0, 0, 0.3);
display: none;
}
.rickshaw_graph .annotation_line.active {
display: block;
}
.rickshaw_graph .annotation_range {
background: rgba(0, 0, 0, 0.1);
display: none;
position: absolute;
top: 0;
bottom: -6px;
}
.rickshaw_graph .annotation_range.active {
display: block;
}
.rickshaw_graph .annotation_range.active.offscreen {
display: none;
}
.rickshaw_annotation_timeline .annotation .content {
background: white;
color: black;
opacity: 0.9;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
border-radius: 3px;
position: relative;
z-index: 20;
font-size: 12px;
padding: 6px 8px 8px;
top: 18px;
left: -11px;
width: 160px;
display: none;
cursor: pointer;
}
.rickshaw_annotation_timeline .annotation .content:before {
content: "\25b2";
position: absolute;
top: -11px;
color: white;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8);
}
.rickshaw_annotation_timeline .annotation.active,
.rickshaw_annotation_timeline .annotation:hover {
background-color: rgba(0, 0, 0, 0.8);
cursor: none;
}
.rickshaw_annotation_timeline .annotation .content:hover {
z-index: 50;
}
.rickshaw_annotation_timeline .annotation.active .content {
display: block;
}
.rickshaw_annotation_timeline .annotation:hover .content {
display: block;
z-index: 50;
}
.rickshaw_graph .y_axis,
.rickshaw_graph .x_axis_d3 {
fill: none;
}
.rickshaw_graph .y_ticks .tick line,
.rickshaw_graph .x_ticks_d3 .tick {
stroke: rgba(0, 0, 0, 0.16);
stroke-width: 2px;
shape-rendering: crisp-edges;
pointer-events: none;
}
.rickshaw_graph .y_grid .tick,
.rickshaw_graph .x_grid_d3 .tick {
z-index: -1;
stroke: rgba(0, 0, 0, 0.20);
stroke-width: 1px;
stroke-dasharray: 1 1;
}
.rickshaw_graph .y_grid .tick[data-y-value="0"] {
stroke-dasharray: 1 0;
}
.rickshaw_graph .y_grid path,
.rickshaw_graph .x_grid_d3 path {
fill: none;
stroke: none;
}
.rickshaw_graph .y_ticks path,
.rickshaw_graph .x_ticks_d3 path {
fill: none;
stroke: #808080;
}
.rickshaw_graph .y_ticks text,
.rickshaw_graph .x_ticks_d3 text {
opacity: 0.5;
font-size: 12px;
pointer-events: none;
}
.rickshaw_graph .x_tick.glow .title,
.rickshaw_graph .y_ticks.glow text {
fill: black;
color: black;
text-shadow: -1px 1px 0 rgba(255, 255, 255, 0.1),
1px -1px 0 rgba(255, 255, 255, 0.1),
1px 1px 0 rgba(255, 255, 255, 0.1),
0 1px 0 rgba(255, 255, 255, 0.1),
0 -1px 0 rgba(255, 255, 255, 0.1),
1px 0 0 rgba(255, 255, 255, 0.1),
-1px 0 0 rgba(255, 255, 255, 0.1),
-1px -1px 0 rgba(255, 255, 255, 0.1);
}
.rickshaw_graph .x_tick.inverse .title,
.rickshaw_graph .y_ticks.inverse text {
fill: white;
color: white;
text-shadow: -1px 1px 0 rgba(0, 0, 0, 0.8),
1px -1px 0 rgba(0, 0, 0, 0.8),
1px 1px 0 rgba(0, 0, 0, 0.8),
0 1px 0 rgba(0, 0, 0, 0.8),
0 -1px 0 rgba(0, 0, 0, 0.8),
1px 0 0 rgba(0, 0, 0, 0.8),
-1px 0 0 rgba(0, 0, 0, 0.8),
-1px -1px 0 rgba(0, 0, 0, 0.8);
}
.custom_rickshaw_graph {
position: relative;
left: 40px;
}
.custom_y_axis {
position: absolute;
width: 40px;
}
.custom_slider {
left: 40px;
}
.custom_x_axis {
position: relative;
left: 40px;
height: 30px;
width: 97%;
top: 20px;
text-align: right;
}
.chartWrapper {
padding-top: 50px;
}
/*detail*/
.rickshaw_graph .detail {
pointer-events: none;
position: absolute;
top: 0;
z-index: 2;
background: rgba(0, 0, 0, 0.1);
bottom: 0;
width: 1px;
transition: opacity 0.25s linear;
-moz-transition: opacity 0.25s linear;
-o-transition: opacity 0.25s linear;
-webkit-transition: opacity 0.25s linear;
}
.rickshaw_graph .detail.inactive {
opacity: 0;
}
.rickshaw_graph .detail .item.active {
opacity: 1;
}
.rickshaw_graph .detail .x_label {
font-family: Arial, sans-serif;
border-radius: 3px;
padding: 6px;
opacity: 0.5;
border: 1px solid #e0e0e0;
font-size: 12px;
position: absolute;
background: white;
white-space: nowrap;
}
.rickshaw_graph .detail .x_label.left {
left: 0;
}
.rickshaw_graph .detail .x_label.right {
right: 0;
}
.rickshaw_graph .detail .item {
position: absolute;
z-index: 2;
border-radius: 3px;
padding: 0.25em;
font-size: 12px;
font-family: Arial, sans-serif;
opacity: 0;
background: rgba(0, 0, 0, 0.4);
color: white;
border: 1px solid rgba(0, 0, 0, 0.4);
margin-left: 1em;
margin-right: 1em;
margin-top: -1em;
white-space: nowrap;
}
.rickshaw_graph .detail .item.left {
left: 0;
}
.rickshaw_graph .detail .item.right {
right: 0;
}
.rickshaw_graph .detail .item.active {
opacity: 1;
background: rgba(0, 0, 0, 0.8);
}
.rickshaw_graph .detail .item:after {
position: absolute;
display: block;
width: 0;
height: 0;
content: "";
border: 5px solid transparent;
}
.rickshaw_graph .detail .item.left:after {
top: 1em;
left: -5px;
margin-top: -5px;
border-right-color: rgba(0, 0, 0, 0.8);
border-left-width: 0;
}
.rickshaw_graph .detail .item.right:after {
top: 1em;
right: -5px;
margin-top: -5px;
border-left-color: rgba(0, 0, 0, 0.8);
border-right-width: 0;
}
.rickshaw_graph .detail .dot {
width: 4px;
height: 4px;
margin-left: -3px;
margin-top: -3.5px;
border-radius: 5px;
position: absolute;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
box-sizing: content-box;
-moz-box-sizing: content-box;
background: white;
border-width: 2px;
border-style: solid;
display: none;
background-clip: padding-box;
}
.rickshaw_graph .detail .dot.active {
display: block;
}
/*legend*/
.rickshaw_legend {
font-family: Arial;
font-size: 12px;
color: white;
background: #404040;
display: inline-block;
padding: 12px 5px;
border-radius: 2px;
position: relative;
float: right;
}
.rickshaw_legend:hover {
z-index: 10;
}
.rickshaw_legend .swatch {
width: 10px;
height: 10px;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.rickshaw_legend .line {
clear: both;
line-height: 140%;
padding-right: 15px;
}
.rickshaw_legend .line .swatch {
display: inline-block;
margin-right: 3px;
border-radius: 2px;
}
.rickshaw_legend .label {
margin: 0;
white-space: nowrap;
display: inline;
font-size: inherit;
background-color: transparent;
color: inherit;
font-weight: normal;
line-height: normal;
padding: 0;
text-shadow: none;
}
.rickshaw_legend .action:hover {
opacity: 0.6;
}
.rickshaw_legend .action {
margin-right: 0.2em;
opacity: 0.2;
cursor: pointer;
font-size: 14px;
}
.rickshaw_legend .line.disabled {
opacity: 0.4;
}
.rickshaw_legend ul {
list-style-type: none;
padding: 0;
margin: 2px;
cursor: pointer;
}
.rickshaw_legend li {
padding: 0 0 0 2px;
min-width: 80px;
white-space: nowrap;
}
.rickshaw_legend li:hover {
background: rgba(255, 255, 255, 0.08);
border-radius: 3px;
}
.rickshaw_legend li:active {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
.legend {
display: inline-block;
position: relative;
left: 8px;
}
.legend_container {
float: right;
padding-right: 10px;
width: 0;
z-index: 1;
position: relative;
opacity: 0.7;
}
.spaced {
margin-top: 20px !important;
}

View File

@ -0,0 +1,265 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var palette = new Rickshaw.Color.Palette({scheme: "classic9"});
var graphMap = {};
function drawGraph_drone(from, to) {
var devices = $("#drone-details").data("devices");
var tzOffset = new Date().getTimezoneOffset() * 60;
var streamIndex = 0;
var streams = ["battery", "heading", "bank", "attitude"];
populateGraph();
function populateGraph() {
if(streamIndex<4){
retrieveDataAndDrawLineGraph(streams[streamIndex], from, to);
}
streamIndex++;
}
function clearContent(type) {
$("#y_axis-" + type).html("");
$("#smoother-" + type).html("");
$("#legend-" + type).html("");
$("#chart-" + type).html("");
$("#x_axis-" + type).html("");
$("#slider-" + type).html("");
}
function initGraph(type, isMultilined) {
if (graphMap[type]) {
return graphMap[type];
}
var chartWrapperElmId = "#drone-div-chart";
var graphWidth = $(chartWrapperElmId).width() - 50;
console.log("document.getElementById("+ document.getElementById("chart-" + type)+ " ---"+ type);
var graphConfig = {
element: document.getElementById("chart-" + type),
width: graphWidth,
height: 400,
strokeWidth: 2,
renderer: 'line',
interpolation: "linear",
unstack: true,
stack: false,
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0.2},
series: []
};
if (devices) {
for (var i = 0; i < devices.length; i++) {
graphConfig['series'].push(
{
'color': palette.color(),
'data': [{
x: parseInt(new Date().getTime() / 1000),
y: 0
}],
'name': devices[i].name
});
}
} else {
if (isMultilined) {
graphConfig['series'].push(
{
'color': palette.color(),
'data': [{
x: parseInt(new Date().getTime() / 1000),
y: 0
}],
'name': "x"
},
{
'color': palette.color(),
'data': [{
x: parseInt(new Date().getTime() / 1000),
y: 0
}],
'name': "y"
},
{
'color': palette.color(),
'data': [{
x: parseInt(new Date().getTime() / 1000),
y: 0
}],
'name': "z"
}
);
} else {
graphConfig['series'].push(
{
'color': palette.color(),
'data': [{
x: parseInt(new Date().getTime() / 1000),
y: 0
}],
'name': $("#drone-details").data("devicename")
});
}
}
var graph = new Rickshaw.Graph(graphConfig);
graph.render();
var xAxis = new Rickshaw.Graph.Axis.Time({
graph: graph
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById("y_axis-" + type),
width: 40,
height: 410
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById("slider-" + type)
});
var legend = new Rickshaw.Graph.Legend({
graph: graph,
element: document.getElementById("legend-" + type)
});
var hoverDetail = new Rickshaw.Graph.HoverDetail({
graph: graph,
formatter: function (series, x, y) {
var date = '<span class="date">' +
moment((x + tzOffset) * 1000).format('Do MMM YYYY h:mm:ss a') + '</span>';
var swatch = '<span class="detail_swatch" style="background-color: ' +
series.color + '"></span>';
return swatch + series.name + ": " + parseInt(y) + '<br>' + date;
}
});
var shelving = new Rickshaw.Graph.Behavior.Series.Toggle({
graph: graph,
legend: legend
});
var order = new Rickshaw.Graph.Behavior.Series.Order({
graph: graph,
legend: legend
});
var highlighter = new Rickshaw.Graph.Behavior.Series.Highlight({
graph: graph,
legend: legend
});
graphMap[type] = {};
graphMap[type].graph = graph;
graphMap[type].config = graphConfig;
return graphMap[type];
}
function retrieveDataAndDrawLineGraph(type, from, to) {
var graphObj = initGraph(type, false);
var graph = graphObj.graph;
var graphConfig = graphObj.config;
var deviceIndex = 0;
if (devices) {
getData();
} else {
var backendApiUrl = $("#drone-div-chart").data("backend-api-url") + "?from=" + from + "&to=" + to;
var successCallback = function (data) {
if (data) {
drawLineGraph(JSON.parse(data));
}
populateGraph();
};
invokerUtil.get(backendApiUrl, successCallback, function (message) {
console.log(message);
populateGraph();
});
}
function getData() {
if (deviceIndex >= devices.length) {
return;
}
var backendApiUrl = $("#drone-div-chart").data("backend-api-url") + "?from=" + from + "&to=" + to;
var successCallback = function (data) {
if (data) {
drawLineGraph(JSON.parse(data));
}
deviceIndex++;
getData();
};
invokerUtil.get(backendApiUrl, successCallback, function (message) {
console.log(message);
deviceIndex++;
getData();
});
}
function drawLineGraph(data) {
if (data.length === 0 || data.length === undefined) {
return;
}
var chartData = [];
for (var i = 0; i < data.length; i++) {
chartData.push(
{
x: parseInt(data[i].values.meta_time) - tzOffset,
y: parseInt(getFieldData(data[i], type))
}
);
}
graphConfig.series[deviceIndex].data = chartData;
graph.update();
}
}
function getFieldData(data, type) {
var columnData;
switch (type) {
case "battery" :
columnData = data.values.battery_level;
break;
case "heading" :
columnData = data.values.yaw;
break;
case "bank" :
columnData = data.values.roll;
break;
case "attitude" :
columnData = data.values.pitch;
break;
}
return columnData;
}
}

View File

@ -0,0 +1,68 @@
{{#zone "topCss"}}
<style>
.thumbnail.icon:before {
padding-top: 0;
}
</style>
{{/zone}}
{{#zone "device-thumbnail"}}
<img src="{{@unit.publicUri}}/images/drone-icon.png"/>
{{/zone}}
{{#zone "device-opetations"}}
<div style="background: #11375B; color: #fff; padding: 10px; margin-bottom: 5px">
Operations
</div>
<div class="add-margin-top-4x">
{{unit "iot.unit.device.operation-bar" device=device backendApiUri=backendApiUri autoCompleteParams=autoCompleteParams}}
</div>
{{/zone}}
{{#zone "device-detail-properties"}}
<div class="media">
<div class="media-left col-xs-12 col-sm-2 col-md-2 col-lg-2">
<ul class="list-group" role="tablist">
<li class="active"><a class="list-group-item" href="#device_statistics" role="tab"
data-toggle="tab" aria-controls="device_statistics">Device
Statistics</a>
</li>
<li><a class="list-group-item" href="#event_log" role="tab" data-toggle="tab"
aria-controls="event_log">Operations Log</a></li>
</ul>
</div>
<div class="media-body add-padding-left-5x remove-padding-xs tab-content">
<div class="panel-group tab-content">
<div class="panel panel-default tab-pane active"
id="device_statistics" role="tabpanel" aria-labelledby="device_statistics">
<div class="panel-heading">Device Statistics</div>
{{unit "cdmf.unit.device.type.drone.realtime.analytics-view" device=device}}
</div>
<div class="panel panel-default tab-pane" id="event_log" role="tabpanel"
aria-labelledby="event_log">
<div class="panel-heading">Operations Log <span><a href="#"
id="refresh-operations"><i
class="fw fw-refresh"></i></a></span></div>
<div class="panel-body">
<div id="operations-spinner" class="wr-advance-operations-init hidden">
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<i class="fw fw-settings fw-spin fw-2x"></i>
&nbsp;&nbsp;&nbsp;
Loading Operations Log . . .
<br>
<br>
</div>
<div id="operations-log-container">
<div class="panel-body">
Not available yet
</div>
<br class="c-both"/>
</div>
</div>
</div>
</div>
</div>
</div>
{{/zone}}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function onRequest(context) {
var log = new Log("device-view.js");
var deviceType = context.uriParams.deviceType;
var deviceId = request.getParameter("id");
var autoCompleteParams = [
{"name" : "deviceId", "value" : deviceId}
];
if (deviceType != null && deviceType != undefined && deviceId != null && deviceId != undefined) {
var deviceModule = require("/app/modules/device.js").deviceModule;
var device = deviceModule.viewDevice(deviceType, deviceId);
if (device && device.status != "error") {
return {"device": device, "backendApiUri" : devicemgtProps["httpsURL"] + "/"+deviceType+"/", "autoCompleteParams" : autoCompleteParams};
} else {
response.sendError(404, "Device Id " + deviceId + " of type " + deviceType + " cannot be found!");
exit();
}
}
}

View File

@ -0,0 +1,210 @@
{{#zone "topCss"}}
{{css "css/graph.css"}}
{{css "css/main-app.css" }}
{{/zone}}
<div id="div-chart" data-websocketurl="{{websocketEndpoint}}">
<div class="chartWrapper" id="chartWrapper">
<div class=" row">
<div class="box col-md-12">
<div>
<div class="col-md-0.5 col-sm-1 col-xs-2">
<p>Battery Level </p>
</div>
<div class="col-md-4 col-sm-2 col-xs-2">
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0"
aria-valuemax="100" style="width: 0%;" id="batteryLevelPlaceholder">
<p id="batteryLevel">0%</p>
</div>
</div>
</div>
<div class="col-md-1 col-sm-1 col-xs-2">
<p>Battery Voltage </p>
</div>
<div class="col-md-4 col-sm-2 col-xs-2">
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0"
aria-valuemax="100" style="width: 0%;" id="batteryVoltagePlaceholder">
<p id="batteryVoltage">0%</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="box col-md-12">
<div class="box col-md-4">
<div class="box-inner">
<div class="box-header well" data-original-title="">
<h2><i class="glyphicon glyphicon-list"></i> Angle of Rotation</h2>
<div class="box-icon" id="Rotation">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content" style="position: relative;" id="objectHolder">
<div class="grayscale" border-radius="2" id="virtualDrone">
</div>
</div>
</div>
</div>
<div class="box col-md-2">
<div class="box-inner" style="max-height: 280px;">
<div class="box-header well" data-original-title="">
<div class="box-icon" id="AngleOfRotation">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<div style="position: relative;">
<img class="grayscale" id="imageTop"
src="{{@unit.publicUri}}/images/drone_position_controller/direction_drone.png"
style="width: 100%;"/>
<img class="grayscale" id="imageBack"
src="{{@unit.publicUri}}/images/drone_position_controller/background_drone.png"
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"/>
</div>
</div>
</div>
</div>
<div class="box col-md-2">
<div class="box-inner" style="max-height: 280px;">
<div class="box-header well" data-original-title="">
<div class="box-icon">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<div style="position: relative;">
<img id="imageBackSecond"
src="{{@unit.publicUri}}/images/drone_position_controller/pitch_drone.png"
style="width: 100%;"/>
<img id="imageTopSecond"
src="{{@unit.publicUri}}/images/drone_position_controller/background_drone.png"
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"/>
</div>
</div>
</div>
</div>
<div class="box col-md-4">
<div class="box-inner">
<div class="box-header well" data-original-title="">
<h2><i class="glyphicon glyphicon-list"></i>Live Video Stream</h2>
<div class="box-icon" id="LiveVideoStream">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<img class="grayscale" src="{{@unit.publicUri}}/images/no_video_preview.gif"
alt="video stream" style="display: block; height:225px; margin: auto;">
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="box col-md-12">
<div class="box col-md-4">
<div class="box-inner">
<div class="box-header well" data-original-title="">
<h2><i class="glyphicon glyphicon-list"></i>Sensor Readings</h2>
<div class="box-icon" id="SensorReadings">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content" id="basicSensoReading">
<div>
<p>Location</br> latitude: <label id="locationLat"></label></br>
longitude: <label id="locationLog"></label></br>
altitudes: <label id="locationAlt"></label></p>
<p> Velocity:</br> x :<label id="velocityx"></label></br>
y : <label id="velocityy"></label></br>
z : <label id="velocityz"></label></p>
</div>
</div>
</div>
</div>
<div class="box col-md-8">
<div class="box-inner">
<div class="box-header well" data-original-title="">
<h2><i class="glyphicon glyphicon-list-alt"></i>Realtime Plotting</h2>
<div class="box-icon" id="RealtimePlotting">
<a href="#" class="btn btn-minimize btn-round btn-default"><i
class="glyphicon glyphicon-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<div class="row">
<div class="box col-md-4" id="plottingMetadata" style="margin-left: 5%">
<div>
Window size : <label id="windowSizeCurrentValue">30</label>
<div id="windowSize" style="width: 100%;"></div>
<br>
Update period : <label id="windowUpdateValue">300</label>
</div>
<div id="windowUpdate" style="width: 100%;"></div>
</br>
<div style="width:100%;">Y-axis: <label>Min: <input id="rangeMin" type="text"
value="-4" size="3"></label>
<label>Max: <input id="rangeMax" value="4" type="text" size="3"></label></div>
<div style="width:100%;"><select ng-model='discussionsSelect' class='form-control'
id="plottingAttribute">
<option value='heading' selected>Heading</option>
<option value='bank'>Bank</option>
<option value='attitude'>Attitude</option>
</select></div>
</br>
<div>
<button class="btn btn-primary" id="replotting">Replot</button>
</div>
</div>
<div class="box col-md-8" id="realtimeChart" style="width:20%; height: 250px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="padding-left"
href="{{@app.context}}/device/{{device.type}}/analytics?deviceId={{device.deviceIdentifier}}&deviceName={{device.name}}">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-statistics fw-stack-1x"></i>
</span> View Device Analytics
</a>
<!-- /statistics -->
{{#zone "bottomJs"}}
{{js "js/libs/d3.min.js"}}
{{js "js/libs/rickshaw.min.js"}}
{{js "js/libs/moment.min.js"}}
{{js "js/libs/socket.io.min.js"}}
{{js "/js/libs/three.min.js" }}
{{js "/js/libs/Coordinates.js" }}
{{js "/js/libs/OrbitAndPanControls.js" }}
{{js "/js/3DDroneController/controler.js" }}
{{js "/js/libs/jQueryRotate.js" }}
{{js "/js/config/config.js" }}
{{js "/js/common/ajaxHandler.js" }}
{{js "/js/modules/realtimePlotting.js" }}
{{js "/js/init.js" }}
{{js "/js/modules/controller.js" }}
{{js "/js/modules/flightDynamics.js" }}
{{js "/js/mainHandler.js" }}
{{/zone}}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
function onRequest(context) {
var log = new Log("stats.js");
var device = context.unit.params.device;
var devicemgtProps = require('/app/conf/devicemgt-props.js').config();
var constants = require("/app/modules/constants.js");
var websocketEndpoint = devicemgtProps["httpsURL"].replace("https", "wss");
var tokenPair = session.get(constants.ACCESS_TOKEN_PAIR_IDENTIFIER);
var token = "";
if (tokenPair) {
token = tokenPair.accessToken;
}
websocketEndpoint = websocketEndpoint + "/secured-outputui/org.wso2.iot.devices.droneStats/1.0.0?" +
"token="+ token +"&deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type;
return {"device": device, "websocketEndpoint" : websocketEndpoint};
}

View File

@ -0,0 +1,471 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* graph */
.rickshaw_graph {
position: relative;
}
.rickshaw_graph svg {
display: block;
overflow: hidden;
}
/* ticks */
.rickshaw_graph .x_tick {
position: absolute;
top: 0;
bottom: 0;
width: 0;
border-left: 1px dotted rgba(0, 0, 0, 0.2);
pointer-events: none;
}
.rickshaw_graph .x_tick .title {
position: absolute;
font-size: 12px;
font-family: Arial, sans-serif;
opacity: 0.5;
white-space: nowrap;
margin-left: 3px;
bottom: -20px;
height: auto;
border-bottom: none;
}
/* annotations */
.rickshaw_annotation_timeline {
height: 1px;
border-top: 1px solid #e0e0e0;
margin-top: 10px;
position: relative;
}
.rickshaw_annotation_timeline .annotation {
position: absolute;
height: 6px;
width: 6px;
margin-left: -2px;
top: -3px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.25);
}
.rickshaw_graph .annotation_line {
position: absolute;
top: 0;
bottom: -6px;
width: 0;
border-left: 2px solid rgba(0, 0, 0, 0.3);
display: none;
}
.rickshaw_graph .annotation_line.active {
display: block;
}
.rickshaw_graph .annotation_range {
background: rgba(0, 0, 0, 0.1);
display: none;
position: absolute;
top: 0;
bottom: -6px;
}
.rickshaw_graph .annotation_range.active {
display: block;
}
.rickshaw_graph .annotation_range.active.offscreen {
display: none;
}
.rickshaw_annotation_timeline .annotation .content {
background: white;
color: black;
opacity: 0.9;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
border-radius: 3px;
position: relative;
z-index: 20;
font-size: 12px;
padding: 6px 8px 8px;
top: 18px;
left: -11px;
width: 160px;
display: none;
cursor: pointer;
}
.rickshaw_annotation_timeline .annotation .content:before {
content: "\25b2";
position: absolute;
top: -11px;
color: white;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8);
}
.rickshaw_annotation_timeline .annotation.active,
.rickshaw_annotation_timeline .annotation:hover {
background-color: rgba(0, 0, 0, 0.8);
cursor: none;
}
.rickshaw_annotation_timeline .annotation .content:hover {
z-index: 50;
}
.rickshaw_annotation_timeline .annotation.active .content {
display: block;
}
.rickshaw_annotation_timeline .annotation:hover .content {
display: block;
z-index: 50;
}
.rickshaw_graph .y_axis,
.rickshaw_graph .x_axis_d3 {
fill: none;
}
.rickshaw_graph .y_ticks .tick line,
.rickshaw_graph .x_ticks_d3 .tick {
stroke: rgba(0, 0, 0, 0.16);
stroke-width: 2px;
shape-rendering: crisp-edges;
pointer-events: none;
}
.rickshaw_graph .y_grid .tick,
.rickshaw_graph .x_grid_d3 .tick {
z-index: -1;
stroke: rgba(0, 0, 0, 0.20);
stroke-width: 1px;
stroke-dasharray: 1 1;
}
.rickshaw_graph .y_grid .tick[data-y-value="0"] {
stroke-dasharray: 1 0;
}
.rickshaw_graph .y_grid path,
.rickshaw_graph .x_grid_d3 path {
fill: none;
stroke: none;
}
.rickshaw_graph .y_ticks path,
.rickshaw_graph .x_ticks_d3 path {
fill: none;
stroke: #808080;
}
.rickshaw_graph .y_ticks text,
.rickshaw_graph .x_ticks_d3 text {
opacity: 0.5;
font-size: 12px;
pointer-events: none;
}
.rickshaw_graph .x_tick.glow .title,
.rickshaw_graph .y_ticks.glow text {
fill: black;
color: black;
text-shadow: -1px 1px 0 rgba(255, 255, 255, 0.1),
1px -1px 0 rgba(255, 255, 255, 0.1),
1px 1px 0 rgba(255, 255, 255, 0.1),
0 1px 0 rgba(255, 255, 255, 0.1),
0 -1px 0 rgba(255, 255, 255, 0.1),
1px 0 0 rgba(255, 255, 255, 0.1),
-1px 0 0 rgba(255, 255, 255, 0.1),
-1px -1px 0 rgba(255, 255, 255, 0.1);
}
.rickshaw_graph .x_tick.inverse .title,
.rickshaw_graph .y_ticks.inverse text {
fill: white;
color: white;
text-shadow: -1px 1px 0 rgba(0, 0, 0, 0.8),
1px -1px 0 rgba(0, 0, 0, 0.8),
1px 1px 0 rgba(0, 0, 0, 0.8),
0 1px 0 rgba(0, 0, 0, 0.8),
0 -1px 0 rgba(0, 0, 0, 0.8),
1px 0 0 rgba(0, 0, 0, 0.8),
-1px 0 0 rgba(0, 0, 0, 0.8),
-1px -1px 0 rgba(0, 0, 0, 0.8);
}
.custom_rickshaw_graph {
position: relative;
left: 40px;
}
.custom_y_axis {
position: absolute;
width: 40px;
margin-top: -20px;
}
.custom_slider {
left: 40px;
}
.custom_x_axis {
position: relative;
left: 40px;
height: 30px;
width: 97%;
top: 20px;
text-align: right;
}
.chartWrapper {
padding-top: 50px;
}
/*detail*/
.rickshaw_graph .detail {
pointer-events: none;
position: absolute;
top: 0;
z-index: 2;
background: rgba(0, 0, 0, 0.1);
bottom: 0;
width: 1px;
transition: opacity 0.25s linear;
-moz-transition: opacity 0.25s linear;
-o-transition: opacity 0.25s linear;
-webkit-transition: opacity 0.25s linear;
}
.rickshaw_graph .detail.inactive {
opacity: 0;
}
.rickshaw_graph .detail .item.active {
opacity: 1;
}
.rickshaw_graph .detail .x_label {
font-family: Arial, sans-serif;
border-radius: 3px;
padding: 6px;
opacity: 0.5;
border: 1px solid #e0e0e0;
font-size: 12px;
position: absolute;
background: white;
white-space: nowrap;
}
.rickshaw_graph .detail .x_label.left {
left: 0;
}
.rickshaw_graph .detail .x_label.right {
right: 0;
}
.rickshaw_graph .detail .item {
position: absolute;
z-index: 2;
border-radius: 3px;
padding: 0.25em;
font-size: 12px;
font-family: Arial, sans-serif;
opacity: 0;
background: rgba(0, 0, 0, 0.4);
color: white;
border: 1px solid rgba(0, 0, 0, 0.4);
margin-left: 1em;
margin-right: 1em;
margin-top: -1em;
white-space: nowrap;
}
.rickshaw_graph .detail .item.left {
left: 0;
}
.rickshaw_graph .detail .item.right {
right: 0;
}
.rickshaw_graph .detail .item.active {
opacity: 1;
background: rgba(0, 0, 0, 0.8);
}
.rickshaw_graph .detail .item:after {
position: absolute;
display: block;
width: 0;
height: 0;
content: "";
border: 5px solid transparent;
}
.rickshaw_graph .detail .item.left:after {
top: 1em;
left: -5px;
margin-top: -5px;
border-right-color: rgba(0, 0, 0, 0.8);
border-left-width: 0;
}
.rickshaw_graph .detail .item.right:after {
top: 1em;
right: -5px;
margin-top: -5px;
border-left-color: rgba(0, 0, 0, 0.8);
border-right-width: 0;
}
.rickshaw_graph .detail .dot {
width: 4px;
height: 4px;
margin-left: -3px;
margin-top: -3.5px;
border-radius: 5px;
position: absolute;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
box-sizing: content-box;
-moz-box-sizing: content-box;
background: white;
border-width: 2px;
border-style: solid;
display: none;
background-clip: padding-box;
}
.rickshaw_graph .detail .dot.active {
display: block;
}
/*legend*/
.rickshaw_legend {
font-family: Arial;
font-size: 12px;
color: white;
background: #404040;
display: inline-block;
padding: 12px 5px;
border-radius: 2px;
position: relative;
float: right;
}
.rickshaw_legend:hover {
z-index: 10;
}
.rickshaw_legend .swatch {
width: 10px;
height: 10px;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.rickshaw_legend .line {
clear: both;
line-height: 140%;
padding-right: 15px;
}
.rickshaw_legend .line .swatch {
display: inline-block;
margin-right: 3px;
border-radius: 2px;
}
.rickshaw_legend .label {
margin: 0;
white-space: nowrap;
display: inline;
font-size: inherit;
background-color: transparent;
color: inherit;
font-weight: normal;
line-height: normal;
padding: 0;
text-shadow: none;
}
.rickshaw_legend .action:hover {
opacity: 0.6;
}
.rickshaw_legend .action {
margin-right: 0.2em;
opacity: 0.2;
cursor: pointer;
font-size: 14px;
}
.rickshaw_legend .line.disabled {
opacity: 0.4;
}
.rickshaw_legend ul {
list-style-type: none;
padding: 0;
margin: 2px;
cursor: pointer;
}
.rickshaw_legend li {
padding: 0 0 0 2px;
min-width: 80px;
white-space: nowrap;
}
.rickshaw_legend li:hover {
background: rgba(255, 255, 255, 0.08);
border-radius: 3px;
}
.rickshaw_legend li:active {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
.legend {
display: inline-block;
position: relative;
left: 8px;
}
.legend_container {
float: right;
padding-right: 10px;
width: 0;
z-index: 1;
position: relative;
opacity: 0.7;
}
.spaced {
margin-top: 20px !important;
}

View File

@ -0,0 +1,220 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
.box {
margin-top: 10px;
margin-bottom: 10px;
}
.box-inner {
border: 1px solid #DEDEDE;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0 0 10px rgba(189, 189, 189, 0.4);
-webkit-box-shadow: 0 0 10px rgba(189, 189, 189, 0.4);
-moz-box-shadow: 0 0 10px rgba(189, 189, 189, 0.4);
}
.box-header {
border: none;
padding-top: 5px;
border-bottom: 1px solid #DEDEDE;
border-radius: 3px 3px 0 0;
-webkit-border-radius: 3px 3px 0 0;
-moz-border-radius: 3px 3px 0 0;
height: 35px;
min-height: 35px !important;
margin-bottom: 0;
font-weight: bold;
font-size: 16px;
background: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(0, 0, 0, 0.1)));
background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
background: -o-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
background: -ms-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffffff', endColorstr='#1a000000', GradientType=0);
}
.box-header h2 {
font-size: 15px;
width: auto;
clear: none;
float: left;
line-height: 25px;
white-space: nowrap;
font-weight: bold;
margin-top: 0;
margin-bottom: 0;
}
.box-header h3 {
font-size: 13px;
width: auto;
clear: none;
float: left;
line-height: 25px;
white-space: nowrap;
}
.box-header h2 > i {
margin-top: 1px;
}
.box-icon {
float: right;
}
.box-icon a {
clear: none;
float: left;
margin: 0 2px;
height: 20px;
width: 5px;
margin-top: 1px;
}
.box-icon a i {
margin-left: -6px;
top: -1px;
}
.box-content {
padding: 10px;
}
.btn-round {
border-radius: 40px;
-webkit-border-radius: 40px;
-moz-border-radius: 40px;
font-size: 12px;
padding-top: 4px;
}
.navbar-brand {
font-family: 'Shojumaru', cursive, Arial, serif;
letter-spacing: 2px;
text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
width: 183px;
font-size: 17px;
}
.navbar-brand img {
float: left;
height: 20px;
width: 20px;
margin-right: 5px;
}
.navbar-brand span {
float: left;
}
.navbar-search {
margin-left: 10px;
margin-top: 7px;
}
.navbar-inner {
padding-top: 5px;
padding-bottom: 5px;
line-height: 30px;
height: 60px;
}
.navbar-inner .btn-group {
margin: 7px 5px 0 5px;
}
.bs-icons li {
list-style: none;
}
.box-content .nav-tabs {
margin-right: -10px;
margin-left: -10px;
}
.box-content.buttons {
min-height: 297px;
}
.sidebar-nav .nav-header {
display: block;
padding: 3px 15px;
font-size: 11px;
font-weight: bold;
line-height: 18px;
color: #999999;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-transform: uppercase;
}
.navbar {
border-radius: 0;
}
.circle {
background: none repeat scroll 0 0 #191919;
border-radius: 50px;
height: 50px;
padding: 10px;
width: 50px;
color: #fff;
}
.padding-top-double {
padding-top: 20px;
}
.padding-double {
padding: 20px;
}
.grey {
color: #333;
}
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #7f7f7f;
margin: 1em 0;
padding: 0;
opacity: 0.2;
}
.light-grey {
color: #7c7c7c;
}
.uppercase {
text-transform: uppercase;
}
.grey-bg {
background-color: #f6f4f4;
}
path {
stroke: black;
stroke-width: 2;
fill: none;
}
.axis path, .axis line {
fill: none;
stroke: #ccc;
stroke-width: 2;
shape-rendering: crispEdges;
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var camera, scene, renderer;
var cameraControls;
var clock = new THREE.Clock();
var ground = true;
var circle1, plate1;
var droneRender = function () {
var api = this;
api.fillScene = function () {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x808080, 2000, 4000);
var ambientLight = new THREE.AmbientLight(0x222222);
var light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
light.position.set(200, 400, 500);
var light2 = new THREE.DirectionalLight(0xFFFFFF, 1.0);
light2.position.set(-500, 250, -200);
scene.add(ambientLight);
scene.add(light);
scene.add(light2);
if (ground) {
Coordinates.drawGround({size: 10000});
}
var robotBaseMaterial = new THREE.MeshPhongMaterial({color: 0x6E23BB, specular: 0x6E23BB, shininess: 20});
var robotForearmMaterial = new THREE.MeshPhongMaterial({color: 0xF4C154, specular: 0xF4C154, shininess: 100});
circle1 = new THREE.Object3D();
var circleLength = 40;
api.addCircles(circle1, circleLength, robotBaseMaterial);
circle1.position.y = circleLength * 2;
scene.add(circle1);
plate1 = new THREE.Object3D();
var plateLength = 40;
api.addPlates(plate1, plateLength, robotForearmMaterial);
plate1.position.y = circleLength / 8;
circle1.add(plate1);
},
api.addPlates = function (part, plateLength, material) {
var cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.x = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.x = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.x = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.x = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.z = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.z = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.z = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.z = plateLength + 15;
part.add(cylinder);
},
api.addCircles = function (part, circleLength, material) {
var circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.x = circleLength + 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.x = -circleLength - 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.z = -circleLength - 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.z = circleLength + 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
},
api.init = function (holder, object_width, object_height) {
var canvasRatio = 1;
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setSize(object_width, object_height);
renderer.setClearColorHex(0xAAAAAA, 1.0);
$(holder).append(renderer.domElement);
camera = new THREE.PerspectiveCamera(30, canvasRatio, 1, 10000);
camera.position.set(-510, 240, 100);
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
cameraControls.target.set(0, 100, 0);
api.fillScene();
},
api.animate = function () {
window.requestAnimationFrame(api.animate);
api.render();
},
api.render = function () {
var delta = clock.getDelta();
cameraControls.update(delta);
circle1.rotation.z = config.effectController.uz;
circle1.rotation.y = config.effectController.uy; // yaw
circle1.rotation.x = config.effectController.ux; // roll
circle1.position.z = config.effectController.fz;
circle1.position.x = config.effectController.fx;
renderer.render(scene, camera);
},
api.getHeadingAttitudeAndBank = function (data) {
if (data.length < 4) {
return {"heading": data[0], "attitude": data[1], "bank": data[2]};
} else {
var heading = Math.atan2(2 * data[1] * data[3] - 2 * data[0] * data[1], 1 - 2 * data[1] * data[1]
- 2 * data[2] * data[2]);
var bank = Math.atan2(2 * data[0] * data[3] - 2 * data[1] * data[2], 1 - 2 * data[0] * data[0]
- 2 * data[2] * data[2]);
var attitude = Math.asin(2 * data[0] * data[1] + 2 * data[2] * data[3]);
return {
"heading": isNaN(heading) ? 0 : heading,
"bank": isNaN(bank) ? 0 : bank,
"attitude": isNaN(attitude) ? 0 : attitude
};
}
},
api.setHeadingAttitudeAndBank = function (data) {
config.effectController.uy = data.heading;
config.effectController.uz = data.attitude;
config.effectController.ux = data.bank;
},
api.setHeading = function (holder, heading) {
var r = (180 / Math.PI) * parseFloat(heading);
$(holder).rotate(r);
},
api.setBank = function (holder, bank) {
var r = (180 / Math.PI) * parseFloat(bank);
$(holder).rotate(r);
}
};

View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var camera, scene, renderer;
var cameraControls;
var clock = new THREE.Clock();
var ground = true;
var circle1, plate1;
var object_maker = function () {
var make_object = this;
make_object.fillScene = function () {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x808080, 2000, 4000);
var ambientLight = new THREE.AmbientLight(0x222222);
var light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
light.position.set(200, 400, 500);
var light2 = new THREE.DirectionalLight(0xFFFFFF, 1.0);
light2.position.set(-500, 250, -200);
scene.add(ambientLight);
scene.add(light);
scene.add(light2);
if (ground) {
Coordinates.drawGround({size: 10000});
}
var robotBaseMaterial = new THREE.MeshPhongMaterial({color: 0x6E23BB, specular: 0x6E23BB, shininess: 20});
var robotForearmMaterial = new THREE.MeshPhongMaterial({color: 0xF4C154, specular: 0xF4C154, shininess: 100});
circle1 = new THREE.Object3D();
var circleLength = 40;
make_object.addCircles(circle1, circleLength, robotBaseMaterial);
circle1.position.y = circleLength * 2;
scene.add(circle1);
plate1 = new THREE.Object3D();
var plateLength = 40;
make_object.addPlates(plate1, plateLength, robotForearmMaterial);
plate1.position.y = circleLength / 8;
circle1.add(plate1);
},
make_object.addPlates = function (part, plateLength, material) {
var cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.x = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.x = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.x = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.x = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.z = -plateLength - 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.z = -plateLength - 15;
part.add(cylinder);
//
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.position.z = plateLength + 15;
part.add(cylinder);
cylinder = new THREE.Mesh(
new THREE.CylinderGeometry(5, 5, 40, 32), material);
cylinder.rotation.x = 90 * Math.PI / 180;
cylinder.rotation.z = 90 * Math.PI / 180;
cylinder.position.z = plateLength + 15;
part.add(cylinder);
},
make_object.addCircles = function (part, circleLength, material) {
var circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.x = circleLength + 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.x = -circleLength - 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.z = -circleLength - 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
circle = new THREE.Mesh(
new THREE.TorusGeometry(40, 10, 40, 20, 6.3), material);
circle.position.z = circleLength + 10;
circle.rotation.x = 90 * Math.PI / 180;
part.add(circle);
},
make_object.init = function (holder, object_width, object_height) {
var canvasRatio = 1;
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setSize(object_width, object_height);
renderer.setClearColorHex(0xAAAAAA, 1.0);
$(holder).append(renderer.domElement);
camera = new THREE.PerspectiveCamera(30, canvasRatio, 1, 10000);
camera.position.set(-510, 240, 100);
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
cameraControls.target.set(0, 100, 0);
make_object.fillScene();
},
make_object.animate = function () {
window.requestAnimationFrame(make_object.animate);
make_object.render();
},
make_object.render = function () {
var delta = clock.getDelta();
cameraControls.update(delta);
circle1.rotation.z = config_api.effectController.uz;
circle1.rotation.y = config_api.effectController.uy; // yaw
circle1.rotation.x = config_api.effectController.ux; // roll
circle1.position.z = config_api.effectController.fz;
circle1.position.x = config_api.effectController.fx;
renderer.render(scene, camera);
},
make_object.get_heading_attitude_bank = function (data) {
if (data.length < 4) {
return {"heading": data[0], "attitude": data[1], "bank": data[2]};
} else {
var heading = Math.atan2(2 * data[1] * data[3] - 2 * data[0] * data[1], 1 - 2 * data[1] * data[1]
- 2 * data[2] * data[2]);
var bank = Math.atan2(2 * data[0] * data[3] - 2 * data[1] * data[2], 1 - 2 * data[0] * data[0]
- 2 * data[2] * data[2]);
var attitude = Math.asin(2 * data[0] * data[1] + 2 * data[2] * data[3]);
return {
"heading": isNaN(heading) ? 0 : heading,
"bank": isNaN(bank) ? 0 : bank,
"attitude": isNaN(attitude) ? 0 : attitude
};
}
},
make_object.set_heading_attitude_bank = function (data) {
config_api.effectController.uy = data.heading;
config_api.effectController.uz = data.attitude;
config_api.effectController.ux = data.bank;
},
make_object.set_heading = function (holder, heading) {
var r = (180 / Math.PI) * parseFloat(heading);
$(holder).rotate(r);
},
make_object.set_bank = function (holder, bank) {
var r = (180 / Math.PI) * parseFloat(bank);
$(holder).rotate(r);
}
};

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*global THREE, scene*/
var Coordinates = {
drawGrid:function(params) {
params = params || {};
var size = params.size !== undefined ? params.size:100;
var scale = params.scale !== undefined ? params.scale:0.1;
var orientation = params.orientation !== undefined ? params.orientation:"x";
var grid = new THREE.Mesh(
new THREE.PlaneGeometry(size, size, size * scale, size * scale),
new THREE.MeshBasicMaterial({ color: 0x555555, wireframe: true })
);
// Yes, these are poorly labeled! It would be a mess to fix.
// What's really going on here:
// "x" means "rotate 90 degrees around x", etc.
// So "x" really means "show a grid with a normal of Y"
// "y" means "show a grid with a normal of X"
// "z" means (logically enough) "show a grid with a normal of Z"
if (orientation === "x") {
grid.rotation.x = - Math.PI / 2;
} else if (orientation === "y") {
grid.rotation.y = - Math.PI / 2;
} else if (orientation === "z") {
grid.rotation.z = - Math.PI / 2;
}
scene.add(grid);
},
drawGround:function(params) {
params = params || {};
var size = params.size !== undefined ? params.size:100;
var color = params.color !== undefined ? params.color:0xFFFFFF;
var ground = new THREE.Mesh(
new THREE.PlaneGeometry(size, size),
// When we use a ground plane we use directional lights, so illuminating
// just the corners is sufficient.
// Use MeshPhongMaterial if you want to capture per-pixel lighting:
// new THREE.MeshPhongMaterial({ color: color, specular: 0x000000,
new THREE.MeshLambertMaterial({ color: color,
// polygonOffset moves the plane back from the eye a bit, so that the lines on top of
// the grid do not have z-fighting with the grid:
// Factor == 1 moves it back relative to the slope (more on-edge means move back farther)
// Units == 4 is a fixed amount to move back, and 4 is usually a good value
polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0
}));
ground.rotation.x = - Math.PI / 2;
scene.add(ground);
},
drawAxes:function(params) {
// x = red, y = green, z = blue (RGB = xyz)
params = params || {};
var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04;
var axisLength = params.axisLength !== undefined ? params.axisLength:11;
var axisTess = params.axisTess !== undefined ? params.axisTess:48;
var axisOrientation = params.axisOrientation !== undefined ? params.axisOrientation:"x";
var axisMaterial = new THREE.MeshLambertMaterial({ color: 0x000000, side: THREE.DoubleSide });
var axis = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisMaterial
);
if (axisOrientation === "x") {
axis.rotation.z = - Math.PI / 2;
axis.position.x = axisLength/2-1;
} else if (axisOrientation === "y") {
axis.position.y = axisLength/2-1;
}
scene.add( axis );
var arrow = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 8*axisRadius, axisTess, 1, true),
axisMaterial
);
if (axisOrientation === "x") {
arrow.rotation.z = - Math.PI / 2;
arrow.position.x = axisLength - 1 + axisRadius*4/2;
} else if (axisOrientation === "y") {
arrow.position.y = axisLength - 1 + axisRadius*4/2;
}
scene.add( arrow );
},
drawAllAxes:function(params) {
params = params || {};
var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04;
var axisLength = params.axisLength !== undefined ? params.axisLength:11;
var axisTess = params.axisTess !== undefined ? params.axisTess:48;
var axisXMaterial = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
var axisYMaterial = new THREE.MeshLambertMaterial({ color: 0x00FF00 });
var axisZMaterial = new THREE.MeshLambertMaterial({ color: 0x0000FF });
axisXMaterial.side = THREE.DoubleSide;
axisYMaterial.side = THREE.DoubleSide;
axisZMaterial.side = THREE.DoubleSide;
var axisX = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisXMaterial
);
var axisY = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisYMaterial
);
var axisZ = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisZMaterial
);
axisX.rotation.z = - Math.PI / 2;
axisX.position.x = axisLength/2-1;
axisY.position.y = axisLength/2-1;
axisZ.rotation.y = - Math.PI / 2;
axisZ.rotation.z = - Math.PI / 2;
axisZ.position.z = axisLength/2-1;
scene.add( axisX );
scene.add( axisY );
scene.add( axisZ );
var arrowX = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisXMaterial
);
var arrowY = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisYMaterial
);
var arrowZ = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisZMaterial
);
arrowX.rotation.z = - Math.PI / 2;
arrowX.position.x = axisLength - 1 + axisRadius*4/2;
arrowY.position.y = axisLength - 1 + axisRadius*4/2;
arrowZ.rotation.z = - Math.PI / 2;
arrowZ.rotation.y = - Math.PI / 2;
arrowZ.position.z = axisLength - 1 + axisRadius*4/2;
scene.add( arrowX );
scene.add( arrowY );
scene.add( arrowZ );
}
};

View File

@ -0,0 +1,549 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
*/
/*global THREE, console */
THREE.OrbitAndPanControls = function ( object, domElement ) {
THREE.EventDispatcher.call( this );
this.enabled = true;
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
this.enabled = true;
this.target = new THREE.Vector3();
// center is old, deprecated; use "target" instead
this.center = this.target;
// This option actually enables dollying in and out
this.noZoom = false;
this.zoomSpeed = 1.0;
this.noRotate = false;
this.rotateSpeed = 1.0;
this.noPan = false;
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
this.minDistance = 0;
this.maxDistance = Infinity;
this.noKeys = false;
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// internals
var scope = this;
var EPS = 0.000001;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var pan = new THREE.Vector3();
var lastPosition = new THREE.Vector3();
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
var state = STATE.NONE;
// events
var changeEvent = { type: 'change' };
this.rotateLeft = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta -= angle;
};
this.rotateUp = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta -= angle;
};
// pass in distance in world space to move left
this.panLeft = function ( distance ) {
var panOffset = new THREE.Vector3();
var te = this.object.matrix.elements;
// get X column of matrix
panOffset.set( te[0], te[1], te[2] );
panOffset.multiplyScalar(-distance);
pan.add( panOffset );
};
// pass in distance in world space to move up
this.panUp = function ( distance ) {
var panOffset = new THREE.Vector3();
var te = this.object.matrix.elements;
// get Y column of matrix
panOffset.set( te[4], te[5], te[6] );
panOffset.multiplyScalar(distance);
pan.add( panOffset );
};
// main entry point; pass in Vector2 of change desired in pixel space,
// right and down are positive
this.pan = function ( delta ) {
if ( scope.object.fov !== undefined )
{
// perspective
var position = scope.object.position;
var offset = position.clone().sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 );
// we actually don't use screenWidth, since perspective camera is fixed to screen height
scope.panLeft( 2 * delta.x * targetDistance / scope.domElement.height );
scope.panUp( 2 * delta.y * targetDistance / scope.domElement.height );
}
else if ( scope.object.top !== undefined )
{
// orthographic
scope.panLeft( delta.x * (scope.object.right - scope.object.left) / scope.domElement.width );
scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / scope.domElement.height );
}
else
{
// camera neither orthographic or perspective - warn user
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
}
};
this.dollyIn = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
scale /= dollyScale;
};
this.dollyOut = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
scale *= dollyScale;
};
this.update = function () {
var position = this.object.position;
var offset = position.clone().sub( this.target );
// angle from z-axis around y-axis
var theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
if ( this.autoRotate ) {
this.rotateLeft( getAutoRotationAngle() );
}
theta += thetaDelta;
phi += phiDelta;
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
// move target to panned location
this.target.add( pan );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
position.copy( this.target ).add( offset );
this.object.lookAt( this.target );
thetaDelta = 0;
phiDelta = 0;
scale = 1;
pan.set(0,0,0);
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
}
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
if ( event.button === 0 ) {
if ( scope.noRotate === true ) { return; }
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === 1 ) {
if ( scope.noZoom === true ) { return; }
state = STATE.DOLLY;
dollyStart.set( event.clientX, event.clientY );
} else if ( event.button === 2 ) {
if ( scope.noPan === true ) { return; }
state = STATE.PAN;
panStart.set( event.clientX, event.clientY );
}
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
}
function onMouseMove( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
if ( state === STATE.ROTATE ) {
if ( scope.noRotate === true ) { return; }
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.DOLLY ) {
if ( scope.noZoom === true ) { return; }
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyIn();
} else {
scope.dollyOut();
}
dollyStart.copy( dollyEnd );
} else if ( state === STATE.PAN ) {
if ( scope.noPan === true ) { return; }
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta );
panStart.copy( panEnd );
}
}
function onMouseUp( /* event */ ) {
if ( scope.enabled === false ) { return; }
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
state = STATE.NONE;
}
function onMouseWheel( event ) {
// this is needed when the program is inside an iframe
// to prevent scrolling the whole page
event.preventDefault();
if ( scope.enabled === false ) { return; }
if ( scope.noZoom === true ) { return; }
var delta = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail ) { // Firefox
delta = - event.detail;
}
if ( delta > 0 ) {
scope.dollyOut();
} else {
scope.dollyIn();
}
}
function onKeyDown( event ) {
if ( scope.enabled === false ) { return; }
if ( scope.noKeys === true ) { return; }
if ( scope.noPan === true ) { return; }
// pan a pixel - I guess for precise positioning?
switch ( event.keyCode ) {
case scope.keys.UP:
scope.pan( new THREE.Vector2( 0, 1 ) );
break;
case scope.keys.BOTTOM:
scope.pan( new THREE.Vector2( 0, -1 ) );
break;
case scope.keys.LEFT:
scope.pan( new THREE.Vector2( 1, 0 ) );
break;
case scope.keys.RIGHT:
scope.pan( new THREE.Vector2( -1, 0 ) );
break;
}
}
function touchstart( event ) {
if ( scope.enabled === false ) { return; }
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) { return; }
state = STATE.TOUCH_ROTATE;
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) { return; }
state = STATE.TOUCH_DOLLY;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyStart.set( 0, distance );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) { return; }
state = STATE.TOUCH_PAN;
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
default:
state = STATE.NONE;
}
}
function touchmove( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
event.stopPropagation();
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) { return; }
if ( state !== STATE.TOUCH_ROTATE ) { return; }
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) { return; }
if ( state !== STATE.TOUCH_DOLLY ) { return; }
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyEnd.set( 0, distance );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyOut();
} else {
scope.dollyIn();
}
dollyStart.copy( dollyEnd );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) { return; }
if ( state !== STATE.TOUCH_PAN ) { return; }
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta );
panStart.copy( panEnd );
break;
default:
state = STATE.NONE;
}
}
function touchend( /* event */ ) {
if ( scope.enabled === false ) { return; }
state = STATE.NONE;
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'keydown', onKeyDown, false );
this.domElement.addEventListener( 'touchstart', touchstart, false );
this.domElement.addEventListener( 'touchend', touchend, false );
this.domElement.addEventListener( 'touchmove', touchmove, false );
};

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ajax_handler = function () {
var api = this;
api.response = "v";
api.ajaxRequest = function (url, type, data, dataType, callback) {
var response;
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function (data, success) {
api.response = data;
callback(data, success);
},
error: function (jqxhr, textStatus, error) {
var err = textStatus + ', ' + error;
callback(data, error);
api.response = data;
},
data: data
});
return api.response;
};
api.makeJSONObject = function () {
var object = {};
for (var i = 0; i < arguments.length - 1; i = i + 2) {
object[arguments[i]] = arguments[i + 1];
}
return object;
}
};

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ajax_handler = function () {
var api = this;
api.response = "v";
api.ajaxRequest = function (url, type, data, dataType, callback) {
var response;
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function (data, success) {
api.response = data;
console.log(" success " + JSON.stringify(success));
console.log(" data " + JSON.stringify(data));
callback(data, success);
},
error: function (jqxhr, textStatus, error) {
var err = textStatus + ', ' + error;
console.log("Request Failed: " + err);
callback(data, error);
api.response = data;
},
data: data
});
return api.response;
};
api.makeJSONObject = function () {
var object = {};
for (var i = 0; i < arguments.length - 1; i = i + 2) {
object[arguments[i]] = arguments[i + 1];
}
return object;
}
};

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
$('.btn-minimize').click(function (e) {
e.preventDefault();
var $target = $(this).parent().parent().next('.box-content');
if ($target.is(':visible')) {
$('i', $(this)).removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down');
checkAndDisable($(this).parent().attr('id'));
}
else {
$('i', $(this)).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up');
checkAndEnable($(this).parent().attr('id'));
}
$target.slideToggle();
});
function checkAndEnable(id) {
//console.log("enable: " + id);
if (id === "RealtimePlotting") {
config_api.modules_status.realtimePlotting = true;
}
else if (id === "SensorReadings") {
config_api.modules_status.sensorReadings = true;
} else if (id === "AngleOfRotation_2") {
config_api.modules_status.angleOfRotation_2 = true;
} else if (id === "AngleOfRotation_1") {
config_api.modules_status.angleOfRotation_1 = true;
}
}
function checkAndDisable(id) {
//console.log("disable: " + id);
if (id === "RealtimePlotting") {
config_api.modules_status.realtimePlotting = false;
}
else if (id === "SensorReadings") {
config_api.modules_status.sensorReadings = false;
} else if (id === "AngleOfRotation_2") {
config_api.modules_status.angleOfRotation_2 = false;
} else if (id === "AngleOfRotation_1") {
config_api.modules_status.angleOfRotation_1 = false;
}
}
function isJSON(data) {
try {
return JSON.parse(data);
}
catch (error) {
return null;
}
}
function Queue() {
var a = [], b = '';
this.enqueue = function (b) {
a.push([this.getLength() - 1 <= 0 ? 0 : this.getLength() - 1, b]);
};
this.dequeue = function () {
if (0 != a.length) {
var c = a[b];
2 * ++b >= a.length && (a = a.slice(b), b = 0);
return c
}
};
this.getLength = function () {
return a.length - b;
};
this.isEmpty = function () {
return 0 == a.length;
};
this.peek = function () {
return 0 < a.length ? a[b] : void 0
};
this.getData = function () {
return a;
};
this.make_fixed_size = function (start, end) {
a = a.slice(start, end);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var config = function () {
var api = this;
api.configDronePlaceholder = "#virtualDrone";
api.realtimePlottingUpdateInterval = 30;
api.realtimePlottingTotalPoints = 30;
api.realtimePlottingDataWindow = {};
api.effectController = {uy: 70.0, uz: 15.0, ux: 10.0, fx: 2.0, fz: 15.0, Tmax: 1};
api.controlType = "POST";
api.dataType = "json";
api.modulesStatus = {
"realtimePlotting": false,
"sensorReadings": false,
"angleOfRotationv1": false,
"angleOfRotationv2": false
};
};

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ws;
var graph;
var chartData = [];
var palette = new Rickshaw.Color.Palette({scheme: "classic9"});
$(window).load(function () {
var tNow = new Date().getTime() / 1000;
for (var i = 0; i < 30; i++) {
chartData.push({
x: tNow - (30 - i) * 15,
y: parseFloat(0)
});
}
graph = new Rickshaw.Graph({
element: document.getElementById("chart"),
width: $("#div-chart").width() - 50,
height: 300,
renderer: "line",
padding: {top: 0.2, left: 0.0, right: 0.0, bottom: 0.2},
xScale: d3.time.scale(),
series: [{
'color': palette.color(),
'data': chartData,
'name': "Temperature"
}]
});
graph.render();
var xAxis = new Rickshaw.Graph.Axis.Time({
graph: graph
});
xAxis.render();
new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
height: 300,
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis')
});
new Rickshaw.Graph.HoverDetail({
graph: graph,
formatter: function (series, x, y) {
var date = '<span class="date">' + moment.unix(x*1000).format('Do MMM YYYY h:mm:ss a') + '</span>';
var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
return swatch + series.name + ": " + parseInt(y) + '<br>' + date;
}
});
var websocketUrl = $("#div-chart").data("websocketurl");
connect(websocketUrl)
});
$(window).unload(function () {
disconnect();
});
//websocket connection
function connect(target) {
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
console.log('WebSocket is not supported by this browser.');
}
if (ws) {
ws.onmessage = function (event) {
var dataPoint = JSON.parse(event.data);
/*var dataPoint = JSON.parse(event.data);
chartData.push({
x: parseInt(dataPoint[4]) / 1000,
y: parseFloat(dataPoint[5])
});
chartData.shift();
graph.update();*/
};
}
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
}
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var modalPopup = ".wr-modalpopup";
var modalPopupContainer = modalPopup + " .modalpopup-container";
var modalPopupContent = modalPopup + " .modalpopup-content";
var body = "body";
/*
* set popup maximum height function.
*/
function setPopupMaxHeight() {
$(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30)));
$(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2)));
}
/*
* show popup function.
*/
function showPopup() {
$(modalPopup).show();
setPopupMaxHeight();
$('#downloadForm').validate({
rules: {
deviceName: {
minlength: 4,
required: true
}
},
highlight: function (element) {
$(element).closest('.control-group').removeClass('success').addClass('error');
},
success: function (element) {
$(element).closest('.control-group').removeClass('error').addClass('success');
$('label[for=deviceName]').remove();
}
});
var deviceType = "";
$('.deviceType').each(function () {
if (this.value != "") {
deviceType = this.value;
}
});
}
/*
* hide popup function.
*/
function hidePopup() {
$('label[for=deviceName]').remove();
$('.control-group').removeClass('success').removeClass('error');
$(modalPopupContent).html('');
$(modalPopup).hide();
}
/*
* DOM ready functions.
*/
$(document).ready(function () {
attachEvents();
});
function attachEvents() {
/**
* Following click function would execute
* when a user clicks on "Download" link
* on Device Management page in WSO2 DC Console.
*/
$("a.download-link").click(function () {
var sketchType = $(this).data("sketchtype");
var deviceType = $(this).data("devicetype");
var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link";
var payload = {"sketchType": sketchType, "deviceType": deviceType};
$(modalPopupContent).html($('#download-device-modal-content').html());
showPopup();
var deviceName;
$("a#download-device-download-link").click(function () {
$('.new-device-name').each(function () {
if (this.value != "") {
deviceName = this.value;
}
});
$('label[for=deviceName]').remove();
if (deviceName && deviceName.length >= 4) {
payload.deviceName = deviceName;
invokerUtil.post(
downloadDeviceAPI,
payload,
function (data, textStatus, jqxhr) {
doAction(data);
},
function (data) {
doAction(data);
}
);
} else if (deviceName) {
$('.controls').append('<label for="deviceName" generated="true" class="error" ' +
'style="display: inline-block;">Please enter at least 4 characters.</label>');
$('.control-group').removeClass('success').addClass('error');
} else {
$('.controls').append('<label for="deviceName" generated="true" class="error" ' +
'style="display: inline-block;">This field is required.</label>');
$('.control-group').removeClass('success').addClass('error');
}
});
$("a#download-device-cancel-link").click(function () {
hidePopup();
});
});
}
function downloadAgent() {
$('#downloadForm').submit();
var deviceName;
$('.new-device-name').each(function () {
if (this.value != "") {
deviceName = this.value;
}
});
if (deviceName && deviceName.length >= 4) {
setTimeout(function () {
hidePopup();
}, 1000);
}
}
function doAction(data) {
//if it is saml redirection response
if (data.status == null) {
document.write(data);
}
if (data.status == "200") {
$(modalPopupContent).html($('#download-device-modal-content-links').html());
$("input#download-device-url").val(data.responseText);
$("input#download-device-url").focus(function () {
$(this).select();
});
showPopup();
} else if (data.status == "401") {
$(modalPopupContent).html($('#device-401-content').html());
$("#device-401-link").click(function () {
window.location = "/devicemgt/login";
});
showPopup();
} else if (data == "403") {
$(modalPopupContent).html($('#device-403-content').html());
$("#device-403-link").click(function () {
window.location = "/devicemgt/login";
});
showPopup();
} else {
$(modalPopupContent).html($('#device-unexpected-error-content').html());
$("a#device-unexpected-error-link").click(function () {
hidePopup();
});
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ajax_handler = new ajax_handler();
var config = new config();
var plotting = new plotting();
var droneRender = new droneRender();

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ajax_handler = new ajax_handler();
var config_api = new config_api();
var plotting = new plotting();
var object_maker = new object_maker();

View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// VERSION: 2.3 LAST UPDATE: 11.07.2013
/*
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*
* Made by Wilq32, wilq32@gmail.com, Wroclaw, Poland, 01.2009
* Website: http://jqueryrotate.com
*/
(function($) {
var supportedCSS,supportedCSSOrigin, styles=document.getElementsByTagName("head")[0].style,toCheck="transformProperty WebkitTransform OTransform msTransform MozTransform".split(" ");
for (var a = 0; a < toCheck.length; a++) if (styles[toCheck[a]] !== undefined) { supportedCSS = toCheck[a]; }
if (supportedCSS) {
supportedCSSOrigin = supportedCSS.replace(/[tT]ransform/,"TransformOrigin");
if (supportedCSSOrigin[0] == "T") supportedCSSOrigin[0] = "t";
}
// Bad eval to preven google closure to remove it from code o_O
eval('IE = "v"=="\v"');
jQuery.fn.extend({
rotate:function(parameters)
{
if (this.length===0||typeof parameters=="undefined") return;
if (typeof parameters=="number") parameters={angle:parameters};
var returned=[];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (!element.Wilq32 || !element.Wilq32.PhotoEffect) {
var paramClone = $.extend(true, {}, parameters);
var newRotObject = new Wilq32.PhotoEffect(element,paramClone)._rootObj;
returned.push($(newRotObject));
}
else {
element.Wilq32.PhotoEffect._handleRotation(parameters);
}
}
return returned;
},
getRotateAngle: function(){
var ret = [];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (element.Wilq32 && element.Wilq32.PhotoEffect) {
ret[i] = element.Wilq32.PhotoEffect._angle;
}
}
return ret;
},
stopRotate: function(){
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (element.Wilq32 && element.Wilq32.PhotoEffect) {
clearTimeout(element.Wilq32.PhotoEffect._timer);
}
}
}
});
// Library agnostic interface
Wilq32=window.Wilq32||{};
Wilq32.PhotoEffect=(function(){
if (supportedCSS) {
return function(img,parameters){
img.Wilq32 = {
PhotoEffect: this
};
this._img = this._rootObj = this._eventObj = img;
this._handleRotation(parameters);
}
} else {
return function(img,parameters) {
this._img = img;
this._onLoadDelegate = [parameters];
this._rootObj=document.createElement('span');
this._rootObj.style.display="inline-block";
this._rootObj.Wilq32 =
{
PhotoEffect: this
};
img.parentNode.insertBefore(this._rootObj,img);
if (img.complete) {
this._Loader();
} else {
var self=this;
// TODO: Remove jQuery dependency
jQuery(this._img).bind("load", function(){ self._Loader(); });
}
}
}
})();
Wilq32.PhotoEffect.prototype = {
_setupParameters : function (parameters){
this._parameters = this._parameters || {};
if (typeof this._angle !== "number") { this._angle = 0 ; }
if (typeof parameters.angle==="number") { this._angle = parameters.angle; }
this._parameters.animateTo = (typeof parameters.animateTo === "number") ? (parameters.animateTo) : (this._angle);
this._parameters.step = parameters.step || this._parameters.step || null;
this._parameters.easing = parameters.easing || this._parameters.easing || this._defaultEasing;
this._parameters.duration = 'duration' in parameters ? parameters.duration : parameters.duration || this._parameters.duration || 1000;
this._parameters.callback = parameters.callback || this._parameters.callback || this._emptyFunction;
this._parameters.center = parameters.center || this._parameters.center || ["50%","50%"];
if (typeof this._parameters.center[0] == "string") {
this._rotationCenterX = (parseInt(this._parameters.center[0],10) / 100) * this._imgWidth * this._aspectW;
} else {
this._rotationCenterX = this._parameters.center[0];
}
if (typeof this._parameters.center[1] == "string") {
this._rotationCenterY = (parseInt(this._parameters.center[1],10) / 100) * this._imgHeight * this._aspectH;
} else {
this._rotationCenterY = this._parameters.center[1];
}
if (parameters.bind && parameters.bind != this._parameters.bind) { this._BindEvents(parameters.bind); }
},
_emptyFunction: function(){},
_defaultEasing: function (x, t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b },
_handleRotation : function(parameters, dontcheck){
if (!supportedCSS && !this._img.complete && !dontcheck) {
this._onLoadDelegate.push(parameters);
return;
}
this._setupParameters(parameters);
if (this._angle==this._parameters.animateTo) {
this._rotate(this._angle);
}
else {
this._animateStart();
}
},
_BindEvents:function(events){
if (events && this._eventObj)
{
// Unbinding previous Events
if (this._parameters.bind){
var oldEvents = this._parameters.bind;
for (var a in oldEvents) if (oldEvents.hasOwnProperty(a))
// TODO: Remove jQuery dependency
jQuery(this._eventObj).unbind(a,oldEvents[a]);
}
this._parameters.bind = events;
for (var a in events) if (events.hasOwnProperty(a))
// TODO: Remove jQuery dependency
jQuery(this._eventObj).bind(a,events[a]);
}
},
_Loader:(function()
{
if (IE)
return function() {
var width=this._img.width;
var height=this._img.height;
this._imgWidth = width;
this._imgHeight = height;
this._img.parentNode.removeChild(this._img);
this._vimage = this.createVMLNode('image');
this._vimage.src=this._img.src;
this._vimage.style.height=height+"px";
this._vimage.style.width=width+"px";
this._vimage.style.position="absolute"; // FIXES IE PROBLEM - its only rendered if its on absolute position!
this._vimage.style.top = "0px";
this._vimage.style.left = "0px";
this._aspectW = this._aspectH = 1;
/* Group minifying a small 1px precision problem when rotating object */
this._container = this.createVMLNode('group');
this._container.style.width=width;
this._container.style.height=height;
this._container.style.position="absolute";
this._container.style.top="0px";
this._container.style.left="0px";
this._container.setAttribute('coordsize',width-1+','+(height-1)); // This -1, -1 trying to fix ugly problem with small displacement on IE
this._container.appendChild(this._vimage);
this._rootObj.appendChild(this._container);
this._rootObj.style.position="relative"; // FIXES IE PROBLEM
this._rootObj.style.width=width+"px";
this._rootObj.style.height=height+"px";
this._rootObj.setAttribute('id',this._img.getAttribute('id'));
this._rootObj.className=this._img.className;
this._eventObj = this._rootObj;
var parameters;
while (parameters = this._onLoadDelegate.shift()) {
this._handleRotation(parameters, true);
}
}
else return function () {
this._rootObj.setAttribute('id',this._img.getAttribute('id'));
this._rootObj.className=this._img.className;
this._imgWidth=this._img.naturalWidth;
this._imgHeight=this._img.naturalHeight;
var _widthMax=Math.sqrt((this._imgHeight)*(this._imgHeight) + (this._imgWidth) * (this._imgWidth));
this._width = _widthMax * 3;
this._height = _widthMax * 3;
this._aspectW = this._img.offsetWidth/this._img.naturalWidth;
this._aspectH = this._img.offsetHeight/this._img.naturalHeight;
this._img.parentNode.removeChild(this._img);
this._canvas=document.createElement('canvas');
this._canvas.setAttribute('width',this._width);
this._canvas.style.position="relative";
this._canvas.style.left = -this._img.height * this._aspectW + "px";
this._canvas.style.top = -this._img.width * this._aspectH + "px";
this._canvas.Wilq32 = this._rootObj.Wilq32;
this._rootObj.appendChild(this._canvas);
this._rootObj.style.width=this._img.width*this._aspectW+"px";
this._rootObj.style.height=this._img.height*this._aspectH+"px";
this._eventObj = this._canvas;
this._cnv=this._canvas.getContext('2d');
var parameters;
while (parameters = this._onLoadDelegate.shift()) {
this._handleRotation(parameters, true);
}
}
})(),
_animateStart:function()
{
if (this._timer) {
clearTimeout(this._timer);
}
this._animateStartTime = +new Date;
this._animateStartAngle = this._angle;
this._animate();
},
_animate:function()
{
var actualTime = +new Date;
var checkEnd = actualTime - this._animateStartTime > this._parameters.duration;
// TODO: Bug for animatedGif for static rotation ? (to test)
if (checkEnd && !this._parameters.animatedGif)
{
clearTimeout(this._timer);
}
else
{
if (this._canvas||this._vimage||this._img) {
var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
this._rotate((~~(angle*10))/10);
}
if (this._parameters.step) {
this._parameters.step(this._angle);
}
var self = this;
this._timer = setTimeout(function()
{
self._animate.call(self);
}, 10);
}
// To fix Bug that prevents using recursive function in callback I moved this function to back
if (this._parameters.callback && checkEnd){
this._angle = this._parameters.animateTo;
this._rotate(this._angle);
this._parameters.callback.call(this._rootObj);
}
},
_rotate : (function()
{
var rad = Math.PI/180;
if (IE)
return function(angle)
{
this._angle = angle;
this._container.style.rotation=(angle%360)+"deg";
this._vimage.style.top = -(this._rotationCenterY - this._imgHeight/2) + "px";
this._vimage.style.left = -(this._rotationCenterX - this._imgWidth/2) + "px";
this._container.style.top = this._rotationCenterY - this._imgHeight/2 + "px";
this._container.style.left = this._rotationCenterX - this._imgWidth/2 + "px";
}
else if (supportedCSS)
return function(angle){
this._angle = angle;
this._img.style[supportedCSS]="rotate("+(angle%360)+"deg)";
this._img.style[supportedCSSOrigin]=this._parameters.center.join(" ");
}
else
return function(angle)
{
this._angle = angle;
angle=(angle%360)* rad;
// clear canvas
this._canvas.width = this._width;//+this._widthAdd;
this._canvas.height = this._height;//+this._heightAdd;
// REMEMBER: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate..
this._cnv.translate(this._imgWidth*this._aspectW,this._imgHeight*this._aspectH); // at least center image on screen
this._cnv.translate(this._rotationCenterX,this._rotationCenterY); // we move image back to its orginal
this._cnv.rotate(angle); // rotate image
this._cnv.translate(-this._rotationCenterX,-this._rotationCenterY); // move image to its center, so we can rotate around its center
this._cnv.scale(this._aspectW,this._aspectH); // SCALE - if needed ;)
this._cnv.drawImage(this._img, 0, 0); // First - we draw image
}
})()
}
if (IE)
{
Wilq32.PhotoEffect.prototype.createVMLNode=(function(){
document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
try {
!document.namespaces.rvml && document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
return function (tagName) {
return document.createElement('<rvml:' + tagName + ' class="rvml">');
};
} catch (e) {
return function (tagName) {
return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
};
}
})();
}
})(jQuery);

View File

@ -0,0 +1,132 @@
/*global THREE, scene*/
var Coordinates = {
drawGrid:function(params) {
params = params || {};
var size = params.size !== undefined ? params.size:100;
var scale = params.scale !== undefined ? params.scale:0.1;
var orientation = params.orientation !== undefined ? params.orientation:"x";
var grid = new THREE.Mesh(
new THREE.PlaneGeometry(size, size, size * scale, size * scale),
new THREE.MeshBasicMaterial({ color: 0x555555, wireframe: true })
);
if (orientation === "x") {
grid.rotation.x = - Math.PI / 2;
} else if (orientation === "y") {
grid.rotation.y = - Math.PI / 2;
} else if (orientation === "z") {
grid.rotation.z = - Math.PI / 2;
}
scene.add(grid);
},
drawGround:function(params) {
params = params || {};
var size = params.size !== undefined ? params.size:100;
var color = params.color !== undefined ? params.color:0xFFFFFF;
var ground = new THREE.Mesh(
new THREE.PlaneGeometry(size, size),
new THREE.MeshLambertMaterial({ color: color,
polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0
}));
ground.rotation.x = - Math.PI / 2;
scene.add(ground);
},
drawAxes:function(params) {
// x = red, y = green, z = blue (RGB = xyz)
params = params || {};
var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04;
var axisLength = params.axisLength !== undefined ? params.axisLength:11;
var axisTess = params.axisTess !== undefined ? params.axisTess:48;
var axisOrientation = params.axisOrientation !== undefined ? params.axisOrientation:"x";
var axisMaterial = new THREE.MeshLambertMaterial({ color: 0x000000, side: THREE.DoubleSide });
var axis = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisMaterial
);
if (axisOrientation === "x") {
axis.rotation.z = - Math.PI / 2;
axis.position.x = axisLength/2-1;
} else if (axisOrientation === "y") {
axis.position.y = axisLength/2-1;
}
scene.add( axis );
var arrow = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 8*axisRadius, axisTess, 1, true),
axisMaterial
);
if (axisOrientation === "x") {
arrow.rotation.z = - Math.PI / 2;
arrow.position.x = axisLength - 1 + axisRadius*4/2;
} else if (axisOrientation === "y") {
arrow.position.y = axisLength - 1 + axisRadius*4/2;
}
scene.add( arrow );
},
drawAllAxes:function(params) {
params = params || {};
var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04;
var axisLength = params.axisLength !== undefined ? params.axisLength:11;
var axisTess = params.axisTess !== undefined ? params.axisTess:48;
var axisXMaterial = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
var axisYMaterial = new THREE.MeshLambertMaterial({ color: 0x00FF00 });
var axisZMaterial = new THREE.MeshLambertMaterial({ color: 0x0000FF });
axisXMaterial.side = THREE.DoubleSide;
axisYMaterial.side = THREE.DoubleSide;
axisZMaterial.side = THREE.DoubleSide;
var axisX = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisXMaterial
);
var axisY = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisYMaterial
);
var axisZ = new THREE.Mesh(
new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true),
axisZMaterial
);
axisX.rotation.z = - Math.PI / 2;
axisX.position.x = axisLength/2-1;
axisY.position.y = axisLength/2-1;
axisZ.rotation.y = - Math.PI / 2;
axisZ.rotation.z = - Math.PI / 2;
axisZ.position.z = axisLength/2-1;
scene.add( axisX );
scene.add( axisY );
scene.add( axisZ );
var arrowX = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisXMaterial
);
var arrowY = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisYMaterial
);
var arrowZ = new THREE.Mesh(
new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true),
axisZMaterial
);
arrowX.rotation.z = - Math.PI / 2;
arrowX.position.x = axisLength - 1 + axisRadius*4/2;
arrowY.position.y = axisLength - 1 + axisRadius*4/2;
arrowZ.rotation.z = - Math.PI / 2;
arrowZ.rotation.y = - Math.PI / 2;
arrowZ.position.z = axisLength - 1 + axisRadius*4/2;
scene.add( arrowX );
scene.add( arrowY );
scene.add( arrowZ );
}
};

View File

@ -0,0 +1,531 @@
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
*/
/*global THREE, console */
THREE.OrbitAndPanControls = function ( object, domElement ) {
THREE.EventDispatcher.call( this );
this.enabled = true;
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
this.enabled = true;
this.target = new THREE.Vector3();
// center is old, deprecated; use "target" instead
this.center = this.target;
// This option actually enables dollying in and out
this.noZoom = false;
this.zoomSpeed = 1.0;
this.noRotate = false;
this.rotateSpeed = 1.0;
this.noPan = false;
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
this.minDistance = 0;
this.maxDistance = Infinity;
this.noKeys = false;
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// internals
var scope = this;
var EPS = 0.000001;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var pan = new THREE.Vector3();
var lastPosition = new THREE.Vector3();
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
var state = STATE.NONE;
// events
var changeEvent = { type: 'change' };
this.rotateLeft = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta -= angle;
};
this.rotateUp = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta -= angle;
};
// pass in distance in world space to move left
this.panLeft = function ( distance ) {
var panOffset = new THREE.Vector3();
var te = this.object.matrix.elements;
// get X column of matrix
panOffset.set( te[0], te[1], te[2] );
panOffset.multiplyScalar(-distance);
pan.add( panOffset );
};
// pass in distance in world space to move up
this.panUp = function ( distance ) {
var panOffset = new THREE.Vector3();
var te = this.object.matrix.elements;
// get Y column of matrix
panOffset.set( te[4], te[5], te[6] );
panOffset.multiplyScalar(distance);
pan.add( panOffset );
};
// main entry point; pass in Vector2 of change desired in pixel space,
// right and down are positive
this.pan = function ( delta ) {
if ( scope.object.fov !== undefined )
{
// perspective
var position = scope.object.position;
var offset = position.clone().sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 );
// we actually don't use screenWidth, since perspective camera is fixed to screen height
scope.panLeft( 2 * delta.x * targetDistance / scope.domElement.height );
scope.panUp( 2 * delta.y * targetDistance / scope.domElement.height );
}
else if ( scope.object.top !== undefined )
{
// orthographic
scope.panLeft( delta.x * (scope.object.right - scope.object.left) / scope.domElement.width );
scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / scope.domElement.height );
}
else
{
// camera neither orthographic or perspective - warn user
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
}
};
this.dollyIn = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
scale /= dollyScale;
};
this.dollyOut = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
scale *= dollyScale;
};
this.update = function () {
var position = this.object.position;
var offset = position.clone().sub( this.target );
// angle from z-axis around y-axis
var theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
if ( this.autoRotate ) {
this.rotateLeft( getAutoRotationAngle() );
}
theta += thetaDelta;
phi += phiDelta;
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
// move target to panned location
this.target.add( pan );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
position.copy( this.target ).add( offset );
this.object.lookAt( this.target );
thetaDelta = 0;
phiDelta = 0;
scale = 1;
pan.set(0,0,0);
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
}
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
if ( event.button === 0 ) {
if ( scope.noRotate === true ) { return; }
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === 1 ) {
if ( scope.noZoom === true ) { return; }
state = STATE.DOLLY;
dollyStart.set( event.clientX, event.clientY );
} else if ( event.button === 2 ) {
if ( scope.noPan === true ) { return; }
state = STATE.PAN;
panStart.set( event.clientX, event.clientY );
}
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
}
function onMouseMove( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
if ( state === STATE.ROTATE ) {
if ( scope.noRotate === true ) { return; }
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.DOLLY ) {
if ( scope.noZoom === true ) { return; }
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyIn();
} else {
scope.dollyOut();
}
dollyStart.copy( dollyEnd );
} else if ( state === STATE.PAN ) {
if ( scope.noPan === true ) { return; }
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta );
panStart.copy( panEnd );
}
}
function onMouseUp( /* event */ ) {
if ( scope.enabled === false ) { return; }
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
state = STATE.NONE;
}
function onMouseWheel( event ) {
// this is needed when the program is inside an iframe
// to prevent scrolling the whole page
event.preventDefault();
if ( scope.enabled === false ) { return; }
if ( scope.noZoom === true ) { return; }
var delta = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail ) { // Firefox
delta = - event.detail;
}
if ( delta > 0 ) {
scope.dollyOut();
} else {
scope.dollyIn();
}
}
function onKeyDown( event ) {
if ( scope.enabled === false ) { return; }
if ( scope.noKeys === true ) { return; }
if ( scope.noPan === true ) { return; }
// pan a pixel - I guess for precise positioning?
switch ( event.keyCode ) {
case scope.keys.UP:
scope.pan( new THREE.Vector2( 0, 1 ) );
break;
case scope.keys.BOTTOM:
scope.pan( new THREE.Vector2( 0, -1 ) );
break;
case scope.keys.LEFT:
scope.pan( new THREE.Vector2( 1, 0 ) );
break;
case scope.keys.RIGHT:
scope.pan( new THREE.Vector2( -1, 0 ) );
break;
}
}
function touchstart( event ) {
if ( scope.enabled === false ) { return; }
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) { return; }
state = STATE.TOUCH_ROTATE;
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) { return; }
state = STATE.TOUCH_DOLLY;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyStart.set( 0, distance );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) { return; }
state = STATE.TOUCH_PAN;
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
default:
state = STATE.NONE;
}
}
function touchmove( event ) {
if ( scope.enabled === false ) { return; }
event.preventDefault();
event.stopPropagation();
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) { return; }
if ( state !== STATE.TOUCH_ROTATE ) { return; }
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) { return; }
if ( state !== STATE.TOUCH_DOLLY ) { return; }
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyEnd.set( 0, distance );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyOut();
} else {
scope.dollyIn();
}
dollyStart.copy( dollyEnd );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) { return; }
if ( state !== STATE.TOUCH_PAN ) { return; }
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta );
panStart.copy( panEnd );
break;
default:
state = STATE.NONE;
}
}
function touchend( /* event */ ) {
if ( scope.enabled === false ) { return; }
state = STATE.NONE;
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'keydown', onKeyDown, false );
this.domElement.addEventListener( 'touchstart', touchstart, false );
this.domElement.addEventListener( 'touchend', touchend, false );
this.domElement.addEventListener( 'touchmove', touchmove, false );
};

View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// VERSION: 2.3 LAST UPDATE: 11.07.2013
/*
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*
* Made by Wilq32, wilq32@gmail.com, Wroclaw, Poland, 01.2009
* Website: http://jqueryrotate.com
*/
(function($) {
var supportedCSS,supportedCSSOrigin, styles=document.getElementsByTagName("head")[0].style,toCheck="transformProperty WebkitTransform OTransform msTransform MozTransform".split(" ");
for (var a = 0; a < toCheck.length; a++) if (styles[toCheck[a]] !== undefined) { supportedCSS = toCheck[a]; }
if (supportedCSS) {
supportedCSSOrigin = supportedCSS.replace(/[tT]ransform/,"TransformOrigin");
if (supportedCSSOrigin[0] == "T") supportedCSSOrigin[0] = "t";
}
// Bad eval to preven google closure to remove it from code o_O
eval('IE = "v"=="\v"');
jQuery.fn.extend({
rotate:function(parameters)
{
if (this.length===0||typeof parameters=="undefined") return;
if (typeof parameters=="number") parameters={angle:parameters};
var returned=[];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (!element.Wilq32 || !element.Wilq32.PhotoEffect) {
var paramClone = $.extend(true, {}, parameters);
var newRotObject = new Wilq32.PhotoEffect(element,paramClone)._rootObj;
returned.push($(newRotObject));
}
else {
element.Wilq32.PhotoEffect._handleRotation(parameters);
}
}
return returned;
},
getRotateAngle: function(){
var ret = [];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (element.Wilq32 && element.Wilq32.PhotoEffect) {
ret[i] = element.Wilq32.PhotoEffect._angle;
}
}
return ret;
},
stopRotate: function(){
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (element.Wilq32 && element.Wilq32.PhotoEffect) {
clearTimeout(element.Wilq32.PhotoEffect._timer);
}
}
}
});
// Library agnostic interface
Wilq32=window.Wilq32||{};
Wilq32.PhotoEffect=(function(){
if (supportedCSS) {
return function(img,parameters){
img.Wilq32 = {
PhotoEffect: this
};
this._img = this._rootObj = this._eventObj = img;
this._handleRotation(parameters);
}
} else {
return function(img,parameters) {
this._img = img;
this._onLoadDelegate = [parameters];
this._rootObj=document.createElement('span');
this._rootObj.style.display="inline-block";
this._rootObj.Wilq32 =
{
PhotoEffect: this
};
img.parentNode.insertBefore(this._rootObj,img);
if (img.complete) {
this._Loader();
} else {
var self=this;
// TODO: Remove jQuery dependency
jQuery(this._img).bind("load", function(){ self._Loader(); });
}
}
}
})();
Wilq32.PhotoEffect.prototype = {
_setupParameters : function (parameters){
this._parameters = this._parameters || {};
if (typeof this._angle !== "number") { this._angle = 0 ; }
if (typeof parameters.angle==="number") { this._angle = parameters.angle; }
this._parameters.animateTo = (typeof parameters.animateTo === "number") ? (parameters.animateTo) : (this._angle);
this._parameters.step = parameters.step || this._parameters.step || null;
this._parameters.easing = parameters.easing || this._parameters.easing || this._defaultEasing;
this._parameters.duration = 'duration' in parameters ? parameters.duration : parameters.duration || this._parameters.duration || 1000;
this._parameters.callback = parameters.callback || this._parameters.callback || this._emptyFunction;
this._parameters.center = parameters.center || this._parameters.center || ["50%","50%"];
if (typeof this._parameters.center[0] == "string") {
this._rotationCenterX = (parseInt(this._parameters.center[0],10) / 100) * this._imgWidth * this._aspectW;
} else {
this._rotationCenterX = this._parameters.center[0];
}
if (typeof this._parameters.center[1] == "string") {
this._rotationCenterY = (parseInt(this._parameters.center[1],10) / 100) * this._imgHeight * this._aspectH;
} else {
this._rotationCenterY = this._parameters.center[1];
}
if (parameters.bind && parameters.bind != this._parameters.bind) { this._BindEvents(parameters.bind); }
},
_emptyFunction: function(){},
_defaultEasing: function (x, t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b },
_handleRotation : function(parameters, dontcheck){
if (!supportedCSS && !this._img.complete && !dontcheck) {
this._onLoadDelegate.push(parameters);
return;
}
this._setupParameters(parameters);
if (this._angle==this._parameters.animateTo) {
this._rotate(this._angle);
}
else {
this._animateStart();
}
},
_BindEvents:function(events){
if (events && this._eventObj)
{
// Unbinding previous Events
if (this._parameters.bind){
var oldEvents = this._parameters.bind;
for (var a in oldEvents) if (oldEvents.hasOwnProperty(a))
// TODO: Remove jQuery dependency
jQuery(this._eventObj).unbind(a,oldEvents[a]);
}
this._parameters.bind = events;
for (var a in events) if (events.hasOwnProperty(a))
// TODO: Remove jQuery dependency
jQuery(this._eventObj).bind(a,events[a]);
}
},
_Loader:(function()
{
if (IE)
return function() {
var width=this._img.width;
var height=this._img.height;
this._imgWidth = width;
this._imgHeight = height;
this._img.parentNode.removeChild(this._img);
this._vimage = this.createVMLNode('image');
this._vimage.src=this._img.src;
this._vimage.style.height=height+"px";
this._vimage.style.width=width+"px";
this._vimage.style.position="absolute"; // FIXES IE PROBLEM - its only rendered if its on absolute position!
this._vimage.style.top = "0px";
this._vimage.style.left = "0px";
this._aspectW = this._aspectH = 1;
/* Group minifying a small 1px precision problem when rotating object */
this._container = this.createVMLNode('group');
this._container.style.width=width;
this._container.style.height=height;
this._container.style.position="absolute";
this._container.style.top="0px";
this._container.style.left="0px";
this._container.setAttribute('coordsize',width-1+','+(height-1)); // This -1, -1 trying to fix ugly problem with small displacement on IE
this._container.appendChild(this._vimage);
this._rootObj.appendChild(this._container);
this._rootObj.style.position="relative"; // FIXES IE PROBLEM
this._rootObj.style.width=width+"px";
this._rootObj.style.height=height+"px";
this._rootObj.setAttribute('id',this._img.getAttribute('id'));
this._rootObj.className=this._img.className;
this._eventObj = this._rootObj;
var parameters;
while (parameters = this._onLoadDelegate.shift()) {
this._handleRotation(parameters, true);
}
}
else return function () {
this._rootObj.setAttribute('id',this._img.getAttribute('id'));
this._rootObj.className=this._img.className;
this._imgWidth=this._img.naturalWidth;
this._imgHeight=this._img.naturalHeight;
var _widthMax=Math.sqrt((this._imgHeight)*(this._imgHeight) + (this._imgWidth) * (this._imgWidth));
this._width = _widthMax * 3;
this._height = _widthMax * 3;
this._aspectW = this._img.offsetWidth/this._img.naturalWidth;
this._aspectH = this._img.offsetHeight/this._img.naturalHeight;
this._img.parentNode.removeChild(this._img);
this._canvas=document.createElement('canvas');
this._canvas.setAttribute('width',this._width);
this._canvas.style.position="relative";
this._canvas.style.left = -this._img.height * this._aspectW + "px";
this._canvas.style.top = -this._img.width * this._aspectH + "px";
this._canvas.Wilq32 = this._rootObj.Wilq32;
this._rootObj.appendChild(this._canvas);
this._rootObj.style.width=this._img.width*this._aspectW+"px";
this._rootObj.style.height=this._img.height*this._aspectH+"px";
this._eventObj = this._canvas;
this._cnv=this._canvas.getContext('2d');
var parameters;
while (parameters = this._onLoadDelegate.shift()) {
this._handleRotation(parameters, true);
}
}
})(),
_animateStart:function()
{
if (this._timer) {
clearTimeout(this._timer);
}
this._animateStartTime = +new Date;
this._animateStartAngle = this._angle;
this._animate();
},
_animate:function()
{
var actualTime = +new Date;
var checkEnd = actualTime - this._animateStartTime > this._parameters.duration;
// TODO: Bug for animatedGif for static rotation ? (to test)
if (checkEnd && !this._parameters.animatedGif)
{
clearTimeout(this._timer);
}
else
{
if (this._canvas||this._vimage||this._img) {
var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
this._rotate((~~(angle*10))/10);
}
if (this._parameters.step) {
this._parameters.step(this._angle);
}
var self = this;
this._timer = setTimeout(function()
{
self._animate.call(self);
}, 10);
}
// To fix Bug that prevents using recursive function in callback I moved this function to back
if (this._parameters.callback && checkEnd){
this._angle = this._parameters.animateTo;
this._rotate(this._angle);
this._parameters.callback.call(this._rootObj);
}
},
_rotate : (function()
{
var rad = Math.PI/180;
if (IE)
return function(angle)
{
this._angle = angle;
this._container.style.rotation=(angle%360)+"deg";
this._vimage.style.top = -(this._rotationCenterY - this._imgHeight/2) + "px";
this._vimage.style.left = -(this._rotationCenterX - this._imgWidth/2) + "px";
this._container.style.top = this._rotationCenterY - this._imgHeight/2 + "px";
this._container.style.left = this._rotationCenterX - this._imgWidth/2 + "px";
}
else if (supportedCSS)
return function(angle){
this._angle = angle;
this._img.style[supportedCSS]="rotate("+(angle%360)+"deg)";
this._img.style[supportedCSSOrigin]=this._parameters.center.join(" ");
}
else
return function(angle)
{
this._angle = angle;
angle=(angle%360)* rad;
// clear canvas
this._canvas.width = this._width;//+this._widthAdd;
this._canvas.height = this._height;//+this._heightAdd;
// REMEMBER: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate..
this._cnv.translate(this._imgWidth*this._aspectW,this._imgHeight*this._aspectH); // at least center image on screen
this._cnv.translate(this._rotationCenterX,this._rotationCenterY); // we move image back to its orginal
this._cnv.rotate(angle); // rotate image
this._cnv.translate(-this._rotationCenterX,-this._rotationCenterY); // move image to its center, so we can rotate around its center
this._cnv.scale(this._aspectW,this._aspectH); // SCALE - if needed ;)
this._cnv.drawImage(this._img, 0, 0); // First - we draw image
}
})()
}
if (IE)
{
Wilq32.PhotoEffect.prototype.createVMLNode=(function(){
document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
try {
!document.namespaces.rvml && document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
return function (tagName) {
return document.createElement('<rvml:' + tagName + ' class="rvml">');
};
} catch (e) {
return function (tagName) {
return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
};
}
})();
}
})(jQuery);

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
object_maker.init(config_api.config_3dobject_holder, $("#objectHolder").width(), $("#objectHolder").width()/1.5);
object_maker.animate();
var ws;
var graph;
var chartData = [];
var flight_dynamics = new flight_dynamics();
$("#window_size").slider({
range: "min",
value: 37,
min: 10,
max: 300,
slide: function (event, ui) {
$("#window_size_current_value").html($("#window_size").slider("value"));
}
});
$("#window_update").slider({
range: "min",
value: 234,
min: 100,
max: 1000,
slide: function (event, ui) {
$("#window_update_value").html($("#window_update").slider("value"));
}
});
$("#replotting").click(function () {
plotting.finishPlotting(function (status) {
if (status) {
plotting.initPlotting(function (status) {
d3.select("#realtimechart").select("svg").remove();
plotting.realtime_plotting("#realtimechart", "#range_min", "#range_max", "#window_update_value",
600, $("#realtimechart").height(), "#window_size_current_value",
'#plotting_attribute');
});
} else {
$("#realtimechart").html("There is no data to plot");
}
});
});
$('.btn-minimize').click(function (e) {
e.preventDefault();
var $target = $(this).parent().parent().next('.box-content');
if ($target.is(':visible')) {
if ($(this).parent().attr('id') === "RealtimePlotting") {
plotting.forceToRedraw(function (status) {
d3.select("#realtimechart").select("svg").remove();
plotting.realtime_plotting("#realtimechart", "#range_min", "#range_max", "#window_update_value",
600, $("#realtimechart").height(), "#window_size_current_value",
'#plotting_attribute');
});
}
} else {
}
});
$('.btn-minimize').parent().parent().next('.box-content').hide();
var webSocket;
config_api.realtime_plotting_data_window["attitude"] = new Queue();
var current_status = {};
$(window).load(function () {
var websocketUrl = $("#div-chart").data("websocketurl");
connect(websocketUrl);
});
$(window).unload(function () {
disconnect();
});
//websocket connection
function connect(target) {
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
console.log('WebSocket is not supported by this browser.');
}
if (ws) {
ws.onmessage = function (event) {
var sender_message = event.data;
sender_message = isJSON(sender_message);
if (sender_message != null) {
var droneStats = mapDroneStats(sender_message);
flight_dynamics.processingMessage(droneStats);
} else {
console.log("Message has been corrupted.");
}
};
}
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
}
}
function mapDroneStats(sender_message){
var responseMessage = {
"quatanium_val":[sender_message[5],sender_message[6],sender_message[7],sender_message[8]],
"basicParam":{
"velocity":[sender_message[9],sender_message[10],sender_message[11]],
"global_location":[sender_message[12],sender_message[13],sender_message[14]],
"battery_level":sender_message[15],
"device_type":"drone",
"battery_voltage": sender_message[16]
}
};
return responseMessage;
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
droneRender.init(config.configDronePlaceholder, $("#objectHolder").width(), $("#objectHolder").width() / 1.5);
droneRender.animate();
var ws;
var graph;
var chartData = [];
var flightDynamics = new flightDynamics();
$("#windowSize").slider({
range: "min",
value: 37,
min: 10,
max: 300,
slide: function (event, ui) {
$("#windowSizeCurrentValue").html($("#windowSize").slider("value"));
}
});
$("#windowUpdate").slider({
range: "min",
value: 234,
min: 100,
max: 1000,
slide: function (event, ui) {
$("#windowUpdateValue").html($("#windowUpdate").slider("value"));
}
});
$("#replotting").click(function () {
plotting.finishPlotting(function (status) {
if (status) {
plotting.initPlotting(function (status) {
d3.select("#realtimeChart").select("svg").remove();
plotting.realtimePlotting("#realtimeChart", "#rangeMin", "#rangeMax", "#windowUpdateValue",
600, $("#realtimeChart").height(), "#windowSizeCurrentValue",
'#plottingAttribute');
});
} else {
$("#realtimeChart").html("There is no data to plot");
}
});
});
$('.btn-minimize').click(function (e) {
e.preventDefault();
var $target = $(this).parent().parent().next('.box-content');
if ($target.is(':visible')) {
if ($(this).parent().attr('id') === "RealtimePlotting") {
plotting.forceToRedraw(function (status) {
d3.select("#realtimeChart").select("svg").remove();
plotting.realtimePlotting("#realtimeChart", "#rangeMin", "#rangeMax", "#windowUpdateValue",
600, $("#realtimeChart").height(), "#windowSizeCurrentValue",
'#plottingAttribute');
});
}
} else {
}
});
$('.btn-minimize').parent().parent().next('.box-content').hide();
config.realtimePlottingDataWindow["attitude"] = new Queue();
var currentStatus = {};
$(window).load(function () {
var websocketUrl = $("#div-chart").data("websocketurl");
connect(websocketUrl);
});
$(window).unload(function () {
disconnect();
});
//websocket connection
function connect(target) {
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
console.log('WebSocket is not supported by this browser.');
}
if (ws) {
ws.onmessage = function (event) {
var sender_message = event.data;
sender_message = isJSON(sender_message);
if (sender_message != null) {
var droneStats = mapDroneStats(sender_message);
flightDynamics.processingMessage(droneStats);
} else {
console.log("Message has been corrupted.");
}
};
}
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
}
}
function mapDroneStats(sender_message) {
var responseMessage = {
"quatanium_val": [sender_message[5], sender_message[6], sender_message[7], sender_message[8]],
"basicParam": {
"velocity": [sender_message[9], sender_message[10], sender_message[11]],
"global_location": [sender_message[12], sender_message[13], sender_message[14]],
"battery_level": sender_message[15],
"device_type": "drone",
"battery_voltage": sender_message[16]
}
};
return responseMessage;
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
$('.btn-minimize').click(function (e) {
e.preventDefault();
var $target = $(this).parent().parent().next('.box-content');
if ($target.is(':visible')) {
$('i', $(this)).removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down');
checkAndDisable($(this).parent().attr('id'));
}
else {
$('i', $(this)).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up');
checkAndEnable($(this).parent().attr('id'));
}
$target.slideToggle();
});
function checkAndEnable(id) {
if (id === "RealtimePlotting") {
config.modulesStatus.realtimePlotting = true;
}
else if (id === "SensorReadings") {
config.modulesStatus.sensorReadings = true;
} else if (id === "Rotation") {
config.modulesStatus.angleOfRotationv1 = true;
} else if (id === "AngleOfRotation") {
config.modulesStatus.angleOfRotationv2 = true;
}
}
function checkAndDisable(id) {
if (id === "RealtimePlotting") {
config.modulesStatus.realtimePlotting = false;
}
else if (id === "SensorReadings") {
config.modulesStatus.sensorReadings = false;
} else if (id === "Rotation") {
config.modulesStatus.angleOfRotationv1 = false;
} else if (id === "AngleOfRotation") {
config.modulesStatus.angleOfRotationv2 = false;
}
}
function isJSON(data) {
try {
return JSON.parse(data);
}
catch (error) {
return null;
}
}
function Queue() {
var a = [], b = '';
this.enqueue = function (b) {
a.push([this.getLength() - 1 <= 0 ? 0 : this.getLength() - 1, b]);
};
this.dequeue = function () {
if (0 != a.length) {
var c = a[b];
2 * ++b >= a.length && (a = a.slice(b), b = 0);
return c
}
};
this.getLength = function () {
return a.length - b;
};
this.isEmpty = function () {
return 0 == a.length;
};
this.peek = function () {
return 0 < a.length ? a[b] : void 0
};
this.getData = function () {
return a;
};
this.makeFixedSize = function (start, end) {
a = a.slice(start, end);
}
}
$("#module_control button").click(function (index) {
var url = config.drone_control;
ajax_handler.ajaxRequest(url, config.controlType, {action: $(this).attr('id'), speed: 7, duration: 7},
config.dataType, function (data, status) {
}
);
});

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var flightDynamics = function () {
var api = this;
api.processingMessage = function (droneStats) {
if (droneStats.basicParam.battery_level != undefined) {
$("#batteryLevelPlaceholder").width(parseInt(droneStats.basicParam.battery_level) + "%");
$("#batteryLevel").html(droneStats.basicParam.battery_level + "%");
}
if (droneStats.basicParam.battery_voltage != undefined) {
$("#batteryVoltagePlaceholder").width(parseInt(droneStats.basicParam.battery_voltage) + "%");
$("#batteryVoltage").html(droneStats.basicParam.battery_voltage + "%");
}
if (droneStats.quatanium_val != undefined) {
currentStatus = droneRender.getHeadingAttitudeAndBank(droneStats.quatanium_val);
droneRender.setHeadingAttitudeAndBank(currentStatus);
$("#imageTop").animate({rotate: '' + (180 / Math.PI) * 2.890456 + 'deg'}, 2);
}
if (config.modulesStatus.angleOfRotationv1 || config.modulesStatus.angleOfRotationv2) {
droneRender.setBank("#imageTop", currentStatus.bank);
droneRender.setHeading("#imageBackSecond", currentStatus.heading);
}
if (config.modulesStatus.realtimePlotting) {
if (currentStatus[$('#plottingAttribute').val()] != undefined) {
plotting.pushData(currentStatus[$('#plottingAttribute').val()]);
}
}
if (droneStats.basicParam != undefined) {
if (droneStats.basicParam.velocity != undefined) {
var velocity = droneStats.basicParam.velocity;
if (velocity.length == 3) {
$("#velocityx").html(velocity[0]);
$("#velocityy").html(velocity[1]);
$("#velocityz").html(velocity[2]);
}
} else {
$("#velocityx").html(NaN);
$("#velocityy").html(NaN);
$("#velocityz").html(NaN);
}
if (droneStats.basicParam.global_location != undefined) {
var location = droneStats.basicParam.global_location;
if (location.length == 3) {
$("#locationLog").html(location[0]);
$("#locationAlt").html(location[1]);
$("#locationLat").html(location[2]);
}
} else {
$("#locationLog").html(NaN);
$("#locationAlt").html(NaN);
$("#locationLat").html(NaN);
}
}
}
};

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var flight_dynamics = function () {
var api = this;
api.processingMessage = function (sender_message) {
if(sender_message.basicParam.battery_level!= undefined){
$("#battery_level_holder").width( parseInt(sender_message.basicParam.battery_level)+"%" );
$("#battery_level").html(sender_message.basicParam.battery_level+"%");
}
if(sender_message.basicParam.battery_voltage!= undefined){
$("#battery_voltage_holder").width( parseInt(sender_message.basicParam.battery_voltage)+"%" );
console.log(sender_message.basicParam.battery_voltage);
$("#battery_voltage").html(sender_message.basicParam.battery_voltage+"%");
}
if (sender_message.quatanium_val != undefined) {
current_status = object_maker.get_heading_attitude_bank(sender_message.quatanium_val);
object_maker.set_heading_attitude_bank(current_status);
$("#imageTop").animate({rotate: '' + (180 / Math.PI) * 2.890456 + 'deg'}, 2);
}
if (config_api.modules_status.angleOfRotation_2 || config_api.modules_status.angleOfRotation_1) {
object_maker.set_bank("#imageTop", current_status.bank);
object_maker.set_heading("#imageBackSecond", current_status.heading);
}
if (config_api.modules_status.realtimePlotting) {
if (current_status[$('#plotting_attribute').val()] != undefined) {
plotting.pushData(current_status[$('#plotting_attribute').val()]);
}
}
if (sender_message.basicParam != undefined) {
if (sender_message.basicParam.velocity != undefined) {
var velocity = sender_message.basicParam.velocity;
if (velocity.length == 3) {
$("#velocityx").html(velocity[0]);
$("#velocityy").html(velocity[1]);
$("#velocityz").html(velocity[2]);
}
} else {
$("#velocityx").html(NaN);
$("#velocityy").html(NaN);
$("#velocityz").html(NaN);
}
if (sender_message.basicParam.global_location != undefined) {
var location = sender_message.basicParam.global_location;
if (location.length == 3) {
$("#locationLog").html(location[0]);
$("#locationAlt").html(location[1]);
$("#locationLat").html(location[2]);
}
} else {
$("#locationLog").html(NaN);
$("#locationAlt").html(NaN);
$("#locationLat").html(NaN);
}
}
if (sender_message.battery_voltage != undefined) {
$("#battery_voltage").html(sender_message.battery_voltage);
} else {
$("#battery_voltage").html(NaN);
}
}
};

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var plotting = function () {
var api = this;
api.isDone = false;
api.currentValue = 0;
api.finishPlotting = function (callBack) {
api.isDone = true;
callBack(true);
},
api.initPlotting = function (callback) {
api.isDone = false;
callback(true);
},
api.forceToRedraw = function (callback) {
api.isDone == true;
callback(true);
},
api.pushData = function (new_value) {
api.currentValue = new_value;
},
api.realtimePlotting = function (placeholder, placeholderYMin, placeholderYMax, updateInterval, placeholderWidth,
placeholderHeight, placeholderWindowSize, title) {
$(placeholder).html();
var initWindow = function () {
return 0;
}
api.data = d3.range(parseInt($(placeholderWindowSize).html())).map(initWindow);
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = placeholderWidth - margin.left - margin.right,
height = placeholderHeight - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([1, parseInt($(placeholderWindowSize).html()) - 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([parseInt($(placeholderYMin).val()), parseInt($(placeholderYMax).val())])
.range([height, 0]);
var line = d3.svg.line()
.interpolate("basis")
.x(function (d, i) {
return x(i);
})
.y(function (d, i) {
return y(d);
});
var svg = d3.select(placeholder).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var axis_x = svg.append("g")
.attr("class", "x_axis")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
var axis_y = svg.append("g")
.attr("class", "y_axis")
.call(d3.svg.axis().scale(y).orient("left"));
var path = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(api.data)
.attr("class", "line")
.attr("d", line);
svg.append("text")
.attr("class", "yaxis_label")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left - 4)
.attr("x", (0 - (height / 2)))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text($(title).val());
svg.append("text")
.attr("class", "xaixs_label")
.attr("transform",
"translate(" + (width / 2) + " ," +
(height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Window Size");
svg.append("text")
.attr("class", "title_label")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 4))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text($(title).val() + " variation within last " + $(placeholderWindowSize).html() + " frames");
updateAgain();
function updateAgain() {
if (api.isDone)return;
api.data.push(api.currentValue);
path.attr("d", line)
.attr("transform", null)
.transition()
.duration($(updateInterval).html())
.ease("linear")
.attr("transform", "translate(" + x(0) + ",0)")
.each("end", updateAgain);
api.data.shift();
}
function rescale() {
y.domain([parseInt($(placeholderYMin).val()), parseInt($(placeholderYMax).val())])
svg.select(".title_label")
.text($(title).val() + " variation within last " + $(placeholderWindowSize).html() + " frames");
svg.select(".yaxis_label")
.text($(title).val());
}
$("#plottingAttribute").change(function () {
rescale();
});
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var plotting = function () {
var api = this;
api.isDone = false;
api.current_value = 0;
api.finishPlotting = function (callBack) {
api.isDone = true;
callBack(true);
},
api.initPlotting = function (callback) {
api.isDone = false;
callback(true);
},
api.forceToRedraw = function (callback) {
api.isDone == true;
callback(true);
},
api.pushData = function (new_value) {
api.current_value = new_value;
},
api.realtime_plotting = function (holder, y_min_hollder, y_max_holder, update_interval_holder, holder_width,
holder_height, window_size_holder, title) {
$(holder).html();
var init_window = function () {
return 0;
}
api.data = d3.range(parseInt($(window_size_holder).html())).map(init_window);
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = holder_width - margin.left - margin.right,
height = holder_height - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([1, parseInt($(window_size_holder).html()) - 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([parseInt($(y_min_hollder).val()), parseInt($(y_max_holder).val())])
.range([height, 0]);
var line = d3.svg.line()
.interpolate("basis")
.x(function (d, i) {
return x(i);
})
.y(function (d, i) {
return y(d);
});
var svg = d3.select(holder).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var axis_x = svg.append("g")
.attr("class", "x_axis")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
var axis_y = svg.append("g")
.attr("class", "y_axis")
.call(d3.svg.axis().scale(y).orient("left"));
var path = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(api.data)
.attr("class", "line")
.attr("d", line);
svg.append("text")
.attr("class", "yaxis_label")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left - 4)
.attr("x", (0 - (height / 2)))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text($(title).val());
svg.append("text")
.attr("class", "xaixs_label")
.attr("transform",
"translate(" + (width / 2) + " ," +
(height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Window Size");
svg.append("text")
.attr("class", "title_label")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 4))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text($(title).val() + " variation within last " + $(window_size_holder).html() + " frames");
updateAgain();
function updateAgain() {
if (api.isDone)return;
api.data.push(api.current_value);
path
.attr("d", line)
.attr("transform", null)
.transition()
.duration($(update_interval_holder).html())
.ease("linear")
.attr("transform", "translate(" + x(0) + ",0)")
.each("end", updateAgain);
api.data.shift();
}
function rescale() {
y.domain([parseInt($(y_min_hollder).val()), parseInt($(y_max_holder).val())])
svg.select(".title_label")
.text($(title).val() + " variation within last " + $(window_size_holder).html() + " frames");
svg.select(".yaxis_label")
.text($(title).val());
}
function rescale_x() {
x.domain([1, parseInt($(window_size_holder).html()) - 2]).range([0, width])
svg.select(".x_axis").transition().call(axis_x);
}
$("#plotting_attribute").change(function () {
rescale();
});
}
}

View File

@ -0,0 +1,8 @@
{
"deviceType": {
"label": "drone",
"category": "virtual",
"downloadAgentUri": "drone/device/download"
}
}

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var modalPopup = ".wr-modalpopup";
var modalPopupContainer = modalPopup + " .modalpopup-container";
var modalPopupContent = modalPopup + " .modalpopup-content";
var body = "body";
/*
* set popup maximum height function.
*/
function setPopupMaxHeight() {
$(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30)));
$(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2)));
}
/*
* show popup function.
*/
function showPopup() {
$(modalPopup).show();
setPopupMaxHeight();
$('#downloadForm').validate({
rules: {
deviceName: {
minlength: 4,
required: true
}
},
highlight: function (element) {
$(element).closest('.control-group').removeClass('success').addClass('error');
},
success: function (element) {
$(element).closest('.control-group').removeClass('error').addClass('success');
$('label[for=deviceName]').remove();
}
});
var deviceType = "";
$('.deviceType').each(function () {
if (this.value != "") {
deviceType = this.value;
}
});
}
/*
* hide popup function.
*/
function hidePopup() {
$('label[for=deviceName]').remove();
$('.control-group').removeClass('success').removeClass('error');
$(modalPopupContent).html('');
$(modalPopup).hide();
}
/*
* DOM ready functions.
*/
$(document).ready(function () {
attachEvents();
});
function attachEvents() {
/**
* Following click function would execute
* when a user clicks on "Download" link
* on Device Management page in WSO2 DC Console.
*/
$("a.download-link").click(function () {
var sketchType = $(this).data("sketchtype");
var deviceType = $(this).data("devicetype");
var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link";
var payload = {"sketchType": sketchType, "deviceType": deviceType};
$(modalPopupContent).html($('#download-device-modal-content').html());
showPopup();
var deviceName;
$("a#download-device-download-link").click(function () {
$('.new-device-name').each(function () {
if (this.value != "") {
deviceName = this.value;
}
});
$('label[for=deviceName]').remove();
if (deviceName && deviceName.length >= 4) {
payload.deviceName = deviceName;
invokerUtil.post(
downloadDeviceAPI,
payload,
function (data, textStatus, jqxhr) {
doAction(data);
},
function (data) {
doAction(data);
}
);
}else if(deviceName){
$('.controls').append('<label for="deviceName" generated="true" class="error" ' +
'style="display: inline-block;">Please enter at least 4 ' +
'characters.</label>');
$('.control-group').removeClass('success').addClass('error');
} else {
$('.controls').append('<label for="deviceName" generated="true" class="error" ' +
'style="display: inline-block;">This field is required.' +
'</label>');
$('.control-group').removeClass('success').addClass('error');
}
});
$("a#download-device-cancel-link").click(function () {
hidePopup();
});
});
}
function downloadAgent() {
var deviceName;
$('.new-device-name').each(function () {
if (this.value != "") {
deviceName = this.value;
}
});
var deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/;
if (deviceName && deviceNameFormat.test(deviceName)) {
$('#downloadForm').submit();
hidePopup();
$(modalPopupContent).html($('#device-agent-downloading-content').html());
showPopup();
setTimeout(function () {
hidePopup();
}, 1000);
}else {
$("#invalid-username-error-msg span").text("Invalid device name");
$("#invalid-username-error-msg").removeClass("hidden");
}
}
function doAction(data) {
//if it is saml redirection response
if (data.status == null) {
document.write(data);
}
if (data.status == "200") {
$(modalPopupContent).html($('#download-device-modal-content-links').html());
$("input#download-device-url").val(data.responseText);
$("input#download-device-url").focus(function () {
$(this).select();
});
showPopup();
} else if (data.status == "401") {
$(modalPopupContent).html($('#device-401-content').html());
$("#device-401-link").click(function () {
window.location = "/devicemgt/login";
});
showPopup();
} else if (data == "403") {
$(modalPopupContent).html($('#device-403-content').html());
$("#device-403-link").click(function () {
window.location = "/devicemgt/login";
});
showPopup();
} else {
$(modalPopupContent).html($('#device-unexpected-error-content').html());
$("a#device-unexpected-error-link").click(function () {
hidePopup();
});
}
}

View File

@ -0,0 +1,329 @@
<div class="col-lg-12 margin-top-double">
<h1 class="grey ">Drone Analyzer</h1>
<hr>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 padding-top">
<img src="{{@unit.publicUri}}/images/drone-icon.png" class="img-responsive">
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h4 class="doc-link">Click <a href="https://docs.wso2.com/pages/viewpage.action?pageId=48289181"
target="_blank">[ here ]</a> for latest instructions and
troubleshooting.</h4>
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h3 class="uppercase">What it Does</h3>
<hr>
<p class="grey margin-top">Connect an
<a href="https://store.3drobotics.com/products/iris" target="_blank">[IRIS+]</a> Drone to
WSO2 IoT Server and visualize statistics.
</p>
<br>
<h3 class="uppercase">What You Need</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">ITEM 01</span>
&nbsp;&nbsp;&nbsp;IRIS+ Drone.
</li>
<li class="padding-top-double">
<span class="circle">ITEM 02</span>
&nbsp;&nbsp;&nbsp;USB to Micro USB cable or Telemetry Radio receiver.
</li>
<li class="padding-top-double">
<span class="circle">STEP 03</span>
&nbsp;&nbsp;&nbsp;Proceed to [Prepare] section.
</ul>
<br>
<a href="/api-store/apis/info?name={{@uriParams.deviceType}}&version=1.0.0&provider=admin"
class="btn-operations"
target="_blank"><i class="fw fw-api"></i> View API</i> &nbsp;
</a>
<a href="#" class="download-link btn-operations">
<i class="fw fw-download"></i>Download Agent
</a>
<div id="download-device-modal-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 center-container">
<h3>Name your device and download the agent from following link.</h3>
<br/>
<form id="downloadForm" method="GET"
action="{{@app.context}}/api/devices/sketch/download">
<div id="invalid-username-error-msg" class="alert alert-danger hidden"
role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<div class="control-group">
<div class="controls">
<input class="new-device-name" style="color:#3f3f3f;padding:5px"
type="text"
placeholder="Ex. drone"
name="deviceName" size="60" required>
<br/>
<input type="hidden" class="deviceType" name="deviceType"
value="drone"/>
<input type="hidden" class="sketchType" name="sketchType"
value="drone"/>
</div>
</div>
<div class="buttons" style="padding-bottom: 0px">
<a class="btn btn-operations" onclick="downloadAgent()">Download Now</a>
&nbsp;&nbsp;
</div>
</form>
</div>
</div>
</div>
</div>
<div id="device-agent-downloading-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Agent will downloading shortly.</h3>
</div>
</div>
</div>
</div>
<div id="device-400-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Exception at backend. Try Later.</h3>
<div class="buttons">
<a href="#" id="device-400-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-401-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>You have to log in first.</h3><br/>
<div class="buttons">
<a href="#" id="device-401-link" class="blue-button">
Goto Login Page
</a>&nbsp;&nbsp;
<a href="#" onclick="hidePopup();" class="btn-operations">
Cancel
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-403-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Action not permitted.</h3><br/>
<div class="buttons">
<a href="#" id="device-403-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-409-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Sketch does not exist.</h3><br/>
<div class="buttons">
<a href="#" id="device-409-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-unexpected-error-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Unexpected error.</h3><br/>
<div class="buttons">
<a href="#" id="device-unexpected-error-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<br/><br/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 padding-double grey-bg">
<h3 class="uppercase">Prepare</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">01</span>
&nbsp;&nbsp;&nbsp;Connect your IRIS+ Drone to your computer using either USB to Micro
USB cable or Telemetry Radio receiver.
</li>
<li class="padding-top-double">
<span class="circle">02</span>
&nbsp;&nbsp;&nbsp;Click on [Download Agent] button above to get IRIS+ Drone agent.
</li>
<li class="padding-top-double">
<span class="circle">03</span>
&nbsp;&nbsp;&nbsp;Once you have downloaded the agent please run
<i>"[startService.sh]"</i> script with root privileges.
</li>
<li class="padding-top-double">
<span class="circle">04</span>
&nbsp;&nbsp;&nbsp;Then you will be prompted to enter time interval (in seconds) between
successive Data-Pushes to the XMPP server, connection target and communication speed. So
below table will help you to find what is the correct connection target and
communication speed.
</li>
<div class="padding-top-double">
<table class="table table-bordered ">
<thead>
<tr>
<th>
<center><i>CONNECTION-TYPE</i></center>
</th>
<th>
<center><i>CONNECTION-STRING</i></center>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Linux computer connected to the vehicle via USB</td>
<td> e.g. /dev/ttyUSB0</td>
</tr>
<tr>
<td>Linux computer connected to the drone via Serial port</td>
<td> e.g. /dev/ttyAMA0 <i>(also set baud=57600)</i></td>
</tr>
<tr>
<td>OSX computer connected to the drone via USB</td>
<td>e.g. dev/cu.usbmodem1</td>
</tr>
<tr>
<td>Windows computer connected to the drone via USB (in this case on COM14)</td>
<td>e.g. com14</td>
</tr>
<tr>
<td>Windows computer connected to the drone using a 3DR Telemetry Radio on
COM14
</td>
<td>e.g. com14 <i>(also set baud=57600)</i></td>
</tr>
</tbody>
</table>
</div>
</ul>
<br>
<br>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 padding-double">
<h3 class="uppercase">IRIS+ Drone Connected to a computer</h3>
<hr>
<p class="grey margin-top">Click on the image to zoom</p>
<center>
<a href="{{@unit.publicUri}}/images/schematicsGuide.png" target="_blank">
<img src="{{@unit.publicUri}}/images/schematicsGuide.png" class="img-responsive">
</a>
</center>
<br/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 padding-double">
<h3 class="uppercase">Try Out</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">01</span>
&nbsp;&nbsp;&nbsp;You can view all your connected devices at
<a href="{{@app.context}}/devices">[Device Management]</a> page.
</li>
<li class="padding-top-double">
<span class="circle">02</span>
&nbsp;&nbsp;&nbsp;Select one of connected devices and view stats which are published by
the device.
</li>
</ul>
<br/>
<p class="grey margin-top">Click on the image to zoom</p>
<center>
<a href="{{@unit.publicUri}}/images/devices_analytics.png" target="_blank">
<img src="{{@unit.publicUri}}/images/devices_analytics.png" class="img-responsive">
</a>
</center>
</div>
{{#zone "topCss"}}
<style type="text/css">
.circle {
background: none repeat scroll 0 0 #191919;
border-radius: 50px;
height: 50px;
padding: 10px;
width: 50px;
color: #fff;
}
.padding-top-double {
padding-top: 20px;
}
.padding-double {
padding: 20px;
}
.grey {
color: #333;
}
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #7f7f7f;
margin: 1em 0;
padding: 0;
opacity: 0.2;
}
.light-grey {
color: #7c7c7c;
}
.uppercase {
text-transform: uppercase;
}
.grey-bg {
background-color: #f6f4f4;
}
.doc-link {
background: #11375B;
padding: 20px;
color: white;
margin-top: 0;
}
.doc-link a {
color: white;
}
</style>
{{/zone}}
{{#zone "bottomJs"}}
{{js "/js/download.js"}}
{{js "/js/jquery.validate.js"}}
{{/zone}}

View File

@ -0,0 +1,315 @@
<div class="col-lg-12 margin-top-double">
<h1 class="grey ">Drone Analyzer</h1>
<hr>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 padding-top">
<img src="{{@unit.publicUri}}/images/drone-icon.png" class="img-responsive">
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h4 class="doc-link">Click <a href="https://docs.wso2.com/pages/viewpage.action?pageId=48289181"
target="_blank">[ here ]</a> for latest instructions and
troubleshooting.</h4>
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h3 class="uppercase">What it Does</h3>
<hr>
<p class="grey margin-top">Connect an
<a href="https://store.3drobotics.com/products/iris" target="_blank">[IRIS+]</a> Drone to
WSO2 IoT Server and visualize statistics.
</p>
<br>
<h3 class="uppercase">What You Need</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">ITEM 01</span>
&nbsp;&nbsp;&nbsp;IRIS+ Drone.
</li>
<li class="padding-top-double">
<span class="circle">ITEM 02</span>
&nbsp;&nbsp;&nbsp;USB to Micro USB cable or Telemetry Radio receiver.
</li>
<li class="padding-top-double">
<span class="circle">STEP 03</span>
&nbsp;&nbsp;&nbsp;Proceed to [Prepare] section.
</ul>
<br>
<a href="/api-store/apis/info?name={{@uriParams.deviceType}}&version=1.0.0&provider=admin"
class="btn-operations"
target="_blank"><i class="fw fw-api"></i> View API</i> &nbsp;</a>
<a href="#" class="download-link btn-operations">
<i class="fw fw-download"></i>Download Agent
</a>
<div id="download-device-modal-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 center-container">
<h3>Name your device and download the agent from following link.</h3>
<br/>
<form id="downloadForm" method="GET"
action="{{@app.context}}/api/devices/sketch/download">
<div id="invalid-username-error-msg" class="alert alert-danger hidden"
role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<div class="control-group">
<div class="controls">
<input class="new-device-name" style="color:#3f3f3f;padding:5px"
type="text"
placeholder="Ex. drone"
name="deviceName" size="60" required>
<br/>
<input type="hidden" class="deviceType" name="deviceType"
value="drone_analyzer"/>
<input type="hidden" class="sketchType" name="sketchType"
value="drone_analyzer"/>
</div>
</div>
<br/>
<div class="buttons">
<a class="btn-operations" onclick="downloadAgent()">Download Now</a>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="device-agent-downloading-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Agent will downloading shortly.</h3>
</div>
</div>
</div>
</div>
<div id="device-400-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Exception at backend. Try Later.</h3>
<div class="buttons">
<a href="#" id="device-400-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-401-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>You have to log in first.</h3><br/>
<div class="buttons">
<a href="#" id="device-401-link" class="blue-button">
Goto Login Page
</a>&nbsp;&nbsp;
<a href="#" onclick="hidePopup();" class="btn-operations">
Cancel
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-403-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Action not permitted.</h3><br/>
<div class="buttons">
<a href="#" id="device-403-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-409-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Sketch does not exist.</h3><br/>
<div class="buttons">
<a href="#" id="device-409-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-unexpected-error-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Unexpected error.</h3><br/>
<div class="buttons">
<a href="#" id="device-unexpected-error-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<br/><br/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 padding-double grey-bg">
<h3 class="uppercase">Prepare</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">01</span>
&nbsp;&nbsp;&nbsp;Connect your IRIS+ Drone to your computer using either USB to Micro
USB cable or Telemetry Radio receiver.
</li>
<li class="padding-top-double">
<span class="circle">02</span>
&nbsp;&nbsp;&nbsp;Click on [Download Agent] button above to get IRIS+ Drone agent.
</li>
<li class="padding-top-double">
<span class="circle">03</span>
&nbsp;&nbsp;&nbsp;Once you have downloaded the agent please run
<i>"[startService.sh]"</i> script with root privileges.
</li>
<li class="padding-top-double">
<span class="circle">04</span>
&nbsp;&nbsp;&nbsp;Then you will be prompted to enter time interval (in seconds) between
successive Data-Pushes to the XMPP server, connection target and communication speed. So
below table will help you to find what is the correct connection target and
communication speed.
</li>
<div class="padding-top-double">
<table class="table table-bordered ">
<thead>
<tr>
<th>
<center><i>CONNECTION-TYPE</i></center>
</th>
<th>
<center><i>CONNECTION-STRING</i></center>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Linux computer connected to the vehicle via USB</td>
<td> e.g. /dev/ttyUSB0</td>
</tr>
<tr>
<td>Linux computer connected to the drone via Serial port</td>
<td> e.g. /dev/ttyAMA0 <i>(also set baud=57600)</i></td>
</tr>
<tr>
<td>OSX computer connected to the drone via USB</td>
<td>e.g. dev/cu.usbmodem1</td>
</tr>
<tr>
<td>Windows computer connected to the drone via USB (in this case on COM14)</td>
<td>e.g. com14</td>
</tr>
<tr>
<td>Windows computer connected to the drone using a 3DR Telemetry Radio on
COM14
</td>
<td>e.g. com14 <i>(also set baud=57600)</i></td>
</tr>
</tbody>
</table>
</div>
</ul>
<br>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 padding-double">
<h3 class="uppercase">IRIS+ Drone Connected to a computer</h3>
<hr>
<p class="grey margin-top">Click on the image to zoom</p>
<center>
<a href="{{@unit.publicUri}}/images/schematicsGuide.png" target="_blank">
<img src="{{@unit.publicUri}}/images/schematicsGuide.png" class="img-responsive">
</a>
</center>
<br/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 padding-double">
<h3 class="uppercase">Try Out</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="circle">01</span>
&nbsp;&nbsp;&nbsp;You can view all your connected devices at
<a href="{{@app.context}}/devices">[Device Management]</a> page.
</li>
<li class="padding-top-double">
<span class="circle">02</span>
&nbsp;&nbsp;&nbsp;Select one of connected devices and view stats which are published by
the device.
</li>
</ul>
<br/>
<p class="grey margin-top">Click on the image to zoom</p>
<center>
<a href="{{@unit.publicUri}}/images/devices_analytics.png" target="_blank">
<img src="{{@unit.publicUri}}/images/devices_analytics.png" class="img-responsive">
</a>
</center>
</div>
{{#zone "topCss"}}
<style type="text/css">
.circle {
background: none repeat scroll 0 0 #191919;
border-radius: 50px;
height: 50px;
padding: 10px;
width: 50px;
color: #fff;
}
.padding-top-double {
padding-top: 20px;
}
.padding-double {
padding: 20px;
}
.grey {
color: #333;
}
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #7f7f7f;
margin: 1em 0;
padding: 0;
opacity: 0.2;
}
.light-grey {
color: #7c7c7c;
}
.uppercase {
text-transform: uppercase;
}
.grey-bg {
background-color: #f6f4f4;
}
.doc-link {
background: #11375B;
padding: 20px;
color: white;
margin-top: 0;
}
.doc-link a {
color: white;
}
</style>
{{/zone}}
{{#zone "bottomJs"}}
{{js "/js/download.js"}}
{{js "/js/jquery.validate.js"}}
{{/zone}}

View File

@ -0,0 +1,207 @@
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.homeautomation</groupId>
<artifactId>droneanalyzer-feature</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0.0</version>
<artifactId>${project-base-package}.feature</artifactId>
<packaging>pom</packaging>
<name>${project-base-package}.feature </name>
<url>http://wso2.org</url>
<dependencies>
<dependency>
<groupId>org.homeautomation</groupId>
<artifactId>${project-base-package}.plugin</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.homeautomation</groupId>
<artifactId>${project-base-package}.api</artifactId>
<version>1.0.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.h2database.wso2</groupId>
<artifactId>h2-database-engine</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources</outputDirectory>
<resources>
<resource>
<directory>resources</directory>
<includes>
<include>build.properties</include>
<include>p2.inf</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.homeautomation</groupId>
<artifactId>${project-base-package}.analytics</artifactId>
<version>1.0.0</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/maven-shared-archive-resources/carbonapps
</outputDirectory>
<includes>**/*</includes>
</artifactItem>
<artifactItem>
<groupId>org.homeautomation</groupId>
<artifactId>${project-base-package}.ui
</artifactId>
<version>${project.version}</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt
</outputDirectory>
<includes>**/*</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>copy-jaxrs-war</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.homeautomation</groupId>
<artifactId>${project-base-package}.api</artifactId>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/maven-shared-archive-resources/webapps/
</outputDirectory>
<destFileName>drone.war</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>${maven-antrun-plugin.version}</version>
<executions>
<execution>
<id>create-drone-plugin-mgt-schema</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<property name="db.dir"
value="target/maven-shared-archive-resources/database"/>
<property name="userid" value="wso2carbon"/>
<property name="password" value="wso2carbon"/>
<property name="dbURL"
value="jdbc:h2:file:${basedir}/${db.dir}/droneDM_DB;DB_CLOSE_ON_EXIT=FALSE"/>
<mkdir dir="${basedir}/${db.dir}"/>
<sql driver="org.h2.Driver" url="${dbURL}" userid="${userid}"
password="${password}"
autocommit="true" onerror="continue">
<classpath refid="maven.dependency.classpath"/>
<classpath refid="maven.compile.classpath"/>
<classpath refid="maven.runtime.classpath"/>
<fileset file="${basedir}/src/main/resources/dbscripts/h2.sql"/>
</sql>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.wso2.maven</groupId>
<artifactId>carbon-p2-plugin</artifactId>
<version>${carbon-p2-plugin.version}</version>
<executions>
<execution>
<id>p2-feature-generation</id>
<phase>package</phase>
<goals>
<goal>p2-feature-gen</goal>
</goals>
<configuration>
<id>${project-base-package}</id>
<propertiesFile>../../../features/etc/feature.properties</propertiesFile>
<adviceFile>
<properties>
<propertyDef>org.wso2.carbon.p2.category.type:server</propertyDef>
<propertyDef>org.eclipse.equinox.p2.type.group:true</propertyDef>
</properties>
</adviceFile>
<bundles>
<bundleDef>
org.homeautomation:${project-base-package}.plugin:1.0.0
</bundleDef>
</bundles>
<importFeatures>
<importFeatureDef>org.wso2.carbon.core.server:${carbon.kernel.version}
</importFeatureDef>
<importFeatureDef>org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version}
</importFeatureDef>
</importFeatures>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,32 @@
#
# Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
[Device-Configurations]
owner=${DEVICE_OWNER}
deviceId=${DEVICE_ID}
device-name=${DEVICE_NAME}
server-name=${SERVER_NAME}
controller-context=/drone
device-type=drone
mqtt-ep=${MQTT_EP}
https-ep=${HTTPS_EP}
auth-method=token
auth-token=${DEVICE_TOKEN}
refresh-token=${DEVICE_REFRESH_TOKEN}
push-interval=15

View File

@ -0,0 +1,16 @@
#/*
# * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
# * WSO2 Inc. licenses this file to you under the Apache License,
# * Version 2.0 (the "License"); you may not use this file except
# * in compliance with the License.
# * You may obtain a copy of the License at
# * http://www.apache.org/licenses/LICENSE-2.0
# * Unless required by applicable law or agreed to in writing,
# * software distributed under the License is distributed on an
# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# * KIND, either express or implied. See the License for the
# * specific language governing permissions and limitations
# * under the License.
# */
templates=deviceConfig.properties
zipfilename=drone.zip

View File

@ -0,0 +1,246 @@
#!/usr/bin/env python
"""
/**
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
"""
import httplib
import logging
import logging.handlers
import signal
import ssl
import sys
import threading
import time, calendar
from functools import wraps
import random
import mqttHandler
import iotUtils
import argparse
import math
from dronekit import connect, VehicleMode
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Overriding the default SSL version used in some of the Python (2.7.x) versions
# This is a known issue in earlier Python releases
# But was fixed in later versions. Ex-2.7.11
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def sslwrap(func):
@wraps(func)
def bar(*args, **kw):
kw['ssl_version'] = ssl.PROTOCOL_TLSv1
return func(*args, **kw)
return bar
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUSH_INTERVAL = 2 # time interval between successive data pushes in seconds
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Logger defaults
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LOG_FILENAME = "agent.log"
logging_enabled = False
LOG_LEVEL = logging.INFO # Could be e.g. "DEBUG" or "WARNING"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Python version
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if sys.version_info<(2,6,0):
sys.stderr.write("You need python 2.6.0 or later to run this script\n")
exit(1)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define and parse command line arguments
# If the log file is specified on the command line then override the default
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONNECTION_TARGET = "/dev/ttyACM0"
PUSH_INTERVAL = 1
BAUD = 57600
parser = argparse.ArgumentParser(description='Connects to drone on ')
parser.add_argument("-c", "--connect", default='/dev/ttyACM0',help="vehicle connection target. Default '/dev/ttyACM0'")
parser.add_argument("-b", '--baud', type=int ,default=57600,help="Serial communication speed. Default 57600")
parser.add_argument("-i", "--push_interval", type=int, default=1,help="This is the interval which is used to push drone")
args = parser.parse_args()
if args.connect:
CONNECTION_TARGET = args.connect
if args.push_interval:
PUSH_INTERVAL = args.push_interval
if args.baud:
BAUD = args.baud
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Endpoint specific settings to connect with the IoT Server
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SERVER_ENDPOINT = iotUtils.HTTPS_EP.split(":")
SERVER_IP = SERVER_ENDPOINT[1].replace('//', '')
SERVER_PORT = int(SERVER_ENDPOINT[2])
API_ENDPOINT_CONTEXT = iotUtils.CONTROLLER_CONTEXT
REGISTER_ENDPOINT = str(API_ENDPOINT_CONTEXT) + '/device/register'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# A class we can use to capture stdout and sterr in the log
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class IOTLogger(object):
def __init__(self, logger, level):
"""Needs a logger and a logger level."""
self.logger = logger
self.level = level
def write(self, message):
if message.rstrip() != "": # Only log if there is a message (not just a new line)
self.logger.log(self.level, message.rstrip())
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Configure logging to log to a file,
# making a new file at midnight and keeping the last 3 day's data
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def configureLogger(loggerName):
logger = logging.getLogger(loggerName)
logger.setLevel(LOG_LEVEL) # Set the log level to LOG_LEVEL
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILENAME, when="midnight",
backupCount=3) # Handler that writes to a file,
# ~~~make new file at midnight and keep 3 backups
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') # Format each log message like this
handler.setFormatter(formatter) # Attach the formatter to the handler
logger.addHandler(handler) # Attach the handler to the logger
if (logging_enabled):
sys.stdout = IOTLogger(logger, logging.INFO) # Replace stdout with logging to file at INFO level
sys.stderr = IOTLogger(logger, logging.ERROR) # Replace stderr with logging to file at ERROR level
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This method is for register the sensor agent into the Device-Cloud
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def registerAgent():
ssl.wrap_socket = sslwrap(ssl.wrap_socket) # using the overridden sslwrap that uses TLSv1
if sys.version_info<(2,7,9):
dcConncection = httplib.HTTPSConnection(host=SERVER_IP, port=SERVER_PORT)
else:
dcConncection = httplib.HTTPSConnection(host=SERVER_IP, port=SERVER_PORT
, context=ssl._create_unverified_context())
dcConncection.set_debuglevel(1)
dcConncection.connect()
PUSH_DATA = iotUtils.DEVICE_INFO + iotUtils.DEVICE_DATA.format(sensorValue=0.0)
PUSH_DATA += '}'
print PUSH_DATA
registerURL = str(REGISTER_ENDPOINT)
dcConncection.putrequest('POST', registerURL)
dcConncection.putheader('Authorization', 'Bearer ' + iotUtils.AUTH_TOKEN)
dcConncection.putheader('Content-Type', 'application/json')
dcConncection.putheader('Content-Length', len(PUSH_DATA))
dcConncection.endheaders()
dcConncection.send(PUSH_DATA)
dcResponse = dcConncection.getresponse()
if(dcResponse.status < 400):
iotUtils.IS_REGISTERED = True
print "Your device has been registered with IoT Server"
else:
iotUtils.IS_REGISTERED = False
print "Your device hasn't been registered with IoT Server"
print ('agentStats: ' + str(dcResponse.status))
print ('agentStats: ' + str(dcResponse.reason))
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
print ('agentStats: ' + str(registerURL))
print ('agentStats: Response Message')
print str(dcResponse.msg)
dcConncection.close()
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This is a Thread object for listening for MQTT Messages
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ListenMQTTThread(object):
def __init__(self):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True # Daemonize thread
thread.start() # Start the execution
def run(self):
mqttHandler.main()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def getSensorValue():
return iotUtils.generateRandomSensorValues()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# When sysvinit sends the TERM signal, cleanup before exiting
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def sigterm_handler(_signo, _stack_frame):
print("[] received signal {}, exiting...".format(_signo))
sys.exit(0)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def generateLatitudeLongitudeValue(lat, lon, num_rows):
for _ in xrange(num_rows):
hex1 = '%012x' % random.randrange(16**12) # 12 char random string
flt = float(random.randint(0,100))
dec_lat = random.random()/100
dec_lon = random.random()/100
return lon+dec_lon, lat+dec_lat
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
signal.signal(signal.SIGTERM, sigterm_handler)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The Main method of the Agent
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main():
configureLogger("agent")
ListenMQTTThread()
registerAgent() # Call the register endpoint and register Device I
print "\nConnecting to vehicle on: %s" % CONNECTION_TARGET
print "----------------------------------------------------------------------"
vehicle = connect(CONNECTION_TARGET, wait_ready=True, baud=BAUD)
while (True):
if(iotUtils.IS_REGISTERED):
currentTime = calendar.timegm(time.gmtime())
PUSH_DATA = iotUtils.SENSOR_STATS + '"time":'+str(currentTime)+'},"payloadData":{"quatanium_val_q1":'+0\
+',"quatanium_val_q2":'+0+',"quatanium_val_q3":'+0+',"quatanium_val_q4":'+0+',"velocity_x":'\
+str(vehicle.velocity[0])+',"velocity_y":'+str(vehicle.velocity[1])+',"velocity_z":'\
+str(vehicle.velocity[2])+',"global_location_lat":'+str(vehicle.location.global_relative_frame.lat)\
+',"global_location_alt":'+str(vehicle.location.global_relative_frame.alt)\
+',"global_location_lon":'+str(vehicle.location.global_relative_frame.lon)+',"battery_level":'\
+str(vehicle.battery.level)+',"battery_voltage":'+str(vehicle.battery.voltage)+',"pitch":'\
+str(vehicle.attitude.pitch)+',"roll":'+str(vehicle.attitude.roll)+',"yaw":'\
+str(vehicle.attitude.yaw)+',"deviceType":"IRIS_DRONE"}}}';
mqttHandler.sendSensorValue(PUSH_DATA)
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Publishing Device-Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
print ('PUBLISHED DATA: ' + PUSH_DATA)
time.sleep(PUSH_INTERVAL)
else:
registerAgent()
time.sleep(PUSH_INTERVAL)
print "-------------------------------------------------------------------------------------------------"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == "__main__":
main()

View File

@ -0,0 +1,239 @@
#!/usr/bin/env python
"""
/**
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
"""
import httplib
import logging
import logging.handlers
import signal
import ssl
import sys
import threading
import time, calendar
from functools import wraps
import random
import mqttHandler
import iotUtils
import argparse
import math
from dronekit import connect, VehicleMode
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Overriding the default SSL version used in some of the Python (2.7.x) versions
# This is a known issue in earlier Python releases
# But was fixed in later versions. Ex-2.7.11
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def sslwrap(func):
@wraps(func)
def bar(*args, **kw):
kw['ssl_version'] = ssl.PROTOCOL_TLSv1
return func(*args, **kw)
return bar
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUSH_INTERVAL = 2 # time interval between successive data pushes in seconds
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Logger defaults
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LOG_FILENAME = "agent.log"
logging_enabled = False
LOG_LEVEL = logging.INFO # Could be e.g. "DEBUG" or "WARNING"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Python version
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if sys.version_info<(2,6,0):
sys.stderr.write("You need python 2.6.0 or later to run this script\n")
exit(1)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define and parse command line arguments
# If the log file is specified on the command line then override the default
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUSH_INTERVAL = 1
parser = argparse.ArgumentParser(description='Connects to drone on ')
parser.add_argument("-i", "--push_interval", type=int, default=1,help="This is the interval which is used to push drone")
args = parser.parse_args()
if args.push_interval:
PUSH_INTERVAL = args.push_interval
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Endpoint specific settings to connect with the IoT Server
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SERVER_ENDPOINT = iotUtils.HTTPS_EP.split(":")
SERVER_IP = SERVER_ENDPOINT[1].replace('//', '')
SERVER_PORT = int(SERVER_ENDPOINT[2])
API_ENDPOINT_CONTEXT = iotUtils.CONTROLLER_CONTEXT
REGISTER_ENDPOINT = str(API_ENDPOINT_CONTEXT) + '/device/register'
INIT_LATITUDE = 19.99
INIT_LONGITUDE = 73.78
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# A class we can use to capture stdout and sterr in the log
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class IOTLogger(object):
def __init__(self, logger, level):
"""Needs a logger and a logger level."""
self.logger = logger
self.level = level
def write(self, message):
if message.rstrip() != "": # Only log if there is a message (not just a new line)
self.logger.log(self.level, message.rstrip())
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Configure logging to log to a file,
# making a new file at midnight and keeping the last 3 day's data
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def configureLogger(loggerName):
logger = logging.getLogger(loggerName)
logger.setLevel(LOG_LEVEL) # Set the log level to LOG_LEVEL
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILENAME, when="midnight",
backupCount=3) # Handler that writes to a file,
# ~~~make new file at midnight and keep 3 backups
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') # Format each log message like this
handler.setFormatter(formatter) # Attach the formatter to the handler
logger.addHandler(handler) # Attach the handler to the logger
if (logging_enabled):
sys.stdout = IOTLogger(logger, logging.INFO) # Replace stdout with logging to file at INFO level
sys.stderr = IOTLogger(logger, logging.ERROR) # Replace stderr with logging to file at ERROR level
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This method is for register the sensor agent into the Device-Cloud
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def registerAgent():
ssl.wrap_socket = sslwrap(ssl.wrap_socket) # using the overridden sslwrap that uses TLSv1
if sys.version_info<(2,7,9):
dcConncection = httplib.HTTPSConnection(host=SERVER_IP, port=SERVER_PORT)
else:
dcConncection = httplib.HTTPSConnection(host=SERVER_IP, port=SERVER_PORT
, context=ssl._create_unverified_context())
dcConncection.set_debuglevel(1)
dcConncection.connect()
PUSH_DATA = iotUtils.DEVICE_INFO + iotUtils.DEVICE_DATA.format(sensorValue=0.0)
PUSH_DATA += '}'
print PUSH_DATA
registerURL = str(REGISTER_ENDPOINT)
dcConncection.putrequest('POST', registerURL)
dcConncection.putheader('Authorization', 'Bearer ' + iotUtils.AUTH_TOKEN)
dcConncection.putheader('Content-Type', 'application/json')
dcConncection.putheader('Content-Length', len(PUSH_DATA))
dcConncection.endheaders()
dcConncection.send(PUSH_DATA)
dcResponse = dcConncection.getresponse()
if(dcResponse.status < 400):
iotUtils.IS_REGISTERED = True
print "Your device has been registered with IoT Server"
else:
iotUtils.IS_REGISTERED = False
print "Your device hasn't been registered with IoT Server"
print ('agentStats: ' + str(dcResponse.status))
print ('agentStats: ' + str(dcResponse.reason))
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
print ('agentStats: ' + str(registerURL))
print ('agentStats: Response Message')
print str(dcResponse.msg)
dcConncection.close()
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This is a Thread object for listening for MQTT Messages
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ListenMQTTThread(object):
def __init__(self):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True # Daemonize thread
thread.start() # Start the execution
def run(self):
mqttHandler.main()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def getSensorValue():
return iotUtils.generateRandomSensorValues()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# When sysvinit sends the TERM signal, cleanup before exiting
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def sigterm_handler(_signo, _stack_frame):
print("[] received signal {}, exiting...".format(_signo))
sys.exit(0)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def generateLatitudeLongitudeValue(lat, lon, num_rows):
for _ in xrange(num_rows):
hex1 = '%012x' % random.randrange(16**12) # 12 char random string
flt = float(random.randint(0,100))
dec_lat = random.random()/100
dec_lon = random.random()/100
return lon+dec_lon, lat+dec_lat
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
signal.signal(signal.SIGTERM, sigterm_handler)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The Main method of the Agent
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main():
configureLogger("agent")
ListenMQTTThread()
registerAgent() # Call the register endpoint and register Device I
print "----------------------------------------------------------------------"
while (True):
if(iotUtils.IS_REGISTERED):
print "-------------------------------------------------------------------------------------------------"
currentTime = calendar.timegm(time.gmtime())
randomLatitudeLongitudeValue = generateLatitudeLongitudeValue(INIT_LATITUDE, INIT_LONGITUDE, 5)
print randomLatitudeLongitudeValue[1]
PUSH_DATA = iotUtils.SENSOR_STATS + '"time":'+str(currentTime)+'},"payloadData":{"quatanium_val_q1":34,' \
'"quatanium_val_q2":'+str(random.randint(15, 40))+',"quatanium_val_q3":'\
+str(random.randint(15, 40))+',"quatanium_val_q4":'+str(random.randint(15, 40))+',"velocity_x":'\
+str(random.randint(15, 40))+',"velocity_y":'+str(random.randint(15, 40))+',"velocity_z":678,' \
'"global_location_lat":'+str(randomLatitudeLongitudeValue[0])+',"global_location_alt":45,' \
'"global_location_lon":'+str(randomLatitudeLongitudeValue[1])+',"battery_level":'\
+str(random.randint(15, 100))+',"battery_voltage":'+str(random.randint(15, 100))+',"pitch":'\
+str(random.randint(15, 40))+',"roll":'+str(random.randint(15, 40))+',"yaw":'\
+str(random.randint(15, 40))+'}}}';
mqttHandler.sendSensorValue(PUSH_DATA)
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Publishing Device-Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
print ('PUBLISHED DATA: ' + PUSH_DATA)
time.sleep(PUSH_INTERVAL)
else:
registerAgent()
time.sleep(PUSH_INTERVAL)
print "-------------------------------------------------------------------------------------------------"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == "__main__":
main()

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python
"""
/**
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
"""
import ConfigParser
import os
import random
import time, calendar
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Device specific info when pushing data to server
# Read from a file "deviceConfig.properties" in the same folder level
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
configParser = ConfigParser.RawConfigParser()
configFilePath = os.path.join(os.path.dirname(__file__), './deviceConfig.properties')
configParser.read(configFilePath)
DEVICE_OWNER = configParser.get('Device-Configurations', 'owner')
DEVICE_ID = configParser.get('Device-Configurations', 'deviceId')
DEVICE_NAME = configParser.get('Device-Configurations', 'device-name')
DEVICE_TYPE = configParser.get('Device-Configurations', 'device-type')
SERVER_NAME = configParser.get('Device-Configurations', 'server-name')
MQTT_EP = configParser.get('Device-Configurations', 'mqtt-ep')
AUTH_TOKEN = configParser.get('Device-Configurations', 'auth-token')
CONTROLLER_CONTEXT = configParser.get('Device-Configurations', 'controller-context')
DEVICE_INFO = '{"owner":"' + DEVICE_OWNER + '","deviceId":"' + DEVICE_ID + '",'
HTTPS_EP = configParser.get('Device-Configurations', 'https-ep')
DEVICE_DATA = '"sensorValue":"{sensorValue}"'
global IS_REGISTERED
IS_REGISTERED = False
def isEmpty (string):
if string and string.strip():
#string is not None AND string is not empty or blank
return False
#string is None OR string is empty or blank
return True
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This method generate a random sensor value between 15 and 40
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def generateRandomSensorValues():
return random.randint(15, 40)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
currentTime = calendar.timegm(time.gmtime())
SENSOR_STATS = '{"event":{"metaData":{"owner":"' + DEVICE_OWNER + '","deviceType":"'+ DEVICE_TYPE +'","deviceId":"'+ DEVICE_ID + '",'

View File

@ -0,0 +1,102 @@
#!/usr/bin/env python
"""
/**
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
"""
import time
import paho.mqtt.client as mqtt
import iotUtils
global mqttClient
mqttClient = mqtt.Client()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The callback for when the client receives a CONNACK response from the server.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_connect(mqttClient, userdata, flags, rc):
print("MQTT_LISTENER: Connected with result code " + str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
print ("MQTT_LISTENER: Subscribing with topic " + TOPIC_TO_SUBSCRIBE)
mqttClient.subscribe(TOPIC_TO_SUBSCRIBE)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The callback for when a PUBLISH message is received from the server.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_message(mqttClient, userdata, msg):
print( "MQTT_LISTENER: " + msg.topic + " " + str(msg.payload))
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The callback for when a PUBLISH message to the server when door is open or close
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def on_publish(mqttClient, msg):
mqttClient.publish(TOPIC_TO_PUBLISH, msg)
def sendSensorValue(msg):
global mqttClient
on_publish(mqttClient, msg)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# The Main method of the server script
# This method is invoked from Agent.py on a new thread
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main():
MQTT_ENDPOINT = iotUtils.MQTT_EP.split(":")
MQTT_IP = MQTT_ENDPOINT[1].replace('//','')
MQTT_PORT = int(MQTT_ENDPOINT[2])
DEV_OWNER = iotUtils.DEVICE_OWNER
DEV_ID = iotUtils.DEVICE_ID
DEV_TYPE =iotUtils.DEVICE_TYPE
TANENT_DOMAIN = iotUtils.SERVER_NAME
global TOPIC_TO_SUBSCRIBE
TOPIC_TO_SUBSCRIBE = TANENT_DOMAIN + "/" + DEV_TYPE + "/" + DEV_ID + "/command"
global TOPIC_TO_PUBLISH
TOPIC_TO_PUBLISH = TANENT_DOMAIN + "/" + DEV_TYPE + "/" + DEV_ID + "/publisher"
print ("MQTT_LISTENER: MQTT_ENDPOINT is " + str(MQTT_ENDPOINT))
print ("MQTT_LISTENER: MQTT_TOPIC is " + TOPIC_TO_SUBSCRIBE)
global mqttClient
mqttClient.username_pw_set(iotUtils.AUTH_TOKEN, password = "")
mqttClient.on_connect = on_connect
mqttClient.on_message = on_message
while True:
try:
mqttClient.connect(MQTT_IP, MQTT_PORT, 60)
print "MQTT_LISTENER: " + time.asctime(), "Connected to MQTT Broker - %s:%s" % (MQTT_IP, MQTT_PORT)
mqttClient.loop_forever()
except (KeyboardInterrupt, Exception) as e:
print "MQTT_LISTENER: Exception in MQTTServerThread (either KeyboardInterrupt or Other)"
print ("MQTT_LISTENER: " + str(e))
mqttClient.disconnect()
print "MQTT_LISTENER: " + time.asctime(), "Connection to Broker closed - %s:%s" % (MQTT_IP, MQTT_PORT)
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
pass
if __name__ == '__main__':
main()

View File

@ -0,0 +1,104 @@
#"""
#/**
#* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
#*
#* WSO2 Inc. licenses this file to you under the Apache License,
#* Version 2.0 (the "License"); you may not use this file except
#* in compliance with the License.
#* You may obtain a copy of the License at
#*
#* http://www.apache.org/licenses/LICENSE-2.0
#*
#* Unless required by applicable law or agreed to in writing,
#* software distributed under the License is distributed on an
#* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#* KIND, either express or implied. See the License for the
#* specific language governing permissions and limitations
#* under the License.
#**/
#"""
#!/bin/bash
echo "----------------------------------------------------------------"
echo "| WSO2 IOT Sample "
echo "| Drone Analyzer "
echo "| ---------------- "
echo "| ....initializing startup-script "
echo "----------------------------------------------------------------"
currentDir=$PWD
while true; do
read -p "Do you wish to run 'apt-get update' and continue? [Yes/No] " yn
case $yn in
[Yy]* ) sudo apt-get update;
break;;
[Nn]* ) echo "Continuing without apt-get update...";
break;;
* ) echo "Please answer yes or no.";
esac
done
for f in ./deviceConfig.properties; do
## Check if the glob gets expanded to existing files.
## If not, f here will be exactly the pattern above
## and the exists test will evaluate to false.
if [ -e "$f" ]; then
echo "Configuration file found......"
else
echo "'deviceConfig.properties' file does not exist in current path. \nExiting installation...";
exit;
fi
## This is all we needed to know, so we can break after the first iteration
break
done
#installing dependencies
sudo apt-get install python-pip python-dev
git clone git://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.python.git
cd org.eclipse.paho.mqtt.python
sudo python setup.py install
cd ../
cp deviceConfig.properties ./src
while true; do
read -p "Do you wish to run this as simulator if it is so enter yes and continue? [Yes/No] " yn
case $yn in
[Yy]* ) echo "Continuing with simulator...";
while true; do
read -p "Whats the time-interval (in seconds) between successive Data-Pushes to the DAS (ex: '60' indicates 1 minute) > " push_interval
if [ $input -eq $input 2>/dev/null ]
then
echo "Setting data-push interval to $push_interval seconds."
break
else
echo "Input needs to be an integer indicating the number seconds between successive data-pushes."
fi
done
python ./src/droneSimulator.py -i $push_interval
break;;
[Nn]* ) echo "Continuing with real device...";
sudo pip install dronekit
while true; do
read -p "Whats the time-interval (in seconds) between successive Data-Pushes to the DAS (ex: '60' indicates 1 minute) > " push_interval
read -p "Vehicle connection target. Default '/dev/ttyACM0' :" connection_target
read -p "Serial communication speed. Default 57600 :" baud
if [ $input -eq $input 2>/dev/null ]
then
echo "Setting data-push interval to $push_interval seconds."
break
else
echo "Input needs to be an integer indicating the number seconds between successive data-pushes."
fi
done
python ./src/drone.py -i $push_interval -b $baud -c $connection_target
break;;
* ) echo "Please answer yes or no.";
esac
done
echo "Could not start the service..."
exit;

View File

@ -0,0 +1,18 @@
#<!--
# ~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
# ~
# ~ WSO2 Inc. licenses this file to you under the Apache License,
# ~ Version 2.0 (the "License"); you may not use this file except
# ~ in compliance with the License.
# ~ You may obtain a copy of the License at
# ~
# ~ http://www.apache.org/licenses/LICENSE-2.0
# ~
# ~ Unless required by applicable law or agreed to in writing,
# ~ software distributed under the License is distributed on an
# ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# ~ KIND, either express or implied. See the License for the
# ~ specific language governing permissions and limitations
# ~ under the License.
# -->
custom = true

View File

@ -0,0 +1,20 @@
{
"deviceType": {
"label": "drone",
"category": "virtual",
"downloadAgentUri": "drone/enrollment/devices/download"
},
"analyticStreams": [
{
"name": "Temperature",
"table": "DEVICE_drone_droneStats_SUMMARY",
"ui_unit": {
"name": "cdmf.unit.analytics.line-chart",
"data":[
{"column": {"name":"TIME", "label":"time", "ui-mapping":"x-axis"}},
{"column": {"name":"droneStats", "label":"droneStats", "ui-mapping":"y-axis"}}
]
}
}
]
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<DeviceTypeConfigurations>
<DeviceTypeConfig type="drone">
<DatasourceName>jdbc/droneDM_DB</DatasourceName>
</DeviceTypeConfig>
</DeviceTypeConfigurations>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<datasources-configuration xmlns:svns="http://org.wso2.securevault/configuration">
<providers>
<provider>org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader</provider>
</providers>
<datasources>
<datasource>
<name>droneDM_DB</name>
<description>The datasource used for the this device type </description>
<jndiConfig>
<name>jdbc/droneDM_DB</name>
</jndiConfig>
<definition type="RDBMS">
<configuration>
<url>jdbc:h2:repository/database/droneDM_DB;DB_CLOSE_ON_EXIT=FALSE
</url>
<username>wso2carbon</username>
<password>wso2carbon</password>
<driverClassName>org.h2.Driver</driverClassName>
<maxActive>50</maxActive>
<maxWait>60000</maxWait>
<testOnBorrow>true</testOnBorrow>
<validationQuery>SELECT 1</validationQuery>
<validationInterval>30000</validationInterval>
</configuration>
</definition>
</datasource>
</datasources>
</datasources-configuration>

View File

@ -0,0 +1,11 @@
-- -----------------------------------------------------
-- Agent Database
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `drone_DEVICE` (
`drone_DEVICE_ID` VARCHAR(45) NOT NULL ,
`DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL,
PRIMARY KEY (`drone_DEVICE_ID`) );

View File

@ -0,0 +1,9 @@
-- -----------------------------------------------------
-- Table `drone_DEVICE`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS drone_DEVICE (
drone_DEVICE_ID VARCHAR(45) NOT NULL ,
DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL,
PRIMARY KEY (drone_DEVICE_ID) );

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS `drone_DEVICE` (
`drone_DEVICE_ID` VARCHAR(45) NOT NULL ,
`DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL,
PRIMARY KEY (`drone_DEVICE_ID`) )
ENGINE = InnoDB;

View File

@ -0,0 +1,9 @@
-- -----------------------------------------------------
-- Table `drone_DEVICE`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS drone_DEVICE (
drone_DEVICE_ID VARCHAR(45) NOT NULL ,
DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL,
PRIMARY KEY (drone_DEVICE_ID) );

View File

@ -0,0 +1,28 @@
instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../conf/device-types/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/configs/,target:${installFolder}/../../conf/device-types/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/droneanalyzer/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/agent/,target:${installFolder}/../../resources/sketches/drone/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/dbscripts/,target:${installFolder}/../../../dbscripts/cdm/plugins/drone,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/datasources/,target:${installFolder}/../../conf/datasources/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/jaggeryapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/carbonapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.droneanalyzer_${feature.version}/carbonapps/,target:${installFolder}/../../deployment/server/carbonapps/,overwrite:true);\
instructions.unconfigure = \
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../conf/device-types/drone.xml);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/drone.war);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/drone);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../dbscripts/cdm/plugins/drone);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../conf/datasources/drone-datasources.xml);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../database/droneDM_DB.h2.db);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone.device-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone.type-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone.realtime.analytics-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone.analytics-view);\

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.homeautomation</groupId>
<artifactId>droneanalyzer</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>droneanalyzer-feature</artifactId>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>feature</module>
</modules>
</project>

Some files were not shown because too many files have changed in this diff Show More