import {firebaseConfig} from './config'; import {initializeApp} from 'firebase/app'; import {getDatabase, onValue, orderByChild, query, ref, startAt} from 'firebase/database'; import {Reading} from './types'; import {createGauges, createGraphs} from './graphs'; import {processData} from './processData'; import {HOUR_OPTIONS, HOURS_DEFAULT, HOURS_QUERY, MAX_HOURS_AGO} from './consts'; import {getWindowTime} from './utils'; const app = initializeApp(firebaseConfig); const rtdb = getDatabase(app); document.body.onload = init; async function init() { const hoursAgo = getHoursAgo(); const readings:Reading[] = await getRecentData(hoursAgo); showLatestReading(readings); // Force a 15-minute window for the gauges, to ensure it shows the most // up-to-date value it can (that's had spikes filtered out) const gaugeValues = processData( readings.slice(-10), { alignWindow: 10 } ); createGauges( gaugeValues, document.getElementById('gauges') ); // Have graphs use a potentially longer window time, so they don't show as // many elements when a longer time is selected. const graphValues = processData(readings, { alignWindow: getWindowTime(hoursAgo) }); createGraphs( graphValues, document.getElementById('time-series-graphs') ); showHourSelection(); } function getHoursAgo():number { const query = new URLSearchParams(document.location.search) .get(HOURS_QUERY); if(!query) { return HOURS_DEFAULT; } let hours = parseInt(query); if(isNaN(hours) || hours > MAX_HOURS_AGO) { return HOURS_DEFAULT; } return hours; } function showLatestReading(readings:Reading[]) { const span = document.getElementById('last-update-value'); span.textContent = new Date(readings.pop().time).toLocaleTimeString(); } function showHourSelection() { const options:HTMLSelectElement = document.getElementById('hours-ago') as HTMLSelectElement; const current = getHoursAgo(); for(let h of HOUR_OPTIONS) { const opt = document.createElement('option'); opt.value = h.toString(); opt.textContent = `Last ${h} hours`; if(h === current) { opt.selected = true; } options.add(opt); } options.addEventListener('change', () => { const selection = options.value; const newUrl = `${document.location.href.split('?')[0]}?hours=${selection}`; document.location.href = newUrl; }); } async function getRecentData( hoursAgo:number = 2 ): Promise { const since = new Date().getTime() - (hoursAgo * 3600 * 1000); const outdoors = ref(rtdb, 'outdoor'); const search = query( outdoors, orderByChild('time'), startAt(since) ); return new Promise((res, err) => { let values:Reading[] = []; onValue(search, snapshot => { snapshot.forEach(child => { values.push(child.val()); }); res(values); }, { onlyOnce: true }); }); }