Skip to content

Commit

Permalink
feat(MockRobot): Mock more capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
Hypfer committed Sep 6, 2023
1 parent dca5e46 commit 34ff556
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 54 deletions.
10 changes: 10 additions & 0 deletions backend/lib/robots/mock/MockRobot.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class MockRobot extends ValetudoRobot {
this.registerCapability(new capabilities.MockManualControlCapability({robot: this}));
this.registerCapability(new capabilities.MockCurrentStatisticsCapability({robot: this}));
this.registerCapability(new capabilities.MockTotalStatisticsCapability({robot: this}));
this.registerCapability(new capabilities.MockOperationModeControlCapability({robot: this}));
this.registerCapability(new capabilities.MockPetObstacleAvoidanceControlCapability({robot: this}));
this.registerCapability(new capabilities.MockCollisionAvoidantNavigationControlCapability({robot: this}));
this.registerCapability(new capabilities.MockCarpetSensorModeControlCapability({robot: this}));
this.registerCapability(new capabilities.MockMopDockCleanManualTriggerCapability({robot: this}));
this.registerCapability(new capabilities.MockMopDockDryManualTriggerCapability({robot: this}));

// Raise events to make them visible in the UI
options.valetudoEventStore.raise(new DustBinFullValetudoEvent({}));
Expand All @@ -54,6 +60,10 @@ class MockRobot extends ValetudoRobot {
options.valetudoEventStore.raise(new ErrorStateValetudoEvent({
message: "This is an error message"
}));

this.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({
value: entities.state.attributes.DockStatusStateAttribute.VALUE.IDLE
}));
}

getManufacturer() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const CarpetSensorModeControlCapability = require("../../../core/capabilities/CarpetSensorModeControlCapability");

/**
* @extends CarpetSensorModeControlCapability<import("../MockRobot")>
*/
class MockCarpetSensorModeControlCapability extends CarpetSensorModeControlCapability {

/**
* @param {object} options
* @param {import("../MockRobot")} options.robot
*/
constructor(options) {
super(options);

this.mode = CarpetSensorModeControlCapability.MODE.LIFT;
}

async getMode() {
return this.mode;
}

async setMode(newMode) {
this.mode = newMode;
}

getProperties() {
return {
supportedModes: [
CarpetSensorModeControlCapability.MODE.LIFT,
CarpetSensorModeControlCapability.MODE.AVOID,
CarpetSensorModeControlCapability.MODE.OFF,
]
};
}
}

module.exports = MockCarpetSensorModeControlCapability;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const CollisionAvoidantNavigationControlCapability = require("../../../core/capabilities/CollisionAvoidantNavigationControlCapability");

/**
* @extends PetObstacleAvoidanceControlCapability<import("../MockRobot")>
*/
class MockCollisionAvoidantNavigationControlCapability extends CollisionAvoidantNavigationControlCapability {
/**
* @param {object} options
* @param {import("../MockRobot")} options.robot
*/
constructor(options) {
super(options);

this.enabled = true;
}

async isEnabled() {
return this.enabled;
}

/**
* @returns {Promise<void>}
*/
async enable() {
this.enabled = true;
}

/**
* @returns {Promise<void>}
*/
async disable() {
this.enabled = false;
}
}

module.exports = MockCollisionAvoidantNavigationControlCapability;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const entities = require("../../../entities");
const MopDockCleanManualTriggerCapability = require("../../../core/capabilities/MopDockCleanManualTriggerCapability");

/**
* @extends MopDockCleanManualTriggerCapability<import("../MockRobot")>
*/
class MockMopDockCleanManualTriggerCapability extends MopDockCleanManualTriggerCapability {
/**
* @returns {Promise<void>}
*/
async startCleaning() {
this.robot.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({
value: entities.state.attributes.DockStatusStateAttribute.VALUE.CLEANING
}));
}

/**
* @returns {Promise<void>}
*/
async stopCleaning() {
this.robot.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({
value: entities.state.attributes.DockStatusStateAttribute.VALUE.IDLE
}));
}
}

module.exports = MockMopDockCleanManualTriggerCapability;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const entities = require("../../../entities");
const MopDockDryManualTriggerCapability = require("../../../core/capabilities/MopDockDryManualTriggerCapability");

/**
* @extends MopDockDryManualTriggerCapability<import("../MockRobot")>
*/
class MockMopDockDryManualTriggerCapability extends MopDockDryManualTriggerCapability {
/**
* @returns {Promise<void>}
*/
async startDrying() {
this.robot.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({
value: entities.state.attributes.DockStatusStateAttribute.VALUE.DRYING
}));
}

/**
* @returns {Promise<void>}
*/
async stopDrying() {
this.robot.state.upsertFirstMatchingAttribute(new entities.state.attributes.DockStatusStateAttribute({
value: entities.state.attributes.DockStatusStateAttribute.VALUE.IDLE
}));
}
}

module.exports = MockMopDockDryManualTriggerCapability;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const entities = require("../../../entities");
const OperationModeControlCapability = require("../../../core/capabilities/OperationModeControlCapability");
const ValetudoSelectionPreset = require("../../../entities/core/ValetudoSelectionPreset");
const stateAttrs = entities.state.attributes;

/**
* @extends OperationModeControlCapability<import("../MockRobot")>
*/
class MockOperationModeControlCapability extends OperationModeControlCapability {
/**
* @param {object} options
* @param {import("../MockRobot")} options.robot
*/
constructor(options) {
let presets = [
new ValetudoSelectionPreset({name: entities.state.attributes.PresetSelectionStateAttribute.MODE.MOP, value: 0}),
new ValetudoSelectionPreset({name: entities.state.attributes.PresetSelectionStateAttribute.MODE.VACUUM, value: 1}),
new ValetudoSelectionPreset({name: entities.state.attributes.PresetSelectionStateAttribute.MODE.VACUUM_AND_MOP, value: 2})
];
super({
robot: options.robot,
presets: presets
});

this.StateAttr = new stateAttrs.PresetSelectionStateAttribute({
type: stateAttrs.PresetSelectionStateAttribute.TYPE.OPERATION_MODE,
value: stateAttrs.PresetSelectionStateAttribute.MODE.VACUUM
});

this.robot.state.upsertFirstMatchingAttribute(this.StateAttr);
}

/**
* @param {string} preset
* @returns {Promise<void>}
*/
async selectPreset(preset) {
const matchedPreset = this.presets.find(p => {
return p.name === preset;
});

if (matchedPreset) {
this.StateAttr.value = matchedPreset.name;
} else {
throw new Error("Invalid Preset");
}
}
}

module.exports = MockOperationModeControlCapability;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const PetObstacleAvoidanceControlCapability = require("../../../core/capabilities/PetObstacleAvoidanceControlCapability");

/**
* @extends PetObstacleAvoidanceControlCapability<import("../MockRobot")>
*/
class MockPetObstacleAvoidanceControlCapability extends PetObstacleAvoidanceControlCapability {
/**
* @param {object} options
* @param {import("../MockRobot")} options.robot
*/
constructor(options) {
super(options);

this.enabled = true;
}

async isEnabled() {
return this.enabled;
}

/**
* @returns {Promise<void>}
*/
async enable() {
this.enabled = true;
}

/**
* @returns {Promise<void>}
*/
async disable() {
this.enabled = false;
}
}

module.exports = MockPetObstacleAvoidanceControlCapability;
6 changes: 6 additions & 0 deletions backend/lib/robots/mock/capabilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module.exports = {
MockAutoEmptyDockManualTriggerCapability: require("./MockAutoEmptyDockManualTriggerCapability"),
MockBasicControlCapability: require("./MockBasicControlCapability"),
MockCarpetModeControlCapability: require("./MockCarpetModeControlCapability"),
MockCarpetSensorModeControlCapability: require("./MockCarpetSensorModeControlCapability"),
MockCollisionAvoidantNavigationControlCapability: require("./MockCollisionAvoidantNavigationControlCapability"),
MockConsumableMonitoringCapability: require("./MockConsumableMonitoringCapability"),
MockCurrentStatisticsCapability: require("./MockCurrentStatisticsCapability"),
MockDoNotDisturbCapability: require("./MockDoNotDisturbCapability"),
Expand All @@ -14,9 +16,13 @@ module.exports = {
MockMapResetCapability: require("./MockMapResetCapability"),
MockMapSegmentationCapability: require("./MockMapSegmentationCapability"),
MockMappingPassCapability: require("./MockMappingPassCapability"),
MockMopDockCleanManualTriggerCapability: require("./MockMopDockCleanManualTriggerCapability"),
MockMopDockDryManualTriggerCapability: require("./MockMopDockDryManualTriggerCapability"),
MockObstacleAvoidanceControlCapability: require("./MockObstacleAvoidanceControlCapability"),
MockOperationModeControlCapability: require("./MockOperationModeControlCapability"),
MockPendingMapChangeHandlingCapability: require("./MockPendingMapChangeHandlingCapability"),
MockPersistentMapControlCapability: require("./MockPersistentMapControlCapability"),
MockPetObstacleAvoidanceControlCapability: require("./MockPetObstacleAvoidanceControlCapability"),
MockSpeakerTestCapability: require("./MockSpeakerTestCapability"),
MockSpeakerVolumeControlCapability: require("./MockSpeakerVolumeControlCapability"),
MockTotalStatisticsCapability: require("./MockTotalStatisticsCapability"),
Expand Down
45 changes: 45 additions & 0 deletions docs/_pages/integrations/mqtt.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ Homie autodiscovery info is best viewed with something like [MQTT Explorer](http
- [Go to location (`go`)](#gotolocationgo)
- [Locate (`LocateCapability`)](#locatelocatecapability)
- [Locate (`locate`)](#locatelocate)
- [Mode control (`OperationModeControlCapability`)](#modecontroloperationmodecontrolcapability)
- [Mode (`preset`)](#modepreset)
- [Segment cleaning (`MapSegmentationCapability`)](#segmentcleaningmapsegmentationcapability)
- [Clean segments (`clean`)](#cleansegmentsclean)
- [Speaker volume control (`SpeakerVolumeControlCapability`)](#speakervolumecontrolspeakervolumecontrolcapability)
Expand Down Expand Up @@ -132,6 +134,7 @@ Homie autodiscovery info is best viewed with something like [MQTT Explorer](http
- [Fan (`select.mqtt`)](#fanpreset)
- [Map data (`camera.mqtt`)](#rawmapdataforhomeassistantmap-data-hass)
- [Map segments (`sensor.mqtt`)](#mapsegmentssegments)
- [Mode (`select.mqtt`)](#modepreset)
- [Mop attachment (`binary_sensor.mqtt`)](#mopmop)
- [Play locate sound (`button.mqtt`)](#locatelocate)
- [Reset <CONSUMABLE-MINUTES> Consumable (`button.mqtt`)](#resettheconsumableconsumable-minutesreset)
Expand Down Expand Up @@ -476,6 +479,48 @@ Sample payload:



#### Mode control (`OperationModeControlCapability`) <a id="modecontroloperationmodecontrolcapability" />

*Node, capability: [OperationModeControlCapability](/pages/usage/capabilities-overview.html#operationmodecontrolcapability)*

Status attributes managed by this node:

- PresetSelectionStateAttribute

##### Mode (`preset`) <a id="modepreset" />

*Property, readable, settable, retained*

This handle allows setting the mode. It accepts the preset payloads specified in `$format` or in the HAss json attributes.

- Read topic: `<TOPIC PREFIX>/<IDENTIFIER>/OperationModeControlCapability/preset`
- Set topic: `<TOPIC PREFIX>/<IDENTIFIER>/OperationModeControlCapability/preset/set`
- Data type: [enum](https://homieiot.github.io/specification/#enum) (allowed payloads: `mop`, `vacuum`, `vacuum_and_mop`)

{% include alert.html type="warning" content="Some information contained in this document may not be exactly what is sent or expected by actual robots, since different vendors have different implementations. Refer to the table below.

|------+--------|
| What | Reason |
|------|--------|
| Enum payloads | Different robot models have different mode presets. Always check `$format`/`json_attributes` during startup. |
|------+--------|

" %}

Sample value:

```
vacuum
```

Home Assistant components controlled by this property:

- Mode ([`select.mqtt`](https://www.home-assistant.io/integrations/select.mqtt/))





#### Speaker volume control (`SpeakerVolumeControlCapability`) <a id="speakervolumecontrolspeakervolumecontrolcapability" />

*Node, capability: [SpeakerVolumeControlCapability](/pages/usage/capabilities-overview.html#speakervolumecontrolcapability)*
Expand Down
Loading

0 comments on commit 34ff556

Please sign in to comment.