forked from community/device-mgt-plugins
Merge pull request #60 from Shabirmean/IoTS-1.0.0-M1
Added complete RaspberryPi Component and Feature
commit
561d46a377
@ -0,0 +1,149 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<artifactId>device-mgt-iot-raspberrypi</artifactId>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
|
||||||
|
<version>1.9.2-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.iot.raspberrypi.service.impl</artifactId>
|
||||||
|
<version>1.9.2-SNAPSHOT</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>WSO2 Carbon - IoT Server RaspberryPi API</name>
|
||||||
|
<description>WSO2 Carbon - RaspberryPi Service API Implementation</description>
|
||||||
|
<url>http://wso2.org</url>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- CDM -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.core</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.axis2.wso2</groupId>
|
||||||
|
<artifactId>axis2-client</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--CXF -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-frontend-jaxws</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-transports-http</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--MQTT -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.paho</groupId>
|
||||||
|
<artifactId>mqtt-client</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--IOT -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpasyncclient</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.iot</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--JAX-RS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-core-asl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-jaxrs</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax</groupId>
|
||||||
|
<artifactId>javaee-web-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.ws.rs</groupId>
|
||||||
|
<artifactId>jsr311-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>org.wso2.carbon.device.mgt.analytics</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<source>${wso2.maven.compiler.source}</source>
|
||||||
|
<target>${wso2.maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<warName>raspberrypi</warName>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,624 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.iot.raspberrypi.service;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
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.iot.DeviceManagement;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.DeviceValidator;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.apimgt.AccessTokenInfo;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.apimgt.TokenClient;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppAccount;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.exception.AccessTokenException;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.service.dto.DeviceJSON;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.service.transport.RaspberryPiMQTTSubscriber;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.service.util.RaspberrypiServiceUtils;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.util.ZipArchive;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.util.ZipUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.HeaderParam;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
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.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Path("/RaspberryPiDeviceManager")
|
||||||
|
public class RaspberryPiService {
|
||||||
|
|
||||||
|
private static Log log = LogFactory.getLog(RaspberryPiService.class);
|
||||||
|
|
||||||
|
//TODO; replace this tenant domain
|
||||||
|
private static final String SUPER_TENANT = "carbon.super";
|
||||||
|
|
||||||
|
@Context //injected response proxy supporting multiple thread
|
||||||
|
private HttpServletResponse response;
|
||||||
|
|
||||||
|
public static final String HTTP_PROTOCOL = "HTTP";
|
||||||
|
public static final String MQTT_PROTOCOL = "MQTT";
|
||||||
|
|
||||||
|
private ConcurrentHashMap<String, String> deviceToIpMap = new ConcurrentHashMap<>();
|
||||||
|
private RaspberryPiMQTTSubscriber raspberryPiMQTTSubscriber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param raspberryPiMQTTSubscriber
|
||||||
|
*/
|
||||||
|
public void setRaspberryPiMQTTSubscriber(
|
||||||
|
final RaspberryPiMQTTSubscriber raspberryPiMQTTSubscriber) {
|
||||||
|
this.raspberryPiMQTTSubscriber = raspberryPiMQTTSubscriber;
|
||||||
|
|
||||||
|
Runnable xmppStarter = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
raspberryPiMQTTSubscriber.initConnector();
|
||||||
|
raspberryPiMQTTSubscriber.connectAndSubscribe();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread xmppStarterThread = new Thread(xmppStarter);
|
||||||
|
xmppStarterThread.setDaemon(true);
|
||||||
|
xmppStarterThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public RaspberryPiMQTTSubscriber getRaspberryPiMQTTSubscriber() {
|
||||||
|
return raspberryPiMQTTSubscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------
|
||||||
|
Device management specific APIs
|
||||||
|
Also contains utility methods required for the execution of these APIs
|
||||||
|
--------------------------------------------------------------------------------------- */
|
||||||
|
@Path("manager/device/register")
|
||||||
|
@PUT
|
||||||
|
public boolean register(@QueryParam("deviceId") String deviceId,
|
||||||
|
@QueryParam("name") String name, @QueryParam("owner") String owner) {
|
||||||
|
|
||||||
|
DeviceManagement deviceManagement = new DeviceManagement(SUPER_TENANT);
|
||||||
|
|
||||||
|
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||||
|
deviceIdentifier.setId(deviceId);
|
||||||
|
deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
try {
|
||||||
|
if (deviceManagement.getDeviceManagementService().isEnrolled(deviceIdentifier)) {
|
||||||
|
response.setStatus(Response.Status.CONFLICT.getStatusCode());
|
||||||
|
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(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
enrolmentInfo.setOwner(owner);
|
||||||
|
device.setEnrolmentInfo(enrolmentInfo);
|
||||||
|
boolean added = deviceManagement.getDeviceManagementService().enrollDevice(device);
|
||||||
|
if (added) {
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
} else {
|
||||||
|
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return added;
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
deviceManagement.endTenantFlow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("manager/device/remove/{device_id}")
|
||||||
|
@DELETE
|
||||||
|
public void removeDevice(@PathParam("device_id") String deviceId,
|
||||||
|
@Context HttpServletResponse response) {
|
||||||
|
|
||||||
|
DeviceManagement deviceManagement = new DeviceManagement(SUPER_TENANT);
|
||||||
|
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||||
|
deviceIdentifier.setId(deviceId);
|
||||||
|
deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
try {
|
||||||
|
boolean removed = deviceManagement.getDeviceManagementService().disenrollDevice(
|
||||||
|
deviceIdentifier);
|
||||||
|
if (removed) {
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
} else {
|
||||||
|
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
|
||||||
|
}
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
} finally {
|
||||||
|
deviceManagement.endTenantFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("manager/device/update/{device_id}")
|
||||||
|
@POST
|
||||||
|
public boolean updateDevice(@PathParam("device_id") String deviceId,
|
||||||
|
@QueryParam("name") String name,
|
||||||
|
@Context HttpServletResponse response) {
|
||||||
|
|
||||||
|
DeviceManagement deviceManagement = new DeviceManagement(SUPER_TENANT);
|
||||||
|
|
||||||
|
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||||
|
deviceIdentifier.setId(deviceId);
|
||||||
|
deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
try {
|
||||||
|
Device device = deviceManagement.getDeviceManagementService().getDevice(deviceIdentifier);
|
||||||
|
device.setDeviceIdentifier(deviceId);
|
||||||
|
|
||||||
|
// device.setDeviceTypeId(deviceTypeId);
|
||||||
|
device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime());
|
||||||
|
|
||||||
|
device.setName(name);
|
||||||
|
device.setType(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
|
||||||
|
boolean updated = deviceManagement.getDeviceManagementService().modifyEnrollment(device);
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
log.error(e.getErrorMessage());
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
deviceManagement.endTenantFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("manager/device/{device_id}")
|
||||||
|
@GET
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Device getDevice(@PathParam("device_id") String deviceId) {
|
||||||
|
|
||||||
|
DeviceManagement deviceManagement = new DeviceManagement(SUPER_TENANT);
|
||||||
|
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||||
|
deviceIdentifier.setId(deviceId);
|
||||||
|
deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return deviceManagement.getDeviceManagementService().getDevice(deviceIdentifier);
|
||||||
|
} catch (DeviceManagementException ex) {
|
||||||
|
log.error("Error occurred while retrieving device with Id " + deviceId + "\n" + ex);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
deviceManagement.endTenantFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("manager/devices/{username}")
|
||||||
|
@GET
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Device[] getRaspberrypiDevices(@PathParam("username") String username) {
|
||||||
|
|
||||||
|
DeviceManagement deviceManagement = new DeviceManagement(SUPER_TENANT);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<Device> userDevices = deviceManagement.getDeviceManagementService().getDevicesOfUser(username);
|
||||||
|
ArrayList<Device> usersRaspberrypiDevices = new ArrayList<>();
|
||||||
|
for (Device device : userDevices) {
|
||||||
|
if (device.getType().equals(RaspberrypiConstants.DEVICE_TYPE) &&
|
||||||
|
device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) {
|
||||||
|
usersRaspberrypiDevices.add(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return usersRaspberrypiDevices.toArray(new Device[]{});
|
||||||
|
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
deviceManagement.endTenantFlow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("manager/device/{sketch_type}/download")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Response downloadSketch(@QueryParam("owner") String owner,
|
||||||
|
@QueryParam("deviceName") String customDeviceName,
|
||||||
|
@PathParam("sketch_type") String
|
||||||
|
sketchType) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipArchive zipFile = createDownloadFile(owner, customDeviceName, sketchType);
|
||||||
|
Response.ResponseBuilder response = Response.ok(FileUtils.readFileToByteArray(zipFile.getZipFile()));
|
||||||
|
response.type("application/zip");
|
||||||
|
response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\"");
|
||||||
|
return response.build();
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
return Response.status(400).entity(ex.getMessage()).build();//bad request
|
||||||
|
} catch (DeviceManagementException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
} catch (AccessTokenException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
} catch (DeviceControllerException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Path("manager/device/{sketch_type}/generate_link")
|
||||||
|
@GET
|
||||||
|
public Response generateSketchLink(@QueryParam("owner") String owner,
|
||||||
|
@QueryParam("deviceName") String customDeviceName,
|
||||||
|
@PathParam("sketch_type") String sketchType) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipArchive zipFile = createDownloadFile(owner, customDeviceName, sketchType);
|
||||||
|
Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId());
|
||||||
|
return rb.build();
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
return Response.status(400).entity(ex.getMessage()).build();//bad request
|
||||||
|
} catch (DeviceManagementException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
} catch (AccessTokenException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
} catch (DeviceControllerException ex) {
|
||||||
|
return Response.status(500).entity(ex.getMessage()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ZipArchive createDownloadFile(String owner, String customDeviceName, String sketchType)
|
||||||
|
throws DeviceManagementException, AccessTokenException, DeviceControllerException {
|
||||||
|
if (owner == null) {
|
||||||
|
throw new IllegalArgumentException("Error on createDownloadFile() Owner is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//create new device id
|
||||||
|
String deviceId = shortUUID();
|
||||||
|
|
||||||
|
TokenClient accessTokenClient = new TokenClient(RaspberrypiConstants.DEVICE_TYPE);
|
||||||
|
AccessTokenInfo accessTokenInfo = accessTokenClient.getAccessToken(owner, deviceId);
|
||||||
|
|
||||||
|
//create token
|
||||||
|
String accessToken = accessTokenInfo.getAccess_token();
|
||||||
|
String refreshToken = accessTokenInfo.getRefresh_token();
|
||||||
|
//adding registering data
|
||||||
|
|
||||||
|
XmppAccount newXmppAccount = new XmppAccount();
|
||||||
|
newXmppAccount.setAccountName(owner + "_" + deviceId);
|
||||||
|
newXmppAccount.setUsername(deviceId);
|
||||||
|
newXmppAccount.setPassword(accessToken);
|
||||||
|
newXmppAccount.setEmail(deviceId + "@wso2.com");
|
||||||
|
|
||||||
|
XmppServerClient xmppServerClient = new XmppServerClient();
|
||||||
|
xmppServerClient.initControlQueue();
|
||||||
|
boolean status;
|
||||||
|
|
||||||
|
if (XmppConfig.getInstance().isEnabled()) {
|
||||||
|
status = xmppServerClient.createXMPPAccount(newXmppAccount);
|
||||||
|
if (!status) {
|
||||||
|
String msg =
|
||||||
|
"XMPP Account was not created for device - " + deviceId + " of owner - " + owner +
|
||||||
|
".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot.common.config" +
|
||||||
|
".server.configs";
|
||||||
|
log.warn(msg);
|
||||||
|
throw new DeviceManagementException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Register the device with CDMF
|
||||||
|
String deviceName = customDeviceName + "_" + deviceId;
|
||||||
|
status = register(deviceId, deviceName, owner);
|
||||||
|
|
||||||
|
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.downloadSketch(owner, SUPER_TENANT, sketchType, deviceId, deviceName, accessToken,
|
||||||
|
refreshToken);
|
||||||
|
zipFile.setDeviceId(deviceId);
|
||||||
|
return zipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------
|
||||||
|
Device specific APIs - Control APIs + Data-Publishing APIs
|
||||||
|
--------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@Path("controller/register/{owner}/{deviceId}/{ip}/{port}")
|
||||||
|
@POST
|
||||||
|
public String registerDeviceIP(@PathParam("owner") String owner,
|
||||||
|
@PathParam("deviceId") String deviceId,
|
||||||
|
@PathParam("ip") String deviceIP,
|
||||||
|
@PathParam("port") String devicePort,
|
||||||
|
@Context HttpServletResponse response,
|
||||||
|
@Context HttpServletRequest request) {
|
||||||
|
|
||||||
|
//TODO:: Need to get IP from the request itself
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Got register call from IP: " + deviceIP + " for Device ID: " + deviceId + " of owner: " + owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
String deviceHttpEndpoint = deviceIP + ":" + devicePort;
|
||||||
|
deviceToIpMap.put(deviceId, deviceHttpEndpoint);
|
||||||
|
|
||||||
|
result = "Device-IP Registered";
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param owner
|
||||||
|
* @param deviceId
|
||||||
|
* @param protocol
|
||||||
|
* @param state
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
@Path("controller/bulb/{state}")
|
||||||
|
@POST
|
||||||
|
public void switchBulb(@HeaderParam("owner") String owner,
|
||||||
|
@HeaderParam("deviceId") String deviceId,
|
||||||
|
@HeaderParam("protocol") String protocol,
|
||||||
|
@PathParam("state") String state,
|
||||||
|
@Context HttpServletResponse response) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
DeviceValidator deviceValidator = new DeviceValidator();
|
||||||
|
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
|
||||||
|
RaspberrypiConstants.DEVICE_TYPE))) {
|
||||||
|
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
log.error("DeviceValidation Failed for deviceId: " + deviceId + " of user: " + owner);
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String switchToState = state.toUpperCase();
|
||||||
|
|
||||||
|
if (!switchToState.equals(RaspberrypiConstants.STATE_ON) && !switchToState.equals(
|
||||||
|
RaspberrypiConstants.STATE_OFF)) {
|
||||||
|
log.error("The requested state change shoud be either - 'ON' or 'OFF'");
|
||||||
|
response.setStatus(Response.Status.BAD_REQUEST.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String protocolString = protocol.toUpperCase();
|
||||||
|
String callUrlPattern = RaspberrypiConstants.BULB_CONTEXT + switchToState;
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Sending request to switch-bulb of device [" + deviceId + "] via " + protocolString);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (protocolString) {
|
||||||
|
case HTTP_PROTOCOL:
|
||||||
|
String deviceHTTPEndpoint = deviceToIpMap.get(deviceId);
|
||||||
|
if (deviceHTTPEndpoint == null) {
|
||||||
|
response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaspberrypiServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_PROTOCOL:
|
||||||
|
String mqttMessage = RaspberrypiConstants.BULB_CONTEXT.replace("/", "");
|
||||||
|
RaspberrypiServiceUtils.sendCommandViaMQTT(owner, deviceId, mqttMessage, switchToState);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " + protocolString);
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param owner
|
||||||
|
* @param deviceId
|
||||||
|
* @param protocol
|
||||||
|
* @param response
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Path("controller/readtemperature")
|
||||||
|
@GET
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public SensorRecord requestTemperature(@HeaderParam("owner") String owner,
|
||||||
|
@HeaderParam("deviceId") String deviceId,
|
||||||
|
@HeaderParam("protocol") String protocol,
|
||||||
|
@Context HttpServletResponse response) {
|
||||||
|
SensorRecord sensorRecord = null;
|
||||||
|
|
||||||
|
DeviceValidator deviceValidator = new DeviceValidator();
|
||||||
|
try {
|
||||||
|
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
|
||||||
|
RaspberrypiConstants.DEVICE_TYPE))) {
|
||||||
|
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
|
||||||
|
}
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
String protocolString = protocol.toUpperCase();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(
|
||||||
|
"Sending request to read raspberrypi-temperature of device [" + deviceId + "] via " +
|
||||||
|
protocolString);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (protocolString) {
|
||||||
|
case HTTP_PROTOCOL:
|
||||||
|
String deviceHTTPEndpoint = deviceToIpMap.get(deviceId);
|
||||||
|
if (deviceHTTPEndpoint == null) {
|
||||||
|
response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
String temperatureValue = RaspberrypiServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint,
|
||||||
|
RaspberrypiConstants
|
||||||
|
.TEMPERATURE_CONTEXT,
|
||||||
|
false);
|
||||||
|
SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE,
|
||||||
|
temperatureValue,
|
||||||
|
Calendar.getInstance().getTimeInMillis());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_PROTOCOL:
|
||||||
|
String mqttMessage = RaspberrypiConstants.BULB_CONTEXT.replace("/", "");
|
||||||
|
RaspberrypiServiceUtils.sendCommandViaMQTT(owner, deviceId, mqttMessage, "");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
|
||||||
|
}
|
||||||
|
sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId,
|
||||||
|
RaspberrypiConstants.SENSOR_TEMPERATURE);
|
||||||
|
} catch (DeviceManagementException | DeviceControllerException e) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setStatus(Response.Status.OK.getStatusCode());
|
||||||
|
return sensorRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param dataMsg
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
@Path("controller/push_temperature")
|
||||||
|
@POST
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void pushTemperatureData(final DeviceJSON dataMsg,
|
||||||
|
@Context HttpServletResponse response,
|
||||||
|
@Context HttpServletRequest request) {
|
||||||
|
String owner = dataMsg.owner;
|
||||||
|
String deviceId = dataMsg.deviceId;
|
||||||
|
String deviceIp = dataMsg.reply; //TODO:: Get IP from request
|
||||||
|
float temperature = dataMsg.value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
DeviceValidator deviceValidator = new DeviceValidator();
|
||||||
|
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
|
||||||
|
RaspberrypiConstants.DEVICE_TYPE))) {
|
||||||
|
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
|
||||||
|
log.warn("Temperature data Received from unregistered raspberrypi device [" + deviceId +
|
||||||
|
"] for owner [" + owner + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String registeredIp = deviceToIpMap.get(deviceId);
|
||||||
|
|
||||||
|
if (registeredIp == null) {
|
||||||
|
log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " + deviceIp +
|
||||||
|
" for device ID - " + deviceId);
|
||||||
|
response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode());
|
||||||
|
return;
|
||||||
|
} else if (!registeredIp.equals(deviceIp)) {
|
||||||
|
log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " + deviceId +
|
||||||
|
" is already registered under some other IP. Re-registration required");
|
||||||
|
response.setStatus(Response.Status.CONFLICT.getStatusCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Received Pin Data Value: " + temperature + " degrees C");
|
||||||
|
}
|
||||||
|
SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE,
|
||||||
|
String.valueOf(temperature),
|
||||||
|
Calendar.getInstance().getTimeInMillis());
|
||||||
|
|
||||||
|
if (!RaspberrypiServiceUtils.publishToDAS(dataMsg.owner, dataMsg.deviceId, dataMsg.value)) {
|
||||||
|
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
|
log.warn("An error occured whilst trying to publish temperature data of raspberrypi with ID [" +
|
||||||
|
deviceId + "] of owner [" + owner + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
String errorMsg = "Validation attempt for deviceId [" + deviceId + "] of owner [" + owner + "] failed.\n";
|
||||||
|
log.error(errorMsg + Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase() + "\n" + e.getErrorMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.iot.raspberrypi.service.dto;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class DeviceJSON {
|
||||||
|
@XmlElement(required = true) public String owner;
|
||||||
|
@XmlElement(required = true) public String deviceId;
|
||||||
|
@XmlElement(required = true) public String reply;
|
||||||
|
@XmlElement public Long time;
|
||||||
|
@XmlElement public String key;
|
||||||
|
@XmlElement public float value;
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.iot.raspberrypi.service.exception;
|
||||||
|
|
||||||
|
public class RaspberryPiException extends Exception {
|
||||||
|
private static final long serialVersionUID = 118512086957330189L;
|
||||||
|
|
||||||
|
public RaspberryPiException(String errorMessage) {
|
||||||
|
super(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RaspberryPiException(String errorMessage, Throwable throwable) {
|
||||||
|
super(errorMessage, throwable);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.iot.raspberrypi.service.transport;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
|
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttSubscriber;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.service.util.RaspberrypiServiceUtils;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RaspberryPiMQTTSubscriber extends MqttSubscriber {
|
||||||
|
private static Log log = LogFactory.getLog(RaspberryPiMQTTSubscriber.class);
|
||||||
|
|
||||||
|
private static final String serverName =
|
||||||
|
DeviceManagementConfigurationManager.getInstance().getDeviceManagementServerInfo().getName();
|
||||||
|
private static final String subscribeTopic =
|
||||||
|
serverName + File.separator + "+" + File.separator + RaspberrypiConstants.DEVICE_TYPE +
|
||||||
|
File.separator + "+" + File.separator + "publisher";
|
||||||
|
|
||||||
|
private static final String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5);
|
||||||
|
private String mqttEndpoint;
|
||||||
|
|
||||||
|
private RaspberryPiMQTTSubscriber() {
|
||||||
|
super(iotServerSubscriber, RaspberrypiConstants.DEVICE_TYPE,
|
||||||
|
MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initConnector() {
|
||||||
|
mqttEndpoint = MqttConfig.getInstance().getMqttQueueEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectAndSubscribe() {
|
||||||
|
try {
|
||||||
|
super.connectAndSubscribe();
|
||||||
|
} catch (DeviceManagementException e) {
|
||||||
|
log.error("Subscription to MQTT Broker at: " + mqttEndpoint + " failed");
|
||||||
|
retryMQTTSubscription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postMessageArrived(String topic, MqttMessage mqttMessage) {
|
||||||
|
String ownerAndId = topic.replace("wso2" + File.separator + "iot" + File.separator, "");
|
||||||
|
ownerAndId = ownerAndId.replace(File.separator + RaspberrypiConstants.DEVICE_TYPE + File.separator, ":");
|
||||||
|
ownerAndId = ownerAndId.replace(File.separator + "publisher", "");
|
||||||
|
|
||||||
|
String owner = ownerAndId.split(":")[0];
|
||||||
|
String deviceId = ownerAndId.split(":")[1];
|
||||||
|
String receivedMessage = mqttMessage.toString();
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Received MQTT message for: {OWNER-" + owner + "} & {DEVICE.ID-" + deviceId + "}");
|
||||||
|
log.debug("MQTT: Received Message [" + receivedMessage + "] topic: [" + topic + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receivedMessage.contains("PUBLISHER")) {
|
||||||
|
float temperature = Float.parseFloat(receivedMessage.split(":")[2]);
|
||||||
|
|
||||||
|
if (!RaspberrypiServiceUtils.publishToDAS(owner, deviceId, temperature)) {
|
||||||
|
log.error("MQTT Subscriber: Publishing data to DAS failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("MQTT Subscriber: Published data to DAS successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (receivedMessage.contains("TEMPERATURE")) {
|
||||||
|
String temperatureValue = receivedMessage.split(":")[1];
|
||||||
|
SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE,
|
||||||
|
temperatureValue,
|
||||||
|
Calendar.getInstance().getTimeInMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retryMQTTSubscription() {
|
||||||
|
Thread retryToSubscribe = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
if (!isConnected()) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Subscriber re-trying to reach MQTT queue....");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
RaspberryPiMQTTSubscriber.super.connectAndSubscribe();
|
||||||
|
} catch (DeviceManagementException e1) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Attempt to re-connect to MQTT-Queue failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e1) {
|
||||||
|
log.error("MQTT: Thread S;eep Interrupt Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
retryToSubscribe.setDaemon(true);
|
||||||
|
retryToSubscribe.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.wso2.carbon.device.mgt.iot.raspberrypi.service.util;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.concurrent.FutureCallback;
|
||||||
|
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||||
|
import org.apache.http.impl.nio.client.HttpAsyncClients;
|
||||||
|
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||||
|
import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException;
|
||||||
|
import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService;
|
||||||
|
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.DeviceController;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException;
|
||||||
|
import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants;
|
||||||
|
|
||||||
|
import javax.ws.rs.HttpMethod;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.ProtocolException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
public class RaspberrypiServiceUtils {
|
||||||
|
private static final Log log = LogFactory.getLog(RaspberrypiServiceUtils.class);
|
||||||
|
|
||||||
|
//TODO; replace this tenant domain
|
||||||
|
private static final String SUPER_TENANT = "carbon.super";
|
||||||
|
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
|
||||||
|
|
||||||
|
public static String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext,
|
||||||
|
boolean fireAndForgot) throws DeviceManagementException {
|
||||||
|
|
||||||
|
String responseMsg = "";
|
||||||
|
String urlString = RaspberrypiConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext;
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(urlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fireAndForgot) {
|
||||||
|
HttpURLConnection httpConnection = getHttpConnection(urlString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpConnection.setRequestMethod(HttpMethod.GET);
|
||||||
|
} catch (ProtocolException e) {
|
||||||
|
String errorMsg =
|
||||||
|
"Protocol specific error occurred when trying to set method to GET" +
|
||||||
|
" for:" + urlString;
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
responseMsg = readResponseFromGetRequest(httpConnection);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
CloseableHttpAsyncClient httpclient = null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
httpclient = HttpAsyncClients.createDefault();
|
||||||
|
httpclient.start();
|
||||||
|
HttpGet request = new HttpGet(urlString);
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
Future<HttpResponse> future = httpclient.execute(
|
||||||
|
request, new FutureCallback<HttpResponse>() {
|
||||||
|
@Override
|
||||||
|
public void completed(HttpResponse httpResponse) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Exception e) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelled() {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Sync Interrupted");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (httpclient != null) {
|
||||||
|
httpclient.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Failed on close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean sendCommandViaMQTT(String deviceOwner, String deviceId, String resource,
|
||||||
|
String state) throws DeviceManagementException {
|
||||||
|
|
||||||
|
boolean result;
|
||||||
|
DeviceController deviceController = new DeviceController();
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = deviceController.publishMqttControl(deviceOwner, RaspberrypiConstants.DEVICE_TYPE, deviceId, resource, state);
|
||||||
|
} catch (DeviceControllerException e) {
|
||||||
|
String errorMsg = "Error whilst trying to publish to MQTT Queue";
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------
|
||||||
|
Utility methods relevant to creating and sending http requests
|
||||||
|
--------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* This methods creates and returns a http connection object */
|
||||||
|
|
||||||
|
public static HttpURLConnection getHttpConnection(String urlString) throws
|
||||||
|
DeviceManagementException {
|
||||||
|
|
||||||
|
URL connectionUrl = null;
|
||||||
|
HttpURLConnection httpConnection;
|
||||||
|
|
||||||
|
try {
|
||||||
|
connectionUrl = new URL(urlString);
|
||||||
|
httpConnection = (HttpURLConnection) connectionUrl.openConnection();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
String errorMsg =
|
||||||
|
"Error occured whilst trying to form HTTP-URL from string: " + urlString;
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
String errorMsg = "Error occured whilst trying to open a connection to: " +
|
||||||
|
connectionUrl.toString();
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This methods reads and returns the response from the connection */
|
||||||
|
|
||||||
|
public static String readResponseFromGetRequest(HttpURLConnection httpConnection)
|
||||||
|
throws DeviceManagementException {
|
||||||
|
BufferedReader bufferedReader;
|
||||||
|
try {
|
||||||
|
bufferedReader = new BufferedReader(new InputStreamReader(
|
||||||
|
httpConnection.getInputStream()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
String errorMsg =
|
||||||
|
"There is an issue with connecting the reader to the input stream at: " +
|
||||||
|
httpConnection.getURL();
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseLine;
|
||||||
|
StringBuilder completeResponse = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ((responseLine = bufferedReader.readLine()) != null) {
|
||||||
|
completeResponse.append(responseLine);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
String errorMsg =
|
||||||
|
"Error occured whilst trying read from the connection stream at: " +
|
||||||
|
httpConnection.getURL();
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new DeviceManagementException(errorMsg, e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bufferedReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(
|
||||||
|
"Could not succesfully close the bufferedReader to the connection at: " +
|
||||||
|
httpConnection.getURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
return completeResponse.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean publishToDAS(String owner, String deviceId, float temperature) {
|
||||||
|
PrivilegedCarbonContext.startTenantFlow();
|
||||||
|
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
|
||||||
|
ctx.setTenantDomain(SUPER_TENANT, true);
|
||||||
|
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService(
|
||||||
|
DeviceAnalyticsService.class, null);
|
||||||
|
Object metdaData[] = {owner, RaspberrypiConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()};
|
||||||
|
Object payloadData[] = {temperature};
|
||||||
|
|
||||||
|
try {
|
||||||
|
deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData, new Object[0], payloadData);
|
||||||
|
} catch (DataPublisherConfigurationException e) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
PrivilegedCarbonContext.endTenantFlow();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
|
||||||
|
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="RaspberryPi" address="/">
|
||||||
|
<jaxrs:serviceBeans>
|
||||||
|
<bean id="RaspberryPiService"
|
||||||
|
class="org.wso2.carbon.device.mgt.iot.raspberrypi.service.RaspberryPiService">
|
||||||
|
<property name="raspberryPiMQTTSubscriber" ref="mqttSubscriberBean"/>
|
||||||
|
</bean>
|
||||||
|
</jaxrs:serviceBeans>
|
||||||
|
<jaxrs:providers>
|
||||||
|
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
|
||||||
|
</jaxrs:providers>
|
||||||
|
</jaxrs:server>
|
||||||
|
|
||||||
|
<bean id="mqttSubscriberBean"
|
||||||
|
class="org.wso2.carbon.device.mgt.iot.raspberrypi.service.transport.RaspberryPiMQTTSubscriber">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
||||||
|
|
@ -0,0 +1,70 @@
|
|||||||
|
<?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>RaspberryPi</display-name>
|
||||||
|
<description>RaspberryPi</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>false</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>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-name</param-name>
|
||||||
|
<param-value>raspberrypi</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-endpoint</param-name>
|
||||||
|
<param-value>http://localhost:9763/raspberrypi</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-version</param-name>
|
||||||
|
<param-value>1.0.0</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-context</param-name>
|
||||||
|
<param-value>/raspberrypi</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-context-template</param-name>
|
||||||
|
<param-value>/raspberrypi/{version}</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-application</param-name>
|
||||||
|
<param-value>raspberrypi</param-value>
|
||||||
|
</context-param>
|
||||||
|
<context-param>
|
||||||
|
<param-name>managed-api-isSecured</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</context-param>
|
||||||
|
|
||||||
|
|
||||||
|
</web-app>
|
@ -0,0 +1,17 @@
|
|||||||
|
Install Rpi.GPIO
|
||||||
|
Install sh
|
||||||
|
sudo easy_install pip
|
||||||
|
sudo pip install sh
|
||||||
|
|
||||||
|
|
||||||
|
wget http://67.192.60.197/mikem/bcm2835/bcm2835-1.8.tar.gz
|
||||||
|
tar xvfz bcm2835-1.8.tar.gz;
|
||||||
|
cd bcm2835-1.8;
|
||||||
|
./configure;
|
||||||
|
make;
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install python-dev
|
||||||
|
|
||||||
|
nohup command >/dev/null 2>&1 &
|
@ -0,0 +1,14 @@
|
|||||||
|
[Device-Configurations]
|
||||||
|
owner=${DEVICE_OWNER}
|
||||||
|
deviceId=${DEVICE_ID}
|
||||||
|
device-name=${DEVICE_NAME}
|
||||||
|
controller-context=/RaspberryPiDeviceManager/raspberrypi/controller
|
||||||
|
https-ep=${HTTPS_EP}
|
||||||
|
http-ep=${HTTP_EP}
|
||||||
|
apim-ep=${APIM_EP}
|
||||||
|
mqtt-ep=${MQTT_EP}
|
||||||
|
xmpp-ep=${XMPP_EP}
|
||||||
|
auth-method=token
|
||||||
|
auth-token=${DEVICE_TOKEN}
|
||||||
|
refresh-token=${DEVICE_REFRESH_TOKEN}
|
||||||
|
push-interval=15
|
Binary file not shown.
@ -0,0 +1,332 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import logging, logging.handlers
|
||||||
|
import sys, os, signal, argparse
|
||||||
|
import httplib, time
|
||||||
|
import threading
|
||||||
|
import Adafruit_DHT # Adafruit library required for temperature sensing
|
||||||
|
|
||||||
|
import iotUtils
|
||||||
|
import httpServer # python script used to start a http-server to listen for operations (includes the TEMPERATURE global variable)
|
||||||
|
import xmppServer # python script used to communicate with xmpp server
|
||||||
|
import mqttListener # python script used to accept messages via mqtt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PUSH_INTERVAL = 300 # time interval between successive data pushes in seconds
|
||||||
|
logging_enabled = False
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Endpoint specific settings to which the data is pushed
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
DC_IP = '204.232.188.214' #'192.168.57.128'
|
||||||
|
DC_PORT = 8281
|
||||||
|
HOST = DC_IP + ':' + `DC_PORT`
|
||||||
|
|
||||||
|
DC_ENDPOINT = '/firealarm/1.0/controller' #'/firealarm/1.0/'
|
||||||
|
PUSH_ENDPOINT = DC_ENDPOINT + '/push_temperature'
|
||||||
|
REGISTER_ENDPOINT = DC_ENDPOINT + '/register'
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Logger defaults
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
LOG_FILENAME = "/usr/local/src/RaspberryAgent/logs/RaspberryStats.log"
|
||||||
|
LOG_LEVEL = logging.INFO # Could be e.g. "DEBUG" or "WARNING"
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Define and parse command line arguments
|
||||||
|
# If the log file is specified on the command line then override the default
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
parser = argparse.ArgumentParser(description="Python service to push RPi info to the Device Cloud")
|
||||||
|
parser.add_argument("-l", "--log", help="file to write log to (default '" + LOG_FILENAME + "')")
|
||||||
|
|
||||||
|
help_string = "time interval between successive data pushes (default '" + str(PUSH_INTERVAL) + "')"
|
||||||
|
parser.add_argument("-i", "--interval", type=int, help=help_string)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.log:
|
||||||
|
LOG_FILENAME = args.log
|
||||||
|
|
||||||
|
if args.interval:
|
||||||
|
PUSH_INTERVAL = args.interval
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# 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 registers the DevieIP in the Device-Cloud
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def registerDeviceIP():
|
||||||
|
dcConncection = httplib.HTTPConnection(DC_IP, DC_PORT)
|
||||||
|
dcConncection.set_debuglevel(1)
|
||||||
|
dcConncection.connect()
|
||||||
|
|
||||||
|
registerURL = REGISTER_ENDPOINT + '/' + iotUtils.DEVICE_OWNER + '/' + iotUtils.DEVICE_ID + '/' + iotUtils.HOST_NAME
|
||||||
|
|
||||||
|
dcConncection.putrequest('POST', registerURL)
|
||||||
|
dcConncection.putheader('Authorization', 'Bearer ' + iotUtils.AUTH_TOKEN)
|
||||||
|
dcConncection.endheaders()
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~ Device Registration ~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
dcResponse = dcConncection.getresponse()
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
print ('RASPBERRY_STATS: ' + str(registerURL))
|
||||||
|
print ('RASPBERRY_STATS: ' + str(dcResponse.status))
|
||||||
|
print ('RASPBERRY_STATS: ' + str(dcResponse.reason))
|
||||||
|
print ('RASPBERRY_STATS: Response Message')
|
||||||
|
print str(dcResponse.msg)
|
||||||
|
|
||||||
|
dcConncection.close()
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This method connects to the Device-Cloud and pushes data
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def connectAndPushData():
|
||||||
|
dcConnection = httplib.HTTPConnection(DC_IP, DC_PORT)
|
||||||
|
dcConnection.set_debuglevel(1)
|
||||||
|
|
||||||
|
dcConnection.connect()
|
||||||
|
|
||||||
|
request = dcConnection.putrequest('POST', PUSH_ENDPOINT)
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
headers['Authorization'] = 'Bearer ' + iotUtils.AUTH_TOKEN
|
||||||
|
headers['Content-Type'] = 'application/json'
|
||||||
|
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
### Read the Temperature and Load info of RPi and construct payload
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
# rPiTemperature=getCPUTemp() # Can be used if required to push CPU Temperature
|
||||||
|
# rPiLoad = getCPULoad() # Can be used if required to push CPU Load
|
||||||
|
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
rPiTemperature = iotUtils.LAST_TEMP # Push the last read temperature value
|
||||||
|
PUSH_DATA = iotUtils.DEVICE_INFO + iotUtils.DEVICE_IP.format(ip=iotUtils.HOST_NAME) + iotUtils.DEVICE_DATA.format(temperature=rPiTemperature)
|
||||||
|
PUSH_DATA += '}'
|
||||||
|
|
||||||
|
# print PUSH_DATA
|
||||||
|
|
||||||
|
headers['Content-Length'] = len(PUSH_DATA)
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
|
||||||
|
for k in headers:
|
||||||
|
dcConnection.putheader(k, headers[k])
|
||||||
|
dcConnection.endheaders()
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~ Pushing Device-Data ~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
|
||||||
|
dcConnection.send(PUSH_DATA) # Push the data
|
||||||
|
dcResponse = dcConnection.getresponse()
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
print ('RASPBERRY_STATS: ' + str(dcResponse.status))
|
||||||
|
print ('RASPBERRY_STATS: ' + str(dcResponse.reason))
|
||||||
|
print ('RASPBERRY_STATS: Response Message')
|
||||||
|
print str(dcResponse.msg)
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
dcConnection.close()
|
||||||
|
|
||||||
|
if (dcResponse.status == 409 or dcResponse.status == 412):
|
||||||
|
print 'RASPBERRY_STATS: Re-registering Device IP'
|
||||||
|
registerDeviceIP()
|
||||||
|
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This is a Thread object for reading temperature continuously
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
class TemperatureReaderThread(object):
|
||||||
|
def __init__(self, interval=3):
|
||||||
|
self.interval = interval
|
||||||
|
|
||||||
|
thread = threading.Thread(target=self.run, args=())
|
||||||
|
thread.daemon = True # Daemonize thread
|
||||||
|
thread.start() # Start the execution
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
TEMP_PIN = 4
|
||||||
|
TEMP_SENSOR_TYPE = 11
|
||||||
|
|
||||||
|
# Try to grab a sensor reading. Use the read_retry method which will retry up
|
||||||
|
# to 15 times to get a sensor reading (waiting 2 seconds between each retry).
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
humidity, temperature = Adafruit_DHT.read_retry(TEMP_SENSOR_TYPE, TEMP_PIN)
|
||||||
|
|
||||||
|
if temperature != iotUtils.LAST_TEMP:
|
||||||
|
iotUtils.LAST_TEMP = temperature
|
||||||
|
connectAndPushData()
|
||||||
|
|
||||||
|
iotUtils.LAST_TEMP = temperature
|
||||||
|
print 'RASPBERRY_STATS: Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temperature, humidity)
|
||||||
|
|
||||||
|
except Exception, e:
|
||||||
|
print "RASPBERRY_STATS: Exception in TempReaderThread: Could not successfully read Temperature"
|
||||||
|
print ("RASPBERRY_STATS: " + str(e))
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
pass
|
||||||
|
|
||||||
|
time.sleep(self.interval)
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This is a Thread object for listening for MQTT Messages
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
class UtilsThread(object):
|
||||||
|
def __init__(self):
|
||||||
|
thread = threading.Thread(target=self.run, args=())
|
||||||
|
thread.daemon = True # Daemonize thread
|
||||||
|
thread.start() # Start the execution
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
iotUtils.main()
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This is a Thread object for HTTP-Server that listens for operations on RPi
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
class ListenHTTPServerThread(object):
|
||||||
|
def __init__(self):
|
||||||
|
thread = threading.Thread(target=self.run, args=())
|
||||||
|
thread.daemon = True # Daemonize thread
|
||||||
|
thread.start() # Start the execution
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
httpServer.main()
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This is a Thread object for Server that listens for XMPP Messages
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
class ListenXMPPServerThread(object):
|
||||||
|
def __init__(self):
|
||||||
|
thread = threading.Thread(target=self.run, args=())
|
||||||
|
thread.daemon = True # Daemonize thread
|
||||||
|
thread.start() # Start the execution
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
xmppServer.main()
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# 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):
|
||||||
|
mqttListener.main()
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# The Main method of the RPi Agent
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def main():
|
||||||
|
configureLogger("WSO2IOT_RPiStats")
|
||||||
|
# iotUtils.setUpGPIOPins()
|
||||||
|
|
||||||
|
UtilsThread()
|
||||||
|
registerDeviceIP() # Call the register endpoint and register Device IP
|
||||||
|
TemperatureReaderThread() # initiates and runs the thread to continuously read temperature from DHT Sensor
|
||||||
|
ListenHTTPServerThread() # starts an HTTP Server that listens for operational commands to switch ON/OFF Led
|
||||||
|
ListenXMPPServerThread()
|
||||||
|
ListenMQTTThread()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if iotUtils.LAST_TEMP > 0: # Push data only if there had been a successful temperature read
|
||||||
|
connectAndPushData() # Push Sensor (Temperature) data to WSO2 BAM
|
||||||
|
time.sleep(PUSH_INTERVAL)
|
||||||
|
except (KeyboardInterrupt, Exception) as e:
|
||||||
|
print "RASPBERRY_STATS: Exception in RaspberryAgentThread (either KeyboardInterrupt or Other)"
|
||||||
|
print ("RASPBERRY_STATS: " + str(e))
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
pass
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
"""
|
||||||
|
|
||||||
|
piMac=`/sbin/ifconfig | grep 'wlan0' | tr -s ' ' | cut -d ' ' -f5 | tr -d ':'`
|
||||||
|
echo The device ID is $piMac
|
@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import BaseHTTPServer
|
||||||
|
import iotUtils
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# HOST and PORT info of the HTTP Server that gets started
|
||||||
|
# HOST_NAME is initialised in the main() method
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
#global HOST_NAME
|
||||||
|
#HOST_NAME = "0.0.0.0"
|
||||||
|
|
||||||
|
SERVER_PORT = 80 # Maybe set this to 9000.
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Class that handles HTTP GET requests for operations on the RPi
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
def do_GET(request):
|
||||||
|
# """Respond to a GET request."""
|
||||||
|
|
||||||
|
if not processURLPath(request.path):
|
||||||
|
return
|
||||||
|
|
||||||
|
resource = request.path.split("/")[1].upper()
|
||||||
|
state = request.path.split("/")[2].upper()
|
||||||
|
print "HTTP_SERVER: Resource - " + resource
|
||||||
|
|
||||||
|
if resource == "TEMP":
|
||||||
|
request.send_response(200)
|
||||||
|
request.send_header("Content-type", "text/plain")
|
||||||
|
request.end_headers()
|
||||||
|
request.wfile.write(iotUtils.LAST_TEMP)
|
||||||
|
|
||||||
|
elif resource == "BULB":
|
||||||
|
iotUtils.switchBulb(state)
|
||||||
|
print "HTTP_SERVER: Requested Switch State - " + state
|
||||||
|
|
||||||
|
elif resource == "SONAR":
|
||||||
|
request.send_response(200)
|
||||||
|
request.send_header("Content-type", "text/plain")
|
||||||
|
request.end_headers()
|
||||||
|
request.wfile.write(iotUtils.LAST_DISTANCE)
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Check the URL string of the request and validate
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def processURLPath(path):
|
||||||
|
if path.count("/") != 2 and not "favicon" in path:
|
||||||
|
print "HTTP_SERVER: Invalid URL String: " + path
|
||||||
|
return False
|
||||||
|
|
||||||
|
resource = path.split("/")[1]
|
||||||
|
|
||||||
|
if not iequal("BULB", resource) and not iequal("TEMP", resource) and not iequal("FAN", resource) and not iequal("SONAR", resource):
|
||||||
|
if not "favicon" in resource:
|
||||||
|
print "HTTP_SERVER: Invalid resource - " + resource + " to execute operation"
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Case-Insensitive check on whether two string are similar
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def iequal(a, b):
|
||||||
|
try:
|
||||||
|
return a.upper() == b.upper()
|
||||||
|
except AttributeError:
|
||||||
|
return a == b
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# The Main method of the server script
|
||||||
|
# This method is invoked from RaspberryStats.py on a new thread
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def main():
|
||||||
|
HOST_NAME = iotUtils.getDeviceIP()
|
||||||
|
server_class = BaseHTTPServer.HTTPServer
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
httpd = server_class((HOST_NAME, SERVER_PORT), MyHandler)
|
||||||
|
print "HTTP_SERVER: " + time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, SERVER_PORT)
|
||||||
|
|
||||||
|
httpd.serve_forever()
|
||||||
|
except (KeyboardInterrupt, Exception) as e:
|
||||||
|
print "HTTP_SERVER: Exception in HttpServerThread (either KeyboardInterrupt or Other)"
|
||||||
|
print ("HTTP_SERVER: " + str(e))
|
||||||
|
|
||||||
|
iotUtils.switchBulb("OFF")
|
||||||
|
httpd.server_close()
|
||||||
|
print "HTTP_SERVER: " + time.asctime(), "Server Stops - %s:%s" % (HOST_NAME, SERVER_PORT)
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,200 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time, commands
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
import ConfigParser
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# HOST_NAME(IP) of the Device
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
global HOST_NAME
|
||||||
|
HOST_NAME = "0.0.0.0"
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
global LAST_TEMP
|
||||||
|
LAST_TEMP = 25 # The Last read temperature value from the DHT sensor. Kept globally
|
||||||
|
# Updated by the temperature reading thread
|
||||||
|
|
||||||
|
global LAST_DISTANCE
|
||||||
|
LAST_DISTANCE = 100
|
||||||
|
|
||||||
|
SONAR_TRIG_PIN = 16 #Associate pin 23 to TRIG
|
||||||
|
SONAR_ECHO_PIN = 18
|
||||||
|
BULB_PIN = 11 # The GPIO Pin# in RPi to which the LED is connected
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Device specific info when pushing data to server
|
||||||
|
# Read from a file "deviceConfigs.cfg" in the same folder level
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
configParser = ConfigParser.RawConfigParser()
|
||||||
|
configFilePath = r'./deviceConfigs.cfg'
|
||||||
|
configParser.read(configFilePath)
|
||||||
|
|
||||||
|
DEVICE_OWNER = configParser.get('Device-Configurations', 'owner')
|
||||||
|
DEVICE_ID = configParser.get('Device-Configurations', 'deviceId')
|
||||||
|
MQTT_EP = configParser.get('Device-Configurations', 'mqtt-ep')
|
||||||
|
XMPP_EP = configParser.get('Device-Configurations', 'xmpp-ep')
|
||||||
|
AUTH_TOKEN = configParser.get('Device-Configurations', 'auth-token')
|
||||||
|
|
||||||
|
DEVICE_INFO = '{"owner":"'+ DEVICE_OWNER + '","deviceId":"' + DEVICE_ID + '","reply":'
|
||||||
|
DEVICE_IP = '"{ip}","value":'
|
||||||
|
DEVICE_DATA = '"{temperature}"' # '"{temperature}:{load}:OFF"'
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Method used to switch ON/OFF the LED attached to RPi
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def switchBulb(state):
|
||||||
|
print "Requested Switch State: " + state
|
||||||
|
|
||||||
|
if state == "ON":
|
||||||
|
GPIO.output(BULB_PIN, True)
|
||||||
|
print "BULB Switched ON"
|
||||||
|
elif state == "OFF":
|
||||||
|
GPIO.output(BULB_PIN, False)
|
||||||
|
print "BULB Switched OFF"
|
||||||
|
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Get the wlan0 interface via which the RPi is connected
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def getDeviceIP():
|
||||||
|
rPi_IP = commands.getoutput("ip route list | grep 'src '").split()
|
||||||
|
rPi_IP = rPi_IP[rPi_IP.index('src') + 1]
|
||||||
|
|
||||||
|
if len(rPi_IP)<=16:
|
||||||
|
print "------------------------------------------------------------------------------------"
|
||||||
|
print "IOT_UTILS: IP Address of RaspberryPi: " + rPi_IP
|
||||||
|
print "------------------------------------------------------------------------------------"
|
||||||
|
return rPi_IP
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Set the GPIO pin modes for the ones to be read
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def setUpGPIOPins():
|
||||||
|
try:
|
||||||
|
GPIO.setwarnings(False)
|
||||||
|
GPIO.setmode(GPIO.BOARD)
|
||||||
|
except Exception as e:
|
||||||
|
print "IOT_UTILS: Exception at 'GPIO.setmode'"
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
pass
|
||||||
|
|
||||||
|
GPIO.setup(SONAR_TRIG_PIN,GPIO.OUT) #Set pin as GPIO out
|
||||||
|
GPIO.setup(SONAR_ECHO_PIN,GPIO.IN) #Set pin as GPIO in
|
||||||
|
GPIO.setup(BULB_PIN, GPIO.OUT)
|
||||||
|
GPIO.output(BULB_PIN, False)
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This method get the CPU Temperature of the Raspberry Pi
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def getCPUTemp():
|
||||||
|
CPU_TEMP_LOC = "/sys/class/thermal/thermal_zone0/temp" # RaspberryPi file location to get CPU TEMP info
|
||||||
|
tempFile = open(CPU_TEMP_LOC)
|
||||||
|
cpuTemp = tempFile.read()
|
||||||
|
cpuTemp = long(float(cpuTemp))
|
||||||
|
cpuTemp = cpuTemp * 1.0 / 1000.0
|
||||||
|
print "The CPU temperature is: %.2f" % cpuTemp
|
||||||
|
return cpuTemp
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# This method get the CPU Load of the Raspberry Pi
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def getCPULoad():
|
||||||
|
CPU_LOAD_LOC = "/proc/loadavg" # RaspberryPi file location to get CPU LOAD info
|
||||||
|
loadFile = open(CPU_LOAD_LOC)
|
||||||
|
cpuLoad = loadFile.read()
|
||||||
|
cpuLoad = cpuLoad.split()[0]
|
||||||
|
cpuLoad = long(float(cpuLoad))
|
||||||
|
print "The CPU temperature is: %.2f" % cpuLoad
|
||||||
|
return cpuLoad
|
||||||
|
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
def readSonarDistance():
|
||||||
|
global LAST_DISTANCE
|
||||||
|
try:
|
||||||
|
GPIO.output(SONAR_TRIG_PIN, False) #Set TRIG as LOW
|
||||||
|
print "IOT_UTILS: Waitng For Sonar Sensor To Settle"
|
||||||
|
time.sleep(0.5) #Delay of 2 seconds
|
||||||
|
|
||||||
|
GPIO.output(SONAR_TRIG_PIN, True) #Set TRIG as HIGH
|
||||||
|
time.sleep(0.00001) #Delay of 0.00001 seconds
|
||||||
|
GPIO.output(SONAR_TRIG_PIN, False) #Set TRIG as LOW
|
||||||
|
|
||||||
|
while GPIO.input(SONAR_ECHO_PIN)==0: #Check whether the ECHO is LOW
|
||||||
|
pulse_start = time.time() #Saves the last known time of LOW pulse
|
||||||
|
|
||||||
|
while GPIO.input(SONAR_ECHO_PIN)==1: #Check whether the ECHO is HIGH
|
||||||
|
pulse_end = time.time() #Saves the last known time of HIGH pulse
|
||||||
|
|
||||||
|
pulse_duration = pulse_end - pulse_start #Get pulse duration to a variable
|
||||||
|
|
||||||
|
distance = pulse_duration * 17150 #Multiply pulse duration by 17150 to get distance
|
||||||
|
distance = round(distance, 2) #Round to two decimal points
|
||||||
|
|
||||||
|
if distance > 2 and distance < 400: #Check whether the distance is within range
|
||||||
|
print "IOT_UTILS: Distance: ", distance - 0.5,"cm" #Print distance with 0.5 cm calibration
|
||||||
|
LAST_DISTANCE = distance
|
||||||
|
else:
|
||||||
|
print "IOT_UTILS: Out Of Range" #display out of range
|
||||||
|
|
||||||
|
except Exception, e:
|
||||||
|
print "IOT_UTILS: Exception in SonarReaderThread: Could not successfully read Sonar"
|
||||||
|
print ("IOT_UTILS: " + str(e))
|
||||||
|
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# The Main method of the server script
|
||||||
|
# This method is invoked from RaspberryStats.py on a new thread
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def main():
|
||||||
|
global HOST_NAME
|
||||||
|
HOST_NAME = getDeviceIP()
|
||||||
|
setUpGPIOPins()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
readSonarDistance()
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,109 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import iotUtils
|
||||||
|
#import RPi.GPIO as GPIO
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
|
|
||||||
|
# The callback for when the client receives a CONNACK response from the server.
|
||||||
|
def on_connect(client, 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)
|
||||||
|
client.subscribe(TOPIC)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# The callback for when a PUBLISH message is received from the server.
|
||||||
|
def on_message(client, userdata, msg):
|
||||||
|
print( "MQTT_LISTENER: " + msg.topic + " " + str(msg.payload) )
|
||||||
|
|
||||||
|
request = str(msg.payload)
|
||||||
|
|
||||||
|
resource = request.split(":")[0].upper()
|
||||||
|
state = request.split(":")[1].upper()
|
||||||
|
|
||||||
|
print "MQTT_LISTENER: Resource- " + resource
|
||||||
|
|
||||||
|
if resource == "TEMP":
|
||||||
|
pass
|
||||||
|
#request.send_response(200)
|
||||||
|
#request.send_header("Content-type", "text/plain")
|
||||||
|
#request.end_headers()
|
||||||
|
#request.wfile.write(LAST_TEMP)
|
||||||
|
# return
|
||||||
|
|
||||||
|
elif resource == "BULB":
|
||||||
|
iotUtils.switchBulb(state)
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# The Main method of the server script
|
||||||
|
# This method is invoked from RaspberryStats.py on a new thread
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
def main():
|
||||||
|
|
||||||
|
MQTT_ENDPOINT = iotUtils.MQTT_EP.split(":")
|
||||||
|
MQTT_IP = MQTT_ENDPOINT[0]
|
||||||
|
MQTT_PORT = MQTT_ENDPOINT[1]
|
||||||
|
|
||||||
|
DEV_OWNER = iotUtils.DEVICE_OWNER
|
||||||
|
DEV_ID = iotUtils.DEVICE_ID
|
||||||
|
|
||||||
|
global TOPIC
|
||||||
|
TOPIC = "wso2/iot/" + DEV_OWNER + "/firealarm/" + DEV_ID
|
||||||
|
|
||||||
|
print ("MQTT_LISTENER: MQTT_ENDPOINT is " + str(MQTT_ENDPOINT))
|
||||||
|
print ("MQTT_LISTENER: MQTT_TOPIC is " + TOPIC)
|
||||||
|
|
||||||
|
mqttClient = mqtt.Client()
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Blocking call that processes network traffic, dispatches callbacks and
|
||||||
|
# handles reconnecting.
|
||||||
|
# Other loop*() functions are available that give a threaded interface and a
|
||||||
|
# manual interface.
|
||||||
|
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__':
|
||||||
|
iotUtils.setUpGPIOPins()
|
||||||
|
main()
|
||||||
|
|
Binary file not shown.
@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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.
|
||||||
|
*/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
import getpass
|
||||||
|
import sys
|
||||||
|
import ssl, pyasn1
|
||||||
|
|
||||||
|
from urllib import urlopen
|
||||||
|
import iotUtils
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||||
|
setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0323.device import Device
|
||||||
|
|
||||||
|
class IoT_TestDevice(sleekxmpp.ClientXMPP):
|
||||||
|
"""
|
||||||
|
A simple IoT device that can act as server or client
|
||||||
|
"""
|
||||||
|
def __init__(self, jid, password):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
self.add_event_handler("session_start", self.session_start)
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
self.device=None
|
||||||
|
self.releaseMe=False
|
||||||
|
self.beServer=True
|
||||||
|
|
||||||
|
def beClientOrServer(self,server=True,clientJID=None ):
|
||||||
|
self.beServer=True
|
||||||
|
|
||||||
|
def testForRelease(self):
|
||||||
|
# todo thread safe
|
||||||
|
return self.releaseMe
|
||||||
|
|
||||||
|
def doReleaseMe(self):
|
||||||
|
# todo thread safe
|
||||||
|
self.releaseMe=True
|
||||||
|
|
||||||
|
def addDevice(self, device):
|
||||||
|
self.device=device
|
||||||
|
|
||||||
|
def session_start(self, event):
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
# tell your preffered friend that you are alive
|
||||||
|
#self.send_message(mto='jocke@jabber.sust.se', mbody=self.boundjid.bare +' is now online use xep_323 stanza to talk to me')
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
if msg['type'] in ('chat', 'normal'):
|
||||||
|
print ("XMPP_SERVER: Got normal chat message" + str(msg))
|
||||||
|
ip = urlopen('http://icanhazip.com').read()
|
||||||
|
msg.reply("XMPP_SERVER: Hi I am " + self.boundjid.full + " and I am on IP " + ip).send()
|
||||||
|
else:
|
||||||
|
print ("XMPP_SERVER: Got unknown message type %s", str(msg['type']))
|
||||||
|
|
||||||
|
class TheDevice(Device):
|
||||||
|
"""
|
||||||
|
This is the actual device object that you will use to get information from your real hardware
|
||||||
|
You will be called in the refresh method when someone is requesting information from you
|
||||||
|
"""
|
||||||
|
def __init__(self,nodeId):
|
||||||
|
Device.__init__(self,nodeId)
|
||||||
|
|
||||||
|
def refresh(self,fields):
|
||||||
|
"""
|
||||||
|
the implementation of the refresh method
|
||||||
|
"""
|
||||||
|
# global LAST_TEMP
|
||||||
|
#self._set_momentary_timestamp(self._get_timestamp())
|
||||||
|
#self._add_field_momentary_data(self, "Temperature", self.counter)
|
||||||
|
|
||||||
|
self._add_field(name="Temperature", typename="numeric", unit="C")
|
||||||
|
self._set_momentary_timestamp(self._get_timestamp())
|
||||||
|
self._add_field_momentary_data("Temperature", str(iotUtils.LAST_TEMP), flags={"automaticReadout": "true"})
|
||||||
|
|
||||||
|
def main():
|
||||||
|
XMPP_ENDP = iotUtils.XMPP_EP.split(":")[0]
|
||||||
|
|
||||||
|
XMPP_OWN = iotUtils.DEVICE_OWNER
|
||||||
|
XMPP_JID = iotUtils.DEVICE_ID + "@" + XMPP_ENDP + "/raspi"
|
||||||
|
XMPP_PWD = iotUtils.AUTH_TOKEN
|
||||||
|
|
||||||
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||||
|
print "XMPP_SERVER: Owner - " + XMPP_OWN
|
||||||
|
print "XMPP_SERVER: AccountID - " + XMPP_JID
|
||||||
|
print "XMPP_SERVER: AccountPass - " + XMPP_PWD
|
||||||
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||||
|
|
||||||
|
xmpp = IoT_TestDevice(XMPP_JID,XMPP_PWD)
|
||||||
|
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||||
|
|
||||||
|
xmpp.register_plugin('xep_0030')
|
||||||
|
xmpp.register_plugin('xep_0323')
|
||||||
|
xmpp.register_plugin('xep_0325')
|
||||||
|
|
||||||
|
if XMPP_OWN:
|
||||||
|
# xmpp['xep_0030'].add_feature(feature='urn:xmpp:sn',
|
||||||
|
# node=opts.nodeid,
|
||||||
|
# jid=xmpp.boundjid.full)
|
||||||
|
|
||||||
|
myDevice = TheDevice(XMPP_OWN)
|
||||||
|
# myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
|
||||||
|
myDevice._add_field(name="Temperature", typename="numeric", unit="C")
|
||||||
|
myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
|
||||||
|
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
|
||||||
|
|
||||||
|
xmpp['xep_0323'].register_node(nodeId=XMPP_OWN, device=myDevice, commTimeout=10)
|
||||||
|
xmpp.beClientOrServer(server=True)
|
||||||
|
|
||||||
|
while not(xmpp.testForRelease()):
|
||||||
|
try:
|
||||||
|
xmpp.connect()
|
||||||
|
xmpp.process(block=True)
|
||||||
|
print ("XMPP_SERVER: Lost Connection")
|
||||||
|
except Exception as e:
|
||||||
|
print "XMPP_SERVER: Exception in XMPPServerThread (either KeyboardInterrupt or Other)"
|
||||||
|
print ("XMPP_SERVER: " + str(e))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "----------------------------------------------------------------"
|
||||||
|
echo "| WSO2 IOT Sample "
|
||||||
|
echo "| RaspiAlarm "
|
||||||
|
echo "| ---------------- "
|
||||||
|
echo "| ....initializing startup-script "
|
||||||
|
echo "----------------------------------------------------------------"
|
||||||
|
|
||||||
|
currentDir=$PWD
|
||||||
|
|
||||||
|
cd /var/lib/dpkg/info
|
||||||
|
sudo rm -rf wso2-raspi-alarm*
|
||||||
|
dpkg --remove --force-remove-reinstreq wso2-raspi-alarm
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "apt-get update failed.... Some dependencies may not get installed"
|
||||||
|
echo "If an already installed version of the package exists, try running:"
|
||||||
|
echo "----------------------------------------------------------------"
|
||||||
|
echo "sudo -i"
|
||||||
|
echo "cd /var/lib/dpkg/info"
|
||||||
|
echo "rm -rf wso2-raspi-alarm*"
|
||||||
|
echo "dpkg --remove --force-remove-reinstreq wso2-raspi-alarm"
|
||||||
|
echo "exit"
|
||||||
|
echo "----------------------------------------------------------------"
|
||||||
|
echo "Retry Installation...."
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
for f in ./deviceConfigs.cfg; 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.
|
||||||
|
# [ -e "$f" ] && echo "'wso2-raspi-alarm_1.0_armhf.deb' file found and installing" || echo "'wso2-raspi-alarm_1.0_armhf.deb' file does not exist in current path"; exit;
|
||||||
|
if [ -e "$f" ]; then
|
||||||
|
echo "Configuration file found......"
|
||||||
|
else
|
||||||
|
echo "'deviceConfigs.cfg' 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
|
||||||
|
|
||||||
|
cd $currentDir
|
||||||
|
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 $currentDir
|
||||||
|
|
||||||
|
#sudo apt-get install python-pip
|
||||||
|
sudo pip install sleekxmpp
|
||||||
|
sudo pip install pyasn1 pyasn1-modules
|
||||||
|
|
||||||
|
|
||||||
|
echo "Running the RaspberryAgent service...."
|
||||||
|
# sudo service RaspberryService.sh start
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Whats the time-interval (in seconds) between successive Data-Pushes to the WSO2-DC (ex: '60' indicates 1 minute) > " input
|
||||||
|
|
||||||
|
if [ $input -eq $input 2>/dev/null ]
|
||||||
|
then
|
||||||
|
echo "Setting data-push interval to $input seconds."
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
echo "Input needs to be an integer indicating the number seconds between successive data-pushes."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo nohup ./RaspberryStats.py -i $input > /dev/null 2>&1 &
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not start the service..."
|
||||||
|
exit;
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "--------------------------------------------------------------------------"
|
||||||
|
echo "| Successfully Started "
|
||||||
|
echo "---------------------------------------------------------------------------"
|
Loading…
Reference in new issue