Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request weather data and send them to the wirst #29

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions asteroidsyncservice/watch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,6 @@ QString Watch::name()
return m_name;
}

QString Watch::weatherCityName()
{
return ""; // TODO
}

void Watch::setWeatherCityName(const QString &c)
{
m_iface->call("WeatherSetCityName", c);
emit weatherCityNameChanged();
}

quint8 Watch::batteryLevel() {
return m_batteryLevel;
}
Expand Down Expand Up @@ -193,3 +182,8 @@ bool Watch::weatherServiceReady()
{
return fetchProperty("StatusWeatherService").toBool();
}

void Watch::setWeatherLocation(const float lat, const float lng)
{
m_iface->call("SetWeatherLocation", QString::number(lat), QString::number(lng));
}
9 changes: 4 additions & 5 deletions asteroidsyncservice/watch.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class Watch : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString weatherCityName READ weatherCityName WRITE setWeatherCityName NOTIFY weatherCityNameChanged)
Q_PROPERTY(bool weatherServiceReady READ weatherServiceReady NOTIFY weatherServiceChanged)
Q_PROPERTY(quint8 batteryLevel READ batteryLevel NOTIFY batteryLevelChanged)
Q_PROPERTY(bool timeServiceReady READ timeServiceReady NOTIFY timeServiceChanged)
Expand All @@ -53,20 +52,20 @@ class Watch : public QObject
quint8 batteryLevel();
bool timeServiceReady();
bool screenshotServiceReady();
bool notificationServiceReady();
bool weatherServiceReady();
unsigned int screenshotProgress();

Q_INVOKABLE void setScreenshotFileInfo(const QString fileInfo);
Q_INVOKABLE void setTime(QDateTime t);
bool notificationServiceReady();
Q_INVOKABLE void setVibration(QString v);
Q_INVOKABLE void sendNotify(unsigned int id, QString appName, QString icon, QString body, QString summary);
bool weatherServiceReady();
Q_INVOKABLE void setWeatherLocation(const float lat, const float lng);

public slots:
void requestScreenshot();
void setWeatherCityName(const QString &in);

signals:
void weatherCityNameChanged();
void batteryLevelChanged();
void timeServiceChanged();
void notificationServiceChanged();
Expand Down
4 changes: 3 additions & 1 deletion asteroidsyncserviced/asteroidsyncserviced.pro
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
QT += core bluetooth dbus
QT += core bluetooth dbus network
QT -= gui

include(../version.pri)
Expand All @@ -21,6 +21,7 @@ contains(CONFIG, starfish) {
SOURCES += main.cpp \
watchesmanager.cpp \
dbusinterface.cpp \
openweathermapparser.cpp \
bluez/bluezclient.cpp \
bluez/bluez_agentmanager1.cpp \
bluez/bluez_adapter1.cpp \
Expand All @@ -30,6 +31,7 @@ SOURCES += main.cpp \

HEADERS += watchesmanager.h \
dbusinterface.h \
openweathermapparser.h \
bluez/bluezclient.h \
bluez/bluez_agentmanager1.h \
bluez/bluez_adapter1.h \
Expand Down
54 changes: 48 additions & 6 deletions asteroidsyncserviced/dbusinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@

#include "dbusinterface.h"
#include "watchesmanager.h"

#include "libasteroid/watch.h"

#include <QDBusConnection>
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>

/* Watch Interface */

Expand All @@ -44,6 +45,9 @@ DBusWatch::DBusWatch(Watch *watch, WatchesManager* wm, QObject *parent): QObject
connect(m_screenshotService, SIGNAL(screenshotReceived(QByteArray)), this, SIGNAL(ScreenshotReceived(QByteArray)));
connect(m_weatherService, SIGNAL(ready()), this, SLOT(onWeatherServiceReady()));
connect(wm, SIGNAL(disconnected()), this, SLOT(onDisconnected()));

m_nam = new QNetworkAccessManager(this);
m_wmp = new OpenWeatherMapParser(this);
}

void DBusWatch::onDisconnected()
Expand Down Expand Up @@ -86,11 +90,6 @@ void DBusWatch::RequestScreenshot()
m_screenshotService->requestScreenshot();
}

void DBusWatch::WeatherSetCityName(QString cityName)
{
m_weatherService->setCity(cityName);
}

void DBusWatch::onTimeServiceReady()
{
m_timeServiceReady = true;
Expand Down Expand Up @@ -150,6 +149,49 @@ bool DBusWatch::StatusWeatherService()
return m_weatherServiceReady;
}

void DBusWatch::SetWeatherLocation(const QString lat, const QString lng)
{
owmRequest(lat, lng);
}

void DBusWatch::owmRequest(const QString lat, const QString lng) const
{
QString owmApiKey = "b1af1d2053458fb4ab724f038ed499aa";
QUrl url;
url.setUrl("http://api.openweathermap.org/data/2.5/forecast");

QUrlQuery query;
query.addQueryItem("lat", lat);
query.addQueryItem("lon", lng);
query.addQueryItem("appid", owmApiKey);
url.setQuery(query);

QNetworkRequest request(url);
QNetworkReply* reply = m_nam->get(request);
connect(reply, &QNetworkReply::finished, this, &DBusWatch::onReplyFinished);
}

void DBusWatch::onReplyFinished()
{
QJsonObject rootObj;
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
reply->deleteLater();

if (reply->error() == QNetworkReply::NoError) {
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
rootObj = document.object();
} else {
qDebug() << "Network error" << reply->errorString();
}

QJsonArray list = rootObj.value("list").toArray();

m_weatherService->setCity(m_wmp->getCity(rootObj.value("city").toObject()));
m_weatherService->setIds(m_wmp->getWeatherId(list));
m_weatherService->setMinTemps(m_wmp->getTempMin(list));
m_weatherService->setMaxTemps(m_wmp->getTempMax(list));
}

/* Manager Interface */

DBusInterface::DBusInterface(WatchesManager *wm, QObject *parent) : QObject(parent)
Expand Down
9 changes: 7 additions & 2 deletions asteroidsyncserviced/dbusinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
#define DBUSINTERFACE_H

#include "watchesmanager.h"
#include "openweathermapparser.h"

#include <QObject>
#include <QDBusAbstractAdaptor>
#include <QDBusObjectPath>
#include <QNetworkAccessManager>

class Watch;

Expand Down Expand Up @@ -59,23 +61,26 @@ public slots:
bool StatusScreenshotService();
bool StatusWeatherService();
void RequestScreenshot();
void WeatherSetCityName(QString cityName);
void SetTime(QDateTime t);
void SetVibration(QString v);
void SendNotify(unsigned int id, QString appName, QString icon, QString body, QString summary);
void SetWeatherLocation(const QString lat, const QString lng);

private slots:
void onTimeServiceReady();
void onNotifyServiceReady();
void onScreenshotServiceReady();
void onWeatherServiceReady();
void onDisconnected();
void onReplyFinished();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this class does a lot, it would be helpful to name this into something more specific, maybe onOwmReplyFinished?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe you could use a lambda and inline the slot in owmRequest. I think that's what the cool kids would do these days


private:
Watch *m_watch;

WatchesManager* m_wm;

void owmRequest(const QString lat, const QString lng) const;
QNetworkAccessManager *m_nam;
OpenWeatherMapParser *m_wmp;
BatteryService *m_batteryService;
ScreenshotService *m_screenshotService;
WeatherService *m_weatherService;
Expand Down
77 changes: 77 additions & 0 deletions asteroidsyncserviced/openweathermapparser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "openweathermapparser.h"

OpenWeatherMapParser::OpenWeatherMapParser(QObject *parent) : QObject(parent)
{
}

QList<short> OpenWeatherMapParser::getWeatherId(QJsonArray list)
{
QList<short> id;
QDateTime timestamp;

for(int i = 0; i < 5; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend using list.size() like in the other methods or you risk accessing undefined values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think range-based loops should work on QJsonArray https://en.wikipedia.org/wiki/C%2B%2B11#Range-based_for_loop

QJsonObject dayInfo = list.takeAt(i).toObject();
QJsonArray dayWeather = dayInfo.value("weather").toArray();
QJsonObject firstEntry = dayWeather.takeAt(0).toObject();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QJsonArray has a first() method that is nicer than takeAt(0)

id << firstEntry.value("id").toInt();
}

return id;
}

QList<short> OpenWeatherMapParser::getTempMin(QJsonArray list)
{
QList<short> tempMin;
QDateTime timestamp;
QJsonObject dayInfo = list.at(0).toObject();
timestamp.setTime_t(dayInfo.value("dt").toInt());
QString actDate = timestamp.toString("dd.MM.yyyy");
QJsonObject dayMain = dayInfo.value("main").toObject();
short int tmp = dayMain.value("temp_min").toDouble();

for(int i = 1; i < list.size(); i++) {
dayInfo = list.at(i).toObject();
timestamp.setTime_t(dayInfo.value("dt").toInt());
dayMain = dayInfo.value("main").toObject();
if(actDate == timestamp.toString("dd.MM.yyyy") && dayMain.value("temp_min").toDouble() < tmp) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a string comparison is always quite an expensive operation (and also a bit risky as a simple space or something is always a risk), it's usually the wrong way to approach a problem. What if you'd compare QDates instead https://doc.qt.io/qt-5/qdatetime.html#date ?

tmp = dayMain.value("temp_min").toDouble();
} else if(actDate != timestamp.toString("dd.MM.yyyy")) {
tempMin << tmp;
actDate = timestamp.toString("dd.MM.yyyy");
tmp = dayMain.value("temp_min").toDouble();
}
}

return tempMin;
}

QList<short> OpenWeatherMapParser::getTempMax(QJsonArray list)
{
QList<short> tempMax;
QDateTime timestamp;
QJsonObject dayInfo = list.at(0).toObject();
timestamp.setTime_t(dayInfo.value("dt").toInt());
QString actDate = timestamp.toString("dd.MM.yyyy");
QJsonObject dayMain = dayInfo.value("main").toObject();
short int tmp = dayMain.value("temp_max").toDouble();

for(int i = 1; i < list.size(); i++) {
dayInfo = list.at(i).toObject();
timestamp.setTime_t(dayInfo.value("dt").toInt());
dayMain = dayInfo.value("main").toObject();
if(actDate == timestamp.toString("dd.MM.yyyy") && dayMain.value("temp_max").toDouble() > tmp) {
tmp = dayMain.value("temp_max").toDouble();
} else if(actDate != timestamp.toString("dd.MM.yyyy")) {
tempMax << tmp;
actDate = timestamp.toString("dd.MM.yyyy");
tmp = dayMain.value("temp_max").toDouble();
}
}

return tempMax;
}

QString OpenWeatherMapParser::getCity(QJsonObject obj)
{
return obj.value("name").toString().trimmed();
}
23 changes: 23 additions & 0 deletions asteroidsyncserviced/openweathermapparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef OPENWEATHERMAPPARSER_H
#define OPENWEATHERMAPPARSER_H

#include <QObject>
#include <QJsonObject>
#include <QList>
#include <QJsonArray>
#include <QDateTime>

class OpenWeatherMapParser : public QObject
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the methods are all stateless you don't really need a class here (an object of type OpenWeatherMapParser doesn't carry any ownership/lifetime semantic)
Or you could do the parsing once in the constructor (because all methods take the same arguments and do the same loop over and over again) and then store the results of the parsing in private members that you could return from getWeatherId(), getTempMin() etc...

{
Q_OBJECT

public:
OpenWeatherMapParser(QObject *parent = nullptr);

QList<short> getWeatherId(QJsonArray list);
QList<short> getTempMin(QJsonArray list);
QList<short> getTempMax(QJsonArray list);
QString getCity(const QJsonObject obj);
};

#endif // OPENWEATHERMAPPARSER_H