Skip to content

Commit

Permalink
Merge d7bc8d1 into 8207ae9
Browse files Browse the repository at this point in the history
  • Loading branch information
peuter committed Mar 25, 2023
2 parents 8207ae9 + d7bc8d1 commit ff3584a
Show file tree
Hide file tree
Showing 24 changed files with 405 additions and 56 deletions.
5 changes: 5 additions & 0 deletions client/source/class/cv/io/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ qx.Class.define('cv.io.Client', {
check: 'String',
nullable: true,
event: 'changedServer'
},

name: {
check: 'String',
nullable: true
}
},

Expand Down
8 changes: 8 additions & 0 deletions client/source/class/cv/io/IClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ qx.Interface.define('cv.io.IClient', {
dataReceived: {
check: 'Boolean',
init: false
},

/**
* The name this client is registered for
*/
name: {
check: 'String',
nullable: true
}
},

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"tile-group-open": "e34fef8052edbda51c960a3e36aa46ed",
"tile-group-value": "65ca859dfa925a5571474017d359cbd8",
"cv-image": "df7acaca8c7c95c18b943a34acad61db",
"cv-js-list": "ff8a5398586d23abc54418f9ad321397",
"cv-js-list": "f2b537cc44664aa84c65a4618a8a5d9a",
"cv-data-list": "4b350281dc4c82d4c1b3dfbddf25a55c",
"cv-backend-list": "0381bb25eac1ff0b2ef5a2bed3818a45",
"cv-backend-list-empty": "ad33582682313d867112227ec706ee07",
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
"mapping-sensor-alarm-ok": "7c354925d5b6298f4628d224a335d254",
"mapping-sensor-alarm-notok": "f4b589ad7489b2159f2dd8d233c2df0d",
"mapping-oh-datetime": "2480fc1bf2cd1e3803e03a95a3b8185d",
"mapping_oh_time": "84732cf132a0d706aed6ce53b00eab10"
"mapping_oh_time": "84732cf132a0d706aed6ce53b00eab10",
"cv-info-outdated": "064477c93d26f6968ed59c468c617562"
}
36 changes: 36 additions & 0 deletions doc/manual/de/config/structure-tile/elements/address.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,42 @@ nicht mehr auf Interaktionen des Benutzers wie z.B. Mausklicks.
</cv-tile>
</cv-widget>
Widget als veraltet markieren
.............................

Besonders bei Widgets die einen Wert anzeigen ist es wichtig zu wissen, dass dieser Wert aktuell ist.
Sofern man die Möglichkeit hat den Zeitpunkt der letzten Aktualisierung vom Backend zu bekommen, kann man diesen
nutzen um das Widget als veraltet zu markieren, wenn die letzte Aktualisierung zu lange zurückliegt.

.. widget-example::

<settings design="tile" selector="cv-info">
<screenshot name="cv-info-outdated">
<data address="1/4/2">21.5</data>
<data address="1/4/3" type="time">00:00:00</data>
</screenshot>
</settings>
<cv-info format="%.2f">
<cv-address slot="address" mode="read" transform="DPT:9.001">1/4/2</cv-address>
<cv-address slot="tileAddress" transform="DPT:10.001" mode="read" target="last-update:120">1/4/3</cv-address>
<span slot="label">Wohnzimmer</span>
<span slot="unit">°C</span>
</cv-info>

Das ``target="last-update:120"`` gibt an, dass die Zeit nicht länger als 120 Sekunden zurückliegen darf, ansonsten
wird das Widget als veraltet markiert.

Dieses Feature steht in allen vordefinierten Widgets zur Verfügung. In eigenen Widgets kann man es ebenfalls nutzen,
mann muss lediglich das slot-Attribut aus dem Beispiel weglassen.

.. code:: xml
<cv-widget>
<cv-tile>
<cv-address transform="DPT:10.001" mode="read" target="last-update:120">1/4/3</cv-address>
</cv-tile>
</cv-widget>
Transform
---------
Expand Down
4 changes: 3 additions & 1 deletion source/class/cv/data/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,9 @@ qx.Class.define('cv.data.Model', {
}
const list = this.__addressList[backendName];
if (address in list) {
list[address].push(id);
if (!list[address].includes(id)) {
list[address].push(id);
}
} else {
list[address] = [id];
}
Expand Down
4 changes: 4 additions & 0 deletions source/class/cv/io/AbstractClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ qx.Class.define('cv.io.AbstractClient', {
dataReceived: {
check: 'Boolean',
init: false
},
name: {
check: 'String',
nullable: true
}
},

Expand Down
1 change: 1 addition & 0 deletions source/class/cv/io/BackendConnections.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ qx.Class.define('cv.io.BackendConnections', {
client.configuredIn = source;
}
this.__clients[name] = client;
client.setName(name);
const model = cv.data.Model.getInstance();
client.addListener('changeConnected', ev => {
const data = {};
Expand Down
3 changes: 3 additions & 0 deletions source/class/cv/io/openhab/Rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ qx.Class.define('cv.io.openhab.Rest', {

const res = req.getResponse();
const update = {};
const model = cv.data.Model.getInstance();
res.forEach(entry => {
if (entry.members && Array.isArray(entry.members)) {
// this is a group
Expand All @@ -245,6 +246,8 @@ qx.Class.define('cv.io.openhab.Rest', {
name: obj.name,
active: false
};
// register member addresses in model
model.addAddress(obj.name, null, this.getName());

if (this.__isActive(obj.type, obj.state)) {
active++;
Expand Down
119 changes: 83 additions & 36 deletions source/class/cv/ui/structure/tile/components/Chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,23 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
currentSeries: {
check: ['hour', 'day', 'week', 'month', 'year'],
init: 'day',
apply: '_refreshData'
apply: '__updateTimeRange'
},

currentPeriod: {
check: 'Number',
init: 0,
apply: '_refreshData'
apply: '__updateTimeRange'
},

startTime: {
check: 'Number',
init: 0
},

endTime: {
check: 'Number',
init: 0
}
},

Expand All @@ -125,6 +135,8 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
__showTooltip: false,
__debouncedOnResize: null,
__resizeTimeout: null,
__startTs: null,
__endTs: null,

/**
* @type {d3.Selection}
Expand Down Expand Up @@ -154,9 +166,6 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
this._initializing = true;
const element = this._element;
await cv.ui.structure.tile.components.Chart.JS_LOADED;
if (this.isVisible()) {
this._loadData();
}
this._id = cv.ui.structure.tile.components.Chart.ChartCounter++;
const chartId = 'chart-' + this._id;
element.setAttribute('data-chart-id', this._id.toString());
Expand Down Expand Up @@ -502,61 +511,100 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
}
}

if (!this._initializing) {
if (!this._initializing && this.getStartTime() > 0 && this.getEndTime() > 0) {
this._loaded = false;
this._loadData();
}
this.__updateTitle();
},

_loadData() {
if (this._loaded && Date.now() - this._loaded < 300000) {
// don't reload within 5 minutes
return;
}
const client = cv.io.BackendConnections.getClient();
if (!client) {
return;
}
if (!client.isConnected()) {
client.addListenerOnce('changeConnected', () => {
this._loadData();
});
return;
}
let url;
const dataSets = this._element.querySelectorAll(':scope > dataset');
__updateTimeRange() {
const series = this.getCurrentSeries();

const currentPeriod = this.getCurrentPeriod();
let start = 'end-1' + series;
let end = 'now';

let end = new Date();
let periodStart = new Date();
let interval = 0;
switch (series) {
case 'hour':
interval = 60 * 60 * 1000;
interval = 60 * 60;
periodStart.setHours(periodStart.getHours() - currentPeriod, 0, 0, 0);
if (currentPeriod > 0) {
end.setHours(periodStart.getHours() + 1, 0, 0, 0);
}
break;

case 'day':
interval = 24 * 60 * 60 * 1000;
interval = 24 * 60 * 60;
periodStart.setDate(periodStart.getDate() - currentPeriod);
periodStart.setHours(0, 0, 0, 0);
if (currentPeriod > 0) {
end.setDate(periodStart.getDate() + 1);
end.setHours(0, 0, 0, 0);
}
break;

case 'week':
interval = 7 * 24 * 60 * 60 * 1000;
interval = 7 * 24 * 60 * 60;
periodStart.setDate(-periodStart.getDay() - 7 * currentPeriod);
periodStart.setHours(0, 0, 0, 0);
if (currentPeriod > 0) {
end.setDate(periodStart.getDate() + 7);
end.setHours(0, 0, 0, 0);
}
break;

case 'month':
interval = 30 * 24 * 60 * 60 * 1000;
interval = 30 * 24 * 60 * 60;
periodStart.setMonth(periodStart.getMonth() - currentPeriod);
periodStart.setDate(1);
periodStart.setHours(0, 0, 0, 0);
if (currentPeriod > 0) {
end.setMonth(periodStart.getMonth() + 1, 1);
end.setHours(0, 0, 0, 0);
}
break;

case 'year':
interval = 365 * 24 * 60 * 60 * 1000;
interval = 365 * 24 * 60 * 60;
periodStart.setFullYear(periodStart.getFullYear() - currentPeriod);
periodStart.setMonth(0, 1);
periodStart.setHours(0, 0, 0, 0);
if (currentPeriod > 0) {
end.setFullYear(periodStart.getFullYear() + 1);
end.setMonth(periodStart.getMonth() + 1, 1);
end.setHours(0, 0, 0, 0);
}
break;
}
if (currentPeriod > 0 && interval > 0) {
end = Math.round((Date.now() - currentPeriod * interval) / 1000);
let startTs = Math.round(periodStart.getTime()/1000);
let endTs = Math.round(end.getTime()/1000);
if (this._element.getAttribute('background') === 'true' || !this._element.hasAttribute('selection')) {
// when have no nagivation, we can just use the old relative time range now - interval
startTs = endTs - interval;
}
this.setStartTime(startTs);
this.setEndTime(endTs);
this._refreshData();
},

_loadData() {
if (this._loaded && Date.now() - this._loaded < 300000) {
// don't reload within 5 minutes
return;
}
const client = cv.io.BackendConnections.getClient();
if (!client) {
return;
}
if (!client.isConnected()) {
client.addListenerOnce('changeConnected', () => {
this._loadData();
});
return;
}
let url;
const dataSets = this._element.querySelectorAll(':scope > dataset');

const promises = [];
if (!this._dataSetConfigs) {
Expand Down Expand Up @@ -603,8 +651,8 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
for (const src in this._dataSetConfigs) {
url = client.getResourcePath('charts', {
src: src,
start: start,
end: end
start: this.getStartTime(),
end: this.getEndTime()
});

const ts = this._dataSetConfigs[src];
Expand Down Expand Up @@ -775,7 +823,6 @@ qx.Class.define('cv.ui.structure.tile.components.Chart', {
this.error('Chart _onStatusError', ts, key, err);
},


/**
* Get svg element selection (create if not exists)
* @param parent d3.selection of the parent this element should be a child of
Expand Down
16 changes: 13 additions & 3 deletions source/class/cv/ui/structure/tile/elements/Address.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ qx.Class.define('cv.ui.structure.tile.elements.Address', {
}
//add listener
model.addUpdateListener(address, this.fireStateUpdate, this, backendName);

if (element.hasAttribute('target') && element.getAttribute('target').startsWith('last-update')) {
if (state === undefined) {
// notify tile that we have no value, so its outdated
this.fireStateUpdate(address, '-');
}
}
}
if (mode !== 'read') {
// listen for sendState events
Expand Down Expand Up @@ -84,7 +91,7 @@ qx.Class.define('cv.ui.structure.tile.elements.Address', {
qx.event.Timer.once(
() => {
cv.io.BackendConnections.getClient(backendName).write(
element.textContent,
address,
encodedValue.bus,
element
);
Expand All @@ -97,7 +104,7 @@ qx.Class.define('cv.ui.structure.tile.elements.Address', {
delay
);
} else {
cv.io.BackendConnections.getClient(backendName).write(element.textContent, encodedValue.bus, element);
cv.io.BackendConnections.getClient(backendName).write(address, encodedValue.bus, element);

if (!allowDuplicates) {
element.lastSentValue = encodedValue.raw;
Expand Down Expand Up @@ -131,13 +138,16 @@ qx.Class.define('cv.ui.structure.tile.elements.Address', {
transformedState instanceof Date ? transformedState.toLocaleString() : transformedState
);
}
let targetConfig = this._element.hasAttribute('target') ? this._element.getAttribute('target').split(':') : [];
const target = targetConfig.length > 0 ? targetConfig.shift() : '';
const ev = new CustomEvent('stateUpdate', {
bubbles: true,
cancelable: true,
detail: {
address: this._element.textContent.trim(),
state: transformedState,
target: this._element.getAttribute('target') || '',
target: target,
targetConfig: targetConfig,
raw: state,
mapping: mapping,
addressValue: this._element.hasAttribute('value') ? this._element.getAttribute('value') : null,
Expand Down

0 comments on commit ff3584a

Please sign in to comment.