Project

General

Profile

Bug #365 » weather-fix.patch

antonic901, 24/12/2022 07:08 PM

View differences:

xbmc/GUIUserMessages.h (working copy)
// Sent from filesystem if a path is known to have changed
#define GUI_MSG_UPDATE_PATH GUI_MSG_USER + 33
// Sent from DoWork() method to tell plugin will be used for weather fetching
#define GUI_MSG_CALL_PLUGIN GUI_MSG_USER + 34
xbmc/settings/GUISettings.cpp (working copy)
// My Weather settings
AddGroup(2, 8);
AddCategory(2, "weather", 16000);
AddString(1, "weather.areacode1", 14019, "USNY0996 - New York, NY", BUTTON_CONTROL_STANDARD);
AddString(2, "weather.areacode2", 14020, "UKXX0085 - London, United Kingdom", BUTTON_CONTROL_STANDARD);
AddString(3, "weather.areacode3", 14021, "JAXX0085 - Tokyo, Japan", BUTTON_CONTROL_STANDARD);
AddString(1, "weather.areacode1", 14019, "40.71;-74.01 - New York, United States of America", BUTTON_CONTROL_STANDARD);
AddString(2, "weather.areacode2", 14020, "51.52;-0.11 - London, United Kingdom", BUTTON_CONTROL_STANDARD);
AddString(3, "weather.areacode3", 14021, "35.69;139.69 - Tokyo, Japan", BUTTON_CONTROL_STANDARD);
AddSeparator(4, "weather.sep1");
AddString(5, "weather.plugin", 23000, "", SPIN_CONTROL_TEXT, true);
AddString(6, "weather.pluginsettings", 23001, "", BUTTON_CONTROL_STANDARD, true);
xbmc/utils/Weather.cpp (working copy)
#include "StringUtils.h"
#include "utils/CharsetConverter.h"
#include "utils/log.h"
#include "time.h"
using namespace std;
using namespace XFILE;
......
if (!g_application.getNetwork().IsAvailable())
return false;
if (!g_guiSettings.GetString("weather.plugin").IsEmpty())
{
CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_CALL_PLUGIN);
g_windowManager.SendThreadMessage(msg);
return true;
}
// Download our weather
CLog::Log(LOGINFO, "WEATHER: Downloading weather");
XFILE::CCurlFile httpUtil;
......
CStdString strSetting;
strSetting.Format("weather.areacode%i", GetArea() + 1);
CStdString areaCode = GetAreaCode(g_guiSettings.GetString(strSetting));
strURL.Format("http://wxdata.weather.com/wxdata/weather/local/%s?cc=*&unit=m&dayf=7", areaCode.c_str());
areaCode.Replace(';', ',');
strURL.Format("http://api.weatherapi.com/v1/forecast.xml?key=be7c11e4b6f04d1fb8d142241221112&q=%s&lang=%s&days=7", areaCode, g_langInfo.GetDVDAudioLanguage().c_str());
CStdString xml;
if (httpUtil.Get(strURL, xml))
{
......
iValue = 0;
}
void CWeather::GetLong(const TiXmlElement* pRootElement, const CStdString& strTagName, long& iValue)
{
if (!XMLUtils::GetLong(pRootElement, strTagName.c_str(), iValue))
iValue = 0;
}
void CWeather::LocalizeOverviewToken(CStdString &token)
{
// NOTE: This routine is case-sensitive. Reason is std::less<CStdString> uses a case-sensitive
......
bool CWeather::LoadWeather(const CStdString &weatherXML)
{
int iTmpInt;
long iTmpLong;
CStdString iTmpStr;
SYSTEMTIME time;
CStdStringArray array;
// I think this variable was unused before implementing new weather API
//SYSTEMTIME time;
GetLocalTime(&time); //used when deciding what weather to grab for today
//GetLocalTime(&time); //used when deciding what weather to grab for today
// Load in our tokens if necessary
if (!m_localizedTokens.size())
......
CLog::Log(LOGERROR, "WEATHER: Unable to get data: %s", error.c_str());
return false;
}
// For what this is used?
// location
TiXmlElement *pElement = pRootElement->FirstChildElement("loc");
if (pElement)
{
GetString(pElement, "dnam", m_location[m_iCurWeather], "");
}
//TiXmlElement *pElement = pRootElement->FirstChildElement("loc");
//if (pElement)
//{
// GetString(pElement, "dnam", m_location[m_iCurWeather], "");
//}
//current weather
pElement = pRootElement->FirstChildElement("cc");
TiXmlElement *pElement = pRootElement->FirstChildElement("current");
if (pElement)
{
// Use the local date/time the file is parsed...
......
// ...and not the date/time from weather.com
//GetString(pElement, "lsup", m_szLastUpdateTime, "");
GetString(pElement, "icon", iTmpStr, ""); //string cause i've seen it return N/A
if (iTmpStr == "")
m_currentIcon.Format("%s128x128/na.png", WEATHER_BASE_PATH);
else
m_currentIcon.Format("%s128x128/%s.png", WEATHER_BASE_PATH, iTmpStr.c_str());
GetString(pElement->FirstChildElement("condition"), "icon", iTmpStr, "");
if (iTmpStr == "")
m_currentIcon.Format("%s128x128/na.png", WEATHER_BASE_PATH);
else
StringUtils::SplitString(iTmpStr, "/", array, 6);
m_currentIcon.Format("%s128x128/%s", WEATHER_BASE_PATH, array.at(5).c_str());
GetString(pElement, "t", m_currentConditions, ""); //current condition
LocalizeOverview(m_currentConditions);
GetString(pElement->FirstChildElement("condition"), "text", m_currentConditions, ""); //current condition
//LocalizeOverview(m_currentConditions);
GetInteger(pElement, "tmp", iTmpInt); //current temp
GetInteger(pElement, "temp_c", iTmpInt); //current temp
CTemperature temp=CTemperature::CreateFromCelsius(iTmpInt);
m_currentTemperature.Format("%2.0f", temp.ToLocale());
GetInteger(pElement, "flik", iTmpInt); //current 'Feels Like'
GetInteger(pElement, "feelslike_c", iTmpInt); //current 'Feels Like'
CTemperature tempFlik=CTemperature::CreateFromCelsius(iTmpInt);
m_currentFeelsLike.Format("%2.0f", tempFlik.ToLocale());
TiXmlElement *pNestElement = pElement->FirstChildElement("wind"); //current wind
if (pNestElement)
{
GetInteger(pNestElement, "s", iTmpInt); //current wind strength
iTmpInt = ConvertSpeed(iTmpInt); //convert speed if needed
GetString(pNestElement, "t", iTmpStr, "N"); //current wind direction
GetInteger(pElement, "wind_kph", iTmpInt); //current wind strength
iTmpInt = ConvertSpeed(iTmpInt); //convert speed if needed
GetString(pElement, "wind_dir", iTmpStr, "N"); //current wind direction
//From <dir eg NW> at <speed> km/h g_localizeStrings.Get(407)
//This is a bit untidy, but i'm fed up with localization and string formats :)
CStdString szWindFrom = g_localizeStrings.Get(407);
CStdString szWindAt = g_localizeStrings.Get(408);
CStdString szCalm = g_localizeStrings.Get(1410);
//From <dir eg NW> at <speed> km/h g_localizeStrings.Get(407)
//This is a bit untidy, but i'm fed up with localization and string formats :)
CStdString szWindFrom = g_localizeStrings.Get(407);
CStdString szWindAt = g_localizeStrings.Get(408);
CStdString szCalm = g_localizeStrings.Get(1410);
if (iTmpStr == "CALM")
m_currentWind = szCalm;
else
m_currentWind.Format("%s %s %s %i %s",
szWindFrom.c_str(), iTmpStr,
szWindAt.c_str(), iTmpInt, g_langInfo.GetSpeedUnitString().c_str());
}
if (iTmpStr == "CALM")
m_currentWind = szCalm;
else
m_currentWind.Format("%s %s %s %i %s",
szWindFrom.c_str(), iTmpStr,
szWindAt.c_str(), iTmpInt, g_langInfo.GetSpeedUnitString().c_str());
GetInteger(pElement, "hmid", iTmpInt); //current humidity
GetInteger(pElement, "humidity", iTmpInt); //current humidity
m_currentHumidity.Format("%i%%", iTmpInt);
pNestElement = pElement->FirstChildElement("uv"); //current UV index
if (pNestElement)
{
GetInteger(pNestElement, "i", iTmpInt);
GetString(pNestElement, "t", iTmpStr, "");
LocalizeOverviewToken(iTmpStr);
m_currentUVIndex.Format("%i %s", iTmpInt, iTmpStr);
}
GetInteger(pElement, "dewp", iTmpInt); //current dew point
CTemperature dewPoint=CTemperature::CreateFromCelsius(iTmpInt);
GetInteger(pElement, "uv", iTmpInt); //uv index
//GetString(pNestElement, "t", iTmpStr, "");
if (iTmpInt <= 2)
iTmpStr = "Low";
else if (iTmpInt <= 5)
iTmpStr = "Medium";
else
iTmpStr = "High";
LocalizeOverviewToken(iTmpStr);
m_currentUVIndex.Format("%s (%i)", iTmpStr, iTmpInt);
//Calculating DewPoint based on current temperature and humidity
int currentTemp;
int currentHumidity;
GetInteger(pElement, "temp_c", currentTemp);
GetInteger(pElement, "humidity", currentHumidity);
double A = 17.27;
double B = 237.7;
double alpha = ((A * currentTemp) / (B + currentTemp)) + log(currentHumidity / 100.0);
double dew_point = (B * alpha) / (A - alpha);//current dew point
CTemperature dewPoint=CTemperature::CreateFromCelsius(dew_point);
m_currentDewPoint.Format("%2.0f", dewPoint.ToLocale());
}
//future forcast
pElement = pRootElement->FirstChildElement("dayf");
pElement = pRootElement->FirstChildElement("forecast");
if (pElement)
{
TiXmlElement *pOneDayElement = pElement->FirstChildElement("day");;
TiXmlElement *pOneDayElement = pElement->FirstChildElement("forecastday");
//first day is actually current day so we skip it
pOneDayElement = pOneDayElement->NextSiblingElement("forecastday");
if (pOneDayElement)
{
for (int i = 0; i < NUM_DAYS; i++)
{
const char *attr = pOneDayElement->Attribute("t");
if (attr)
{
m_dfForcast[i].m_day = attr;
LocalizeDay(m_dfForcast[i].m_day);
}
GetLong(pOneDayElement, "date_epoch", iTmpLong); //datetime in milliseconds
GetDayName(iTmpLong, m_dfForcast[i].m_day);
LocalizeDay(m_dfForcast[i].m_day);
GetString(pOneDayElement, "hi", iTmpStr, ""); //string cause i've seen it return N/A
if (iTmpStr == "N/A")
m_dfForcast[i].m_high = "";
else
{
CTemperature temp=CTemperature::CreateFromCelsius(atoi(iTmpStr));
m_dfForcast[i].m_high.Format("%2.0f", temp.ToLocale());
}
GetInteger(pOneDayElement->FirstChildElement("day"), "maxtemp_c", iTmpInt); //max temp
CTemperature temp=CTemperature::CreateFromCelsius(iTmpInt);
m_dfForcast[i].m_high.Format("%2.0f", temp.ToLocale());
GetString(pOneDayElement, "low", iTmpStr, "");
if (iTmpStr == "N/A")
m_dfForcast[i].m_high = "";
else
{
CTemperature temp=CTemperature::CreateFromCelsius(atoi(iTmpStr));
m_dfForcast[i].m_low.Format("%2.0f", temp.ToLocale());
}
GetInteger(pOneDayElement->FirstChildElement("day"), "mintemp_c", iTmpInt); //min temp
temp=CTemperature::CreateFromCelsius(iTmpInt);
m_dfForcast[i].m_low.Format("%2.0f", temp.ToLocale());
TiXmlElement *pDayTimeElement = pOneDayElement->FirstChildElement("part"); //grab the first day/night part (should be day)
if (pDayTimeElement)
TiXmlElement *pConditionElement = pOneDayElement->FirstChildElement("day")->FirstChildElement("condition"); //grab condition element
if (pConditionElement)
{
GetString(pDayTimeElement, "icon", iTmpStr, ""); //string cause i've seen it return N/A
if (iTmpStr == "N/A")
m_dfForcast[i].m_icon.Format("%s128x128/na.png", WEATHER_BASE_PATH);
else
m_dfForcast[i].m_icon.Format("%s128x128/%s.png", WEATHER_BASE_PATH, iTmpStr);
GetString(pConditionElement, "icon", iTmpStr, ""); //icon
if (iTmpStr == "")
m_dfForcast[i].m_icon.Format("%s128x128/na.png", WEATHER_BASE_PATH);
else
StringUtils::SplitString(iTmpStr, "/", array, 6);
m_dfForcast[i].m_icon.Format("%s128x128/%s", WEATHER_BASE_PATH, array.at(5).c_str());
GetString(pDayTimeElement, "t", m_dfForcast[i].m_overview, "");
LocalizeOverview(m_dfForcast[i].m_overview);
GetString(pConditionElement, "text", m_dfForcast[i].m_overview, ""); //current condition
//LocalizeOverview(m_dfForcast[i].m_overview);
}
pOneDayElement = pOneDayElement->NextSiblingElement("day");
pOneDayElement = pOneDayElement->NextSiblingElement("forecastday");
if (!pOneDayElement)
break; // No more days, break out
}
......
return true;
}
//get day name from date represented as milliseconds from 01.01.1970.
void CWeather::GetDayName(long& ms, CStdString& dayName)
{
tm* curr_tm = localtime(&ms);
char date_string[10];
strftime(date_string, 10, "%A", curr_tm);
dayName = CStdString(date_string);
}
//convert weather.com day strings into localized string id's
void CWeather::LocalizeDay(CStdString &day)
{
......
}
}
bool CWeather::GetSearchResults(const CStdString &strSearch, CStdString &strResult)
{
// Check to see if the user entered a weather.com code
if (strSearch.size() == 8)
{
strResult = "";
int i = 0;
for (i = 0; i < 4; ++i)
{
strResult += toupper(strSearch[i]);
if (!isalpha(strSearch[i]))
break;
}
if (i == 4)
{
for ( ; i < 8; ++i)
{
strResult += strSearch[i];
if (!isdigit(strSearch[i]))
break;
}
if (i == 8)
{
return true; // match
}
}
// no match, wipe string
strResult = "";
}
CGUIDialogSelect *pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
CGUIDialogProgress *pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
//do the download
CStdString strURL;
CStdString strXML;
XFILE::CCurlFile httpUtil;
if (pDlgProgress)
{
pDlgProgress->SetHeading(410); //"Accessing Weather.com"
pDlgProgress->SetLine(0, 194); //"Searching"
pDlgProgress->SetLine(1, strSearch);
pDlgProgress->SetLine(2, "");
pDlgProgress->StartModal();
pDlgProgress->Progress();
}
strURL.Format("http://wxdata.weather.com/wxdata/search/search?where=%s", strSearch);
if (!httpUtil.Get(strURL, strXML))
{
if (pDlgProgress)
pDlgProgress->Close();
return false;
}
//some select dialog init stuff
if (!pDlgSelect)
{
if (pDlgProgress)
pDlgProgress->Close();
return false;
}
pDlgSelect->SetHeading(396); //"Select Location"
pDlgSelect->Reset();
///////////////////////////////
// load the xml file
///////////////////////////////
TiXmlDocument xmlDoc;
xmlDoc.Parse(strXML.c_str());
if (xmlDoc.Error())
return false;
TiXmlElement *pRootElement = xmlDoc.RootElement();
if (pRootElement)
{
CStdString strItemTmp;
TiXmlElement *pElement = pRootElement->FirstChildElement("loc");
while (pElement)
{
if (!pElement->NoChildren())
{
strItemTmp.Format("%s - %s", pElement->Attribute("id"), pElement->FirstChild()->Value());
pDlgSelect->Add(strItemTmp);
}
pElement = pElement->NextSiblingElement("loc");
}
}
if (pDlgProgress)
pDlgProgress->Close();
pDlgSelect->EnableButton(TRUE);
pDlgSelect->SetButtonLabel(222); //'Cancel' button returns to weather settings
pDlgSelect->DoModal();
if (pDlgSelect->GetSelectedLabel() < 0)
{
if (pDlgSelect->IsButtonPressed())
{
pDlgSelect->Close(); //close the select dialog and return to weather settings
return true;
}
}
//copy the selected code into the settings
if (pDlgSelect->GetSelectedLabel() >= 0)
strResult = pDlgSelect->GetSelectedLabelText();
if (pDlgProgress)
pDlgProgress->Close();
return true;
bool CWeather::GetSearchResults(const CStdString &strSearch, CStdString &strResult)
{
CGUIDialogSelect *pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
CGUIDialogProgress *pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
//do the download
CStdString strURL;
CStdString strXML;
XFILE::CCurlFile httpUtil;
if (pDlgProgress)
{
pDlgProgress->SetHeading(410); //"Accessing Weatherapi.com"
pDlgProgress->SetLine(0, 194); //"Searching"
pDlgProgress->SetLine(1, strSearch);
pDlgProgress->SetLine(2, "");
pDlgProgress->StartModal();
pDlgProgress->Progress();
}
strURL.Format("http://api.weatherapi.com/v1/search.xml?key=e74f39b17d374e86ad4233506220912&q=%s", strSearch);
if (!httpUtil.Get(strURL, strXML))
{
if (pDlgProgress)
pDlgProgress->Close();
return false;
}
//some select dialog init stuff
if (!pDlgSelect)
{
if (pDlgProgress)
pDlgProgress->Close();
return false;
}
pDlgSelect->SetHeading(396); //"Select Location"
pDlgSelect->Reset();
///////////////////////////////
// load the xml file
///////////////////////////////
TiXmlDocument xmlDoc;
xmlDoc.Parse(strXML.c_str());
if (xmlDoc.Error())
return false;
TiXmlElement *pRootElement = xmlDoc.RootElement();
if (pRootElement)
{
CStdString strItemTmp;
TiXmlElement *pElement = pRootElement->FirstChildElement("geo");
while (pElement)
{
if (!pElement->NoChildren())
{
strItemTmp.Format("%s;%s - %s, %s", pElement->FirstChildElement("lat")->GetText(), pElement->FirstChildElement("lon")->GetText(), pElement->FirstChildElement("name")->GetText(), pElement->FirstChildElement("country")->GetText());
pDlgSelect->Add(strItemTmp);
}
pElement = pElement->NextSiblingElement("geo");
}
}
if (pDlgProgress)
pDlgProgress->Close();
pDlgSelect->EnableButton(TRUE);
pDlgSelect->SetButtonLabel(222); //'Cancel' button returns to weather settings
pDlgSelect->DoModal();
if (pDlgSelect->GetSelectedLabel() < 0)
{
if (pDlgSelect->IsButtonPressed())
{
pDlgSelect->Close(); //close the select dialog and return to weather settings
return true;
}
}
//copy the selected code into the settings
if (pDlgSelect->GetSelectedLabel() >= 0)
strResult = pDlgSelect->GetSelectedLabelText();
if (pDlgProgress)
pDlgProgress->Close();
return true;
}
CStdString CWeather::BusyInfo(int info) const
xbmc/utils/Weather.h (working copy)
bool LoadWeather(const CStdString& strWeatherFile); //parse strWeatherFile
void GetString(const TiXmlElement* pRootElement, const CStdString& strTagName, CStdString &value, const CStdString& strDefaultValue);
void GetInteger(const TiXmlElement* pRootElement, const CStdString& strTagName, int& iValue);
void GetLong(const TiXmlElement* pRootElement, const CStdString& strTagName, long& iValue);
void LocalizeOverview(CStdString &str);
void LocalizeOverviewToken(CStdString &str);
void GetDayName(long& ms, CStdString& dayName);
void LocalizeDay(CStdString &day);
void LoadLocalizedToken();
int ConvertSpeed(int speed);
xbmc/windows/GUIWindowWeather.cpp (working copy)
{
UpdateLocations();
SetProperties();
}
else if (message.GetParam1() == GUI_MSG_CALL_PLUGIN)
{
CLog::Log(LOGINFO, "WEATHER: Calling plugin");
if (g_windowManager.GetActiveWindow() == WINDOW_WEATHER)
{
if (!g_guiSettings.GetString("weather.plugin").IsEmpty())
......
}
else
CallPlugin();
}
}
break;
}
......
CStdString plugin = "special://home/plugins/weather/" + g_guiSettings.GetString("weather.plugin") + "/default.py";
// initialize our sys.argv variables
unsigned int argc = 2;
unsigned int argc = 3;
char ** argv = new char*[argc];
argv[0] = (char*)plugin.c_str();
......
strSetting.Format("weather.areacode%i", m_iCurWeather + 1);
const CStdString &areacode = g_weatherManager.GetAreaCode(g_guiSettings.GetString(strSetting));
argv[1] = (char*)areacode.c_str();
// get current index of selected location (this will allow plugin developers to use their own locations)
strSetting.Format("%i", m_iCurWeather + 1);
argv[2] = (char*)strSetting.c_str();
// call our plugin, passing the areacode
// call our plugin, passing the areacode and location index
g_pythonParser.evalFile(argv[0], argc, (const char**)argv);
CLog::Log(LOGDEBUG, "%s - Weather plugin called: %s (%s)", __FUNCTION__, argv[0], argv[1]);
CLog::Log(LOGDEBUG, "%s - Weather plugin called: %s (%s) %s", __FUNCTION__, argv[0], argv[1], argv[2]);
}
}
(2-2/4)