Initial commit
commit
067dc38d38
@ -0,0 +1 @@
|
|||||||
|
/solar-android.pro.user
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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; i<step; i+=2){
|
||||||
|
var coords = data[index+i];
|
||||||
|
if(!coords){ break};
|
||||||
|
|
||||||
|
var x = new Date(coords[3].getTime()+shifttime);
|
||||||
|
var y = coords[1]
|
||||||
|
if(y>ymax){
|
||||||
|
ymax = y
|
||||||
|
}
|
||||||
|
if(x>xmin){
|
||||||
|
xmax = x
|
||||||
|
}
|
||||||
|
if(x<xmin || xmin === 0){
|
||||||
|
xmin = x
|
||||||
|
}
|
||||||
|
series.append(x, y)
|
||||||
|
}
|
||||||
|
xa.max = xmax;
|
||||||
|
xa.min = xmin;
|
||||||
|
ya.max = ymax;
|
||||||
|
const te = new Date().getTime();
|
||||||
|
// console.log("drew", step, "points in ", te-ts, "ms")
|
||||||
|
background.setTimeout(function(){draw(series, data, shifttime, index+step, ymax, xmin, xmax)}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh(){
|
||||||
|
var ts = new Date().getTime();
|
||||||
|
// chart.removeAllSeries();
|
||||||
|
const DAY =1000*60*60*24;
|
||||||
|
var s = series;
|
||||||
|
var ys = yesterdaySeries;
|
||||||
|
s.clear();
|
||||||
|
ys.clear();
|
||||||
|
cache.getForDay(day, month, year, function(data){draw(s, data, 0)})
|
||||||
|
if(isToday){
|
||||||
|
cache.getForDay(day-1, month, year, function(data){draw(ys, data, DAY)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// const xa = xaxis;
|
||||||
|
// const ya = yaxis;
|
||||||
|
// cache.getForDay(day, month, year)
|
||||||
|
// .forEach(function(coords){
|
||||||
|
// var x = coords[3];
|
||||||
|
// var y = coords[1]
|
||||||
|
// if(y>ymax){
|
||||||
|
// ymax = y
|
||||||
|
// }
|
||||||
|
// if(x>xmin){
|
||||||
|
// xmax = x
|
||||||
|
// }
|
||||||
|
// if(x<xmin || xmin === 0){
|
||||||
|
// xmin = x
|
||||||
|
// }
|
||||||
|
// s.append(x, y)
|
||||||
|
// })
|
||||||
|
// cache.getForDay(day-1, month, year)
|
||||||
|
// .forEach(function(coords){
|
||||||
|
// var x = coords[3];
|
||||||
|
// var y = coords[1]
|
||||||
|
// if(y>ymax){
|
||||||
|
// ymax = y
|
||||||
|
// }
|
||||||
|
// if(x>xmin){
|
||||||
|
// xmax = x
|
||||||
|
// }
|
||||||
|
// if(x<xmin || xmin === 0){
|
||||||
|
// xmin = x
|
||||||
|
// }
|
||||||
|
// ys.append(x, y)
|
||||||
|
// })
|
||||||
|
// xa.max = xmax;
|
||||||
|
// xa.min = xmin;
|
||||||
|
// ya.max = ymax;
|
||||||
|
// var te = new Date().getTime();
|
||||||
|
// console.log("rendering graph: ", te-ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
title: year.toString() + "-" + month.toString() + "-" + day.toString()
|
||||||
|
anchors.fill: parent
|
||||||
|
antialiasing: true
|
||||||
|
id: chart
|
||||||
|
|
||||||
|
DateTimeAxis{
|
||||||
|
id: xaxis
|
||||||
|
format: "hh:mm"
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuesAxis {
|
||||||
|
id: yaxis
|
||||||
|
min: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AreaSeries{
|
||||||
|
useOpenGL: true
|
||||||
|
name: "wczoraj"
|
||||||
|
axisX: xaxis
|
||||||
|
axisY: yaxis
|
||||||
|
color: "#ccc"
|
||||||
|
visible: isToday
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: yesterdaySeries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
useOpenGL: true
|
||||||
|
name: isToday? "dzisiaj" : year + "-" + month + "-" + day
|
||||||
|
color: "#0074D9"
|
||||||
|
borderColor: "#0074D9"
|
||||||
|
axisX: xaxis
|
||||||
|
axisY: yaxis
|
||||||
|
borderWidth: 0
|
||||||
|
upperSeries: LineSeries{
|
||||||
|
id: series
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import QtQuick 2.4
|
||||||
|
|
||||||
|
Item {
|
||||||
|
function get(url, callback){
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", url);
|
||||||
|
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
if (xhr.readyState === 4) {
|
||||||
|
callback(xhr.responseText);
|
||||||
|
}};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
var data = [];
|
||||||
|
const day_cache = {};
|
||||||
|
var is_loaded = false;
|
||||||
|
|
||||||
|
function getForDay(day, month, year){
|
||||||
|
if(!is_loaded) return [];
|
||||||
|
var key = day + "-" + month + "-" + year;
|
||||||
|
if(day_cache[key]) return day_cache[key];
|
||||||
|
const ts = new Date().getTime();
|
||||||
|
const targetDateStart = new Date(`${year}-${month<10?"0":""}${month}-${day<10? "0":""}${day}`)
|
||||||
|
const targetDateEnd = new Date(`${year}-${month<10?"0":""}${month}-${day<10? "0":""}${day}`);
|
||||||
|
targetDateEnd.setDate(targetDateEnd.getDate() + 1);
|
||||||
|
const timestamp_start = targetDateStart.getTime();
|
||||||
|
const timestamp_end = targetDateEnd.getTime();
|
||||||
|
var result = (data)
|
||||||
|
.filter(function(coords){
|
||||||
|
if(coords[1]>6000){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})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#include <QtQuick/QQuickView>
|
||||||
|
#include <QtCore/QDir>
|
||||||
|
#include <QtQml/QQmlEngine>
|
||||||
|
#include <QSslSocket>
|
||||||
|
#include <QApplication>
|
||||||
|
#include "date.h"
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QSurfaceFormat fmt;
|
||||||
|
fmt.setVersion(3, 1);
|
||||||
|
fmt.setDepthBufferSize(24);
|
||||||
|
QSurfaceFormat::setDefaultFormat(fmt);
|
||||||
|
qmlRegisterType<DateParser>("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();
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue