[APP][Pro] MOVA & Dreame Mower

Hi everyone :waving_hand:

I’m excited to share my Homey app for MOVA and Dreame robotic lawn mowers. If you own a MOVA LiDAX, ViAX or a Dreame A-series mower — this app is for you.


:herb: What is this app?

The MOVA & Dreame Mower app connects your robotic lawn mower to Homey via the official cloud API. Control mowing, manage zones and spots, adjust blade height, and automate everything with full flow card support.

Both MOVA and Dreame robots are supported across all cloud regions:

Brand Regions
MOVA Europe (EU), China (CN), North America (US), Asia (SG)
Dreame Europe (EU), China (CN), North America (US), Asia (SG)

:backhand_index_pointing_right: [Install from the Homey App Store] → TEST

:backhand_index_pointing_right: [Install from the Homey App Store] → LIVE
https://homey.app/en-ch/app/com.mova-dreame.mower/MOVA-&-Dreame-Mower/


:video_game: Device Card

The device card gives you direct control without opening the manufacturer app:

Button / Picker Description
Start Mowing Starts mowing using the selection in the Zone picker
Start Spot Mowing Starts mowing at the location selected in the Spot picker
Pause Pauses the mower in place
Stop Stops the current mowing session
Return to Dock Sends the mower back to the charging station
Go to Maintenance Point Drives the mower to its configured maintenance point
Zone picker Select Full Area, individual zones, edge mowing (full perimeter) or edge mowing for a single zone — populated automatically from your map
Spot picker Select a named spot — populated automatically from your map

Live sensors on the card: battery level, charging status, mower status, cutting height slider, mow efficiency picker, consumable life (blade / brush / robot), collision avoidance, firmware update indicator.


:gear: Device Settings

All settings are read from the mower on startup and written back immediately when changed:

Cutting Height & Mowing

  • Cutting height slider (mm) — min/max configurable per device
  • Mow efficiency — Standard or Efficient mode

Edge Mowing

  • Automatic edge mowing after main area
  • Safe edge mowing (keeps distance from boundary)
  • UltraTrim™ — shifts cutter disc outward on the last pass
  • Obstacle avoidance at edges

Obstacle Avoidance

  • LiDAR obstacle detection
  • Avoidance height threshold (5 / 10 / 15 / 20 cm)
  • Avoidance distance threshold (10 / 15 / 20 cm)
  • AI detection categories (Off / People / Animals / Objects / combinations)

Protection & Scheduling

  • Frost protection
  • Rain protection — sensitivity (1–3) and wait time in hours
  • Do Not Disturb — quiet window (mower stops and returns to dock if already mowing)
  • Low Speed at Night — time window to protect animals

Hardware

  • Battery — return-to-dock threshold, resume threshold, auto-resume after charging
  • Child lock
  • Volume (0–100)
  • Voice announcements — regular notification, work status, special status, errors
  • LED lighting — custom activation time window and per-scenario behaviour (standby, mowing, charging, error)
  • Anti-theft alarm — lift alarm, map-leave alarm, real-time location (Link module required)
  • AI obstacle photo capture

:repeat_button: Flow Cards

10 Triggers

Card Description
Mowing started Fires when the mower transitions to mowing
Mowing completed Fires when the mower returns home after mowing
Mower docked at station Fires when the mower docks or starts charging
Mower status changed Token: status
Charging status changed Token: status
Mower error occurred Tokens: error code, error description
Battery drops below X% Arg: threshold %; fires on each decrease below threshold
Consumable drops below X% Arg: threshold %; tokens: consumable type, remaining %
Firmware update available Fires when a new firmware version is detected
Obstacle detected by AI camera Fires once per obstacle after each session; tokens: photo, obstacle type

7 Conditions

Card Description
Mower is / is not mowing
Mower is / is not docked Docked, charging or charging completed
Mower is / is not charging
Mower has / has no error
Mowing mode is / is not Dropdown: All Area / Zone / Edge / Spot / Manual
Mow efficiency is / is not set to efficient
Battery is above / is below X% Arg: percentage

14 Actions

Card Description
Start mowing Full area
Start edge mowing Full perimeter edge mowing
Start zone mowing Comma-separated zone IDs
Start edge zone mowing Edge mow a specific zone
Start spot mowing Comma-separated spot IDs
Pause mowing
Stop mowing
Return to dock
Go to maintenance point
Find mower with audible alert
Clear error Clears a recoverable fault
Set mowing mode Dropdown: All Area / Zone / Edge / Spot / Manual
Set cutting height Number: mm
Set mow efficiency mode Dropdown: Standard / Efficient

:wrench: Setup

  1. Install the app from the Homey App Store
  2. Add a new device: Devices → + → MOVA & Dreame Mower
  3. Select your brand (MOVA or Dreame) and cloud region
  4. Enter the email address and password from your MOVA or Dreame smartphone app
  5. Select your mower from the list — done

:mobile_phone: Tested Devices

Device Model Status
MOVA LiDAX Ultra 1200 mova.mower.g2529d :white_check_mark: Fully tested
MOVA ViAX 300 mova.mower.g2420b :yellow_circle: Basic tests ok
Dreame A2 dreame.mower.g2422 :yellow_circle: Basic tests ok
Dreame A3 AWD Pro 3500 dreame.mower.g2541e :yellow_circle: Basic tests ok

Other MOVA and Dreame mowers using the same cloud API should work too. If you test a different model, let me know and I’ll add it here.


:robot: About this app

This app was developed with the help of Claude (Anthropic AI). All code, configuration and documentation were generated and iteratively refined through AI-assisted development.

The app is open source: :backhand_index_pointing_right: GitHub – com.mova-dreame.mower

If you find this app useful, I’d appreciate a coffee: :backhand_index_pointing_right: PayPal – Support development


:balloon: Feedback welcome!

I’d love to hear from you:

  • Does it work with your mower model?
  • Which features or settings are you missing?
  • Any bugs or unexpected behaviour?

Drop a comment below or open an issue on GitHub. :raising_hands:

Just ordered a Mova Viax 300.

Should be interesting testing it with this app​:+1:

Excellent @Andi - second highly anticipated app in just a few weeks, great contributions to the Homey community!

Quick update - installed but unable to add my mower while trying to add a device.. No issue using the Dreame app so account should be OK.

@micke_011 Could you please post the debug logs (copy them) from the settings menu of the app? Thank you

Meanwhile my MOVA 1200 is fully working.

Sorry @Andi for not reporting back, since 0.0.11 the issue is fixed, and in 0.0.14 all the settings and controls seem to accessible and be working as they should. Haven’t had to mow the lawn yet, so not sure about the all the features but will report back in as soon as its done and send in an debug log as well. Oh and I got the Dreame A2 just so you know.

Thanks for the feedback! I’m honestly a bit surprised that your Dreame A2 runs just as smoothly with the same settings as my MOVA LiDAX Ultra 1200.

If anything behaves oddly, just let me know — and feel free to share your debug logs from the app settings once your lawn is ready :grinning_face_with_smiling_eyes:

Added my new Mova Viax 300, but no status or battery updates.

Device log:

{
“code”: 0,
“success”: true,
“data”: {
“page”: {
“records”: [
{
“id”: “2052448325450797057”,
“did”: “-116992552”,
“model”: “mova.mower.g2420b”,
“subModel”: “mova.mower.g2420b”,
“ver”: “4.3.6_0375”,
“customName”: “PlenInge”,
“property”: “{“lwt”:1,“mac”:“10:06:48:A7:7C:A7”}”,
“mac”: “10:06:48:A7:7C:A7”,
“vendor”: “tx”,
“sn”: “G2420B61WEE01046A4”,
“master”: true,
“masterUid”: “DI844690”,
“masterUid2UUID”: null,
“masterName”: null,
“permissions”: “”,
“bindDomain”: “20000.mt.eu.iot.mova-tech.com:19974”,
“sharedTimes”: 0,
“sharedStatus”: 1,
“calltag”: null,
“updateTime”: “2026-05-07 20:21:24”,
“devBindTime”: 1778176788000,
“createTime”: 1778176788000,
“lang”: null,
“deviceInfo”: {
“productId”: “11095”,
“categoryPath”: “/lifeapps/mower”,
“model”: “mova.mower.g2420b”,
“submodel”: “mova.mower.g2420b”,
“remark”: “”,
“feature”: “video_tx”,
“videoDynamicVendor”: false,
“defaultVendors”: [
“tx”
],
“scType”: “BLE”,
“extendScType”: ,
“status”: “Live”,
“mainImage”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000002/ali_dreame/null/4b1b6ce5502cc2088f5b1d8ea710b66920250930054758.png”,
“smallImageUrl”: “”
},
“popup”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000002/ali_dreame/null/4b1b6ce5502cc2088f5b1d8ea710b66920250930054758.png”,
“smallImageUrl”: “”
},
“icon”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000002/ali_dreame/null/4b1b6ce5502cc2088f5b1d8ea710b66920250930054758.png”,
“smallImageUrl”: “”
},
“overlook”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000002/ali_dreame/null/4b1b6ce5502cc2088f5b1d8ea710b66920250930054758.png”,
“smallImageUrl”: “”
},
“images”: ,
“extensionId”: “1968”,
“updatedAt”: “1769487129316”,
“createdAt”: “1750059803470”,
“releaseAt”: “1769487129316”,
“quickConnectStatus”: 0,
“quickConnects”: {},
“permit”: “video”,
“firmwareDevelopType”: “SINGLE_PLATFORM”,
“bindType”: “strong”,
“displayName”: “ViAX 300”,
“liveKeyDefine”: {},
“qaKeyDefine”: {},
“pluginForceUpdate”: false
},
“online”: true,
“latestStatus”: 6,
“battery”: 100,
“videoStatus”: null,
“region”: null,
“featureCode”: -1,
“featureCode2”: -1,
“btnMode”: null,
“keyDefine”: {
“ver”: 14,
“url”: “https://oss.iot.dreame.tech/pub/device_status_multi_lang/000002/ali_dreame/6359309613a2e762b83b48a975e9ac2790c1c48e_mova.mower.g2420b_iotKeyValue_translate_14.json
},
“groupType”: null,
“groupName”: null,
“roomName”: null
}
],
“total”: “1”,
“size”: “100”,
“current”: “1”,
“orders”: ,
“optimizeCountSql”: true,
“hitCount”: false,
“searchCount”: true,
“pages”: “1”
}
},
“msg”: “操作成功”
}

@FinnKje
Could you please provide as well the Raw JSON from here?

Can not get any device up in here.

understand - could you please update to version 0.0.17 and test again if you’re able to add the mower?

There we go!

All status in place and updated!:+1:

Have you looked in to getting the camera push images transferred? While on patrol or when unrecognizable item is on the lawn?

:tada:

Not yet but added it as feature request. as soon as I have time to implement this I’ll update the issue on github: Camera Images when on patrol or when unrecognizable item is on the lawn · Issue #2 · andiwirz/com.mova-dreame.mower

@FinnKje
@micke_011
Could you please send me (via private message) your Raw JSON so I can compare it against my output - Thank you

first of all. THANK YOU for the app :grinning_face: .

I’ve just ordered a Dreame A3 pro 3500.

Connexion to Dreame account Ok

Raw API response : OK (1 device found)

but in Device poll “Select Device” is empty and seems to be unable to see my device.

@Razell
Please send me the JSON under discover devices.

Thank you

{
“code”: 0,
“success”: true,
“data”: {
“page”: {
“records”: [
{
“id”: “2052423882350645249”,
“did”: “-119442448”,
“model”: “dreame.mower.g2541e”,
“subModel”: “dreame.mower.g2541e”,
“ver”: “4.3.6_0407”,
“customName”: “Cetelem”,
“property”: “{"lwt":1,"mac":"10:06:48:A9:1B:5B"}”,
“mac”: “10:06:48:A9:1B:5B”,
“vendor”: “”,
“sn”: “G2541E642WE0021332”,
“master”: true,
“masterUid”: “HA715135”,
“masterUid2UUID”: null,
“masterName”: null,
“permissions”: “”,
“bindDomain”: “10000.mt.eu.iot.dreame.tech:19973”,
“sharedTimes”: 0,
“sharedStatus”: 1,
“calltag”: null,
“updateTime”: “2026-05-07 18:43:14”,
“devBindTime”: 1778170960000,
“createTime”: 1778170960000,
“lang”: null,
“deviceInfo”: {
“productId”: “11980”,
“categoryPath”: “/lifeapps/mower”,
“model”: “dreame.mower.g2541e”,
“submodel”: “dreame.mower.g2541e”,
“remark”: “”,
“feature”: “video_tx”,
“videoDynamicVendor”: false,
“defaultVendors”: ,
“scType”: “BLE”,
“extendScType”: [
“PINCODE”
],
“status”: “Live”,
“mainImage”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/null/d3710a639f2895fa7931b5ca72d2d59120260209063712.png”,
“smallImageUrl”: “”
},
“popup”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/null/d3710a639f2895fa7931b5ca72d2d59120260209063712.png”,
“smallImageUrl”: “”
},
“icon”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/null/d3710a639f2895fa7931b5ca72d2d59120260209063712.png”,
“smallImageUrl”: “”
},
“overlook”: {
“as”: “1”,
“caption”: “1”,
“height”: 0,
“width”: 0,
“imageUrl”: “https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/null/d3710a639f2895fa7931b5ca72d2d59120260209063712.png”,
“smallImageUrl”: “”
},
“images”: ,
“extensionId”: “2413”,
“updatedAt”: “1770967786189”,
“createdAt”: “1764299815394”,
“releaseAt”: “1770967786189”,
“quickConnectStatus”: -1,
“quickConnects”: {},
“permit”: “pincode,video,aiobs”,
“firmwareDevelopType”: “SINGLE_PLATFORM”,
“bindType”: “strong”,
“displayName”: “A3 AWD Pro 3500”,
“liveKeyDefine”: {},
“qaKeyDefine”: {},
“pluginForceUpdate”: false
},
“online”: true,
“latestStatus”: 13,
“battery”: 100,
“videoStatus”: null,
“region”: null,
“featureCode”: -1,
“featureCode2”: -1,
“btnMode”: null,
“keyDefine”: {
“ver”: 5,
“url”: “https://oss.iot.dreame.tech/pub/device_status_multi_lang/000000/ali_dreame/db6cb9479cee92dd08a4dc5f1fbcee8ee1553d42_dreame.mower.g2541e_iotKeyValue_translate_5.json
},
“groupType”: null,
“groupName”: null,
“roomName”: null
}
],
“total”: “1”,
“size”: “100”,
“current”: “1”,
“orders”: ,
“optimizeCountSql”: true,
“hitCount”: false,
“searchCount”: true,
“pages”: “1”
}
},
“msg”: “操作成功”
}

@Razell
Please update to version 0.0.36 and try to add the device again in Homey.

Getting an error when polling the device in app settings, possibly related to it being identified as an A1 rather than an A2? App version is 0.0.36

Edit: Did a debug device discovery, sent in pm @Andi

Same result unfortunally
Update done and debug device discovery is ok but not in debug installed device.
Select device is empty

@Razell
@micke_011
@FinnKje

Please update to Version 0.0.38 and try it again.

Changes:

v0.0.37 — Mow Spot / Zone picker recovery

  • Root cause: addCapability() failures during migrations are silently swallowed by .catch(), but setStoreValue(key, true) still runs — so a migration can be marked done even though mow_spot was never actually added to the device.
  • Added migration v23: re-adds mow_zone and mow_spot if either is absent, recovering any device that ended up without them.
  • Guarded registerCapabilityListener('mow_zone') and registerCapabilityListener('mow_spot') with hasCapability() checks so a device missing either picker can still complete onInit and benefit from the recovery migration.
  • Guarded getCapabilityOptions('mow_zone'/'mow_spot') in getDebugPollData() with hasCapability() checks, eliminating the “Poll failed: Invalid Capability: mow_spot” crash in the settings debug page.

v0.0.38 — Init crash fix + fresh-device migration fast-path

  • Root cause of “Cannot read properties of undefined (reading ‘getRawProperties’)”: instance fields (including this._api) were assigned after await this._migrate() in onInit(). If _migrate() threw for any reason, this._api stayed undefined and every subsequent call crashed.
  • Moved all instance field initialisations to the very top of onInit(), before _migrate() runs — this._api is null from the first line regardless of what happens next.
  • Added an early-exit guard in getDebugPollData(): if this._api is still null, the debug poll returns a clear “Device not initialised yet” message instead of a JS TypeError.
  • Fresh-device fast-path in _migrate(): for a newly paired device, all historic migration keys are stamped as done immediately — only the final recovery migration (v23) runs. This eliminates the dozens of redundant addCapability / removeCapability API calls that previously fired on every new device (capabilities added in v1–v17, then removed and re-added four times through reorder migrations v18–v22), which also reduces the chance of a transient failure leaving a capability missing.