openhab / openhab-addons

Add-ons for openHAB
https://www.openhab.org/
Eclipse Public License 2.0
1.9k stars 3.59k forks source link

[boschindego] Optimization of API calls #13182

Open jlaur opened 2 years ago

jlaur commented 2 years ago

In order to:

it would be beneficial to:

As an example, operating data is of most interest when the device is working or charging. Additionally, when this data is requested, the display on the device will turn on, i.e. the device will be woken up. On the other hand, only by performing this call will we actually reach the device, so if we would avoid calling it for several days, the device could have been stolen, and it would still appear online.

The state request: GET https://api.indego.iot.bosch-si.com/api/v1/alms/xxxxxxxx/state

has some parameters that might be of use:

The longpoll is particularly interesting as this could be a way to get faster updates with fewer calls, i.e. a kind of push mechanism. If this would be implemented as asynchronous HTTP calls using Jetty, that might be a significant improvement.

13158 recently improved update of next planned cutting time, but this could be further improved by separating last and next cutting times. This way one of the two calls could be eliminated in some cases. For example, when time of next planned cutting is hit, next planned cutting needs an update, but last cutting does not. This will only be updated after completing a session - which does not affect next cutting. The calls are inexpensive, but nevertheless.

Last, when making changes to .items files, all items will request REFRESH. Not only will this cause multiple calls, but worse than that, it will cause redundant calls as some channels are updated through the same API calls.

jlaur commented 2 years ago

I have now been able to verify that this request indeed does start position tracking: POST /api/v1/alms/xxxxxxx/requestPosition?count=10&interval=6

Also, longpoll mentioned above has been confirmed to work in the way that it doesn't return until state has changed. When it does, the response is a bit differently structured than usual:

{
    "state": 258,
    "map_update_available": false,
    "charge": 24,
    "operate": 30,
    "mapsvgcache_ts": 1659036798849,
    "svg_xPos": 408,
    "svg_yPos": 680
}
jlaur commented 2 years ago

@BillGOH - if you are interested, you can give latest version a try: https://ci.openhab.org/job/openHAB-Addons/lastSuccessfulBuild/artifact/bundles/org.openhab.binding.boschindego/target/org.openhab.binding.boschindego-3.4.0-SNAPSHOT.jar

It includes #13192 as well as #13179. The first of these has a significant fix for an issue that caused the mower to never go to sleep, and leaving the display turned on all the time.

BillGOH commented 2 years ago

@jlaur Thank you very much. I installed the new version and I will test it. I already saw that the display is on very often; however I was unsure whether it is a problem of the binding or the "normal" functioning of the indego.

BillGOH commented 2 years ago

Seems to work fine!

jlaur commented 2 years ago

Most of the findings were addressed in #13192, but what still remains:

jlaur commented 2 years ago

Small status update: I'm struggling with Jetty and longpoll. After five minutes of waiting for HTTP GET, an EOFException is thrown. What I have tried to far:

Example:

final QueuedThreadPool queuedThreadPool = createThreadPool(BINDING_ID, 5, 10, 3600);
httpClient.setExecutor(queuedThreadPool);
httpClient.setScheduler(new ScheduledExecutorScheduler(BINDING_ID + "-scheduler", false));
httpClient.start();

And yet:

org.openhab.binding.boschindego.internal.exceptions.IndegoException: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@dea133::DecryptedEndPoint@32d347{l=/192.168.0.236:39190,r=api.indego.iot.bosch-si.com/139.15.214.16:443,OPEN,fill=-,flush=-,to=303481/3660000}
    at org.openhab.binding.boschindego.internal.IndegoController.getRequest(IndegoController.java:312) ~[?:?]
    at org.openhab.binding.boschindego.internal.IndegoController.getRequestWithAuthentication(IndegoController.java:223) ~[?:?]
    at org.openhab.binding.boschindego.internal.IndegoController.getState(IndegoController.java:611) ~[?:?]
    at org.openhab.binding.boschindego.internal.handler.BoschIndegoHandler.longPollJob(BoschIndegoHandler.java:229) ~[?:?]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
    at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
    at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@dea133::DecryptedEndPoint@32d347{l=/192.168.0.236:39190,r=api.indego.iot.bosch-si.com/139.15.214.16:443,OPEN,fill=-,flush=-,to=303481/3660000}
    at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118) ~[?:?]
    at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:101) ~[?:?]
    at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:730) ~[?:?]
    at org.openhab.binding.boschindego.internal.IndegoController.sendRequest(IndegoController.java:571) ~[?:?]
    at org.openhab.binding.boschindego.internal.IndegoController.getRequest(IndegoController.java:265) ~[?:?]
    ... 9 more
Caused by: java.io.EOFException: HttpConnectionOverHTTP@dea133::DecryptedEndPoint@32d347{l=/192.168.0.236:39190,r=api.indego.iot.bosch-si.com/139.15.214.16:443,OPEN,fill=-,flush=-,to=303481/3660000}
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:385) ~[?:?]
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1620) ~[?:?]
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:269) ~[?:?]
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:185) ~[?:?]
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:80) ~[?:?]
    at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:131) ~[?:?]
    at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:172) ~[?:?]
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[?:?]
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[?:?]
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555) ~[?:?]
    at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410) ~[?:?]
    at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164) ~[?:?]
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[?:?]
    at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) ~[?:?]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) ~[?:?]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) ~[?:?]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) ~[?:?]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) ~[?:?]
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) ~[?:?]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) ~[?:?]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) ~[?:?]
    ... 1 more