TheAgentK / tuya-mqtt

Nodejs-Script to combine tuyaapi and openhab via mqtt
MIT License
173 stars 81 forks source link

"parse data error" when requesting /state before 1st command #42

Closed Flip76 closed 3 years ago

Flip76 commented 3 years ago

I did some tracing as sometimes everything works fine and sometimes it doesn't work at all. First of all I realized that when using protocol version 3.3 the state-response will be on the non "ver3.3"-topic.

mosquitto_pub -t tuya/ver3.3/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/command -m "ON"

updates this topic:

tuya/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/state

Ok, so as a workaround I tried to use tuya/ver3.3 for commands and tuya/ as state topic. With this config I had a 50/50 chance to work :-) I restarted tuya-mqtt and tried:

mosquitto_pub -t tuya/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/state -n

Result:

  TuyAPI Parsed: +13ms
  TuyAPI {
  TuyAPI   payload: 'parse data error',
  TuyAPI   leftover: false,
  TuyAPI   commandByte: 10,
  TuyAPI   sequenceN: 1
  TuyAPI } +

Next try: Restart tuya-mqtt and send:

mosquitto_pub -t tuya/ver3.3/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/command -m "ON"

Result: No parse data error => everything works fine! Now I can even query the state-topic and the result is ok:

TuyAPI:mqtt receive settings {"topic":"tuya/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/state","action":"state","message":"","options":{"id":"bf0751f4b74d39cXXXXXXX","key":"eacb979dbXXXXXXX","ip":"192.168.103.14"}} +11ms

I did many other tests but the result is always the same: If you don't send a valid (ver3.3) command after starting tuya-mqtt, you will receive parse-errors for any following command. Even if you send a command to non "ver3.3" first, you will hit the same problem. Instead: If you send a valid command first, you can do whatever you want and everything works like a charme...

tsightler commented 3 years ago

As far as I can tell, everything you describe is expected behavior based on the current way the code works.

mosquitto_pub -t tuya/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/state -n

State topics don't support MQTT publish, only subscribe, so, whatever you get from publishing to this topic is pretty much always undefined. If you want to see state updates you should subscribe to the state topic:

mosquitto_sub -t tuya/bf0751f4b74d39cXXXXXXX/eacb979dbXXXXXXX/192.168.103.14/state

Once you subscribe to the state topic any state changes (manual switch events, changes through the app, or published changes through MQTT command topic) will be reflected here.

All publish commands should be sent through the appropriate command topic (simple text command via command topic, or raw Tuya style JSON via DPS topic) and you must specify the protocol version for initial connection or use the auto discovery feature, which can typically automatically determine the protocol . You can publish the "schema" command to the command topic (see documentation) to have the device send the current state, although this only works on some devices.

I definitely agree that using a different base topic for command vs state (i.e. not having /ver3.3/ in the state topic when it is specified in the command topic) is somewhat confusing, but it's unlikely to change at this point as, once I release ver 3.0 (currently in dev tree, but under heavy refactor) the legacy topic based configuration will be going away and never return.

Flip76 commented 3 years ago

Thanks for the detailed information - much appreciated! My problem is that OpenHAB mqtt broker subscribes to the state topic before a command has been published and this leads to "parse data error"... Only if I restart tuya-mqtt and publish a command quick enough, everything is ok - but honestly this doesn't sound like a solution right? Is there any way to "persist" the protocol setting per device or to publish a initial command?

tsightler commented 3 years ago

There should be no issue with subscribing to a topic, that should be totally fine as the script isn't even aware when topics are subscribed (standard MQTT). There are a couple of ways to handle device persistence during startup. You can set "retain" in the config to true. This will cause the publish topics to stay in the MQTT broker and, each time tuya-mqtt starts, it will find them and attempt connecting. In the past the script actually used retain by default, but it caused a lot of confusion as you had to manually publish a null packet using mosquitto or some other tool to delete devices, but it's still there, just have to add "retain": true to the config file.

However, what most people seem to do, including myself, is just to create a small script which starts tuya-mqtt and then immediately uses mosquitto_pub to send the "{ \"schema\": true }" command as the message, which causes the devices to connect and update state (hopefully).

Based on exactly what you are attempting to accomplish, you may already find the 3.0 version to be easier to use. Instead of using a topic based config, you simply use the output of tuya-cli wizard (or manually create) a simple JSON config file with the ID/key/friendly name of the device (and alternatively the IP address/protocol, etc). It then uses this to connect to the devices. You can then get/set each DPS topic value, or use JSON.

The end goal is to automatically support most devices with a simple config file as the source, but right now it mostly only works with simple switches/sockets and dimmers. I'm hoping to have it mostly functional in the next couple of weeks, but if your use cases is simple switches, it may already be easier.

tsightler commented 3 years ago

BTW, there's also the possibility that OpenHAB published a prior state with retain and that's why the script fails on startup as, in general, subscribing should be no issues. I'd use a tool like MQTT Explorer and clean out the tuya/ tree.

Flip76 commented 3 years ago

Thanks again! Yes, I am using MQTT Explorer too for the debugging. So version 3.0 sounds the way to go for me as I only have sockets and 2 powerstrips (but I guess this works as it's just a different dps right?). With all my other devices I already moved away from Tuya.

Meanwhile I will try to modify the startup rule to send the "{ \"schema\": true }" command...

tsightler commented 3 years ago

Indeed, 3.0 might be easier, although it is admittedly in a state of flux at the moment, I don't expect the core capability around DPS support to change. You can read the state of any device via dps/<#>/state and send simples command via dps/<#>/command topics.

tsightler commented 3 years ago

Also, because it is in active development, it will be easier for me to make any changes that might be required to make it more "OpenHAB" friendly, although I believe that for the most part it should just work.

Flip76 commented 3 years ago

That sound perfect for my needs! Then I will have an eye on #41 and will give it a try. Thank you so much for your time spent and your help!

Flip76 commented 3 years ago

Also, because it is in active development, it will be easier for me to make any changes that might be required to make it more "OpenHAB" friendly, although I believe that for the most part it should just work.

Getting rid of the different topics for the version would be a big help!

tsightler commented 3 years ago

The topic format for 3.0 is simple:

tuya//state tuya//command tuya//dps/state tuya//dps/command tuya//dps/<1-255>/state tuya//state/<1-255>/command

The friendly name is read from devices.conf file or, if not available, it uses the device ID. There is also the beginnings of a simple templating engine that allows mapping the DPS values to more friendly state names for specific devices. The dps/state and dps/command provide raw Tuya style JSON commands, while the dps/<#>/state and dps/<#>/commands represent values for individual DPS settings.

The templating engine allows you to map specific DPS values to topics, for example, a simple dimmer where dps1 is true/false (on/off) and dps2 is brightness can use a template like this:


{
    "state": { "dpsKey": 1, "dpsType": "bool" },
    "brightness_state": { "dpsKey": 2, "dpsType": "int", "minVal": 0, "maxVal": 255 }
}```

This way tuya/<friendly_name_or_devId>/state would be "On/Off" and tuya/<friendly_name_or_devId>/brightness_state would be brightness value.  Your could then control these values via the automatically created equivalent command topics command/brightness_command.

Admittedly, it's the templating engine that still needs to most work, and the goal is to provide base templates for the most common functions.  I think this will provide the flexibility to use tuya-mqtt in the widest array of examples since you can use raw tuya JSON, consume values directly from DPS values, or map them to more friendly names with a template or device.

Feedback is welcome for sure.
Flip76 commented 3 years ago

Can't wait for give it a try :-) And personally I think, tuya-mqtt is doing exactly what it's supposed to do... Maybe someone from the OH-community wants to write a binding in order to create things (and therefore the mapping) directly within Openhab... But tuya-mqtt 3.0 seems to be the best solution for the OH-community! I will give it a try as soon as you have the first version ready - would be a pleasure to be an Alpha-tester :-)

tsightler commented 3 years ago

Closing this since it should be addressed when 3.0 is released.