Add last status update timestamp and fetch update from the database
This commit is contained in:
parent
79d8d661f6
commit
2c235b75aa
@ -135,6 +135,7 @@ class DashboardApp {
|
||||
'chargers.columns.energyManagerMode': 'Energy manager mode',
|
||||
'chargers.columns.connected': 'Connected',
|
||||
'chargers.columns.status': 'Status',
|
||||
'chargers.columns.lastStatusUpdate': 'Last status update',
|
||||
'chargers.columns.chargingCurrent': 'Charging current',
|
||||
'chargers.columns.chargingPhases': 'Charging phases',
|
||||
'chargers.columns.currentPower': 'Current power',
|
||||
@ -283,6 +284,7 @@ class DashboardApp {
|
||||
'chargers.columns.energyManagerMode': 'Energiemanager-Modus',
|
||||
'chargers.columns.connected': 'Verbunden',
|
||||
'chargers.columns.status': 'Status',
|
||||
'chargers.columns.lastStatusUpdate': 'Letzte Statusaktualisierung',
|
||||
'chargers.columns.chargingCurrent': 'Ladestrom',
|
||||
'chargers.columns.chargingPhases': 'Ladephasen',
|
||||
'chargers.columns.currentPower': 'Aktuelle Leistung',
|
||||
@ -1306,6 +1308,7 @@ class DashboardApp {
|
||||
return;
|
||||
|
||||
const items = [
|
||||
{ label: this.t('chargers.columns.lastStatusUpdate'), key: 'lastStatusUpdate' },
|
||||
{ label: this.t('chargers.columns.version'), key: 'version' },
|
||||
{ label: this.t('chargers.columns.temperature'), key: 'temperature' },
|
||||
{ label: this.t('chargers.columns.digitalInputMode'), key: 'digitalInputMode' }
|
||||
@ -1593,6 +1596,27 @@ class DashboardApp {
|
||||
return Number.isFinite(value) ? this.t('value.unknownWithValue', { value }) : '—';
|
||||
}
|
||||
|
||||
if (key === 'lastStatusUpdate') {
|
||||
const numeric = typeof value === 'string' ? Number.parseFloat(value) : value;
|
||||
if (!Number.isFinite(numeric))
|
||||
return '—';
|
||||
|
||||
const ms = numeric > 1e12 ? numeric : numeric * 1000;
|
||||
const date = new Date(ms);
|
||||
if (Number.isNaN(date.getTime()))
|
||||
return '—';
|
||||
|
||||
const pad = part => String(part).padStart(2, '0');
|
||||
const day = pad(date.getDate());
|
||||
const month = pad(date.getMonth() + 1);
|
||||
const year = date.getFullYear();
|
||||
const hours = pad(date.getHours());
|
||||
const minutes = pad(date.getMinutes());
|
||||
const seconds = pad(date.getSeconds());
|
||||
|
||||
return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
if (key === 'currentPower' || key === 'sessionEnergy') {
|
||||
const numericValue = this.coerceFiniteNumber(value);
|
||||
if (numericValue === null)
|
||||
|
||||
@ -196,6 +196,7 @@ void EvDashEngine::onThingAdded(Thing *thing)
|
||||
m_chargers.append(thing);
|
||||
monitorChargerThing(thing);
|
||||
sendNotification("ChargerAdded", packCharger(thing));
|
||||
verifyChargerStatusChanged(thing);
|
||||
}
|
||||
|
||||
if (isCarThing(thing)) {
|
||||
@ -210,8 +211,9 @@ void EvDashEngine::onThingRemoved(const ThingId &thingId)
|
||||
foreach (Thing *thing, m_chargers) {
|
||||
if (thing->id() == thingId) {
|
||||
qCDebug(dcEvDashExperience()) << "Charger has been removed.";
|
||||
m_chargers.removeAll(thing);
|
||||
sendNotification("ChargerRemoved", packCharger(thing));
|
||||
m_chargers.removeAll(thing);
|
||||
m_chargersStatusChangedCache.remove(thing);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -224,12 +226,15 @@ void EvDashEngine::onThingRemoved(const ThingId &thingId)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EvDashEngine::onThingChanged(Thing *thing)
|
||||
{
|
||||
if (isChargerThing(thing))
|
||||
if (isChargerThing(thing)) {
|
||||
sendNotification("ChargerChanged", packCharger(thing));
|
||||
verifyChargerStatusChanged(thing);
|
||||
}
|
||||
|
||||
if (isCarThing(thing))
|
||||
sendNotification("CarChanged", packCar(thing));
|
||||
@ -261,6 +266,37 @@ void EvDashEngine::monitorCarThing(Thing *thing)
|
||||
});
|
||||
}
|
||||
|
||||
void EvDashEngine::verifyChargerStatusChanged(Thing *charger)
|
||||
{
|
||||
QString stateName = "status";
|
||||
QString source = QString("state-%1-%2").arg(charger->id().toString(QUuid::WithBraces), stateName);
|
||||
LogFetchJob *job = m_logEngine->fetchLogEntries({source}, {stateName}, {}, {}, {}, Types::SampleRateAny, Qt::DescendingOrder, 0, 1);
|
||||
connect(job, &LogFetchJob::finished, charger, [this, charger, stateName](const LogEntries &entries) {
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
qCDebug(dcEvDashExperience()) << "Last state change of" << charger->name() << stateName << "unknown";
|
||||
// Forget any cached values, the database did not return any information...
|
||||
m_chargersStatusChangedCache.remove(charger);
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 lastChangeTimestamp = entries.first().timestamp().toSecsSinceEpoch();
|
||||
qCDebug(dcEvDashExperience()) << "Last state change" << charger->name() << stateName << entries.first().timestamp().toString() << entries.first().values().first();
|
||||
|
||||
if (!m_chargersStatusChangedCache.contains(charger)) {
|
||||
m_chargersStatusChangedCache.insert(charger, lastChangeTimestamp);
|
||||
sendNotification("ChargerChanged", packCharger(charger));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_chargersStatusChangedCache.value(charger) != lastChangeTimestamp) {
|
||||
m_chargersStatusChangedCache[charger] = lastChangeTimestamp;
|
||||
sendNotification("ChargerChanged", packCharger(charger));
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool EvDashEngine::startWebSocketServer(quint16 port)
|
||||
{
|
||||
if (m_webSocketServer->isListening()) {
|
||||
@ -451,7 +487,6 @@ void EvDashEngine::sendReply(QWebSocket *socket, QJsonObject response) const
|
||||
void EvDashEngine::sendNotification(const QString ¬ification, QJsonObject payload) const
|
||||
{
|
||||
// Send to all active clients
|
||||
|
||||
for (QWebSocket *client : qAsConst(m_clients)) {
|
||||
if (m_authenticatedClients.value(client).isEmpty())
|
||||
continue;
|
||||
@ -521,28 +556,6 @@ QJsonObject EvDashEngine::packCharger(Thing *charger) const
|
||||
chargerObject.insert("pluggedIn", charger->stateValue("pluggedIn").toBool());
|
||||
chargerObject.insert("chargingAllowed", charger->stateValue("power").toBool());
|
||||
|
||||
QString stateName = "currentPower";
|
||||
chargerObject.insert(stateName, charger->stateValue(stateName).toString());
|
||||
QString source = QString("state-%1-%2").arg(charger->id().toString(QUuid::WithBraces), stateName);
|
||||
LogFetchJob *job = m_logEngine->fetchLogEntries(
|
||||
{source},
|
||||
{stateName},
|
||||
{}, {}, {}, // start/end/filter
|
||||
Types::SampleRateAny,
|
||||
Qt::DescendingOrder,
|
||||
0, 1 // offset, limit
|
||||
);
|
||||
|
||||
connect(job, &LogFetchJob::finished, this, [charger, stateName](const LogEntries &entries) {
|
||||
if (entries.isEmpty()) {
|
||||
qCDebug(dcEvDashExperience()) << "##### Last state change of" << charger->name() << stateName << "unknwon";
|
||||
return;
|
||||
}
|
||||
|
||||
//qint64 lastChangeMs = entries.first().timestamp().toMSecsSinceEpoch();
|
||||
qCDebug(dcEvDashExperience()) << "##### Last state change" << charger->name() << stateName << entries.first().timestamp().toString() << entries.first().values().first();
|
||||
});
|
||||
|
||||
if (charger->hasState("currentVersion"))
|
||||
chargerObject.insert("version", charger->stateValue("currentVersion").toDouble());
|
||||
|
||||
@ -559,10 +572,11 @@ QJsonObject EvDashEngine::packCharger(Thing *charger) const
|
||||
if (charger->hasState("error"))
|
||||
chargerObject.insert("error", charger->stateValue("error").toString());
|
||||
|
||||
if (charger->hasState("status")) {
|
||||
if (charger->hasState("status"))
|
||||
chargerObject.insert("status", charger->stateValue("status").toString());
|
||||
|
||||
|
||||
}
|
||||
if (m_chargersStatusChangedCache.contains(charger))
|
||||
chargerObject.insert("lastStatusUpdate", m_chargersStatusChangedCache.value(charger));
|
||||
|
||||
if (charger->hasState("digitalInputMode"))
|
||||
chargerObject.insert("digitalInputMode", charger->stateValue("digitalInputMode").toInt());
|
||||
@ -618,6 +632,7 @@ QStringList EvDashEngine::carThingIdsForCharger(const QString &chargerId) const
|
||||
const QString assignedCarId = chargingInfo.value(QStringLiteral("assignedCarId")).toString();
|
||||
if (!assignedCarId.isEmpty())
|
||||
carThingIds.append(assignedCarId);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -640,6 +655,7 @@ void EvDashEngine::onSessionsReceived(const QList<QVariantMap> &sessions)
|
||||
QPointer<QWebSocket> socket = m_pendingChargingSessionsRequests.take(requestId);
|
||||
if (!socket)
|
||||
continue;
|
||||
|
||||
sendReply(socket, createSuccessResponse(requestId, payload));
|
||||
}
|
||||
|
||||
@ -655,6 +671,7 @@ void EvDashEngine::onSessionsError(const QString &errorMessage)
|
||||
QPointer<QWebSocket> socket = m_pendingChargingSessionsRequests.take(requestId);
|
||||
if (!socket)
|
||||
continue;
|
||||
|
||||
sendReply(socket, createErrorResponse(requestId, errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,11 +86,15 @@ private:
|
||||
QList<QWebSocket *> m_clients;
|
||||
QHash<QWebSocket *, QString> m_authenticatedClients;
|
||||
|
||||
QList<Thing *> m_chargers;
|
||||
void monitorChargerThing(Thing *thing);
|
||||
QList<Thing *> m_cars;
|
||||
QList<Thing *> m_chargers;
|
||||
|
||||
void monitorChargerThing(Thing *thing);
|
||||
void monitorCarThing(Thing *thing);
|
||||
|
||||
QHash<Thing *, qint64> m_chargersStatusChangedCache;
|
||||
void verifyChargerStatusChanged(Thing *charger);
|
||||
|
||||
// Pending requests waiting for charging sessions data to return
|
||||
QHash<QString, QPointer<QWebSocket>> m_pendingChargingSessionsRequests;
|
||||
QStringList carThingIdsForCharger(const QString &chargerId) const;
|
||||
|
||||
Reference in New Issue
Block a user