1 #include <boost/array.hpp> 23 #include <QtXml/QDomDocument> 25 namespace ba = boost::asio;
26 namespace bs = boost::system;
27 namespace dummy = ba::placeholders;
58 boost::array<char, 4096> fArray;
65 void HandleRead(
const boost::system::error_code& err,
size_t bytes_received)
68 if (bytes_received==0 || err)
70 if (err==ba::error::eof)
71 Warn(
"Connection closed by remote host.");
75 if (err && err!=ba::error::eof &&
76 err!=ba::error::basic_errors::not_connected &&
77 err!=ba::error::basic_errors::operation_aborted)
80 str <<
"Reading from " << URL() <<
": " << err.message() <<
" (" << err <<
")";
83 PostClose(err!=ba::error::basic_errors::operation_aborted);
89 fRdfData += string(fArray.data(), bytes_received);
91 const size_t end = fRdfData.find(
"\r\n\r\n");
92 if (end==string::npos)
94 Out() <<
"Received data corrupted [1]." << endl;
95 Out() << fRdfData << endl;
99 string data(fRdfData);
100 data.erase(0, end+4);
105 const size_t chunk = data.find(
"\r\n", pos);
106 if (chunk==0 || chunk==string::npos)
113 stringstream val(data.substr(pos, chunk-pos));
116 data.erase(pos, chunk-pos+2);
124 fLastReception =
Time();
130 Out() <<
"------------------------------------------------------" << endl;
131 Out() << data << endl;
132 Out() <<
"------------------------------------------------------" << endl;
136 if (!doc.setContent(QString(data.data()),
false))
138 Warn(
"Parsing of xml failed [0].");
144 Out() <<
"Parsed:\n-------\n" << doc.toString().toStdString() << endl;
146 const QDomElement root = doc.documentElement();
147 const QDomElement channel = root.firstChildElement(
"channel");
148 const QDomElement
item = channel.firstChildElement(
"item");
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");
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())
170 Warn(
"Parsing of xml failed [1].");
187 s.
fSeeing = see .text().toFloat();
191 const string dateObj = date.text().toStdString();
192 const string dateSee = mjd .text().toStdString();
194 Time timeObj(dateObj);
195 Time timeSee(dateSee);
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);
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);
215 Warn(
"Seeing time invalid ["+dateObj+
"]");
219 throw runtime_error(
"object time invalid");
221 if (timeObj!=fLastReport && fIsVerbose)
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;
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;
235 Out() <<
"Seeing: " << s.
fSeeing <<
" arcsec [" << timeSee <<
"]" << endl;
240 fLastReport = timeObj;
242 UpdateWeather(timeObj, w);
244 if (timeSee.
IsValid() && fLastSeeing!=timeSee)
246 UpdateSeeing(timeSee, s);
247 fLastSeeing = timeSee;
257 out << setprecision(3) <<
"Dust: " << fDust <<
"ug/m^3 [" << timeObj <<
"]";
265 dummy::error, dummy::bytes_transferred));
273 "GET "+fSite+
" HTTP/1.1\r\n" 274 "User-Agent: FACT tngweather\r\n" 276 "Host: "+URL()+
"\r\n" 277 "Connection: close\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" 283 "Cache-Control: max-age=0\r\n" 293 fKeepAlive.expires_from_now(boost::posix_time::seconds(fInterval));
295 this, dummy::error));
301 if (error && error!=ba::error::basic_errors::operation_aborted)
304 str <<
"Write timeout of " << URL() <<
": " << error.message() <<
" (" << error <<
")";
323 if (fKeepAlive.expires_at() > ba::deadline_timer::traits_type::now())
344 fIsVerbose(true), fDust(-1),
345 fLastReport(
Time::none), fLastReception(
Time::none), fLastSeeing(
Time::none),
346 fKeepAlive(ioservice)
369 if (fLastReport.
IsValid() && fLastReport+boost::posix_time::seconds(fInterval*2)>
Time())
372 if (fLastReception.
IsValid() && fLastReception+boost::posix_time::seconds(fInterval*2)>
Time())
400 fDimAtmosphere.
setData(&dust,
sizeof(
float));
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" 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")
435 template <
class T,
class S>
447 msg << name <<
" - Received event has " << has <<
" bytes, but expected " << size <<
".";
454 if (!CheckEventSize(evt.
GetSize(),
"SetVerbosity", 1))
455 return T::kSM_FatalError;
457 fWeather.SetVerbose(evt.
GetBool());
459 return T::GetCurrentState();
490 return fWeather.GetState();
500 "No connection to web-server could be established recently");
503 "Connection to webserver can be established, but received data is not recent or invalid");
506 "Connection to webserver can be established, receint data received");
509 T::AddEvent(
"SET_VERBOSE",
"B")
511 (
"set verbosity state" 512 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
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();
544 template<
class T,
class S,
class R>
547 return Main::execute<T, StateMachineWeather<S, R>>(conf);
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.")
577 "The tngweather is an interface to the TNG weather data.\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" 584 "Usage: tngweather [-c type] [OPTIONS]\n" 585 " or: tngweather [OPTIONS]\n";
611 int main(
int argc,
const char* argv[])
624 if (!conf.
Has(
"console"))
626 if (conf.
Get<
bool>(
"no-dim"))
627 return RunShell<LocalStream, StateMachine, ConnectionWeather>(conf);
629 return RunShell<LocalStream, StateMachineDim, ConnectionDimWeather>(conf);
632 if (conf.
Get<
bool>(
"no-dim"))
634 if (conf.
Get<
int>(
"console")==0)
635 return RunShell<LocalShell, StateMachine, ConnectionWeather>(conf);
637 return RunShell<LocalConsole, StateMachine, ConnectionWeather>(conf);
641 if (conf.
Get<
int>(
"console")==0)
642 return RunShell<LocalShell, StateMachineDim, ConnectionDimWeather>(conf);
644 return RunShell<LocalConsole, StateMachineDim, ConnectionDimWeather>(conf);
void SetupConfiguration(Configuration &conf)
DimDescribedService fDimAtmosphere
A general base-class describing events issues in a state machine.
boost::asio::deadline_timer fKeepAlive
void SetupConfiguration(Configuration &conf)
The base implementation of a distributed messaging system.
Adds some functionality to boost::posix_time::ptime for our needs.
ConnectionWeather(ba::io_service &ioservice, MessageImp &imp)
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
po::typed_value< bool > * po_switch()
void ConnectionEstablished()
virtual void UpdateSeeing(const Time &, const DimSeeing &)
static const uint16_t kMaxAddr
void HandleRead(const boost::system::error_code &err, size_t bytes_received)
int main(int argc, const char *argv[])
virtual void UpdateWeather(const Time &, const DimWeather &)
bool Has(const std::string &var)
void AddOptions(const po::options_description &opt, bool visible=true)
void setData(const void *ptr, size_t sz)
bool CheckEventSize(size_t has, const char *name, size_t size)
void HandleRequest(const bs::error_code &error)
void SetInterval(uint16_t i)
virtual void UpdateWeather(const Time &t, const DimWeather &data)
DimDescribedService fDimSeeing
void SetVerbose(bool b=true)
virtual void UpdateDust(const Time &t, const float &dust)
int RunShell(Configuration &conf)
Commandline parsing, resource file parsing and database access.
void SetSite(const string &site)
virtual void UpdateDust(const Time &, const float &)
StateMachineWeather(ostream &out=cout)
int SetVerbosity(const EventImp &evt)
po::typed_value< bool > * po_bool(bool def=false)
int EvalOptions(Configuration &conf)
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
ConnectionDimWeather(ba::io_service &ioservice, MessageImp &imp)
virtual void UpdateSeeing(const Time &t, const DimSeeing &see)
virtual size_t GetSize() const