diff --git a/web/public/assets/js/app/__tests__/node-page.test.js b/web/public/assets/js/app/__tests__/node-page.test.js index a0e7b8c..7571ed1 100644 --- a/web/public/assets/js/app/__tests__/node-page.test.js +++ b/web/public/assets/js/app/__tests__/node-page.test.js @@ -361,6 +361,7 @@ test('renderTelemetryCharts renders condensed scatter charts when telemetry exis relative_humidity: 55, barometric_pressure: 995, gas_resistance: 1500, + iaq: 83, }, }, { @@ -377,6 +378,7 @@ test('renderTelemetryCharts renders condensed scatter charts when telemetry exis relativeHumidity: 52, barometricPressure: 1000, gasResistance: 2000, + iaq: 88, }, }, ], @@ -396,6 +398,8 @@ test('renderTelemetryCharts renders condensed scatter charts when telemetry exis assert.equal(html.includes('Air util TX (%)'), true); assert.equal(html.includes('Utilization (%)'), true); assert.equal(html.includes('Gas resistance (\u03a9)'), true); + assert.equal(html.includes('Air quality'), true); + assert.equal(html.includes('IAQ index'), true); assert.equal(html.includes('Temperature (\u00b0C)'), true); assert.equal(html.includes(expectedDate), true); assert.equal(html.includes('node-detail__chart-point'), true); @@ -473,6 +477,7 @@ test('renderNodeDetailHtml embeds telemetry charts when snapshots are present', }); assert.equal(html.includes('node-detail__charts'), true); assert.equal(html.includes('Power metrics'), true); + assert.equal(html.includes('Air quality'), true); }); test('fetchNodeDetailHtml renders the node layout for overlays', async () => { diff --git a/web/public/assets/js/app/node-page.js b/web/public/assets/js/app/node-page.js index 88a12ef..8d8fd88 100644 --- a/web/public/assets/js/app/node-page.js +++ b/web/public/assets/js/app/node-page.js @@ -167,25 +167,6 @@ const TELEMETRY_CHART_SPECS = Object.freeze([ color: '#91bfdb', visible: false, }, - { - id: 'pressure', - position: 'right', - label: 'Pressure (hPa)', - min: 800, - max: 1_100, - ticks: 4, - color: '#c51b8a', - }, - { - id: 'gas', - position: 'rightSecondary', - label: 'Gas resistance (\u03a9)', - min: 10, - max: 100_000, - ticks: 5, - color: '#fa9fb5', - scale: 'log', - }, ], series: [ { @@ -206,6 +187,42 @@ const TELEMETRY_CHART_SPECS = Object.freeze([ fields: ['humidity', 'relative_humidity', 'relativeHumidity'], valueFormatter: value => `${value.toFixed(1)}%`, }, + ], + }, + { + id: 'airQuality', + title: 'Air quality', + axes: [ + { + id: 'pressure', + position: 'left', + label: 'Pressure (hPa)', + min: 800, + max: 1_100, + ticks: 4, + color: '#c51b8a', + }, + { + id: 'gas', + position: 'right', + label: 'Gas resistance (\u03a9)', + min: 10, + max: 100_000, + ticks: 5, + color: '#fa9fb5', + scale: 'log', + }, + { + id: 'iaq', + position: 'rightSecondary', + label: 'IAQ index', + min: 0, + max: 500, + ticks: 5, + color: '#636363', + }, + ], + series: [ { id: 'pressure', axis: 'pressure', @@ -224,6 +241,15 @@ const TELEMETRY_CHART_SPECS = Object.freeze([ fields: ['gas_resistance', 'gasResistance'], valueFormatter: value => formatGasResistance(value), }, + { + id: 'iaq', + axis: 'iaq', + color: '#636363', + label: 'IAQ', + legend: 'IAQ index', + fields: ['iaq'], + valueFormatter: value => value.toFixed(0), + }, ], }, ]);