Skip to content
This repository has been archived by the owner on Feb 2, 2021. It is now read-only.

Commit

Permalink
feat: display battery history
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart committed Aug 2, 2019
1 parent 1a715f6 commit 70998fc
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 38 deletions.
4 changes: 4 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
margin-right: 0.25rem;
}
}

.MuiSvgIcon-root {
margin-top: -4px;
}
1 change: 1 addition & 0 deletions src/Cat/Cat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ const ShowCat = ({
</small>
</div>
)}
<hr/>
<div>
<p>
<strong>Battery</strong>
Expand Down
84 changes: 46 additions & 38 deletions src/HistoricalData/HistoricalDataChart.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import * as am4core from '@amcharts/amcharts4/core'
import * as am4charts from '@amcharts/amcharts4/charts'
import React, { useEffect, useRef } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { v4 } from 'uuid'
import Athena from 'aws-sdk/clients/athena'
import { exponential } from 'backoff'
import { parseAthenaResult } from '../parseAthenaResult'
import { Loading } from '../Loading/Loading'
import { Error as ShowError } from '../Error/Error'

import './HistoricalDataChart.scss'

Expand All @@ -20,11 +23,32 @@ export const HistoricalDataChart = ({
}) => {
const chartRef = useRef<am4charts.XYChart>()
const uuid = useRef<string>(v4())
const [loading, setLoading] = useState(true)
const [error, setError] = useState<Error>()
useEffect(() => {
const chart = am4core.create(uuid.current, am4charts.XYChart)
chartRef.current = chart

const dateAxis = chart.xAxes.push(
new am4charts.DateAxis<am4charts.AxisRendererX>(),
)
dateAxis.fontSize = 10
dateAxis.renderer.minGridDistance = 60

const valueAxes = chart.yAxes.push(
new am4charts.ValueAxis<am4charts.AxisRendererY>(),
)
valueAxes.fontSize = 10

const series = chart.series.push(new am4charts.LineSeries())
series.dataFields.valueY = 'value'
series.dataFields.dateX = 'date'
series.tooltipText = '{value}'

athena
.startQueryExecution({
WorkGroup: athenaWorkGroup,
QueryString: `SELECT * FROM ${athenaDataBase}.${athenaRawDataTable} WHERE deviceId='${deviceId}' AND reported.bat IS NOT NULL`,
QueryString: `SELECT reported.bat.ts as date, reported.bat.v as value FROM ${athenaDataBase}.${athenaRawDataTable} WHERE deviceId='${deviceId}' AND reported.bat IS NOT NULL ORDER BY reported.bat.v DESC LIMIT 100`,
})
.promise()
.then(({ QueryExecutionId }) => {
Expand Down Expand Up @@ -76,46 +100,30 @@ export const HistoricalDataChart = ({
reject(new Error(`Timed out waiting for query ${QueryExecutionId}`))
})
b.backoff()
})
.then(() => athena.getQueryResults({ QueryExecutionId }).promise())
}).then(() => athena.getQueryResults({ QueryExecutionId }).promise())
})
.then(console.log)
.catch(console.error)

const chart = am4core.create(uuid.current, am4charts.XYChart)
chartRef.current = chart

const data = []
let value = 50
for (let i = 0; i < 300; i++) {
const date = new Date()
date.setHours(0, 0, 0, 0)
date.setDate(i)
value -= Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10)
data.push({ date: date, value: value })
}

chart.data = data

const dateAxis = chart.xAxes.push(
new am4charts.DateAxis<am4charts.AxisRendererX>(),
)
dateAxis.fontSize = 10
dateAxis.renderer.minGridDistance = 60

const valueAxes = chart.yAxes.push(
new am4charts.ValueAxis<am4charts.AxisRendererY>(),
)
valueAxes.fontSize = 10
.then(({ ResultSet }) => {
if (!ResultSet || !ResultSet.Rows) {
throw new Error(`No resultset returned.`)
}
return parseAthenaResult(ResultSet)
})
.then(data => {
setLoading(false)
chart.data = data
})
.catch(setError)

const series = chart.series.push(new am4charts.LineSeries())
series.dataFields.valueY = 'value'
series.dataFields.dateX = 'date'
series.tooltipText = '{value}'
return () => {
chartRef.current && chartRef.current.dispose()
}
}, [athena, deviceId])
}, [athena, deviceId, setLoading, setError])

return <div id={uuid.current} className={'historicalDataChart'} />
return (
<>
{loading && <Loading text={`Fetching historical data...`} />}
{error && <ShowError error={error} />}
<div id={uuid.current} className={'historicalDataChart'} />
</>
)
}
62 changes: 62 additions & 0 deletions src/parseAthenaResult.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { parseAthenaResult } from './parseAthenaResult'

describe('parseAthenaResult', () => {
it('parse an Athena result into an array of values', () => {
expect(
parseAthenaResult({
Rows: [
{ Data: [{ VarCharValue: 'date' }, { VarCharValue: 'value' }] },
{
Data: [
{ VarCharValue: '2019-08-01T10:29:54.406Z' },
{ VarCharValue: '2607' },
],
},
{
Data: [
{ VarCharValue: '2019-07-31T08:34:20.765Z' },
{ VarCharValue: '2046' },
],
},
],
ResultSetMetadata: {
ColumnInfo: [
{
CatalogName: 'hive',
SchemaName: '',
TableName: '',
Name: 'date',
Label: 'date',
Type: 'varchar',
Precision: 2147483647,
Scale: 0,
Nullable: 'UNKNOWN',
CaseSensitive: true,
},
{
CatalogName: 'hive',
SchemaName: '',
TableName: '',
Name: 'value',
Label: 'value',
Type: 'integer',
Precision: 10,
Scale: 0,
Nullable: 'UNKNOWN',
CaseSensitive: false,
},
],
},
}),
).toEqual([
{
date: '2019-08-01T10:29:54.406Z',
value: 2607,
},
{
date: '2019-07-31T08:34:20.765Z',
value: 2046,
},
])
})
})
40 changes: 40 additions & 0 deletions src/parseAthenaResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Athena from 'aws-sdk/clients/athena'

const parseValue = ({ value, type }: { value?: string; type: string }) => {
if (value === undefined) {
return value
}
switch (type) {
case 'integer':
return parseInt(value, 10)
default:
return value
}
}

export type ParsedResult = { [key: string]: string | number }[]

export const parseAthenaResult = ({
Rows,
ResultSetMetadata,
}: Athena.ResultSet): ParsedResult => {
if (!Rows || !ResultSetMetadata || !ResultSetMetadata.ColumnInfo) {
return []
}
const { ColumnInfo } = ResultSetMetadata
return Rows.slice(1).map(({ Data }) => {
if (!Data) {
return {}
}
return ColumnInfo.reduce(
(result, { Name, Type }, key) => ({
...result,
[Name]: parseValue({
value: Data[key].VarCharValue,
type: Type,
}),
}),
{},
)
})
}

0 comments on commit 70998fc

Please sign in to comment.