Worx Landroid Binding

Hi all,

I implemented a binding for Landroid mowers (without the need to use the landroid-bridge).

Current README with documentation and examples for Things, Items and Sitemap can be found here:
https://github.com/nibi79/worxlandroid/blob/master/README.md

You can find the newest version of the Worx Landroid Binding here:
https://github.com/nibi79/worxlandroid/releases/

Download the jar from the release page and copy the file to your addons directory. In case you want to upgrade the binding to a newer version, please check the release notes first.

If you encounter any issues with the bindng, please enable trace log in Karaf console

log:set DEBUG org.openhab.binding.worxlandroid

and post the trace log here or send me the log via PM.
! take care that there is no private data (email
) in the log before posting !

Your feedback is appreciated! !
regards

Versions
2020-03-24 - v0.1
2020-03-29 - v0.2
2020-04-12 - v1.0
2020-07-08 - v2.0
2020-09-03 - v2.1
2020-12-03 - v3.0

34 Likes

Thanks. Is it supposed to work with older models ? I have a WG.797E1 and do not use the bridge so far, don’t even have an account.

hi Markus,

I really don’t know which models are supported. But what you definitely need is a Landroid account.
The binding connects to the landroid account and retrieve all information (token, certificate, name of the mqtt broker and names of the in/out topic for the mower) needed to connect and subscribe to the AWS mqtt broker (Amazon). Are you not be able to control your mower with the official landroid app?

The api offers a http request to get product items, perhaps these are the supported mowers. This is the response of the query:
https://github.com/nibi79/worxlandroid/blob/master/doc/products.json

So your mower is listed:

{
	"id": 19,
	"product_family_id": 3,
	"default_name": "Landroid L",
	"code": "WG797E.1",
	"product_year": 2016,
	"features": {
		"unrestricted_mowing_time": true,
		"multi_zone": true,
		"wifi_connection": "manual_display",
		"display_type": "lcd",
		"pin": true,
		"rain_delay": true,
		"chassis": "l_2016"
	},
	"board_id": 2,
	"meters": 2000,
	"iot_enabled": true,
	"registration_enabled": true,
	"mowing_runtime": 60,
	"charge_time": 120,
	"mow_speed": 0.41887902,
	"wire_speed": 0.293215314,
	"cutting_width": 220,
	"region": "eu",
	"accessories": null,
	"maximum_weekly_scheduled_time": 5550,
	"onboard_accessories": null,
	"created_at": "2017-03-13 19:25:50",
	"updated_at": "2020-03-12 00:00:56"
},

No. It works with the previous-gen app (which was current by the time I got my Landroid) which was working locally only. I had sniffed that protocol (it’s just HTTP) and use HTTP commands to control my Landroid.
But the current app just does not find my mower, and it’s even too intelligent to allow the user to enter the mower’s IP manually.

Thanks for your effort in writing this binding. It works intuitive and really well, good job! Thank you so much!

1 Like

I have installed this binding, i used the THINGS and ITEMS text file examples from Github, it took me less than 30min to have a working solution.
Last year my mower was connected via the Landroid brigde software, this worked perfectly but was more complicated to install and configure.

1 Like

My Landroid S still in the garage. The installation went well after configuring the bridge the Landroid S appeared in the Inbox.
I had my landroid bridge running in a docker container. This solution for sure better.
Thanks in advance.
My feedback will be in few weeks.

1 Like

The Binding is running with the Landroid S Offline (still in the garage).
I got this error in the log this morning:

2020-03-27 07:10:00.046 [ERROR] [id.internal.WorxLandroidMowerHandler] - RefreshStatusRunnable 2018301909020029945B: Unknown error

org.openhab.binding.worxlandroid.internal.webapi.WebApiException: java.io.EOFException: HttpConnectionOverHTTP@a4ec0f::DecryptedEndPoint@10a98b2{api.worxlandroid.com/34.248.123.187:443<->/192.168.3.145:49524,OPEN,fill=-,flush=W,to=60021/0}

	at org.openhab.binding.worxlandroid.internal.webapi.request.WebApiRequest.callWebApi(WebApiRequest.java:122) ~[bundleFile:?]

	at org.openhab.binding.worxlandroid.internal.webapi.request.WebApiRequest.callWebApiGet(WebApiRequest.java:79) ~[bundleFile:?]

	at org.openhab.binding.worxlandroid.internal.webapi.request.ProductItemsRequest.call(ProductItemsRequest.java:46) ~[bundleFile:?]

	at org.openhab.binding.worxlandroid.internal.webapi.WorxLandroidWebApiImpl.retrieveUserDevices(WorxLandroidWebApiImpl.java:101) ~[bundleFile:?]

	at org.openhab.binding.worxlandroid.internal.WorxLandroidMowerHandler$1.run(WorxLandroidMowerHandler.java:102) [bundleFile:?]

	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_232]

	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:1.8.0_232]

	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_232]

	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:1.8.0_232]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_232]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_232]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232]

Caused by: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@a4ec0f::DecryptedEndPoint@10a98b2{api.worxlandroid.com/34.248.123.187:443<->/192.168.3.145:49524,OPEN,fill=-,flush=W,to=60021/0}

	at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118) ~[bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:101) ~[bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:685) ~[bundleFile:9.4.20.v20190813]

	at org.openhab.binding.worxlandroid.internal.webapi.request.WebApiRequest.callWebApi(WebApiRequest.java:92) ~[bundleFile:?]

	... 11 more

Caused by: java.io.EOFException: HttpConnectionOverHTTP@a4ec0f::DecryptedEndPoint@10a98b2{api.worxlandroid.com/34.248.123.187:443<->/192.168.3.145:49524,OPEN,fill=-,flush=W,to=60021/0}

	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:335) ~[?:?]

	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1526) ~[?:?]

	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:209) ~[?:?]

	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:147) ~[?:?]

	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) ~[?:?]

	at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) ~[?:?]

	at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:154) ~[?:?]

	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[?:?]

	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?]

	at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:426) ~[?:?]

	at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:320) ~[?:?]

	at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:158) ~[?:?]

	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?]

	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) ~[?:?]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) ~[?:?]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) ~[?:?]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) ~[?:?]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ~[?:?]

	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) ~[?:?]

	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) ~[?:?]

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) ~[?:?]

	... 1 more

Did you get error once or permanently? Is the Bridge online at the moment? Can you restart oh and check the log again. Perhaps it was a temporary HTTP problem.

I just witnessed once, not repeating, though should not throw an exception.

Thanks a lot

I’ve been waiting for this binding since new API version of worx. The landroid bridge was always having lots of problem on my raspberry and I didn’t use it anymore.

I just install the binding and everything goes well for the moment:

  • Installation with Karaf Console
  • Restart OpenHab
  • Add API Things and use discovery to add my mower
  • Copy/Paste all provinding items and sitemaps

Perfect !

1 Like

Hi everybody!
Thank you for that wonderful binding which solves many problems with the prevoius used bridge. But I do also have a problem, my Mower does not accept the commands, but it has also a problem with the Worx Android App:

2020-03-28 12:29:33.558 [vent.ItemStateChangedEvent] - Landroid_Status_dateTimeS changed from 2020-03-28T12:28:33.232+0100 to 2020-03-28T12:29:33.557+0100
2020-03-28 12:29:57.685 [ome.event.ItemCommandEvent] - Item 'Landroid_Command' received command START
2020-03-28 12:29:57.686 [nt.ItemStatePredictedEvent] - Landroid_Command predicted to become START
2020-03-28 12:29:57.688 [vent.ItemStateChangedEvent] - Landroid_Command changed from 1970-01-01T00:00:00.000+0000 to START
2020-03-28 12:33:24.846 [DEBUG] [d.internal.WorxLandroidBridgeHandler] - publish topic -> DB510/F0FE6B831BC2/commandIn
2020-03-28 12:33:24.847 [DEBUG] [d.internal.WorxLandroidBridgeHandler] - publish message -> {}
2020-03-28 12:33:24.851 [INFO ] [orxlandroid.internal.mqtt.AWSMessage] - onSuccess
2020-03-28 12:33:25.297 [INFO ] [.worxlandroid.internal.mqtt.AWSTopic] - onMessage: {"cfg":{"id":1,"lg":"it","tm":"12:34:27","dt":"28/03/2020","sc":{"m":1,"p":0,"d":[["00:00",0,0],["11:00",300,1],["11:00",300,1],["11:00",300,1],["11:00",300,1],["11:00",300,1],["11:00",300,1]]},"cmd":0,"mz":[0,0,0,0],"mzv":[0,0,0,0,0,0,0,0,0,0],"rd":0,"sn":"201830190902001711FE"},"dat":{"mac":"F0FE6B831BC2","fw":3.52,"bt":{"t":27.2,"v":20.25,"p":94,"nr":1385,"c":1,"m":0},"dmp":[-1.1,-0.5,345.8],"st":{"b":33231,"d":559051,"wt":34700},"ls":1,"le":0,"lz":0,"rsi":-66,"lk":1}}
2020-03-28 12:33:25.299 [INFO ] [id.internal.WorxLandroidMowerHandler] - HOME | StatusCode: 1 - Home

==> /var/log/openhab2/events.log <==

2020-03-28 12:33:25.305 [vent.ItemStateChangedEvent] - Landroid_Command changed from START to 1970-01-01T00:00:00.000+0000

==> /var/log/openhab2/openhab.log <==

2020-03-28 12:33:25.308 [INFO ] [id.internal.WorxLandroidMowerHandler] - NO_ERROR | ErrorCode: 0 - No error
2020-03-28 12:33:35.388 [DEBUG] [nternal.webapi.request.WebApiRequest] - URI: https://api.worxlandroid.com/api/v2/product-items
2020-03-28 12:33:35.658 [DEBUG] [nternal.webapi.request.WebApiRequest] - Worx Landroid WebApi Response: [{"id":239984,"product_id":37,"user_id":77143,"serial_number":"xxxxx","mac_address":"xxxxx","name":"Robby","setup_location":{"latitude":xxxx,"longitude"xxxx},"locked":true,"firmware_version":3.52,"firmware_auto_upgrade":false,"distance_covered":558302,"mower_work_time":34654,"blade_work_time":33187,"battery_charge_cycles":1385,"messages_in":630,"messages_out":28925,"push_notifications":true,"city":{"id":2887175,"country_id":276,"name":"xxxx","latitude":xxxx,"longitude":xxxx,"created_at":"2018-02-15 22:23:54","updated_at":"2018-02-15 22:23:54"},"sim":null,"push_notifications_level":"notice","lawn_size":0,"lawn_perimeter":null,"raw_messages_in":34393,"raw_messages_out":28925,"test":0,"iot_registered":true,"warranty_registered":true,"pin_code":null,"time_zone":"Europe\/Berlin","purchased_at":"2018-06-02 00:00:00","warranty_expires_at":"2020-06-02 00:00:00","registered_at":"2018-07-09 00:00:00","online":true,"app_settings":null,"accessories":null,"features":{"unrestricted_mowing_time":true,"multi_zone":true,"wifi_connection":"smartlink_no_display","display_type":"led","lock":true,"rain_delay":true,"chassis":"s_2017","mqtt":true,"wifi_pairing":"smartlink","tracking_firmware":true,"provisoning_replaceable":true},"auto_schedule_settings":null,"auto_schedule":false,"pending_radio_link_validation":null,"mqtt_topics":{"command_in":"DB510\/F0FE6B831BC2\/commandIn","command_out":"DB510\/F0FE6B831BC2\/commandOut"},"created_at":"2018-06-22 15:25:57","updated_at":"2020-03-28 01:12:04"}]

==> /var/log/openhab2/events.log <==

2020-03-28 12:33:35.659 [vent.ItemStateChangedEvent] - Landroid_Status_dateTimeS changed from 2020-03-28T12:32:35.388+0100 to 2020-03-28T12:33:35.659+0100

To me, it seems like the channel is bound to wrong information, or is there a problem with my configuration?
landroid.items:

DateTime Landroid_Status_dateTimeS "Letztes Update [%1$td.%1$tm.%1$ty %1$tH:%1$tM:%1$tS]" <kalender>  {channel="worxlandroid:mower:99e526be:201830190902001711FE:common#lastUpdateOnlineStatus"}
String Landroid_Command "Befehl [%s]" <movecontrol> {channel="worxlandroid:mower:99e526be:201830190902001711FE:cfgCommon#command"}

landroid.sitemap:

Default item=Landroid_Status_dateTimeS
Switch item=Landroid_Command mappings=[START="Start",STOP="Stop",HOME="Go Home"]

Hi Stefan,

your channel is wrong:

String Landroid_Command "Befehl [%s]" <movecontrol> {channel="worxlandroid:mower:99e526be:201830190902001711FE:cfgCommon#command"}

to control the mower you need ‘common#action’

String Landroid_Command "Befehl [%s]" <movecontrol> {channel="worxlandroid:mower:99e526be:201830190902001711FE:common#action"}
1 Like

Hi Nils!

This is a great binding! I was waiting for this for a long time as the landroid bridge was not working stable for me! Great job, thanks a lot!

One question:
What are the commands that can be transmitted via “common#action” channel?
I could not find any info about this. I remember it was documented somewhere in the API.

Thanks in advance!

1 Like

you are right!

These are the commands you can use for “common#action” channel:

  • START
  • STOP
  • HOME

I just added the info to the README.

Hi
 Is it possible to add a command that forces the mower to a specific zone?

Regards Mads

There are some options regarding zones but I don’t know exactly which one yet.
I’ll take a look at that.

I’ve just seen that @INT5749 created an issue regarding zones: https://github.com/nibi79/worxlandroid/issues/5

Hi,

ja, und Enhencement trifft es gut :wink: Braucht man nicht hĂ€ufig, aber ich finde die Lösung der Desktop App klasse, da können die Zonen direkt geschrieben werden, ohne die mĂŒhsam immer wieder abzufahren. Hat mir geholfen Shaun an der richtigen stelle vom Kabel ins Feld zu schicken.

VG

Hi Mads,

there is no specific command, mower always start with next zone.
e.g. if you have 3 Zones which are all in scope it will be
1
2
3
1
2
etc

I’m not aware how to send mower to start with a specific zone