Added menu option to send init script to nodes. Added charts 'Average Power' and 'Average Temperature'. Limited the number of displayed chart items to 250 in the time charts

This commit is contained in:
nifi 2008-08-29 09:00:15 +00:00
parent 71c219f5fc
commit ec69c1c825
5 changed files with 376 additions and 85 deletions

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: CollectServer.java,v 1.5 2008/07/10 20:05:09 adamdunkels Exp $
* $Id: CollectServer.java,v 1.6 2008/08/29 09:00:15 nifi Exp $
*
* -----------------------------------------------------------------
*
@ -34,8 +34,8 @@
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2008/07/10 20:05:09 $
* $Revision: 1.5 $
* Updated : $Date: 2008/08/29 09:00:15 $
* $Revision: 1.6 $
*/
package se.sics.contiki.collect;
@ -110,6 +110,7 @@ public class CollectServer {
private JFrame window;
private JTabbedPane mainPanel;
private JMenuItem serialItem;
private JMenuItem runInitScriptItem;
private Visualizer[] visualizers;
private MapPanel mapPanel;
@ -121,6 +122,7 @@ public class CollectServer {
private Node[] selectedNodes;
private SerialConnection serialConnection;
private String initScript;
@SuppressWarnings("serial")
public CollectServer(String comPort) {
@ -133,6 +135,7 @@ public class CollectServer {
if (comPort == null) {
comPort = configTable.getProperty("collect.serialport");
}
this.initScript = config.getProperty("init.script", INIT_SCRIPT);
/* Make sure we have nice window decorations */
// JFrame.setDefaultLookAndFeelDecorated(true);
@ -200,8 +203,26 @@ public class CollectServer {
if (image != null) {
mapPanel.setMapBackground(image);
}
final int defaultMaxItemCount = 250;
visualizers = new Visualizer[] {
mapPanel,
new BarChartPanel(this, "Average Power", "Average Power Consumption", null, "Power (mW)",
new String[] { "LPM", "CPU", "Radio listen", "Radio transmit" }) {
{
ValueAxis axis = chart.getCategoryPlot().getRangeAxis();
axis.setLowerBound(0.0);
axis.setUpperBound(75.0);
}
protected void addSensorData(SensorData data) {
Node node = data.getNode();
String nodeName = node.getName();
SensorDataAggregator aggregator = node.getSensorDataAggregator();
dataset.addValue(aggregator.getLPMPower(), categories[0], nodeName);
dataset.addValue(aggregator.getCPUPower(), categories[1], nodeName);
dataset.addValue(aggregator.getListenPower(), categories[2], nodeName);
dataset.addValue(aggregator.getTransmitPower(), categories[3], nodeName);
}
},
new BarChartPanel(this, "Instantaneous Power", "Instantaneous Power Consumption", null, "Power (mW)",
new String[] { "LPM", "CPU", "Radio listen", "Radio transmit" }) {
{
@ -219,16 +240,32 @@ public class CollectServer {
}
},
new TimeChartPanel(this, "Power History", "Historical Power Consumption", "Time", "mW") {
{
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getAveragePower();
}
},
new BarChartPanel(this, "Average Temperature", "Temperature", null, "Celsius",
new String[] { "Celsius" }) {
{
chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits());
}
protected void addSensorData(SensorData data) {
Node node = data.getNode();
String nodeName = node.getName();
SensorDataAggregator aggregator = node.getSensorDataAggregator();
dataset.addValue(aggregator.getAverageTemperature(), categories[0], nodeName);
}
},
new TimeChartPanel(this, "Temperature", "Temperature", "Time", "Celsius") {
{
chart.getXYPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits());
setRangeTick(5);
setRangeMinimumSize(10.0);
setGlobalRange(true);
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getTemperature();
@ -236,6 +273,7 @@ public class CollectServer {
},
new TimeChartPanel(this, "Relative Humidity", "Humidity", "Time", "%") {
{
setMaxItemCount(defaultMaxItemCount);
chart.getXYPlot().getRangeAxis().setRange(0.0, 100.0);
}
protected double getSensorDataValue(SensorData data) {
@ -243,11 +281,17 @@ public class CollectServer {
}
},
new TimeChartPanel(this, "Light 1", "Light 1", "Time", "-") {
{
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getLight1();
}
},
new TimeChartPanel(this, "Light 2", "Light 2", "Time", "-") {
{
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getLight2();
}
@ -258,6 +302,7 @@ public class CollectServer {
axis.setLowerBound(0.0);
axis.setUpperBound(4.0);
axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getValue(SensorData.HOPS);
@ -273,6 +318,9 @@ public class CollectServer {
}
},
new TimeChartPanel(this, "Latency", "Latency", "Time", "Seconds") {
{
setMaxItemCount(defaultMaxItemCount);
}
protected double getSensorDataValue(SensorData data) {
return data.getLatency();
}
@ -368,6 +416,23 @@ public class CollectServer {
toolsMenu.setMnemonic(KeyEvent.VK_T);
menuBar.add(toolsMenu);
runInitScriptItem = new JMenuItem("Run Init Script");
runInitScriptItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mainPanel.setSelectedComponent(serialConsole.getPanel());
if (serialConnection != null && serialConnection.isOpen()) {
runInitScript();
} else {
JOptionPane.showMessageDialog(mainPanel, "No serial port connection", "No connected node", JOptionPane.ERROR_MESSAGE);
}
}
});
runInitScriptItem.setEnabled(false);
toolsMenu.add(runInitScriptItem);
toolsMenu.addSeparator();
final JCheckBoxMenuItem scrollItem = new JCheckBoxMenuItem("Scroll Layout");
scrollItem.addActionListener(new ActionListener() {
@ -425,11 +490,11 @@ public class CollectServer {
if (!hasSentInit) {
hasSentInit = true;
String initScript = config.getProperty("init.script", INIT_SCRIPT);
if (initScript != null) {
if (hasInitScript()) {
// Wait a short time before running the init script
sleep(3000);
runScript(initScript);
runInitScript();
}
}
}
@ -515,36 +580,46 @@ public class CollectServer {
}
}
private boolean runScript(String script) {
try {
BufferedReader in = new BufferedReader(new FileReader(script));
String line;
while ((line = in.readLine()) != null) {
if (line.length() == 0 || line.charAt(0) == '#') {
// Ignore empty lines and comments
} else if (line.startsWith("echo ")) {
line = line.substring(5).trim();
if (line.indexOf('%') >= 0) {
line = line.replace("%TIME%", "" + (System.currentTimeMillis() / 1000));
protected boolean hasInitScript() {
return initScript != null && new File(initScript).canRead();
}
protected void runInitScript() {
if (initScript != null) {
runScript(initScript);
}
}
protected void runScript(final String scriptFileName) {
new Thread("scripter") {
public void run() {
try {
BufferedReader in = new BufferedReader(new FileReader(scriptFileName));
String line;
while ((line = in.readLine()) != null) {
if (line.length() == 0 || line.charAt(0) == '#') {
// Ignore empty lines and comments
} else if (line.startsWith("echo ")) {
line = line.substring(5).trim();
if (line.indexOf('%') >= 0) {
line = line.replace("%TIME%", "" + (System.currentTimeMillis() / 1000));
}
sendToNode(line);
} else if (line.startsWith("sleep ")) {
long delay = Integer.parseInt(line.substring(6).trim());
Thread.sleep(delay * 1000);
} else {
System.err.println("Unknown script command: " + line);
break;
}
}
sendToNode(line);
} else if (line.startsWith("sleep ")) {
long delay = Integer.parseInt(line.substring(6).trim());
Thread.sleep(delay * 1000);
} else {
System.err.println("Unknown script comand: " + line);
return false;
in.close();
} catch (Exception e) {
System.err.println("Failed to run script: " + scriptFileName);
e.printStackTrace();
}
}
in.close();
return true;
} catch (FileNotFoundException e) {
return false;
} catch (Exception e) {
System.err.println("Failed to run script: " + script);
e.printStackTrace();
return false;
}
}.start();
}
public String getConfig(String property) {
@ -559,12 +634,14 @@ public class CollectServer {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
boolean isOpen = serialConnection.isOpen();
if (message == null) {
window.setTitle(WINDOW_TITLE);
} else {
window.setTitle(WINDOW_TITLE + " (" + message + ')');
}
serialItem.setText(serialConnection.isOpen() ? "Disconnect from serial" : "Connect to serial");
serialItem.setText(isOpen ? "Disconnect from serial" : "Connect to serial");
runInitScriptItem.setEnabled(isOpen && hasInitScript());
}
});

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: Node.java,v 1.1 2008/07/09 23:18:06 nifi Exp $
* $Id: Node.java,v 1.2 2008/08/29 09:00:15 nifi Exp $
*
* -----------------------------------------------------------------
*
@ -34,8 +34,8 @@
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2008/07/09 23:18:06 $
* $Revision: 1.1 $
* Updated : $Date: 2008/08/29 09:00:15 $
* $Revision: 1.2 $
*/
package se.sics.contiki.collect;
@ -47,6 +47,7 @@ import java.util.Hashtable;
*/
public class Node implements Comparable<Node> {
private SensorDataAggregator sensorDataAggregator;
private ArrayList<SensorData> sensorDataList = new ArrayList<SensorData>();
private ArrayList<Link> links = new ArrayList<Link>();
@ -62,6 +63,7 @@ public class Node implements Comparable<Node> {
public Node(String nodeID) {
this.id = nodeID;
this.name = "Node " + nodeID;
sensorDataAggregator = new SensorDataAggregator(this);
}
public final String getID() {
@ -141,13 +143,17 @@ public class Node implements Comparable<Node> {
// SensorData
// -------------------------------------------------------------------
public SensorDataAggregator getSensorDataAggregator() {
return sensorDataAggregator;
}
public SensorData[] getAllSensorData() {
return sensorDataList.toArray(new SensorData[sensorDataList.size()]);
}
public void removeAllSensorData() {
sensorDataList.clear();
sensorDataAggregator.clear();
}
public SensorData getSensorData(int index) {
@ -170,6 +176,7 @@ public class Node implements Comparable<Node> {
}
}
sensorDataList.add(data);
sensorDataAggregator.addSensorData(data);
return true;
}

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SensorData.java,v 1.2 2008/08/15 18:47:13 adamdunkels Exp $
* $Id: SensorData.java,v 1.3 2008/08/29 09:00:15 nifi Exp $
*
* -----------------------------------------------------------------
*
@ -34,50 +34,16 @@
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2008/08/15 18:47:13 $
* $Revision: 1.2 $
* Updated : $Date: 2008/08/29 09:00:15 $
* $Revision: 1.3 $
*/
package se.sics.contiki.collect;
/**
*
*/
public class SensorData {
public static final int TICKS_PER_SECOND = 4096;
private static final double VOLTAGE = 3;
private static final double POWER_CPU = 1.800 * VOLTAGE; /* mW */
private static final double POWER_LPM = 0.0545 * VOLTAGE; /* mW */
private static final double POWER_TRANSMIT = 17.7 * VOLTAGE; /* mW */
private static final double POWER_LISTEN = 20.0 * VOLTAGE; /* mW */
public static final int DATA_LEN = 0;
public static final int TIMESTAMP1 = 1;
public static final int TIMESTAMP2 = 2;
public static final int TIMESYNCTIMESTAMP = 3;
public static final int NODE_ID = 4;
public static final int SEQNO = 5;
public static final int HOPS = 6;
public static final int LATENCY = 7;
public static final int DATA_LEN2 = 8;
public static final int CLOCK = 9;
public static final int TIMESYNCHTIME = 10;
public static final int LIGHT1 = 11;
public static final int LIGHT2 = 12;
public static final int TEMPERATURE = 13;
public static final int HUMIDITY = 14;
public static final int RSSI = 15;
public static final int TIME_CPU = 16;
public static final int TIME_LPM = 17;
public static final int TIME_TRANSMIT = 18;
public static final int TIME_LISTEN = 19;
public static final int BEST_NEIGHBOR = 20;
public static final int BEST_NEIGHBOR_ETX = 21;
public static final int BEST_NEIGHBOR_RTMETRIC = 22;
public static final int VALUES_COUNT = 23;
public class SensorData implements SensorInfo {
private final Node node;
private final int[] values;
@ -101,6 +67,10 @@ public class SensorData {
return values[index];
}
public int getValueCount() {
return values.length;
}
public long getTime() {
return time;
}
@ -169,7 +139,7 @@ public class SensorData {
}
public long getPowerMeasureTime() {
return (1000 * (values[TIME_CPU] + values[TIME_LPM])) / TICKS_PER_SECOND;
return (1000L * (values[TIME_CPU] + values[TIME_LPM])) / TICKS_PER_SECOND;
}
public double getTemperature() {
@ -185,12 +155,7 @@ public class SensorData {
}
public double getHumidity() {
double v;
// double v = values[HUMIDITY];
// double humidity = -4.0 + 0.0405 * v + -0.0000028 * v * v;
// // Correct humidity using temperature compensation
// return (getTemperature() - 25) * (0.01 + 0.00008*v + humidity);
v = -4.0 + 405.0 * values[HUMIDITY] / 10000.0;
double v = -4.0 + 405.0 * values[HUMIDITY] / 10000.0;
if(v > 100) {
return 100;
} else {
@ -199,8 +164,6 @@ public class SensorData {
}
public double getLight1() {
// double v = (values[LIGHT1] * VOLTAGE) / 4096.0;
// return 0.625 * 1000000 * v * 10;
return 10.0 * values[LIGHT1] / 7.0;
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SensorDataAggregator.java,v 1.1 2008/08/29 09:00:15 nifi Exp $
*
* -----------------------------------------------------------------
*
* SensorDataAggregator
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 20 aug 2008
* Updated : $Date: 2008/08/29 09:00:15 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
/**
*
*/
public class SensorDataAggregator implements SensorInfo {
private final Node node;
private long[] values;
private int dataCount;
public SensorDataAggregator(Node node) {
this.node = node;
this.values = new long[VALUES_COUNT];
}
public Node getNode() {
return node;
}
public String getNodeID() {
return node.getID();
}
public long getValue(int index) {
return values[index];
}
public long getAverageValue(int index) {
return dataCount > 0 ? values[index] / dataCount : 0;
}
public int getValueCount() {
return values.length;
}
public int getDataCount() {
return dataCount;
}
public void addSensorData(SensorData data) {
for (int i = 0, n = Math.max(VALUES_COUNT, data.getValueCount()); i < n; i++) {
values[i] += data.getValue(i);
}
dataCount++;
}
public void clear() {
for (int i = 0, n = values.length; i < n; i++) {
values[i] = 0L;
}
dataCount = 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0, n = values.length; i < n; i++) {
if (i > 0) sb.append(' ');
sb.append(values[i]);
}
return sb.toString();
}
public double getCPUPower() {
return (values[TIME_CPU] * POWER_CPU) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getLPMPower() {
return (values[TIME_LPM] * POWER_LPM) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getListenPower() {
return (values[TIME_LISTEN] * POWER_LISTEN) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getTransmitPower() {
return (values[TIME_TRANSMIT] * POWER_TRANSMIT) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getAveragePower() {
return (values[TIME_CPU] * POWER_CPU + values[TIME_LPM] * POWER_LPM
+ values[TIME_LISTEN] * POWER_LISTEN + values[TIME_TRANSMIT] * POWER_TRANSMIT)
/ (values[TIME_CPU] + values[TIME_LPM]);
}
public long getPowerMeasureTime() {
return (1000L * (values[TIME_CPU] + values[TIME_LPM])) / TICKS_PER_SECOND;
}
public double getAverageTemperature() {
return dataCount > 0 ? (-39.6 + 0.01 * (values[TEMPERATURE] / dataCount)) : 0.0;
}
public double getAverageRadioIntensity() {
return getAverageValue(RSSI);
}
public double getAverageLatency() {
return getAverageValue(LATENCY) / 4096.0;
}
public double getAverageHumidity() {
double v = 0.0;
if (dataCount > 0) {
v = -4.0 + 405.0 * (values[HUMIDITY] / dataCount) / 10000.0;
}
return v > 100 ? 100 : v;
}
public double getAverageLight1() {
return 10.0 * getAverageValue(LIGHT1) / 7.0;
}
public double getAverageLight2() {
return 46.0 * getAverageValue(LIGHT2) / 10.0;
}
public double getAverageBestNeighborETX() {
return getAverageValue(BEST_NEIGHBOR_ETX) / 16.0;
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SensorInfo.java,v 1.1 2008/08/29 09:00:15 nifi Exp $
*
* -----------------------------------------------------------------
*
* SensorInfo
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 20 aug 2008
* Updated : $Date: 2008/08/29 09:00:15 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
/**
*
*/
public interface SensorInfo {
public static final long TICKS_PER_SECOND = 4096L;
public static final double VOLTAGE = 3;
public static final double POWER_CPU = 1.800 * VOLTAGE; /* mW */
public static final double POWER_LPM = 0.0545 * VOLTAGE; /* mW */
public static final double POWER_TRANSMIT = 17.7 * VOLTAGE; /* mW */
public static final double POWER_LISTEN = 20.0 * VOLTAGE; /* mW */
public static final int DATA_LEN = 0;
public static final int TIMESTAMP1 = 1;
public static final int TIMESTAMP2 = 2;
public static final int TIMESYNCTIMESTAMP = 3;
public static final int NODE_ID = 4;
public static final int SEQNO = 5;
public static final int HOPS = 6;
public static final int LATENCY = 7;
public static final int DATA_LEN2 = 8;
public static final int CLOCK = 9;
public static final int TIMESYNCHTIME = 10;
public static final int LIGHT1 = 11;
public static final int LIGHT2 = 12;
public static final int TEMPERATURE = 13;
public static final int HUMIDITY = 14;
public static final int RSSI = 15;
public static final int TIME_CPU = 16;
public static final int TIME_LPM = 17;
public static final int TIME_TRANSMIT = 18;
public static final int TIME_LISTEN = 19;
public static final int BEST_NEIGHBOR = 20;
public static final int BEST_NEIGHBOR_ETX = 21;
public static final int BEST_NEIGHBOR_RTMETRIC = 22;
public static final int VALUES_COUNT = 23;
}