mirror of
https://github.com/Hypfer/Valetudo.git
synced 2025-10-26 11:27:27 +00:00
feat!: Remove ZonePresets and GoToLocationPresets
This commit is contained in:
parent
f7f3f0db6e
commit
de8719012f
@ -44,12 +44,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"zonePresets": {
|
||||
"type": "object"
|
||||
},
|
||||
"goToLocationPresets": {
|
||||
"type": "object"
|
||||
},
|
||||
"mqtt": {
|
||||
"$ref": "#/components/schemas/MqttConfigDTO"
|
||||
},
|
||||
@ -387,9 +381,7 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full_cleanup",
|
||||
"zone_cleanup",
|
||||
"segment_cleanup",
|
||||
"goto_location"
|
||||
"segment_cleanup"
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
|
||||
@ -1,29 +1,34 @@
|
||||
const SerializableEntity = require("../SerializableEntity");
|
||||
const uuid = require("uuid");
|
||||
|
||||
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
class ValetudoGoToLocation extends SerializableEntity {
|
||||
/**
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string} options.name
|
||||
* @param {object} options.coordinates
|
||||
* @param {number} options.coordinates.x
|
||||
* @param {number} options.coordinates.y
|
||||
* @param {string} [options.id]
|
||||
* @param {object} [options.metaData]
|
||||
* @class
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.name = options.name;
|
||||
|
||||
this.coordinates = {
|
||||
x: options.coordinates.x,
|
||||
y: options.coordinates.y
|
||||
};
|
||||
this.id = options.id ?? uuid.v4();
|
||||
|
||||
if (
|
||||
!(
|
||||
this.coordinates &&
|
||||
typeof this.coordinates.x === "number" &&
|
||||
typeof this.coordinates.y === "number"
|
||||
)
|
||||
) {
|
||||
throw new Error("Invalid coordinates");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,9 +15,7 @@ class ValetudoTimer extends SerializableEntity {
|
||||
* @param {object} options.action
|
||||
* @param {ValetudoTimerActionType} options.action.type
|
||||
* @param {object} options.action.params
|
||||
* @param {string} [options.action.params.zone_id]
|
||||
* @param {Array<string>} [options.action.params.segment_ids]
|
||||
* @param {string} [options.action.params.goto_id]
|
||||
* @param {number} [options.action.params.iterations]
|
||||
* @param {boolean} [options.action.params.custom_order]
|
||||
* @param {object} [options.metaData]
|
||||
@ -42,9 +40,7 @@ class ValetudoTimer extends SerializableEntity {
|
||||
*/
|
||||
ValetudoTimer.ACTION_TYPE = Object.freeze({
|
||||
FULL_CLEANUP: "full_cleanup",
|
||||
ZONE_CLEANUP: "zone_cleanup",
|
||||
SEGMENT_CLEANUP: "segment_cleanup",
|
||||
GOTO_LOCATION: "goto_location"
|
||||
SEGMENT_CLEANUP: "segment_cleanup"
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -32,6 +32,22 @@ class ValetudoZone extends SerializableEntity {
|
||||
|
||||
this.points = options.points;
|
||||
this.iterations = options.iterations ? options.iterations : 1;
|
||||
|
||||
if (
|
||||
!(
|
||||
this.points &&
|
||||
typeof this.points.pA?.x === "number" &&
|
||||
typeof this.points.pA?.y === "number" &&
|
||||
typeof this.points.pB?.x === "number" &&
|
||||
typeof this.points.pB?.y === "number" &&
|
||||
typeof this.points.pC?.x === "number" &&
|
||||
typeof this.points.pC?.y === "number" &&
|
||||
typeof this.points.pD?.x === "number" &&
|
||||
typeof this.points.pD?.y === "number"
|
||||
)
|
||||
) {
|
||||
throw new Error("Invalid Zone points data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
const SerializableEntity = require("../SerializableEntity");
|
||||
const uuid = require("uuid");
|
||||
|
||||
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
class ValetudoZonePreset extends SerializableEntity {
|
||||
/**
|
||||
* This is a named container which contains ValetudoZones
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string} options.name
|
||||
* @param {Array<import("./ValetudoZone")>} options.zones
|
||||
* @param {string} [options.id]
|
||||
* @param {object} [options.metaData]
|
||||
* @class
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.name = options.name;
|
||||
this.zones = options.zones;
|
||||
this.id = options.id ?? uuid.v4();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ValetudoZonePreset;
|
||||
@ -1,26 +0,0 @@
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ValetudoZonePreset": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"metaData": {
|
||||
"type": "object"
|
||||
},
|
||||
"zones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValetudoZone"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
module.exports = {
|
||||
ValetudoDNDConfiguration: require("./ValetudoDNDConfiguration"),
|
||||
ValetudoDataPoint: require("./ValetudoDataPoint"),
|
||||
ValetudoGoToLocation: require("./ValetudoGoToLocation"),
|
||||
ValetudoMapSegment: require("./ValetudoMapSegment"),
|
||||
ValetudoMapSnapshot: require("./ValetudoMapSnapshot"),
|
||||
ValetudoRestrictedZone: require("./ValetudoRestrictedZone"),
|
||||
@ -15,6 +14,5 @@ module.exports = {
|
||||
ValetudoWifiNetwork: require("./ValetudoWifiNetwork"),
|
||||
ValetudoWifiStatus: require("./ValetudoWifiStatus"),
|
||||
ValetudoZone: require("./ValetudoZone"),
|
||||
ValetudoZonePreset: require("./ValetudoZonePreset"),
|
||||
ntpClient: require("./ntpClient")
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ const ValetudoMapSegment = require("../core/ValetudoMapSegment");
|
||||
*
|
||||
* Everything is int. Coordinates and size are in cm
|
||||
*
|
||||
* The origin is found on the top-left corner
|
||||
* The origin is found in the top-left corner
|
||||
*
|
||||
*/
|
||||
class ValetudoMap extends SerializableEntity { //TODO: Current, Historic, Etc.
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
const CapabilityMqttHandle = require("./CapabilityMqttHandle");
|
||||
const ComponentType = require("../homeassistant/ComponentType");
|
||||
const DataType = require("../homie/DataType");
|
||||
const HassAnchor = require("../homeassistant/HassAnchor");
|
||||
const InLineHassComponent = require("../homeassistant/components/InLineHassComponent");
|
||||
const PropertyMqttHandle = require("../handles/PropertyMqttHandle");
|
||||
const ValetudoGoToLocation = require("../../entities/core/ValetudoGoToLocation");
|
||||
|
||||
class GoToLocationCapabilityMqttHandle extends CapabilityMqttHandle {
|
||||
/**
|
||||
@ -19,68 +17,42 @@ class GoToLocationCapabilityMqttHandle extends CapabilityMqttHandle {
|
||||
}));
|
||||
this.capability = options.capability;
|
||||
|
||||
this.registerChild(
|
||||
new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "presets",
|
||||
friendlyName: "Presets",
|
||||
datatype: DataType.STRING,
|
||||
format: "json",
|
||||
getter: async () => {
|
||||
const result = this.robot.config.get("goToLocationPresets") ?? {};
|
||||
await HassAnchor.getAnchor(HassAnchor.ANCHOR.GOTO_PRESETS_LEN).post(Object.keys(result).length);
|
||||
this.registerChild(new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "go",
|
||||
friendlyName: "Go to location",
|
||||
datatype: DataType.STRING,
|
||||
format: "same json as the REST interface",
|
||||
setter: async (value) => {
|
||||
const reqGoToLocation = JSON.parse(value);
|
||||
|
||||
return result;
|
||||
},
|
||||
helpText: "This handle provides a set of configured Go-to-location presets as a JSON object."
|
||||
}).also((prop) => {
|
||||
HassAnchor.getTopicReference(HassAnchor.REFERENCE.GOTO_PRESETS).post(prop.getBaseTopic()).then();
|
||||
})
|
||||
);
|
||||
|
||||
this.registerChild(
|
||||
new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "go",
|
||||
friendlyName: "Go to location preset",
|
||||
datatype: DataType.STRING,
|
||||
setter: async (value) => {
|
||||
const gotoPreset = this.robot.config.get("goToLocationPresets")[value];
|
||||
|
||||
if (gotoPreset === undefined) {
|
||||
throw new Error("Invalid go to location preset ID found in go payload");
|
||||
if (
|
||||
reqGoToLocation && reqGoToLocation.coordinates &&
|
||||
typeof reqGoToLocation.coordinates.x === "number" &&
|
||||
typeof reqGoToLocation.coordinates.y === "number"
|
||||
) {
|
||||
await this.capability.goTo(new ValetudoGoToLocation({
|
||||
coordinates: {
|
||||
x: reqGoToLocation.coordinates.x,
|
||||
y: reqGoToLocation.coordinates.y
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
throw new Error("Invalid go to location payload");
|
||||
}
|
||||
},
|
||||
helpText: "This handle accepts a JSON object identical to the one used by the REST API.\n\n" +
|
||||
"Sample payload:\n\n" +
|
||||
"```json\n" +
|
||||
JSON.stringify({
|
||||
coordinates: {
|
||||
x: 50,
|
||||
y: 50
|
||||
}
|
||||
|
||||
await this.capability.goTo(gotoPreset);
|
||||
},
|
||||
helpText: "Use this handle to make the robot go to a configured preset location. It accepts one " +
|
||||
"single preset UUID as a regular string."
|
||||
})
|
||||
);
|
||||
|
||||
this.controller.withHass((hass) => {
|
||||
this.attachHomeAssistantComponent(
|
||||
new InLineHassComponent({
|
||||
hass: hass,
|
||||
robot: this.robot,
|
||||
name: this.capability.getType(),
|
||||
friendlyName: "GoTo Locations",
|
||||
componentType: ComponentType.SENSOR,
|
||||
baseTopicReference: HassAnchor.getTopicReference(HassAnchor.REFERENCE.HASS_GOTO_LOCATION_STATE),
|
||||
autoconf: {
|
||||
state_topic: HassAnchor.getTopicReference(HassAnchor.REFERENCE.HASS_GOTO_LOCATION_STATE),
|
||||
icon: "mdi:map-marker-outline",
|
||||
json_attributes_topic: HassAnchor.getTopicReference(HassAnchor.REFERENCE.GOTO_PRESETS),
|
||||
json_attributes_template: "{{ value }}"
|
||||
},
|
||||
topics: {
|
||||
"": HassAnchor.getAnchor(HassAnchor.ANCHOR.GOTO_PRESETS_LEN)
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}, null, 2) +
|
||||
"\n```"
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -58,16 +58,16 @@ class MapSegmentationCapabilityMqttHandle extends CapabilityMqttHandle {
|
||||
helpText: "This handle accepts a JSON object identical to the one used by the REST API.\n\n" +
|
||||
"Sample payload:\n\n" +
|
||||
"```json\n" +
|
||||
"{\n" +
|
||||
" \"segment_ids\": [\n" +
|
||||
" \"20\",\n"+
|
||||
" \"18\",\n"+
|
||||
" \"16\"\n"+
|
||||
" ],\n"+
|
||||
" \"iterations\": 2,\n"+
|
||||
" \"customOrder\": true\n"+
|
||||
"}\n" +
|
||||
"```"
|
||||
JSON.stringify({
|
||||
segment_ids: [
|
||||
"20",
|
||||
"18",
|
||||
"16"
|
||||
],
|
||||
iterations: 2,
|
||||
customOrder: true
|
||||
}, null, 2) +
|
||||
"\n```"
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
const CapabilityMqttHandle = require("./CapabilityMqttHandle");
|
||||
const ComponentType = require("../homeassistant/ComponentType");
|
||||
const DataType = require("../homie/DataType");
|
||||
const HassAnchor = require("../homeassistant/HassAnchor");
|
||||
const InLineHassComponent = require("../homeassistant/components/InLineHassComponent");
|
||||
const PropertyMqttHandle = require("../handles/PropertyMqttHandle");
|
||||
const ValetudoZone = require("../../entities/core/ValetudoZone");
|
||||
|
||||
class ZoneCleaningCapabilityMqttHandle extends CapabilityMqttHandle {
|
||||
/**
|
||||
@ -19,71 +17,57 @@ class ZoneCleaningCapabilityMqttHandle extends CapabilityMqttHandle {
|
||||
}));
|
||||
this.capability = options.capability;
|
||||
|
||||
this.registerChild(
|
||||
new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "presets",
|
||||
friendlyName: "Presets",
|
||||
datatype: DataType.STRING,
|
||||
format: "json",
|
||||
getter: async () => {
|
||||
const result = this.robot.config.get("zonePresets") ?? {};
|
||||
await HassAnchor.getAnchor(HassAnchor.ANCHOR.ZONE_PRESETS_LEN).post(Object.keys(result).length);
|
||||
return result;
|
||||
},
|
||||
helpText: "This handles provides the list of configured zone presets as a JSON object."
|
||||
}).also((prop) => {
|
||||
HassAnchor.getTopicReference(HassAnchor.REFERENCE.ZONE_PRESETS).post(prop.getBaseTopic()).then();
|
||||
})
|
||||
);
|
||||
this.registerChild(new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "start",
|
||||
friendlyName: "Start zoned cleaning",
|
||||
datatype: DataType.STRING,
|
||||
format: "same json as the REST interface",
|
||||
setter: async (value) => {
|
||||
const req = JSON.parse(value);
|
||||
|
||||
this.registerChild(
|
||||
new PropertyMqttHandle({
|
||||
parent: this,
|
||||
controller: this.controller,
|
||||
topicName: "start",
|
||||
friendlyName: "Start zone preset",
|
||||
datatype: DataType.STRING,
|
||||
format: "json",
|
||||
setter: async (value) => {
|
||||
const loadedZone = this.robot.config.get("zonePresets")[value];
|
||||
if (!loadedZone) {
|
||||
throw new Error("Error while starting zone cleanup. There is no zone preset with id " + value);
|
||||
}
|
||||
try {
|
||||
await this.capability.start(loadedZone.zones);
|
||||
} catch (e) {
|
||||
throw new Error(`Error while starting zone cleaning for zone_id ${value}: ${e}`);
|
||||
}
|
||||
},
|
||||
helpText: "This handle accepts a zone preset **UUID** to start. You can retrieve them from the `/presets` handle.\n\n" +
|
||||
"Sample value:\n" +
|
||||
"`25f6b7fe-0a28-477d-a1af-937ad91b2df4`\n"
|
||||
})
|
||||
);
|
||||
|
||||
this.controller.withHass((hass) => {
|
||||
this.attachHomeAssistantComponent(
|
||||
new InLineHassComponent({
|
||||
hass: hass,
|
||||
robot: this.robot,
|
||||
name: this.capability.getType(),
|
||||
friendlyName: "Zone Presets",
|
||||
componentType: ComponentType.SENSOR,
|
||||
baseTopicReference: HassAnchor.getTopicReference(HassAnchor.REFERENCE.HAZZ_ZONE_CLEANING_STATE),
|
||||
autoconf: {
|
||||
state_topic: HassAnchor.getTopicReference(HassAnchor.REFERENCE.HAZZ_ZONE_CLEANING_STATE),
|
||||
icon: "mdi:square-outline",
|
||||
json_attributes_topic: HassAnchor.getTopicReference(HassAnchor.REFERENCE.ZONE_PRESETS),
|
||||
json_attributes_template: "{{ value }}"
|
||||
},
|
||||
topics: {
|
||||
"": HassAnchor.getAnchor(HassAnchor.ANCHOR.ZONE_PRESETS_LEN)
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
if (Array.isArray(req?.zones)) {
|
||||
await this.capability.start(req.zones.map(z => {
|
||||
return new ValetudoZone({
|
||||
points: z.points,
|
||||
iterations: z.iterations
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
throw new Error("Invalid zone cleaning payload");
|
||||
}
|
||||
},
|
||||
helpText: "This handle accepts a JSON object identical to the one used by the REST API.\n\n" +
|
||||
"Sample payload:\n\n" +
|
||||
"```json\n" +
|
||||
JSON.stringify({
|
||||
zones: [
|
||||
{
|
||||
iterations: 1,
|
||||
points: {
|
||||
pA: {
|
||||
x: 50,
|
||||
y: 50
|
||||
},
|
||||
pB: {
|
||||
x: 100,
|
||||
y: 50
|
||||
},
|
||||
pC: {
|
||||
x: 100,
|
||||
y: 100
|
||||
},
|
||||
pD: {
|
||||
x: 50,
|
||||
y: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}, null, 2) +
|
||||
"\n```"
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -209,14 +209,12 @@ HassAnchor.ANCHOR = Object.freeze({
|
||||
CURRENT_STATISTICS_TIME: "current_statistics_time",
|
||||
CURRENT_STATISTICS_AREA: "current_statistics_area",
|
||||
FAN_SPEED: "fan_speed",
|
||||
GOTO_PRESETS_LEN: "goto_presets_len",
|
||||
MAP_SEGMENTS_LEN: "map_segments_len",
|
||||
VACUUM_STATE: "vacuum_state",
|
||||
WIFI_IPS: "wifi_ips",
|
||||
WIFI_FREQUENCY: "wifi_freq",
|
||||
WIFI_SIGNAL: "wifi_signal",
|
||||
WIFI_SSID: "wifi_ssid",
|
||||
ZONE_PRESETS_LEN: "zone_presets_len",
|
||||
});
|
||||
|
||||
HassAnchor.REFERENCE = Object.freeze({
|
||||
@ -224,14 +222,10 @@ HassAnchor.REFERENCE = Object.freeze({
|
||||
BASIC_CONTROL_COMMAND: "basic_control_command",
|
||||
FAN_SPEED_SET: "fan_speed_set",
|
||||
FAN_SPEED_PRESETS: "fan_speed_presets", // Actually contains the presets, not a topic
|
||||
GOTO_PRESETS: "goto_presets",
|
||||
ZONE_PRESETS: "zone_presets",
|
||||
HASS_CONSUMABLE_STATE: "hass_consumable_state_",
|
||||
HASS_GOTO_LOCATION_STATE: "hass_goto_location_state",
|
||||
HASS_MAP_SEGMENTS_STATE: "hass_map_segments_state",
|
||||
HASS_WATER_GRADE_PRESETS: "hass_water_grade_presets",
|
||||
HASS_WIFI_CONFIG_ATTRS: "hass_wifi_config_attrs",
|
||||
HAZZ_ZONE_CLEANING_STATE: "hass_zone_cleaning_state",
|
||||
});
|
||||
|
||||
module.exports = HassAnchor;
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
},
|
||||
"blockExternalAccess": true
|
||||
},
|
||||
"zonePresets": {},
|
||||
"goToLocationPresets": {},
|
||||
"mqtt": {
|
||||
"enabled": false,
|
||||
"connection": {
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
const Logger = require("../Logger");
|
||||
const ValetudoFullCleanupTimerAction = require("./actions/ValetudoFullCleanupTimerAction");
|
||||
const ValetudoGoToTimerAction = require("./actions/ValetudoGoToTimerAction");
|
||||
const ValetudoNTPClientDisabledState = require("../entities/core/ntpClient/ValetudoNTPClientDisabledState");
|
||||
const ValetudoNTPClientSyncedState = require("../entities/core/ntpClient/ValetudoNTPClientSyncedState");
|
||||
const ValetudoSegmentCleanupTimerAction = require("./actions/ValetudoSegmentCleanupTimerAction");
|
||||
const ValetudoTimer = require("../entities/core/ValetudoTimer");
|
||||
const ValetudoZoneCleanupTimerAction = require("./actions/ValetudoZoneCleanupTimerAction");
|
||||
|
||||
const MS_PER_MIN = 60 * 1000;
|
||||
|
||||
@ -91,12 +89,6 @@ class Scheduler {
|
||||
case ValetudoTimer.ACTION_TYPE.FULL_CLEANUP:
|
||||
action = new ValetudoFullCleanupTimerAction({robot: this.robot});
|
||||
break;
|
||||
case ValetudoTimer.ACTION_TYPE.ZONE_CLEANUP:
|
||||
action = new ValetudoZoneCleanupTimerAction({
|
||||
robot: this.robot,
|
||||
zoneId: timerDefinition.action?.params?.zone_id
|
||||
});
|
||||
break;
|
||||
case ValetudoTimer.ACTION_TYPE.SEGMENT_CLEANUP:
|
||||
action = new ValetudoSegmentCleanupTimerAction({
|
||||
robot: this.robot,
|
||||
@ -105,12 +97,6 @@ class Scheduler {
|
||||
customOrder: timerDefinition.action?.params?.custom_order
|
||||
});
|
||||
break;
|
||||
case ValetudoTimer.ACTION_TYPE.GOTO_LOCATION:
|
||||
action = new ValetudoGoToTimerAction({
|
||||
robot: this.robot,
|
||||
goToId: timerDefinition.action?.params?.goto_id
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (action) {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
const GoToLocationCapability = require("../../core/capabilities/GoToLocationCapability");
|
||||
const ValetudoTimerAction = require("./ValetudoTimerAction");
|
||||
|
||||
class ValetudoGoToTimerAction extends ValetudoTimerAction {
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {import("../../core/ValetudoRobot")} options.robot
|
||||
* @param {string} options.goToId
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.goToId = options.goToId;
|
||||
}
|
||||
|
||||
async run() {
|
||||
if (!this.goToId) {
|
||||
throw new Error("Missing goToId");
|
||||
}
|
||||
|
||||
if (!this.robot.hasCapability(GoToLocationCapability.TYPE)) {
|
||||
throw new Error("Robot is missing the GoToLocationCapability");
|
||||
} else {
|
||||
const capability = this.robot.capabilities[GoToLocationCapability.TYPE];
|
||||
const goToLocationPreset = this.robot.config.get("goToLocationPresets")[this.goToId];
|
||||
|
||||
if (goToLocationPreset) {
|
||||
return capability.goTo(goToLocationPreset);
|
||||
} else {
|
||||
throw new Error("There is no go to location preset with id " + this.goToId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ValetudoGoToTimerAction;
|
||||
@ -1,36 +0,0 @@
|
||||
const ValetudoTimerAction = require("./ValetudoTimerAction");
|
||||
const ZoneCleaningCapability = require("../../core/capabilities/ZoneCleaningCapability");
|
||||
|
||||
class ValetudoZoneCleanupTimerAction extends ValetudoTimerAction {
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {import("../../core/ValetudoRobot")} options.robot
|
||||
* @param {string} options.zoneId
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.zoneId = options.zoneId;
|
||||
}
|
||||
|
||||
async run() {
|
||||
if (!this.zoneId) {
|
||||
throw new Error("Missing zoneId");
|
||||
}
|
||||
|
||||
if (!this.robot.hasCapability(ZoneCleaningCapability.TYPE)) {
|
||||
throw new Error("Robot is missing the ZoneCleaningCapability");
|
||||
} else {
|
||||
const capability = this.robot.capabilities[ZoneCleaningCapability.TYPE];
|
||||
const zonePreset = this.robot.config.get("zonePresets")[this.zoneId];
|
||||
|
||||
if (zonePreset) {
|
||||
return capability.start(zonePreset.zones);
|
||||
} else {
|
||||
throw new Error("There is no zone preset with id " + this.zoneId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ValetudoZoneCleanupTimerAction;
|
||||
@ -1,9 +1,7 @@
|
||||
const BasicControlCapability = require("../core/capabilities/BasicControlCapability");
|
||||
const express = require("express");
|
||||
const GoToLocationCapability = require("../core/capabilities/GoToLocationCapability");
|
||||
const MapSegmentationCapability = require("../core/capabilities/MapSegmentationCapability");
|
||||
const ValetudoTimer = require("../entities/core/ValetudoTimer");
|
||||
const ZoneCleaningCapability = require("../core/capabilities/ZoneCleaningCapability");
|
||||
|
||||
class TimerRouter {
|
||||
/**
|
||||
@ -42,14 +40,6 @@ class TimerRouter {
|
||||
response.supportedActions.push(ValetudoTimer.ACTION_TYPE.SEGMENT_CLEANUP);
|
||||
}
|
||||
|
||||
if (this.robot.hasCapability(ZoneCleaningCapability.TYPE)) {
|
||||
response.supportedActions.push(ValetudoTimer.ACTION_TYPE.ZONE_CLEANUP);
|
||||
}
|
||||
|
||||
if (this.robot.hasCapability(GoToLocationCapability.TYPE)) {
|
||||
response.supportedActions.push(ValetudoTimer.ACTION_TYPE.GOTO_LOCATION);
|
||||
}
|
||||
|
||||
res.json(response);
|
||||
});
|
||||
|
||||
|
||||
@ -8,155 +8,11 @@ const ValetudoGoToLocation = require("../../entities/core/ValetudoGoToLocation")
|
||||
class GoToLocationCapabilityRouter extends CapabilityRouter {
|
||||
|
||||
initRoutes() {
|
||||
this.router.get("/presets", (req, res) => {
|
||||
res.json(this.capability.robot.config.get("goToLocationPresets"));
|
||||
});
|
||||
|
||||
this.router.get("/presets/:id", (req, res) => {
|
||||
const locationPreset = this.capability.robot.config.get("goToLocationPresets")[req.params.id];
|
||||
|
||||
if (locationPreset) {
|
||||
res.json(locationPreset);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.put("/presets/:id", async (req, res) => {
|
||||
const locationPreset = this.capability.robot.config.get("goToLocationPresets")[req.params.id];
|
||||
|
||||
if (locationPreset && req.body && req.body.action === "goto") {
|
||||
try {
|
||||
await this.capability.goTo(locationPreset);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while going to goToLocationPreset for preset " + req.params.id, e);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.delete("/presets/:id", (req, res) => {
|
||||
const goToLocationPresets = this.capability.robot.config.get("goToLocationPresets");
|
||||
|
||||
if (goToLocationPresets[req.params.id]) {
|
||||
delete(goToLocationPresets[req.params.id]);
|
||||
|
||||
this.capability.robot.config.set("goToLocationPresets", goToLocationPresets);
|
||||
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.post("/presets/:id", (req, res) => {
|
||||
const goToLocationPresets = this.capability.robot.config.get("goToLocationPresets");
|
||||
|
||||
if (goToLocationPresets[req.params.id]) {
|
||||
if (req.body && req.body.name && req.body.coordinates && req.body.coordinates.x !== undefined && req.body.coordinates.y !== undefined) {
|
||||
try {
|
||||
const newPreset = new ValetudoGoToLocation({
|
||||
name: req.body.name,
|
||||
id: req.params.id,
|
||||
coordinates: req.body.coordinates
|
||||
});
|
||||
|
||||
goToLocationPresets[newPreset.id] = newPreset;
|
||||
|
||||
this.capability.robot.config.set("goToLocationPresets", goToLocationPresets);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while saving goToLocationPreset", req.body);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.post("/presets", (req, res) => {
|
||||
if (req.body && req.body.name && req.body.coordinates && req.body.coordinates.x !== undefined && req.body.coordinates.y !== undefined) {
|
||||
try {
|
||||
const goToLocationPresets = this.capability.robot.config.get("goToLocationPresets");
|
||||
const newPreset = new ValetudoGoToLocation({
|
||||
name: req.body.name,
|
||||
id: req.body.id,
|
||||
coordinates: req.body.coordinates
|
||||
});
|
||||
|
||||
goToLocationPresets[newPreset.id] = newPreset;
|
||||
|
||||
this.capability.robot.config.set("goToLocationPresets", goToLocationPresets);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while saving new goToLocationPreset", req.body);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
});
|
||||
|
||||
//TODO: Remove this after building a new webinterface
|
||||
|
||||
this.router.get("/presets_legacy", (req, res) => {
|
||||
const presetsFromConfig = Object.values(this.capability.robot.config.get("goToLocationPresets"));
|
||||
|
||||
res.json(presetsFromConfig.map(preset => {
|
||||
return {
|
||||
name: preset.name,
|
||||
id: preset.id,
|
||||
coordinates: [preset.coordinates.x, preset.coordinates.y]
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
this.router.post("/presets_legacy", (req, res) => {
|
||||
if (Array.isArray(req.body)) {
|
||||
const valid = req.body.every(p => {
|
||||
return p && p.name && Array.isArray(p.coordinates);
|
||||
});
|
||||
|
||||
if (valid) {
|
||||
const presetsArr = req.body.map(preset => {
|
||||
return new ValetudoGoToLocation({
|
||||
name: preset.name,
|
||||
id: preset.id,
|
||||
coordinates: {
|
||||
x: preset.coordinates[0],
|
||||
y: preset.coordinates[1]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const presets = {};
|
||||
|
||||
presetsArr.forEach(z => {
|
||||
presets[z.id] = z;
|
||||
});
|
||||
|
||||
|
||||
this.capability.robot.config.set("goToLocationPresets", presets);
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.router.put("/", async (req, res) => {
|
||||
if (req.body && req.body.action) {
|
||||
if (req.body.action === "goto" && req.body.coordinates && req.body.coordinates.x !== undefined && req.body.coordinates.y !== undefined) {
|
||||
try {
|
||||
await this.capability.goTo(new ValetudoGoToLocation({
|
||||
name: "dynamic",
|
||||
coordinates: req.body.coordinates
|
||||
}));
|
||||
res.sendStatus(200);
|
||||
|
||||
@ -4,191 +4,10 @@ const CapabilityRouter = require("./CapabilityRouter");
|
||||
const Logger = require("../../Logger");
|
||||
|
||||
const ValetudoZone = require("../../entities/core/ValetudoZone");
|
||||
const ValetudoZonePreset = require("../../entities/core/ValetudoZonePreset");
|
||||
|
||||
class ZoneCleaningCapabilityRouter extends CapabilityRouter {
|
||||
|
||||
initRoutes() {
|
||||
this.router.get("/presets", (req, res) => {
|
||||
res.json(this.capability.robot.config.get("zonePresets"));
|
||||
});
|
||||
|
||||
this.router.get("/presets/:id", (req, res) => {
|
||||
const zone = this.capability.robot.config.get("zonePresets")[req.params.id];
|
||||
|
||||
if (zone) {
|
||||
res.json(zone);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.put("/presets/:id", async (req, res) => {
|
||||
const zone = this.capability.robot.config.get("zonePresets")[req.params.id];
|
||||
|
||||
if (zone && req.body && req.body.action === "clean") {
|
||||
try {
|
||||
await this.capability.start(zone.zones);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while starting zone cleaning for preset " + req.params.id, e);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.delete("/presets/:id", (req, res) => {
|
||||
const zoneSettings = this.capability.robot.config.get("zonePresets");
|
||||
|
||||
if (zoneSettings[req.params.id]) {
|
||||
delete(zoneSettings[req.params.id]);
|
||||
|
||||
this.capability.robot.config.set("zonePresets", zoneSettings);
|
||||
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.post("/presets", (req, res) => {
|
||||
if (req.body && req.body.name && Array.isArray(req.body.zones) && req.body.zones.length > 0) {
|
||||
try {
|
||||
const zoneSettings = this.capability.robot.config.get("zonePresets");
|
||||
const newPreset = new ValetudoZonePreset({
|
||||
name: req.body.name,
|
||||
id: req.body.id,
|
||||
zones: req.body.zones.map(z => {
|
||||
return new ValetudoZone({
|
||||
points: z.points,
|
||||
iterations: z.iterations
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
zoneSettings[newPreset.id] = newPreset;
|
||||
|
||||
this.capability.robot.config.set("zonePresets", zoneSettings);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while saving new zone", req.body);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
});
|
||||
|
||||
//TODO: Remove this after building a new webinterface
|
||||
|
||||
this.router.get("/presets_legacy", (req, res) => {
|
||||
const presetsFromConfig = Object.values(this.capability.robot.config.get("zonePresets"));
|
||||
|
||||
res.json(presetsFromConfig.map(preset => {
|
||||
return {
|
||||
name: preset.name,
|
||||
id: preset.id,
|
||||
areas: preset.zones.map(zone => {
|
||||
return [
|
||||
zone.points.pA.x,
|
||||
zone.points.pA.y,
|
||||
zone.points.pC.x,
|
||||
zone.points.pC.y,
|
||||
zone.iterations
|
||||
];
|
||||
})
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
this.router.post("/presets_legacy", (req, res) => {
|
||||
if (Array.isArray(req.body)) {
|
||||
const valid = req.body.every(z => {
|
||||
return z && z.name && Array.isArray(z.areas);
|
||||
});
|
||||
|
||||
if (valid) {
|
||||
const zonePresetsArr = req.body.map(preset => {
|
||||
return new ValetudoZonePreset({
|
||||
name: preset.name,
|
||||
id: preset.id,
|
||||
zones: preset.areas.map(zone => {
|
||||
return new ValetudoZone({
|
||||
points: {
|
||||
pA: {
|
||||
x: zone[0],
|
||||
y: zone[1]
|
||||
},
|
||||
pB: {
|
||||
x: zone[2],
|
||||
y: zone[1]
|
||||
},
|
||||
pC: {
|
||||
x: zone[2],
|
||||
y: zone[3]
|
||||
},
|
||||
pD: {
|
||||
x: zone[0],
|
||||
y: zone[3]
|
||||
},
|
||||
},
|
||||
iterations: zone[4]
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
const zonePresets = {};
|
||||
|
||||
zonePresetsArr.forEach(z => {
|
||||
zonePresets[z.id] = z;
|
||||
});
|
||||
|
||||
|
||||
|
||||
this.capability.robot.config.set("zonePresets", zonePresets);
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.router.post("/presets/:id", (req, res) => {
|
||||
const zoneSettings = this.capability.robot.config.get("zonePresets");
|
||||
|
||||
if (zoneSettings[req.params.id]) {
|
||||
|
||||
if (req.body && req.body.name && Array.isArray(req.body.zones) && req.body.zones.length > 0) {
|
||||
try {
|
||||
const newPreset = new ValetudoZonePreset({
|
||||
name: req.body.name,
|
||||
id: req.params.id,
|
||||
zones: req.body.zones.map(z => {
|
||||
return new ValetudoZone({
|
||||
points: z.points,
|
||||
iterations: z.iterations
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
zoneSettings[newPreset.id] = newPreset;
|
||||
|
||||
this.capability.robot.config.set("zonePresets", zoneSettings);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
Logger.warn("Error while saving new zone", req.body);
|
||||
res.status(500).json(e.message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
this.router.put("/", async (req, res) => {
|
||||
if (req.body && req.body.action) {
|
||||
if (req.body.action === "clean" && Array.isArray(req.body.zones)) {
|
||||
|
||||
@ -1,190 +1,4 @@
|
||||
{
|
||||
"/api/v2/robot/capabilities/GoToLocationCapability/presets": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Get available go-to-location presets",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "Describing this structure requires OpenAPI 3.1 support in Swagger UI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Add new preset",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoGoToLocation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/400"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/robot/capabilities/GoToLocationCapability/presets/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Get go-to-location preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoGoToLocation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified preset ID was not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Go to a go-to-location preset",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"action"
|
||||
],
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"goto"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified preset ID was not found"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/components/responses/500"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Edit existing preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoGoToLocation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified preset ID does not exist."
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"GoToLocationCapability"
|
||||
],
|
||||
"summary": "Delete go-to-location preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified preset IDs was not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/robot/capabilities/GoToLocationCapability": {
|
||||
"put": {
|
||||
"tags": [
|
||||
|
||||
@ -1,186 +1,4 @@
|
||||
{
|
||||
"/api/v2/robot/capabilities/ZoneCleaningCapability/presets": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Get available zone presets",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "Describing this structure requires OpenAPI 3.1 support in Swagger UI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Add new preset",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoZonePreset"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/400"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/robot/capabilities/ZoneCleaningCapability/presets/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Get zone preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoZonePreset"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "One or more specified zone preset IDs were not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Clean zone preset by ID",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"clean"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified zone preset IDs was not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Delete zone preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified zone preset IDs was not found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"ZoneCleaningCapability"
|
||||
],
|
||||
"summary": "Edit existing preset by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"description": "Preset UUID",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValetudoZonePreset"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/200"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/400"
|
||||
},
|
||||
"404": {
|
||||
"description": "The specified zone ID does not exist."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/robot/capabilities/ZoneCleaningCapability": {
|
||||
"put": {
|
||||
"tags": [
|
||||
|
||||
@ -63,36 +63,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"zone_cleanup": {
|
||||
"description": "A timer scheduling a cleanup of a zone preset every sunday at 11:10 UTC",
|
||||
"value": {
|
||||
"enabled": true,
|
||||
"dow": [0],
|
||||
"hour": 11,
|
||||
"minute": 10,
|
||||
"action": {
|
||||
"type": "zone_cleanup",
|
||||
"params": {
|
||||
"zone_id": "338b8c37-8ecd-48b4-b3d2-e03fd74d2e25"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"goto_location": {
|
||||
"description": "A timer scheduling a goto preset every tuesday at 4AM UTC",
|
||||
"value": {
|
||||
"enabled": true,
|
||||
"dow": [2],
|
||||
"hour": 4,
|
||||
"minute": 0,
|
||||
"action": {
|
||||
"type": "goto_location",
|
||||
"params": {
|
||||
"goto_id": "c04a24bd-67fc-4ca8-9dbe-2d867fb71147"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,9 +195,7 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full_cleanup",
|
||||
"zone_cleanup",
|
||||
"segment_cleanup",
|
||||
"goto_location"
|
||||
"segment_cleanup"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,8 +57,6 @@ This capability enables you to send your robot to a location on your map. It wil
|
||||
|
||||
One common use-case of this is to send the robot to your bin.
|
||||
|
||||
Furthermore, this capability will enable you to define ValetudoGoToLocationPresets which are predefined spots that can be called via MQTT.
|
||||
|
||||
## KeyLockCapability <a id="KeyLockCapability"></a>
|
||||
|
||||
This capability enables you to disable control of the robot via the buttons on the devices.
|
||||
@ -143,5 +141,3 @@ This capability enables you to get the current Wi-Fi connection details (includi
|
||||
## ZoneCleaningCapability <a id="ZoneCleaningCapability"></a>
|
||||
|
||||
This capability enables you to send your robot to clean one or more (depending on the vendor) zones drawn onto the map.
|
||||
|
||||
Furthermore, this also enables you to define ValetudoZonePresets which are predefined zones that can be called via MQTT.
|
||||
|
||||
@ -8,7 +8,6 @@ import {
|
||||
ConsumableId,
|
||||
ConsumableState,
|
||||
DoNotDisturbConfiguration,
|
||||
GoToLocation,
|
||||
HTTPBasicAuthConfiguration,
|
||||
LogLevelResponse,
|
||||
ManualControlInteraction,
|
||||
@ -51,7 +50,6 @@ import {
|
||||
WifiConfiguration,
|
||||
WifiStatus,
|
||||
Zone,
|
||||
ZonePreset,
|
||||
ZoneProperties,
|
||||
} from "./types";
|
||||
import { floorObject } from "./utils";
|
||||
@ -226,16 +224,6 @@ export const sendGoToCommand = async (point: Point): Promise<void> => {
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchZonePresets = async (): Promise<ZonePreset[]> => {
|
||||
return valetudoAPI
|
||||
.get<Record<string, ZonePreset>>(
|
||||
`/robot/capabilities/${Capability.ZoneCleaning}/presets`
|
||||
)
|
||||
.then(({data}) => {
|
||||
return Object.values(data);
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchZoneProperties = async (): Promise<ZoneProperties> => {
|
||||
return valetudoAPI
|
||||
.get<ZoneProperties>(
|
||||
@ -246,15 +234,6 @@ export const fetchZoneProperties = async (): Promise<ZoneProperties> => {
|
||||
});
|
||||
};
|
||||
|
||||
export const sendCleanZonePresetCommand = async (id: string): Promise<void> => {
|
||||
await valetudoAPI.put(
|
||||
`/robot/capabilities/${Capability.ZoneCleaning}/presets/${id}`,
|
||||
{
|
||||
action: "clean",
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const sendCleanTemporaryZonesCommand = async (
|
||||
zones: Zone[]
|
||||
): Promise<void> => {
|
||||
@ -339,27 +318,6 @@ export const sendRenameSegmentCommand = async (
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchGoToLocationPresets = async (): Promise<Segment[]> => {
|
||||
return valetudoAPI
|
||||
.get<Record<string, GoToLocation>>(
|
||||
`/robot/capabilities/${Capability.GoToLocation}/presets`
|
||||
)
|
||||
.then(({data}) => {
|
||||
return Object.values(data);
|
||||
});
|
||||
};
|
||||
|
||||
export const sendGoToLocationPresetCommand = async (
|
||||
id: string
|
||||
): Promise<void> => {
|
||||
await valetudoAPI.put(
|
||||
`/robot/capabilities/${Capability.GoToLocation}/presets/${id}`,
|
||||
{
|
||||
action: "goto",
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const sendLocateCommand = async (): Promise<void> => {
|
||||
await valetudoAPI.put(`/robot/capabilities/${Capability.Locate}`, {
|
||||
action: "locate",
|
||||
|
||||
@ -19,7 +19,6 @@ import {
|
||||
fetchCurrentStatistics,
|
||||
fetchCurrentStatisticsProperties,
|
||||
fetchDoNotDisturbConfiguration,
|
||||
fetchGoToLocationPresets,
|
||||
fetchHTTPBasicAuthConfiguration,
|
||||
fetchKeyLockState,
|
||||
fetchManualControlProperties,
|
||||
@ -49,7 +48,6 @@ import {
|
||||
fetchValetudoLogLevel,
|
||||
fetchVoicePackManagementState,
|
||||
fetchWifiStatus,
|
||||
fetchZonePresets,
|
||||
fetchZoneProperties,
|
||||
sendAutoEmptyDockAutoEmptyControlEnable,
|
||||
sendAutoEmptyDockManualTriggerCommand,
|
||||
@ -57,12 +55,10 @@ import {
|
||||
sendCarpetModeEnable,
|
||||
sendCleanSegmentsCommand,
|
||||
sendCleanTemporaryZonesCommand,
|
||||
sendCleanZonePresetCommand,
|
||||
sendCombinedVirtualRestrictionsUpdate,
|
||||
sendConsumableReset,
|
||||
sendDoNotDisturbConfiguration,
|
||||
sendGoToCommand,
|
||||
sendGoToLocationPresetCommand,
|
||||
sendHTTPBasicAuthConfiguration,
|
||||
sendJoinSegmentsCommand,
|
||||
sendKeyLockEnable,
|
||||
@ -134,11 +130,9 @@ enum CacheKey {
|
||||
Consumables = "consumables",
|
||||
Attributes = "attributes",
|
||||
PresetSelections = "preset_selections",
|
||||
ZonePresets = "zone_presets",
|
||||
ZoneProperties = "zone_properties",
|
||||
Segments = "segments",
|
||||
MapSegmentationProperties = "map_segmentation_properties",
|
||||
GoToLocationPresets = "go_to_location_presets",
|
||||
PersistentData = "persistent_data",
|
||||
RobotInformation = "robot_information",
|
||||
ValetudoInformation = "valetudo_information",
|
||||
@ -386,39 +380,12 @@ export const useGoToMutation = (
|
||||
);
|
||||
};
|
||||
|
||||
export const useZonePresetsQuery = () => {
|
||||
return useQuery(CacheKey.ZonePresets, fetchZonePresets);
|
||||
};
|
||||
|
||||
export const useZonePropertiesQuery = () => {
|
||||
return useQuery(CacheKey.ZoneProperties, fetchZoneProperties, {
|
||||
staleTime: Infinity,
|
||||
});
|
||||
};
|
||||
|
||||
export const useCleanZonePresetMutation = (
|
||||
options?: UseMutationOptions<RobotAttribute[], unknown, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
const onError = useOnCommandError(Capability.ZoneCleaning);
|
||||
|
||||
return useMutation(
|
||||
(id: string) => {
|
||||
return sendCleanZonePresetCommand(id).then(fetchStateAttributes);
|
||||
},
|
||||
{
|
||||
onError,
|
||||
...options,
|
||||
async onSuccess(data, ...args) {
|
||||
queryClient.setQueryData<RobotAttribute[]>(CacheKey.Attributes, data, {
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
await options?.onSuccess?.(data, ...args);
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useCleanTemporaryZonesMutation = (
|
||||
options?: UseMutationOptions<RobotAttribute[], unknown, Zone[]>
|
||||
) => {
|
||||
@ -547,33 +514,6 @@ export const useRenameSegmentMutation = (
|
||||
);
|
||||
};
|
||||
|
||||
export const useGoToLocationPresetsQuery = () => {
|
||||
return useQuery(CacheKey.GoToLocationPresets, fetchGoToLocationPresets);
|
||||
};
|
||||
|
||||
export const useGoToLocationPresetMutation = (
|
||||
options?: UseMutationOptions<RobotAttribute[], unknown, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
const onError = useOnCommandError(Capability.ZoneCleaning);
|
||||
|
||||
return useMutation(
|
||||
(id: string) => {
|
||||
return sendGoToLocationPresetCommand(id).then(fetchStateAttributes);
|
||||
},
|
||||
{
|
||||
onError,
|
||||
...options,
|
||||
async onSuccess(data, ...args) {
|
||||
queryClient.setQueryData<RobotAttribute[]>(CacheKey.Attributes, data, {
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
await options?.onSuccess?.(data, ...args);
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocateMutation = () => {
|
||||
const onError = useOnCommandError(Capability.Locate);
|
||||
|
||||
|
||||
@ -46,12 +46,6 @@ export interface Zone {
|
||||
iterations: number;
|
||||
}
|
||||
|
||||
export interface ZonePreset {
|
||||
id: string;
|
||||
name: string;
|
||||
zones: Zone[];
|
||||
}
|
||||
|
||||
export interface ZoneProperties {
|
||||
zoneCount: {
|
||||
min: number;
|
||||
@ -71,12 +65,6 @@ export interface MapSegmentationProperties {
|
||||
customOrderSupport: boolean;
|
||||
}
|
||||
|
||||
export interface GoToLocation {
|
||||
id: string;
|
||||
name: string;
|
||||
coordinates: Point;
|
||||
}
|
||||
|
||||
export interface Segment {
|
||||
id: string;
|
||||
name?: string;
|
||||
|
||||
@ -3,10 +3,8 @@ import {Opacity as WaterUsageIcon,} from "@mui/icons-material";
|
||||
import {Capability, useRobotInformationQuery} from "../api";
|
||||
import {useCapabilitiesSupported} from "../CapabilitiesProvider";
|
||||
import BasicControls from "./BasicControls";
|
||||
import GoToLocationPresets from "./GoToLocationPresets";
|
||||
import PresetSelectionControl from "./PresetSelection";
|
||||
import RobotStatus from "./RobotStatus";
|
||||
import ZonePresets from "./ZonePresets";
|
||||
import Dock from "./Dock";
|
||||
import CurrentStatistics from "./CurrentStatistics";
|
||||
import Attachments from "./Attachments";
|
||||
@ -19,16 +17,12 @@ const ControlsBody = (): JSX.Element => {
|
||||
basicControls,
|
||||
fanSpeed,
|
||||
waterControl,
|
||||
goToLocation,
|
||||
zoneCleaning,
|
||||
triggerEmptySupported,
|
||||
currentStatistics,
|
||||
] = useCapabilitiesSupported(
|
||||
Capability.BasicControl,
|
||||
Capability.FanSpeedControl,
|
||||
Capability.WaterUsageControl,
|
||||
Capability.GoToLocation,
|
||||
Capability.ZoneCleaning,
|
||||
Capability.AutoEmptyDockManualTrigger,
|
||||
Capability.CurrentStatistics
|
||||
);
|
||||
@ -64,8 +58,6 @@ const ControlsBody = (): JSX.Element => {
|
||||
)}
|
||||
|
||||
{triggerEmptySupported && <Dock/>}
|
||||
{goToLocation && <GoToLocationPresets />}
|
||||
{zoneCleaning && <ZonePresets />}
|
||||
|
||||
{
|
||||
robotInformation &&
|
||||
|
||||
@ -1,147 +0,0 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Grid,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
styled,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import {
|
||||
Capability,
|
||||
useGoToLocationPresetMutation,
|
||||
useGoToLocationPresetsQuery,
|
||||
useRobotStatusQuery,
|
||||
} from "../api";
|
||||
|
||||
const StyledFormControl = styled(FormControl)({
|
||||
minWidth: 120,
|
||||
});
|
||||
|
||||
const GoToLocationPresets = (): JSX.Element => {
|
||||
const { data: status } = useRobotStatusQuery((status) => {
|
||||
return status.value;
|
||||
});
|
||||
const {
|
||||
data: goToLocations,
|
||||
isLoading: goToLocationPresetsLoading,
|
||||
isError: goToLocationPresetLoadError,
|
||||
} = useGoToLocationPresetsQuery();
|
||||
const {
|
||||
isLoading: goToLocationPresetIsExecuting,
|
||||
mutate: goToLocationPreset
|
||||
} = useGoToLocationPresetMutation({
|
||||
onSuccess() {
|
||||
setSelected("");
|
||||
},
|
||||
});
|
||||
const [selected, setSelected] = React.useState<string>("");
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
(event: SelectChangeEvent<string>) => {
|
||||
setSelected(event.target.value);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const canGo = status === "idle" || status === "docked";
|
||||
|
||||
const handleGo = React.useCallback(() => {
|
||||
if (selected === "" || !canGo) {
|
||||
return;
|
||||
}
|
||||
|
||||
goToLocationPreset(selected);
|
||||
}, [canGo, goToLocationPreset, selected]);
|
||||
|
||||
const body = React.useMemo(() => {
|
||||
if (goToLocationPresetsLoading) {
|
||||
return (
|
||||
<Grid item>
|
||||
<CircularProgress size={20} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
if (goToLocationPresetLoadError || goToLocations === undefined) {
|
||||
return (
|
||||
<Grid item>
|
||||
<Typography color="error">
|
||||
Error loading {Capability.GoToLocation}
|
||||
</Typography>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid item>
|
||||
<StyledFormControl>
|
||||
<Select
|
||||
value={selected}
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
variant="standard"
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>Preset</em>
|
||||
</MenuItem>
|
||||
{goToLocations.map(({ name, id }) => {
|
||||
return (
|
||||
<MenuItem key={id} value={id}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
{!canGo && selected !== "" && (
|
||||
<FormHelperText>Can only go to location when idle</FormHelperText>
|
||||
)}
|
||||
</StyledFormControl>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<Box display="flex" justifyContent="flex-end">
|
||||
<Button
|
||||
disabled={!selected || goToLocationPresetIsExecuting || !canGo}
|
||||
onClick={handleGo}
|
||||
>
|
||||
Go
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
canGo,
|
||||
handleChange,
|
||||
handleGo,
|
||||
goToLocationPresetIsExecuting,
|
||||
goToLocationPresetLoadError,
|
||||
goToLocationPresetsLoading,
|
||||
goToLocations,
|
||||
selected,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Grid item>
|
||||
<Paper>
|
||||
<Box px={2} py={1}>
|
||||
<Grid container direction="row" alignItems="center" spacing={1}>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">Go to</Typography>
|
||||
</Grid>
|
||||
{body}
|
||||
</Grid>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoToLocationPresets;
|
||||
@ -1,144 +0,0 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Grid,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
styled,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import {
|
||||
Capability,
|
||||
useCleanZonePresetMutation,
|
||||
useRobotStatusQuery,
|
||||
useZonePresetsQuery,
|
||||
} from "../api";
|
||||
|
||||
const StyledFormControl = styled(FormControl)({
|
||||
minWidth: 120,
|
||||
});
|
||||
|
||||
const ZonePresets = (): JSX.Element => {
|
||||
const { data: status } = useRobotStatusQuery((status) => {
|
||||
return status.value;
|
||||
});
|
||||
const {
|
||||
data: zonePresets,
|
||||
isLoading: zonePresetsLoading,
|
||||
isError: errorLoadingZonePresets,
|
||||
} = useZonePresetsQuery();
|
||||
const {
|
||||
isLoading: cleanZonePresetExecuting,
|
||||
mutate: cleanZonePreset
|
||||
} = useCleanZonePresetMutation({
|
||||
onSuccess() {
|
||||
setSelected("");
|
||||
},
|
||||
});
|
||||
const [selected, setSelected] = React.useState<string>("");
|
||||
const canClean = status === "idle" || status === "docked";
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
(event: SelectChangeEvent<string>) => {
|
||||
setSelected(event.target.value as string);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleClean = React.useCallback(() => {
|
||||
if (selected === "" || !canClean) {
|
||||
return;
|
||||
}
|
||||
cleanZonePreset(selected);
|
||||
}, [canClean, cleanZonePreset, selected]);
|
||||
|
||||
const body = React.useMemo(() => {
|
||||
if (zonePresetsLoading) {
|
||||
return (
|
||||
<Grid item>
|
||||
<CircularProgress size={20} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
if (errorLoadingZonePresets || zonePresets === undefined) {
|
||||
return (
|
||||
<Grid item>
|
||||
<Typography color="error">
|
||||
Error loading {Capability.ZoneCleaning}
|
||||
</Typography>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid item>
|
||||
<StyledFormControl>
|
||||
<Select
|
||||
value={selected}
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
variant="standard"
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>Preset</em>
|
||||
</MenuItem>
|
||||
{zonePresets.map(({ name, id }) => {
|
||||
return (
|
||||
<MenuItem key={id} value={id}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
{!canClean && selected !== "" && (
|
||||
<FormHelperText>Can only start cleaning when idle</FormHelperText>
|
||||
)}
|
||||
</StyledFormControl>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<Box display="flex" justifyContent="flex-end">
|
||||
<Button
|
||||
disabled={!selected || cleanZonePresetExecuting || !canClean}
|
||||
onClick={handleClean}
|
||||
>
|
||||
Clean
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
canClean,
|
||||
handleChange,
|
||||
handleClean,
|
||||
cleanZonePresetExecuting,
|
||||
errorLoadingZonePresets,
|
||||
zonePresetsLoading,
|
||||
selected,
|
||||
zonePresets,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Grid item>
|
||||
<Paper>
|
||||
<Box px={2} py={1}>
|
||||
<Grid container direction="row" alignItems="center" spacing={1}>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">Clean zone preset</Typography>
|
||||
</Grid>
|
||||
{body}
|
||||
</Grid>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
export default ZonePresets;
|
||||
@ -2,10 +2,8 @@ import React, { FunctionComponent } from "react";
|
||||
import { TimerActionControlProps } from "./types";
|
||||
import {
|
||||
Capability,
|
||||
useGoToLocationPresetsQuery,
|
||||
useMapSegmentationPropertiesQuery,
|
||||
useSegmentsQuery,
|
||||
useZonePresetsQuery,
|
||||
} from "../../api";
|
||||
import {
|
||||
Box,
|
||||
@ -34,15 +32,9 @@ export const validateParams: Record<
|
||||
full_cleanup: () => {
|
||||
return true;
|
||||
},
|
||||
zone_cleanup: (props) => {
|
||||
return props.zone_id && props.zone_id !== "none";
|
||||
},
|
||||
segment_cleanup: (props) => {
|
||||
return props.segment_ids?.length > 0 && (props.iterations ?? 1 > 0);
|
||||
},
|
||||
goto_location: (props) => {
|
||||
return props.goto_id && props.goto_id !== "none";
|
||||
},
|
||||
};
|
||||
|
||||
export const FullCleanupControls: FunctionComponent<TimerActionControlProps> =
|
||||
@ -51,65 +43,6 @@ export const FullCleanupControls: FunctionComponent<TimerActionControlProps> =
|
||||
return null;
|
||||
};
|
||||
|
||||
export const ZoneCleanupControls: FunctionComponent<TimerActionControlProps> =
|
||||
({ disabled, params, setParams }) => {
|
||||
const selectedZoneId = params.zone_id ?? "none";
|
||||
|
||||
const {
|
||||
data: zonePresets,
|
||||
isLoading: zonePresetsLoading,
|
||||
isError: zonePresetsError,
|
||||
} = useZonePresetsQuery();
|
||||
|
||||
const zoneMenuItems = React.useMemo(() => {
|
||||
if (!zonePresets) {
|
||||
return null;
|
||||
}
|
||||
return zonePresets.map(({ name, id }) => {
|
||||
return (
|
||||
<MenuItem key={id} value={id}>
|
||||
{name || "Unnamed zone: " + id}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
}, [zonePresets]);
|
||||
|
||||
if (zonePresetsLoading) {
|
||||
return <CircularProgress />;
|
||||
}
|
||||
|
||||
if (zonePresetsError) {
|
||||
return (
|
||||
<Typography color="error">
|
||||
Error loading {Capability.ZoneCleaning}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InputLabel id={"zone-label"}>Select zone</InputLabel>
|
||||
<Select
|
||||
labelId={"zone-label"}
|
||||
id={"zone-select"}
|
||||
value={selectedZoneId}
|
||||
label="Select zone"
|
||||
disabled={disabled}
|
||||
onChange={(e) => {
|
||||
setParams({
|
||||
zone_id: e.target.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MenuItem value={"none"}>
|
||||
<em>No zone selected</em>
|
||||
</MenuItem>
|
||||
{zoneMenuItems}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export const SegmentCleanupControls: FunctionComponent<TimerActionControlProps> =
|
||||
({ disabled, params, setParams }) => {
|
||||
const segmentIds: Array<string> = React.useMemo(() => {
|
||||
@ -318,64 +251,3 @@ export const SegmentCleanupControls: FunctionComponent<TimerActionControlProps>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const GoToLocationControls: FunctionComponent<TimerActionControlProps> =
|
||||
({ params, setParams, disabled }) => {
|
||||
const selectedGoToId = params.goto_id ?? "none";
|
||||
|
||||
const {
|
||||
data: goToLocations,
|
||||
isLoading: goToLocationPresetsLoading,
|
||||
isError: goToLocationPresetLoadError,
|
||||
} = useGoToLocationPresetsQuery();
|
||||
|
||||
const goToMenuItems = React.useMemo(() => {
|
||||
if (!goToLocations) {
|
||||
return null;
|
||||
}
|
||||
return goToLocations.map(({ name, id }) => {
|
||||
return (
|
||||
<MenuItem key={id} value={id}>
|
||||
{name || "Unnamed go to location: " + id}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
}, [goToLocations]);
|
||||
|
||||
if (goToLocationPresetsLoading) {
|
||||
return <CircularProgress />;
|
||||
}
|
||||
|
||||
if (goToLocationPresetLoadError) {
|
||||
return (
|
||||
<Typography color="error">
|
||||
Error loading {Capability.GoToLocation}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InputLabel id={"go-to-location-label"}>
|
||||
Select go to location
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId={"go-to-location-label"}
|
||||
id={"go-to-location-select"}
|
||||
value={selectedGoToId}
|
||||
label="Select go to location"
|
||||
disabled={disabled}
|
||||
onChange={(e) => {
|
||||
setParams({
|
||||
goto_id: e.target.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MenuItem value={"none"}>
|
||||
<em>No go to location selected</em>
|
||||
</MenuItem>
|
||||
{goToMenuItems}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
@ -39,9 +39,7 @@ type TimerCardProps = {
|
||||
|
||||
export const timerActionLabels: Record<string, string> = {
|
||||
full_cleanup: "Full cleanup",
|
||||
zone_cleanup: "Zone cleanup",
|
||||
segment_cleanup: "Segment cleanup",
|
||||
goto_location: "Go to location",
|
||||
};
|
||||
|
||||
function convertTime(hour: number, minute: number, offset: number) : { hour: number, minute: number } {
|
||||
|
||||
@ -25,10 +25,8 @@ import { StaticTimePicker } from "@mui/lab";
|
||||
import { TimerActionControlProps } from "./types";
|
||||
import {
|
||||
FullCleanupControls,
|
||||
GoToLocationControls,
|
||||
SegmentCleanupControls,
|
||||
validateParams,
|
||||
ZoneCleanupControls,
|
||||
} from "./ActionControls";
|
||||
|
||||
const actionControls: Record<
|
||||
@ -36,9 +34,7 @@ const actionControls: Record<
|
||||
React.ComponentType<TimerActionControlProps>
|
||||
> = {
|
||||
full_cleanup: FullCleanupControls,
|
||||
zone_cleanup: ZoneCleanupControls,
|
||||
segment_cleanup: SegmentCleanupControls,
|
||||
goto_location: GoToLocationControls,
|
||||
};
|
||||
|
||||
type TimerDialogProps = {
|
||||
|
||||
@ -86,28 +86,6 @@ const fakeConfig = {
|
||||
onUpdate: (_) => {
|
||||
},
|
||||
get: key => fakeConfig[key],
|
||||
"goToLocationPresets": {
|
||||
"a9666386-7041-4bd4-a823-ebefa48665eb": {
|
||||
"__class": "ValetudoGoToLocation",
|
||||
"metaData": {},
|
||||
"name": "SpotA",
|
||||
"coordinates": {
|
||||
"x": 2589,
|
||||
"y": 2364
|
||||
},
|
||||
"id": "a9666386-7041-4bd4-a823-ebefa48665eb"
|
||||
},
|
||||
"6c74ac84-dfe9-4c4c-8bec-836ff268d630": {
|
||||
"__class": "ValetudoGoToLocation",
|
||||
"metaData": {},
|
||||
"name": "SpotB",
|
||||
"coordinates": {
|
||||
"x": 2186,
|
||||
"y": 2262
|
||||
},
|
||||
"id": "6c74ac84-dfe9-4c4c-8bec-836ff268d630"
|
||||
}
|
||||
},
|
||||
};
|
||||
const eventStore = new ValetudoEventStore()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user