Tuya API - Encrypted Logs?

Has anyone come across these encrypted logs from a Tuya device?


I have one of these 100A MCBs which has a WR4 Module, based on the RTL8710BN chip, so won’t be able to flash. I was hoping to be able to get the power reading into HA via the Tuya Integration V1 or V2, or the tuya local integration, but this device doesn’t seem to support the readouts (Tuya V2 just added circuit breaker support but only as a switch, it don’t provide the power vaules for this device). It does not seem to report them as a data point but rather an encrypted log? Anyone have any ideas? Thanks

Looks like base64 encoded (not encrypted) data.

$ base64 -d | xxd
CcwAAAAA
00000000: 09cc 0000 0000                           ......

0x09cc is 2508, possibly 250.8V?

Ok great! Thanks for that. Do you have a suggestion how I get the data from the logs into HA?

So Tuya Local integration gets me access to the data, after looking at the logs I can see the following datapoints…

2021-07-27 22:33:31 DEBUG (MainThread) [custom_components.localtuya.pytuya] [bfb...tfk] Decrypted payload: {"dps":{"101":"CbEAAAAA"},"t":1627421610}
2021-07-27 22:33:31 DEBUG (MainThread) [custom_components.localtuya.pytuya] [bfb...tfk] Decrypted payload: {"dps":{"102":"AAAAAAAAAAAA"},"t":1627421610}
2021-07-27 22:33:31 DEBUG (MainThread) [custom_components.localtuya.pytuya] [bfb...tfk] Decrypted payload: {"dps":{"103":"AAAAAAAAAAAAAAAA"},"t":1627421610}

And so i can add a sensor with those dp ids …

image

The last bit I’m struggling with is the base64 decode. I see you converted the base64 to hexadecimal, then to decimal. So to me, it looks the hexadecimal value is encoded in base64, which means I cant use the base64_decode in a template?

If anyone can offer any advice I would be grateful.

I used the base64 command to convert the string to binary data and piped it’s output to xxd, which shows each byte of that data in hexadecimal.

The base64 encoded data is a sequence of bytes that represent the integer, not a string of digits.
You cannot use base64_decode because it expects the encoded data to be a utf-8 string:

I can’t find a way to decode your data to an integer in a template. Adding custom template filters also seems impossible without modifying homeassistant/helpers/template.py. Your modifications would be overwritten by every HA update, so I don’t think this is the way to go either.

I guess you could create a command line sensor with this script (let’s call it base64_int.py):

#!/usr/bin/env python3
import base64
import sys

data = base64.b64decode(sys.argv[1])
if len(sys.argv) >= 3:
    length = int(sys.argv[2])
    data = data[:length]
val = int.from_bytes(data, byteorder='big')
print(val)

This is how it works:

$ ./base64_int.py CbkAAAAA 2
2489

The 2 at the end specifies that only the first 2 bytes should be used. We don’t want the 0x00 bytes at the end of our data:

$ ./base64_int.py CbkAAAAA        
10690173599744

The command line sensor’s config could be something like this:

sensor:
  - platform: command_line
    name: decoded voltage
    command: "python3 /config/base64_int.py {{ states('sensor.encoded_voltage') }} 2"
    value_template: "{{ value | multiply(0.1) }}"

@ondras12345. Thank you so much for the detail! I now have it working! It took me a while but would have never have done it without your help. I increased it to 3 bytes for current and power, and adjusted the multiplier but now does the job. Annoyingly the scan_interval does not want to work for me, so can only use the default 60s.

Also looks like the command_line sensor doesn’t support device_class either.

image

edit: also added a round() to all in the end as sometimes I would get a load of zeros with a digit at the end.

You should be able to set the device class in the UI:
Click on the entity you want to customize. In the Settings tab, you should see this:

You can overwrite some attributes in the entity customizations section.

Click on the entity customizations hyperlink, pick an attribute to override and select device class.

I have one command line sensor that has scan_interval: 600 and it seems to work just fine. Haven’t tried less than the default 60s though.

Thanks again, not sure why the scan interval isn’t working for me, for now 60s will do the job.

thank you @ondras12345 for your great little script.
it is working like a charm on almost all the values in debug.
but… it seems it is not working with the value AQAAASwBAAA=
it should return something like 300 or 3000. this is the leakage current value set in the app (in mA).
now i get 256 with second parameter 2 and 65536 with second parameter 3.
am i doing something wrong?

That seems to be a more complex data structure than just a single integer:

$ base64 -d | xxd
AQAAASwBAAA=
00000000: 0100 0001 2c01 0000                      ....,...

I’m not sure how to decode it. 0x012c = 300, so maybe that’s it. However, there are two occurrences of 0x012c in your message (0x012c and 0x2c01 - different byte orders) and I’m not sure which is the right one:

$ python3
Python 3.8.10 (default, Mar 13 2023, 10:26:41) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
: >>> import base64
: >>> data = base64.b64decode("AQAAASwBAAA=")
: >>> int.from_bytes(data[4:6], byteorder='little')
300
+ >>> int.from_bytes(data[3:5], byteorder='big')
300
+ >>> 

it is working with data[3:5].
thank you!