More work and fixes on the energy dashboard
This commit is contained in:
parent
6f04164513
commit
3e31724f90
@ -84,32 +84,6 @@ void EnergyLogs::setSampleRate(SampleRate sampleRate)
|
||||
}
|
||||
}
|
||||
|
||||
bool EnergyLogs::fetchPowerBalance() const
|
||||
{
|
||||
return m_fetchPowerBalance;
|
||||
}
|
||||
|
||||
void EnergyLogs::setFetchPowerBalance(bool fetchPowerBalance)
|
||||
{
|
||||
if (m_fetchPowerBalance != fetchPowerBalance) {
|
||||
m_fetchPowerBalance = fetchPowerBalance;
|
||||
emit fetchPowerBalanceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QList<QUuid> EnergyLogs::thingIds() const
|
||||
{
|
||||
return m_thingIds;
|
||||
}
|
||||
|
||||
void EnergyLogs::setThingIds(const QList<QUuid> &thingIds)
|
||||
{
|
||||
if (m_thingIds != thingIds) {
|
||||
m_thingIds = thingIds;
|
||||
emit thingIdsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime EnergyLogs::startTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
@ -118,7 +92,6 @@ QDateTime EnergyLogs::startTime() const
|
||||
void EnergyLogs::setStartTime(const QDateTime &startTime)
|
||||
{
|
||||
if (m_startTime != startTime) {
|
||||
qCDebug(dcEnergyLogs()) << "Setting startTime";
|
||||
m_startTime = startTime;
|
||||
emit startTimeChanged();
|
||||
}
|
||||
|
||||
@ -57,12 +57,6 @@ public:
|
||||
SampleRate sampleRate() const;
|
||||
void setSampleRate(SampleRate sampleRate);
|
||||
|
||||
bool fetchPowerBalance() const;
|
||||
void setFetchPowerBalance(bool fetchPowerBalance);
|
||||
|
||||
QList<QUuid> thingIds() const;
|
||||
void setThingIds(const QList<QUuid> &thingIds);
|
||||
|
||||
QDateTime startTime() const;
|
||||
void setStartTime(const QDateTime &startTime);
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ EnergyLogEntry *PowerBalanceLogs::find(const QDateTime ×tamp) const
|
||||
int newest = rowCount() - 1;
|
||||
EnergyLogEntry *entry = nullptr;
|
||||
int step = 0;
|
||||
while (oldest < newest && step < rowCount()) {
|
||||
while (oldest <= newest && step < rowCount()) {
|
||||
EnergyLogEntry *oldestEntry = get(oldest);
|
||||
EnergyLogEntry *newestEntry = get(newest);
|
||||
int middle = (newest - oldest) / 2 + oldest;
|
||||
@ -155,7 +155,6 @@ EnergyLogEntry *PowerBalanceLogs::find(const QDateTime ×tamp) const
|
||||
step++;
|
||||
}
|
||||
return entry;
|
||||
|
||||
}
|
||||
|
||||
void PowerBalanceLogs::logEntriesReceived(const QVariantMap ¶ms)
|
||||
@ -172,7 +171,7 @@ void PowerBalanceLogs::logEntriesReceived(const QVariantMap ¶ms)
|
||||
double totalAcquisition = map.value("totalAcquisition").toDouble();
|
||||
double totalReturn = map.value("totalReturn").toDouble();
|
||||
PowerBalanceLogEntry *entry = new PowerBalanceLogEntry(timestamp, consumption, production, acquisition, storage, totalConsumption, totalProduction, totalAcquisition, totalReturn, this);
|
||||
qCritical() << "Adding entry:" << entry->timestamp() << entry->totalConsumption();
|
||||
// qCritical() << "Adding entry:" << entry->timestamp() << entry->totalConsumption();
|
||||
|
||||
addEntry(entry);
|
||||
}
|
||||
|
||||
@ -73,15 +73,17 @@ EnergyLogEntry *ThingPowerLogs::find(const QUuid &thingId, const QDateTime &time
|
||||
{
|
||||
// TODO: Can we do a binary search even if they key we're looking for is not unique (but still sorted)?
|
||||
// For now, 365 * consumers items is the max we'll have here which seems on the edge for doing a stupid linear search...
|
||||
// qWarning() << "Finding item for" << thingId.toString() << timestamp.toString();
|
||||
for (int i = rowCount() - 1; i >= 0; i--) {
|
||||
ThingPowerLogEntry *entry = static_cast<ThingPowerLogEntry*>(get(i));
|
||||
if (entry->thingId() != thingId) {
|
||||
continue;
|
||||
}
|
||||
// qWarning() << "comparing" << entry->timestamp().toString();
|
||||
if (timestamp == entry->timestamp()) {
|
||||
return entry;
|
||||
}
|
||||
if (timestamp < entry->timestamp()) {
|
||||
if (timestamp > entry->timestamp()) {
|
||||
return nullptr; // Giving up, entry is not here
|
||||
}
|
||||
}
|
||||
@ -130,6 +132,7 @@ void ThingPowerLogs::logEntriesReceived(const QVariantMap ¶ms)
|
||||
double totalConsumption = map.value("totalConsumption").toDouble();
|
||||
double totalProduction = map.value("totalProduction").toDouble();
|
||||
ThingPowerLogEntry *entry = new ThingPowerLogEntry(timestamp, thingId, currentPower, totalConsumption, totalProduction, this);
|
||||
// qWarning() << "Adding entry:" << entry->thingId() << entry->timestamp().toString() << entry->totalConsumption();
|
||||
|
||||
if (groupForTimestamp.isEmpty()) {
|
||||
groupForTimestamp.append(entry);
|
||||
@ -156,6 +159,9 @@ void ThingPowerLogs::notificationReceived(const QVariantMap &data)
|
||||
QVariantMap map = params.value("thingPowerLogEntry").toMap();
|
||||
QDateTime timestamp = QDateTime::fromSecsSinceEpoch(map.value("timestamp").toLongLong());
|
||||
QUuid thingId = map.value("thingId").toUuid();
|
||||
if (!m_thingIds.isEmpty() && !m_thingIds.contains(thingId)) {
|
||||
return;
|
||||
}
|
||||
double currentPower = map.value("currentPower").toDouble();
|
||||
double totalConsumption = map.value("totalConsumption").toDouble();
|
||||
double totalProduction = map.value("totalProduction").toDouble();
|
||||
|
||||
@ -233,10 +233,14 @@ LogEntry *LogsModel::get(int index) const
|
||||
LogEntry *LogsModel::findClosest(const QDateTime &dateTime)
|
||||
{
|
||||
qWarning() << "********************Finding closest for:" << dateTime.time().toString();
|
||||
if (m_list.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
int newest = 0;
|
||||
int oldest = m_list.count() - 1;
|
||||
LogEntry *entry = nullptr;
|
||||
int step = 0;
|
||||
|
||||
LogEntry *allTimeOldestEntry = m_list.at(oldest);
|
||||
if (dateTime < allTimeOldestEntry->timestamp()) {
|
||||
return nullptr;
|
||||
|
||||
@ -98,7 +98,7 @@ bool PackagesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &so
|
||||
}
|
||||
}
|
||||
if (!m_nameFilter.isEmpty()) {
|
||||
if (!m_packages->get(source_row)->displayName().contains(m_nameFilter)) {
|
||||
if (!m_packages->get(source_row)->displayName().toLower().contains(m_nameFilter.toLower())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +164,7 @@ void TagsManager::getTagsResponse(int /*commandId*/, const QVariantMap ¶ms)
|
||||
m_tags->addTags(tags);
|
||||
|
||||
m_busy = false;
|
||||
qWarning() << "Tags busy changed to false";
|
||||
emit busyChanged();
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ private:
|
||||
JsonRpcClient *m_jsonClient = nullptr;
|
||||
|
||||
Tags *m_tags = nullptr;
|
||||
bool m_busy = false;
|
||||
bool m_busy = true;
|
||||
};
|
||||
|
||||
#endif // TAGSMANAGER_H
|
||||
|
||||
@ -56,7 +56,7 @@ void ThingsProxy::setEngine(Engine *engine)
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_engine->tagsManager()->tags(), &Tags::countChanged, this, &ThingsProxy::invalidateFilter);
|
||||
connect(m_engine->tagsManager()->tags(), &Tags::countChanged, this, &ThingsProxy::invalidateFilterInternal);
|
||||
|
||||
if (!sourceModel()) {
|
||||
setSourceModel(m_engine->thingManager()->things());
|
||||
@ -65,10 +65,8 @@ void ThingsProxy::setEngine(Engine *engine)
|
||||
sort(0, sortOrder());
|
||||
connect(sourceModel(), SIGNAL(countChanged()), this, SIGNAL(countChanged()));
|
||||
connect(sourceModel(), &QAbstractItemModel::dataChanged, this, [this]() {
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,8 +90,7 @@ void ThingsProxy::setParentProxy(ThingsProxy *parentProxy)
|
||||
connect(m_parentProxy, SIGNAL(countChanged()), this, SIGNAL(countChanged()));
|
||||
connect(m_parentProxy, &QAbstractItemModel::dataChanged, this, [this]() {
|
||||
if (m_engine) {
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
});
|
||||
|
||||
@ -116,8 +113,7 @@ void ThingsProxy::setFilterTagId(const QString &filterTag)
|
||||
if (m_filterTagId != filterTag) {
|
||||
m_filterTagId = filterTag;
|
||||
emit filterTagIdChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,8 +127,35 @@ void ThingsProxy::setFilterTagValue(const QString &tagValue)
|
||||
if (m_filterTagValue != tagValue) {
|
||||
m_filterTagValue = tagValue;
|
||||
emit filterTagValueChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
QString ThingsProxy::hideTagId() const
|
||||
{
|
||||
return m_hideTagId;
|
||||
}
|
||||
|
||||
void ThingsProxy::setHideTagId(const QString &tagId)
|
||||
{
|
||||
if (m_hideTagId != tagId) {
|
||||
m_hideTagId = tagId;
|
||||
emit hideTagIdChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
QString ThingsProxy::hideTagValue() const
|
||||
{
|
||||
return m_hideTagValue;
|
||||
}
|
||||
|
||||
void ThingsProxy::setHideTagValue(const QString &tagValue)
|
||||
{
|
||||
if (m_hideTagValue != tagValue) {
|
||||
m_hideTagValue = tagValue;
|
||||
emit hideTagValueChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +169,7 @@ void ThingsProxy::setFilterThingId(const QString &filterThingId)
|
||||
if (m_filterThingId != filterThingId) {
|
||||
m_filterThingId = filterThingId;
|
||||
emit filterThingIdChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,8 +183,7 @@ void ThingsProxy::setShownInterfaces(const QStringList &shownInterfaces)
|
||||
if (m_shownInterfaces != shownInterfaces) {
|
||||
m_shownInterfaces = shownInterfaces;
|
||||
emit shownInterfacesChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,8 +197,7 @@ void ThingsProxy::setHiddenInterfaces(const QStringList &hiddenInterfaces)
|
||||
if (m_hiddenInterfaces != hiddenInterfaces) {
|
||||
m_hiddenInterfaces = hiddenInterfaces;
|
||||
emit hiddenInterfacesChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,8 +211,7 @@ void ThingsProxy::setNameFilter(const QString &nameFilter)
|
||||
if (m_nameFilter != nameFilter) {
|
||||
m_nameFilter = nameFilter;
|
||||
emit nameFilterChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,8 +225,7 @@ void ThingsProxy::setShownThingClassIds(const QList<QUuid> &shownThingClassIds)
|
||||
if (m_shownThingClassIds != shownThingClassIds) {
|
||||
m_shownThingClassIds = shownThingClassIds;
|
||||
emit shownThingClassIdsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,8 +240,7 @@ void ThingsProxy::setHiddenThingClassIds(const QList<QUuid> &hiddenThingClassIds
|
||||
if (m_hiddenThingClassIds != hiddenThingClassIds) {
|
||||
m_hiddenThingClassIds = hiddenThingClassIds;
|
||||
emit hiddenThingClassIdsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,8 +254,7 @@ void ThingsProxy::setRequiredEventName(const QString &requiredEventName)
|
||||
if (m_requiredEventName != requiredEventName) {
|
||||
m_requiredEventName = requiredEventName;
|
||||
emit requiredEventNameChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,8 +268,7 @@ void ThingsProxy::setRequiredStateName(const QString &requiredStateName)
|
||||
if (m_requiredStateName != requiredStateName) {
|
||||
m_requiredStateName = requiredStateName;
|
||||
emit requiredStateNameChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,8 +282,7 @@ void ThingsProxy::setRequiredActionName(const QString &requiredActionName)
|
||||
if (m_requiredActionName != requiredActionName) {
|
||||
m_requiredActionName = requiredActionName;
|
||||
emit requiredActionNameChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,8 +296,7 @@ void ThingsProxy::setShowDigitalInputs(bool showDigitalInputs)
|
||||
if (m_showDigitalInputs != showDigitalInputs) {
|
||||
m_showDigitalInputs = showDigitalInputs;
|
||||
emit showDigitalInputsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,8 +310,7 @@ void ThingsProxy::setShowDigitalOutputs(bool showDigitalOutputs)
|
||||
if (m_showDigitalOutputs != showDigitalOutputs) {
|
||||
m_showDigitalOutputs = showDigitalOutputs;
|
||||
emit showDigitalOutputsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,8 +324,7 @@ void ThingsProxy::setShowAnalogInputs(bool showAnalogInputs)
|
||||
if (m_showAnalogInputs != showAnalogInputs) {
|
||||
m_showAnalogInputs = showAnalogInputs;
|
||||
emit showAnalogInputsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,8 +338,7 @@ void ThingsProxy::setShowAnalogOutputs(bool showAnalogOutputs)
|
||||
if (m_showAnalogOutputs != showAnalogOutputs) {
|
||||
m_showAnalogOutputs = showAnalogOutputs;
|
||||
emit showAnalogOutputsChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,8 +352,7 @@ void ThingsProxy::setFilterBatteryCritical(bool filterBatteryCritical)
|
||||
if (m_filterBatteryCritical != filterBatteryCritical) {
|
||||
m_filterBatteryCritical = filterBatteryCritical;
|
||||
emit filterBatteryCriticalChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,8 +366,7 @@ void ThingsProxy::setFilterDisconnected(bool filterDisconnected)
|
||||
if (m_filterDisconnected != filterDisconnected) {
|
||||
m_filterDisconnected = filterDisconnected;
|
||||
emit filterDisconnectedChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,8 +380,7 @@ void ThingsProxy::setFilterSetupFailed(bool filterSetupFailed)
|
||||
if (m_filterSetupFailed != filterSetupFailed) {
|
||||
m_filterSetupFailed = filterSetupFailed;
|
||||
emit filterSetupFailedChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,8 +394,7 @@ void ThingsProxy::setFilterUpdates(bool filterUpdates)
|
||||
if (m_filterUpdates != filterUpdates) {
|
||||
m_filterUpdates = filterUpdates;
|
||||
emit filterUpdatesChanged();
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,8 +409,7 @@ void ThingsProxy::setParamsFilter(const QVariantMap ¶msFilter)
|
||||
m_paramsFilter = paramsFilter;
|
||||
emit paramsFilterChanged();
|
||||
|
||||
invalidateFilter();
|
||||
emit countChanged();
|
||||
invalidateFilterInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,6 +482,15 @@ int ThingsProxy::indexOf(Thing *thing) const
|
||||
return mapFromSource(sourceIndex).row();
|
||||
}
|
||||
|
||||
void ThingsProxy::invalidateFilterInternal()
|
||||
{
|
||||
int oldCount = rowCount();
|
||||
invalidateFilter();
|
||||
if (oldCount != rowCount()) {
|
||||
emit countChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Thing *ThingsProxy::getInternal(int source_index) const
|
||||
{
|
||||
Things* d = qobject_cast<Things*>(sourceModel());
|
||||
@ -543,11 +557,22 @@ bool ThingsProxy::filterAcceptsRow(int source_row, const QModelIndex &source_par
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!m_hideTagId.isEmpty()) {
|
||||
Tag *tag = m_engine->tagsManager()->tags()->findThingTag(thing->id().toString(), m_hideTagId);
|
||||
if (tag && m_hideTagValue.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (tag && tag->value() == m_hideTagValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_filterThingId.isEmpty()) {
|
||||
if (thing->id() != QUuid(m_filterThingId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ThingClass *thingClass = m_engine->thingManager()->thingClasses()->getThingClass(thing->thingClassId());
|
||||
// qDebug() << "Checking thing" << thingClass->name() << thingClass->interfaces();
|
||||
if (!m_shownInterfaces.isEmpty()) {
|
||||
|
||||
@ -48,6 +48,8 @@ class ThingsProxy : public QSortFilterProxyModel
|
||||
Q_PROPERTY(QString filterTagId READ filterTagId WRITE setFilterTagId NOTIFY filterTagIdChanged)
|
||||
Q_PROPERTY(QString filterTagValue READ filterTagValue WRITE setFilterTagValue NOTIFY filterTagValueChanged)
|
||||
Q_PROPERTY(QString filterThingId READ filterThingId WRITE setFilterThingId NOTIFY filterThingIdChanged)
|
||||
Q_PROPERTY(QString hideTagId READ hideTagId WRITE setHideTagId NOTIFY hideTagIdChanged)
|
||||
Q_PROPERTY(QString hideTagValue READ hideTagValue WRITE setHideTagValue NOTIFY hideTagValueChanged)
|
||||
Q_PROPERTY(QStringList shownInterfaces READ shownInterfaces WRITE setShownInterfaces NOTIFY shownInterfacesChanged)
|
||||
Q_PROPERTY(QStringList hiddenInterfaces READ hiddenInterfaces WRITE setHiddenInterfaces NOTIFY hiddenInterfacesChanged)
|
||||
Q_PROPERTY(QString nameFilter READ nameFilter WRITE setNameFilter NOTIFY nameFilterChanged)
|
||||
@ -101,6 +103,12 @@ public:
|
||||
QString filterTagValue() const;
|
||||
void setFilterTagValue(const QString &tagValue);
|
||||
|
||||
QString hideTagId() const;
|
||||
void setHideTagId(const QString &tagId);
|
||||
|
||||
QString hideTagValue() const;
|
||||
void setHideTagValue(const QString &tagValue);
|
||||
|
||||
QString filterThingId() const;
|
||||
void setFilterThingId(const QString &filterThingId);
|
||||
|
||||
@ -172,6 +180,8 @@ signals:
|
||||
void parentProxyChanged();
|
||||
void filterTagIdChanged();
|
||||
void filterTagValueChanged();
|
||||
void hideTagIdChanged();
|
||||
void hideTagValueChanged();
|
||||
void filterThingIdChanged();
|
||||
void shownInterfacesChanged();
|
||||
void hiddenInterfacesChanged();
|
||||
@ -195,6 +205,9 @@ signals:
|
||||
void sortOrderChanged();
|
||||
void countChanged();
|
||||
|
||||
private slots:
|
||||
void invalidateFilterInternal();
|
||||
|
||||
private:
|
||||
Thing *getInternal(int source_index) const;
|
||||
|
||||
@ -202,6 +215,8 @@ private:
|
||||
ThingsProxy *m_parentProxy = nullptr;
|
||||
QString m_filterTagId;
|
||||
QString m_filterTagValue;
|
||||
QString m_hideTagId;
|
||||
QString m_hideTagValue;
|
||||
QString m_filterThingId;
|
||||
QStringList m_shownInterfaces;
|
||||
QStringList m_hiddenInterfaces;
|
||||
|
||||
@ -269,5 +269,7 @@
|
||||
<file>ui/mainviews/energy/CurrentConsumptionBalancePieChart.qml</file>
|
||||
<file>ui/mainviews/energy/ConsumerStats.qml</file>
|
||||
<file>ui/system/PackageListPage.qml</file>
|
||||
<file>ui/mainviews/energy/StatsBase.qml</file>
|
||||
<file>ui/mainviews/energy/EnergySettingsPage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -110,6 +110,8 @@ Item {
|
||||
property color darkGray: "darkGray"
|
||||
property color blue: "deepskyblue"
|
||||
property color orange: "#f6a625"
|
||||
property color purple: "#6d5fd5"
|
||||
property color lime: "#99ca53"
|
||||
|
||||
readonly property int fastAnimationDuration: 100
|
||||
readonly property int animationDuration: 150
|
||||
|
||||
@ -44,11 +44,25 @@ MainViewBase {
|
||||
|
||||
contentY: flickable.contentY + topMargin
|
||||
|
||||
headerButtons: [
|
||||
{
|
||||
iconSource: "/ui/images/configure.svg",
|
||||
color: Style.iconColor,
|
||||
trigger: function() {
|
||||
pageStack.push("energy/EnergySettingsPage.qml", {energyManager: energyManager});
|
||||
},
|
||||
visible: true
|
||||
}
|
||||
]
|
||||
|
||||
EnergyManager {
|
||||
id: energyManager
|
||||
engine: _engine
|
||||
}
|
||||
|
||||
property var thingColors: [Style.blue, Style.green, Style.red, Style.yellow, Style.purple, Style.yellow, Style.lime]
|
||||
|
||||
|
||||
ThingsProxy {
|
||||
id: energyMeters
|
||||
engine: _engine
|
||||
@ -60,6 +74,7 @@ MainViewBase {
|
||||
id: consumers
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterconsumer"]
|
||||
hideTagId: "hiddenInEnergyView"
|
||||
}
|
||||
|
||||
ThingsProxy {
|
||||
@ -97,57 +112,60 @@ MainViewBase {
|
||||
columnSpacing: 0
|
||||
|
||||
|
||||
// CurrentConsumptionBalancePieChart {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// energyManager: energyManager
|
||||
// visible: producers.count > 0
|
||||
// }
|
||||
// CurrentProductionBalancePieChart {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// energyManager: energyManager
|
||||
// visible: producers.count > 0
|
||||
// }
|
||||
CurrentConsumptionBalancePieChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
}
|
||||
CurrentProductionBalancePieChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
visible: producers.count > 0
|
||||
}
|
||||
|
||||
// PowerConsumptionBalanceHistory {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// visible: producers.count > 0
|
||||
// }
|
||||
PowerConsumptionBalanceHistory {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
}
|
||||
|
||||
// PowerProductionBalanceHistory {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// visible: producers.count > 0
|
||||
// }
|
||||
PowerProductionBalanceHistory {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
visible: producers.count > 0
|
||||
}
|
||||
|
||||
// ConsumersBarChart {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// energyManager: energyManager
|
||||
// visible: consumers.count > 0
|
||||
// }
|
||||
// ConsumersHistory {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// visible: consumers.count > 0
|
||||
// }
|
||||
ConsumersBarChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
consumers: consumers
|
||||
}
|
||||
ConsumersHistory {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
consumers: consumers
|
||||
}
|
||||
|
||||
PowerBalanceStats {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
}
|
||||
// ConsumerStats {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.preferredHeight: width
|
||||
// energyManager: energyManager
|
||||
// visible: consumers.count > 0
|
||||
// }
|
||||
ConsumerStats {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
energyManager: energyManager
|
||||
visible: consumers.count > 0
|
||||
colors: root.thingColors
|
||||
consumers: consumers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EmptyViewPlaceholder {
|
||||
|
||||
@ -3,180 +3,241 @@ import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.3
|
||||
import QtCharts 2.3
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components/"
|
||||
|
||||
ChartView {
|
||||
StatsBase {
|
||||
id: root
|
||||
backgroundColor: "transparent"
|
||||
legend.alignment: Qt.AlignBottom
|
||||
legend.font: Style.extraSmallFont
|
||||
legend.labelColor: !powerLogs.fetchingData && powerLogs.count > 0 ? Style.foregroundColor : Style.gray
|
||||
|
||||
// margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
title: qsTr("Consumer statistics")
|
||||
titleColor: Style.foregroundColor
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
property var colors: null
|
||||
|
||||
property ThingsProxy consumers: null
|
||||
|
||||
readonly property date dayStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
return d;
|
||||
Connections {
|
||||
target: consumers
|
||||
onCountChanged: root.update()
|
||||
}
|
||||
|
||||
readonly property var daysList: {
|
||||
var ret = []
|
||||
for (var i = 6; i >= 0; i--) {
|
||||
var last = new Date(dayStart)
|
||||
ret.push(last.setDate(last.getDate() - i))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
readonly property var daysListNames: {
|
||||
var ret = []
|
||||
for (var i = 0; i < daysList.length; i++) {
|
||||
ret.push(new Date(daysList[i]).toLocaleString(Qt.locale(), "ddd"))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
readonly property date weekStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
d.setDate(d.getDate() - d.getDay());
|
||||
return d
|
||||
}
|
||||
readonly property date monthStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(1);
|
||||
return d;
|
||||
}
|
||||
readonly property date yearStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(1);
|
||||
d.setMonth(0);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
ThingsProxy {
|
||||
id: consumers
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterconsumer"]
|
||||
sortStateName: "totalEnergyConsumed"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
|
||||
}
|
||||
Connections {
|
||||
target: engine.thingManager
|
||||
onFetchingDataChanged: {
|
||||
var thingIds = []
|
||||
for (var i = 0; i < consumers.count; i++) {
|
||||
thingIds.push(consumers.get(i).id)
|
||||
}
|
||||
powerLogs.thingIds = thingIds
|
||||
onFetchingDataChanged: root.update()
|
||||
}
|
||||
Connections {
|
||||
target: engine.tagsManager
|
||||
onBusyChanged: root.update()
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (engine.thingManager.fetchingData || engine.tagsManager.busy) {
|
||||
return
|
||||
}
|
||||
powerLogs.loadingInhibited = true
|
||||
|
||||
var thingIds = []
|
||||
for (var i = 0; i < consumers.count; i++) {
|
||||
thingIds.push(consumers.get(i).id)
|
||||
}
|
||||
powerLogs.thingIds = thingIds
|
||||
|
||||
var config = root.configs[selectionTabs.currentValue.config]
|
||||
// print("config:", config.startTime(), config.sampleList(), config.sampleListNames())
|
||||
|
||||
powerLogs.sampleRate = config.sampleRate
|
||||
powerLogs.startTime = config.startTime()
|
||||
powerLogs.sampleList = config.sampleList()
|
||||
|
||||
barSeries.clear();
|
||||
barSeries.thingBarSetMap = ({})
|
||||
|
||||
valueAxis.max = 0
|
||||
categoryAxis.categories = config.sampleListNames()
|
||||
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
|
||||
powerLogs.loadingInhibited = false
|
||||
}
|
||||
|
||||
ThingPowerLogs {
|
||||
id: powerLogs
|
||||
engine: _engine
|
||||
sampleRate: EnergyLogs.SampleRate1Day
|
||||
startTime: root.yearStart
|
||||
loadingInhibited: thingIds.length === 0
|
||||
loadingInhibited: true
|
||||
|
||||
property var sampleList: null
|
||||
|
||||
onFetchingDataChanged: {
|
||||
if (!fetchingData) {
|
||||
barSeries.clear();
|
||||
for (var j = 0; j < consumers.count; j++) {
|
||||
var consumer = consumers.get(j)
|
||||
// Note: Needs to be let, not var so the lambda capture below copies it instead of capturing the reference
|
||||
let consumer = consumers.get(j)
|
||||
// print("ConsumerStats: Adding thing:", consumer.name)
|
||||
let totalEnergyConsumedState = consumer.stateByName("totalEnergyConsumed")
|
||||
// print("Adding consumer:", consumer.name, consumer.id)
|
||||
var consumptionValues = []
|
||||
for (var i = 0; i < daysList.length; i++) {
|
||||
var start = powerLogs.find(consumer.id, new Date(daysList[i]))
|
||||
for (var i = 0; i < sampleList.length; i++) {
|
||||
var start = powerLogs.find(consumer.id, new Date(sampleList[i]))
|
||||
var startValue = start !== null ? start.totalConsumption : 0
|
||||
var end = i < daysList.length -1 ? powerLogs.find(consumer.id, new Date(daysList[i+1])) : null
|
||||
var endValue = end !== null ? end.totalConsumption : start !== null ? consumer.stateByName("totalEnergyConsumed").value : 0
|
||||
var end = i < sampleList.length -1 ? powerLogs.find(consumer.id, new Date(sampleList[i+1])) : null
|
||||
var endValue = end !== null ? end.totalConsumption : 0
|
||||
if (i == sampleList.length - 1) {
|
||||
endValue = totalEnergyConsumedState.value
|
||||
}
|
||||
|
||||
// print("adding sample", new Date(sampleList[i]), start ? start.timestamp : "X", " - ", end ? end.timestamp : "X")
|
||||
// print("values. start:", startValue, "end", endValue, "diff", endValue - startValue)
|
||||
var consumptionValue = endValue - startValue
|
||||
// print("Value", consumptionValue)
|
||||
consumptionValues.push(consumptionValue)
|
||||
valueAxis.adjustMax(consumptionValue)
|
||||
}
|
||||
var barSet = barSeries.append(consumer.name, consumptionValues)
|
||||
let barSet = barSeries.append(consumer.name, consumptionValues)
|
||||
barSet.color = root.colors[j % root.colors.length]
|
||||
barSet.borderWidth = 0
|
||||
barSet.borderColor = barSet.color
|
||||
barSeries.thingBarSetMap[consumer] = barSet
|
||||
|
||||
totalEnergyConsumedState.onValueChanged.connect(function() {
|
||||
var sampleList = root.configs[selectionTabs.currentValue.config].sampleList()
|
||||
var lastSample = sampleList[sampleList.length - 1]
|
||||
// print("sampleList:", powerLogs.sampleList)
|
||||
var start = powerLogs.find(consumer.id, new Date(lastSample))
|
||||
// print("consumer value changed:", consumer.name, totalEnergyConsumedState.value, start.timestamp, start.totalConsumption)
|
||||
var barSet = barSeries.thingBarSetMap[consumer]
|
||||
barSet.replace(barSet.count - 1, totalEnergyConsumedState.value - start.totalConsumption)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: labelsLayout
|
||||
x: Style.smallMargins
|
||||
y: root.plotArea.y
|
||||
height: root.plotArea.height
|
||||
width: plotArea.x - x
|
||||
Repeater {
|
||||
model: valueAxis.tickCount
|
||||
delegate: Label {
|
||||
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
|
||||
width: parent.width - Style.smallMargins
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(0) + "kWh"
|
||||
verticalAlignment: Text.AlignTop
|
||||
font: Style.extraSmallFont
|
||||
color: !powerLogs.fetchingData && powerLogs.count > 0 ? Style.foregroundColor : Style.gray
|
||||
onEntriesAdded: {
|
||||
if (fetchingData) {
|
||||
return
|
||||
}
|
||||
|
||||
chartView.animationOptions = ChartView.NoAnimation
|
||||
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var entry = entries[i]
|
||||
var thing = engine.thingManager.things.getThing(entry.thingId)
|
||||
// print("Adding new sample. thing:", thing.name);
|
||||
// print("Timestamp:", entry.timestamp)
|
||||
var totalEnergyConsumedState = thing.stateByName("totalEnergyConsumed")
|
||||
// print("current total:", entry.totalConsumption)
|
||||
|
||||
var consumptionValue = totalEnergyConsumedState.value - entry.totalConsumption
|
||||
// print("new slot total:", consumptionValue)
|
||||
|
||||
categoryAxis.categories = configs[selectionTabs.currentValue.config].sampleListNames()
|
||||
barSeries.thingBarSetMap[thing].append(consumptionValue)
|
||||
barSeries.thingBarSetMap[thing].remove(0, 1);
|
||||
}
|
||||
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
}
|
||||
}
|
||||
|
||||
BarSeries {
|
||||
id: barSeries
|
||||
axisX: BarCategoryAxis {
|
||||
id: categoryAxis
|
||||
categories: daysListNames
|
||||
labelsColor: !powerLogs.fetchingData && powerLogs.count > 0 ? Style.foregroundColor : Style.gray
|
||||
labelsFont: Style.extraSmallFont
|
||||
gridVisible: false
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Consumers statistics")
|
||||
|
||||
}
|
||||
axisY: ValueAxis {
|
||||
id: valueAxis
|
||||
min: 0
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
labelsVisible: false
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
|
||||
function adjustMax(newValue) {
|
||||
if (max < newValue) {
|
||||
max = Math.ceil(newValue)
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.smallMargins
|
||||
Layout.rightMargin: Style.smallMargins
|
||||
currentIndex: 0
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
append({modelData: qsTr("Months"), config: "months" })
|
||||
append({modelData: qsTr("Weeks"), config: "weeks" })
|
||||
append({modelData: qsTr("Days"), config: "days" })
|
||||
append({modelData: qsTr("Hours"), config: "hours" })
|
||||
// append({modelData: qsTr("Minutes"), config: "minutes" })
|
||||
|
||||
selectionTabs.currentIndex = 2
|
||||
}
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
root.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
x: root.plotArea.x
|
||||
y: root.plotArea.y
|
||||
width: root.plotArea.width
|
||||
height: root.plotArea.height
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("No data available")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: !powerLogs.fetchingData && powerLogs.count == 0
|
||||
|
||||
ChartView {
|
||||
id: chartView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
// margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
backgroundColor: "transparent"
|
||||
legend.alignment: Qt.AlignBottom
|
||||
legend.font: Style.extraSmallFont
|
||||
legend.labelColor: Style.foregroundColor
|
||||
|
||||
|
||||
Item {
|
||||
id: labelsLayout
|
||||
x: Style.smallMargins
|
||||
y: chartView.plotArea.y
|
||||
height: chartView.plotArea.height
|
||||
width: chartView.plotArea.x - x
|
||||
Repeater {
|
||||
model: valueAxis.tickCount
|
||||
delegate: Label {
|
||||
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
|
||||
width: parent.width - Style.smallMargins
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(1) + "kWh"
|
||||
verticalAlignment: Text.AlignTop
|
||||
font: Style.extraSmallFont
|
||||
color: Style.foregroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarSeries {
|
||||
id: barSeries
|
||||
axisX: BarCategoryAxis {
|
||||
id: categoryAxis
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
gridVisible: false
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
}
|
||||
axisY: ValueAxis {
|
||||
id: valueAxis
|
||||
min: 0
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
labelsVisible: false
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
|
||||
function adjustMax(newValue) {
|
||||
if (max < newValue) {
|
||||
max = Math.ceil(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var thingBarSetMap: ({})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,13 @@ Item {
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
|
||||
property ThingsProxy consumers: ThingsProxy {
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterconsumer"]
|
||||
}
|
||||
|
||||
property var colors: null
|
||||
|
||||
property int tickCount: 5
|
||||
|
||||
property int labelsWidth: 40
|
||||
@ -148,13 +155,12 @@ Item {
|
||||
ColorIcon {
|
||||
anchors.centerIn: parent
|
||||
name: consumerDelegate.thing ? app.interfacesToIcon(consumerDelegate.thing.thingClass.interfaces) : "energy"
|
||||
color: root.colors[index % root.colors.length]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ ChartView {
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
property var colors: null
|
||||
|
||||
title: qsTr("Consumers history")
|
||||
titleColor: Style.foregroundColor
|
||||
|
||||
@ -19,6 +21,17 @@ ChartView {
|
||||
legend.labelColor: Style.foregroundColor
|
||||
legend.font: Style.extraSmallFont
|
||||
|
||||
property ThingsProxy consumers: null
|
||||
|
||||
Connections {
|
||||
target: consumers
|
||||
onCountChanged: d.updateConsumers()
|
||||
}
|
||||
Connections {
|
||||
target: engine.tagsManager
|
||||
onBusyChanged: d.updateConsumers()
|
||||
}
|
||||
|
||||
ThingPowerLogs {
|
||||
id: thingPowerLogs
|
||||
engine: _engine
|
||||
@ -75,14 +88,14 @@ ChartView {
|
||||
}
|
||||
}
|
||||
|
||||
ThingsProxy {
|
||||
id: consumers
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterconsumer"]
|
||||
}
|
||||
Connections {
|
||||
target: engine.thingManager
|
||||
onFetchingDataChanged: d.updateConsumers()
|
||||
onThingAdded: {
|
||||
if (thing.thingClass.interfaces.indexOf("smartmeterconsumer") >= 0) {
|
||||
d.updateConsumers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -100,9 +113,10 @@ ChartView {
|
||||
property var thingsSeriesMap: ({})
|
||||
|
||||
function updateConsumers() {
|
||||
if (engine.thingManager.fetchingData) {
|
||||
if (engine.thingManager.fetchingData || engine.tagsManager.busy) {
|
||||
return;
|
||||
}
|
||||
thingPowerLogs.loadingInhibited = true;
|
||||
|
||||
for (var thingId in d.thingsSeriesMap) {
|
||||
root.removeSeries(d.thingsSeriesMap[thingId])
|
||||
@ -116,20 +130,22 @@ ChartView {
|
||||
var baseSeries = zeroSeries;
|
||||
if (i > 0) {
|
||||
baseSeries = d.thingsSeriesMap[consumerThingIds[i-1]].upperSeries
|
||||
print("base for:", thing.name, "is", engine.thingManager.things.getThing(consumerThingIds[i-1]).name)
|
||||
// print("base for:", thing.name, "is", engine.thingManager.things.getThing(consumerThingIds[i-1]).name)
|
||||
}
|
||||
|
||||
var series = root.createSeries(ChartView.SeriesTypeArea, thing.name, dateTimeAxis, valueAxis)
|
||||
series.lowerSeries = baseSeries
|
||||
series.upperSeries = lineSeriesComponent.createObject(series)
|
||||
series.color = root.colors[i % root.colors.length]
|
||||
series.borderWidth = 0;
|
||||
series.borderColor = series.color
|
||||
|
||||
print("Adding thingId series", thing.id, thing.name)
|
||||
// print("Adding thingId series", thing.id, thing.name)
|
||||
d.thingsSeriesMap[thing.id] = series
|
||||
consumerThingIds.push(thing.id)
|
||||
}
|
||||
thingPowerLogs.thingIds = consumerThingIds;
|
||||
thingPowerLogs.loadingInhibited = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +213,7 @@ ChartView {
|
||||
id: consumptionSeries
|
||||
axisX: dateTimeAxis
|
||||
axisY: valueAxis
|
||||
// color: Style.accentColor
|
||||
color: Style.gray
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
name: qsTr("Unknown")
|
||||
|
||||
84
nymea-app/ui/mainviews/energy/EnergySettingsPage.qml
Normal file
84
nymea-app/ui/mainviews/energy/EnergySettingsPage.qml
Normal file
@ -0,0 +1,84 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.3
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components"
|
||||
|
||||
SettingsPageBase {
|
||||
id: root
|
||||
title: qsTr("Energy settings")
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
|
||||
|
||||
|
||||
SettingsPageSectionHeader {
|
||||
text: qsTr("General")
|
||||
visible: rootMeterProxy.count > 1
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.margins
|
||||
Layout.rightMargin: Style.margins
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("Multiple energy meters are installed in the system. Please select the one you'd like to use as the root meter. That is, the one measuring the entire household.")
|
||||
visible: rootMeterProxy.count > 1
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
visible: rootMeterProxy.count > 1
|
||||
Layout.leftMargin: Style.margins
|
||||
Layout.rightMargin: Style.margins
|
||||
|
||||
Label {
|
||||
text: qsTr("Root meter")
|
||||
}
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
model: ThingsProxy {
|
||||
id: rootMeterProxy
|
||||
engine: _engine
|
||||
shownInterfaces: ["energymeter"]
|
||||
}
|
||||
|
||||
textRole: "name"
|
||||
currentIndex: rootMeterProxy.indexOf(rootMeterProxy.getThing(energyManager.rootMeterId))
|
||||
Component.onCompleted: print("root meter id:", energyManager.rootMeterId)
|
||||
onActivated: {
|
||||
energyManager.setRootMeterId(rootMeterProxy.get(index).id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsPageSectionHeader {
|
||||
text: qsTr("Consumers")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ThingsProxy {
|
||||
engine: _engine
|
||||
shownInterfaces: ["smartmeterconsumer"]
|
||||
}
|
||||
delegate: CheckDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: model.name
|
||||
checked: !tagWatcher.tag
|
||||
onToggled: {
|
||||
if (checked) {
|
||||
engine.tagsManager.untagThing(model.id, "hiddenInEnergyView")
|
||||
} else {
|
||||
engine.tagsManager.tagThing(model.id, "hiddenInEnergyView", "1")
|
||||
}
|
||||
}
|
||||
|
||||
TagWatcher {
|
||||
id: tagWatcher
|
||||
tags: engine.tagsManager.tags
|
||||
thingId: model.id
|
||||
tagId: "hiddenInEnergyView"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,341 +5,234 @@ import QtCharts 2.3
|
||||
import Nymea 1.0
|
||||
import "qrc:/ui/components/"
|
||||
|
||||
ColumnLayout {
|
||||
StatsBase {
|
||||
id: root
|
||||
|
||||
property EnergyManager energyManager: null
|
||||
|
||||
readonly property date minuteStart: {
|
||||
var d = new Date();
|
||||
d.setSeconds(0, 0)
|
||||
return d;
|
||||
}
|
||||
readonly property var minutesList: {
|
||||
var ret = []
|
||||
for (var i = 15; i >= 0; i--) {
|
||||
var last = new Date(minuteStart)
|
||||
ret.push(last.setTime(last.getTime() - i * 60 * 1000))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
readonly property var minutesListNames: {
|
||||
var ret = []
|
||||
for (var i = 0; i < minutesList.length; i++) {
|
||||
ret.push(new Date(minutesList[i]).toLocaleString(Qt.locale(), "hh:mm"))
|
||||
}
|
||||
return ret;
|
||||
QtObject {
|
||||
id: d
|
||||
property BarSet consumptionSet: null
|
||||
property BarSet productionSet: null
|
||||
property BarSet acquisitionSet: null
|
||||
property BarSet returnSet: null
|
||||
}
|
||||
|
||||
readonly property date hourStart: {
|
||||
var d = new Date();
|
||||
d.setMinutes(0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
readonly property var hoursList: {
|
||||
var ret = []
|
||||
for (var i = 24; i >= 0; i--) {
|
||||
var last = new Date(hourStart)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
readonly property var hoursListNames: {
|
||||
var ret = [];
|
||||
for (var i = 0; i < hoursList.length; i++) {
|
||||
ret.push(new Date(hoursList[i]).toLocaleString(Qt.locale(), "dd"));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
readonly property date dayStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
return d;
|
||||
}
|
||||
|
||||
readonly property var daysList: {
|
||||
var ret = []
|
||||
for (var i = 6; i >= 0; i--) {
|
||||
var last = new Date(dayStart)
|
||||
ret.push(last.setDate(last.getDate() - i))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
readonly property var daysListNames: {
|
||||
var ret = []
|
||||
for (var i = 0; i < daysList.length; i++) {
|
||||
ret.push(new Date(daysList[i]).toLocaleString(Qt.locale(), "ddd"))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
readonly property date weekStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
d.setDate(d.getDate() - d.getDay());
|
||||
return d
|
||||
}
|
||||
readonly property date monthStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(1);
|
||||
return d;
|
||||
}
|
||||
readonly property date yearStart: {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(1);
|
||||
d.setMonth(0);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Energy consumption statistics")
|
||||
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.smallMargins
|
||||
Layout.rightMargin: Style.smallMargins
|
||||
model: ListModel {
|
||||
// ListElement {
|
||||
// modelData: qsTr("Year")
|
||||
// sampleRate: EnergyLogs.SampleRate1Year
|
||||
// }
|
||||
// ListElement {
|
||||
// text: qsTr("Month")
|
||||
// sampleRate: EnergyLogs.SampleRate1Month
|
||||
// }
|
||||
// ListElement {
|
||||
// text: qsTr("Week")
|
||||
// sampleRate: EnergyLogs.SampleRate1Week
|
||||
// }
|
||||
|
||||
Component.onCompleted: {
|
||||
append({modelData: qsTr("Day"), config: "days", sampleRate: EnergyLogs.SampleRate1Day, startTime: yearStart, sampleList: daysList, sampleListNames: daysListNames })
|
||||
append({modelData: qsTr("Hour"), config: "hours", sampleRate: EnergyLogs.SampleRate1Hour, startTime: monthStart, sampleList: hoursList, sampleListNames: hoursListNames })
|
||||
}
|
||||
|
||||
// ListElement {
|
||||
// modelData: qsTr("Day")
|
||||
// sampleRate: EnergyLogs.SampleRate1Day
|
||||
// startTime: weekStart
|
||||
// }
|
||||
// ListElement {
|
||||
// modelData: qsTr("Hour")
|
||||
// sampleRate: EnergyLogs.SampleRate1Hour
|
||||
// startTime: dayStart
|
||||
// }
|
||||
}
|
||||
// currentIndex: 3
|
||||
onCurrentValueChanged: {
|
||||
print("Selecging model:", currentValue)
|
||||
powerBalanceLogs.loadingInhibited = true
|
||||
powerBalanceLogs.sampleRate = currentValue.sampleRate
|
||||
powerBalanceLogs.startTime = currentValue.startTime
|
||||
powerBalanceLogs.loadingInhibited = false
|
||||
|
||||
consumptionSeries.remove(0, consumptionSeries.count-1)
|
||||
productionSeries.remove(0, productionSeries.count-1)
|
||||
acquisitionSeries.remove(0, acquisitionSeries.count-1)
|
||||
returnSeries.remove(0, returnSeries.count-1)
|
||||
|
||||
print("sample list names:", currentValue.sampleListNames)
|
||||
categoryAxis.categories = currentValue.sampleListNames
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: energyManager
|
||||
onPowerBalanceChanged: {
|
||||
var start = powerBalanceLogs.get(powerBalanceLogs.count - 1)
|
||||
print("updating", start.timestamp, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
consumptionSeries.replace(consumptionSeries.count - 1, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
productionSeries.replace(productionSeries.count - 1, root.energyManager.totalProduction - (start ? start.totalProduction : 0))
|
||||
acquisitionSeries.replace(acquisitionSeries.count - 1, root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0))
|
||||
returnSeries.replace(returnSeries.count - 1, root.energyManager.totalReturn - (start ? start.totalReturn : 0))
|
||||
}
|
||||
}
|
||||
|
||||
PowerBalanceLogs {
|
||||
id: powerBalanceLogs
|
||||
engine: _engine
|
||||
// sampleRate: EnergyLogs.SampleRate1Day
|
||||
// startTime: root.yearStart;
|
||||
sampleRate: selectionTabs.currentValue.sampleRate// EnergyLogs.SampleRate1Min
|
||||
startTime: selectionTabs.currentValue.startTime // root.weekStart;
|
||||
|
||||
property var sampleList: minutesList
|
||||
|
||||
onFetchingDataChanged: {
|
||||
if (!fetchingData) {
|
||||
for (var i = 0; i < sampleList.length; i++) {
|
||||
var start = powerBalanceLogs.find(new Date(sampleList[i]))
|
||||
var end = null;
|
||||
if (i+1 < sampleList.length) {
|
||||
end = powerBalanceLogs.find(new Date(sampleList[i+1]))
|
||||
}
|
||||
print("** stats for:", new Date(sampleList[i]), start.timestamp, start.totalConsumption)
|
||||
var consumptionValue = (end != null ? end.totalConsumption : root.energyManager.totalConsumption) - (start ? start.totalConsumption : 0)
|
||||
var productionValue = (end != null ? end.totalProduction : root.energyManager.totalProduction) - (start ? start.totalProduction : 0)
|
||||
var acquisitionValue = (end != null ? end.totalAcquisition : root.energyManager.totalAcquisition) - (start ? start.totalAcquisition : 0)
|
||||
var returnValue = (end != null ? end.totalReturn : root.energyManager.totalReturn) - (start ? start.totalReturn : 0)
|
||||
consumptionSeries.append(consumptionValue)
|
||||
productionSeries.append(productionValue)
|
||||
acquisitionSeries.append(acquisitionValue)
|
||||
returnSeries.append(returnValue)
|
||||
|
||||
valueAxis.adjustMax(consumptionValue)
|
||||
valueAxis.adjustMax(productionValue)
|
||||
valueAxis.adjustMax(acquisitionValue)
|
||||
valueAxis.adjustMax(returnValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onEntryAdded: {
|
||||
if (fetchingData) {
|
||||
return
|
||||
}
|
||||
|
||||
var start = entry
|
||||
var consumptionValue = root.energyManager.totalConsumption - (start ? start.totalConsumption : 0)
|
||||
var productionValue = root.energyManager.totalProduction - (start ? start.totalProduction : 0)
|
||||
var acquisitionValue = root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0)
|
||||
var returnValue = root.energyManager.totalReturn - (start ? start.totalReturn : 0)
|
||||
consumptionSeries.append(consumptionValue)
|
||||
productionSeries.append(productionValue)
|
||||
acquisitionSeries.append(acquisitionValue)
|
||||
returnSeries.append(returnValue)
|
||||
consumptionSeries.remove(0, 1);
|
||||
productionSeries.remove(0, 1);
|
||||
acquisitionSeries.remove(0, 1);
|
||||
returnSeries.remove(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChartView {
|
||||
id: chartView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
backgroundColor: "transparent"
|
||||
legend.alignment: Qt.AlignBottom
|
||||
legend.font: Style.extraSmallFont
|
||||
legend.labelColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
|
||||
|
||||
// margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
// title: qsTr("Energy consumption statistics")
|
||||
// titleColor: "red"// Style.foregroundColor
|
||||
|
||||
Item {
|
||||
id: labelsLayout
|
||||
x: Style.smallMargins
|
||||
y: chartView.plotArea.y
|
||||
height: chartView.plotArea.height
|
||||
width: chartView.plotArea.x - x
|
||||
enabled: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0
|
||||
|
||||
Repeater {
|
||||
model: valueAxis.tickCount
|
||||
delegate: Label {
|
||||
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
|
||||
width: parent.width - Style.smallMargins
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(0) + "kWh"
|
||||
verticalAlignment: Text.AlignTop
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarSeries {
|
||||
axisX: BarCategoryAxis {
|
||||
id: categoryAxis
|
||||
// categories: daysListNames
|
||||
// categories: minutesListNames
|
||||
labelsColor: !powerBalanceLogs.fetchingData && powerBalanceLogs.count > 0 ? Style.foregroundColor : Style.gray
|
||||
|
||||
labelsFont: Style.extraSmallFont
|
||||
gridVisible: false
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
|
||||
}
|
||||
axisY: ValueAxis {
|
||||
id: valueAxis
|
||||
min: 0
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
labelsVisible: false
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
|
||||
function adjustMax(newValue) {
|
||||
if (max < newValue) {
|
||||
max = newValue // Math.ceil(newValue / 100) * 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarSet {
|
||||
id: consumptionSeries
|
||||
label: qsTr("Consumed")
|
||||
borderWidth: 0
|
||||
}
|
||||
BarSet {
|
||||
id: productionSeries
|
||||
label: qsTr("Produced")
|
||||
color: Style.green
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
}
|
||||
BarSet {
|
||||
id: acquisitionSeries
|
||||
label: qsTr("From grid")
|
||||
color: Style.red
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
}
|
||||
BarSet {
|
||||
id: returnSeries
|
||||
label: qsTr("To grid")
|
||||
color: Style.orange
|
||||
borderWidth: 0
|
||||
borderColor: color
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
x: chartView.plotArea.x
|
||||
y: chartView.plotArea.y
|
||||
width: chartView.plotArea.width
|
||||
height: chartView.plotArea.height
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("No data available")
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.smallMargins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: !powerBalanceLogs.fetchingData && powerBalanceLogs.count == 0
|
||||
text: qsTr("Energy consumption statistics")
|
||||
|
||||
}
|
||||
|
||||
SelectionTabs {
|
||||
id: selectionTabs
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.smallMargins
|
||||
Layout.rightMargin: Style.smallMargins
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
append({modelData: qsTr("Months"), config: "months" })
|
||||
append({modelData: qsTr("Weeks"), config: "weeks" })
|
||||
append({modelData: qsTr("Days"), config: "days" })
|
||||
append({modelData: qsTr("Hours"), config: "hours" })
|
||||
// append({modelData: qsTr("Minutes"), config: "minutes" })
|
||||
|
||||
selectionTabs.currentIndex = 2
|
||||
}
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
var config = root.configs[currentValue.config]
|
||||
print("config:", config.startTime(), config.sampleList(), config.sampleListNames())
|
||||
|
||||
powerBalanceLogs.loadingInhibited = true
|
||||
powerBalanceLogs.sampleRate = config.sampleRate
|
||||
powerBalanceLogs.startTime = config.startTime()
|
||||
powerBalanceLogs.sampleList = config.sampleList()
|
||||
powerBalanceLogs.loadingInhibited = false
|
||||
|
||||
barSeries.clear();
|
||||
|
||||
d.consumptionSet = barSeries.append(qsTr("Consumed"), [])
|
||||
d.consumptionSet.color = Style.blue
|
||||
d.consumptionSet.borderWidth = 0
|
||||
d.productionSet = barSeries.append(qsTr("Produced"), [])
|
||||
d.productionSet.color = Style.green
|
||||
d.productionSet.borderWidth = 0
|
||||
d.acquisitionSet = barSeries.append(qsTr("From grid"), [])
|
||||
d.acquisitionSet.color = Style.red
|
||||
d.acquisitionSet.borderWidth = 0
|
||||
d.returnSet = barSeries.append(qsTr("To grid"), [])
|
||||
d.returnSet.color = Style.orange
|
||||
d.returnSet.borderWidth = 0
|
||||
|
||||
|
||||
valueAxis.max = 0
|
||||
categoryAxis.categories = config.sampleListNames()
|
||||
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: energyManager
|
||||
onPowerBalanceChanged: {
|
||||
var start = powerBalanceLogs.get(powerBalanceLogs.count - 1)
|
||||
// print("balance changed:", d.consumptionSet, powerBalanceLogs, powerBalanceLogs.count)
|
||||
// print("updating", start.timestamp, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
d.consumptionSet.replace(d.consumptionSet.count - 1, root.energyManager.totalConsumption - (start ? start.totalConsumption : 0))
|
||||
d.productionSet.replace(d.productionSet.count - 1, root.energyManager.totalProduction - (start ? start.totalProduction : 0))
|
||||
d.acquisitionSet.replace(d.acquisitionSet.count - 1, root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0))
|
||||
d.returnSet.replace(d.returnSet.count - 1, root.energyManager.totalReturn - (start ? start.totalReturn : 0))
|
||||
}
|
||||
}
|
||||
|
||||
PowerBalanceLogs {
|
||||
id: powerBalanceLogs
|
||||
engine: _engine
|
||||
loadingInhibited: true
|
||||
|
||||
property var sampleList: minutesList
|
||||
|
||||
onFetchingDataChanged: {
|
||||
if (!fetchingData) {
|
||||
if (powerBalanceLogs.count == 0) {
|
||||
valueAxis.adjustMax(root.energyManager.totalConsumption)
|
||||
valueAxis.adjustMax(root.energyManager.totalAcquisition)
|
||||
valueAxis.adjustMax(root.energyManager.totalProduction)
|
||||
valueAxis.adjustMax(root.energyManager.totalReturn)
|
||||
|
||||
for (var i = 0; i < sampleList.length; i++) {
|
||||
d.consumptionSet.append(i == sampleList.length - 1 ? root.energyManager.totalConsumption : 0)
|
||||
d.productionSet.append(i == sampleList.length - 1 ? root.energyManager.totalProduction : 0)
|
||||
d.acquisitionSet.append(i == sampleList.length - 1 ? root.energyManager.totalAcquisition : 0)
|
||||
d.returnSet.append(i == sampleList.length - 1 ? root.energyManager.totalReturn : 0)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < sampleList.length; i++) {
|
||||
var start = powerBalanceLogs.find(new Date(sampleList[i]))
|
||||
var end = null;
|
||||
if (i+1 < sampleList.length) {
|
||||
end = powerBalanceLogs.find(new Date(sampleList[i+1]))
|
||||
}
|
||||
// print("** stats for:", new Date(sampleList[i]), /*start, end, */"start:", start ? start.totalConsumption : 0, "end:", end ? end.totalConsumption : root.energyManager.totalConsumption)
|
||||
var consumptionValue = (end != null ? end.totalConsumption : root.energyManager.totalConsumption) - (start ? start.totalConsumption : 0)
|
||||
var productionValue = (end != null ? end.totalProduction : root.energyManager.totalProduction) - (start ? start.totalProduction : 0)
|
||||
var acquisitionValue = (end != null ? end.totalAcquisition : root.energyManager.totalAcquisition) - (start ? start.totalAcquisition : 0)
|
||||
var returnValue = (end != null ? end.totalReturn : root.energyManager.totalReturn) - (start ? start.totalReturn : 0)
|
||||
|
||||
valueAxis.adjustMax(consumptionValue)
|
||||
valueAxis.adjustMax(productionValue)
|
||||
valueAxis.adjustMax(acquisitionValue)
|
||||
valueAxis.adjustMax(returnValue)
|
||||
|
||||
d.consumptionSet.append(consumptionValue)
|
||||
d.productionSet.append(productionValue)
|
||||
d.acquisitionSet.append(acquisitionValue)
|
||||
d.returnSet.append(returnValue)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onEntryAdded: {
|
||||
if (fetchingData) {
|
||||
return
|
||||
}
|
||||
|
||||
var start = entry
|
||||
var consumptionValue = root.energyManager.totalConsumption - (start ? start.totalConsumption : 0)
|
||||
var productionValue = root.energyManager.totalProduction - (start ? start.totalProduction : 0)
|
||||
var acquisitionValue = root.energyManager.totalAcquisition - (start ? start.totalAcquisition : 0)
|
||||
var returnValue = root.energyManager.totalReturn - (start ? start.totalReturn : 0)
|
||||
|
||||
chartView.animationOptions = ChartView.NoAnimation
|
||||
categoryAxis.categories = configs[selectionTabs.currentValue.config].sampleListNames()
|
||||
d.consumptionSet.append(consumptionValue)
|
||||
d.productionSet.append(productionValue)
|
||||
d.acquisitionSet.append(acquisitionValue)
|
||||
d.returnSet.append(returnValue)
|
||||
d.consumptionSet.remove(0, 1);
|
||||
d.productionSet.remove(0, 1);
|
||||
d.acquisitionSet.remove(0, 1);
|
||||
d.returnSet.remove(0, 1);
|
||||
chartView.animationOptions = ChartView.SeriesAnimations
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChartView {
|
||||
id: chartView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
animationOptions: ChartView.NoAnimations
|
||||
|
||||
backgroundColor: "transparent"
|
||||
legend.alignment: Qt.AlignBottom
|
||||
legend.font: Style.extraSmallFont
|
||||
legend.labelColor: Style.foregroundColor
|
||||
|
||||
// margins.left: 0
|
||||
margins.right: 0
|
||||
margins.bottom: 0
|
||||
margins.top: 0
|
||||
|
||||
Item {
|
||||
id: labelsLayout
|
||||
x: Style.smallMargins
|
||||
y: chartView.plotArea.y
|
||||
height: chartView.plotArea.height
|
||||
width: chartView.plotArea.x - x
|
||||
|
||||
Repeater {
|
||||
model: valueAxis.tickCount
|
||||
delegate: Label {
|
||||
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
|
||||
width: parent.width - Style.smallMargins
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1)))).toFixed(1) + "kWh"
|
||||
verticalAlignment: Text.AlignTop
|
||||
font: Style.extraSmallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarSeries {
|
||||
id: barSeries
|
||||
axisX: BarCategoryAxis {
|
||||
id: categoryAxis
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
gridVisible: false
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
}
|
||||
axisY: ValueAxis {
|
||||
id: valueAxis
|
||||
min: 0
|
||||
gridLineColor: Style.tileOverlayColor
|
||||
labelsVisible: false
|
||||
labelsColor: Style.foregroundColor
|
||||
labelsFont: Style.extraSmallFont
|
||||
lineVisible: false
|
||||
titleVisible: false
|
||||
shadesVisible: false
|
||||
|
||||
function adjustMax(newValue) {
|
||||
if (max < newValue) {
|
||||
max = newValue // Math.ceil(newValue / 100) * 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
177
nymea-app/ui/mainviews/energy/StatsBase.qml
Normal file
177
nymea-app/ui/mainviews/energy/StatsBase.qml
Normal file
@ -0,0 +1,177 @@
|
||||
import QtQuick 2.0
|
||||
import Nymea 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property int minutesCount: 10
|
||||
property int hoursCount: 12
|
||||
property int daysCount: 7
|
||||
property int weeksCount: 12
|
||||
property int monthsCount: 12
|
||||
|
||||
property var configs: ({
|
||||
minutes: {
|
||||
startTime: minutesStart,
|
||||
sampleRate: EnergyLogs.SampleRate1Min,
|
||||
sampleList: minutesList,
|
||||
sampleListNames: minutesListNames
|
||||
},
|
||||
hours: {
|
||||
startTime: hoursStart,
|
||||
sampleRate: EnergyLogs.SampleRate1Hour,
|
||||
sampleList: hoursList,
|
||||
sampleListNames: hoursListNames
|
||||
},
|
||||
days: {
|
||||
startTime: daysStart,
|
||||
sampleRate: EnergyLogs.SampleRate1Day,
|
||||
sampleList: daysList,
|
||||
sampleListNames: daysListNames
|
||||
},
|
||||
weeks: {
|
||||
startTime: weeksStart,
|
||||
sampleRate: EnergyLogs.SampleRate1Week,
|
||||
sampleList: weeksList,
|
||||
sampleListNames: weeksListNames
|
||||
},
|
||||
months: {
|
||||
startTime: monthsStart,
|
||||
sampleRate: EnergyLogs.SampleRate1Month,
|
||||
sampleList: monthsList,
|
||||
sampleListNames: monthsListNames
|
||||
}
|
||||
})
|
||||
|
||||
function minutesStart() {
|
||||
var d = new Date();
|
||||
d.setMinutes(d.getMinutes() - minutesCount + 1, 0, 0)
|
||||
return d;
|
||||
}
|
||||
function minutesList() {
|
||||
var ret = []
|
||||
var startTime = minutesStart();
|
||||
for (var i = 0; i < minutesCount; i++) {
|
||||
var last = new Date(startTime)
|
||||
ret.push(last.setTime(last.getTime() + i * 60 * 1000))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function minutesListNames() {
|
||||
var ret = []
|
||||
var list = minutesList()
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
ret.push(new Date(list[i]).toLocaleString(Qt.locale(), "hh:mm"))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function hoursStart() {
|
||||
var d = new Date();
|
||||
d.setHours(d.getHours() - hoursCount + 1, 0, 0, 0)
|
||||
return d;
|
||||
}
|
||||
function hoursList() {
|
||||
var ret = []
|
||||
var startTime = hoursStart();
|
||||
for (var i = 0; i < hoursCount; i++) {
|
||||
var last = new Date(startTime)
|
||||
ret.push(last.setTime(last.getTime() + i * 60 * 60 * 1000))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function hoursListNames() {
|
||||
var ret = [];
|
||||
var list = hoursList();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
ret.push(new Date(list[i]).toLocaleString(Qt.locale(), "hh"));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function daysStart() {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(d.getDate() - daysCount + 1);
|
||||
return d;
|
||||
}
|
||||
|
||||
function daysList() {
|
||||
var ret = []
|
||||
var startTime = daysStart();
|
||||
for (var i = 0; i < daysCount; i++) {
|
||||
var last = new Date(startTime)
|
||||
ret.push(last.setDate(last.getDate() + i))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function daysListNames() {
|
||||
var ret = []
|
||||
var list = daysList();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
ret.push(new Date(list[i]).toLocaleString(Qt.locale(), "ddd"))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function weeksStart() {
|
||||
var d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
d.setDate(d.getDate() - d.getDay() - weeksCount * 7);
|
||||
return d
|
||||
}
|
||||
function weeksList() {
|
||||
var ret = []
|
||||
var startTime = weeksStart();
|
||||
for (var i = 0; i < weeksCount; i++) {
|
||||
var last = new Date(startTime)
|
||||
ret.push(last.setDate(last.getDate() + i * 7))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function weeksListNames() {
|
||||
var ret = []
|
||||
var list = weeksList();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var d = new Date(list[i])
|
||||
var dayNum = d.getDay() || 7;
|
||||
d.setDate(d.getDate() + 4 - dayNum);
|
||||
ret.push(Math.ceil((((d - yearStart()) / 86400000) + 1)/7))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function monthsStart() {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setMonth(d.getMonth() - monthsCount + 1, 1);
|
||||
return d;
|
||||
}
|
||||
function monthsList() {
|
||||
var ret = []
|
||||
var startTime = monthsStart();
|
||||
for (var i = 0; i < monthsCount; i++) {
|
||||
var last = new Date(startTime)
|
||||
ret.push(last.setMonth(last.getMonth() + i))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function monthsListNames() {
|
||||
var ret = []
|
||||
var list = monthsList();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
ret.push(new Date(list[i]).toLocaleString(Qt.locale(), "MMM"))
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function yearStart() {
|
||||
var d = new Date();
|
||||
d.setHours(0,0,0,0);
|
||||
d.setDate(1);
|
||||
d.setMonth(0);
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
@ -40,7 +40,7 @@ SettingsPageBase {
|
||||
title: qsTr("All packages")
|
||||
|
||||
property Packages packages: engine.systemController.packages
|
||||
property string filter: ""
|
||||
property alias filter: filterTextField.text
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
@ -53,8 +53,6 @@ SettingsPageBase {
|
||||
TextField {
|
||||
id: filterTextField
|
||||
Layout.fillWidth: true
|
||||
text: packageListPage.filter
|
||||
onTextChanged: packageListPage.filter = text
|
||||
}
|
||||
ColorIcon {
|
||||
name: "close"
|
||||
@ -78,7 +76,7 @@ SettingsPageBase {
|
||||
model: PackagesFilterModel {
|
||||
id: filterModel
|
||||
packages: packageListPage.packages
|
||||
nameFilter: packageListPage.filter
|
||||
nameFilter: filterTextField.displayText
|
||||
}
|
||||
|
||||
delegate: NymeaSwipeDelegate {
|
||||
|
||||
Reference in New Issue
Block a user