Untitled

                Never    
Java
       
public void onExecute() throws Exception
{
  new Thread(this, getComponent().getSlotPath().toString()).start();
}

HistoryDatabaseConnection conn = null;

public void run()
{
  setLastAttempt(BAbsTime.now());
  setDebug("Started");
  try
  {
    //get connection to history database
    conn = Sys.getService(BHistoryService.TYPE).as(BHistoryService.class).getDatabase().getDbConnection(null);
    //get all the historyIds from properties
    
//    BHistoryId[] hisIds = getComponent().getChildren(BHistoryId.class);
//    debug("Found "+hisIds.length+" history id properties");
    //get the associated history
     
    List<ListElement> data = new ArrayList<ListElement>();
     
    List<Property> props = Arrays.asList(getComponent().getPropertiesArray());
    List<HistoryDescriptor> histories = new ArrayList<HistoryDescriptor>();
    for (Property prop : props)
    {
      if (prop.getDefaultValue() instanceof BHistoryId && !prop.getName().equals("outputHistory")) {
        BHistoryId hisId = BHistoryId.make(((BHistoryId)(prop.getDefaultValue())).getDeviceName(), SlotPath.escape(((BHistoryId)(prop.getDefaultValue())).getHistoryName())); //this is for proper handling of special characters in the historyId
        BIHistory hisInt = conn.getHistory(hisId);
        if (getShowDebug()) debug("Getting history "+hisId);
        if (hisInt== null) debug ("**** ERROR getting "+hisId);
        else {
        HistoryDescriptor hisDes = new HistoryDescriptor(hisInt); //get the history interface for the current historyId
        hisDes.setAddSub(prop.getName().startsWith("sub"));
        histories.add(hisDes);
        if (getShowDebug()) debugNoCR("...Done");
      } //else if (getShowDebug()) debug("Ignoring Property: "+prop.getName());
    }
    }
    
    //fill array with hourly usage from all histories
    double currentMax     = Double.NEGATIVE_INFINITY;
    double currentMin     = Double.POSITIVE_INFINITY;
    double runningTotal   = 0;
    long averageCount     = 0;
    BAbsTime maxStartTime = BAbsTime.NULL;
    BAbsTime minStartTime = BAbsTime.NULL;
    BAbsTime endOfCurrentPeriod = getStartTime();
    // this code below runs for each hour
    for (BAbsTime startOfCurrentPeriod = getStartTime(); endOfCurrentPeriod.isBefore(getEndTime()); startOfCurrentPeriod = startOfCurrentPeriod.add(BRelTime.makeHours(1))) //start at "start time", increment by 1 hour per iteration until we reach the "end time"
    {
      if (getShowDebug()) debug("Time: "+startOfCurrentPeriod);
      ListElement listEle = new ListElement(startOfCurrentPeriod);
      double totalUsageForPeriod = 0;
      endOfCurrentPeriod = startOfCurrentPeriod.add(BRelTime.makeHours(1)); //endOfCurrentPeriod is always 1 hour after startOfCurrentPeriod
      // for each history
      for (HistoryDescriptor hisDes : histories)
      {
        if (hisDes.getHistory() != null) {
          BStatusNumeric startVal = guesstimateValue(hisDes.getHistory(), startOfCurrentPeriod, null); //get the value in the current history that relates the startOfCurrentPeriod (will be estimated if no value is found with in 10secs of exact time)
          BStatusNumeric endVal = guesstimateValue(hisDes.getHistory(), endOfCurrentPeriod, null); //get the value in the current history that relates the endOfCurrentPeriod (will be estimated if no value is found with in 10secs of exact time)
          double value = 0;
          if (startVal != null && endVal != null) value = (endVal.getValue() - startVal.getValue());
          if (getShowDebug()) debugNoCR(" "+(hisDes.getAddSub() ? "-" : "")+value);
          if (hisDes.getAddSub()) totalUsageForPeriod = totalUsageForPeriod - value;
          else totalUsageForPeriod = totalUsageForPeriod + value;
        }      
      } 
      if (getShowDebug()) debugNoCR(" T:"+totalUsageForPeriod);
      runningTotal = runningTotal + totalUsageForPeriod;
      averageCount++;
      listEle.addValue(totalUsageForPeriod);
      data.add(listEle);
    }  
    //find highest hour and output this
    
    double expectedAvg = 0;
    if (averageCount > 0) expectedAvg = runningTotal/averageCount;
    Iterator<ListElement> it = data.iterator();
    if (getShowDebug()) debug("Got Iterator, "+data.size()+" elements to go through");
    BHistoryDatabase db = Sys.getService(BHistoryService.TYPE).as(BHistoryService.class).getDatabase();
    conn = db.getDbConnection(null);

    while(it.hasNext())
    {
      ListElement ele = it.next();
      double val = ele.getTotal();
      BHistoryConfig config = new BHistoryConfig(getOutputHistory(), BTypeSpec.make("history:NumericTrendRecord"));
      config.setCapacity(BCapacity.makeByRecordCount(100000));
      config.setTimeZone(BTimeZone.getLocal());
      if (conn.exists(config.getId())) {
        //System.out.println("History Already Exists, skipping creation!!");
        //conn.clearAllRecords(config.getId());
        conn.reconfigureHistory(config);
      }
      else conn.createHistory(config);
      BIHistory his = conn.getHistory(config.getId());
      BNumericTrendRecord rec = new BNumericTrendRecord();
      rec.setTimestamp(ele.getTime());
      rec.setValue(val);
      conn.append(his, rec);
      if (val > (expectedAvg * 1.5) || val < (expectedAvg * 0.5)) debug("Bad Data Detected: "+ele.getTime()+" Value: "+ val);
      if (getShowDebug()) debug("Element: "+ele.getTimeKey()+" "+ele.getTotal());
      if (val > currentMax){
        currentMax = val;
        maxStartTime = ele.getTime();
      }
      if (val < currentMin){
        currentMin = val;
        minStartTime = ele.getTime();
      }
      runningTotal = runningTotal + val;
      averageCount++;
    }
    if (getShowDebug()) debug("AvgCount: "+averageCount);
    if (getShowDebug()) debug("runningTotal: "+runningTotal);
  
    if(Double.isInfinite(currentMax))
    {
      getMax().setValue(0);
      getMax().setStatusNull(true);
    }
    else
    {
     getMax().setValue(currentMax);
     getMax().setStatus(BStatus.ok);
    }

    if(Double.isInfinite(currentMin))
    {
      getMin().setValue(0);
      getMin().setStatusNull(true);
    }
    else
    {
      getMin().setValue(currentMin);
      getMin().setStatus(BStatus.ok);
    }

    if(averageCount == 0)
    {
      getAvg().setValue(0);
      getAvg().setStatusNull(true);
    }
    else
    {
      getAvg().setValue(runningTotal/averageCount);
      getAvg().setStatus(BStatus.ok);
    }

    setMaxTime(maxStartTime);
    setMinTime(minStartTime);
    setHistorySegmentCount((int)averageCount);
    if (getShowDebug()) debug("Finished");
  }
  catch(Exception e)
  {
    debug("Error: "+e);
  }
  finally
  {
    conn.close();
  }

  setLastSuccess(BAbsTime.now());
}

private BStatusNumeric guesstimateValue(BIHistory h, BAbsTime time, BRelTime limit)
{
  //identify value before and after time
  if (limit == null) limit = BRelTime.makeHours(1); //default to 1 hour limit (search window)
  BAbsTime start = time.subtract(limit);
  BAbsTime end = time.add(limit);
  //BICollection recs = h.timeQuery(start, end);
  Cursor<BHistoryRecord> c = conn.timeQuery(h, start, end).cursor();
  BNumericTrendRecord recBefore = null;
  BNumericTrendRecord recAfter = null;
  while (c.next())
  {
    BNumericTrendRecord rec = (BNumericTrendRecord) c.get();
    if (rec.getTimestamp().delta(time).getMillis() < 10000 && rec.getTimestamp().delta(time).getMillis() > -10000)
    {
      return new BStatusNumeric(rec.getValue());
    }
    if (rec.getTimestamp().isBefore(time)) recBefore = rec;
    if (rec.getTimestamp().isAfter(time) && recAfter == null)
    {
      recAfter = rec;
      break;
    }
  }    
  if (recBefore != null && recAfter != null)
  {
    long timeBetweenRecords = recBefore.getTimestamp().getMillis() - recAfter.getTimestamp().getMillis();
    long timeToFocusTime = time.getMillis() - recBefore.getTimestamp().getMillis();
    double valDelta = recBefore.getValue()-recAfter.getValue();
    double valAtFocus;
    if (valDelta != 0) valAtFocus = timeToFocusTime/timeBetweenRecords*valDelta+recBefore.getValue();
      else valAtFocus = recBefore.getValue();
    return new BStatusNumeric(valAtFocus);
  }
  //if only one record can be determined in the range, return that value 
  if (recBefore != null) return new BStatusNumeric(recBefore.getValue());
  if (recAfter != null) return new BStatusNumeric(recAfter.getValue());
   
  // if no values found, return null
  return null;
}

private class HistoryDescriptor extends Object
{
  BIHistory history;
  boolean addSub = false; //false = add, true = subtract

  public HistoryDescriptor(BIHistory h)
  {
    history = h;
  }

  public BIHistory getHistory() { return history; }
  public void setHistory(BIHistory h) { history = h; }
  public boolean getAddSub() { return addSub; }
  public void setAddSub(boolean b) { addSub = b; }
}

private class ListElement extends Object
{
  BAbsTime timestamp = BAbsTime.NULL;
  //boolean addSub = false; //false = add, true = subtract
  List<Double> values = new ArrayList<Double>();
  
  public ListElement(BAbsTime time)
  {
    timestamp = time;
  }
  
  public BAbsTime getTime()
  {
    return timestamp;
  }
  
  public void addValue(double v)
  {
    values.add(new Double(v));    
  }
  
  public double getTotal()
  {
    double total = 0;
    Iterator<Double> it = values.iterator();
    while(it.hasNext())
    {
      total =+ it.next().doubleValue();
    }
    return total;
  }
  
  public String getTimeKey()
  {
    StringBuffer b = new StringBuffer();

    b.append(timestamp.getDate());
    b.append("-");
    b.append(timestamp.getTime().getHour());
    return b.toString();
  }
}

private void debug(String s)
{
  setDebug(getDebug()+"\n"+s);
}

private void debugNoCR(String s)
{
  setDebug(getDebug()+s);
}