mirror of
https://github.com/Hypfer/Valetudo.git
synced 2025-10-26 11:27:27 +00:00
feat(core): MopDockMopWashTemperatureControlCapability
This commit is contained in:
parent
0c6272f704
commit
de62cbf812
@ -0,0 +1,65 @@
|
||||
const Capability = require("./Capability");
|
||||
const NotImplementedError = require("../NotImplementedError");
|
||||
|
||||
/**
|
||||
* @template {import("../ValetudoRobot")} T
|
||||
* @extends Capability<T>
|
||||
*/
|
||||
class MopDockMopWashTemperatureControlCapability extends Capability {
|
||||
/**
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {T} options.robot
|
||||
* @class
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<MopDockMopWashTemperatureControlCapabilityTemperature>}
|
||||
*/
|
||||
async getTemperature() {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MopDockMopWashTemperatureControlCapabilityTemperature} newTemperature
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setTemperature(newTemperature) {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{supportedTemperatures: Array<MopDockMopWashTemperatureControlCapabilityTemperature>}}
|
||||
*/
|
||||
getProperties() {
|
||||
return {
|
||||
supportedTemperatures: []
|
||||
};
|
||||
}
|
||||
|
||||
getType() {
|
||||
return MopDockMopWashTemperatureControlCapability.TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
MopDockMopWashTemperatureControlCapability.TYPE = "MopDockMopWashTemperatureControlCapability";
|
||||
|
||||
/**
|
||||
* @typedef {string} MopDockMopWashTemperatureControlCapabilityTemperature
|
||||
* @enum {string}
|
||||
*
|
||||
*/
|
||||
MopDockMopWashTemperatureControlCapability.TEMPERATURE = Object.freeze({
|
||||
COLD: "cold",
|
||||
WARM: "warm",
|
||||
HOT: "hot",
|
||||
SCALDING: "scalding",
|
||||
BOILING: "boiling"
|
||||
});
|
||||
|
||||
|
||||
module.exports = MopDockMopWashTemperatureControlCapability;
|
||||
@ -25,6 +25,7 @@ module.exports = {
|
||||
MappingPassCapability: require("./MappingPassCapability"),
|
||||
MopDockCleanManualTriggerCapability: require("./MopDockCleanManualTriggerCapability"),
|
||||
MopDockDryManualTriggerCapability: require("./MopDockDryManualTriggerCapability"),
|
||||
MopDockMopWashTemperatureControlCapability: require("./MopDockMopWashTemperatureControlCapability"),
|
||||
MopExtensionControlCapability: require("./MopExtensionControlCapability"),
|
||||
ObstacleAvoidanceControlCapability: require("./ObstacleAvoidanceControlCapability"),
|
||||
ObstacleImagesCapability: require("./ObstacleImagesCapability"),
|
||||
|
||||
@ -92,7 +92,8 @@ const CAPABILITY_TYPE_TO_ROUTER_MAPPING = {
|
||||
[capabilities.ObstacleImagesCapability.TYPE]: capabilityRouters.ObstacleImagesCapabilityRouter,
|
||||
[capabilities.HighResolutionManualControlCapability.TYPE]: capabilityRouters.HighResolutionManualControlCapabilityRouter,
|
||||
[capabilities.MopExtensionControlCapability.TYPE]: capabilityRouters.SimpleToggleCapabilityRouter,
|
||||
[capabilities.CameraLightControlCapability.TYPE]: capabilityRouters.SimpleToggleCapabilityRouter
|
||||
[capabilities.CameraLightControlCapability.TYPE]: capabilityRouters.SimpleToggleCapabilityRouter,
|
||||
[capabilities.MopDockMopWashTemperatureControlCapability.TYPE]: capabilityRouters.MopDockMopWashTemperatureControlCapabilityRouter,
|
||||
};
|
||||
|
||||
module.exports = CapabilitiesRouter;
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
const CapabilityRouter = require("./CapabilityRouter");
|
||||
|
||||
class MopDockMopWashTemperatureControlCapabilityRouter extends CapabilityRouter {
|
||||
initRoutes() {
|
||||
this.router.get("/", async (req, res) => {
|
||||
try {
|
||||
res.json({
|
||||
temperature: await this.capability.getTemperature()
|
||||
});
|
||||
} catch (e) {
|
||||
this.sendErrorResponse(req, res, e);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.put("/", this.validator, async (req, res) => {
|
||||
if (req.body.temperature) {
|
||||
try {
|
||||
await this.capability.setTemperature(req.body.temperature);
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
this.sendErrorResponse(req, res, e);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MopDockMopWashTemperatureControlCapabilityRouter;
|
||||
@ -0,0 +1,104 @@
|
||||
{
|
||||
"/api/v2/robot/capabilities/MopDockMopWashTemperatureControlCapability": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"MopDockMopWashTemperatureControlCapability"
|
||||
],
|
||||
"summary": "Get current mop wash water temperature",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"temperature": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cold",
|
||||
"warm",
|
||||
"hot",
|
||||
"scalding",
|
||||
"boiling"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"MopDockMopWashTemperatureControlCapability"
|
||||
],
|
||||
"summary": "Set mop wash water temperature",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"temperature": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cold",
|
||||
"warm",
|
||||
"hot",
|
||||
"scalding",
|
||||
"boiling"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/400"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/robot/capabilities/MopDockMopWashTemperatureControlCapability/properties": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"MopDockMopWashTemperatureControlCapability"
|
||||
],
|
||||
"summary": "Get various capability-related properties",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"supportedTemperatures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cold",
|
||||
"warm",
|
||||
"hot",
|
||||
"scalding",
|
||||
"boiling"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ module.exports = {
|
||||
MappingPassCapabilityRouter: require("./MappingPassCapabilityRouter"),
|
||||
MopDockCleanManualTriggerCapabilityRouter: require("./MopDockCleanManualTriggerCapabilityRouter"),
|
||||
MopDockDryManualTriggerCapabilityRouter: require("./MopDockDryManualTriggerCapabilityRouter"),
|
||||
MopDockMopWashTemperatureControlCapabilityRouter : require("./MopDockMopWashTemperatureControlCapabilityRouter"),
|
||||
ObstacleImagesCapabilityRouter: require("./ObstacleImagesCapabilityRouter"),
|
||||
PendingMapChangeHandlingCapabilityRouter: require("./PendingMapChangeHandlingCapabilityRouter"),
|
||||
PresetSelectionCapabilityRouter: require("./PresetSelectionCapabilityRouter"),
|
||||
@ -29,5 +30,5 @@ module.exports = {
|
||||
VoicePackManagementCapabilityRouter: require("./VoicePackManagementCapabilityRouter"),
|
||||
WifiConfigurationCapabilityRouter: require("./WifiConfigurationCapabilityRouter"),
|
||||
WifiScanCapabilityRouter: require("./WifiScanCapabilityRouter"),
|
||||
ZoneCleaningCapabilityRouter: require("./ZoneCleaningCapabilityRouter")
|
||||
ZoneCleaningCapabilityRouter: require("./ZoneCleaningCapabilityRouter"),
|
||||
};
|
||||
|
||||
@ -25,6 +25,9 @@ import {
|
||||
MapSegmentEditJoinRequestParameters,
|
||||
MapSegmentEditSplitRequestParameters,
|
||||
MapSegmentRenameRequestParameters,
|
||||
MopDockMopWashTemperature,
|
||||
MopDockMopWashTemperaturePayload,
|
||||
MopDockMopWashTemperatureProperties,
|
||||
MQTTConfiguration,
|
||||
MQTTProperties,
|
||||
MQTTStatus,
|
||||
@ -1186,3 +1189,31 @@ export const fetchObstacleImagesProperties = async (): Promise<ObstacleImagesPro
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
export const sendMopDockMopWashTemperature = async (payload: MopDockMopWashTemperaturePayload): Promise<void> => {
|
||||
return valetudoAPI
|
||||
.put(`/robot/capabilities/${Capability.MopDockMopWashTemperatureControl}`, payload)
|
||||
.then(({status}) => {
|
||||
if (status !== 200) {
|
||||
throw new Error("Could not send mop dock mop wash temperature");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchMopDockMopWashTemperature = async (): Promise<MopDockMopWashTemperature> => {
|
||||
return valetudoAPI
|
||||
.get<MopDockMopWashTemperaturePayload>(`/robot/capabilities/${Capability.MopDockMopWashTemperatureControl}`)
|
||||
.then(({data}) => {
|
||||
return data.temperature;
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchMopDockMopWashTemperatureProperties = async (): Promise<MopDockMopWashTemperatureProperties> => {
|
||||
return valetudoAPI
|
||||
.get<MopDockMopWashTemperatureProperties>(
|
||||
`/robot/capabilities/${Capability.MopDockMopWashTemperatureControl}/properties`
|
||||
)
|
||||
.then(({data}) => {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
@ -128,6 +128,9 @@ import {
|
||||
sendMopExtensionControlState,
|
||||
fetchCameraLightControlState,
|
||||
sendCameraLightControlState,
|
||||
fetchMopDockMopWashTemperature,
|
||||
sendMopDockMopWashTemperature,
|
||||
fetchMopDockMopWashTemperatureProperties,
|
||||
} from "./client";
|
||||
import {
|
||||
PresetSelectionState,
|
||||
@ -150,6 +153,7 @@ import {
|
||||
MapSegmentEditJoinRequestParameters,
|
||||
MapSegmentEditSplitRequestParameters,
|
||||
MapSegmentRenameRequestParameters,
|
||||
MopDockMopWashTemperature,
|
||||
MQTTConfiguration,
|
||||
NetworkAdvertisementConfiguration,
|
||||
NTPClientConfiguration,
|
||||
@ -228,7 +232,9 @@ enum QueryKey {
|
||||
ObstacleImages = "obstacle_image",
|
||||
ObstacleImagesProperties = "obstacle_image_properties",
|
||||
MopExtensionControl = "mop_extension_control",
|
||||
CameraLightControl = "camera_light_control"
|
||||
CameraLightControl = "camera_light_control",
|
||||
MopDockMopWashTemperature = "mop_dock_mop_wash_temperature",
|
||||
MopDockMopWashTemperatureProperties = "mop_dock_mop_wash_temperature_properties",
|
||||
}
|
||||
|
||||
const useOnCommandError = (capability: Capability | string): ((error: unknown) => void) => {
|
||||
@ -1592,3 +1598,31 @@ export const prefetchObstacleImagesProperties = async (queryClient : QueryClient
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const useMopDockMopWashTemperatureQuery = () => {
|
||||
return useQuery({
|
||||
queryKey: [QueryKey.MopDockMopWashTemperature],
|
||||
queryFn: fetchMopDockMopWashTemperature,
|
||||
});
|
||||
};
|
||||
|
||||
export const useMopDockMopWashTemperatureMutation = () => {
|
||||
return useValetudoFetchingMutation({
|
||||
queryKey: [QueryKey.MopDockMopWashTemperature],
|
||||
mutationFn: (temperature: MopDockMopWashTemperature) => {
|
||||
return sendMopDockMopWashTemperature({ temperature: temperature }).then(
|
||||
fetchMopDockMopWashTemperature
|
||||
);
|
||||
},
|
||||
onError: useOnCommandError(Capability.MopDockMopWashTemperatureControl),
|
||||
});
|
||||
};
|
||||
|
||||
export const useMopDockMopWashTemperaturePropertiesQuery = () => {
|
||||
return useQuery({
|
||||
queryKey: [QueryKey.MopDockMopWashTemperatureProperties],
|
||||
queryFn: fetchMopDockMopWashTemperatureProperties,
|
||||
|
||||
staleTime: Infinity,
|
||||
});
|
||||
};
|
||||
|
||||
@ -25,6 +25,7 @@ export enum Capability {
|
||||
MapSegmentation = "MapSegmentationCapability",
|
||||
MapSnapshot = "MapSnapshotCapability",
|
||||
MappingPass = "MappingPassCapability",
|
||||
MopDockMopWashTemperatureControl = "MopDockMopWashTemperatureControlCapability",
|
||||
ObstacleAvoidanceControl = "ObstacleAvoidanceControlCapability",
|
||||
PetObstacleAvoidanceControl = "PetObstacleAvoidanceControlCapability",
|
||||
MopExtensionControl = "MopExtensionControlCapability",
|
||||
@ -594,3 +595,13 @@ export interface ObstacleImagesProperties {
|
||||
height: number
|
||||
}
|
||||
}
|
||||
|
||||
export type MopDockMopWashTemperature = "cold" | "warm" | "hot" | "scalding" | "boiling";
|
||||
|
||||
export interface MopDockMopWashTemperaturePayload {
|
||||
temperature: MopDockMopWashTemperature;
|
||||
}
|
||||
|
||||
export interface MopDockMopWashTemperatureProperties {
|
||||
supportedTemperatures: Array<MopDockMopWashTemperature>;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
AutoEmptyDockAutoEmptyInterval,
|
||||
Capability,
|
||||
CarpetSensorMode,
|
||||
MopDockMopWashTemperature,
|
||||
useAutoEmptyDockAutoEmptyControlMutation,
|
||||
useAutoEmptyDockAutoEmptyControlQuery,
|
||||
useAutoEmptyDockAutoEmptyIntervalMutation,
|
||||
@ -22,6 +23,9 @@ import {
|
||||
useKeyLockStateMutation,
|
||||
useKeyLockStateQuery,
|
||||
useLocateMutation,
|
||||
useMopDockMopWashTemperatureMutation,
|
||||
useMopDockMopWashTemperaturePropertiesQuery,
|
||||
useMopDockMopWashTemperatureQuery,
|
||||
useMopExtensionControlMutation,
|
||||
useMopExtensionControlQuery,
|
||||
useObstacleAvoidanceControlMutation,
|
||||
@ -48,6 +52,7 @@ import {
|
||||
Sensors as CarpetModeIcon,
|
||||
Star as QuirksIcon,
|
||||
Waves as CarpetSensorModeIcon,
|
||||
DeviceThermostat as MopDockMopWashTemperatureControlIcon,
|
||||
} from "@mui/icons-material";
|
||||
import {SpacerListMenuItem} from "../components/list_menu/SpacerListMenuItem";
|
||||
import {LinkListMenuItem} from "../components/list_menu/LinkListMenuItem";
|
||||
@ -477,6 +482,89 @@ const CameraLightControlCapabilitySwitchListMenuItem = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const MopDockMopWashTemperatureControlCapabilitySelectListMenuItem = () => {
|
||||
const SORT_ORDER: Record<MopDockMopWashTemperature, number> = {
|
||||
"cold": 1,
|
||||
"warm": 2,
|
||||
"hot": 3,
|
||||
"scalding": 4,
|
||||
"boiling": 5,
|
||||
};
|
||||
|
||||
const {
|
||||
data: mopDockMopWashTemperatureProperties,
|
||||
isPending: mopDockMopWashTemperaturePropertiesPending,
|
||||
isError: mopDockMopWashTemperaturePropertiesError
|
||||
} = useMopDockMopWashTemperaturePropertiesQuery();
|
||||
|
||||
const options: Array<SelectListMenuItemOption> = (
|
||||
mopDockMopWashTemperatureProperties?.supportedTemperatures ?? []
|
||||
).sort((a, b) => {
|
||||
const aMapped = SORT_ORDER[a] ?? 10;
|
||||
const bMapped = SORT_ORDER[b] ?? 10;
|
||||
|
||||
return aMapped - bMapped;
|
||||
}).map((val: MopDockMopWashTemperature) => {
|
||||
let label;
|
||||
|
||||
switch (val) {
|
||||
case "cold":
|
||||
label = "Cold";
|
||||
break;
|
||||
case "warm":
|
||||
label = "Warm";
|
||||
break;
|
||||
case "hot":
|
||||
label = "Hot";
|
||||
break;
|
||||
case "scalding":
|
||||
label = "Scalding";
|
||||
break;
|
||||
case "boiling":
|
||||
label = "Boiling";
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
value: val,
|
||||
label: label
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
const {
|
||||
data: data,
|
||||
isPending: isPending,
|
||||
isFetching: isFetching,
|
||||
isError: isError,
|
||||
} = useMopDockMopWashTemperatureQuery();
|
||||
|
||||
const {mutate: mutate, isPending: isChanging} = useMopDockMopWashTemperatureMutation();
|
||||
const loading = isFetching || isChanging;
|
||||
const disabled = loading || isChanging || isError;
|
||||
|
||||
const currentValue = options.find(mode => {
|
||||
return mode.value === data;
|
||||
}) ?? {value: "", label: ""};
|
||||
|
||||
|
||||
return (
|
||||
<SelectListMenuItem
|
||||
options={options}
|
||||
currentValue={currentValue}
|
||||
setValue={(e) => {
|
||||
mutate(e.value as MopDockMopWashTemperature);
|
||||
}}
|
||||
disabled={disabled}
|
||||
loadingOptions={mopDockMopWashTemperaturePropertiesPending || isPending}
|
||||
loadError={mopDockMopWashTemperaturePropertiesError}
|
||||
primaryLabel="Mop Wash Temperature"
|
||||
secondaryLabel="Select if and/or how much the dock should heat the water used to rinse the mop pads."
|
||||
icon={<MopDockMopWashTemperatureControlIcon/>}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const RobotOptions = (): React.ReactElement => {
|
||||
const [
|
||||
locateCapabilitySupported,
|
||||
@ -490,6 +578,7 @@ const RobotOptions = (): React.ReactElement => {
|
||||
carpetSensorModeControlCapabilitySupported,
|
||||
|
||||
mopExtensionControlCapabilitySupported,
|
||||
mopDockMopWashTemperatureControlSupported,
|
||||
|
||||
autoEmptyDockAutoEmptyControlCapabilitySupported,
|
||||
autoEmptyDockAutoEmptyIntervalControlCapabilitySupported,
|
||||
@ -514,6 +603,7 @@ const RobotOptions = (): React.ReactElement => {
|
||||
Capability.CarpetSensorModeControl,
|
||||
|
||||
Capability.MopExtensionControl,
|
||||
Capability.MopDockMopWashTemperatureControl,
|
||||
|
||||
Capability.AutoEmptyDockAutoEmptyControl,
|
||||
Capability.AutoEmptyDockAutoEmptyIntervalControl,
|
||||
@ -591,6 +681,12 @@ const RobotOptions = (): React.ReactElement => {
|
||||
);
|
||||
}
|
||||
|
||||
if (mopDockMopWashTemperatureControlSupported) {
|
||||
items.push(
|
||||
<MopDockMopWashTemperatureControlCapabilitySelectListMenuItem key={"mopDockMopWashTemperatureControl"}/>
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [
|
||||
obstacleAvoidanceControlCapabilitySupported,
|
||||
@ -600,7 +696,8 @@ const RobotOptions = (): React.ReactElement => {
|
||||
collisionAvoidantNavigationControlCapabilitySupported,
|
||||
carpetModeControlCapabilitySupported,
|
||||
carpetSensorModeControlCapabilitySupported,
|
||||
mopExtensionControlCapabilitySupported
|
||||
mopExtensionControlCapabilitySupported,
|
||||
mopDockMopWashTemperatureControlSupported
|
||||
]);
|
||||
|
||||
const dockListItems = React.useMemo(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user