FACT++  1.0
tngweather.cc
Go to the documentation of this file.
1 #include <boost/array.hpp>
2 
3 #include <string> // std::string
4 #include <algorithm> // std::transform
5 #include <cctype> // std::tolower
6 
7 #include "FACT.h"
8 #include "Dim.h"
9 #include "Event.h"
10 #include "Shell.h"
11 #include "StateMachineDim.h"
12 #include "StateMachineAsio.h"
13 #include "Connection.h"
14 #include "LocalControl.h"
15 #include "Configuration.h"
16 #include "Timers.h"
17 #include "Console.h"
18 
19 #include "tools.h"
20 
21 #include "HeadersTNGWeather.h"
22 
23 #include <QtXml/QDomDocument>
24 
25 namespace ba = boost::asio;
26 namespace bs = boost::system;
27 namespace dummy = ba::placeholders;
28 
29 using namespace std;
30 using namespace TNGWeather;
31 
32 
33 class ConnectionWeather : public Connection
34 {
35  uint16_t fInterval;
36 
37  bool fIsVerbose;
38 
39  string fSite;
40 
41  virtual void UpdateWeather(const Time &, const DimWeather &)
42  {
43  }
44 
45  virtual void UpdateSeeing(const Time &, const DimSeeing &)
46  {
47  }
48 
49  virtual void UpdateDust(const Time &, const float &)
50  {
51  }
52 
53  string fRdfData;
54  float fDust;
55 
56 protected:
57 
58  boost::array<char, 4096> fArray;
59 
60  Time fLastReport;
61  Time fLastReception;
62 
64 
65  void HandleRead(const boost::system::error_code& err, size_t bytes_received)
66  {
67  // Do not schedule a new read if the connection failed.
68  if (bytes_received==0 || err)
69  {
70  if (err==ba::error::eof)
71  Warn("Connection closed by remote host.");
72 
73  // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
74  // 125: Operation canceled
75  if (err && err!=ba::error::eof && // Connection closed by remote host
76  err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
77  err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
78  {
79  ostringstream str;
80  str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
81  Error(str);
82  }
83  PostClose(err!=ba::error::basic_errors::operation_aborted);
84 
85  fRdfData = "";
86  return;
87  }
88 
89  fRdfData += string(fArray.data(), bytes_received);
90 
91  const size_t end = fRdfData.find("\r\n\r\n");
92  if (end==string::npos)
93  {
94  Out() << "Received data corrupted [1]." << endl;
95  Out() << fRdfData << endl;
96  return;
97  }
98 
99  string data(fRdfData);
100  data.erase(0, end+4);
101 
102  size_t pos = 0;
103  while (1)
104  {
105  const size_t chunk = data.find("\r\n", pos);
106  if (chunk==0 || chunk==string::npos)
107  {
108  StartReadReport();
109  return;
110  }
111 
112  size_t len = 0;
113  stringstream val(data.substr(pos, chunk-pos));
114  val >> hex >> len;
115 
116  data.erase(pos, chunk-pos+2);
117  if (len==0)
118  break;
119 
120  pos += len+2; // Count trailing \r\n of chunk
121  }
122 
123 
124  fLastReception = Time();
125  fRdfData = "";
126  PostClose(false);
127 
128  if (fIsVerbose)
129  {
130  Out() << "------------------------------------------------------" << endl;
131  Out() << data << endl;
132  Out() << "------------------------------------------------------" << endl;
133  }
134 
135  QDomDocument doc;
136  if (!doc.setContent(QString(data.data()), false))
137  {
138  Warn("Parsing of xml failed [0].");
139  PostClose(false);
140  return;
141  }
142 
143  if (fIsVerbose)
144  Out() << "Parsed:\n-------\n" << doc.toString().toStdString() << endl;
145 
146  const QDomElement root = doc.documentElement();
147  const QDomElement channel = root.firstChildElement("channel");
148  const QDomElement item = channel.firstChildElement("item");
149 
150  const QDomElement see = item.firstChildElement("tngw:dimmSeeing");
151  const QDomElement mjd = item.firstChildElement("tngw:dimmSeeing.date");
152  const QDomElement med = item.firstChildElement("tngw:dimmSeeing.median");
153  const QDomElement sdev = item.firstChildElement("tngw:dimmSeeing.stdev");
154  const QDomElement dust = item.firstChildElement("tngw:dustTotal");
155  const QDomElement trend = item.firstChildElement("tngw:trend");
156  const QDomElement pres = item.firstChildElement("tngw:airPressure");
157  const QDomElement dew = item.firstChildElement("tngw:dewPoint");
158  const QDomElement wdir = item.firstChildElement("tngw:windDirection");
159  const QDomElement speed = item.firstChildElement("tngw:windSpeed");
160  const QDomElement hum = item.firstChildElement("tngw:hum");
161  const QDomElement tmp = item.firstChildElement("tngw:temperature");
162  const QDomElement solar = item.firstChildElement("tngw:solarimeter");
163  const QDomElement date = item.firstChildElement("tngw:date");
164 
165  if (see.isNull() || mjd.isNull() || med.isNull() || sdev.isNull() ||
166  dust.isNull() || trend.isNull() || pres.isNull() || dew.isNull() ||
167  wdir.isNull() || speed.isNull() || hum.isNull() || tmp.isNull() ||
168  solar.isNull()|| date.isNull())
169  {
170  Warn("Parsing of xml failed [1].");
171  PostClose(false);
172  return;
173  }
174 
175  DimWeather w;
176  w.fDustTotal = dust .text().toFloat();
177  w.fTempTrend = trend.text().toFloat();
178  w.fAirPressure = pres .text().toFloat();
179  w.fDewPoint = dew .text().toFloat();
180  w.fWindDirection = wdir .text().toFloat();
181  w.fWindSpeed = speed.text().toFloat()*3.6;
182  w.fHumidity = hum .text().toFloat();
183  w.fTemperature = tmp .text().toFloat();
184  w.fSolarimeter = solar.text().toFloat();
185 
186  DimSeeing s;
187  s.fSeeing = see .text().toFloat();
188  s.fSeeingMed = med .text().toFloat();
189  s.fSeeingStdev = sdev .text().toFloat();
190 
191  const string dateObj = date.text().toStdString();
192  const string dateSee = mjd .text().toStdString();
193 
194  Time timeObj(dateObj);
195  Time timeSee(dateSee);
196  if (!timeObj.IsValid())
197  {
198  struct tm tm;
199 
200  vector<char> buf(255);
201  if (strptime(dateObj.c_str(), "%c", &tm))
202  timeObj = Time(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
203  tm.tm_hour, tm.tm_min, tm.tm_sec);
204  }
205 
206  if (!timeSee.IsValid())
207  {
208  struct tm tm;
209 
210  vector<char> buf(255);
211  if (strptime(dateSee.c_str(), "%c", &tm))
212  timeSee = Time(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
213  tm.tm_hour, tm.tm_min, tm.tm_sec);
214 
215  Warn("Seeing time invalid ["+dateObj+"]");
216  }
217 
218  if (!timeObj.IsValid())
219  throw runtime_error("object time invalid");
220 
221  if (timeObj!=fLastReport && fIsVerbose)
222  {
223  Out() << endl;
224  Out() << "Date: " << timeObj << endl;
225  Out() << "DustTotal: " << w.fDustTotal << " ugr/m^2" << endl;
226  Out() << "AirPressure: " << w.fAirPressure << " mbar" << endl;
227  Out() << "DewPoint: " << w.fDewPoint << " deg C" << endl;
228  Out() << "WindDirection: " << w.fWindDirection << " deg" << endl;
229  Out() << "WindSpeed: " << w.fWindSpeed << " m/s" << endl;
230  Out() << "Humidity: " << w.fHumidity << "%" << endl;
231  Out() << "Temperature: " << w.fTemperature << " deg C" << endl;
232  Out() << "TempTrend 24h: " << w.fTempTrend << " deg C" << endl;
233  Out() << "Solarimeter: " << w.fSolarimeter << " W/m^2" << endl;
234  Out() << endl;
235  Out() << "Seeing: " << s.fSeeing << " arcsec [" << timeSee << "]" << endl;
236  Out() << "Seeing: " << s.fSeeingMed << " +- " << s.fSeeingStdev << endl;
237  Out() << endl;
238  }
239 
240  fLastReport = timeObj;
241 
242  UpdateWeather(timeObj, w);
243 
244  if (timeSee.IsValid() && fLastSeeing!=timeSee)
245  {
246  UpdateSeeing(timeSee, s);
247  fLastSeeing = timeSee;
248  }
249 
250  if (fDust==w.fDustTotal)
251  return;
252 
253  UpdateDust(timeObj, w.fDustTotal);
254  fDust = w.fDustTotal;
255 
256  ostringstream out;
257  out << setprecision(3) << "Dust: " << fDust << "ug/m^3 [" << timeObj << "]";
258  Message(out);
259  }
260 
262  {
263  async_read_some(ba::buffer(fArray),
264  boost::bind(&ConnectionWeather::HandleRead, this,
265  dummy::error, dummy::bytes_transferred));
266  }
267 
268  boost::asio::deadline_timer fKeepAlive;
269 
270  void PostRequest()
271  {
272  const string cmd =
273  "GET "+fSite+" HTTP/1.1\r\n"
274  "User-Agent: FACT tngweather\r\n"
275  "Accept: */*\r\n"
276  "Host: "+URL()+"\r\n"
277  "Connection: close\r\n"//Keep-Alive\r\n"
278  "Content-Type: application/rss+xml\r\n"
279  "User-Agent: FACT\r\n"
280  "Pragma: no-cache\r\n"
281  "Cache-Control: no-cache\r\n"
282  "Expires: 0\r\n"
283  "Cache-Control: max-age=0\r\n"
284  "\r\n";
285 
286  PostMessage(cmd);
287  }
288 
289  void Request()
290  {
291  PostRequest();
292 
293  fKeepAlive.expires_from_now(boost::posix_time::seconds(fInterval));
294  fKeepAlive.async_wait(boost::bind(&ConnectionWeather::HandleRequest,
295  this, dummy::error));
296  }
297 
298  void HandleRequest(const bs::error_code &error)
299  {
300  // 125: Operation canceled (bs::error_code(125, bs::system_category))
301  if (error && error!=ba::error::basic_errors::operation_aborted)
302  {
303  ostringstream str;
304  str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
305  Error(str);
306 
307  PostClose(false);
308  return;
309  }
310 
311  if (!is_open())
312  {
313  // For example: Here we could schedule a new accept if we
314  // would not want to allow two connections at the same time.
315  PostClose(true);
316  return;
317  }
318 
319  // Check whether the deadline has passed. We compare the deadline
320  // against the current time since a new asynchronous operation
321  // may have moved the deadline before this actor had a chance
322  // to run.
323  if (fKeepAlive.expires_at() > ba::deadline_timer::traits_type::now())
324  return;
325 
326  Request();
327  }
328 
329 
330 private:
331  // This is called when a connection was established
333  {
334  Request();
335  StartReadReport();
336  }
337 
338 public:
339 
340  static const uint16_t kMaxAddr;
341 
342 public:
343  ConnectionWeather(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
344  fIsVerbose(true), fDust(-1),
345  fLastReport(Time::none), fLastReception(Time::none), fLastSeeing(Time::none),
346  fKeepAlive(ioservice)
347  {
348  SetLogStream(&imp);
349  }
350 
351  void SetVerbose(bool b)
352  {
353  fIsVerbose = b;
355  }
356 
357  void SetInterval(uint16_t i)
358  {
359  fInterval = i;
360  }
361 
362  void SetSite(const string &site)
363  {
364  fSite = site;
365  }
366 
367  int GetState() const
368  {
369  if (fLastReport.IsValid() && fLastReport+boost::posix_time::seconds(fInterval*2)>Time())
370  return 3; // receiving
371 
372  if (fLastReception.IsValid() && fLastReception+boost::posix_time::seconds(fInterval*2)>Time())
373  return 2; // connected
374 
375  return 1; // Disconnected
376  }
377 };
378 
379 const uint16_t ConnectionWeather::kMaxAddr = 0xfff;
380 
381 // ------------------------------------------------------------------------
382 
383 #include "DimDescriptionService.h"
384 
386 {
387 private:
388  DimDescribedService fDimWeather;
391 
392  virtual void UpdateWeather(const Time &t, const DimWeather &data)
393  {
394  fDimWeather.setData(&data, sizeof(DimWeather));
395  fDimWeather.Update(t);
396  }
397 
398  virtual void UpdateDust(const Time &t, const float &dust)
399  {
400  fDimAtmosphere.setData(&dust, sizeof(float));
401  fDimAtmosphere.Update(t);
402  }
403 
404  virtual void UpdateSeeing(const Time &t, const DimSeeing &see)
405  {
406  fDimSeeing.setData(&see, sizeof(DimSeeing));
407  fDimSeeing.Update(t);
408  }
409 
410 public:
411  ConnectionDimWeather(ba::io_service& ioservice, MessageImp &imp) :
412  ConnectionWeather(ioservice, imp),
413  fDimWeather("TNG_WEATHER/DATA", "F:1;F:1;F:1;F:1;F:1;F:1;F:1;F:1;F:1",
414  "|T[deg C]:Temperature"
415  "|DeltaT[deg C]:Temperature trend 24h"
416  "|T_dew[deg C]:Dew point"
417  "|H[%]:Humidity"
418  "|P[mbar]:Air pressure"
419  "|v[km/h]:Wind speed"
420  "|d[deg]:Wind direction (N-E)"
421  "|Dust[ug/m^3]:Dust (total)"
422  "|Solarimeter[W/m^2]:Solarimeter"),
423  fDimAtmosphere("TNG_WEATHER/DUST", "F:1",
424  "|Dust[ug/m^3]:Dust (total)"),
425  fDimSeeing("TNG_WEATHER/SEEING", "F:1;F:1;F:1",
426  "|Seeing[arcsec]:Seeing"
427  "|Seeing[arcsec]:Seeing Median"
428  "|SeeingStdev[arcsec]:Seeing Stdev")
429  {
430  }
431 };
432 
433 // ------------------------------------------------------------------------
434 
435 template <class T, class S>
436 class StateMachineWeather : public StateMachineAsio<T>
437 {
438 private:
439  S fWeather;
440 
441  bool CheckEventSize(size_t has, const char *name, size_t size)
442  {
443  if (has==size)
444  return true;
445 
446  ostringstream msg;
447  msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
448  T::Fatal(msg);
449  return false;
450  }
451 
452  int SetVerbosity(const EventImp &evt)
453  {
454  if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
455  return T::kSM_FatalError;
456 
457  fWeather.SetVerbose(evt.GetBool());
458 
459  return T::GetCurrentState();
460  }
461 /*
462  int Disconnect()
463  {
464  // Close all connections
465  fWeather.PostClose(false);
466 
467  return T::GetCurrentState();
468  }
469 
470  int Reconnect(const EventImp &evt)
471  {
472  // Close all connections to supress the warning in SetEndpoint
473  fWeather.PostClose(false);
474 
475  // Now wait until all connection have been closed and
476  // all pending handlers have been processed
477  poll();
478 
479  if (evt.GetBool())
480  fWeather.SetEndpoint(evt.GetString());
481 
482  // Now we can reopen the connection
483  fWeather.PostClose(true);
484 
485  return T::GetCurrentState();
486  }
487 */
488  int Execute()
489  {
490  return fWeather.GetState();
491  }
492 
493 
494 public:
495  StateMachineWeather(ostream &out=cout) :
496  StateMachineAsio<T>(out, "TNG_WEATHER"), fWeather(*this, *this)
497  {
498  // State names
499  T::AddStateName(State::kDisconnected, "NoConnection",
500  "No connection to web-server could be established recently");
501 
502  T::AddStateName(State::kConnected, "Invalid",
503  "Connection to webserver can be established, but received data is not recent or invalid");
504 
505  T::AddStateName(State::kReceiving, "Valid",
506  "Connection to webserver can be established, receint data received");
507 
508  // Verbosity commands
509  T::AddEvent("SET_VERBOSE", "B")
510  (bind(&StateMachineWeather::SetVerbosity, this, placeholders::_1))
511  ("set verbosity state"
512  "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
513 /*
514  // Conenction commands
515  AddEvent("DISCONNECT")
516  (bind(&StateMachineWeather::Disconnect, this))
517  ("disconnect from ethernet");
518 
519  AddEvent("RECONNECT", "O")
520  (bind(&StateMachineWeather::Reconnect, this, placeholders::_1))
521  ("(Re)connect ethernet connection to FTM, a new address can be given"
522  "|[host][string]:new ethernet address in the form <host:port>");
523 */
524  }
525 
527  {
528  fWeather.SetVerbose(!conf.Get<bool>("quiet"));
529  fWeather.SetInterval(conf.Get<uint16_t>("interval"));
530  fWeather.SetDebugTx(conf.Get<bool>("debug-tx"));
531  fWeather.SetSite(conf.Get<string>("url"));
532  fWeather.SetEndpoint(conf.Get<string>("addr"));
533  fWeather.StartConnect();
534 
535  return -1;
536  }
537 };
538 
539 // ------------------------------------------------------------------------
540 
541 #include "Main.h"
542 
543 
544 template<class T, class S, class R>
546 {
547  return Main::execute<T, StateMachineWeather<S, R>>(conf);
548 }
549 
551 {
552  po::options_description control("TNG weather control options");
553  control.add_options()
554  ("no-dim,d", po_switch(), "Disable dim services")
555  ("addr,a", var<string>("tngweb.tng.iac.es:80"), "Network address of Cosy")
556  ("url,u", var<string>("/api/meteo/weather/feed.xml"), "File name and path to load")
557  ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
558  ("interval,i", var<uint16_t>(300), "Interval between two updates on the server in seconds")
559  ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
560  ;
561 
562  conf.AddOptions(control);
563 }
564 
565 /*
566  Extract usage clause(s) [if any] for SYNOPSIS.
567  Translators: "Usage" and "or" here are patterns (regular expressions) which
568  are used to match the usage synopsis in program output. An example from cp
569  (GNU coreutils) which contains both strings:
570  Usage: cp [OPTION]... [-T] SOURCE DEST
571  or: cp [OPTION]... SOURCE... DIRECTORY
572  or: cp [OPTION]... -t DIRECTORY SOURCE...
573  */
575 {
576  cout <<
577  "The tngweather is an interface to the TNG weather data.\n"
578  "\n"
579  "The default is that the program is started without user intercation. "
580  "All actions are supposed to arrive as DimCommands. Using the -c "
581  "option, a local shell can be initialized. With h or help a short "
582  "help message about the usuage can be brought to the screen.\n"
583  "\n"
584  "Usage: tngweather [-c type] [OPTIONS]\n"
585  " or: tngweather [OPTIONS]\n";
586  cout << endl;
587 }
588 
589 void PrintHelp()
590 {
591 // Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
592 
593  /* Additional help text which is printed after the configuration
594  options goes here */
595 
596  /*
597  cout << "bla bla bla" << endl << endl;
598  cout << endl;
599  cout << "Environment:" << endl;
600  cout << "environment" << endl;
601  cout << endl;
602  cout << "Examples:" << endl;
603  cout << "test exam" << endl;
604  cout << endl;
605  cout << "Files:" << endl;
606  cout << "files" << endl;
607  cout << endl;
608  */
609 }
610 
611 int main(int argc, const char* argv[])
612 {
613  Configuration conf(argv[0]);
616  SetupConfiguration(conf);
617 
618  if (!conf.DoParse(argc, argv, PrintHelp))
619  return 127;
620 
621  //try
622  {
623  // No console access at all
624  if (!conf.Has("console"))
625  {
626  if (conf.Get<bool>("no-dim"))
627  return RunShell<LocalStream, StateMachine, ConnectionWeather>(conf);
628  else
629  return RunShell<LocalStream, StateMachineDim, ConnectionDimWeather>(conf);
630  }
631  // Cosole access w/ and w/o Dim
632  if (conf.Get<bool>("no-dim"))
633  {
634  if (conf.Get<int>("console")==0)
635  return RunShell<LocalShell, StateMachine, ConnectionWeather>(conf);
636  else
637  return RunShell<LocalConsole, StateMachine, ConnectionWeather>(conf);
638  }
639  else
640  {
641  if (conf.Get<int>("console")==0)
642  return RunShell<LocalShell, StateMachineDim, ConnectionDimWeather>(conf);
643  else
644  return RunShell<LocalConsole, StateMachineDim, ConnectionDimWeather>(conf);
645  }
646  }
647  /*catch (std::exception& e)
648  {
649  cerr << "Exception: " << e.what() << endl;
650  return -1;
651  }*/
652 
653  return 0;
654 }
void SetupConfiguration(Configuration &conf)
Definition: tngweather.cc:550
DimDescribedService fDimAtmosphere
Definition: tngweather.cc:389
void PrintUsage()
Definition: tngweather.cc:574
A general base-class describing events issues in a state machine.
Definition: EventImp.h:11
boost::asio::deadline_timer fKeepAlive
Definition: tngweather.cc:268
void SetupConfiguration(Configuration &conf)
Definition: Main.h:25
Definition: did.h:42
int i
Definition: db_dim_client.c:21
The base implementation of a distributed messaging system.
Definition: MessageImp.h:10
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
char str[80]
Definition: test_client.c:7
ConnectionWeather(ba::io_service &ioservice, MessageImp &imp)
Definition: tngweather.cc:343
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
po::typed_value< bool > * po_switch()
STL namespace.
void ConnectionEstablished()
Definition: tngweather.cc:332
void SetVerbose(bool b)
Definition: tngweather.cc:351
virtual void UpdateSeeing(const Time &, const DimSeeing &)
Definition: tngweather.cc:45
static const uint16_t kMaxAddr
void HandleRead(const boost::system::error_code &err, size_t bytes_received)
Definition: tngweather.cc:65
int main(int argc, const char *argv[])
Definition: tngweather.cc:611
void PrintHelp()
Definition: tngweather.cc:589
void StartReadReport()
Definition: tngweather.cc:261
virtual void UpdateWeather(const Time &, const DimWeather &)
Definition: tngweather.cc:41
bool Has(const std::string &var)
void AddOptions(const po::options_description &opt, bool visible=true)
Definition: Configuration.h:92
void setData(const void *ptr, size_t sz)
bool CheckEventSize(size_t has, const char *name, size_t size)
Definition: tngweather.cc:441
void HandleRequest(const bs::error_code &error)
void SetInterval(uint16_t i)
Definition: tngweather.cc:357
virtual void UpdateWeather(const Time &t, const DimWeather &data)
Definition: tngweather.cc:392
DimDescribedService fDimSeeing
Definition: tngweather.cc:390
void SetVerbose(bool b=true)
Definition: Connection.h:148
virtual void UpdateDust(const Time &t, const float &dust)
Definition: tngweather.cc:398
bool IsValid() const
Definition: Time.h:90
int RunShell(Configuration &conf)
Definition: tngweather.cc:545
double end
float hum
Definition: HeadersPFmini.h:55
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
int buffer[BUFFSIZE]
Definition: db_dim_client.c:14
void SetSite(const string &site)
Definition: tngweather.cc:362
virtual void UpdateDust(const Time &, const float &)
Definition: tngweather.cc:49
int size
Definition: db_dim_server.c:17
float data[4 *1440]
StateMachineWeather(ostream &out=cout)
Definition: tngweather.cc:495
int SetVerbosity(const EventImp &evt)
Definition: tngweather.cc:452
bool GetBool() const
Definition: EventImp.h:90
TT t
Definition: test_client.c:26
Error()
Definition: HeadersFTM.h:197
po::typed_value< bool > * po_bool(bool def=false)
int EvalOptions(Configuration &conf)
Definition: tngweather.cc:526
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
int GetState() const
Definition: tngweather.cc:367
ConnectionDimWeather(ba::io_service &ioservice, MessageImp &imp)
Definition: tngweather.cc:411
virtual void UpdateSeeing(const Time &t, const DimSeeing &see)
Definition: tngweather.cc:404
virtual size_t GetSize() const
Definition: EventImp.h:55