Skip to content

Commit e7ed408

Browse files
committed
feat!: Replace hours_to_show with graph_span. Takes a time string instead of a number of hours.
1 parent 2cbd769 commit e7ed408

9 files changed

+52
-32
lines changed

.devcontainer/ui-lovelace.yaml

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ views:
1313
- entity: sensor.random_0_1000
1414
name: Sensor 2
1515
type: area
16-
hours_to_show: 0.20
16+
graph_span: 15min
1717
cache: true
1818
layout: minimal
1919
header:
@@ -30,7 +30,7 @@ views:
3030
- entity: sensor.random_0_1000
3131
name: Ram Free
3232
type: area
33-
hours_to_show: 0.20
33+
graph_span: 15min
3434
cache: true
3535
layout: minimal
3636
header:
@@ -45,16 +45,16 @@ views:
4545
- entity: sensor.random_0_1000
4646
name: test2
4747
type: column
48-
hours_to_show: 0.25
48+
graph_span: 20min
4949
cache: true
5050
- type: custom:apexcharts-card
51-
hours_to_show: 200
51+
graph_span: 200h
5252
series:
5353
- entity: sensor.humidity
5454
curve: straight
5555

5656
- type: custom:apexcharts-card
57-
hours_to_show: 1
57+
graph_span: 1h
5858
header:
5959
title: Test Aggregate
6060
show: true
@@ -98,7 +98,7 @@ views:
9898
func: first
9999

100100
- type: custom:apexcharts-card
101-
hours_to_show: 4
101+
graph_span: 4h
102102
header:
103103
title: Test
104104
series:
@@ -119,7 +119,7 @@ views:
119119
graph: line
120120

121121
- type: custom:apexcharts-card
122-
hours_to_show: 6
122+
graph_span: 6h
123123
header:
124124
show: false
125125
series:

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ The card stricly validates all the options available (but not for the `apex_conf
9292
| :white_check_mark: `type` | string | | v1.0.0 | `custom:apexcharts-card` |
9393
| :white_check_mark: `series` | array | | v1.0.0 | See [series](#series-options) |
9494
| `update_interval` | string | | NEXT_VERSION | By default the card updates on every state change. Setting this overrides the behaviour. Valid values are any time string, eg: `1h`, `12min`, `1d`, `1h25`, `10sec`, ... |
95-
| `hours_to_show` | number | `24` | v1.0.0 | The span of the graph in hours (Use `0.25` for 15min for eg.) |
95+
| `graph_span` | string | `24h` | NEXT_VERSION | The span of the graph as a time interval. Valid values are any time string, eg: `1h`, `12min`, `1d`, `1h25`, `10sec`, ... |
9696
| `show` | object | | v1.0.0 | See [show](#show-options) |
9797
| `cache` | boolean | `true` | v1.0.0 | Use in-browser data caching to reduce the load on Home Assistant's server |
9898
| `stacked` | boolean | `false` | v1.0.0 | Enable if you want the data to be stacked on the graph |
@@ -216,7 +216,7 @@ series:
216216

217217
```yaml
218218
type: custom:apexcharts-card
219-
hours_to_show: 6
219+
graph_span: 6h
220220
header:
221221
show: false
222222
series:
@@ -240,7 +240,7 @@ series:
240240

241241
```yaml
242242
type: custom:apexcharts-card
243-
hours_to_show: 1
243+
graph_span: 1h
244244
header:
245245
show: false
246246
series:

src/apex-layouts.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { HomeAssistant } from 'custom-card-helpers';
2-
import { moment } from './const';
2+
import parse from 'parse-duration';
3+
import { HOUR_24, moment } from './const';
34
import { ChartCardConfig } from './types';
45
import { computeName, computeUom, mergeDeep } from './utils';
56

@@ -45,7 +46,8 @@ export function getLayoutConfig(config: ChartCardConfig, hass: HomeAssistant | u
4546
tooltip: {
4647
x: {
4748
formatter:
48-
config.hours_to_show < 24
49+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
50+
parse(config.graph_span!)! < HOUR_24
4951
? function (val) {
5052
return moment(new Date(val)).format('HH:mm:ss');
5153
}

src/apexcharts-card.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import {
1818
DEFAULT_DURATION,
1919
DEFAULT_FUNC,
2020
DEFAULT_GROUP_BY_FILL,
21-
DEFAULT_HOURS_TO_SHOW,
21+
DEFAULT_GRAPH_SPAN,
2222
DEFAULT_SERIE_TYPE,
23+
HOUR_24,
2324
} from './const';
2425
import parse from 'parse-duration';
2526

@@ -41,9 +42,13 @@ localForage
4142
.iterate((data, key) => {
4243
const value: EntityEntryCache = key.endsWith('-raw') ? data : decompress(data);
4344
const start = new Date();
44-
start.setHours(start.getHours() - value.hours_to_show);
45-
if (new Date(value.last_fetched) < start) {
45+
if (value.span === undefined) {
4646
localForage.removeItem(key);
47+
} else {
48+
start.setTime(start.getTime() - value.span);
49+
if (new Date(value.last_fetched) < start) {
50+
localForage.removeItem(key);
51+
}
4752
}
4853
})
4954
.catch((err) => {
@@ -73,6 +78,8 @@ class ChartsCard extends LitElement {
7378

7479
private _colors?: string[];
7580

81+
private _graphSpan: number | null = HOUR_24;
82+
7683
@property({ attribute: false }) private _lastState: (number | string | null)[] = [];
7784

7885
public connectedCallback() {
@@ -148,10 +155,16 @@ class ChartsCard extends LitElement {
148155
throw new Error(`'update_interval: ${config.update_interval}' is not a valid interval of time`);
149156
}
150157
}
158+
if (config.graph_span) {
159+
this._graphSpan = parse(config.graph_span);
160+
if (this._graphSpan === null) {
161+
throw new Error(`'graph_span: ${config.update_interval}' is not a valid range of time`);
162+
}
163+
}
151164

152165
this._config = mergeDeep(
153166
{
154-
hours_to_show: DEFAULT_HOURS_TO_SHOW,
167+
graph_span: DEFAULT_GRAPH_SPAN,
155168
cache: true,
156169
useCompress: false,
157170
show: { loading: true },
@@ -183,7 +196,7 @@ class ChartsCard extends LitElement {
183196
serie.entity,
184197
index,
185198
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
186-
this._config!.hours_to_show,
199+
this._graphSpan!,
187200
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
188201
this._config!.cache,
189202
serie,
@@ -301,7 +314,9 @@ class ChartsCard extends LitElement {
301314
// const end = this.getEndDate();
302315
const end = new Date();
303316
const start = new Date(end);
304-
start.setTime(start.getTime() - getMilli(config.hours_to_show));
317+
// validated during Init
318+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
319+
start.setTime(start.getTime() - this._graphSpan!);
305320

306321
try {
307322
const promise = this._graphs.map((graph) => graph?._updateHistory(start, end));

src/const.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { extendMoment } from 'moment-range';
33

44
export const moment = extendMoment(Moment);
55
export const ONE_HOUR = 1000 * 3600;
6+
export const HOUR_24 = ONE_HOUR * 24;
67

7-
export const DEFAULT_HOURS_TO_SHOW = 24;
8+
export const DEFAULT_GRAPH_SPAN = '24h';
89
export const DEFAULT_SERIE_TYPE = 'line';
910
export const DEFAULT_DURATION = '1h';
1011
export const DEFAULT_FUNC = 'raw';

src/graphEntry.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { compress, decompress, log } from './utils';
44
import localForage from 'localforage';
55
import { HassEntity } from 'home-assistant-js-websocket';
66
import { DateRange } from 'moment-range';
7-
import { DEFAULT_HOURS_TO_SHOW, moment } from './const';
7+
import { HOUR_24, moment } from './const';
88
import parse from 'parse-duration';
99
import SparkMD5 from 'spark-md5';
1010

@@ -23,7 +23,9 @@ export default class GraphEntry {
2323

2424
private _cache = true;
2525

26-
private _hoursToShow: number;
26+
// private _hoursToShow: number;
27+
28+
private _graphSpan: number;
2729

2830
private _useCompress = false;
2931

@@ -43,7 +45,7 @@ export default class GraphEntry {
4345

4446
private _md5Config: string;
4547

46-
constructor(entity: string, index: number, hoursToShow: number, cache: boolean, config: ChartCardSeriesConfig) {
48+
constructor(entity: string, index: number, graphSpan: number, cache: boolean, config: ChartCardSeriesConfig) {
4749
const aggregateFuncMap = {
4850
avg: this._average,
4951
max: this._maximum,
@@ -58,19 +60,19 @@ export default class GraphEntry {
5860
this._cache = cache;
5961
this._entityID = entity;
6062
this._history = undefined;
61-
this._hoursToShow = hoursToShow;
63+
this._graphSpan = graphSpan;
6264
this._config = config;
6365
const now = new Date();
6466
const now2 = new Date(now);
6567
this._func = aggregateFuncMap[config.group_by.func];
66-
now2.setHours(now2.getHours() - DEFAULT_HOURS_TO_SHOW);
68+
now2.setTime(now2.getTime() - HOUR_24);
6769
this._timeRange = moment.range(now, now2);
6870
this._realEnd = new Date();
6971
this._realStart = new Date();
7072
// Valid because tested during init;
7173
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7274
this._groupByDurationMs = parse(this._config.group_by.duration)!;
73-
this._md5Config = SparkMD5.hash(`${this._hoursToShow}${JSON.stringify(this._config)}`);
75+
this._md5Config = SparkMD5.hash(`${this._graphSpan}${JSON.stringify(this._config)}`);
7476
}
7577

7678
set hass(hass: HomeAssistant) {
@@ -129,7 +131,7 @@ export default class GraphEntry {
129131

130132
let history = this._cache ? await this._getCache(this._entityID, this._useCompress) : undefined;
131133

132-
if (history && history.hours_to_show === this._hoursToShow) {
134+
if (history && history.span === this._graphSpan) {
133135
const currDataIndex = history.data.findIndex((item) => item && new Date(item[0]).getTime() > start.getTime());
134136
if (currDataIndex !== -1) {
135137
// skip initial state when fetching recent/not-cached data
@@ -160,14 +162,14 @@ export default class GraphEntry {
160162
return [new Date(item.last_changed).getTime(), !Number.isNaN(stateParsed) ? stateParsed : null];
161163
});
162164
if (history?.data.length) {
163-
history.hours_to_show = this._hoursToShow;
165+
history.span = this._graphSpan;
164166
history.last_fetched = new Date();
165167
if (history.data.length !== 0) {
166168
history.data.push(...newStateHistory);
167169
}
168170
} else {
169171
history = {
170-
hours_to_show: this._hoursToShow,
172+
span: this._graphSpan,
171173
last_fetched: new Date(),
172174
data: newStateHistory,
173175
};

src/types-config-ti.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const ChartCardExternalConfig = t.iface([], {
88
"type": t.lit('custom:apexcharts-card'),
99
"update_interval": t.opt("string"),
1010
"series": t.array("ChartCardSeriesExternalConfig"),
11-
"hours_to_show": t.opt("number"),
11+
"graph_span": t.opt("string"),
1212
"show": t.opt(t.iface([], {
1313
"loading": t.opt("boolean"),
1414
})),

src/types-config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export interface ChartCardExternalConfig {
22
type: 'custom:apexcharts-card';
33
update_interval?: string;
44
series: ChartCardSeriesExternalConfig[];
5-
hours_to_show?: number;
5+
graph_span?: string;
66
show?: {
77
loading?: boolean;
88
};

src/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ChartCardExternalConfig, ChartCardSeriesExternalConfig, GroupByFill, Gr
33

44
export interface ChartCardConfig extends ChartCardExternalConfig {
55
series: ChartCardSeriesConfig[];
6-
hours_to_show: number;
6+
graph_span: string;
77
cache: boolean;
88
useCompress: boolean;
99
apex_config?: ApexOptions;
@@ -19,7 +19,7 @@ export interface ChartCardSeriesConfig extends ChartCardSeriesExternalConfig {
1919
}
2020

2121
export interface EntityEntryCache {
22-
hours_to_show: number;
22+
span: number;
2323
last_fetched: Date;
2424
data: EntityCachePoints;
2525
}

0 commit comments

Comments
 (0)