Ambrogio lawn mover

Makes sense,

The app looks every inefficient a lot of redundant calls, the AppID and ThingID seems to be tied to the Login User then you list the thinkgs under the AppID/ ThingID.

Shame we can’t set up an account/ App ID for Home Assistant. However it seems it finds the Thing ID direct from the Mower using Bluetooth during setup.

I could use the AppToken then have the user log in to grab the AppID, after this just store the AppID and interact direct with the API on devicewise.

At least to try it.

2 Likes

So it would be possible to build an integration for the over air, but would have to use the API Key and Googe Login from the Mobile app to get the right keys to communicate with the mower.

However before I do anything I want to look at the bluetooth I am waiting for a bluetooth adapter for my dev machine so I can see what it is doing. If I can work that out then perhaps an ESP32 module with battery could be attached to the mower to allow HASS to Communicate by Wifi/ Bluetooth rather than use the mobile data which is limited per month.

Sounds interesting using Bluetooth, but then makes a dependency of this module to make it work.
FYI. As a test, ive been hitting their API’s every 30 mins for past 6 months and not hit any limits.
I’ve been polling location and state data.
Then occasionally send a mow, set profile or border cut command.

I think the mower talks back to devicewise constantly checking for updated instructions in a message queue and also posting its state, which is what comes back in the response from devicewise.
Only when we hit it via the live tracking api does it start polling the mower and using up data.

Good to know I will look at setting up a repo then for the connect API and for the HASS Integration.

I (almost) completely reverse engineered the API today: it’s not really secure, but that’s “good” for us.

I have gone through the whole process several times with fresh Android setups. Several tokens/keys remained the same, which is why I don’t blur them.

In the first step, we authenticate against the Google service with email address and password:

POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyCUGSbVrwZ3X7BHU6oiUSmdzQwx-QXypUI HTTP/1.1
Content-Type: application/json
X-Android-Package: it.centrosistemi.ambrogioremote
X-Android-Cert: 4753441615021C6147D5F0946A0DA83877EF3D41
Accept-Language: en-US
X-Client-Version: Android/Fallback/X21000008/FirebaseCore-Android
X-Firebase-GMPID: 1:373506005239:android:07fcd128132313f3
X-Firebase-Client: H4sIAAAAAAAAAKtWykhNLCpJSk0sKVayio7VUSpLLSrOzM9TslIyUqoFAFyivEQfAAAA
Content-Length: 84
User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86_64 Build/PSR1.180720.122)
Host: www.googleapis.com
Connection: Keep-Alive
Accept-Encoding: gzip

{"email":"<yourEmail>","password":"<yourPassword>","returnSecureToken":true}

We get an JSON formatted response with important tokens:

600
{
  "kind": "identitytoolkit#VerifyPasswordResponse",
  "localId": "<importantLocalId>",
  "email": "<yourEmail>",
  "displayName": "<yourUsername>",
  "idToken": "<tokenYouCanGetGoogleAccountInformation>",
  "registered": true,
  "refreshToken": "<someNotUsesToken>",
  "expiresIn": "3600"
}

In next steps we need only the “localId” for API requests. Now, we need our session ID for get information about our lawn mower:

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
content-type: application/json
content-length: 161
accept-encoding: gzip
user-agent: okhttp/4.9.0

{"auth":{"command":"api.authenticate","params":{"appToken":"DJMYYngGNEit40vA","appId":"<importantLocalId>","thingKey":"<importantLocalId>"}}}

The domain of the API endpoint was always the same regardless of my language setting. The correspondence with the Google API, not further mentioned here, did not return a country code.

The request brings us a SessionID. Unfortunately, we do not know when it expires:

{"auth":{"success":true,"params":{"orgKey":"ZUCCHETTICENTROSISTEMI","sessionId":"<importantSessionId>"}}}

In the next requests we need to include the SessionID as HTTP header.

Now a little Bluetooth magic happens. The IMEI of your lawn mower is determined.

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
sessionid: <importantSessionId>
content-type: application/json
accept-encoding: gzip
user-agent: okhttp/4.9.0

{"thing_find":{"command":"thing.list","params":{"show":["id","key","name","connected","lastSeen","lastCommunication","loc","properties","alarms","attrs","createdOn","storage","varBillingPlanCode"],"keys":["<imeiOfYourMover>"],"hideFields":true}}}

You will get back all requested parameters.

Next, I will try to determine the control commands.

2 Likes

Now I have prepared the commands to control the lawn mower. Time indications are given in local time. The numeric representation of the day of the week is 0 (for Sunday) through 6 (for Saturday).

Set profile 1 to 3:

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
sessionid: <importantSessionId>
content-type: application/json
accept-encoding: gzip
user-agent: okhttp/4.9.0

{
	"cmd": {
		"command": "method.exec",
		"params": {
			"ackTimeout": 30,
			"imei": "<imeiOfYourMover>",
			"method": "set_profile",
			"params": {
				"profile": <profileNo>
			},
			"singleton": true
		}
	}
}

Also, the “mow up” command. The zone in which the lawn mower should start can be specified. Note that the Area ID in request is one number lower than the zone number. So zone 1 of your robot is area 0, zone 2 is area 1 and so on:

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
sessionid: <importantSessionId>
content-type: application/json
accept-encoding: gzip
user-agent: okhttp/4.9.0

{
	"cmd": {
		"command": "method.exec",
		"params": {
			"ackTimeout": 30,
			"imei": "<imeiOfYourMover>",
			"method": "work_until",
			"params": {
				"area": <startArea>,
				"hh": <hourLocalTime>,
				"mm": <minuteLocalTime>
			},
			"singleton": true
		}
	}
}

The command to start border mowing:

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
sessionid: <importantSessionId>
content-type: application/json
accept-encoding: gzip
user-agent: okhttp/4.9.0

{
	"cmd": {
		"command": "method.exec",
		"params": {
			"ackTimeout": 30,
			"imei": "<imeiOfYourMover>",
			"method": "border_cut",
			"singleton": true
		}
	}
}

And the command to send the lawn mower to the charging station:

POST https://api-de.devicewise.com/api HTTP/2.0
accept: application/json
sessionid: <importantSessionId>
content-type: application/json
accept-encoding: gzip
user-agent: okhttp/4.9.0

{
	"cmd": {
		"command": "method.exec",
		"params": {
			"ackTimeout": 30,
			"imei": "<imeiOfYourMover>",
			"method": "charge_until",
			"params": {
				"hh": <hourLocalTime>,
				"mm": <minuteLocalTime>
				"weekday": <dayOfWeek>
			},
			"singleton": true
		}
	}
}
1 Like

I have started to write an integration. This will be my first python and HA app (but i’m developing software since 2000). it will probably take some time. Help is welcome - I already have all API calls and flows figured out.

Great, looking forward to test it :slight_smile:
But I’m not able to install it via HACS, perhaps it’s not available yet -

Will try lather-

Hi, I think You haven’t pushed any code from local repo :slight_smile: ha-zcs-mower/custom_components/zcs-mower at main · ufozone/ha-zcs-mower · GitHub
I will try to help, have Wiper ZCS and application is really trashy :slight_smile:

Hope it will be possible to use HACS, I think HACS is the way most people are using, just tried again - but bot available yet.

There will not be a usable version so soon. I have to learn python first and the peculiarities of developing a HA integration.

Short note: I don’t develop my integration further for the moment - I don’t know enough about python and the Home Assistant integration. But under the following URL an excellent integration is created:

So far there is already a super config flow. The deviceWISE API is not yet connected. I try to support the developer with this. I have rewritten the official Telit python library for Home Assistant:

In my repository fork have connected the API and now I get the status of my mower:
grafik

Feel free to test:

It is not an integration that should be used in production!!

First of all thanks to all, great job!

  1. One note for iOS users, localId from app configuration screen is all uppercase while authentication is case sensitive, I had to register a new robot_client with a new google account to get a functional localId, than when getting thing_find I’ve been able to retrive already registered mails with their respective localId and I realised they were matching the ones shown on the app but not all uppercase; with proper case I’ve been able to authenticate even with them.
  2. I’ve a remaining problem to solve: everything work smoothly when the mower is in online status, it gets commands and execute them, but normally the mower is not online and I’ve not found a way to get it online yet, but opening the app and issuing a command, i.e. to locate the mower.
    Hereafter an example:
payload = {
...         "cmd": {
...                 "command": "method.exec",
...                 "params": {
...                         "ackTimeout": 30,
...                         "imei": imeiOfMover,
...                         "method": "border_cut",
...                         "singleton": "true"
...                 }
...         }
>>> r=requests.post(url, headers=headers, json=payload)
>>> r.json()
{'cmd': {'success': False, 'errorMessages': ['Device not connected.'], 'errorCodes': [-94108]}}

When robot is not online I notice thing_find returns connection_state with state:0
In fact even in the app as soon as I try to give a command 99% of the time I’m prompted with a popup message saying “Warning I’m connecting to your robot. Please wait”, but then after a while it connects and once connected through the app thing_find returns connection_state with state:1
Once connected if I post the command it’s executed correctly through the api returning:
{‘cmd’: {‘success’: True}}
Any idea on how to get the mower online through the api?
Thanks!
Best Regards
Pietro

This is easy: you have to wake him up :slight_smile:

{
    "cmd": {
        "command": "sms.send",
        "params": {
            "coding": "SEVEN_BIT",
            "imei": imeiOfMover,
            "message": "UP"
        }
    }
}

Thanks!!! It works!!!

I can offer a first usable version:

You can add the repository to your “custom repositories” in HACS:
grafik

1 Like

Hi community,

to help us with the development, we would appreciate the following information from you / your robotic lawn mowers:

  • Model, e.g. Ambrogio L35 Deluxe
  • The first six characters of the serial number, e.g. AM035L
  • Which commands are available in mobile app when you are not connected via Bluetooth, e.g. “mow until”, “charge until”, “border cutting”…

This helps us to define the supported features and to create a reasonable mapping so that we get the best possible compatibility between integration and numerous robot models.

  • Ambrogio Twenty Elite
  • AM020L
  • Charge Until, Work Until, Border Cut, Keep out (don’t know what it is)
1 Like