Compare commits

..
7 Commits
Author SHA1 Message Date
Tannerandaider 4e24836aec fix: filter out null values in lastFormatter
Co-authored-by: aider (gemini/gemini-3.1-pro-preview) <aider@aider.chat>
2026-08-25 20:51:25 +00:00
Tanner 88b830973a Rename Soil Moisture 2026-08-25 19:54:36 +00:00
Tannerandaider d499eedb70 refactor: stack soil moisture charts with MultiLineChart
Co-authored-by: aider (gemini/gemini-3.1-pro-preview) <aider@aider.chat>
2026-08-25 19:52:59 +00:00
Tanner 44b33cea75 fix: format tooltip values to one decimal place 2026-08-25 19:52:57 +00:00
Tanner 87c62ca860 Adjust interval settings, use avg air data 2026-08-25 19:36:22 +00:00
Tanner d6c5226e44 Remove trailing whitespace 2026-08-25 19:10:31 +00:00
Tanner d1d6812863 Adjust pressure chart labels 2026-08-25 19:07:49 +00:00
+32 -29
View File
@@ -9,14 +9,10 @@ import './App.css';
let tzcache = {}; let tzcache = {};
const durations = [ const durations = [
{id: 0, len: 'Day', win: '10m', full: '10 min', delta: [1, 'days'], format: 'HH'}, {id: 0, len: 'Day', win: '5m', full: '5 min', delta: [1, 'days'], format: 'HH'},
{id: 1, len: 'Day', win: '1h', full: '1 hour', delta: [1, 'days'], format: 'HH'}, {id: 1, len: 'Week', win: '30m', full: '30 min', delta: [7, 'days'], format: 'HH'},
{id: 2, len: 'Week', win: '1h', full: '1 hour', delta: [7, 'days'], format: 'HH'}, {id: 2, len: 'Month', win: '2h', full: '2 hour', delta: [1, 'months'], format: 'D'},
{id: 3, len: 'Week', win: '1d', full: '1 day', delta: [7, 'days'], format: 'D'}, {id: 3, len: 'Year', win: '1d', full: '1 day', delta: [1, 'years'], format: 'M/D'},
{id: 4, len: 'Month', win: '1d', full: '1 day', delta: [1, 'months'], format: 'D'},
{id: 5, len: 'Month', win: '7d', full: '7 day', delta: [1, 'months'], format: 'D'},
{id: 6, len: 'Year', win: '1d', full: '1 day', delta: [1, 'years'], format: 'M/D'},
{id: 7, len: 'Year', win: '30d', full: '30 day', delta: [1, 'years'], format: 'M'},
]; ];
const units = { const units = {
@@ -501,7 +497,7 @@ function Air({name, sensorName, end, duration}) {
<ChartContainer <ChartContainer
name={name} name={name}
data={data} data={data}
lastFormatter={(x) => x.max_p10?.toFixed(1) + ' ug/m³'} lastFormatter={(x) => x.p10?.toFixed(1) + ' ug/m³'}
loading={loading} loading={loading}
> >
<XAxis <XAxis
@@ -529,7 +525,7 @@ function Air({name, sensorName, end, duration}) {
<CartesianGrid strokeDasharray='3 3'/> <CartesianGrid strokeDasharray='3 3'/>
<Tooltip <Tooltip
formatter={(v, name) => v + units[name]} formatter={(v, name) => v.toFixed(1) + units[name]}
labelFormatter={timeStr => moment(timeStr).tz('America/Edmonton').format('ddd MMM DD h:mm A')} labelFormatter={timeStr => moment(timeStr).tz('America/Edmonton').format('ddd MMM DD h:mm A')}
separator=': ' separator=': '
/> />
@@ -539,7 +535,7 @@ function Air({name, sensorName, end, duration}) {
<Line <Line
yAxisId='pm' yAxisId='pm'
type='monotone' type='monotone'
dataKey='max_p10' dataKey='p10'
name='PM10' name='PM10'
stroke='black' stroke='black'
strokeWidth={2} strokeWidth={2}
@@ -550,7 +546,7 @@ function Air({name, sensorName, end, duration}) {
<Line <Line
yAxisId='pm' yAxisId='pm'
type='monotone' type='monotone'
dataKey='max_p25' dataKey='p25'
name='PM2.5' name='PM2.5'
stroke='red' stroke='red'
strokeWidth={2} strokeWidth={2}
@@ -561,7 +557,7 @@ function Air({name, sensorName, end, duration}) {
<Line <Line
yAxisId='co2' yAxisId='co2'
type='monotone' type='monotone'
dataKey='max_co2' dataKey='co2'
name='CO2' name='CO2'
stroke='blue' stroke='blue'
strokeWidth={2} strokeWidth={2}
@@ -572,7 +568,7 @@ function Air({name, sensorName, end, duration}) {
<Line <Line
yAxisId='voc' yAxisId='voc'
type='monotone' type='monotone'
dataKey='max_voc' dataKey='voc'
name='VOC' name='VOC'
stroke='green' stroke='green'
strokeWidth={2} strokeWidth={2}
@@ -723,7 +719,7 @@ function MultiLineChart({title, measurement, dataKey, sensors, colors, end, dura
name={title} name={title}
data={data} data={data}
lastFormatter={(x) => { lastFormatter={(x) => {
const vals = sensors.map(s => x[s]).filter(v => v !== undefined); const vals = sensors.map(s => x[s]).filter(v => v !== undefined && v !== null);
return vals.length ? vals[0].toFixed(1) + (units[unitKey] || '') : 'No data'; return vals.length ? vals[0].toFixed(1) + (units[unitKey] || '') : 'No data';
}} }}
loading={loading} loading={loading}
@@ -737,7 +733,6 @@ function MultiLineChart({title, measurement, dataKey, sensors, colors, end, dura
separator=': ' separator=': '
/> />
<ReferenceLine x={moment().tz('America/Edmonton').startOf('day').toISOString().replace('.000', '')} stroke='blue' /> <ReferenceLine x={moment().tz('America/Edmonton').startOf('day').toISOString().replace('.000', '')} stroke='blue' />
<Legend />
{sensors.map((sensor, i) => ( {sensors.map((sensor, i) => (
<Line <Line
key={sensor} key={sensor}
@@ -876,21 +871,29 @@ function Graphs({end, duration}) {
<Lux name='Kitchen Lux' sensorName='Kitchen' end={end} duration={duration} /> <Lux name='Kitchen Lux' sensorName='Kitchen' end={end} duration={duration} />
<Lux name='Bedroom Lux' sensorName='Bedroom' end={end} duration={duration} /> <Lux name='Bedroom Lux' sensorName='Bedroom' end={end} duration={duration} />
<Lux name='Laundry Room Lux' sensorName='Laundry Room' end={end} duration={duration} /> <Lux name='Laundry Room Lux' sensorName='Laundry Room' end={end} duration={duration} />
<MultiLineChart <MultiLineChart
title='Pressure' title='Absolute Pressure'
measurement='hpa' measurement='hpa'
dataKey='hpa' dataKey='hpa'
sensors={['Kitchen', 'Bedroom', 'Laundry Room']} sensors={['Kitchen', 'Bedroom', 'Laundry Room']}
colors={['black', 'red', 'blue']} colors={['black', 'red', 'blue']}
end={end} end={end}
duration={duration} duration={duration}
yDomain={[850, 915]} yDomain={[870, 915]}
unitKey='Hpa' unitKey='Hpa'
/> />
<WH51Soil name='Side Garden Soil Moisture' sensorName='Side Garden' end={end} duration={duration} /> <WH51Soil name='Side Garden Soil Moisture' sensorName='Side Garden' end={end} duration={duration} />
<Soil name='Dumb Cane Soil Moisture' sensorName='Dumb Cane' end={end} duration={duration} /> <MultiLineChart
<Soil name='Kitchen Pothos Soil Moisture' sensorName='Kitchen Pothos' end={end} duration={duration} /> title='House Plant Soil Moisture'
<Soil name='Dracaena Soil Moisture' sensorName='Dracaena' end={end} duration={duration} /> measurement='soil'
dataKey='soil'
sensors={['Dumb Cane', 'Kitchen Pothos', 'Dracaena']}
colors={['black', 'red', 'blue']}
end={end}
duration={duration}
yDomain={[0, 1000]}
unitKey='Soil'
/>
{!!api_key || {!!api_key ||
<div> <div>