From 067dc38d38ca2b044917aafcc5ad4dcf92d40a0d Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Fri, 22 Apr 2022 15:15:32 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + Data.qml | 41 +++++++++++ Day.qml | 183 ++++++++++++++++++++++++++++++++++++++++++++++ XHR.qml | 15 ++++ background.mjs | 66 +++++++++++++++++ main.cpp | 40 ++++++++++ main.qml | 156 +++++++++++++++++++++++++++++++++++++++ solar-android.pro | 38 ++++++++++ 8 files changed, 540 insertions(+) create mode 100644 .gitignore create mode 100644 Data.qml create mode 100644 Day.qml create mode 100644 XHR.qml create mode 100644 background.mjs create mode 100644 main.cpp create mode 100644 main.qml create mode 100644 solar-android.pro diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2468ea9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/solar-android.pro.user diff --git a/Data.qml b/Data.qml new file mode 100644 index 0000000..b8e44f3 --- /dev/null +++ b/Data.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 + +Item { + property var data; + property var day_cache; + signal loaded(); + property bool is_loaded; + id: root + + function measure(title, fn){ + const ts = new Date().getTime(); + fn(); + const te = new Date().getTime(); + console.log(title, te-ts, "ms"); + } + + function refresh(callback){ + log.text = "Wczytywanie..." + is_loaded = false; + data = []; + day_cache = {} + console.log("making request..."); + http.get("https://solar.kuba-orlik.name/data.csv", function(text){ + console.log("got response!"); + background.send("newdata", text, function(data){ + is_loaded = true; + const update_time = new Date(data[data.length-2]); + log.text = "Aktualna produkcja: " + data[data.length-2][1] + "W\nDane z " + update_time.getHours() + ":" + (update_time.getMinutes() < 10 ? "0" : "") + update_time.getMinutes(); + root.loaded(); + callback(); + }) + + }) + } + + function getForDay(day, month, year, callback){ + background.send("get-for-day", {day, month, year}, callback) + } + + +} diff --git a/Day.qml b/Day.qml new file mode 100644 index 0000000..7d2fab3 --- /dev/null +++ b/Day.qml @@ -0,0 +1,183 @@ +import QtQuick 2.0 +import QtCharts 2.3 + +Item { + property int year; + property int day; + property int month; + property bool isToday: false; + + Component.onCompleted: { + refresh(); + cache.loaded.connect(refresh) + } + + Component.onDestruction: { + cache.loaded.disconnect(refresh); + } + + function setTimeout(func, interval, ...params) { + console.log("Setting timeout!", interval) + return setTimeoutComponent.createObject(parent, { func, interval} ); + } + + function clearTimeout(timerObj) { + timerObj.stop(); + timerObj.destroy(); + } + + Component { + id: setTimeoutComponent + Timer { + property var func + running: true + repeat: false + onTriggered: { + func(); + destroy(); + } + } + } + + function draw(series, data, shifttime, index, ymax, xmin, xmax){ + const ts = new Date().getTime(); + var xa = xaxis; + var ya = yaxis; + if(index === undefined){ + index = 0; + } + if(ymax === undefined){ + ymax= 0; + xmin= new Date("2222-01-01"); + xmax= new Date("1990-01-01"); + } + + if(index >= data.length){ + xa.max = xmax; + xa.min = xmin; + ya.max = ymax; + return; + } + var step = 50; + for(var i=0; iymax){ + ymax = y + } + if(x>xmin){ + xmax = x + } + if(xymax){ +// ymax = y +// } +// if(x>xmin){ +// xmax = x +// } +// if(xymax){ +// ymax = y +// } +// if(x>xmin){ +// xmax = x +// } +// if(x6000){return false} + const timestamp = coords[0] + //console.log(timestamp_start, timestamp, timestamp_end, timestamp <=timestamp_end && timestamp >= timestamp_start); + return timestamp <=timestamp_end && timestamp >= timestamp_start + }) + const te = new Date().getTime(); + day_cache[key] = result; + return result; +} + +function newData(text){ + const lines = text.split("\n"); +// measure("map to floats", ()=>lines.map(function(line){ +// var coords = line.split(",").map(parseFloat) +// var d = new Date(coords[0]); +// //(coords[0] / 3600) % 24 +// //dateParser.hours(coords[0]) +// //var hour = d.getHours() + d.getMinutes()/60; +// //coords.push(hour) +// })); + + data = text.split("\n") + .map(function(line){ + // maps to [timestamp, production, hour, datetime] + var coords = line.split(",").map(parseFloat) + var d = new Date(coords[0]); + //var hour = d.getHours() + d.getMinutes()/60; + //coords.push(hour) + coords.push(0); +// d.setDate(1); +// d.setMonth(1); +// d.setYear(1990); // so two dates always nicely overlap in comparison view + coords.push(d) + return coords; + }) + is_loaded = true; +} + +WorkerScript.onMessage = function(message) { + if(message.type === "newdata"){ + newData(message.data); + WorkerScript.sendMessage({id: message.id, data}); + } + if(message.type === "get-for-day"){ + WorkerScript.sendMessage({id: message.id, data: getForDay(message.data.day, message.data.month, message.data.year)}) + } + if(message.type === "set-timeout"){ + WorkerScript.sendMessage({id: message.id}) + } +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bca148f --- /dev/null +++ b/main.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "date.h" +#include + +int main(int argc, char *argv[]) +{ + QSurfaceFormat fmt; + fmt.setVersion(3, 1); + fmt.setDepthBufferSize(24); + QSurfaceFormat::setDefaultFormat(fmt); + qmlRegisterType("DateParser", 1, 0, "DateParser"); + qDebug() << "Device supports OpenSSL: " << QSslSocket::supportsSsl(); + // Qt Charts uses Qt Graphics View Framework for drawing, therefore QApplication must be used. + QApplication app(argc, argv); + + QQuickView viewer; + // The following are needed to make examples run without having to install the module + // in desktop environments. +#ifdef Q_OS_WIN + QString extraImportPath(QStringLiteral("%1/../../../../%2")); +#else + QString extraImportPath(QStringLiteral("%1/../../../%2")); +#endif + viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(), + QString::fromLatin1("qml"))); + QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close); + + viewer.setTitle(QStringLiteral("QML Chart")); + + viewer.setSource(QUrl("qrc:/solar-android/main.qml")); + viewer.setResizeMode(QQuickView::SizeRootObjectToView); + viewer.show(); + + return app.exec(); +} diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..d0c4b16 --- /dev/null +++ b/main.qml @@ -0,0 +1,156 @@ +import QtQuick 2.15 +import QtQuick.Controls 6.3 + + +Item { + width: 720 + height: 480 + visible: true + id: main + + property int offset: 0; + + XHR{id: http} + Data{id: cache} + + Component.onCompleted: { + offset = 0; + init(); + addDays(4); + } + + function init(){ + log.text = "Pobieranie danych..." + //daysModel.clear(); + cache.refresh(function(){ + offset = 0; + days.currentIndex = 0; + //addDays(4); + }); + + } + + function addDays(n){ + for(var i=0; i<=n; i++){ + addDay(); + } + } + + function addDay(){ + const d = new Date(); + d.setDate(d.getDate() - offset); + daysModel.append({_day: d.getDate(), _month: d.getMonth()+1, _year: d.getFullYear(), _isToday: offset==0}) + offset = offset +1; + } + + NumberAnimation { id: anim; target: days; property: "contentX"; duration: 500 } + + function gotoIndex(idx) { + anim.running = false; + + var pos = days.contentX; + var destPos; + + days.positionViewAtIndex(idx, ListView.Contain); + destPos = days.contentX; + + anim.from = pos; + anim.to = destPos; + anim.running = true; + } + + + ListView { + id: days + anchors.fill: parent + highlightFollowsCurrentItem: true + anchors.topMargin: 54 + snapMode: ListView.SnapToItem + cacheBuffer: 5000 + layoutDirection: Qt.RightToLeft + orientation: ListView.Horizontal + focus: true + interactive: true + highlightMoveDuration: 50 + currentIndex: 0 + + onAtXBeginningChanged: { + if (days.atXBeginning) { + addDays(5); + } + } + model: ListModel{ + id: daysModel + } + delegate: + Day { + width: days.width + height: days.height + day: _day + month: _month + year: _year + isToday: _isToday + } + } + + Text{id: log} + + WorkerScript { + id: background + source: "background.mjs" + + property var callback_number: 0; + property var callbacks: ({}); + function send(type, data, cb){ + background.callback_number++; + callbacks[callback_number] = cb + const message = {type, data, id: callback_number} + background.sendMessage(message) + } + function handleMessage(message){ + const id = message.id; + if(callbacks[id]){ + callbacks[id](message && message.data); + delete callbacks[id]; + } + } + + function setTimeout(callback){ // delay is assumed to be 0 + send("set-timeout", 0, callback); + } + + Component.onCompleted: { + background.onMessage.connect(handleMessage) + } + } + + Row { + id: row + x: 184 + width: 448 + height: 40 + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 8 + anchors.rightMargin: 8 + spacing: 12 + layoutDirection: Qt.RightToLeft + + Button { + id: button + text: qsTr("Odśwież") + onClicked:{ + init(); + } + } + Button { + id: button1 + text: qsTr("Dzisiaj") + visible: !days.atXEnd; + onClicked: { + gotoIndex(0) + } + } + } + +} diff --git a/solar-android.pro b/solar-android.pro new file mode 100644 index 0000000..58236c1 --- /dev/null +++ b/solar-android.pro @@ -0,0 +1,38 @@ +QT += quick qml widgets charts + +SOURCES += \ + main.cpp + +resources.files = main.qml XHR.qml Data.qml Day.qml background.mjs +resources.prefix = /$${TARGET} +RESOURCES += resources + +QT_DEBUG_PLUGINS=1 +QML_IMPORT_TRACE=1 + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = /home/kuba/Downloads/kquickcharts/lib/qml +QML2_IMPORT_PATH = /home/kuba/Downloads/kquickcharts/lib/qml + +LIBS += -L/home/kuba/Downloads/kquickcharts/lib/qml + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + ../../../Downloads/kquickcharts/lib/qml/org/kde/quickcharts/qmldir \ + Data.qml \ + Day.qml \ + XHR.qml main.qml \ + background.mjs + +android: include(../android_openssl/openssl.pri) + +HEADERS += \ + date.h +