attempting to fix date issue
This commit is contained in:
@@ -16,7 +16,7 @@ try:
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
print(
|
print(
|
||||||
'Time:', str(datetime.now()),
|
'Time:', str(datetime.isoformat(datetime.now())),
|
||||||
'\nTemp:', temp,
|
'\nTemp:', temp,
|
||||||
'\nHumidity:', humidity,
|
'\nHumidity:', humidity,
|
||||||
'\nCO2:', co2,
|
'\nCO2:', co2,
|
||||||
|
|||||||
2
webapp/dist/main.js
vendored
2
webapp/dist/main.js
vendored
File diff suppressed because one or more lines are too long
837
webapp/package-lock.json
generated
837
webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"dev": "webpack-dev-server"
|
"dev": "webpack serve"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -14,17 +14,17 @@
|
|||||||
"@webpack-cli/init": "^1.0.3",
|
"@webpack-cli/init": "^1.0.3",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
"css-loader": "^5.0.1",
|
"css-loader": "^5.0.1",
|
||||||
|
"prettier": "^2.1.2",
|
||||||
"style-loader": "^2.0.0",
|
"style-loader": "^2.0.0",
|
||||||
"terser-webpack-plugin": "^5.0.3",
|
"terser-webpack-plugin": "^5.0.3",
|
||||||
"ts-loader": "^8.0.10",
|
"ts-loader": "^8.0.10",
|
||||||
"typescript": "^4.0.5",
|
"typescript": "^4.0.5",
|
||||||
"webpack": "^5.4.0",
|
"webpack": "^5.4.0",
|
||||||
"webpack-cli": "^4.2.0",
|
"webpack-cli": "^4.2.0"
|
||||||
"webpack-dev-server": "^3.11.0",
|
|
||||||
"prettier": "^2.1.2"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/chart.js": "^2.9.27",
|
"@types/chart.js": "^2.9.27",
|
||||||
"chart.js": "^2.9.4"
|
"chart.js": "^2.9.4",
|
||||||
|
"webpack-dev-server": "^3.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//@ts-ignore
|
import Chart from "chart.js/dist/Chart.bundle.min";
|
||||||
import Chart, {ChartPoint} from "chart.js/dist/Chart.bundle.min";
|
import type {ChartPoint} from "chart.js";
|
||||||
import {generateClimateChartConfig} from "./climateChartConfig";
|
import {generateClimateChartConfig} from "./climateChartConfig";
|
||||||
|
|
||||||
interface Snapshot {
|
interface Snapshot {
|
||||||
@@ -14,38 +14,31 @@ interface SnapshotRecords {
|
|||||||
snapshots: Snapshot[]
|
snapshots: Snapshot[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ClimatePoint {
|
||||||
|
x: string;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
class ClimateChart {
|
class ClimateChart {
|
||||||
private chart: Chart | null;
|
private chart: Chart | null;
|
||||||
private latestSnapshot: Snapshot | null;
|
private latestSnapshot: Snapshot | null;
|
||||||
private onLoadedCallback: () => void = () => {};
|
private onLoadedCallback: () => void = () => {};
|
||||||
private onErrorCallback: (e: Error) => void = () => {};
|
private onErrorCallback: (e: Error) => void = () => {};
|
||||||
constructor(
|
private errorLog: string = "";
|
||||||
private readonly rootUrl: string,
|
private readonly rootUrl: string;
|
||||||
private readonly canvasId: string,
|
private readonly canvasId: string;
|
||||||
private readonly minutesDisplayed: number = 60
|
private readonly minutesDisplayed: number = 60;
|
||||||
) {
|
|
||||||
if (minutesDisplayed > 0 && Math.floor(minutesDisplayed) == minutesDisplayed) {
|
constructor(rootUrl: string, canvasId: string, minutesDisplayed: number) {
|
||||||
this.minutesDisplayed = minutesDisplayed;
|
this.minutesDisplayed = Math.floor(minutesDisplayed);
|
||||||
} else {
|
if (minutesDisplayed < 0 || Math.floor(minutesDisplayed) !== minutesDisplayed) {
|
||||||
throw new Error(`invalid minutes passed to display in chart: ${minutesDisplayed}`);
|
console.warn(`Minutes passed were ${ minutesDisplayed }, which is invalid. ${ this.minutesDisplayed } minutes are being shown instead.`);
|
||||||
}
|
}
|
||||||
this.initChart().catch((e) => {this.onErrorCallback(e);});
|
this.initChart().catch((e) => {this.logError(e);});
|
||||||
}
|
|
||||||
|
|
||||||
onLoaded(callback: () => void) {
|
|
||||||
this.onLoadedCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
onErrored(callback: (e: Error) => void) {
|
|
||||||
this.onErrorCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static isCanvas(el: HTMLElement): el is HTMLCanvasElement {
|
|
||||||
return el.tagName === "CANVAS";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getInitialDataBlob(): Promise<SnapshotRecords> {
|
private async getInitialDataBlob(): Promise<SnapshotRecords> {
|
||||||
const data = await fetch("data?since=" + new Date((new Date().getTime() - this.minutesDisplayed * 60 * 1000)).toISOString());
|
const data = await fetch("data?since=" + new Date((new Date().getTime() - this.minutesDisplayed * 60000)).toISOString());
|
||||||
const payload = await data.json();
|
const payload = await data.json();
|
||||||
if (payload.snapshots.length < 0) {
|
if (payload.snapshots.length < 0) {
|
||||||
throw new Error("Bad response - no snapshots found!");
|
throw new Error("Bad response - no snapshots found!");
|
||||||
@@ -66,64 +59,85 @@ class ClimateChart {
|
|||||||
const payload = await this.getInitialDataBlob();
|
const payload = await this.getInitialDataBlob();
|
||||||
this.latestSnapshot = payload.snapshots[0];
|
this.latestSnapshot = payload.snapshots[0];
|
||||||
this.insertSnapshots(...payload.snapshots);
|
this.insertSnapshots(...payload.snapshots);
|
||||||
setInterval(() => this.updateFromServer(), 30 * 1000);
|
setInterval(async () => this.updateFromServer().catch(e => this.logError(e)), 30 * 1000);
|
||||||
this.chart.update();
|
this.chart.update();
|
||||||
this.onLoadedCallback();
|
this.onLoadedCallback();
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.onErrorCallback(new Error(`Server error: ${e}`));
|
new Error(`Server error: ${e}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private jsonToChartPoints(json: SnapshotRecords): {humidity: ChartPoint[], temp: ChartPoint[], co2: ChartPoint[]} {
|
|
||||||
const humidity = [];
|
|
||||||
const co2 = [];
|
|
||||||
const temp = [];
|
|
||||||
for (let i = 0; i < json.snapshots.length; i++) {
|
|
||||||
const snapshot = json.snapshots[json.snapshots.length - i - 1];
|
|
||||||
co2.push({x: snapshot.time, y: snapshot.co2});
|
|
||||||
temp.push({x: snapshot.time, y: snapshot.temp});
|
|
||||||
humidity.push({x: snapshot.time, y: snapshot.humidity});
|
|
||||||
}
|
|
||||||
return {humidity, co2, temp};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateFromServer() {
|
private async updateFromServer() {
|
||||||
const currentTime = (new Date(this.latestSnapshot.time)).toISOString();
|
const lastTimeInChart = (new Date(this.latestSnapshot.time)).toISOString();
|
||||||
const url = "data?since=" + currentTime;
|
const url = "data?since=" + lastTimeInChart;
|
||||||
try {
|
try {
|
||||||
const payload: SnapshotRecords = await (await fetch(url)).json();
|
const payload: SnapshotRecords = await (await fetch(url)).json();
|
||||||
if (payload.snapshots.length > 0 && new Date(payload.snapshots[0].time).getTime() > Date.now()) {
|
if (payload.snapshots.length > 0) {
|
||||||
this.latestSnapshot = payload.snapshots[0];
|
const latestSnapshotIsNew = new Date(payload.snapshots[0].time).getTime() > new Date(lastTimeInChart).getTime();
|
||||||
this.removeExpiredData(currentTime);
|
if (latestSnapshotIsNew) {
|
||||||
this.insertSnapshots(...payload.snapshots);
|
this.removeExpiredPointsAfter(lastTimeInChart);
|
||||||
this.chart.update();
|
this.latestSnapshot = payload.snapshots[0];
|
||||||
|
this.insertSnapshots(...payload.snapshots);
|
||||||
|
this.chart.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.onErrorCallback(new Error(`Server error: ${e}`));
|
this.logError(`Server error: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private insertSnapshots(...snapshots: Snapshot[]) {
|
private insertSnapshots(...snapshots: Snapshot[]) {
|
||||||
for (const snapshot of snapshots.reverse()) {
|
for (const snapshot of snapshots.reverse()) {
|
||||||
this.chart.data.datasets[0].data.push({x: snapshot.time, y: snapshot.humidity});
|
this.humidityPointList().push({x: snapshot.time, y: snapshot.humidity});
|
||||||
this.chart.data.datasets[1].data.push({x: snapshot.time, y: snapshot.temp});
|
this.tempPointList().push({x: snapshot.time, y: snapshot.temp});
|
||||||
this.chart.data.datasets[2].data.push({x: snapshot.time, y: snapshot.co2});
|
this.co2PointList().push({x: snapshot.time, y: snapshot.co2});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeExpiredData(latestTime: string) {
|
private removeExpiredPointsAfter(referenceTime: string) {
|
||||||
for (let i = 0; i < this.chart.data.datasets[0].data.length; i++) {
|
for (let i = 0; i < this.humidityPointList().length; i++) {
|
||||||
const timeOnPoint = (this.chart.data.datasets[0].data[i] as ChartPoint).x as string;
|
const timeOnPoint = this.humidityPointList()[i].x;
|
||||||
const timeElapsedSincePoint = Date.parse(latestTime) - Date.parse(timeOnPoint);
|
const timeElapsedSinceReference = Date.parse(referenceTime) - Date.parse(timeOnPoint);
|
||||||
if (timeElapsedSincePoint > this.minutesDisplayed * 60000) {
|
if (timeElapsedSinceReference > this.minutesDisplayed * 60000) {
|
||||||
this.chart.data.datasets[0].data.splice(i, 1);
|
this.humidityPointList().splice(i, 1);
|
||||||
this.chart.data.datasets[1].data.splice(i, 1);
|
this.tempPointList().splice(i, 1);
|
||||||
this.chart.data.datasets[2].data.splice(i, 1);
|
this.co2PointList().splice(i, 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private humidityPointList(): ClimatePoint[] {
|
||||||
|
return this.chart.data.datasets[0].data as ClimatePoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
private tempPointList(): ClimatePoint[] {
|
||||||
|
return this.chart.data.datasets[1].data as ClimatePoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
private co2PointList(): ClimatePoint[] {
|
||||||
|
return this.chart.data.datasets[1].data as ClimatePoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded(callback: () => void) {
|
||||||
|
this.onLoadedCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
onErrored(callback: (e: Error) => void) {
|
||||||
|
this.onErrorCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static isCanvas(el: HTMLElement): el is HTMLCanvasElement {
|
||||||
|
return el.tagName === "CANVAS";
|
||||||
|
}
|
||||||
|
|
||||||
|
private logError(error: string) {
|
||||||
|
this.errorLog += `${new Date().toISOString()}: ${ error }\n`;
|
||||||
|
this.onErrorCallback(new Error(error));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ClimateChart;
|
export default ClimateChart;
|
||||||
4
webapp/src/types.d.ts
vendored
Normal file
4
webapp/src/types.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
declare module "chart.js/dist/Chart.bundle.min" {
|
||||||
|
import * as Charts from "chart.js";
|
||||||
|
export default Charts;
|
||||||
|
}
|
||||||
@@ -73,5 +73,13 @@ module.exports = {
|
|||||||
minSize: 30000,
|
minSize: 30000,
|
||||||
name: false
|
name: false
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.join(__dirname, "dist/"),
|
||||||
|
contentBasePublicPath: "/static/",
|
||||||
|
port: 3000,
|
||||||
|
publicPath: "http://localhost:3000/",
|
||||||
|
hotOnly: true
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user