Skip to content

Commit 67bbeac

Browse files
committed
Add confirmation prompt for map creation mode
- Require explicit 'yes' confirmation before launching map creation (cmd=4) - Display warning about robot movement - Allows skipping dangerous operations safely
1 parent 4695340 commit 67bbeac

File tree

2 files changed

+296
-0
lines changed

2 files changed

+296
-0
lines changed

examples/Q10/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ Interactive test script with detailed debug information. This script:
1919
### test_q10_vacuum.py
2020
Basic test script for Q10 vacuum commands. A simpler version focused on testing the vacuum trait.
2121

22+
### test_q10_advanced.py (NEW!)
23+
Advanced test suite with complex features and detailed diagnostics:
24+
- Tests multiple cleaning modes (standard, area, fast map)
25+
- Device status monitoring and diagnostics
26+
- Structured test suite with multiple test categories
27+
- Interactive menu for manual command testing
28+
- Full test suite execution
29+
30+
**Use this script when:**
31+
- You want to test advanced cleaning modes
32+
- You need comprehensive diagnostics
33+
- You want to verify all VacuumTrait features
34+
- You're developing or debugging Q10 device support
35+
2236
## Requirements
2337

2438
Install the package in development mode:
@@ -56,6 +70,14 @@ The VacuumTrait provides these commands:
5670
- **Stop cleaning** - Stops the cleaning operation completely
5771
- **Return to dock** - Sends the robot back to its charging dock
5872

73+
### Advanced Cleaning Modes
74+
75+
Additional cleaning modes can be tested with `test_q10_advanced.py`:
76+
77+
- **Standard cleaning (cmd=1)** - Full cleaning cycle
78+
- **Electoral/Area cleaning (cmd=2)** - Clean specific areas/zones
79+
- **Fast map creation (cmd=4)** - Quickly generate room map
80+
5981
## Supported Devices
6082

6183
These scripts are designed for Roborock Q10 devices that support the B01 Q10 protocol. The script will automatically detect if your device has the required `b01_q10_properties` API.

examples/Q10/test_q10_advanced.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#!/usr/bin/env python3
2+
"""Advanced test script for Q10 VacuumTrait with complex features."""
3+
4+
import asyncio
5+
import pathlib
6+
7+
from roborock.devices.device_manager import UserParams, create_device_manager
8+
from roborock.devices.file_cache import FileCache, load_value, store_value
9+
from roborock.web_api import RoborockApiClient
10+
11+
# Cache paths
12+
USER_PARAMS_PATH = pathlib.Path.home() / ".cache" / "roborock-user-params.pkl"
13+
CACHE_PATH = pathlib.Path.home() / ".cache" / "roborock-cache-data.pkl"
14+
15+
16+
async def login_flow() -> UserParams:
17+
"""Perform the login flow to obtain UserData from the web API."""
18+
username = input("📧 Email: ")
19+
web_api = RoborockApiClient(username=username)
20+
print("📨 Requesting login code sent to email...")
21+
await web_api.request_code()
22+
code = input("🔑 Code: ")
23+
user_data = await web_api.code_login(code)
24+
base_url = await web_api.base_url
25+
return UserParams(
26+
username=username,
27+
user_data=user_data,
28+
base_url=base_url,
29+
)
30+
31+
32+
async def get_or_create_session() -> UserParams:
33+
"""Initialize the session by logging in if necessary."""
34+
user_params = await load_value(USER_PARAMS_PATH)
35+
if user_params is None:
36+
print("No cached login data found, please login.")
37+
user_params = await login_flow()
38+
print("✅ Login successful, caching login data...")
39+
await store_value(USER_PARAMS_PATH, user_params)
40+
return user_params
41+
42+
43+
async def test_basic_commands(vacuum):
44+
"""Test basic vacuum commands."""
45+
print("\n" + "=" * 50)
46+
print("🧪 TESTING BASIC COMMANDS")
47+
print("=" * 50)
48+
49+
commands = [
50+
("Start cleaning", vacuum.start_clean),
51+
("Pause cleaning", vacuum.pause_clean),
52+
("Resume cleaning", vacuum.resume_clean),
53+
("Stop cleaning", vacuum.stop_clean),
54+
("Return to dock", vacuum.return_to_dock),
55+
]
56+
57+
for idx, (name, cmd) in enumerate(commands, 1):
58+
try:
59+
print(f"\n{idx}. Testing: {name}")
60+
await cmd()
61+
print(f" ✅ Command sent successfully!")
62+
except Exception as e:
63+
print(f" ❌ Error: {e}")
64+
import traceback
65+
traceback.print_exc()
66+
67+
68+
async def test_advanced_features(vacuum):
69+
"""Test advanced cleaning features (based on code comments)."""
70+
print("\n" + "=" * 50)
71+
print("🚀 TESTING ADVANCED FEATURES")
72+
print("=" * 50)
73+
74+
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
75+
76+
# Test different cleaning modes
77+
print("\n1. Testing different cleaning modes...")
78+
79+
modes = [
80+
("Standard cleaning (cmd=1)", 1),
81+
("Electoral/Area cleaning (cmd=2)", 2),
82+
("Fast map creation (cmd=4)", 4),
83+
]
84+
85+
for mode_name, cmd_value in modes:
86+
try:
87+
# Ask for confirmation for map creation mode
88+
if cmd_value == 4:
89+
print(f"\n ⚠️ {mode_name}")
90+
print(" ⚠️ WARNING: This will start the map creation process!")
91+
print(" ⚠️ The robot will start moving to map your home.")
92+
confirm = input(" Are you sure you want to proceed? (yes/no): ").strip().lower()
93+
if confirm != "yes":
94+
print(" ⏭️ Skipped!")
95+
continue
96+
97+
print(f"\n{mode_name}")
98+
await vacuum._command.send(
99+
command=B01_Q10_DP.START_CLEAN,
100+
params={"cmd": cmd_value},
101+
)
102+
print(f" ✅ Sent!")
103+
except Exception as e:
104+
print(f" ❌ Error: {e}")
105+
106+
107+
async def test_device_status(device):
108+
"""Test device status monitoring."""
109+
print("\n" + "=" * 50)
110+
print("📊 CHECKING DEVICE STATUS")
111+
print("=" * 50)
112+
113+
try:
114+
# Check if device has properties for status
115+
print(f"\nDevice: {device.name}")
116+
print(f"Product: {device.product.name} ({device.product.model})")
117+
print(f"Connected: {device.is_connected}")
118+
print(f"Local connected: {device.is_local_connected}")
119+
120+
# Try to get status if available
121+
if device.v1_properties and device.v1_properties.status:
122+
print("\n🔍 V1 Status available")
123+
try:
124+
await device.v1_properties.status.refresh()
125+
status = device.v1_properties.status
126+
print(f" Status: {status}")
127+
except Exception as e:
128+
print(f" Could not refresh status: {e}")
129+
130+
# Check Q10 properties
131+
if device.b01_q10_properties:
132+
print("\n✅ Q10 Properties available")
133+
print(f" Command API: {device.b01_q10_properties.command}")
134+
print(f" Vacuum Trait: {device.b01_q10_properties.vacuum}")
135+
136+
except Exception as e:
137+
print(f"❌ Error checking device status: {e}")
138+
import traceback
139+
traceback.print_exc()
140+
141+
142+
async def interactive_menu(vacuum):
143+
"""Interactive menu for manual testing."""
144+
print("\n" + "=" * 50)
145+
print("🎮 INTERACTIVE TEST MENU")
146+
print("=" * 50)
147+
print("\n1. Start cleaning")
148+
print("2. Pause cleaning")
149+
print("3. Resume cleaning")
150+
print("4. Stop cleaning")
151+
print("5. Return to dock")
152+
print("6. Test all modes")
153+
print("0. Exit")
154+
print("=" * 50)
155+
156+
while True:
157+
try:
158+
choice = input("\nEnter your choice (0-6): ").strip()
159+
160+
if choice == "0":
161+
print("👋 Exiting...")
162+
break
163+
elif choice == "1":
164+
print("▶️ Starting cleaning...")
165+
await vacuum.start_clean()
166+
print("✅ Command sent!")
167+
elif choice == "2":
168+
print("⏸️ Pausing cleaning...")
169+
await vacuum.pause_clean()
170+
print("✅ Command sent!")
171+
elif choice == "3":
172+
print("▶️ Resuming cleaning...")
173+
await vacuum.resume_clean()
174+
print("✅ Command sent!")
175+
elif choice == "4":
176+
print("⏹️ Stopping cleaning...")
177+
await vacuum.stop_clean()
178+
print("✅ Command sent!")
179+
elif choice == "5":
180+
print("🏠 Returning to dock...")
181+
await vacuum.return_to_dock()
182+
print("✅ Command sent!")
183+
elif choice == "6":
184+
await test_advanced_features(vacuum)
185+
else:
186+
print("❌ Invalid choice")
187+
except KeyboardInterrupt:
188+
print("\n👋 Exiting...")
189+
break
190+
except Exception as e:
191+
print(f"❌ Error: {e}")
192+
193+
194+
async def main():
195+
"""Main test function."""
196+
try:
197+
user_params = await get_or_create_session()
198+
cache = FileCache(CACHE_PATH)
199+
200+
print("\n🔄 Connecting to devices...")
201+
device_manager = await create_device_manager(user_params, cache=cache)
202+
devices = await device_manager.get_devices()
203+
204+
print(f"\n📱 Found {len(devices)} device(s)")
205+
for idx, device in enumerate(devices, 1):
206+
print(f" {idx}. {device.name} ({device.product.model})")
207+
208+
# Select device
209+
if len(devices) == 1:
210+
device = devices[0]
211+
print(f"\n✅ Using device: {device.name}")
212+
else:
213+
device_idx = int(input("\nSelect device number: ")) - 1
214+
device = devices[device_idx]
215+
print(f"\n✅ Selected device: {device.name}")
216+
217+
# Check Q10 properties
218+
if device.b01_q10_properties is None:
219+
print("\n❌ This device doesn't have Q10 properties")
220+
await cache.flush()
221+
return
222+
223+
vacuum = device.b01_q10_properties.vacuum
224+
225+
# Show main menu
226+
print("\n" + "=" * 50)
227+
print("Q10 ADVANCED TEST SUITE")
228+
print("=" * 50)
229+
print("\n1. Run basic commands test")
230+
print("2. Test advanced features")
231+
print("3. Check device status")
232+
print("4. Interactive menu")
233+
print("5. Run all tests")
234+
print("0. Exit")
235+
print("=" * 50)
236+
237+
while True:
238+
try:
239+
choice = input("\nSelect test (0-5): ").strip()
240+
241+
if choice == "0":
242+
break
243+
elif choice == "1":
244+
await test_basic_commands(vacuum)
245+
elif choice == "2":
246+
await test_advanced_features(vacuum)
247+
elif choice == "3":
248+
await test_device_status(device)
249+
elif choice == "4":
250+
await interactive_menu(vacuum)
251+
elif choice == "5":
252+
await test_device_status(device)
253+
await test_basic_commands(vacuum)
254+
await test_advanced_features(vacuum)
255+
else:
256+
print("❌ Invalid choice")
257+
except KeyboardInterrupt:
258+
print("\n👋 Exiting...")
259+
break
260+
except Exception as e:
261+
print(f"❌ Error: {e}")
262+
import traceback
263+
traceback.print_exc()
264+
265+
await cache.flush()
266+
267+
except Exception as e:
268+
print(f"\n❌ Fatal error: {e}")
269+
import traceback
270+
traceback.print_exc()
271+
272+
273+
if __name__ == "__main__":
274+
asyncio.run(main())

0 commit comments

Comments
 (0)