/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.jfrontend.extras; import com.freedomotic.api.EventTemplate; import com.freedomotic.api.Protocol; import com.freedomotic.model.charting.UsageData; import com.freedomotic.model.charting.UsageDataFrame; import com.freedomotic.behaviors.DataBehaviorLogic; import com.freedomotic.things.EnvObjectLogic; import com.freedomotic.reactions.Command; import java.awt.Color; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.table.AbstractTableModel; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickUnit; import org.jfree.chart.axis.DateTickUnitType; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.renderer.xy.XYStepRenderer; import org.jfree.data.time.Millisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.XYDataset; import org.jfree.ui.RectangleInsets; /** * * @author Matteo Mazzoni */ public class GraphPanel extends javax.swing.JFrame { private UsageDataFrame points = new UsageDataFrame(); private EnvObjectLogic obj; private TimeSeries series; private JFreeChart chart; private String title; private Protocol master; /** * Creates new form GraphWindow * * @param master * @param obj */ public GraphPanel(Protocol master, EnvObjectLogic obj) { this.master = master; this.obj = obj; this.title = obj.getPojo().getPhisicalAddress(); initComponents(); this.setTitle(title); reDraw(); } /** * */ public final void reDraw() { // String JSON = obj.getBehavior("data").getValueAsString(); DataBehaviorLogic dbl = (DataBehaviorLogic) obj.getBehavior("data"); if (dbl.isChanged()) { this.points.setData(dbl.getData()); createChart(this.points, title); jRawDatatxt.setText(dbl.getValueAsString()); dataTable.setModel(new FreedomoticTableModel()); setVisible(true); } } /** * Creates a chart. * * @param dataset a dataset. * * @return A chart. */ /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jTabbedPane1 = new javax.swing.JTabbedPane(); graphPanel = new javax.swing.JPanel(); tabDataPanel = new javax.swing.JScrollPane(); dataTable = new javax.swing.JTable(); rawDataPanel = new javax.swing.JScrollPane(); jRawDatatxt = new javax.swing.JTextArea(); jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jSpinnerStartDate = new javax.swing.JSpinner(); jSpinnerStopDate = new javax.swing.JSpinner(); jButton2 = new javax.swing.JButton(); jComboGranularity = new javax.swing.JComboBox(); jLabel3 = new javax.swing.JLabel(); graphPanel.setLayout(new java.awt.BorderLayout()); jTabbedPane1.addTab("Graph", graphPanel); dataTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { }, new String [] { } )); tabDataPanel.setViewportView(dataTable); jTabbedPane1.addTab("TableData", tabDataPanel); jRawDatatxt.setColumns(20); jRawDatatxt.setRows(5); rawDataPanel.setViewportView(jRawDatatxt); jTabbedPane1.addTab("RawData", rawDataPanel); jLabel1.setText("Start Date"); jLabel2.setText("End Date"); jButton1.setText("Apply filters"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); jSpinnerStartDate.setModel(new javax.swing.SpinnerDateModel(new java.util.Date(), null, null, java.util.Calendar.SECOND)); jSpinnerStopDate.setModel(new javax.swing.SpinnerDateModel(new java.util.Date(), null, null, java.util.Calendar.SECOND)); jButton2.setText("Redraw"); jButton2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton2ActionPerformed(evt); } }); jComboGranularity.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Year", "Month", "Day", "Hour", "Minute", "Second" })); jComboGranularity.setSelectedIndex(3); jLabel3.setText("Granularity"); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jButton2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton1) .addContainerGap()) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE)) .addComponent(jLabel3)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(jSpinnerStartDate) .addComponent(jSpinnerStopDate) .addComponent(jComboGranularity, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap(336, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(17, 17, 17) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(jSpinnerStartDate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel2) .addComponent(jSpinnerStopDate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jComboGranularity, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel3)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 193, Short.MAX_VALUE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jButton1) .addComponent(jButton2)) .addContainerGap()) ); jTabbedPane1.addTab("Filters", jPanel1); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jTabbedPane1) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed Command command; List<Command> list = master.getApi().commands().findByName("Ask data from the harvester"); if (!list.isEmpty()) { command = list.get(0); } else { throw new RuntimeException("No commands found with the specified name"); } Command cloned; if (command != null) { try { cloned = command.clone(); cloned.setProperty("startDate", Long.toString(((Date) jSpinnerStartDate.getValue()).getTime())); cloned.setProperty("stopDate", Long.toString(((Date) jSpinnerStopDate.getValue()).getTime())); cloned.setProperty("QueryAddress", obj.getPojo().getPhisicalAddress()); master.notifyCommand(cloned); } catch (CloneNotSupportedException ex) { Logger.getLogger(GraphPanel.class.getName()).log(Level.SEVERE, null, ex); } } }//GEN-LAST:event_jButton1ActionPerformed private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed // TODO add your handling code here: reDraw(); }//GEN-LAST:event_jButton2ActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTable dataTable; private javax.swing.JPanel graphPanel; private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JComboBox jComboGranularity; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JPanel jPanel1; private javax.swing.JTextArea jRawDatatxt; private javax.swing.JSpinner jSpinnerStartDate; private javax.swing.JSpinner jSpinnerStopDate; private javax.swing.JTabbedPane jTabbedPane1; private javax.swing.JScrollPane rawDataPanel; private javax.swing.JScrollPane tabDataPanel; // End of variables declaration//GEN-END:variables private void createChart(UsageDataFrame points, String title) { series = new TimeSeries(title); for (UsageData d : points.getData()) { Date resultdate = d.getDateTime(); Millisecond ms_read = new Millisecond(resultdate); int poweredValue = -1; if (d.getObjBehavior().equalsIgnoreCase("powered")) { poweredValue = d.getObjValue().equalsIgnoreCase("true") ? 1 : 0; } else if (d.getObjBehavior().equalsIgnoreCase("brigthness")) { try { poweredValue = Integer.parseInt(d.getObjValue()); } catch (NumberFormatException ex) { poweredValue = -1; } } series.addOrUpdate(ms_read, poweredValue); } XYDataset xyDataset = new TimeSeriesCollection(series); chart = ChartFactory.createTimeSeriesChart("Chart", "TIME", "VALUE", xyDataset, true, // legend true, // tooltips false // urls ); chart.setAntiAlias(true); // Set plot styles XYPlot plot = (XYPlot) chart.getPlot(); plot.setBackgroundPaint(Color.lightGray); plot.setDomainGridlinePaint(Color.white); plot.setRangeGridlinePaint(Color.white); plot.setAxisOffset(new RectangleInsets(2.0, 2.0, 2.0, 2.0)); // Set series line styles plot.setRenderer(new XYStepRenderer()); XYItemRenderer r = plot.getRenderer(); if (r instanceof XYLineAndShapeRenderer) { XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; renderer.setShapesVisible(true); renderer.setShapesFilled(true); } // Set date axis style DateAxis axis = (DateAxis) plot.getDomainAxis(); String formatString = "MM-dd HH"; DateTickUnitType dtut = DateTickUnitType.HOUR; if (jComboGranularity.getSelectedItem().equals("Year")) { formatString = "yyyy"; dtut = DateTickUnitType.YEAR; } else if (jComboGranularity.getSelectedItem().equals("Month")) { axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM")); dtut = DateTickUnitType.MONTH; } else if (jComboGranularity.getSelectedItem().equals("Day")) { axis.setDateFormatOverride(new SimpleDateFormat("MM-dd")); dtut = DateTickUnitType.DAY; } else if (jComboGranularity.getSelectedItem().equals("Minute")) { formatString = "MM-dd HH:mm"; dtut = DateTickUnitType.MINUTE; } else if (jComboGranularity.getSelectedItem().equals("Second")) { formatString = "HH:mm:SS"; dtut = DateTickUnitType.SECOND; } DateFormat formatter = new SimpleDateFormat(formatString); DateTickUnit unit = new DateTickUnit(dtut, 1, formatter); axis.setTickUnit(unit); ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new java.awt.Dimension(800, 500)); graphPanel.removeAll(); graphPanel.add(chartPanel); } /** * * @param ev */ public void addDataFromEvent(EventTemplate ev) { Date d = new Date(ev.getCreation()); Millisecond ms_read = new Millisecond(d); int valut = ev.getProperty("object.behavior.powered").equalsIgnoreCase("true") ? 1 : 0; series.addOrUpdate(ms_read, valut); chart.fireChartChanged(); } /** * */ public class FreedomoticTableModel extends AbstractTableModel { /** * * @return */ @Override public int getRowCount() { return points.getData().size(); } /** * * @return */ @Override public int getColumnCount() { return 6; } /** * * @param rowIndex * @param columnIndex * @return */ @Override public Object getValueAt(int rowIndex, int columnIndex) { UsageData item = points.getData().get(rowIndex); switch (columnIndex) { case 0: return item.getDateTime(); case 1: return item.getObjName(); case 2: return item.getObjProtocol(); case 3: return item.getObjAddress(); case 4: return item.getObjBehavior(); case 5: return item.getObjValue(); } return null; } /** * * @param columnIndex * @return */ @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == 0) { return Date.class; } else { return String.class; } } private final String[] columnNames = {"Datetime", "Name", "Protocol", "Address", "Behavior", "Value"}; /** * * @param column * @return */ @Override public String getColumnName(int column) { return columnNames[column]; } } }