konqi / roborock-bridge

Bridge between a local mqtt broker and your roborock vaccuum through the vendor apis
MIT License
4 stars 1 forks source link

unrecognized property "auto_dry" with QRevo MaxV #54

Open birnbeidla opened 1 month ago

birnbeidla commented 1 month ago

crashing exception:

Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "auto_dry" (class de.konqi.roborockbridge.remote.rest.dto.user.ParamsForSegmentedCleanup), not marked as ignorable (9 known properties: "mop_mode", "fan_power", "clean_order_mode", "repeat", "segs", "water_box_mode", "mop_template_id", "map_flag", "tid"])
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: de.konqi.roborockbridge.remote.rest.dto.user.UserSceneParam["action"]->de.konqi.roborockbridge.remote.rest.dto.user.UserSceneAction["items"]->java.util.ArrayList[0]->de.konqi.roborockbridge.remote.rest.dto.user.UserSceneParamActionItem["param"]->de.konqi.roborockbridge.remote.rest.dto.user.DifferentiatingCleanupParams["data"]->java.util.ArrayList[0]->de.konqi.roborockbridge.remote.rest.dto.user.ParamsForSegmentedCleanup["auto_dry"])
        at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1138) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2224) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1709) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1687) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:284) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:463) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:359) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:439) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4801) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2999) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at de.konqi.roborockbridge.remote.rest.dto.user.ActionItemParamDeserializer.deserialize(UserScenes.kt:169) ~[classes!/:0.0.6-SNAPSHOT]
        at de.konqi.roborockbridge.remote.rest.dto.user.ActionItemParamDeserializer.deserialize(UserScenes.kt:48) ~[classes!/:0.0.6-SNAPSHOT]
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:439) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:359) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:439) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:439) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4825) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3772) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3740) ~[jackson-databind-2.15.3.jar!/:2.15.3]
        at de.konqi.roborockbridge.utility.NestedJsonDeserializer.convert(NestedJsonDeserializer.kt:11) ~[classes!/:0.0.6-SNAPSHOT]
        ... 60 common frames omitted
birnbeidla commented 1 month ago

Played around a bit with your code and found out that there are several other missing properties once you add "auto_dry"...

This is what I added to get the service up and running:


ExtendedCleanupParams:

@get:JsonProperty("auto_dry")
val autoDry: Boolean,

@get:JsonProperty("auto_dustCollection")
val autoDustCollection: Boolean,

@get:JsonProperty("region_num")
val regionNum: Int

UserSceneParam:

val tagId: String

Once I did that, i was able to get status information about my QRevo Max and was also able to start a routine. Once the routing starts, the service crashes again with the following exception:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.konqi.roborockbridge.persistence.entity.Routine.triggeredDeviceIds: could not initialize proxy - no Session at org.hibernate.collection.spi.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:634) ~[hibernate-core-6.4.4.Final.jar!/:6.4.4.Final] at org.hibernate.collection.spi.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217) ~[hibernate-core-6.4.4.Final.jar!/:6.4.4.Final] at org.hibernate.collection.spi.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:613) ~[hibernate-core-6.4.4.Final.jar!/:6.4.4.Final] at org.hibernate.collection.spi.AbstractPersistentCollection.read(AbstractPersistentCollection.java:136) ~[hibernate-core-6.4.4.Final.jar!/:6.4.4.Final] at org.hibernate.collection.spi.PersistentSet.iterator(PersistentSet.java:169) ~[hibernate-core-6.4.4.Final.jar!/:6.4.4.Final] at de.konqi.roborockbridge.BridgeService.bridgeMqttProcessingLoop$lambda$16(BridgeService.kt:442) ~[!/:0.0.6-SNAPSHOT] at de.konqi.roborockbridge.BridgeService.bridgeMqttProcessingLoop$lambda$17(BridgeService.kt:295) ~[!/:0.0.6-SNAPSHOT] at java.base/java.util.Optional.ifPresent(Optional.java:178) ~[na:na] at de.konqi.roborockbridge.BridgeService.bridgeMqttProcessingLoop(BridgeService.kt:295) ~[!/:0.0.6-SNAPSHOT] at de.konqi.roborockbridge.BridgeService.worker(BridgeService.kt:130) ~[!/:0.0.6-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:365) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:237) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:168) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:451) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:384) ~[spring-context-6.1.6.jar!/:6.1.6] at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:109) ~[spring-boot-3.2.5.jar!/:3.2.5] at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:80) ~[spring-boot-3.2.5.jar!/:3.2.5] at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na] at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.2.5.jar!/:3.2.5] at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.2.5.jar!/:3.2.5] at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:80) ~[spring-boot-3.2.5.jar!/:3.2.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:348) ~[spring-boot-3.2.5.jar!/:3.2.5] at de.konqi.roborockbridge.RoborockBridgeApplicationKt.main(RoborockBridgeApplication.kt:38) ~[!/:0.0.6-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[roborock-bridge-0.0.6-SNAPSHOT.jar:0.0.6-SNAPSHOT] at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[roborock-bridge-0.0.6-SNAPSHOT.jar:0.0.6-SNAPSHOT] at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[roborock-bridge-0.0.6-SNAPSHOT.jar:0.0.6-SNAPSHOT]

konqi commented 3 weeks ago

Let's see:

First things first: Please make sure that you start a routine that is first published via mqtt to your broker. From here on there are a couple of ways to dig deeper into the issue if you are willing to do so and you have the technical expertise.

birnbeidla commented 3 weeks ago

I don't use the webUI, I only care about the bridge functionality. I started the routine by handcrafted publish via OpenHAB mqtt binding.

Race may be possible. I run the service from an endless loop in a shell script so it automatically recovers if there are random crashes (which are quite a few) It might be possible (although very unlikely) that my OpenHAB scheduler triggers a cleaning routing the moment the service is restarting after a crash.

I can try to help debugging the service a bit any try to perform the actions you requested. Although, it might take some time so I can get familiar with the architecture and kotlin itself (I'm more of a .NET guy...) IMHO, the first goal should be to make the service more robust against unknown properties and schema errors. Perhaps ignore unknown properties or mirror them to mqtt in a generic way. Also the service should not crash on invalid messages, invalid devices or connection issues.

konqi commented 3 weeks ago

Feel free to open pull requests for any of the things you think are important or necessary. I will gladly review them.

konqi commented 3 weeks ago

Version 0.0.7 ignores extra properties but also outputs them in the log so that new properties can be identified. As for the random crashes, I don't have sufficient data to determine the cause, yet. Since I don't have the same type of robot I simply cannot create the required tests. If you want this service to support your type of robot you can:

If you live in the greater Stuttgart (D) area we can do the work together and you can bring along (and also take home) your robot. A good place & time would be here. Ping me if you're interested.

Michl7 commented 3 weeks ago

I don't use the webUI, I only care about the bridge functionality. I started the routine by handcrafted publish via OpenHAB mqtt binding.

Race may be possible. I run the service from an endless loop in a shell script so it automatically recovers if there are random crashes (which are quite a few) It might be possible (although very unlikely) that my OpenHAB scheduler triggers a cleaning routing the moment the service is restarting after a crash.

I can try to help debugging the service a bit any try to perform the actions you requested. Although, it might take some time so I can get familiar with the architecture and kotlin itself (I'm more of a .NET guy...) IMHO, the first goal should be to make the service more robust against unknown properties and schema errors. Perhaps ignore unknown properties or mirror them to mqtt in a generic way. Also the service should not crash on invalid messages, invalid devices or connection issues.

how does your handcrafted publish look? i try the same and didn't get anything to work. I only get initial data of the robot by MQTT. but with commands i am stuck.