Meter::Meter(std::list<Option> pOptions) : _name("meter") { id = instances++; OptionList optlist; // set meter name std::stringstream oss; oss<<"mtr"<< id; _name = oss.str(); //optlist.dump(pOptions); try { // protocol const char *protocol_str = optlist.lookup_string(pOptions, "protocol"); print(log_debug, "Creating new meter with protocol %s.", name(), protocol_str); if (meter_lookup_protocol(protocol_str, &_protocol_id) != SUCCESS) { //print(log_error, "Invalid protocol: %s", mtr, protocol_str); //return ERR; /* skipping this meter */ throw vz::VZException("Protocol not found."); } } catch (vz::VZException &e) { std::stringstream oss; oss << e.what(); print(log_error, "Missing protocol or invalid type (%s)", name(), oss.str().c_str()); throw; } try { // interval Option interval_opt = optlist.lookup(pOptions, "interval"); _interval = (int)(interval_opt); } catch (vz::OptionNotFoundException &e) { _interval = -1; /* indicates unknown interval */ } catch (vz::VZException &e) { print(log_error, "Invalid type for interval", name()); throw; } try { // aggregation time Option interval_opt = optlist.lookup(pOptions, "aggtime"); _aggtime = (int)(interval_opt); } catch (vz::OptionNotFoundException &e) { _aggtime = -1; /* indicates no aggregation */ } catch (vz::VZException &e) { print(log_error, "Invalid type for aggtime", name()); throw; } try { _aggFixedInterval = optlist.lookup_bool(pOptions, "aggfixedinterval"); } catch (vz::OptionNotFoundException &e) { _aggFixedInterval = false; } catch (vz::VZException &e) { print(log_error, "Invalid type for aggfixedinterval", name()); throw; } try{ const meter_details_t *details = meter_get_details(_protocol_id); if (details->periodic == true && _interval < 0) { print(log_error, "Interval has to be set and positive!", name()); } } catch (vz::VZException &e) { std::stringstream oss; oss << e.what(); print(log_error, "Missing protocol or invalid type (%s)", name(), oss.str().c_str()); throw; } switch(_protocol_id) { case meter_protocol_file: _protocol = vz::protocol::Protocol::Ptr(new MeterFile(pOptions)); _identifier = ReadingIdentifier::Ptr(new StringIdentifier()); break; case meter_protocol_exec: _protocol = vz::protocol::Protocol::Ptr(new MeterExec(pOptions)); _identifier = ReadingIdentifier::Ptr(new StringIdentifier()); break; case meter_protocol_random: _protocol = vz::protocol::Protocol::Ptr(new MeterRandom(pOptions)); _identifier = ReadingIdentifier::Ptr(new NilIdentifier()); break; case meter_protocol_s0: _protocol = vz::protocol::Protocol::Ptr(new MeterS0(pOptions)); _identifier = ReadingIdentifier::Ptr(new StringIdentifier()); break; case meter_protocol_d0: _protocol = vz::protocol::Protocol::Ptr(new MeterD0(pOptions)); _identifier = ReadingIdentifier::Ptr(new ObisIdentifier()); break; #ifdef SML_SUPPORT case meter_protocol_sml: _protocol = vz::protocol::Protocol::Ptr(new MeterSML(pOptions)); _identifier = ReadingIdentifier::Ptr(new ObisIdentifier()); break; #endif case meter_protocol_fluksov2: _protocol = vz::protocol::Protocol::Ptr(new MeterFluksoV2(pOptions)); _identifier = ReadingIdentifier::Ptr(new ChannelIdentifier()); break; #ifdef OCR_SUPPORT case meter_protocol_ocr: _protocol = vz::protocol::Protocol::Ptr(new MeterOCR(pOptions)); _identifier = ReadingIdentifier::Ptr(new StringIdentifier()); break; #endif case meter_protocol_w1therm: _protocol = vz::protocol::Protocol::Ptr(new MeterW1therm(pOptions)); _identifier = ReadingIdentifier::Ptr(new StringIdentifier()); break; #ifdef OMS_SUPPORT case meter_protocol_oms: _protocol = vz::protocol::Protocol::Ptr(new MeterOMS(pOptions)); _identifier = ReadingIdentifier::Ptr(new ObisIdentifier()); break; #endif default: break; } try { // enable _enable = optlist.lookup_bool(pOptions, "enabled"); } catch (vz::OptionNotFoundException &e) { _enable = false; /* bye default meter is disabled */ } catch (vz::VZException &e) { print(log_error, "Invalid type for enable", name()); throw; } try { // skip _skip = optlist.lookup_bool(pOptions, "allowskip"); } catch (vz::OptionNotFoundException &e) { _skip = false; /* by default meter will throw an exception if opening fails */ } catch (vz::VZException &e) { print(log_error, "Invalid type for allowskip", name()); throw; } print(log_debug, "Meter configured, %s.", name(), _enable ? "enabled" : "disabled"); }
void * reading_thread(void *arg) { std::vector<Reading> rds; MeterMap *mapping = static_cast<MeterMap *>(arg); Meter::Ptr mtr = mapping->meter(); time_t aggIntEnd; const meter_details_t *details; size_t n = 0; details = meter_get_details(mtr->protocolId()); /* allocate memory for readings */ for (size_t i=0; i< details->max_readings; i++) { Reading rd(mtr->identifier()); rds.push_back(rd); } //pthread_cleanup_push(&reading_thread_cleanup, rds); print(log_debug, "Number of readers: %d", mtr->name(), details->max_readings); print(log_debug, "Config.daemon: %d", mtr->name(), options.daemon()); print(log_debug, "Config.local: %d", mtr->name(), options.local()); try { aggIntEnd = time(NULL); do { /* start thread main loop */ aggIntEnd += mtr->aggtime(); /* end of this aggregation period */ do { /* aggregate loop */ /* fetch readings from meter and calculate delta */ n = mtr->read(rds, details->max_readings); /* dumping meter output */ if (options.verbosity() > log_debug) { print(log_debug, "Got %i new readings from meter:", mtr->name(), n); char identifier[MAX_IDENTIFIER_LEN]; for (size_t i = 0; i < n; i++) { rds[i].unparse(/*mtr->protocolId(),*/ identifier, MAX_IDENTIFIER_LEN); print(log_debug, "Reading: id=%s/%s value=%.2f ts=%.3f", mtr->name(), identifier, rds[i].identifier()->toString().c_str(), rds[i].value(), rds[i].tvtod()); } } /* update buffer length with current interval */ // if (details->periodic == FALSE && delta > 0 && delta != mtr->interval()) { // print(log_debug, "Updating interval to %i", mtr->name(), delta); // mtr->interval(delta); // } /* insert readings into channel queues */ for (MeterMap::iterator ch = mapping->begin(); ch!=mapping->end(); ch++) { Reading *add = NULL; //print(log_debug, "Check channel %s, n=%d", mtr->name(), ch->name(), n); for (size_t i = 0; i < n; i++) { if (*rds[i].identifier().get() == *(*ch)->identifier().get()) { //print(log_debug, "found channel", mtr->name()); if ((*ch)->tvtod() < rds[i].tvtod()) { (*ch)->last(&rds[i]); } print(log_info, "Adding reading to queue (value=%.2f ts=%.3f)", (*ch)->name(), rds[i].value(), rds[i].tvtod()); (*ch)->push(rds[i]); if (add == NULL) { add = &rds[i]; /* remember first reading which has been added to the buffer */ } } } /* update buffer length */ if (options.local()) { (*ch)->buffer()->keep((mtr->interval() > 0) ? ceil(options.buffer_length() / mtr->interval()) : 0); } } // channel loop } while((mtr->aggtime() > 0) && (time(NULL) < aggIntEnd)); /* default aggtime is -1 */ for (MeterMap::iterator ch = mapping->begin(); ch!=mapping->end(); ch++) { /* aggregate buffer values if aggmode != NONE */ (*ch)->buffer()->aggregate(mtr->aggtime(), mtr->aggFixedInterval()); /* mark buffer "ready" */ (*ch)->buffer()->have_newValues(); /* shrink buffer */ (*ch)->buffer()->clean(); /* notify webserver and logging thread */ (*ch)->notify(); /* debugging */ if (options.verbosity() >= log_debug) { size_t dump_len = 24; char *dump = (char*)malloc(dump_len); if (dump == NULL) { print(log_error, "cannot allocate buffer", (*ch)->name()); } while (dump == NULL || (*ch)->dump(dump, dump_len) == NULL) { dump_len *= 1.5; free(dump); dump = (char*)malloc(dump_len); } print(log_debug, "Buffer dump (size=%i keep=%i): %s", (*ch)->name(), (*ch)->size(), (*ch)->keep(), dump); free(dump); } } if (mtr->interval() > 0) { print(log_info, "Next reading in %i seconds", mtr->name(), mtr->interval()); sleep(mtr->interval()); } } while (options.daemon() || options.local() || options.logging() ); } catch (std::exception &e) { std::stringstream oss; oss << e.what(); print(log_error, "Reading-THREAD - reading Got an exception : %s", mtr->name(), e.what()); pthread_exit(0); } print(log_debug, "Stop reading.! ", mtr->name()); //pthread_cleanup_pop(1); pthread_exit(0); return NULL; }