Skip to content

Commit

Permalink
feat(ui): Add total statistics page
Browse files Browse the repository at this point in the history
  • Loading branch information
ccoors committed Jan 5, 2022
1 parent ee3154b commit 28bede7
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 38 deletions.
1 change: 1 addition & 0 deletions backend/lib/robots/mock/MockRobot.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class MockRobot extends ValetudoRobot {
this.registerCapability(new capabilities.MockVoicePackManagementCapability({robot: this}));
this.registerCapability(new capabilities.MockManualControlCapability({robot: this}));
this.registerCapability(new capabilities.MockCurrentStatisticsCapability({robot: this}));
this.registerCapability(new capabilities.MockTotalStatisticsCapability({robot: this}));

// Raise events to make them visible in the UI
options.valetudoEventStore.raise(new DustBinFullValetudoEvent({}));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const TotalStatisticsCapability = require("../../../core/capabilities/TotalStatisticsCapability");

const {ValetudoDataPoint} = require("../../../entities/core");

/**
* @extends TotalStatisticsCapability<import("../MockRobot")>
*/
class MockTotalStatisticsCapability extends TotalStatisticsCapability {
constructor(options) {
super(options);

const count = 5;
this.totalStatistics = {
time: count * 24 * 60,
area: count * 63 * 10000,
count
};
}

/**
* @return {Promise<Array<ValetudoDataPoint>>}
*/
// @ts-ignore
async getStatistics() {
return [
new ValetudoDataPoint({
type: ValetudoDataPoint.TYPES.TIME,
value: this.totalStatistics.time
}),
new ValetudoDataPoint({
type: ValetudoDataPoint.TYPES.AREA,
value: this.totalStatistics.area
}),
new ValetudoDataPoint({
type: ValetudoDataPoint.TYPES.COUNT,
value: this.totalStatistics.count
})
];
}

getProperties() {
return {
availableStatistics: [
ValetudoDataPoint.TYPES.TIME,
ValetudoDataPoint.TYPES.AREA,
ValetudoDataPoint.TYPES.COUNT
]
};
}
}

module.exports = MockTotalStatisticsCapability;
1 change: 1 addition & 0 deletions backend/lib/robots/mock/capabilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = {
MockPersistentMapControlCapability: require("./MockPersistentMapControlCapability"),
MockSpeakerTestCapability: require("./MockSpeakerTestCapability"),
MockSpeakerVolumeControlCapability: require("./MockSpeakerVolumeControlCapability"),
MockTotalStatisticsCapability: require("./MockTotalStatisticsCapability"),
MockVoicePackManagementCapability: require("./MockVoicePackManagementCapability"),
MockWaterUsageControlCapability: require("./MockWaterUsageControlCapability"),
MockWifiConfigurationCapability: require("./MockWifiConfigurationCapability"),
Expand Down
20 changes: 16 additions & 4 deletions frontend/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,20 +831,32 @@ export const sendUpdaterCommand = async (

export const fetchCurrentStatistics = async (): Promise<Array<ValetudoDataPoint>> => {
return valetudoAPI
.get<Array<ValetudoDataPoint>>(`/robot/capabilities/${Capability.CurrentStatisticsCapability}`)
.get<Array<ValetudoDataPoint>>(`/robot/capabilities/${Capability.CurrentStatistics}`)
.then(({ data }) => {
return data;
});
};

export const fetchCurrentStatisticsProperties = async (): Promise<StatisticsProperties> => {
return valetudoAPI
.get<StatisticsProperties>(`/robot/capabilities/${Capability.CurrentStatisticsCapability}/properties`)
.get<StatisticsProperties>(`/robot/capabilities/${Capability.CurrentStatistics}/properties`)
.then(({ data }) => {
return data;
});
};

export const fetchTotalStatistics = async (): Promise<Array<ValetudoDataPoint>> => {
return valetudoAPI
.get<Array<ValetudoDataPoint>>(`/robot/capabilities/${Capability.TotalStatistics}`)
.then(({ data }) => {
return data;
});
};



export const fetchTotalStatisticsProperties = async (): Promise<StatisticsProperties> => {
return valetudoAPI
.get<StatisticsProperties>(`/robot/capabilities/${Capability.TotalStatistics}/properties`)
.then(({ data }) => {
return data;
});
};
19 changes: 18 additions & 1 deletion frontend/src/api/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import {
fetchSystemRuntimeInfo,
fetchTimerInformation,
fetchTimerProperties,
fetchTotalStatistics,
fetchTotalStatisticsProperties,
fetchUpdaterState,
fetchValetudoEvents,
fetchValetudoVersionInformation,
Expand Down Expand Up @@ -161,7 +163,9 @@ enum CacheKey {
CombinedVirtualRestrictionsProperties = "combined_virtual_restrictions_properties",
UpdaterState = "updater_state",
CurrentStatistics = "current_statistics",
CurrentStatisticsProperties = "current_statistics_properties"
CurrentStatisticsProperties = "current_statistics_properties",
TotalStatistics = "total_statistics",
TotalStatisticsProperties = "total_statistics_properties"
}

const useOnCommandError = (capability: Capability | string): ((error: unknown) => void) => {
Expand Down Expand Up @@ -1042,3 +1046,16 @@ export const useCurrentStatisticsPropertiesQuery = () => {
});
};

export const useTotalStatisticsQuery = () => {
return useQuery(CacheKey.TotalStatistics, fetchTotalStatistics , {
staleTime: 60_000,
refetchInterval: 60_000
});
};

export const useTotalStatisticsPropertiesQuery = () => {
return useQuery(CacheKey.TotalStatisticsProperties, fetchTotalStatisticsProperties, {
staleTime: Infinity
});
};

3 changes: 2 additions & 1 deletion frontend/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export enum Capability {
CarpetModeControl = "CarpetModeControlCapability",
CombinedVirtualRestrictions = "CombinedVirtualRestrictionsCapability",
ConsumableMonitoring = "ConsumableMonitoringCapability",
CurrentStatisticsCapability = "CurrentStatisticsCapability",
CurrentStatistics = "CurrentStatisticsCapability",
DoNotDisturb = "DoNotDisturbCapability",
FanSpeedControl = "FanSpeedControlCapability",
GoToLocation = "GoToLocationCapability",
Expand All @@ -23,6 +23,7 @@ export enum Capability {
SensorCalibration = "SensorCalibrationCapability",
SpeakerTest = "SpeakerTestCapability",
SpeakerVolumeControl = "SpeakerVolumeControlCapability",
TotalStatistics = "TotalStatisticsCapability",
VoicePackManagement = "VoicePackManagementCapability",
WaterUsageControl = "WaterUsageControlCapability",
WifiConfiguration = "WifiConfigurationCapability",
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/components/ValetudoAppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import React from "react";
import {
AccessTime as TimeIcon,
Build as BuildIcon,
CleaningServices as CleaningServicesIcon,
DarkMode as DarkModeIcon,
Map as MapManagementIcon,
Home as HomeIcon,
Expand Down Expand Up @@ -114,6 +115,17 @@ const menuTree: Array<MenuEntry | MenuSubEntry | MenuSubheader> = [
menuIcon: BuildIcon,
menuText: "Robot settings"
},
{
kind: "MenuEntry",
routeMatch: "/robot/statistics",
title: "Statistics",
menuIcon: CleaningServicesIcon,
menuText: "Statistics",
requiredCapabilities: {
capabilities: [Capability.TotalStatistics],
type: "allof"
}
},
{
kind: "Subheader",
title: "Settings"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/controls/ControlsBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const ControlsBody = (): JSX.Element => {
Capability.GoToLocation,
Capability.ZoneCleaning,
Capability.AutoEmptyDockManualTrigger,
Capability.CurrentStatisticsCapability
Capability.CurrentStatistics
);

return (
Expand Down
35 changes: 4 additions & 31 deletions frontend/src/controls/CurrentStatistics.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,9 @@
import {
useCurrentStatisticsQuery,
ValetudoDataPoint
} from "../api";
import {useCurrentStatisticsQuery} from "../api";
import {Box, CircularProgress, Grid, Paper, Typography} from "@mui/material";
import {
Equalizer as StatisticsIcon
} from "@mui/icons-material";
import {Equalizer as StatisticsIcon} from "@mui/icons-material";
import React from "react";
import LoadingFade from "../components/LoadingFade";
import {convertSecondsToHumans} from "../utils";

function getFriendlyStatName(stat: ValetudoDataPoint) : string {
switch (stat.type) {
case "area":
return "Area";
case "time":
return "Time";
case "count":
return "Count";
}
}

function getHumanReadableStatValue(stat: ValetudoDataPoint): string {
switch (stat.type) {
case "area":
return (stat.value / 10000).toFixed(2).padStart(6, "0") + " m²";
case "time":
return convertSecondsToHumans(stat.value, true, false);
case "count":
return stat.value.toString();
}
}
import {getFriendlyStatName, getHumanReadableStatValue} from "../utils";

const CurrentStatistics = (): JSX.Element => {
const {
Expand All @@ -43,7 +16,7 @@ const CurrentStatistics = (): JSX.Element => {
if (statisticsLoading) {
return (
<Grid item>
<CircularProgress size={20} />
<CircularProgress size={20}/>
</Grid>
);
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/robot/RobotRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {useRouteMatch} from "react-router-dom";
import Consumables from "./Consumables";
import Capabilities from "./capabilities";
import ManualControl from "./ManualControl";
import Statistics from "./Statistics";

const RobotRouter = (): JSX.Element => {
const {path} = useRouteMatch();
Expand All @@ -18,6 +19,9 @@ const RobotRouter = (): JSX.Element => {
<Route exact path={path + "/settings"}>
<Capabilities/>
</Route>
<Route exact path={path + "/statistics"}>
<Statistics/>
</Route>
<Route path="*">
<h3>Unknown route</h3>
</Route>
Expand Down
Loading

0 comments on commit 28bede7

Please sign in to comment.