Skip to content

Commit

Permalink
feat: support for server time
Browse files Browse the repository at this point in the history
Closes #709, closes #579
  • Loading branch information
RomRider committed Jul 4, 2024
1 parent 9374ccb commit 55c8f97
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 17 deletions.
1 change: 1 addition & 0 deletions .devcontainer/ui-lovelace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,7 @@ views:
const tomorrow = new Date(start.getTime() + 25 * 1000 * 60 * 60);
const tomorrow2 = new Date(start.getTime() + 28 * 1000 * 60 * 60);
return [
[start.getTime(), 5],
[tomorrow.getTime(), 30],
[tomorrow2.getTime(), 20]
];
Expand Down
5 changes: 3 additions & 2 deletions hacs.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"name": "apexcharts-card",
"render_readme": true
"name": "apexcharts-card",
"homeassistant": "2023.7.0",
"render_readme": true
}
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"moment": "^2.30.1",
"moment-duration-format": "^2.3.2",
"moment-range": "^4.0.2",
"moment-timezone": "^0.5.45",
"parse-duration": "^1.1.0",
"spark-md5": "^3.0.2",
"tinycolor": "^0.0.1",
Expand Down
47 changes: 35 additions & 12 deletions src/apexcharts-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {
validateInterval,
validateOffset,
getLovelace,
isUsingServerTimezone,
computeTimezoneDiffWithLocal,
} from './utils';
import ApexCharts from 'apexcharts';
import { Ripple } from '@material/mwc-ripple';
Expand Down Expand Up @@ -80,6 +82,7 @@ import {
import parse from 'parse-duration';
import tinycolor from '@ctrl/tinycolor';
import { actionHandler } from './action-handler-directive';
import { OverrideFrontendLocaleData } from './types-ha';

/* eslint no-console: 0 */
console.info(
Expand Down Expand Up @@ -163,6 +166,8 @@ class ChartsCard extends LitElement {

private _yAxisConfig?: ChartCardYAxis[];

private _serverTimeOffset = 0;

@property({ attribute: false }) _lastUpdated: Date = new Date();

@property({ type: Boolean }) private _warning = false;
Expand Down Expand Up @@ -287,6 +292,7 @@ class ChartsCard extends LitElement {
this._loaded = false;
this._dataLoaded = false;
this._updating = false;
this._serverTimeOffset = 0;
if (this._apexBrush) {
this._apexBrush.destroy();
this._apexBrush = undefined;
Expand Down Expand Up @@ -753,6 +759,10 @@ class ChartsCard extends LitElement {
private async _initialLoad() {
await this.updateComplete;

if (isUsingServerTimezone(this._hass)) {
this._serverTimeOffset = computeTimezoneDiffWithLocal(this._hass?.config.time_zone);
}

if (!this._apexChart && this.shadowRoot && this._config && this.shadowRoot.querySelector('#graph')) {
this._loaded = true;
const graph = this.shadowRoot.querySelector('#graph');
Expand Down Expand Up @@ -826,33 +836,41 @@ class ChartsCard extends LitElement {
const offset = (this._seriesOffset[index] || 0) - (this._seriesTimeDelta[index] || 0);
if (offset) {
data = offsetData(graph.history, offset);
} else if (this._serverTimeOffset) {
data = offsetData(graph.history, this._serverTimeOffset);
} else {
data = [...graph.history];
}
if (this._config?.series[index].type !== 'column' && this._config?.series[index].extend_to) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const lastPoint = data.slice(-1)[0]!;
if (this._config?.series[index].extend_to === 'end' && lastPoint[0] < end.getTime()) {
if (
this._config?.series[index].extend_to === 'end' &&
lastPoint[0] < end.getTime() - this._serverTimeOffset
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
data.push([end.getTime(), lastPoint[1]]);
} else if (this._config?.series[index].extend_to === 'now' && lastPoint[0] < now.getTime()) {
data.push([end.getTime() - this._serverTimeOffset, lastPoint[1]]);
} else if (
this._config?.series[index].extend_to === 'now' &&
lastPoint[0] < now.getTime() - this._serverTimeOffset
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
data.push([now.getTime(), lastPoint[1]]);
data.push([now.getTime() - this._serverTimeOffset, lastPoint[1]]);
}
}
const result = this._config?.series[index].invert ? { data: this._invertData(data) } : { data };
if (this._config?.series[index].show.in_chart) graphData.series.push(result);
if (this._config?.series[index].show.in_brush) brushData.series.push(result);
return;
});
graphData.annotations = this._computeAnnotations(start, end, now);
graphData.annotations = this._computeAnnotations(start, end, new Date(now.getTime() - this._serverTimeOffset));
if (this._yAxisConfig) {
graphData.yaxis = this._computeYAxisAutoMinMax(start, end);
}
if (!this._apexBrush) {
graphData.xaxis = {
min: start.getTime(),
max: this._findEndOfChart(end, false),
min: start.getTime() - this._serverTimeOffset,
max: this._findEndOfChart(new Date(end.getTime() - this._serverTimeOffset), false),
};
}
} else {
Expand Down Expand Up @@ -949,8 +967,8 @@ class ChartsCard extends LitElement {
TIMESERIES_TYPES.includes(this._config.chart_type) ? false : true,
);
if (this._apexBrush) {
const newMin = start.getTime();
const newMax = this._findEndOfChart(end, false);
const newMin = start.getTime() - this._serverTimeOffset;
const newMax = this._findEndOfChart(new Date(end.getTime() - this._serverTimeOffset), false);
brushData.xaxis = {
min: newMin,
max: newMax,
Expand Down Expand Up @@ -1008,6 +1026,7 @@ class ChartsCard extends LitElement {
? new Date(start.getTime() + this._seriesOffset[index]).getTime()
: start.getTime(),
this._seriesOffset[index] ? new Date(end.getTime() + this._seriesOffset[index]).getTime() : end.getTime(),
this._serverTimeOffset,
) || {
min: [0, null],
max: [0, null],
Expand Down Expand Up @@ -1444,14 +1463,18 @@ class ChartsCard extends LitElement {
private _getSpanDates(): { start: Date; end: Date } {
let end = new Date();
let start = new Date(end.getTime() - this._graphSpan + 1);
// Span
const curMoment = moment();
if ((this._hass?.locale as OverrideFrontendLocaleData).time_zone === 'server') {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
curMoment.tz(this._hass!.config.time_zone);
}
if (this._config?.span?.start) {
// Just Span
const startM = moment().startOf(this._config.span.start);
const startM = curMoment.startOf(this._config.span.start);
start = startM.toDate();
end = new Date(start.getTime() + this._graphSpan);
} else if (this._config?.span?.end) {
const endM = moment().endOf(this._config.span.end);
const endM = curMoment.endOf(this._config.span.end);
end = new Date(endM.toDate().getTime() + 1);
start = new Date(end.getTime() - this._graphSpan + 1);
}
Expand Down
2 changes: 1 addition & 1 deletion src/const.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Moment from 'moment';
import Moment from 'moment-timezone';
import { extendMoment } from 'moment-range';
import momentDurationFormatSetup from 'moment-duration-format';

Expand Down
13 changes: 11 additions & 2 deletions src/graphEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,15 @@ export default class GraphEntry {
return Math.max(...this._computedHistory.flatMap((item) => (item[1] === null ? [] : [item[1]])));
}

public minMaxWithTimestamp(start: number, end: number): { min: HistoryPoint; max: HistoryPoint } | undefined {
public minMaxWithTimestamp(
start: number,
end: number,
serverOffset = 0,
): { min: HistoryPoint; max: HistoryPoint } | undefined {
if (!this._computedHistory || this._computedHistory.length === 0) return undefined;
if (this._computedHistory.length === 1)
return { min: [start, this._computedHistory[0][1]], max: [end, this._computedHistory[0][1]] };
return this._computedHistory.reduce(
const minMax = this._computedHistory.reduce(
(acc: { min: HistoryPoint; max: HistoryPoint }, point) => {
if (point[1] === null) return acc;
if (point[0] > end || point[0] < start) return acc;
Expand All @@ -149,6 +153,11 @@ export default class GraphEntry {
},
{ min: [0, null], max: [0, null] },
);
if (serverOffset) {
if (minMax.min[0]) minMax.min[0] -= serverOffset;
if (minMax.max[0]) minMax.max[0] -= serverOffset;
}
return minMax;
}

public minMaxWithTimestampForYAxis(start: number, end: number): { min: HistoryPoint; max: HistoryPoint } | undefined {
Expand Down
48 changes: 48 additions & 0 deletions src/types-ha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
export enum NumberFormat {
language = 'language',
system = 'system',
comma_decimal = 'comma_decimal',
decimal_comma = 'decimal_comma',
space_comma = 'space_comma',
none = 'none',
}

export enum TimeFormat {
language = 'language',
system = 'system',
am_pm = '12',
twenty_four = '24',
}

export enum TimeZone {
local = 'local',
server = 'server',
}

export enum DateFormat {
language = 'language',
system = 'system',
DMY = 'DMY',
MDY = 'MDY',
YMD = 'YMD',
}

export enum FirstWeekday {
language = 'language',
monday = 'monday',
tuesday = 'tuesday',
wednesday = 'wednesday',
thursday = 'thursday',
friday = 'friday',
saturday = 'saturday',
sunday = 'sunday',
}

export interface OverrideFrontendLocaleData {
language: string;
number_format: NumberFormat;
time_format: TimeFormat;
date_format: DateFormat;
first_weekday: FirstWeekday;
time_zone: TimeZone;
}
10 changes: 10 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import parse from 'parse-duration';
import { ChartCardExternalConfig, ChartCardPrettyTime, ChartCardSeriesExternalConfig } from './types-config';
import { DEFAULT_FLOAT_PRECISION, DEFAULT_MAX, DEFAULT_MIN, moment, NO_VALUE } from './const';
import { formatNumber, FrontendLocaleData, HomeAssistant } from 'custom-card-helpers';
import { OverrideFrontendLocaleData } from './types-ha';

export function compress(data: unknown): string {
return lzStringCompress(JSON.stringify(data));
Expand Down Expand Up @@ -325,3 +326,12 @@ export function myFormatNumber(
maximumFractionDigits: precision === undefined ? DEFAULT_FLOAT_PRECISION : precision,
});
}

export function computeTimezoneDiffWithLocal(timezone: string | undefined): number {
if (!timezone) return 0;
return (moment().utcOffset() - moment().tz(timezone).utcOffset()) * 60 * 1000;
}

export function isUsingServerTimezone(/*config: ChartCardConfig, */ hass: HomeAssistant | undefined): boolean {
return (hass?.locale as OverrideFrontendLocaleData).time_zone === 'server';
}

0 comments on commit 55c8f97

Please sign in to comment.