Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ body:
- label: "I have saved the log as a `.txt` file and attached it below (DON'T PASTE!)."
required: true

- type: textarea
- type: upload
id: debug_log_upload
attributes:
label: "Debug Log Upload (Drag & Drop .txt file here)"
description: "DO NOT PASTE! Just drag and drop your .txt file into this field."
placeholder: "Drag & drop file here. DO NOT PASTE!"
label: "Debug Log Upload (.txt file required)"
description: "Upload the debug log as a .txt file. Pasted logs or plain text are not accepted."
validations:
required: true
accept: ".txt"

- type: markdown
attributes:
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ This feature only works when map creation is enabled in the adapter options. Ope
Placeholder for the next version (at the beginning of the line):
### **WORK IN PROGRESS**
-->
### **WORK IN PROGRESS**

* (copystring) Fixed missing auto-empty command for Roborock Qrevo MaxV (#1272).
* (copystring) Require bug reports to upload a `.txt` debug log file.

### 0.7.1 (2026-05-19)

* (copystring) Fixed local TCP recovery when a Roborock device gets a new LAN IP address.
Expand Down Expand Up @@ -107,7 +112,9 @@ This feature only works when map creation is enabled in the adapter options. Ope
* (copystring) Update LICENSE
* (copystring) Update README.md

Older changes can be found in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).## License
Older changes can be found in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).

## License
MIT License

Copyright (c) 2025-2026 copystring <copystring@gmail.com>
Expand Down
3 changes: 2 additions & 1 deletion src/lib/features/vacuum/a87_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const a87Config: DeviceModelConfig = {
Feature.Rdt,
Feature.CleanArea,
Feature.CleanTime,
Feature.SwitchStatus
Feature.SwitchStatus,
Feature.AutoEmptyDock
]
};

Expand Down
65 changes: 65 additions & 0 deletions src/lib/features/vacuum/registeredModelFeatures.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { describe, expect, it, vi } from "vitest";
import { BaseDeviceFeatures, type FeatureDependencies } from "../baseDeviceFeatures";
import { Feature } from "../features.enum";
import "./index";

describe("registered vacuum model features", () => {
function createDependencies(): FeatureDependencies {
const requestsHandlerMock = {
sendRequest: vi.fn().mockResolvedValue({}),
command: vi.fn().mockResolvedValue(undefined),
mapParser: { parsedata: vi.fn().mockResolvedValue({}) },
mapCreator: { canvasMap: vi.fn().mockResolvedValue(["", "", ""]) }
};

const adapterMock = {
namespace: "roborock.0",
log: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn(), silly: vi.fn() },
setStateChanged: vi.fn().mockResolvedValue(undefined),
setState: vi.fn(),
ensureState: vi.fn().mockResolvedValue(undefined),
ensureFolder: vi.fn().mockResolvedValue(undefined),
getStateAsync: vi.fn().mockResolvedValue(undefined),
getStatesAsync: vi.fn().mockResolvedValue({}),
getObjectAsync: vi.fn().mockResolvedValue(undefined),
extendObject: vi.fn().mockResolvedValue(undefined),
setObject: vi.fn().mockResolvedValue(undefined),
setObjectNotExistsAsync: vi.fn().mockResolvedValue(undefined),
requestsHandler: requestsHandlerMock,
getDeviceProtocolVersion: vi.fn().mockResolvedValue("1.0"),
translations: {},
http_api: {
getFwFeaturesResult: vi.fn(),
storeFwFeaturesResult: vi.fn(),
getRobotModel: vi.fn().mockReturnValue("roborock.vacuum.a87"),
getDevices: vi.fn().mockReturnValue([])
},
rLog: vi.fn(),
translationManager: {
get: vi.fn().mockImplementation((key, def) => def || key)
},
errorMessage: (error: unknown) => error instanceof Error ? error.message : String(error)
};

return {
adapter: adapterMock,
http_api: adapterMock.http_api,
ensureState: vi.fn().mockResolvedValue(undefined),
ensureFolder: vi.fn().mockResolvedValue(undefined),
log: adapterMock.log,
config: { staticFeatures: [] }
} as unknown as FeatureDependencies;
}

it("exposes the auto-empty command for Qrevo MaxV through the model registry", async () => {
const ModelClass = BaseDeviceFeatures.getRegisteredModelClass("roborock.vacuum.a87");
expect(ModelClass).toBeDefined();
if (!ModelClass) throw new Error("roborock.vacuum.a87 is not registered");

const vacuum = new ModelClass(createDependencies(), "duid1");
await vacuum.initialize();

expect(vacuum.hasStaticFeature(Feature.AutoEmptyDock)).toBe(true);
expect(vacuum.commands).toHaveProperty("app_start_dust_collection");
});
});
Loading