forked from community/device-mgt-plugins
Merge branch 'IoTS-1.0.0-M1' of https://github.com/wso2/carbon-device-mgt-plugins into IoTS-1.0.0-M1
Conflicts: components/device-mgt-iot-virtualfirealarm/org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/service/VirtualFireAlarmService.java
commit
eb3a5c7254
@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.droneanalyzer.service.transport;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.jivesoftware.smack.*;
|
|
||||||
import org.jivesoftware.smack.filter.AndFilter;
|
|
||||||
import org.jivesoftware.smack.filter.PacketFilter;
|
|
||||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
|
||||||
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
|
|
||||||
import org.wso2.carbon.device.mgt.iot.droneanalyzer.service.trasformer.MessageTransformer;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by geesara on 12/7/15.
|
|
||||||
*/
|
|
||||||
public class DroneXMPPConnector {
|
|
||||||
|
|
||||||
private static Log log = LogFactory.getLog(DroneXMPPConnector.class);
|
|
||||||
|
|
||||||
// XmppManager xmppManager;
|
|
||||||
|
|
||||||
private MessageTransformer messageController;
|
|
||||||
private static String xmppServerIP;
|
|
||||||
private static int xmppServerPort;
|
|
||||||
private static String xmppAdminUsername;
|
|
||||||
private static String xmppAdminPassword;
|
|
||||||
private static String xmppAdminAccountJID;
|
|
||||||
|
|
||||||
public DroneXMPPConnector(MessageTransformer messageController) {
|
|
||||||
this.messageController = messageController;
|
|
||||||
initConnector();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void initConnector() {
|
|
||||||
/* xmppServerIP = XmppConfig.getInstance().getXmppServerIP();
|
|
||||||
xmppAdminUsername = XmppConfig.getInstance().getXmppUsername();
|
|
||||||
xmppAdminPassword = XmppConfig.getInstance().getXmppPassword();
|
|
||||||
xmppAdminAccountJID = xmppAdminUsername + "@" + xmppServerIP;*/
|
|
||||||
xmppServerPort = 5222;
|
|
||||||
xmppServerIP = "localhost";
|
|
||||||
xmppAdminUsername = "admin";
|
|
||||||
xmppAdminPassword = "admin";
|
|
||||||
xmppAdminAccountJID = xmppAdminUsername + "@" + xmppServerIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*public void connectAndLogin() {
|
|
||||||
try {
|
|
||||||
super.connectAndLogin(xmppAdminUsername, xmppAdminPassword, null);
|
|
||||||
super.setMessageFilterOnReceiver(xmppAdminAccountJID);
|
|
||||||
} catch (DeviceManagementException e) {
|
|
||||||
log.error("Connect/Login attempt to XMPP Server at: " + xmppServerIP + " failed");
|
|
||||||
retryXMPPConnection();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private XMPPConnection xmppConnection;
|
|
||||||
|
|
||||||
public void connect(String server, int port) throws Exception {
|
|
||||||
if(xmppConnection == null){
|
|
||||||
xmppConnection = new XMPPConnection(new ConnectionConfiguration(server, port));
|
|
||||||
xmppConnection.connect();
|
|
||||||
}else{
|
|
||||||
System.out.println("Already user is connected");
|
|
||||||
}
|
|
||||||
/*xmppConnection = new XMPPConnection(new ConnectionConfiguration(server, port));
|
|
||||||
xmppConnection.connect();*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnect(){
|
|
||||||
if(xmppConnection != null){
|
|
||||||
xmppConnection.disconnect();
|
|
||||||
//interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void login(String username, String password) throws Exception{
|
|
||||||
printRoster();
|
|
||||||
connect( xmppServerIP, xmppServerPort);
|
|
||||||
xmppConnection.login(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run(){
|
|
||||||
try {
|
|
||||||
System.out.println(xmppAdminAccountJID+xmppAdminPassword);
|
|
||||||
login(xmppAdminAccountJID, xmppAdminPassword);
|
|
||||||
System.out.println("Login successful");
|
|
||||||
listeningForMessages();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void listeningForMessages() {
|
|
||||||
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class));
|
|
||||||
PacketCollector collector = xmppConnection.createPacketCollector(filter);
|
|
||||||
while (true) {
|
|
||||||
System.out.println("waiting ...");
|
|
||||||
Packet packet = collector.nextResult();
|
|
||||||
if (packet instanceof Message) {
|
|
||||||
Message inbound_message = (Message) packet;
|
|
||||||
if (inbound_message != null && inbound_message.getBody() != null){
|
|
||||||
System.out.println(inbound_message.getBody());
|
|
||||||
messageController.messageTranslater(inbound_message.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.error("Message has been corrupted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printRoster() throws Exception {
|
|
||||||
if(xmppConnection != null){
|
|
||||||
Roster roster = xmppConnection.getRoster();
|
|
||||||
if(roster !=null && roster.getEntries() != null){
|
|
||||||
Collection<RosterEntry> entries = roster.getEntries();
|
|
||||||
for (RosterEntry entry : entries) {
|
|
||||||
System.out.println(String.format("Buddy:%1$s - Status:%2$s",
|
|
||||||
entry.getName(), entry.getStatus()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{
|
|
||||||
System.out.println("There are no users");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* private void retryXMPPConnection() {
|
|
||||||
Thread retryToConnect = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!isConnected()) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Re-trying to reach XMPP Server....");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
VirtualFireAlarmXMPPConnector.super.connectAndLogin(xmppAdminUsername,
|
|
||||||
xmppAdminPassword,
|
|
||||||
null);
|
|
||||||
VirtualFireAlarmXMPPConnector.super.setMessageFilterOnReceiver(
|
|
||||||
xmppAdminAccountJID);
|
|
||||||
} catch (DeviceManagementException e1) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Attempt to re-connect to XMPP-Server failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
log.error("XMPP: Thread Sleep Interrupt Exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
retryToConnect.setDaemon(true);
|
|
||||||
retryToConnect.start();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
package org.wso2.carbon.device.mgt.iot.droneanalyzer.service;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.apache.cxf.jaxrs.client.WebClient;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
||||||
|
|
||||||
import org.wso2.carbon.device.mgt.common.Device;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
|
|
||||||
public class DroneServiceTest {
|
|
||||||
|
|
||||||
private static org.apache.commons.logging.Log log = LogFactory.getLog(DroneServiceTest.class);
|
|
||||||
ApplicationContext context;
|
|
||||||
WebClient client;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init(){
|
|
||||||
context = new ClassPathXmlApplicationContext("spring-cxf-client.xml");
|
|
||||||
client = context.getBean("droneClient", WebClient.class);
|
|
||||||
}
|
|
||||||
//@Test
|
|
||||||
public void registerDevice(){
|
|
||||||
client.path("manager/device/register").accept(MediaType.APPLICATION_JSON_TYPE);
|
|
||||||
client.query("deviceId", "device7");
|
|
||||||
client.query("name", "dronetypeOne");
|
|
||||||
client.query("owner", "DroneOwner");
|
|
||||||
Response res = client.put(null);
|
|
||||||
log.info("Response status :"+ res.getStatus());
|
|
||||||
System.out.println("Response status :"+ res.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void removeDevice(){
|
|
||||||
client.path("manager/device/remove/").accept(MediaType.APPLICATION_JSON_TYPE);
|
|
||||||
client.path("device7");
|
|
||||||
Response res = client.delete();
|
|
||||||
log.info("Response status :"+ res.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void updateDevice(){
|
|
||||||
client.path("manager/device/update/").accept(MediaType.APPLICATION_JSON_TYPE);
|
|
||||||
client.path("device2");
|
|
||||||
client.query("name", "ARDrone");
|
|
||||||
Response res = client.post(null);
|
|
||||||
log.info("Response status :"+ res.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void getDevice(){
|
|
||||||
client.path("manager/device/").accept(MediaType.APPLICATION_JSON_TYPE);
|
|
||||||
client.path("device2");
|
|
||||||
Device res = client.get(Device.class);
|
|
||||||
log.info("Device name :"+ res.getName());
|
|
||||||
log.info("Device type :"+ res.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void getDroneDevices(){
|
|
||||||
client.path("manager/devices/").accept(MediaType.APPLICATION_JSON_TYPE);
|
|
||||||
client.path("DroneOwner");
|
|
||||||
Collection<? extends Device> res = client.getCollection(Device.class);
|
|
||||||
Iterator<? extends Device> iterator = res.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Device device = iterator.next();
|
|
||||||
log.info("Device name :" + device.getName());
|
|
||||||
log.info("Device type :"+ device.getType());
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void downloadSketch(){
|
|
||||||
client.path("manager/devices/");
|
|
||||||
client.path("type1");
|
|
||||||
client.path("download").accept(MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
Response res = client.get();
|
|
||||||
log.info(res.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void droneController(){
|
|
||||||
client.path("controller/send_command");
|
|
||||||
client.query("owner", "DroneOwner");
|
|
||||||
client.query("deviceId", "device2");
|
|
||||||
client.query("action", "takeoff");
|
|
||||||
client.query("speed", 5);
|
|
||||||
client.query("duration", 56);
|
|
||||||
client.accept(MediaType.APPLICATION_JSON);
|
|
||||||
Response res = client.post(null);
|
|
||||||
System.out.println(res.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateSketchLink(){
|
|
||||||
client.path("manager/devices/");
|
|
||||||
client.path("type1");
|
|
||||||
client.path("download").accept(MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
Response res = client.get();
|
|
||||||
log.info(res.getStatus());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package org.wso2.carbon.device.mgt.iot.droneanalyzer.service.transport;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
|
|
||||||
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig;
|
|
||||||
import org.wso2.carbon.utils.CarbonUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by geesara on 12/10/15.
|
|
||||||
*/
|
|
||||||
public class DroneAnalyzerXMPPConnectorTest {
|
|
||||||
private static Log log = LogFactory.getLog(DroneAnalyzerXMPPConnectorTest.class);
|
|
||||||
public DroneAnalyzerXMPPConnector droneAnalyzerXMPPConnector;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public void setup(){
|
|
||||||
//droneAnalyzerXMPPConnector = new DroneAnalyzerXMPPConnector();
|
|
||||||
//droneAnalyzerXMPPConnector.initConnector();
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void login(){
|
|
||||||
// droneAnalyzerXMPPConnector.connectAndLogin();
|
|
||||||
// log.info("ip address "+XmppConfig.getInstance().getXmppServerIP());
|
|
||||||
//log.info("path "+ CarbonUtils.getCarbonConfigDirPath());
|
|
||||||
// log.info("path "+ CarbonUtils.getCarbonHome());
|
|
||||||
//System.out.println(System.getProperty("carbon.home"));
|
|
||||||
System.out.println(System.getenv("CARBON_HOME"));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
|
||||||
|
|
||||||
|
|
||||||
<bean id="jacksonJsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"></bean>
|
|
||||||
|
|
||||||
<util:list id="webClientProviders">
|
|
||||||
<ref bean="jacksonJsonProvider"/>
|
|
||||||
</util:list>
|
|
||||||
|
|
||||||
<bean id="droneClient" class="org.apache.cxf.jaxrs.client.WebClient"
|
|
||||||
factory-method="create">
|
|
||||||
<constructor-arg type="java.lang.String" value="http://localhost:9763/drone_analyzer/DroneAnalyzerServiceUnitManager/"/>
|
|
||||||
<constructor-arg ref="webClientProviders" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
</beans>
|
|
@ -0,0 +1,38 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
--------------
|
||||||
|
testRun.sh
|
||||||
|
--------------
|
||||||
|
This script is used to run this service in a testing environment. It can be run on a real Raspberry Pi device or
|
||||||
|
a virtual environment.
|
||||||
|
To run: sudo ./testRun.sh and follow the instructions.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
startService.sh
|
||||||
|
-------------------
|
||||||
|
After testing, this script can be used to deploy this application as a service on Raspberry Pi which will get loaded
|
||||||
|
during boot up process.
|
||||||
|
To run: sudo ./startService.sh
|
||||||
|
Note: You should have to provide following arguments in RaspberryService.sh as shown below.
|
||||||
|
|
||||||
|
DAEMON_OPTS="-l /usr/local/src/RaspberryAgent/RaspberryStats.log -m N -i 56"
|
||||||
|
|
||||||
|
-l ----> file to write log
|
||||||
|
-i ----> time interval between successive data pushes to the wso2 IoT Server
|
||||||
|
-m ----> weather is going to run on the real device or not
|
@ -1,20 +0,0 @@
|
|||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
templates=deviceConfig.properties
|
|
||||||
zipfilename=RaspberryPi.zip
|
|
@ -1,338 +0,0 @@
|
|||||||
#!/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 datetime
|
|
||||||
|
|
||||||
import running_mode
|
|
||||||
|
|
||||||
PUSH_INTERVAL = 5000 # time interval between successive data pushes in seconds
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# Logger defaults
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
#LOG_FILENAME = "/usr/local/src/RaspberryAgent/logs/RaspberryStats.log"
|
|
||||||
LOG_FILENAME = "RaspberryStats.log"
|
|
||||||
logging_enabled = False
|
|
||||||
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_for_data_push_interval = "time interval between successive data pushes (default '" + str(PUSH_INTERVAL) + "')"
|
|
||||||
help_string_for_running_mode = "time interval between successive data pushes (default '" + str(PUSH_INTERVAL) + "')"
|
|
||||||
parser.add_argument("-i", "--interval", type=int, help=help_string_for_data_push_interval)
|
|
||||||
parser.add_argument("-m", "--mode", type=str, help=help_string_for_running_mode)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
if args.log:
|
|
||||||
LOG_FILENAME = args.log
|
|
||||||
|
|
||||||
if args.interval:
|
|
||||||
PUSH_INTERVAL = args.interval
|
|
||||||
|
|
||||||
if args.mode:
|
|
||||||
running_mode.RUNNING_MODE = args.mode
|
|
||||||
iotUtils = __import__('iotUtils')
|
|
||||||
httpServer = __import__('httpServer') # python script used to start a http-server to listen for operations
|
|
||||||
# (includes the TEMPERATURE global variable)
|
|
||||||
mqttListener = __import__('mqttListener') # python script used to accept messages via mqtt
|
|
||||||
#xmppServer = __import__('xmppServer') # python script used to communicate with xmpp server
|
|
||||||
|
|
||||||
if running_mode.RUNNING_MODE == 'N':
|
|
||||||
Adafruit_DHT = __import__('Adafruit_DHT') # Adafruit library required for temperature sensing
|
|
||||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# Endpoint specific settings to which the data is pushed
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
DC_ENDPOINT = iotUtils.HTTP_EP.split(":")
|
|
||||||
DC_IP = DC_ENDPOINT[1].replace('//', '')
|
|
||||||
DC_PORT = int(DC_ENDPOINT[2])
|
|
||||||
DC_ENDPOINT_CONTEXT = iotUtils.CONTROLLER_CONTEXT
|
|
||||||
PUSH_ENDPOINT = str(DC_ENDPOINT_CONTEXT) + '/push_temperature/'
|
|
||||||
REGISTER_ENDPOINT = str(DC_ENDPOINT_CONTEXT) + '/register'
|
|
||||||
|
|
||||||
HOST = iotUtils.getDeviceIP()
|
|
||||||
HOST_HTTP_SERVER_PORT = iotUtils.getHTTPServerPort()
|
|
||||||
HOST_AND_PORT = str(HOST)+ ":" + str(HOST_HTTP_SERVER_PORT)
|
|
||||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# 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 = str(REGISTER_ENDPOINT) + '/' + str(iotUtils.DEVICE_OWNER) + '/' + str(iotUtils.DEVICE_ID) + '/' + \
|
|
||||||
str(HOST) + '/' + str(HOST_HTTP_SERVER_PORT) + '/'
|
|
||||||
dcConncection.putrequest('POST', registerURL)
|
|
||||||
dcConncection.putheader('Authorization', 'Bearer ' + iotUtils.AUTH_TOKEN)
|
|
||||||
dcConncection.endheaders()
|
|
||||||
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)
|
|
||||||
dcConnection.putheader('Authorization', 'Bearer ' + iotUtils.AUTH_TOKEN)
|
|
||||||
dcConnection.putheader('Content-Type', 'application/json')
|
|
||||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
### Read the Temperature and Load info of RPi and construct payload
|
|
||||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
rPiTemperature = iotUtils.LAST_TEMP # Push the last read temperature value
|
|
||||||
PUSH_DATA = iotUtils.DEVICE_INFO + iotUtils.DEVICE_IP.format(ip=HOST_AND_PORT) + iotUtils.DEVICE_DATA.format(
|
|
||||||
temperature=rPiTemperature)
|
|
||||||
PUSH_DATA += '}'
|
|
||||||
dcConnection.putheader('Content-Length', len(PUSH_DATA))
|
|
||||||
dcConnection.endheaders()
|
|
||||||
|
|
||||||
print PUSH_DATA
|
|
||||||
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):
|
|
||||||
if running_mode.RUNNING_MODE == 'N':
|
|
||||||
self.interval = iotUtils.TEMPERATURE_READING_INTERVAL_REAL_MODE
|
|
||||||
else:
|
|
||||||
self.interval = iotUtils.TEMPERATURE_READING_INTERVAL_VIRTUAL_MODE
|
|
||||||
thread = threading.Thread(target=self.run, args=())
|
|
||||||
thread.daemon = True # Daemonize thread
|
|
||||||
thread.start() # Start the execution
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
if running_mode.RUNNING_MODE == 'N':
|
|
||||||
humidity, temperature = Adafruit_DHT.read_retry(iotUtils.TEMP_SENSOR_TYPE, iotUtils.TEMP_PIN)
|
|
||||||
else:
|
|
||||||
humidity, temperature = iotUtils.generateRandomTemperatureAndHumidityValues()
|
|
||||||
|
|
||||||
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()
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
def get_now():
|
|
||||||
"get the current date and time as a string"
|
|
||||||
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
|
|
||||||
def sigterm_handler(_signo, _stack_frame):
|
|
||||||
"When sysvinit sends the TERM signal, cleanup before exiting."
|
|
||||||
print("[] received signal {}, exiting...".format(_signo))
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# 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):
|
|
||||||
pass
|
|
||||||
#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()
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, sigterm_handler)
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# The Main method of the RPi Agent
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
def main():
|
|
||||||
configureLogger("WSO2IOT_RPiStats")
|
|
||||||
if running_mode.RUNNING_MODE == 'N':
|
|
||||||
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,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
Loading…
Reference in new issue