[dss-commits] digitalSTROM Server branch, master, updated. a74566c2d8a2236959f6c376c4578fc201270554

git version control dss-commits at forum.digitalstrom.org
Thu Jan 21 16:15:34 CET 2010


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "digitalSTROM Server".

The branch, master has been updated
       via  a74566c2d8a2236959f6c376c4578fc201270554 (commit)
       via  e5e85f2d96e90b233441f06893e9975fcbff0362 (commit)
       via  9709cd7b69b910ed2aed4c9ca5eb9c7e97cc102b (commit)
       via  dd907bfab4789a44c0dbb23e19ab001811bc6c13 (commit)
       via  0724232f4c5a8cf37c3440434c0ef0ea540f68b8 (commit)
       via  f6ad93fd46fb865cf93bcb3d301ad1924523cdbe (commit)
       via  37043ac1faaeb2f7ff2dbfd11a39d81a876283ea (commit)
      from  793b035827ecac85a7dd9a1815fbe7ecff1fe6f9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a74566c2d8a2236959f6c376c4578fc201270554
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 16:15:08 2010 +0100

    Ignore metering subdirectory

commit e5e85f2d96e90b233441f06893e9975fcbff0362
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 16:03:53 2010 +0100

    Metering: Poll meters simultanously
    
    * Removes delays between polls
    * Only processes meters that are present
    
    Closes #208

commit 9709cd7b69b910ed2aed4c9ca5eb9c7e97cc102b
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 16:03:00 2010 +0100

    Functions to poll all meter for metering values

commit dd907bfab4789a44c0dbb23e19ab001811bc6c13
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 16:02:37 2010 +0100

    Removed commented code and tabs

commit 0724232f4c5a8cf37c3440434c0ef0ea540f68b8
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 16:01:39 2010 +0100

    Only use cached values in fake_meter

commit f6ad93fd46fb865cf93bcb3d301ad1924523cdbe
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 13:42:20 2010 +0100

    Moved some methods around

commit 37043ac1faaeb2f7ff2dbfd11a39d81a876283ea
Author: Patrick Stählin <pstaehlin at futurelab.ch>
Date:   Thu Jan 21 13:30:43 2010 +0100

    Removed tabs

-----------------------------------------------------------------------

Changes:
diff --git a/.gitignore b/.gitignore
index 5cfac8a..754faf2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ doc/json_api.xml
 data/webroot/js/lib/
 Debug/
 data/webroot/js/dss-setup-interface.js
+data/webroot/metering/
 *~
diff --git a/core/DS485Interface.h b/core/DS485Interface.h
index bbb37f8..6dba5e7 100644
--- a/core/DS485Interface.h
+++ b/core/DS485Interface.h
@@ -120,9 +120,13 @@ namespace dss {
   public:
     /** Returns the current power-consumption in mW */
     virtual unsigned long getPowerConsumption(const int _dsMeterID) = 0;
+    /** Sends a message to all devices to report their power consumption */
+    virtual void requestPowerConsumption() = 0;
 
     /** Returns the meter value in Wh */
     virtual unsigned long getEnergyMeterValue(const int _dsMeterID) = 0;
+    /** Sends a message to all devices to report their energy value */
+    virtual void requestEnergyMeterValue() = 0;
 
     virtual ~MeteringBusInterface() {}; // please the compiler (virtual dtor)
   }; // MeteringBusInterface
diff --git a/core/ds485/businterfacehandler.cpp b/core/ds485/businterfacehandler.cpp
index 670d219..4d05b3c 100644
--- a/core/ds485/businterfacehandler.cpp
+++ b/core/ds485/businterfacehandler.cpp
@@ -217,21 +217,17 @@ namespace dss {
             PayloadDissector pd2(frame->getPayload());
             pd2.get<uint8_t>();
             if (functionID == FunctionDSMeterGetPowerConsumption) {
-              /* hard optimized */
-              //getDSS().getApartment().getDSMeterByBusID((int)(frame->getHeader().getSource())).setPowerConsumption(pd2.get<uint32_t>());
-                int modID = frame->getHeader().getSource();
-                ModelEvent* pEvent = new ModelEvent(ModelEvent::etPowerConsumption);
-                pEvent->addParameter(modID);
-                pEvent->addParameter(pd2.get<uint32_t>());
-                raiseModelEvent(pEvent);
+              int modID = frame->getHeader().getSource();
+              ModelEvent* pEvent = new ModelEvent(ModelEvent::etPowerConsumption);
+              pEvent->addParameter(modID);
+              pEvent->addParameter(pd2.get<uint32_t>());
+              raiseModelEvent(pEvent);
             } else if (functionID == FunctionDSMeterGetEnergyMeterValue) {
-              /* hard optimized */
-              //getDSS().getApartment().getDSMeterByBusID((int)(frame->getHeader().getSource())).setEnergyMeterValue(pd2.get<uint32_t>());
-                int modID = frame->getHeader().getSource();
-                ModelEvent* pEvent = new ModelEvent(ModelEvent::etEnergyMeterValue);
-                pEvent->addParameter(modID);
-                pEvent->addParameter(pd2.get<uint32_t>());
-                raiseModelEvent(pEvent);
+              int modID = frame->getHeader().getSource();
+              ModelEvent* pEvent = new ModelEvent(ModelEvent::etEnergyMeterValue);
+              pEvent->addParameter(modID);
+              pEvent->addParameter(pd2.get<uint32_t>());
+              raiseModelEvent(pEvent);
             } else if (functionID == FunctionDSMeterGetDSID) {
               int sourceID = frame->getHeader().getSource();
               ModelEvent* pEvent = new ModelEvent(ModelEvent::etDS485DeviceDiscovered);
diff --git a/core/ds485/ds485proxy.cpp b/core/ds485/ds485proxy.cpp
index 1fe11ba..195e29f 100644
--- a/core/ds485/ds485proxy.cpp
+++ b/core/ds485/ds485proxy.cpp
@@ -256,7 +256,7 @@ namespace dss {
     frame.getPayload().add<uint16_t>(_value);
     sendFrame(frame);
   } // setValueDevice
-  
+
   DSMeterSpec_t DS485Proxy::dsMeterSpecFromFrame(boost::shared_ptr<DS485CommandFrame> _frame) {
     int source = _frame->getHeader().getSource();
 
@@ -655,6 +655,15 @@ namespace dss {
     return pd.get<uint32_t>();
   } // getPowerConsumption
 
+  void DS485Proxy::requestPowerConsumption() {
+    DS485CommandFrame cmdFrame;
+    cmdFrame.getHeader().setDestination(0);
+    cmdFrame.getHeader().setBroadcast(true);
+    cmdFrame.setCommand(CommandRequest);
+    cmdFrame.getPayload().add<uint8_t>(FunctionDSMeterGetPowerConsumption);
+    sendFrame(cmdFrame);
+  } // requestPowerConsumption
+
   unsigned long DS485Proxy::getEnergyMeterValue(const int _dsMeterID) {
     DS485CommandFrame cmdFrame;
     cmdFrame.getHeader().setDestination(_dsMeterID);
@@ -672,6 +681,15 @@ namespace dss {
     return pd.get<uint32_t>();
   } // getEnergyMeterValue
 
+  void DS485Proxy::requestEnergyMeterValue() {
+    DS485CommandFrame cmdFrame;
+    cmdFrame.getHeader().setDestination(0);
+    cmdFrame.getHeader().setBroadcast(true);
+    cmdFrame.setCommand(CommandRequest);
+    cmdFrame.getPayload().add<uint8_t>(FunctionDSMeterGetEnergyMeterValue);
+    sendFrame(cmdFrame);
+  } // requestEnergyMeterValue
+
   bool DS485Proxy::getEnergyBorder(const int _dsMeterID, int& _lower, int& _upper) {
     DS485CommandFrame cmdFrame;
     cmdFrame.getHeader().setDestination(_dsMeterID);
diff --git a/core/ds485/ds485proxy.h b/core/ds485/ds485proxy.h
index 6003663..50e6b62 100644
--- a/core/ds485/ds485proxy.h
+++ b/core/ds485/ds485proxy.h
@@ -142,6 +142,8 @@ namespace dss {
 
     virtual unsigned long getPowerConsumption(const int _dsMeterID);
     virtual unsigned long getEnergyMeterValue(const int _dsMeterID);
+    virtual void requestEnergyMeterValue();
+    virtual void requestPowerConsumption();
     virtual bool getEnergyBorder(const int _dsMeterID, int& _lower, int& _upper);
 
     //------------------------------------------------ UDI
diff --git a/core/dss.cpp b/core/dss.cpp
index a89be29..d137c5f 100644
--- a/core/dss.cpp
+++ b/core/dss.cpp
@@ -169,7 +169,7 @@ const char* WebrootDirectory = "data/webroot";
 
     m_pBusDispatcher = boost::shared_ptr<DS485BusRequestDispatcher>(new DS485BusRequestDispatcher());
     m_pBusDispatcher->setFrameSender(m_pDS485Interface->getFrameSenderInterface());
-    
+
     m_pApartment->setDS485Interface(m_pDS485Interface.get());
     m_pApartment->setBusRequestDispatcher(m_pBusDispatcher.get());
 
@@ -193,6 +193,8 @@ const char* WebrootDirectory = "data/webroot";
 
     m_pMetering = boost::shared_ptr<Metering>(new Metering(this));
     m_Subsystems.push_back(m_pMetering.get());
+    m_pMetering->setMeteringBusInterface(m_pDS485Interface->getMeteringBusInterface());
+    m_pModelMaintenance->setMetering(m_pMetering.get());
 
     m_pFakeMeter = boost::shared_ptr<FakeMeter>(new FakeMeter(this));
     m_Subsystems.push_back(m_pFakeMeter.get());
@@ -246,12 +248,12 @@ const char* WebrootDirectory = "data/webroot";
       boost::shared_ptr<dss::LogTarget>
         logTarget(new dss::FileLogTarget(logFileName));
       if (!dss::Logger::getInstance()->setLogTarget(logTarget)) {
-        Logger::getInstance()->log("Failed to open logfile '" + 
+        Logger::getInstance()->log("Failed to open logfile '" +
                                    logFileName + "'", lsFatal);
         return false;
       }
     } else {
-      Logger::getInstance()->log("No logfile configured, logging to stdout", 
+      Logger::getInstance()->log("No logfile configured, logging to stdout",
                                  lsInfo);
     }
 
diff --git a/core/metering/fake_meter.cpp b/core/metering/fake_meter.cpp
index fb60d1e..2ce4fc4 100644
--- a/core/metering/fake_meter.cpp
+++ b/core/metering/fake_meter.cpp
@@ -98,7 +98,7 @@ namespace dss {
       unsigned long consumption = 0;
       foreach(DSMeter* dsMeter, getDSS().getApartment().getDSMeters()) {
         try {
-      	  consumption += dsMeter->getPowerConsumption();
+      	  consumption += dsMeter->getCachedPowerConsumption();
         } catch(std::runtime_error& err) {
           log("Could not poll dsMeter " + dsMeter->getDSID().toString() + ". Message: " + err.what());
         }
diff --git a/core/metering/metering.cpp b/core/metering/metering.cpp
index 86855d0..3a5802d 100644
--- a/core/metering/metering.cpp
+++ b/core/metering/metering.cpp
@@ -45,27 +45,29 @@ namespace dss {
 
   Metering::Metering(DSS* _pDSS)
   : Subsystem(_pDSS, "Metering"),
-    Thread("Metering")
+    Thread("Metering"),
+    m_pMeteringBusInterface(NULL)
   {
     getDSS().getPropertySystem().setStringValue(getConfigPropertyBasePath() + "storageLocation", getDSS().getWebrootDirectory() + "metering/", true);
-    boost::shared_ptr<MeteringConfigChain> configConsumption(new MeteringConfigChain(false, 1, "mW"));
-    configConsumption->setComment("Consumption in mW");
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_seconds",        2, 400)));
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_10seconds",     10, 400)));
-//    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_minutely",  1 * 60, 400)));
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_5minutely", 5 * 60, 400)));
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_halfhourly",30 * 60, 400)));
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_2hourly", 2 * 60*60, 400)));
-    configConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_daily",  24 * 60*60, 400)));
-    m_Config.push_back(configConsumption);
-
-    boost::shared_ptr<MeteringConfigChain> configEnergy(new MeteringConfigChain(true, 60, "Wh"));
-    configEnergy->setComment("Energymeter value");
-    configEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_minutely",  1 * 60, 400)));
-    configEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_5minutely", 5 * 60, 400)));
-    configEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_hourly",   60 * 60, 400)));
-    configEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_daily", 24 * 60*60, 400)));
-    m_Config.push_back(configEnergy);
+    m_ConfigConsumption.reset(new MeteringConfigChain(false, 1, "mW"));
+    m_ConfigConsumption->setComment("Consumption in mW");
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_seconds",        2, 400)));
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_10seconds",     10, 400)));
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_5minutely", 5 * 60, 400)));
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_halfhourly",30 * 60, 400)));
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_2hourly", 2 * 60*60, 400)));
+    m_ConfigConsumption->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("consumption_daily",  24 * 60*60, 400)));
+    m_Config.push_back(m_ConfigConsumption.get());
+    m_ConfigConsumption->running();
+
+    m_ConfigEnergy.reset(new MeteringConfigChain(true, 60, "Wh"));
+    m_ConfigEnergy->setComment("Energymeter value");
+    m_ConfigEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_minutely",  1 * 60, 400)));
+    m_ConfigEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_5minutely", 5 * 60, 400)));
+    m_ConfigEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_hourly",   60 * 60, 400)));
+    m_ConfigEnergy->addConfig(boost::shared_ptr<MeteringConfig>(new MeteringConfig("energy_daily", 24 * 60*60, 400)));
+    m_Config.push_back(m_ConfigEnergy.get());
+    m_ConfigEnergy->running();
   } // metering
 
   void Metering::doStart() {
@@ -76,167 +78,168 @@ namespace dss {
 
 //#define LOG_TIMING
 
-  void Metering::checkDSMeters(boost::shared_ptr<MeteringConfigChain> _config) {
+  void Metering::processValue(MeteringValue _value, boost::shared_ptr<MeteringConfigChain> _config) {
     SeriesReader<CurrentValue> reader;
     SeriesWriter<CurrentValue> writer;
 
     _config->running();
-#ifdef LOG_TIMING
+    #ifdef LOG_TIMING
     std::ostringstream logSStream;
-#endif
-
-#ifdef LOG_TIMING
-    Timestamp checkingAll;
-#endif
-    std::vector<DSMeter*>& dsMeters = DSS::getInstance()->getApartment().getDSMeters();
-    for(std::vector<DSMeter*>::iterator ipDSMeter = dsMeters.begin(), e = dsMeters.end();
-        ipDSMeter != e; ++ipDSMeter)
-    {
-      if(!(*ipDSMeter)->isPresent()) {
-        continue;
-      }
-#ifdef LOG_TIMING
-      Timestamp checkingDSMeter;
-      Timestamp startedLoading;
-#endif
-      std::vector<boost::shared_ptr<Series<CurrentValue> > > series;
-      for(int iConfig = 0; iConfig < _config->size(); iConfig++) {
-        // Load series from file
-        std::string fileName = m_MeteringStorageLocation + (*ipDSMeter)->getDSID().toString() + "_" + _config->getFilenameSuffix(iConfig) + ".xml";
-        log("Metering::checkDSMeters: Trying to load series from '" + fileName + "'");
-        if(boost::filesystem::exists(fileName)) {
-          Timestamp startedLoadingSingle;
-          boost::shared_ptr<Series<CurrentValue> > s = boost::shared_ptr<Series<CurrentValue> >(reader.readFromXML(fileName));
-#ifdef LOG_TIMING
-          logSStream << "loading single: " << Timestamp().getDifference(startedLoadingSingle);
-          log(logSStream.str());
-          logSStream.str("");
-#endif
-          if(s.get() != NULL) {
-            series.push_back(s);
-          } else {
-            log("Metering::checkDSMeters: Failed to load series");
-            return; // TODO: another strategy would be moving the file out of our way and just create an empty one
-          }
+    #endif
+
+    #ifdef LOG_TIMING
+    Timestamp checkingDSMeter;
+    Timestamp startedLoading;
+    #endif
+    std::vector<boost::shared_ptr<Series<CurrentValue> > > series;
+    for(int iConfig = 0; iConfig < _config->size(); iConfig++) {
+      // Load series from file
+      std::string fileName = m_MeteringStorageLocation + _value.getDSMeter().getDSID().toString() + "_" + _config->getFilenameSuffix(iConfig) + ".xml";
+      log("Metering::processValue: Trying to load series from '" + fileName + "'");
+      if(boost::filesystem::exists(fileName)) {
+        Timestamp startedLoadingSingle;
+        boost::shared_ptr<Series<CurrentValue> > s = boost::shared_ptr<Series<CurrentValue> >(reader.readFromXML(fileName));
+        #ifdef LOG_TIMING
+        logSStream << "loading single: " << Timestamp().getDifference(startedLoadingSingle);
+        log(logSStream.str());
+        logSStream.str("");
+        #endif
+        if(s.get() != NULL) {
+          series.push_back(s);
         } else {
-          boost::shared_ptr<Series<CurrentValue> > newSeries((new Series<CurrentValue>(_config->getResolution(iConfig), _config->getNumberOfValues(iConfig))));
-          newSeries->setUnit(_config->getUnit());
-          newSeries->setComment(_config->getComment());
-          newSeries->setFromDSID((*ipDSMeter)->getDSID());
-          series.push_back(newSeries);
+          log("Metering::processValue: Failed to load series");
+          return; // TODO: another strategy would be moving the file out of our way and just create an empty one
         }
+      } else {
+        boost::shared_ptr<Series<CurrentValue> > newSeries((new Series<CurrentValue>(_config->getResolution(iConfig), _config->getNumberOfValues(iConfig))));
+        newSeries->setUnit(_config->getUnit());
+        newSeries->setComment(_config->getComment());
+        newSeries->setFromDSID(_value.getDSMeter().getDSID());
+        series.push_back(newSeries);
       }
-#ifdef LOG_TIMING
-      logSStream << "loading: " << Timestamp().getDifference(startedLoading);
-      log(logMessage.str());
-      logSStream.str("");
-#endif
+    }
+    #ifdef LOG_TIMING
+    logSStream << "loading: " << Timestamp().getDifference(startedLoading);
+    log(logMessage.str());
+    logSStream.str("");
+    #endif
 
-      // stitch up chain
-      for(std::vector<boost::shared_ptr<Series<CurrentValue> > >::reverse_iterator iSeries = series.rbegin(), e = series.rend();
-          iSeries != e; ++iSeries)
-      {
-        if(iSeries != series.rbegin()) {
-          (*iSeries)->setNextSeries(boost::prior(iSeries)->get());
-        }
+    // stitch up chain
+    for(std::vector<boost::shared_ptr<Series<CurrentValue> > >::reverse_iterator iSeries = series.rbegin(), e = series.rend();
+    iSeries != e; ++iSeries)
+    {
+      if(iSeries != series.rbegin()) {
+        (*iSeries)->setNextSeries(boost::prior(iSeries)->get());
       }
-      if(series.empty()) {
-        log("Metering::checkDSMeters: No series configured, check your config");
-      } else {
-        log("Metering::checkDSMeters: Series loaded, updating");
-        // Update series
-
-        unsigned long value;
-        DateTime timeRequested;
-#ifdef LOG_TIMING
-        Timestamp fetchingValue;
-#endif
-        try {
-          if(_config->isEnergy()) {
-            value = (*ipDSMeter)->getEnergyMeterValue();
-          } else {
-            value = (*ipDSMeter)->getPowerConsumption();
-          }
-        } catch(std::runtime_error& err) {
-          log("Could not poll dsMeter " + (*ipDSMeter)->getDSID().toString() + ". Message: " + err.what());
-        }
-#ifdef LOG_TIMING
-        logSStream << "fetching value: " << Timestamp().getDifference(fetchingValue);
-        log(logSStream.str());
-        logSStream.str("");
-#endif
-
-#ifdef LOG_TIMING
-        Timestamp startedAddingValue;
-#endif
-        series[0]->addValue(value, timeRequested);
-#ifdef LOG_TIMING
-        logSStream << "adding value: " << Timestamp().getDifference(startedAddingValue);
-        log(logSStream.str());
-        logSStream.str("");
-#endif
+    }
+    if(series.empty()) {
+      log("Metering::processValue: No series configured, check your config");
+    } else {
+      log("Metering::processValue: Series loaded, updating");
+
+      // Update series
+      #ifdef LOG_TIMING
+      Timestamp startedAddingValue;
+      #endif
+      series[0]->addValue(_value.getValue(), _value.getSampledAt());
+      #ifdef LOG_TIMING
+      logSStream << "adding value: " << Timestamp().getDifference(startedAddingValue);
+      log(logSStream.str());
+      logSStream.str("");
+      #endif
 
-#ifdef LOG_TIMING
-        Timestamp startedWriting;
-#endif
-        // Store series
-        log("Metering::checkDSMeters: Writing series back...");
-        for(int iConfig = 0; iConfig < _config->size(); iConfig++) {
-#ifdef LOG_TIMING
-          Timestamp startedWritingSingle;
-#endif
-          // Write series to file
-          std::string fileName = m_MeteringStorageLocation + (*ipDSMeter)->getDSID().toString() + "_" + _config->getFilenameSuffix(iConfig) + ".xml";
-          Series<CurrentValue>* s = series[iConfig].get();
-          log("Metering::checkDSMeters: Trying to save series to '" + fileName + "'");
-          writer.writeToXML(*s, fileName);
-#ifdef LOG_TIMING
-          logSStream << "writing single: " << Timestamp().getDifference(startedWritingSingle) << endl;
-          log(logSStream.str());
-          logSStream.str("");
-#endif
-        }
-#ifdef LOG_TIMING
-        logSStream << "writing: " << Timestamp().getDifference(startedWriting) << endl;
+      #ifdef LOG_TIMING
+      Timestamp startedWriting;
+      #endif
+      // Store series
+      log("Metering::processValue: Writing series back...");
+      for(int iConfig = 0; iConfig < _config->size(); iConfig++) {
+        #ifdef LOG_TIMING
+        Timestamp startedWritingSingle;
+        #endif
+        // Write series to file
+        std::string fileName = m_MeteringStorageLocation + _value.getDSMeter().getDSID().toString() + "_" + _config->getFilenameSuffix(iConfig) + ".xml";
+        Series<CurrentValue>* s = series[iConfig].get();
+        log("Metering::processValue: Trying to save series to '" + fileName + "'");
+        writer.writeToXML(*s, fileName);
+        #ifdef LOG_TIMING
+        logSStream << "writing single: " << Timestamp().getDifference(startedWritingSingle) << endl;
         log(logSStream.str());
         logSStream.str("");
-#endif
+        #endif
       }
-#ifdef LOG_TIMING
-      logSStream << "checkingDSMeter: " << Timestamp().getDifference(checkingDSMeter) << endl;
+      #ifdef LOG_TIMING
+      logSStream << "writing: " << Timestamp().getDifference(startedWriting) << endl;
       log(logSStream.str());
       logSStream.str("");
-#endif
+      #endif
     }
-#ifdef LOG_TIMING
-    logSStream << "checking all: " << Timestamp().getDifference(checkingAll) << endl;
+    #ifdef LOG_TIMING
+    logSStream << "checkingDSMeter: " << Timestamp().getDifference(checkingDSMeter) << endl;
     log(logSStream.str());
     logSStream.str("");
-#endif
+    #endif
+  } // processValue
+
+  void Metering::checkDSMeters(MeteringConfigChain* _pConfig) {
+    if(_pConfig->isConsumption()) {
+      m_pMeteringBusInterface->requestPowerConsumption();
+    } else {
+      m_pMeteringBusInterface->requestEnergyMeterValue();
+    }
+    _pConfig->running();
   } // checkDSMeters
 
   //#undef LOG_TIMING
 
   void Metering::execute() {
+    if(m_pMeteringBusInterface == NULL) {
+      throw std::runtime_error("Missing bus interface");
+    }
     // check dsMeters periodically
     while(DSS::getInstance()->getModelMaintenance().isInitializing()) {
       sleepSeconds(1);
     }
     while(!m_Terminated) {
-      int sleepTimeSec = 60000;
+      int sleepTimeMSec = 60000 * 1000;
 
-      log("Metering::execute: Checking dsMeters");
       for(unsigned int iConfig = 0; iConfig < m_Config.size(); iConfig++) {
         if(m_Config[iConfig]->needsRun()) {
           checkDSMeters(m_Config[iConfig]);
         }
-        sleepTimeSec = std::min(sleepTimeSec, m_Config[iConfig]->getCheckIntervalSeconds());
+        sleepTimeMSec = std::min(sleepTimeMSec, 1000 * m_Config[iConfig]->getCheckIntervalSeconds());
       }
-      log("Metering::execute: Done checking dsMeters");
-      sleepSeconds(sleepTimeSec);
+      DateTime startedSleeping;
+      DateTime doneSleepingBy = DateTime().addSeconds(sleepTimeMSec / 1000);
+      do {
+        processValues(m_EnergyValues, m_ConfigEnergy);
+        processValues(m_ConsumptionValues, m_ConfigConsumption);
+        sleepMS(100); // wait roughly one token hold-time for new events
+      } while(DateTime().before(doneSleepingBy));
     }
   } // execute
 
+  void Metering::processValues(std::vector<MeteringValue>& _values, boost::shared_ptr<MeteringConfigChain> _config) {
+    while(!_values.empty()) {
+      m_ValuesMutex.lock();
+      MeteringValue value = _values.front();
+      _values.erase(_values.begin());
+      m_ValuesMutex.unlock();
+      processValue(value, _config);
+    }
+  } // processValues
+
+  void Metering::postConsumptionEvent(dss::DSMeter& _meter, int _value, DateTime _sampledAt) {
+    m_ValuesMutex.lock();
+    m_ConsumptionValues.push_back(MeteringValue(&_meter, _value, _sampledAt));
+    m_ValuesMutex.unlock();
+  } // postConsumptionEvent
+
+  void Metering::postEnergyEvent(dss::DSMeter& _meter, int _value, DateTime _sampledAt) {
+    m_ValuesMutex.lock();
+    m_EnergyValues.push_back(MeteringValue(&_meter, _value, _sampledAt));
+    m_ValuesMutex.unlock();
+  } // postEnergyEvent
 
   //================================================== MeteringConfigChain
 
@@ -245,7 +248,7 @@ namespace dss {
   } // addConfig
 
   bool MeteringConfigChain::needsRun() const {
-    return  DateTime().difference(m_LastRun) >= m_CheckIntervalSeconds;
+    return DateTime().difference(m_LastRun) >= m_CheckIntervalSeconds;
   }
 
   void MeteringConfigChain::running() {
diff --git a/core/metering/metering.h b/core/metering/metering.h
index 9efecbd..95d195e 100644
--- a/core/metering/metering.h
+++ b/core/metering/metering.h
@@ -26,6 +26,7 @@
 #include "core/thread.h"
 #include "core/subsystem.h"
 #include "core/datetools.h"
+#include "core/mutex.h"
 
 #include <string>
 #include <vector>
@@ -35,6 +36,23 @@ namespace dss {
 
   class MeteringConfig;
   class MeteringConfigChain;
+  class DSMeter;
+  class MeteringValue;
+  class MeteringBusInterface;
+
+  class MeteringValue {
+  public:
+    MeteringValue(DSMeter* _pMeter, int _value, DateTime& _sampledAt)
+    : m_pMeter(_pMeter), m_Value(_value), m_SampledAt(_sampledAt)
+    {}
+    DSMeter& getDSMeter() const { return *m_pMeter; }
+    int getValue() const { return m_Value; }
+    const DateTime& getSampledAt() const { return m_SampledAt; }
+  private:
+    DSMeter* m_pMeter;
+    int m_Value;
+    DateTime m_SampledAt;
+  };
 
   class Metering : public Subsystem,
                    private Thread {
@@ -42,9 +60,17 @@ namespace dss {
     int m_MeterEnergyCheckIntervalSeconds;
     int m_MeterConsumptionCheckIntervalSeconds;
     std::string m_MeteringStorageLocation;
-    std::vector<boost::shared_ptr<MeteringConfigChain> > m_Config;
+    boost::shared_ptr<MeteringConfigChain> m_ConfigEnergy;
+    boost::shared_ptr<MeteringConfigChain> m_ConfigConsumption;
+    std::vector<MeteringConfigChain*> m_Config;
+    std::vector<MeteringValue> m_ConsumptionValues;
+    std::vector<MeteringValue> m_EnergyValues;
+    Mutex m_ValuesMutex;
+    MeteringBusInterface* m_pMeteringBusInterface;
+    void processValue(MeteringValue _value, boost::shared_ptr<MeteringConfigChain> _config);
+    void processValues(std::vector<MeteringValue>& _values, boost::shared_ptr<MeteringConfigChain> _config);
   private:
-    void checkDSMeters(boost::shared_ptr<MeteringConfigChain> _config);
+    void checkDSMeters(MeteringConfigChain* _pConfig);
 
     virtual void execute();
   protected:
@@ -52,9 +78,12 @@ namespace dss {
   public:
     Metering(DSS* _pDSS);
     virtual ~Metering() {};
-    
-    const std::vector<boost::shared_ptr<MeteringConfigChain> > getConfig() const { return m_Config; }
+
+    const std::vector<MeteringConfigChain*> getConfig() const { return m_Config; }
     const std::string& getStorageLocation() const { return m_MeteringStorageLocation; }
+    void postConsumptionEvent(dss::DSMeter& _meter, int _value, DateTime _sampledAt);
+    void postEnergyEvent(dss::DSMeter& _meter, int _value, DateTime _sampledAt);
+    void setMeteringBusInterface(MeteringBusInterface* _value) { m_pMeteringBusInterface = _value; }
   }; // Metering
 
   class MeteringConfig {
@@ -84,7 +113,8 @@ namespace dss {
     std::vector<boost::shared_ptr<MeteringConfig> > m_Chain;
   public:
     MeteringConfigChain(bool _isEnergy, int _checkIntervalSeconds, const std::string& _unit)
-    : m_IsEnergy(_isEnergy), m_CheckIntervalSeconds(_checkIntervalSeconds), m_Unit(_unit)
+    : m_IsEnergy(_isEnergy), m_CheckIntervalSeconds(_checkIntervalSeconds),
+      m_LastRun(DateTime()), m_Unit(_unit)
     { }
 
     void addConfig(boost::shared_ptr<MeteringConfig> _config);
diff --git a/core/model/modelmaintenance.cpp b/core/model/modelmaintenance.cpp
index 8b204ff..89375c0 100644
--- a/core/model/modelmaintenance.cpp
+++ b/core/model/modelmaintenance.cpp
@@ -33,6 +33,7 @@
 #include "core/propertysystem.h"
 #include "core/ds485const.h"
 #include "core/model/modelconst.h"
+#include "core/metering/metering.h"
 
 
 #include "apartment.h"
@@ -50,7 +51,9 @@ namespace dss {
   ModelMaintenance::ModelMaintenance(DSS* _pDSS)
   : Subsystem(_pDSS, "Apartment"),
     Thread("Apartment"),
-    m_IsInitializing(true)
+    m_IsInitializing(true),
+    m_pApartment(NULL),
+    m_pMetering(NULL)
   { }
 
   void ModelMaintenance::initialize() {
@@ -194,20 +197,22 @@ namespace dss {
         if(event.getParameterCount() != 2) {
           log("Expected exactly 2 parameter for ModelEvent::etPowerConsumption");
         } else {
-	  int meterID = event.getParameter(0);
-	  int consumption = event.getParameter(1);
-	  DSMeter& meter = m_pApartment->getDSMeterByBusID(meterID);
-	  meter.setPowerConsumption(consumption);
+          int meterID = event.getParameter(0);
+          int value = event.getParameter(1);
+          DSMeter& meter = m_pApartment->getDSMeterByBusID(meterID);
+          meter.setPowerConsumption(value);
+          m_pMetering->postConsumptionEvent(meter, value, DateTime());
         }
         break;
       case ModelEvent::etEnergyMeterValue:
         if(event.getParameterCount() != 2) {
           log("Expected exactly 2 parameter for ModelEvent::etEnergyMeterValue");
         } else {
-	  int meterID = event.getParameter(0);
-	  int value = event.getParameter(1);
-	  DSMeter& meter = m_pApartment->getDSMeterByBusID(meterID);
-	  meter.setEnergyMeterValue(value);
+          int meterID = event.getParameter(0);
+          int value = event.getParameter(1);
+          DSMeter& meter = m_pApartment->getDSMeterByBusID(meterID);
+          meter.setEnergyMeterValue(value);
+          m_pMetering->postEnergyEvent(meter, value, DateTime());
         }
         break;
       case ModelEvent::etDS485DeviceDiscovered:
@@ -527,4 +532,9 @@ namespace dss {
     }
   } // setApartment
 
+  void ModelMaintenance::setMetering(Metering* _value) {
+    m_pMetering = _value;
+  } // setMetering
+
+
 } // namespace dss
diff --git a/core/model/modelmaintenance.h b/core/model/modelmaintenance.h
index 7a40567..76b10f6 100644
--- a/core/model/modelmaintenance.h
+++ b/core/model/modelmaintenance.h
@@ -36,6 +36,7 @@ namespace dss {
   class Apartment;
   class ModelEvent;
   class Event;
+  class Metering;
 
 
   class ModelMaintenance : public Subsystem,
@@ -51,21 +52,14 @@ namespace dss {
      */
     void addModelEvent(ModelEvent* _pEvent);
 
-    /** Called by the DS485Proxy if a group-call-scene frame was intercepted.
-     *  Updates the state of all devices contained in the group. */
-    void onGroupCallScene(const int _zoneID, const int _groupID, const int _sceneID);
-    /** Called by the DS485Proxy if a device-call-scene frame was intercepted.
-     *  Updates the state of the device. */
-    void onDeviceCallScene(const int _dsMeterID, const int _deviceID, const int _sceneID);
-    /** Called by the DS485Proxy if an add-device frame was intercepted.
-     *  Adds the device to the model. */
-    void onAddDevice(const int _modID, const int _zoneID, const int _devID, const int _functionID);
-    void onDSLinkInterrupt(const int _modID, const int _devID, const int _priority);
     /** Starts the event-processing */
     virtual void execute();
 
+    void onGroupCallScene(const int _zoneID, const int _groupID, const int _sceneID);
+
     bool isInitializing() const { return m_IsInitializing; }
     void setApartment(Apartment* _value);
+    void setMetering(Metering* _value);
   protected:
     virtual void doStart();
   private:
@@ -78,6 +72,10 @@ namespace dss {
     void writeConfiguration();
 
     void raiseEvent(boost::shared_ptr<Event> _pEvent);
+
+    void onDeviceCallScene(const int _dsMeterID, const int _deviceID, const int _sceneID);
+    void onAddDevice(const int _modID, const int _zoneID, const int _devID, const int _functionID);
+    void onDSLinkInterrupt(const int _modID, const int _devID, const int _priority);
   private:
     bool m_IsInitializing;
 
@@ -87,6 +85,7 @@ namespace dss {
     Mutex m_ModelEventsMutex;
     SyncEvent m_NewModelEvent;
     Apartment* m_pApartment;
+    Metering* m_pMetering;
   }; // ModelMaintenance
 
 }
diff --git a/core/model/modulator.cpp b/core/model/modulator.cpp
index fc76ad4..a2bba60 100644
--- a/core/model/modulator.cpp
+++ b/core/model/modulator.cpp
@@ -29,6 +29,7 @@
 
 namespace dss {
 
+
   //================================================== DSMeter
 
   DSMeter::DSMeter(const dsid_t _dsid)
@@ -89,7 +90,6 @@ namespace dss {
     return m_EnergyMeterValue;
   } // getEnergyMeterValue
 
-
   /** set the consumption in mW */
   void DSMeter::setPowerConsumption(unsigned long _value) {
     DateTime now;
@@ -112,5 +112,4 @@ namespace dss {
     return m_EnergyMeterValue;
   } // getEnergyMeterValue
 
-
 } // namespace dss
diff --git a/core/web/handler/meteringrequesthandler.cpp b/core/web/handler/meteringrequesthandler.cpp
index 26a1f58..b9b23f4 100644
--- a/core/web/handler/meteringrequesthandler.cpp
+++ b/core/web/handler/meteringrequesthandler.cpp
@@ -41,7 +41,7 @@ namespace dss {
 
 
   //=========================================== MeteringRequestHandler
-  
+
   MeteringRequestHandler::MeteringRequestHandler(Apartment& _apartment, Metering& _metering)
   : m_Apartment(_apartment),
     m_Metering(_metering)
@@ -50,12 +50,12 @@ namespace dss {
 
   boost::shared_ptr<JSONObject> MeteringRequestHandler::jsonHandleRequest(const RestfulRequest& _request, Session* _session) {
     if(_request.getMethod() == "getResolutions") {
-      std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = m_Metering.getConfig();
+      std::vector<MeteringConfigChain*> meteringConfig = m_Metering.getConfig();
       boost::shared_ptr<JSONObject> resultObj(new JSONObject());
       boost::shared_ptr<JSONArrayBase> resolutions(new JSONArrayBase());
       resultObj->addElement("resolutions", resolutions);
 
-      foreach(boost::shared_ptr<MeteringConfigChain> pChain, meteringConfig) {
+      foreach(MeteringConfigChain* pChain, meteringConfig) {
         for(int iConfig = 0; iConfig < pChain->size(); iConfig++) {
           boost::shared_ptr<JSONObject> resolution(new JSONObject());
           resolutions->addElement("", resolution);
@@ -124,10 +124,10 @@ namespace dss {
         }
       }
       if(!resolutionString.empty()) {
-        std::vector<boost::shared_ptr<MeteringConfigChain> > meteringConfig = m_Metering.getConfig();
+        std::vector<MeteringConfigChain*> meteringConfig = m_Metering.getConfig();
         storageLocation = m_Metering.getStorageLocation();
         for(unsigned int iConfig = 0; iConfig < meteringConfig.size(); iConfig++) {
-          boost::shared_ptr<MeteringConfigChain> cConfig = meteringConfig[iConfig];
+          MeteringConfigChain* cConfig = meteringConfig[iConfig];
           for(int jConfig = 0; jConfig < cConfig->size(); jConfig++) {
             if(cConfig->isEnergy() == energy && cConfig->getResolution(jConfig) == resolution) {
               fileSuffix = cConfig->getFilenameSuffix(jConfig);


hooks/post-receive
-- 
digitalSTROM Server


More information about the dss-commits mailing list