nymea/plugins/deviceplugins/openweathermap/devicepluginopenweathermap.cpp

555 lines
20 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This file is part of guh. *
* *
* Guh 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, version 2 of the License. *
* *
* Guh 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 guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*!
\page openweathermap.html
\title Open Weather Map
\ingroup plugins
\ingroup services
This plugin alows you to get the current weather data from \l{http://www.openweathermap.org}.
The plugin offers two different search methods: if the user searches for a empty string,
the plugin makes an autodetction with the WAN ip and offers the user the found autodetectresult.
Otherwise the plugin return the list with the found searchresults.
\section1 Examples
\section2 Autodetect location
If you want to autodetect your location dend a discovery request with an empty string.
\code
{
"id":1,
"method":"Devices.GetDiscoveredDevices",
"params":{
"deviceClassId":"985195aa-17ad-4530-88a4-cdd753d747d7",
"discoveryParams": {
"location":""
}
}
}
\endcode
response from autodetection...
\code
{
"id": 1,
"params": {
"deviceDescriptors": [
{
"description": "AT",
"id": "{75607672-5354-428f-a752-910140c22b18}",
"title": "Vienna"
}
],
"errorMessage": "",
"success": true
},
"status": "success"
}
\endcode
\section2 Searching city
If you want to search a string send following discovery message:
\code
{
"id":1,
"method":"Devices.GetDiscoveredDevices",
"params":{
"deviceClassId":"985195aa-17ad-4530-88a4-cdd753d747d7",
"discoveryParams": {
"location":"Vie"
}
}
}
\endcode
response...
\code
{
"id": 1,
"params": {
"deviceDescriptors": [
{
"description": "DE",
"id": "{6dc6be43-5bdc-4dbd-bcbf-6f8e1f90000b}",
"title": "Viersen"
},
{
"description": "VN",
"id": "{af275298-77f1-40b4-843a-d0f3c7aef6bb}",
"title": "Viet Tri"
},
{
"description": "DE",
"id": "{86a4ab63-41b4-4348-9830-4bf6c87474bf}",
"title": "Viernheim"
},
{
"description": "AR",
"id": "{3b5f8eea-6159-4375-bd01-1f07de9c3a9d}",
"title": "Viedma"
},
{
"description": "FR",
"id": "{f3b91f26-3275-4bb4-a594-924202a2124e}",
"title": "Vierzon"
},
{
"description": "AT",
"id": "{b59d15f7-f52b-43a0-a9c5-a3fa80cbc2bd}",
"title": "Vienna"
}
],
"errorMessage": "",
"success": true
},
"status": "success"
}
\endcode
\section2 Adding a discovered city
If you want to add a dicovered city send the add "AddConfiguredDevice" message
with the deviceDescriptorId from the searchresult list. In this example the id for Vienna.
\code
{
"id":1,
"method":"Devices.AddConfiguredDevice",
"params":{
"deviceClassId":"985195aa-17ad-4530-88a4-cdd753d747d7",
"deviceDescriptorId": "b59d15f7-f52b-43a0-a9c5-a3fa80cbc2bd"
}
}
\endcode
response...
\code
{
"id": 1,
"params": {
"deviceId": "{af0f1958-b901-48da-ad97-d4d64af88cf8}",
"errorMessage": "",
"success": true
},
"status": "success"
}
\endcode
\section1 Plugin propertys:
\section2 Plugin parameters
Each configured plugin has following paramters:
\table
\header
\li Name
\li Description
\li Data Type
\row
\li location
\li This parameter holds the name of the city
\li string
\row
\li country
\li This parameter holds the country of the city
\li string
\row
\li id
\li This parameter holds the city id from \l{http://www.openweathermap.org}
\li string
\endtable
\section2 Actions
Following list contains all plugin \l{Action}s:
\table
\header
\li Name
\li Description
\li UUID
\row
\li refresh
\li This action refreshes all states.
\li cfbc6504-d86f-4856-8dfa-97b6fbb385e4
\endtable
\section2 States
Following list contains all plugin \l{State}s:
\table
\header
\li Name
\li Description
\li UUID
\li Data Type
\row
\li city name
\li The name of the city
\li fd9e7b7f-cf1f-4093-8f6d-fff5b223471f
\li string
\row
\li city id
\li The city ID for openweathermap.org
\li c6ef1c07-e817-4251-b83d-115bbf6f0ae9
\li string
\row
\li country name
\li The country name
\li 0e607a5f-1938-4e77-a146-15e9ad15bfad
\li string
\row
\li last update
\li The timestamp of the weather data from the weatherstation in unixtime
format
\li 98e48095-87da-47a4-b812-28c6c17a3e76
\li unsignend int
\row
\li temperature
\li Current temperature [Celsius]
\li 2f949fa3-ff21-4721-87ec-0a5c9d0a5b8a
\li double
\row
\li temperature minimum
\li Today temperature minimum [Clesius]
\li 701338b3-80de-4c95-8abf-26f44529d620
\li double
\row
\li temperature maximum
\li Today temperature maximum [Clesius]
\li f69bedd2-c997-4a7d-9242-76bf2aab3d3d
\li double
\row
\li humidity
\li Current relative humidity [%]
\li 3f01c9f0-206b-4477-afa2-80d6e5e54fbb
\li int
\row
\li pressure
\li Current pressure [hPa]
\li 6a57b6e9-7010-4a89-982c-ce0bc2a71f11
\li double
\row
\li wind speed
\li Current wind speed [m/s]
\li 12dc85a9-825d-4375-bef4-abd66e9e301b
\li double
\row
\li wind direction
\li The wind direction rellative to the north pole [degree]
\li a8b0383c-d615-41fe-82b8-9b797f045cc9
\li int
\row
\li cloudiness
\li This value represents how much of the sky is clowdy [%]
\li 0c1dc881-560e-40ac-a4a1-9ab69138cfe3
\li int
\row
\li weather description
\li This string describes the current weather condition in clear words
\li e71d98e3-ebd8-4abf-ad25-9ecc2d05276a
\li string
\row
\li sunset
\li The time of todays sunset in unixtime format
\li 5dd6f5a3-25d6-4e60-82ca-e934ad76a4b6
\li unsigned int
\row
\li sunrise
\li The time of todays sunrise in unixtime format
\li 413b3fc6-bd1c-46fb-8c86-03096254f94f
\li unsigned int
\endtable
*/
#include "devicepluginopenweathermap.h"
#include "plugin/device.h"
#include "devicemanager.h"
#include <QDebug>
#include <QJsonDocument>
#include <QVariantMap>
#include <QDateTime>
VendorId openweathermapVendorId = VendorId("bf1e96f0-9650-4e7c-a56c-916d54d18e7a");
DeviceClassId openweathermapDeviceClassId = DeviceClassId("985195aa-17ad-4530-88a4-cdd753d747d7");
ActionTypeId updateWeatherActionTypeId = ActionTypeId("cfbc6504-d86f-4856-8dfa-97b6fbb385e4");
StateTypeId updateTimeStateTypeId = StateTypeId("36b2f09b-7d77-4fbc-a68f-23d735dda0b1");
StateTypeId temperatureStateTypeId = StateTypeId("6013402f-b5b1-46b3-8490-f0c20d62fe61");
StateTypeId temperatureMinStateTypeId = StateTypeId("14ec2781-cb04-4bbf-b097-7d01ef982630");
StateTypeId temperatureMaxStateTypeId = StateTypeId("fefe5563-452f-4833-b5cf-49c3cc67c772");
StateTypeId humidityStateTypeId = StateTypeId("6f32ec73-3240-4630-ada9-1c10b8e98123");
StateTypeId pressureStateTypeId = StateTypeId("4a42eea9-00eb-440b-915e-dbe42180f83b");
StateTypeId windSpeedStateTypeId = StateTypeId("2bf63430-e9e2-4fbf-88e6-6f1b4770f287");
StateTypeId windDirectionStateTypeId = StateTypeId("589e2ea5-65b2-4afd-9b72-e3708a589a12");
StateTypeId cloudinessStateTypeId = StateTypeId("798553bc-45c7-42eb-9105-430bddb5d9b7");
StateTypeId weatherDescriptionStateTypeId = StateTypeId("f9539108-0e0e-4736-a306-6408f8e20a26");
StateTypeId sunriseStateTypeId = StateTypeId("af155e94-9492-44e1-8608-7d0ee8b5d50d");
StateTypeId sunsetStateTypeId = StateTypeId("a1dddc3d-549f-4f20-b78b-be850548f286");
DevicePluginOpenweathermap::DevicePluginOpenweathermap()
{
m_openweaher = new OpenWeatherMap(this);
connect(m_openweaher, SIGNAL(searchResultReady(QList<QVariantMap>)), this, SLOT(searchResultsReady(QList<QVariantMap>)));
connect(m_openweaher, SIGNAL(weatherDataReady(QByteArray)), this, SLOT(weatherDataReady(QByteArray)));
}
QList<Vendor> DevicePluginOpenweathermap::supportedVendors() const
{
QList<Vendor> ret;
Vendor openweathermap(openweathermapVendorId, "openweathermap");
ret.append(openweathermap);
return ret;
}
QList<DeviceClass> DevicePluginOpenweathermap::supportedDevices() const
{
QList<DeviceClass> ret;
DeviceClass deviceClassOpenweathermap(pluginId(), openweathermapVendorId, openweathermapDeviceClassId);
deviceClassOpenweathermap.setName("Weather from openweathermap.org");
deviceClassOpenweathermap.setCreateMethod(DeviceClass::CreateMethodDiscovery);
// Params
QList<ParamType> params;
ParamType locationParam("location", QVariant::String);
params.append(locationParam);
//Location is all we need for discovery.
deviceClassOpenweathermap.setDiscoveryParamTypes(params);
ParamType countryParam("country", QVariant::String);
params.append(countryParam);
ParamType idParam("id", QVariant::String);
params.append(idParam);
deviceClassOpenweathermap.setParamTypes(params);
// Actions
QList<ActionType> weatherActions;
ActionType updateWeather(updateWeatherActionTypeId);
updateWeather.setName("refresh");
weatherActions.append(updateWeather);
// States
QList<StateType> weatherStates;
StateType updateTimeState(updateTimeStateTypeId);
updateTimeState.setName("last update [unixtime]");
updateTimeState.setType(QVariant::UInt);
updateTimeState.setDefaultValue(0);
weatherStates.append(updateTimeState);
StateType temperatureState(temperatureStateTypeId);
temperatureState.setName("temperature [Celsius]");
temperatureState.setType(QVariant::Double);
temperatureState.setDefaultValue(-999.9);
weatherStates.append(temperatureState);
StateType temperatureMinState(temperatureMinStateTypeId);
temperatureMinState.setName("temperature minimum [Celsius]");
temperatureMinState.setType(QVariant::Double);
temperatureMinState.setDefaultValue(-999.9);
weatherStates.append(temperatureMinState);
StateType temperatureMaxState(temperatureMaxStateTypeId);
temperatureMaxState.setName("temperature maximum [Celsius]");
temperatureMaxState.setType(QVariant::Double);
temperatureMaxState.setDefaultValue(999.9);
weatherStates.append(temperatureMaxState);
StateType humidityState(humidityStateTypeId);
humidityState.setName("humidity [%]");
humidityState.setType(QVariant::Int);
humidityState.setDefaultValue(-1);
weatherStates.append(humidityState);
StateType pressureState(pressureStateTypeId);
pressureState.setName("pressure [hPa]");
pressureState.setType(QVariant::Double);
pressureState.setDefaultValue(-1);
weatherStates.append(pressureState);
StateType windSpeedState(windSpeedStateTypeId);
windSpeedState.setName("wind speed [m/s]");
windSpeedState.setType(QVariant::Double);
windSpeedState.setDefaultValue(-1);
weatherStates.append(windSpeedState);
StateType windDirectionState(windDirectionStateTypeId);
windDirectionState.setName("wind direction [degree]");
windDirectionState.setType(QVariant::Int);
windDirectionState.setDefaultValue(-1);
weatherStates.append(windDirectionState);
StateType cloudinessState(cloudinessStateTypeId);
cloudinessState.setName("cloudiness [%]");
cloudinessState.setType(QVariant::Int);
cloudinessState.setDefaultValue(-1);
weatherStates.append(cloudinessState);
StateType weatherDescriptionState(weatherDescriptionStateTypeId);
weatherDescriptionState.setName("weather description");
weatherDescriptionState.setType(QVariant::String);
weatherDescriptionState.setDefaultValue("");
weatherStates.append(weatherDescriptionState);
StateType sunsetState(sunsetStateTypeId);
sunsetState.setName("sunset [unixtime]");
sunsetState.setType(QVariant::UInt);
sunsetState.setDefaultValue(0);
weatherStates.append(sunsetState);
StateType sunriseState(sunriseStateTypeId);
sunriseState.setName("sunrise [unixtime]");
sunriseState.setType(QVariant::UInt);
sunriseState.setDefaultValue(0);
weatherStates.append(sunriseState);
deviceClassOpenweathermap.setActions(weatherActions);
deviceClassOpenweathermap.setStateTypes(weatherStates);
ret.append(deviceClassOpenweathermap);
return ret;
}
DeviceManager::DeviceError DevicePluginOpenweathermap::discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const
{
qDebug() << "should discover divces for" << deviceClassId << params.value("location").toString();
if(params.value("location").toString() == ""){
m_openweaher->searchAutodetect();
return DeviceManager::DeviceErrorNoError;
}
m_openweaher->search(params.value("location").toString());
return DeviceManager::DeviceErrorNoError;
}
QPair<DeviceManager::DeviceSetupStatus, QString> DevicePluginOpenweathermap::setupDevice(Device *device)
{
m_openweaher->update(device->paramValue("id").toString());
return reportDeviceSetup();
}
DeviceManager::HardwareResources DevicePluginOpenweathermap::requiredHardware() const
{
return DeviceManager::HardwareResourceTimer;
}
QPair<DeviceManager::DeviceError, QString> DevicePluginOpenweathermap::executeAction(Device *device, const Action &action)
{
qDebug() << "execute action " << updateWeatherActionTypeId.toString();
if(action.actionTypeId() == updateWeatherActionTypeId){
m_openweaher->update(device->paramValue("id").toString());
}
return report();
}
QString DevicePluginOpenweathermap::pluginName() const
{
return "Openweathermap";
}
PluginId DevicePluginOpenweathermap::pluginId() const
{
return PluginId("bc6af567-2338-41d5-aac1-462dec6e4783");
}
void DevicePluginOpenweathermap::guhTimer()
{
foreach (Device *device, deviceManager()->findConfiguredDevices(openweathermapDeviceClassId)) {
m_openweaher->update(device->paramValue("id").toString());
}
}
void DevicePluginOpenweathermap::searchResultsReady(const QList<QVariantMap> &cityList)
{
QList<DeviceDescriptor> retList;
foreach (QVariantMap elemant, cityList) {
DeviceDescriptor descriptor(openweathermapDeviceClassId, elemant.value("name").toString(),elemant.value("country").toString());
QList<Param> params;
Param locationParam("location", elemant.value("name"));
params.append(locationParam);
Param countryParam("country", elemant.value("country"));
params.append(countryParam);
Param idParam("id", elemant.value("id"));
params.append(idParam);
descriptor.setParams(params);
retList.append(descriptor);
}
emit devicesDiscovered(openweathermapDeviceClassId,retList);
}
void DevicePluginOpenweathermap::weatherDataReady(const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qWarning() << "failed to parse data" << data << ":" << error.errorString();
return;
}
QVariantMap dataMap = jsonDoc.toVariant().toMap();
foreach (Device *device, deviceManager()->findConfiguredDevices(openweathermapDeviceClassId)) {
if(device->paramValue("id").toString() == dataMap.value("id").toString()){
if(dataMap.contains("clouds")){
int cloudiness = dataMap.value("clouds").toMap().value("all").toInt();
device->setStateValue(cloudinessStateTypeId,cloudiness);
}
if(dataMap.contains("dt")){
uint lastUpdate = dataMap.value("dt").toUInt();
device->setStateValue(updateTimeStateTypeId,lastUpdate);
}
if(dataMap.contains("main")){
double temperatur = dataMap.value("main").toMap().value("temp").toDouble();
double temperaturMax = dataMap.value("main").toMap().value("temp_max").toDouble();
double temperaturMin = dataMap.value("main").toMap().value("temp_min").toDouble();
double pressure = dataMap.value("main").toMap().value("pressure").toDouble();
int humidity = dataMap.value("main").toMap().value("humidity").toInt();
device->setStateValue(temperatureStateTypeId,temperatur);
device->setStateValue(temperatureMinStateTypeId,temperaturMin);
device->setStateValue(temperatureMaxStateTypeId,temperaturMax);
device->setStateValue(pressureStateTypeId,pressure);
device->setStateValue(humidityStateTypeId,humidity);
}
if(dataMap.contains("sys")){
uint sunrise = dataMap.value("sys").toMap().value("sunrise").toUInt();
uint sunset = dataMap.value("sys").toMap().value("sunset").toUInt();
device->setStateValue(sunriseStateTypeId,sunrise);
device->setStateValue(sunsetStateTypeId,sunset);
}
if(dataMap.contains("weather")){
QString description = dataMap.value("weather").toMap().value("description").toString();
device->setStateValue(weatherDescriptionStateTypeId,description);
}
if(dataMap.contains("wind")){
int windDirection = dataMap.value("wind").toMap().value("deg").toInt();
double windSpeed = dataMap.value("wind").toMap().value("speed").toDouble();
device->setStateValue(windDirectionStateTypeId,windDirection);
device->setStateValue(windSpeedStateTypeId,windSpeed);
}
}
}
}