@WG25 Das kann man nur mit flexCharts machen.
flexCharts installieren
Skript in javascript einfügen, HISTORY und DATA_POINT anpassen, Skript starten
Aufruf im Browser mit der unteren Adresse (Protocoll und IP anpassen)
Beispiel Skript in javascript einfügen
Skript für javascript
// ---------------------------------------------------------
// Einstellungen
// ---------------------------------------------------------
const HISTORY_INSTANCE = 'history.0';
// Hier den festen Datenpunkt eintragen
const DATA_POINT = 'DEIN DATENPUNKT MIT HISTORY';
// Name für den Flexcharts-Aufruf
const MESSAGE_NAME = 'verbrauchHistory';
// Anzahl der angezeigten Kalendertage
const DAYS = 14;
// Ein aggregierter History-Wert pro Tag
const STEP_MS = 24 * 60 * 60 * 1000;
// Anzahl der Nachkommastellen
const DECIMALS = 2;
// Diagrammüberschrift
const TITLE = `Verbrauch der letzten ${DAYS} Tage`;
// ---------------------------------------------------------
// Einheit sicher aus common.unit lesen
// ---------------------------------------------------------
function getDataPointUnit(id) {
const object = getObject(id);
if (!object) {
console.warn(`Das Objekt ${id} wurde nicht gefunden.`);
return '';
}
if (object.type !== 'state') {
console.warn(
`${id} ist kein State, sondern vom Typ "${object.type}".`
);
return '';
}
/*
* Reflect.get vermeidet den Typfehler des Editors.
* Es wird damit object.common.unit gelesen.
*/
const unit = Reflect.get(object.common, 'unit');
return typeof unit === 'string'
? unit.trim()
: '';
}
const UNIT = getDataPointUnit(DATA_POINT);
if (UNIT) {
console.info(
`Einheit von ${DATA_POINT}: ${UNIT}`
);
} else {
console.warn(
`Für ${DATA_POINT} wurde keine Einheit gefunden.`
);
}
// ---------------------------------------------------------
// Zahlenwert deutsch formatieren
// ---------------------------------------------------------
function formatNumber(value) {
const number = Number(value);
if (!Number.isFinite(number)) {
return '';
}
return number.toLocaleString('de-DE', {
minimumFractionDigits: DECIMALS,
maximumFractionDigits: DECIMALS
});
}
// ---------------------------------------------------------
// Zahlenwert mit Einheit formatieren
// ---------------------------------------------------------
function formatValue(value) {
const formattedNumber = formatNumber(value);
if (!formattedNumber) {
return '';
}
return UNIT
? `${formattedNumber} ${UNIT}`
: formattedNumber;
}
// ---------------------------------------------------------
// Flexcharts-Anfrage empfangen
// ---------------------------------------------------------
onMessage(MESSAGE_NAME, (_httpParams, callback) => {
const end = Date.now();
/*
* Beginn des ersten angezeigten Tages auf
* 00:00 Uhr setzen.
*/
const startDate = new Date();
startDate.setHours(0, 0, 0, 0);
startDate.setDate(
startDate.getDate() - (DAYS - 1)
);
const start = startDate.getTime();
getHistory(
HISTORY_INSTANCE,
{
id: DATA_POINT,
start: start,
end: end,
/*
* Tagesmaximum:
*
* Geeignet für einen Tageszähler, der während
* des Tages hochzählt und nachts zurückgesetzt wird.
*/
aggregate: 'max',
// Ein Wert pro Tag
step: STEP_MS,
timeout: 10000,
// Keine zusätzlichen Werte außerhalb des Zeitraums
removeBorderValues: true,
// Fehlende Werte nicht künstlich auffüllen
ignoreNull: false
},
(error, result) => {
if (error) {
console.error(
`History-Fehler bei ${DATA_POINT}: ` +
JSON.stringify(error)
);
callback(
createErrorChart(
'Die History-Daten konnten nicht geladen werden.'
)
);
return;
}
if (!Array.isArray(result) || result.length === 0) {
callback(
createErrorChart(
'Für den gewählten Zeitraum wurden keine Daten gefunden.'
)
);
return;
}
const historyData = result
.filter(item => {
const timestamp = Number(item?.ts);
return (
Number.isFinite(timestamp) &&
timestamp >= start &&
timestamp <= end
);
})
.sort((a, b) => {
return Number(a.ts) - Number(b.ts);
});
if (historyData.length === 0) {
callback(
createErrorChart(
'Es wurden keine gültigen History-Einträge gefunden.'
)
);
return;
}
const labels = [];
const seriesData = [];
for (const item of historyData) {
const timestamp = Number(item.ts);
const date = new Date(timestamp);
labels.push(
date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit'
})
);
if (
item.val === null ||
item.val === undefined ||
item.val === ''
) {
seriesData.push({
value: null,
label: {
show: false
}
});
continue;
}
const value = Number(item.val);
if (!Number.isFinite(value)) {
seriesData.push({
value: null,
label: {
show: false
}
});
continue;
}
const roundedValue = Number(
value.toFixed(DECIMALS)
);
/*
* Der fertige Beschriftungstext wird direkt
* am jeweiligen Datenwert gespeichert.
*
* Dadurch ist keine JavaScript-Formatterfunktion
* innerhalb des ECharts-Objekts erforderlich.
*/
seriesData.push({
value: roundedValue,
label: {
formatter: formatValue(roundedValue)
}
});
}
const hasValidValues = seriesData.some(item => {
return item.value !== null;
});
if (!hasValidValues) {
callback(
createErrorChart(
'Für die ausgewählten Tage wurden keine Zahlenwerte gefunden.'
)
);
return;
}
const seriesName = UNIT
? `Verbrauch (${UNIT})`
: 'Verbrauch';
const option = {
backgroundColor: 'transparent',
textStyle: {
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal'
},
title: {
text: TITLE,
left: 'center',
textStyle: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'bold',
fontSize: 16,
textBorderWidth: 0,
textShadowBlur: 0
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
textStyle: {
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal'
}
},
grid: {
left: 60,
right: 30,
// Platz für die senkrechten Beschriftungen
top: 120,
bottom: 70,
containLabel: true
},
xAxis: {
type: 'category',
data: labels,
axisLabel: {
interval: 0,
rotate: 0,
hideOverlap: true,
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal',
fontSize: 11,
textBorderWidth: 0,
textShadowBlur: 0
},
axisLine: {
lineStyle: {
color: '#000000'
}
},
axisTick: {
alignWithLabel: true,
lineStyle: {
color: '#000000'
}
}
},
yAxis: {
type: 'value',
// Einheit automatisch aus dem Datenpunkt
name: UNIT,
min: 0,
nameTextStyle: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal',
fontSize: 12,
textBorderWidth: 0,
textShadowBlur: 0
},
axisLabel: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal',
fontSize: 11,
textBorderWidth: 0,
textShadowBlur: 0
},
axisLine: {
show: true,
lineStyle: {
color: '#000000'
}
},
splitLine: {
lineStyle: {
opacity: 0.25
}
}
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100
}
],
series: [
{
name: seriesName,
type: 'bar',
data: seriesData,
barMaxWidth: 35,
label: {
show: true,
// Wert um 90 Grad drehen
rotate: 90,
// Wert oberhalb des Balkens anzeigen
position: 'top',
distance: 8,
align: 'left',
verticalAlign: 'middle',
// Schwarze Schrift
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'bold',
fontSize: 12,
// Keine Textumrandung
textBorderWidth: 0,
textBorderColor: 'transparent',
// Kein Texthintergrund
backgroundColor: 'transparent',
borderWidth: 0,
// Kein Textschatten
textShadowBlur: 0,
textShadowColor: 'transparent',
textShadowOffsetX: 0,
textShadowOffsetY: 0
},
itemStyle: {
borderRadius: [4, 4, 0, 0]
},
emphasis: {
label: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'bold',
textBorderWidth: 0,
textBorderColor: 'transparent',
backgroundColor: 'transparent',
borderWidth: 0,
textShadowBlur: 0,
textShadowColor: 'transparent'
}
}
}
]
};
callback(option);
}
);
});
// ---------------------------------------------------------
// Fehlerdiagramm erzeugen
// ---------------------------------------------------------
function createErrorChart(message) {
return {
backgroundColor: 'transparent',
textStyle: {
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal'
},
title: {
text: 'Flexcharts-Fehler',
subtext: message,
left: 'center',
top: 'middle',
textStyle: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'bold',
textBorderWidth: 0,
textShadowBlur: 0
},
subtextStyle: {
color: '#000000',
fontFamily: 'Arial, sans-serif',
fontStyle: 'normal',
fontWeight: 'normal',
textBorderWidth: 0,
textShadowBlur: 0
}
},
xAxis: {
show: false
},
yAxis: {
show: false
},
series: []
};
}
Eintrag im Browser
https://192.168.178.150:8082/flexcharts/echarts.html?source=script&message=verbrauchHistory&darkmode=auto