-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tuya CO2 PM2.5 temp humidity sensor #14
Comments
I don't have a Tuya sensor to help you troubleshoot. What device did you get? The tinytuya or tuyapower scan functions should decrypt the UDP payload:
Do you see the sensor in that list? If so, grab the Device ID and IP address. You can get the LOCAL KEY via the method described here: https://github.com/jasonacox/tinytuya#get-the-tuya-device-local-key In case it helps, the data points (DPS) mapping for the sensor should be here: https://github.com/jasonacox/tinytuya#version-33---sensor-type I suspect sensors may not respond to polling, but if it does, you could try something like: import tinytuya
deviceID = "xxxxxxxx"
ipAddress = "xxxxxxxx"
localKey = "xxxxxxxx"
d = tinytuya.OutletDevice(deviceID, ipAddress, local_key)
d.set_version(3.3)
data = d.status()
print('Response from Sensor: %r' % data) If that doesn't work, we would need to decrypt the UDP payload. It would be something similar to how we decode the response payload (see https://github.com/jasonacox/tinytuya/blob/master/tinytuya/__init__.py) log.debug('status received data=%r', data)
result = data[20:-8] # hard coded offsets
if self.dev_type != 'default':
result = result[15:]
log.debug('result=%r', result)
if result.startswith(b'{'):
# this is the regular expected code path
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
elif result.startswith(PROTOCOL_VERSION_BYTES_31):
# got an encrypted payload
# expect resulting json to look similar to:: {"devId":"ID","dps":{"1":true,"2":0},"t":EPOCH_SECS,"s":3_DIGIT_NUM}
result = result[len(PROTOCOL_VERSION_BYTES_31):] # remove version header
result = result[16:] # Remove 16-bytes appears to be MD5 hexdigest of payload
cipher = AESCipher(self.local_key)
result = cipher.decrypt(result)
log.debug('decrypted result=%r', result)
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
elif self.version == 3.3:
cipher = AESCipher(self.local_key)
result = cipher.decrypt(result, False)
log.debug('decrypted result=%r', result)
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
else:
log.error('Unexpected status() payload=%r', result)
return result |
hi
thanks for your advice.
as i said,I am working with labview, not Python, so unable to use your code
directly.
The device responses well to *GET
https://openapi.tuyaeu.com/v1.0/devices/#deviceid#
<https://openapi.tuyaeu.com/v1.0/devices/#deviceid#>* and returns it
category and name and online status, which is
[image: image.png]
but when I try to use the *GET
https://openapi.tuyaeu.com/v1.0/devices/#deviceid#/status
<https://openapi.tuyaeu.com/v1.0/devices/#deviceid#/status>* or similar
commands (*statistics, log*, etc) , the device returns error message, like
[image: image.png]
Is that what you mean that sensor don't response to polling ?
I know the IP of the sensor, as it is connected to my home router.
The UDP payload recorded by wireshark is (alo attached in a file)
0000 00 00 55 aa 00 00 00 00 00 00 00 13 00 00 00 9c ..U..... ........
0010 00 00 00 00 d0 97 66 67 6f 33 69 eb 10 b5 e9 f1 ......fg o3i.....
0020 32 fd 80 2a 51 b4 1a 6c b8 79 4d d0 1f 28 ca 5e 2..*Q..l .yM..(.^
0030 45 ed cb 20 38 ba 18 05 44 31 0a 27 91 c1 60 59 E.. 8... D1.'..`Y
0040 ab 44 0e 92 9e 57 8a 1a ba 06 b8 2b 52 24 4f fb .D...W.. ...+R$O.
0050 cc f8 57 c8 72 56 f9 92 ef 0b b3 c9 94 6f 6c a8 ..W.rV.. .....ol.
0060 e2 e1 48 53 2e 0d bc 9a 92 c3 31 72 86 eb f2 38 ..HS.... ..1r...8
0070 be 57 97 86 7f d5 18 2f 0d c1 94 9b fe 08 16 f2 .W...../ ........
0080 f9 db 35 80 7f 1d 5d 33 0b 04 95 e8 94 e3 fb 57 ..5...]3 .......W
0090 71 e9 be 66 7a 23 e3 b2 24 9f 5a df 48 a7 14 f8 q..fz#.. $.Z.H...
00A0 51 aa f4 39 85 c4 56 44 00 00 aa 55 Q..9..VD ...U
The device reports its data to the SMART LIFE APP, so if I just could
decode the fields of the payload I will have all I need.
Attached the picture of the device screen and its page in the APP.
You see , there are a lot of measurements.
Hope you understand something from what I am writing here :)
Thanks
Vlad
*ולדי גריגורוביץ*
*נייד 050-7756282*
On Mon, Nov 23, 2020 at 8:33 PM Jason Cox ***@***.***> wrote:
I don't have a Tuya sensor to help you troubleshoot. What device did you
get?
The *tinytuya* or *tuyapower* scan functions should decrypt the UDP
payload:
python -m tinytuya
Do you see the sensor in that list? If so, grab the Device ID and IP
address. You can get the LOCAL KEY via the method described here:
https://github.com/jasonacox/tinytuya#get-the-tuya-device-local-key
In case it helps, the data points (DPS) mapping for the sensor should be
here: https://github.com/jasonacox/tinytuya#version-33---sensor-type
I suspect sensors may not respond to polling, but if it does, you could
try something like:
import tinytuya
deviceID = "xxxxxxxx"ipAddress = "xxxxxxxx"localKey = "xxxxxxxx"
d = tinytuya.OutletDevice(deviceID, ipAddress, local_key)d.set_version(3.3)data = d.status()
print('Response from Sensor: %r' % data)
If that doesn't work, we would need to decrypt the UDP payload. It would
be something similar to how we decode the response payload (see
https://github.com/jasonacox/tinytuya/blob/master/tinytuya/__init__.py)
log.debug('status received data=%r', data)
result = data[20:-8] # hard coded offsets
if self.dev_type != 'default':
result = result[15:]
log.debug('result=%r', result)
if result.startswith(b'{'):
# this is the regular expected code path
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
elif result.startswith(PROTOCOL_VERSION_BYTES_31):
# got an encrypted payload
# expect resulting json to look similar to:: {"devId":"ID","dps":{"1":true,"2":0},"t":EPOCH_SECS,"s":3_DIGIT_NUM}
result = result[len(PROTOCOL_VERSION_BYTES_31):] # remove version header
result = result[16:] # Remove 16-bytes appears to be MD5 hexdigest of payload
cipher = AESCipher(self.local_key)
result = cipher.decrypt(result)
log.debug('decrypted result=%r', result)
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
elif self.version == 3.3:
cipher = AESCipher(self.local_key)
result = cipher.decrypt(result, False)
log.debug('decrypted result=%r', result)
if not isinstance(result, str):
result = result.decode()
result = json.loads(result)
else:
log.error('Unexpected status() payload=%r', result)
return result
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#14 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AR3QACIBZMABHRH5WRQ6P3TSRKTIJANCNFSM4T7LTKOA>
.
0000 00 00 55 aa 00 00 00 00 00 00 00 13 00 00 00 9c ..U..... ........
0010 00 00 00 00 d0 97 66 67 6f 33 69 eb 10 b5 e9 f1 ......fg o3i.....
0020 32 fd 80 2a 51 b4 1a 6c b8 79 4d d0 1f 28 ca 5e 2..*Q..l .yM..(.^
0030 45 ed cb 20 38 ba 18 05 44 31 0a 27 91 c1 60 59 E.. 8... D1.'..`Y
0040 ab 44 0e 92 9e 57 8a 1a ba 06 b8 2b 52 24 4f fb .D...W.. ...+R$O.
0050 cc f8 57 c8 72 56 f9 92 ef 0b b3 c9 94 6f 6c a8 ..W.rV.. .....ol.
0060 e2 e1 48 53 2e 0d bc 9a 92 c3 31 72 86 eb f2 38 ..HS.... ..1r...8
0070 be 57 97 86 7f d5 18 2f 0d c1 94 9b fe 08 16 f2 .W...../ ........
0080 f9 db 35 80 7f 1d 5d 33 0b 04 95 e8 94 e3 fb 57 ..5...]3 .......W
0090 71 e9 be 66 7a 23 e3 b2 24 9f 5a df 48 a7 14 f8 q..fz#.. $.Z.H...
00A0 51 aa f4 39 85 c4 56 44 00 00 aa 55 Q..9..VD ...U
|
hi
I am again on wireshark
[image: image.png]
192.168.1.213 is the IP of the device
[image: image.png]
*ולדי גריגורוביץ*
*נייד 050-7756282*
On Mon, Nov 23, 2020 at 9:43 PM Vlad Grigorovitch <[email protected]>
wrote:
… hi
thanks for your advice.
as i said,I am working with labview, not Python, so unable to use your
code directly.
The device responses well to *GET https://openapi.tuyaeu.com/v1.0/devices/#deviceid#
<https://openapi.tuyaeu.com/v1.0/devices/#deviceid%23>* and returns it
category and name and online status, which is
[image: image.png]
but when I try to use the *GET https://openapi.tuyaeu.com/v1.0/devices/#deviceid#/status
<https://openapi.tuyaeu.com/v1.0/devices/#deviceid%23/status>* or similar
commands (*statistics, log*, etc) , the device returns error message, like
[image: image.png]
Is that what you mean that sensor don't response to polling ?
I know the IP of the sensor, as it is connected to my home router.
The UDP payload recorded by wireshark is (alo attached in a file)
0000 00 00 55 aa 00 00 00 00 00 00 00 13 00 00 00 9c ..U..... ........
0010 00 00 00 00 d0 97 66 67 6f 33 69 eb 10 b5 e9 f1 ......fg o3i.....
0020 32 fd 80 2a 51 b4 1a 6c b8 79 4d d0 1f 28 ca 5e 2..*Q..l .yM..(.^
0030 45 ed cb 20 38 ba 18 05 44 31 0a 27 91 c1 60 59 E.. 8... D1.'..`Y
0040 ab 44 0e 92 9e 57 8a 1a ba 06 b8 2b 52 24 4f fb .D...W.. ...+R$O.
0050 cc f8 57 c8 72 56 f9 92 ef 0b b3 c9 94 6f 6c a8 ..W.rV.. .....ol.
0060 e2 e1 48 53 2e 0d bc 9a 92 c3 31 72 86 eb f2 38 ..HS.... ..1r...8
0070 be 57 97 86 7f d5 18 2f 0d c1 94 9b fe 08 16 f2 .W...../ ........
0080 f9 db 35 80 7f 1d 5d 33 0b 04 95 e8 94 e3 fb 57 ..5...]3 .......W
0090 71 e9 be 66 7a 23 e3 b2 24 9f 5a df 48 a7 14 f8 q..fz#.. $.Z.H...
00A0 51 aa f4 39 85 c4 56 44 00 00 aa 55 Q..9..VD ...U
The device reports its data to the SMART LIFE APP, so if I just could
decode the fields of the payload I will have all I need.
Attached the picture of the device screen and its page in the APP.
You see , there are a lot of measurements.
Hope you understand something from what I am writing here :)
Thanks
Vlad
*ולדי גריגורוביץ*
*נייד 050-7756282*
On Mon, Nov 23, 2020 at 8:33 PM Jason Cox ***@***.***>
wrote:
> I don't have a Tuya sensor to help you troubleshoot. What device did you
> get?
>
> The *tinytuya* or *tuyapower* scan functions should decrypt the UDP
> payload:
>
> python -m tinytuya
>
> Do you see the sensor in that list? If so, grab the Device ID and IP
> address. You can get the LOCAL KEY via the method described here:
> https://github.com/jasonacox/tinytuya#get-the-tuya-device-local-key
>
> In case it helps, the data points (DPS) mapping for the sensor should be
> here: https://github.com/jasonacox/tinytuya#version-33---sensor-type
>
> I suspect sensors may not respond to polling, but if it does, you could
> try something like:
>
> import tinytuya
> deviceID = "xxxxxxxx"ipAddress = "xxxxxxxx"localKey = "xxxxxxxx"
> d = tinytuya.OutletDevice(deviceID, ipAddress, local_key)d.set_version(3.3)data = d.status()
> print('Response from Sensor: %r' % data)
>
> If that doesn't work, we would need to decrypt the UDP payload. It would
> be something similar to how we decode the response payload (see
> https://github.com/jasonacox/tinytuya/blob/master/tinytuya/__init__.py)
>
> log.debug('status received data=%r', data)
>
> result = data[20:-8] # hard coded offsets
> if self.dev_type != 'default':
> result = result[15:]
>
> log.debug('result=%r', result)
>
> if result.startswith(b'{'):
> # this is the regular expected code path
> if not isinstance(result, str):
> result = result.decode()
> result = json.loads(result)
> elif result.startswith(PROTOCOL_VERSION_BYTES_31):
> # got an encrypted payload
> # expect resulting json to look similar to:: {"devId":"ID","dps":{"1":true,"2":0},"t":EPOCH_SECS,"s":3_DIGIT_NUM}
> result = result[len(PROTOCOL_VERSION_BYTES_31):] # remove version header
> result = result[16:] # Remove 16-bytes appears to be MD5 hexdigest of payload
> cipher = AESCipher(self.local_key)
> result = cipher.decrypt(result)
> log.debug('decrypted result=%r', result)
> if not isinstance(result, str):
> result = result.decode()
> result = json.loads(result)
> elif self.version == 3.3:
> cipher = AESCipher(self.local_key)
> result = cipher.decrypt(result, False)
> log.debug('decrypted result=%r', result)
> if not isinstance(result, str):
> result = result.decode()
> result = json.loads(result)
> else:
> log.error('Unexpected status() payload=%r', result)
>
> return result
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <#14 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AR3QACIBZMABHRH5WRQ6P3TSRKTIJANCNFSM4T7LTKOA>
> .
>
|
Hi @grigvlad - Keep in mind that Tuya devices are designed to communicate with the TuyaCloud. Once you add the device to the SmartLife App, it creates a LocalKey that is used to encrypt the data payloads. Without that key you can't read the payloads directly from the App. However, you may be able to use the TuyaCloud to get that information. It requires that you use your credential to get a token to request the data directly. I suggest you check out the developer information on Tuya's website: https://developer.tuya.com/en/docs/iot . |
Hi
I have the key and I am able to get a token. The developer section on Tuya
website is intended for hardware developing , while I am trying to develop
software using existing hardware.
Thank you anyway for trying.
*ולדי גריגורוביץ*
*נייד 050-7756282*
…On Tue, Nov 24, 2020 at 3:31 AM Jason Cox ***@***.***> wrote:
Hi @grigvlad <https://github.com/grigvlad> - Keep in mind that Tuya
devices are designed to communicate with the TuyaCloud. Once you add the
device to the SmartLife App, it creates a LocalKey that is used to encrypt
the data payloads. Without that key you can't read the payloads directly
from the App. However, you may be able to use the TuyaCloud to get that
information. It requires that you use your credential to get a token to
request the data directly. I suggest you check out the developer
information on Tuya's website: https://developer.tuya.com/en/docs/iot .
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#14 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AR3QACJAC5AEKR4QKDLUNUDSRMEGLANCNFSM4T7LTKOA>
.
|
Thanks Vladi, I would very much like to hear how your research goes. Looking at the payload you are getting back, I do see the Tuya prefix and suffix: "prefix": "000055aa00000000000000",
# Next byte is command "hexByte" + length of remaining payload + command + suffix
# (unclear if multiple bytes used for length, zero padding implies could be more
# than one byte)
"suffix": "000000000000aa55" I don't know the labview equivalent, but a python approach could be: # data contains the payload
# KEY is the Tuya local key you have
result = data[20:-8] # trim off the first 20 bytes (header) and last 8 (crc?)
cipher = AESCipher(KEY)
result = cipher.decrypt(result, False)
print('decrypted result=%r', result) |
hi
If 13 is the hex byte, 0x0000009C = 156 bytes is the length of data.
if I count from address 0xB (the first zero after 13) to A7 (last byte
before suffix), I have exactly 0x9C = 156 bytes.
Does it mean that encrypted data includes 156 bytes starting actually from
the zeros just after the '13' hexbyte ?
[image: image.png]
Tuya uses two steps SHA-256 encryption. At first step to get the token,
while the string to encode includes client ID + secret key + timestamp.
At the second step, the access signature is calculated again, this time by
client ID + secret key + token + timestamp.
I have all the info, but what about then timestamp. Does UDP payload
report the timestamp in seconds or milliseconds ?
I doubt what of the above info (client ID + secret key + token +
timestamp) is required to decrypt the payload ?
Vlad
*ולדי גריגורוביץ*
*נייד 050-7756282*
…On Tue, Nov 24, 2020 at 8:23 PM Jason Cox ***@***.***> wrote:
Thanks Vladi, I would very much like to hear how your research goes.
Looking at the payload you are getting back, I do see the Tuya prefix and
suffix:
"prefix": "000055aa00000000000000",
# Next byte is command "hexByte" + length of remaining payload + command + suffix
# (unclear if multiple bytes used for length, zero padding implies could be more
# than one byte)
"suffix": "000000000000aa55"
I don't know the labview equivalent, but a python approach could be:
# data contains the payload
# KEY is the Tuya local key you have
result = data[20:-8] # trim off the first 20 bytes (header) and last 8 (crc?)
cipher = AESCipher(KEY)
result = cipher.decrypt(result, False)
print('decrypted result=%r', result)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#14 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AR3QACLSVTUC6N4KWZRAISTSRP2ZPANCNFSM4T7LTKOA>
.
|
I have the CO2 PM2.5 temp humidity sensor.
Despite developing in Labview and not in Python, I hope you could help.
My device works well with app, and also I have managed to communicate with it using my code in Labview using Tuya APIs.
I get its device id and category, but it says the reading of measurements is not supported.
In wireshark, I got its UDP payload, 172 bytes length.
How can I decode it? what is the structure of the payload ?
1.txt
hope for your help
The text was updated successfully, but these errors were encountered: