2011-03-25 18:45:13 +00:00
|
|
|
|
//
|
|
|
|
|
// Temperature.app
|
|
|
|
|
//
|
|
|
|
|
// Copyright (c) 2000-2002 Per Liden
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program; if not, write to the Free Software
|
2012-06-05 17:20:27 +00:00
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307,
|
2011-03-25 18:45:13 +00:00
|
|
|
|
// USA.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include "Xpm.h"
|
|
|
|
|
#include "Temperature.h"
|
|
|
|
|
|
|
|
|
|
#include "pixmaps/main.xpm"
|
|
|
|
|
#include "pixmaps/redlight.xpm"
|
|
|
|
|
|
|
|
|
|
volatile static ChildStatus childStatus;
|
|
|
|
|
|
|
|
|
|
static void catchBrokenPipe(int sig)
|
|
|
|
|
{
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void catchChildExit(int sig)
|
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
waitpid(-1, &status, 0);
|
|
|
|
|
|
|
|
|
|
if (WIFEXITED(status)) {
|
|
|
|
|
if (WEXITSTATUS(status)) {
|
|
|
|
|
childStatus = ChildError;
|
|
|
|
|
} else {
|
|
|
|
|
childStatus = ChildDone;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
childStatus = ChildError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (childStatus == ChildError) {
|
|
|
|
|
std::cerr << APPNAME << ": could not fetch temperature (wget failed), try option -V for more information" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Temperature::Temperature(int argc, char** argv)
|
|
|
|
|
{
|
|
|
|
|
XClassHint classHint;
|
|
|
|
|
XSizeHints sizeHints;
|
|
|
|
|
XWMHints wmHints;
|
|
|
|
|
Atom deleteWindow;
|
|
|
|
|
Xpm* image;
|
|
|
|
|
char* displayName = NULL;
|
|
|
|
|
|
|
|
|
|
mInstanceName = INSTANCENAME;
|
|
|
|
|
mStationId = 0;
|
|
|
|
|
mTemperature[0] = 0;
|
|
|
|
|
mTime[0] = 0;
|
|
|
|
|
mTimeDiff = 0.0;
|
|
|
|
|
mFahrenheit = false;
|
|
|
|
|
mShowTime = false;
|
|
|
|
|
mTime12HourFormat = false;
|
|
|
|
|
mVerbose = false;
|
|
|
|
|
|
|
|
|
|
// Parse command line
|
|
|
|
|
if (argc>1) {
|
|
|
|
|
for (int i=1; i<argc; i++) {
|
|
|
|
|
// Display
|
|
|
|
|
if (!strcmp(argv[i], "-d")) {
|
|
|
|
|
checkArgument(argv, argc, i);
|
|
|
|
|
displayName = argv[i+1];
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Station id
|
|
|
|
|
else if (!strcmp(argv[i], "-s")) {
|
|
|
|
|
checkArgument(argv, argc, i);
|
|
|
|
|
mStationId = argv[i+1];
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fahrenheit
|
|
|
|
|
else if (!strcmp(argv[i], "-f")) {
|
|
|
|
|
mFahrenheit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Time
|
|
|
|
|
else if (!strcmp(argv[i], "-t")) {
|
|
|
|
|
mShowTime = true;
|
|
|
|
|
checkArgument(argv, argc, i);
|
|
|
|
|
if (!strcmp(argv[i+1], "12")) {
|
|
|
|
|
mTime12HourFormat = true;
|
|
|
|
|
} else if (strcmp(argv[i+1], "24")) {
|
|
|
|
|
std::cerr << APPNAME << ": unknown time format, use 12 or 24" << std::endl;
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verbose
|
|
|
|
|
else if (!strcmp(argv[i], "-V")) {
|
|
|
|
|
mVerbose = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instance name
|
|
|
|
|
else if (!strcmp(argv[i], "-n")) {
|
|
|
|
|
checkArgument(argv, argc, i);
|
|
|
|
|
mInstanceName = argv[i+1];
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Version
|
|
|
|
|
else if (!strcmp(argv[i], "-v")) {
|
|
|
|
|
std::cerr << APPNAME << " version " << VERSION << std::endl;
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Help
|
|
|
|
|
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
|
|
|
|
showHelp();
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unknown option
|
|
|
|
|
else {
|
|
|
|
|
std::cerr << APPNAME << ": invalid option '" << argv[i] << "'" << std::endl;
|
|
|
|
|
tryHelp(argv[0]);
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mStationId == 0) {
|
|
|
|
|
std::cerr << APPNAME << ": you must supply a station id using -s <id>" << std::endl;
|
|
|
|
|
tryHelp(argv[0]);
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open display
|
|
|
|
|
if ((mDisplay = XOpenDisplay(displayName)) == NULL) {
|
|
|
|
|
std::cerr << APPNAME << ": could not open display " << displayName << std::endl;
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get root window
|
|
|
|
|
mRoot = RootWindow(mDisplay, DefaultScreen(mDisplay));
|
|
|
|
|
|
|
|
|
|
// Create windows
|
|
|
|
|
mAppWin = XCreateSimpleWindow(mDisplay, mRoot, 1, 1, 64, 64, 0, 0, 0);
|
|
|
|
|
mIconWin = XCreateSimpleWindow(mDisplay, mAppWin, 0, 0, 64, 64, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
// Set classhint
|
|
|
|
|
classHint.res_name = mInstanceName;
|
|
|
|
|
classHint.res_class = CLASSNAME;
|
|
|
|
|
XSetClassHint(mDisplay, mAppWin, &classHint);
|
|
|
|
|
|
|
|
|
|
// Create delete atom
|
|
|
|
|
deleteWindow = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
|
|
|
|
|
XSetWMProtocols(mDisplay, mAppWin, &deleteWindow, 1);
|
|
|
|
|
XSetWMProtocols(mDisplay, mIconWin, &deleteWindow, 1);
|
|
|
|
|
|
|
|
|
|
// Set windowname
|
|
|
|
|
XStoreName(mDisplay, mAppWin, APPNAME);
|
|
|
|
|
XSetIconName(mDisplay, mAppWin, APPNAME);
|
|
|
|
|
|
|
|
|
|
// Set sizehints
|
|
|
|
|
sizeHints.flags= USPosition;
|
|
|
|
|
sizeHints.x = 0;
|
|
|
|
|
sizeHints.y = 0;
|
|
|
|
|
XSetWMNormalHints(mDisplay, mAppWin, &sizeHints);
|
|
|
|
|
|
|
|
|
|
// Set wmhints
|
|
|
|
|
wmHints.initial_state = WithdrawnState;
|
|
|
|
|
wmHints.icon_window = mIconWin;
|
|
|
|
|
wmHints.icon_x = 0;
|
|
|
|
|
wmHints.icon_y = 0;
|
|
|
|
|
wmHints.window_group = mAppWin;
|
|
|
|
|
wmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
|
|
|
|
|
XSetWMHints(mDisplay, mAppWin, &wmHints);
|
|
|
|
|
|
|
|
|
|
// Set command
|
|
|
|
|
XSetCommand(mDisplay, mAppWin, argv, argc);
|
|
|
|
|
|
|
|
|
|
// Set background image
|
|
|
|
|
image = new Xpm(mDisplay, mRoot, main_xpm);
|
|
|
|
|
image->setWindowPixmapShaped(mIconWin);
|
|
|
|
|
delete image;
|
|
|
|
|
|
|
|
|
|
// Create status led
|
|
|
|
|
mStatusLed = XCreateSimpleWindow(mDisplay, mIconWin, LED_X, LED_Y, 3, 2, 0, 0, 0);
|
|
|
|
|
image = new Xpm(mDisplay, mRoot, redlight_xpm);
|
|
|
|
|
image->setWindowPixmap(mStatusLed);
|
|
|
|
|
delete image;
|
|
|
|
|
|
|
|
|
|
XMapWindow(mDisplay, mIconWin);
|
|
|
|
|
XMapWindow(mDisplay, mAppWin);
|
|
|
|
|
XSync(mDisplay, False);
|
|
|
|
|
|
|
|
|
|
// Catch broker pipe signal
|
|
|
|
|
signal(SIGPIPE, catchBrokenPipe);
|
|
|
|
|
|
|
|
|
|
// Catch child exit signal
|
|
|
|
|
signal(SIGCHLD, catchChildExit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::tryHelp(char* appname)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << std::endl << "Try `" << appname << " --help' for more information" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::showHelp()
|
|
|
|
|
{
|
|
|
|
|
std::cerr << APPNAME << " Copyright (c) 2000-2002 by Per Liden (per@fukt.bth.se)" << std::endl << std::endl
|
|
|
|
|
<< "options:" << std::endl
|
|
|
|
|
<< " -s <id> set station id (ICAO Location Indicator)" << std::endl
|
|
|
|
|
<< " -t 12|24 display time of temperature observation (12 or 24 hour format)" << std::endl
|
|
|
|
|
<< " -f display degrees in Fahrenheit" << std::endl
|
|
|
|
|
<< " -V display verbose messages from wget" << std::endl
|
|
|
|
|
<< " -n <name> set client instance name" << std::endl
|
|
|
|
|
<< " -d <disp> set display" << std::endl
|
|
|
|
|
<< " -v print version and exit" << std::endl
|
|
|
|
|
<< " -h, --help display this help text and exit" << std::endl
|
|
|
|
|
<< std::endl
|
|
|
|
|
<< "You must supply the ICAO Location Indicator (a 4-character string)" << std::endl
|
|
|
|
|
<< "of a weather station near you. You can search for a station on" << std::endl
|
|
|
|
|
<< "this site: http://www.nws.noaa.gov/oso/siteloc.shtml" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::checkArgument(char** argv, int argc, int index)
|
|
|
|
|
{
|
|
|
|
|
if (argc-1 < index+1) {
|
|
|
|
|
std::cerr << APPNAME << ": option '" << argv[index] << "' requires an argument" << std::endl;
|
|
|
|
|
tryHelp(argv[0]);
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::showLed(bool show)
|
|
|
|
|
{
|
|
|
|
|
if (show) {
|
|
|
|
|
XMapWindow(mDisplay, mStatusLed);
|
|
|
|
|
} else {
|
|
|
|
|
XUnmapWindow(mDisplay, mStatusLed);
|
|
|
|
|
}
|
|
|
|
|
XSync(mDisplay, False);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::calcTimeDiff()
|
|
|
|
|
{
|
|
|
|
|
struct tm* t;
|
|
|
|
|
double localTime;
|
|
|
|
|
double universalTime;
|
|
|
|
|
time_t currentTime;
|
|
|
|
|
|
|
|
|
|
currentTime = time(0);
|
|
|
|
|
t = gmtime(¤tTime);
|
|
|
|
|
universalTime = (double)t->tm_hour + (double)t->tm_min / 60.0 + (double)t->tm_sec / 3600.0;
|
|
|
|
|
|
|
|
|
|
currentTime = time(0);
|
|
|
|
|
t = localtime(¤tTime);
|
|
|
|
|
localTime = (double)t->tm_hour + (double)t->tm_min / 60.0 + (double)t->tm_sec / 3600.0;
|
|
|
|
|
|
|
|
|
|
mTimeDiff = universalTime - localTime;
|
|
|
|
|
if (mTimeDiff > 24.0) {
|
|
|
|
|
mTimeDiff -= 24.0;
|
|
|
|
|
} else if (mTimeDiff < 0.0) {
|
|
|
|
|
mTimeDiff += 24.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::setTime(char* utcTime)
|
|
|
|
|
{
|
|
|
|
|
char unit[3];
|
|
|
|
|
int hour = 0;
|
|
|
|
|
int min = 0;
|
|
|
|
|
|
|
|
|
|
strncpy(unit, &utcTime[0], 2);
|
|
|
|
|
hour = atoi(unit);
|
|
|
|
|
strncpy(unit, &utcTime[2], 2);
|
|
|
|
|
min = atoi(unit);
|
|
|
|
|
|
|
|
|
|
double time = ((double)hour + (double)min / 60.0) - mTimeDiff;
|
|
|
|
|
if (time < 0.0) {
|
|
|
|
|
time += 24.0;
|
|
|
|
|
} else if (time > 24.0) {
|
|
|
|
|
time -= 24.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hour = (int)time;
|
|
|
|
|
min = (int)((time - (double)hour) * 60.0 + 0.5);
|
|
|
|
|
if (min >= 60){
|
|
|
|
|
min = 0;
|
|
|
|
|
if (++hour >= 24) {
|
|
|
|
|
hour = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mTime12HourFormat) {
|
|
|
|
|
if (hour >= 0 && hour <= 11) {
|
|
|
|
|
mTimeAMPM = "AM";
|
|
|
|
|
} else {
|
|
|
|
|
mTimeAMPM = "PM";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hour == 0) {
|
|
|
|
|
hour = 12;
|
|
|
|
|
} else if (hour > 12) {
|
|
|
|
|
hour -= 12;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sprintf(mTime, "%d:%.2d", hour, min);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Temperature::updateTemperture(ifstream& file)
|
|
|
|
|
{
|
|
|
|
|
const int MAX_LINE = 1024;
|
|
|
|
|
char buffer[MAX_LINE];
|
|
|
|
|
|
|
|
|
|
if (mShowTime) {
|
|
|
|
|
// Find time of observation
|
|
|
|
|
char* start;
|
|
|
|
|
char time[5];
|
|
|
|
|
file.getline(buffer, MAX_LINE - 1);
|
|
|
|
|
file.getline(buffer, MAX_LINE - 1);
|
|
|
|
|
if ((start = strstr(buffer, "UTC")) == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
strncpy(time, start - 5, 4);
|
|
|
|
|
setTime(time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find temperature
|
|
|
|
|
while (!file.eof()) {
|
|
|
|
|
file >> buffer;
|
|
|
|
|
if (!strcmp(buffer, "Temperature:")) {
|
|
|
|
|
file >> buffer;
|
|
|
|
|
if (buffer && strlen(buffer) < 5) {
|
|
|
|
|
char* unit;
|
|
|
|
|
if (mFahrenheit) {
|
|
|
|
|
strcpy(mTemperature, buffer);
|
|
|
|
|
unit = " <20>F";
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(mTemperature, "%d", (int)rint((atoi(buffer) - 32) / 1.8));
|
|
|
|
|
unit = " <20>C";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Xpm* image = new Xpm(mDisplay, mRoot, main_xpm);
|
|
|
|
|
if (mShowTime) {
|
|
|
|
|
if (mTime12HourFormat) {
|
|
|
|
|
image->drawComposedString(TIME_POS, TIME_FONT, mTime, AMPM_FONT, mTimeAMPM);
|
|
|
|
|
} else {
|
|
|
|
|
image->drawString(TIME_POS, TIME_FONT, mTime);
|
|
|
|
|
}
|
|
|
|
|
image->drawComposedString(TEMP_WITH_TIME_POS, TEMP_FONT, mTemperature, UNIT_FONT, unit);
|
|
|
|
|
} else {
|
|
|
|
|
image->drawComposedString(TEMP_POS, TEMP_FONT, mTemperature, UNIT_FONT, unit);
|
|
|
|
|
}
|
|
|
|
|
image->setWindowPixmap(mIconWin);
|
|
|
|
|
delete image;
|
|
|
|
|
XSync(mDisplay, False);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cerr << APPNAME << ": could not fetch temperature (unknown file format)" << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Temperature::run()
|
|
|
|
|
{
|
|
|
|
|
if (mShowTime) {
|
|
|
|
|
calcTimeDiff();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
|
while(1) {
|
|
|
|
|
if (counter <= 0) {
|
|
|
|
|
char tmpFile[sizeof(TMP_FILE)] = TMP_FILE;
|
|
|
|
|
int fd = mkstemp(tmpFile);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
std::cerr << APPNAME << ": could not create temporary file " << tmpFile << ": " << strerror(errno) << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
|
|
counter = UPDATE_INTERVAL;
|
|
|
|
|
childStatus = ChildRunning;
|
|
|
|
|
signal(SIGCHLD, catchChildExit);
|
|
|
|
|
showLed(true);
|
|
|
|
|
int pid = fork();
|
|
|
|
|
if (pid == 0) {
|
|
|
|
|
const char* verbose = (mVerbose ? "--verbose" : "--quiet");
|
|
|
|
|
char* URL = new char[strlen(METAR_URL) + strlen(mStationId) + 1];
|
|
|
|
|
sprintf(URL, METAR_URL, mStationId);
|
|
|
|
|
execlp("wget", "wget", "--cache=off", "--tries=0", verbose, "-O", tmpFile, URL, 0);
|
|
|
|
|
std::cerr << APPNAME << ": could not fetch temperature (wget not found in $PATH)" << std::endl;
|
|
|
|
|
remove(tmpFile);
|
|
|
|
|
exit(0);
|
|
|
|
|
} else if (pid == -1) {
|
|
|
|
|
std::cerr << APPNAME << ": could not fetch temperature (fork() failed)" << std::endl;
|
|
|
|
|
} else {
|
|
|
|
|
bool toggle = true;
|
|
|
|
|
while (childStatus == ChildRunning) {
|
|
|
|
|
showLed(toggle);
|
|
|
|
|
toggle ^= true;
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
showLed(true);
|
|
|
|
|
if (childStatus == ChildDone) {
|
|
|
|
|
ifstream file(tmpFile);
|
|
|
|
|
if (file) {
|
|
|
|
|
if (updateTemperture(file)) {
|
|
|
|
|
showLed(false);
|
|
|
|
|
}
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
remove(tmpFile);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
counter--;
|
|
|
|
|
sleep(1);
|
|
|
|
|
XSync(mDisplay, False);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|