codetheweb / tuyapi

🌧 An easy-to-use API for devices that use Tuya's cloud services. Documentation: https://codetheweb.github.io/tuyapi.
MIT License
2.05k stars 334 forks source link

Web streaming #124

Closed dantart closed 5 years ago

dantart commented 5 years ago

Hi: How can I put the streaming of a Tuya camera into a website? I've seen a lot of docs explaining switching for lights, but nothing about camera streaming. thank you !

codetheweb commented 5 years ago

I've never seen a camera device before, do you have a link to where you bought it?

dantart commented 5 years ago

I have a webcamera that is using Tuya Cloud services with the Smart Life's Google Play app

codetheweb commented 5 years ago

I very much doubt TuyAPI will be able to work with cameras at all in its current state, unless it returns something like a URL to get a RTSP feed. But I'm open to looking into adding support for them.

Try getting the device's parameters, then post the output of this script:

const TuyAPI = require('tuyapi');

const device = new TuyAPI({
  id: 'xxxxxxxxxxxxxxxxxxxx',
  key: 'xxxxxxxxxxxxxxxx',
  ip: 'xxx.xxx.xxx.xxx'});

device.get({schema: true}).then(data => {
  console.log(data);
});

If the script fails to return anything, post the output of DEBUG=* node myscript.js.

dantart commented 5 years ago

"Sniffing" the communication of the mobile app, I see a MQTT url, password and more data. There's no RTSP, but MQTT. does it fix ? ;-)

codetheweb commented 5 years ago

Might work, as other Tuya devices use MQTT as well.

What's the output of the above script?

dantart commented 5 years ago

G“$*e:40028) UnhandledPromiseRejectionWarning: AóW.îNÔÅ

(node:40028) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:40028) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

dantart commented 5 years ago

and with the DEBUG:

TuyAPI Payload: { gwId: 'bfb9025b246883e9abmhgh', devId: 'bfb9025b246883e9abmhgh' } +0ms TuyAPI Send attempt 1 +7ms TuyAPI Sending this data: 000055aa000000000000000a0000004a7b2267774964223a226266623930323562323436383833653961626d686768222c226465764964223a226266623930323562323436383833653961626d686768227d000000000000aa56 +0ms TuyAPI Connect 172.20.27.247 +0ms TuyAPI Socket connected. +62ms TuyAPI Received data back: 172.20.27.247 +10ms TuyAPI 000055aa000000000000000a0000001900000001677720696420696e76616c6964f402c15e0000aa56 +0ms G�$yAPI decrypt 172.20.27.247 AóW.îNÔÅ 10 +3ms TuyAPI Disconnect +0ms G�$e:40191) UnhandledPromiseRejectionWarning: AóW.îNÔÅ

(node:40191) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:40191) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. TuyAPI Socket closed: 172.20.27.247 +4ms

dantart commented 5 years ago

I don't know if this helps you but , for example, sniffing the communication of the app when I enter to see a camera, it calls to

https://a1.tuyaeu.com/api.json?appVersion=3.7.1&appRnVersion=5.9&sign=0e6b1f7d60684d469ee0407c94******&imsi=27700ONEPLU65cf&deviceId=13ec00d8247a9758b967ec23eaa61f4c50f40******&platform=ONEPLUS%20A5010&sid=eu154539G0872400culDHPC3cab1db33f1297158509bcbce******&requestId=c361ec4c-aa00-44ad-9b4e-ae0dde******&lang=es&a=tuya.m.ipc.config.get&clientId=8qp5cfk8c4gyr******&osSystem=8.1.0&os=Android&timeZoneId=Europe%2FMadrid&ttid=sdk_tuya%408qp5cfk8c4gy******&v=1.0&imei=27700O******&sdkVersion=2.9.0&time=1545981282

with a postData of {"devId":"bfb9025b246883***"}

and it returns

{
    "result": {
        "password": "ad******",
        "timeZoneId": "Europe/Madrid",
        "audioAttributes": {
            "callMode": [1, 2],
            "hardwareCapability": [1, 2]
        },
        "id": "bfb9025b246883e******",
        "p2pId": "AAPATGXWKF3C******"
    },
    "t": 1545981283323,
    "success": true,
    "status": "ok"
}

(I have put ** at the end of critical id's :-P )

codetheweb commented 5 years ago

Yeah, it looks like this type of devices uses a fundamentally different protocol than smart sockets, lightbulbs, etc.

I'm sorry, but I don't foresee being able to add support for Tuya cameras anytime soon.

However, if you or anyone else manages to get it working I'll happily accept a PR.

AMoo-Miki commented 5 years ago

I had a similar request for Tuya based camera. Walmart had them for $25-ish and I grabbed one; here is what I learned:

  1. They don't advertise themselves so an IP cannot be found automatically.
  2. They have ports 80, 6668, and 8554 open for TCP. 8554 must be for RTSP streaming.
  3. From what I have deduced, there is a common password across a brand or a model.
  4. A P2PIPC app discovered the camera instantly; while authentication didn't work, this could be used for discovery.

Someone had posted that rtsp://admin:<pass>@<ip>:8554 worked for them on some other model of camera that worked with Tuya; that didn't work for me and the camera doesn't advertise a certain URL either. I'll try and sniff this.

dantart commented 5 years ago

Hi @AMoo-Miki I have everything from a camera from 2 packets sniffed. (below)

As you can see I have IP, password, localkey, devideid, ... etc but I have no luck trying to figure out how to connect to the camera.

I have tested public and local IP ... but your method of rtsp is not working.


{
    "result": {
        "password": "*******",
        "timeZoneId": "Europe/Madrid",
        "audioAttributes": {
            "callMode": [1, 2],
            "hardwareCapability": [1, 2]
        },
        "id": "bfb9025b246883e9abmhgh",
        "p2pId": "AAPATGXWKF3CXW3U111A"
    },
    "t": 1546505820371,
    "success": true,
    "status": "ok"
}

{
            "virtual": false,
            "dpName": {},
            "lon": "-0.879584",
            "uuid": "jdws0abdedfc470888e4",
            "skills": {
                "p2pType": 1
            },
            "iconUrl": "https://images.tuyaus.com/smart/icon/1504772581_0.png",
            "lat": "41.653294",
            "runtimeEnv": "prod",
            "devId": "bfb9025b246883e9abmhgh",
            "dpMaxTime": 1546420021886,
            "productId": "v86uW5IC1RYLFN6q",
            "dps": {
                "150": true,
                "161": false,
                "151": "2",
                "110": 1,
                "111": false,
                "134": false,
                "113": false,
                "135": true,
                "103": true,
                "114": "22:00|23:59",
                "115": "yJ2IjoiMS4wIiwiYnVja2V0IjoidHktZXUtc3RvcmFnZTMwIiwiZmlsZXMiOltbIi8xY2M5YWMtMjc4OTEwMC1qZHdzMGFiZGVkZmM0NzA4ODhlNC9kZXRlY3QvL3RtcC9tb3Rpb25fZGV0ZWN0LTE1NDU3ODA2MjcuanBnIiwiIl1dfQ==",
                "116": true,
                "106": "2",
                "117": 0,
                "119": "2",
                "109": "15558144|5005664|10552480"
            },
            "activeTime": 1545402786,
            "ip": "*******",
            "moduleMap": {
                "wifi": {
                    "upgradeStatus": 0,
                    "bv": "20.00",
                    "cdv": "",
                    "pv": "2.1",
                    "verSw": "5.0.14",
                    "isOnline": true,
                    "id": 5007941,
                    "cadv": ""
                },
                "mcu": {
                    "upgradeStatus": 0,
                    "cdv": "",
                    "verSw": "5.0.14",
                    "isOnline": true,
                    "id": 5007942,
                    "cadv": ""
                }
            },
            "devAttribute": 0,
            "name": "Entrada",
            "timezoneId": "Europe/Madrid",
            "localKey": "1f57e010c6eddfa3"
        }, {
AMoo-Miki commented 5 years ago

I have gotten only as far as you have. Checking the packets between the native app and the camera, I see STUN and UDP packets but I can't make sense of it.

I have been able to make calls to HTTP and RTSP but all end in 401s; I even tried P2PIPC and hit the wall of auth. I deduce that you have the same password as me: "ad2c6d47". Is yours a Geeni or Merkury cam too? I feel brands are keeping the same common password across their cameras and that password is not to be used directly but encrypted with something.

Anyway, I really don't know how to go forward; I will keep on looking though.

dantart commented 5 years ago

No, I have different password in all my cameras... I run 8 cameras (Smart Life Tuya). There should be a way to connect to the RTSP ... I've seen the code of the app and they use MQTT but I don't know how to handle it

luci-11 commented 5 years ago

Do you think that this recently Sdk published can help? https://github.com/TuyaInc/tuyasmart_camera_android_sdk_doc

I can see some P2P keys, .. I hope they are useful

codetheweb commented 5 years ago

Interesting, but it doesn't look like there's any actual code unless I'm missing something.

Centaron commented 5 years ago

I've been trying to understand this camera I bought recently as well.

I've been scanning these forums and trying to connect with it through several wrappers. I've been able to connect it and wireshark android emulated interactions with it, as well as get its device key and other information through the python and packet capture on android. I'd love to be able to directly interact with the stream and I'll provide any information if it helps.

luci-11 commented 5 years ago

Interesting, but it doesn't look like there's any actual code unless I'm missing something.

sorry for very late reply. There is .aar file in TuyaInc repository which can easily be decompiled as java. I'm not a great programmer but can read something here and there and maybe the clue is here in the MD5Utils part:

public void connect(String... args) { String p2pID = args[0]; String pwd = args[1]; String localKey = args[2]; if (p2pID != null && pwd != null && localKey != null && this.mCamera != null) { this.mPwd = MD5Utils.md5AsBase64(pwd + "||" + localKey); this.mCamera.connect(p2pID, this.mPwd); } }

@Centaron or @dantart @AMoo-Miki you were some steps ahead with the camera, could you give it a try?

AMoo-Miki commented 4 years ago

One additional note, while Tuya's app talks to devices locally when there is not internet access, it refuses to talk to the camera I have; it doesn't even make an attempt.

@luci-11, could you please point me to where you found this file?

ankurp commented 4 years ago

Any update on figuring this out. I have purchased these cameras and want a way to get the stream so can enable it for homebridge. https://www.walmart.com/ip/Merkury-Innovations-Smart-WiFi-720P-Camera-with-Voice-Control/835969619

donavanbecker commented 2 years ago

https://developer.tuya.com/en/docs/iot/rtsp?id=Kacsdjcqllyql

porok commented 2 years ago

https://developer.tuya.com/en/docs/iot/rtsp?id=Kacsdjcqllyql

This seems promising.

ground-creative commented 2 years ago

Here is an example of how to stream the camera to your pc, taken from this repo https://github.com/ifsale/tuyapiphp

    $app_id = 'xxxxxxxxxxxxxxxxxx';

$camera_id = 'xxxxxxxxxxxxxxxxxxxx';

$tuya = new \tuyapiphp\TuyaApi( $config );

// Get a token
$token = $tuya->token->get_new( )->result->access_token;

// Get camera stream link
$stream = $tuya->devices( $token )->post_stream_allocate( $app_id , $camera_id , [ 'type' => 'rtsp' ] );

Use the returned url to open the stream: ffplay -i rtsps://xxxxxxxxx

dos-ise commented 2 years ago

Is there a way to this with the tuya-cli or a rest client direct? @ifsale

ground-creative commented 2 years ago

Is there a way to this with the tuya-cli or a rest client direct? @ifsale

It's a rest client, directly connects to the tuya cloud api.

dos-ise commented 2 years ago

image

I found it in the api explorer. Thanks alot! Very awesome!

gotschi commented 2 years ago

image

I found it in the api explorer. Thanks alot! Very awesome!

Do you by chance know why I always get this:

{ "code": 115001, "msg": "rtc server busy", "success": false, "t": 1632849208553 }

And how much does it cost to stream 24/7?

thanks

ground-creative commented 2 years ago

Never seer that message, the link expires so you need to get a new one.

Here is a link that streams the camera from the smart life/tuya app with a qrcode:

https://ipc-us.ismartlife.me/

This one is for the us server.

dos-ise commented 2 years ago

I got the busy result when using the wrong user id. This is not the app id

gotschi commented 2 years ago

I got the busy result when using the wrong user id. This is not the app id

thank you, I finally managed to get the correct uid!

However, ffmpeg/ffplay refuse to process the stream:

ffmpeg version 4.3.2-0+deb11u2 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 10 (Debian 10.2.1-6)
  configuration: --prefix=/usr --extra-version=0+deb11u2 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
[rtsp @ 0x55a4ee6c8f40] CSeq 2 expected, -1 received.
[rtsp @ 0x55a4ee6c8f40] CSeq 3 expected, -1 received.
[rtsp @ 0x55a4ee6c8f40] CSeq 4 expected, -1 received.
rtsps://XXX:XXX@aws-tractor1.tuyaeu.com:443/v1/proxy/echo_show/ID: Invalid data found when processing input

edit: guess my camera falls into this:

  1. To obtain real-time video streams of IoT devices through API, the device firmware must be developed based on Tuya IPC SDK 4.7.0 or later.
dos-ise commented 2 years ago

ttps://ipc-us.ismartlife.me/

This web site is really good. Where did you find this?

ground-creative commented 2 years ago

ttps://ipc-us.ismartlife.me/

This web site is really good. Where did you find this?

Digging the web, frustration can be a powerful motivator!

killone78 commented 2 years ago

I got the busy result when using the wrong user id. This is not the app id

could you explain how to get a correct uid? Thanks

patertmg commented 2 years ago

I have really no programming hability, but would it be possible to get a working stream from our indoor IP-camera at https://ipc-eu.ismartlife.me (it's the European version of ipc-us.ismartlife.me) directly into our Youtube channel, for public viewing? Thank you for helping!

ground-creative commented 2 years ago

I have really no programming hability, but would it be possible to get a working stream from our indoor IP-camera at https://ipc-eu.ismartlife.me (it's the European version of ipc-us.ismartlife.me) directly into our Youtube channel, for public viewing? Thank you for helping!

If I'd have to take a wild guess, i'd say no not with that link. https://ipc-eu.ismartlife.me opening it on the browser is pretty much all you can do with that address.

patertmg commented 2 years ago

If I'd have to take a wild guess, i'd say no not with that link. https://ipc-eu.ismartlife.me opening it on the browser is pretty much all you can do with that address.

But if that website can stream my IP camera from anywhere (after I have allowed the login through a QR code), it should be possible to get the stream into Youtube too – or am I wrong? I just would love to have a simple public stream of our IP cam

ground-creative commented 2 years ago

If I'd have to take a wild guess, i'd say no not with that link. https://ipc-eu.ismartlife.me opening it on the browser is pretty much all you can do with that address.

But if that website can stream my IP camera from anywhere (after I have allowed the login through a QR code), it should be possible to get the stream into Youtube too – or am I wrong? I just would love to have a simple public stream of our IP cam

AS i understand, you would need a link for the stream in order to view it through a youtube player which is not what this web address provides, the stream you view has a back end system which has used your login credentials to actually generate the link you would need which you couldn't use anyways as it expires soon as the connection is cut. The first step is that you need to generate your stream link from some kind of tool that does the job just as this web address does

$app_id = 'xxxxxxxxxxxxxxxxxx';

$camera_id = 'xxxxxxxxxxxxxxxxxxxx';

$tuya = new \tuyapiphp\TuyaApi( $config );

// Get a token $token = $tuya->token->get_new( )->result->access_token;

// Get camera stream link $stream = $tuya->devices( $token )->post_stream_allocate( $app_id , $camera_id , [ 'type' => 'rtsp' ] );

this code for instance will do the job, although I still think youtube cannot handle the stream in this case for protocol incompatibility reasons.

Again, not everything I said might be correct 100% but I think generally speaking the explanation and the approach are.

ground-creative commented 2 years ago

If I'd have to take a wild guess, i'd say no not with that link. https://ipc-eu.ismartlife.me opening it on the browser is pretty much all you can do with that address.

But if that website can stream my IP camera from anywhere (after I have allowed the login through a QR code), it should be possible to get the stream into Youtube too – or am I wrong? I just would love to have a simple public stream of our IP cam

You could try to install node which should be easy and doesn't require any programming knowledge, and use some tool like this one https://github.com/ifsale/YourHomeServer which needs basic configuration, from there you just have to deal with how the link generated should be streamed.

mortenmoulder commented 2 years ago

Not sure who to tell this, so I'll just write it in here, as I found a lot of good info in this issue. I found a way to forward the WebRTC stream from the Smart Life WebRTC page to RTSP. I wrote a longer post on Reddit, because I wanted to reach a bunch of people, who might be interested. Mainly to find someone who could turn that thing into a real product, but since tuyapi is so well documented and updated, I figured I would post it here as well.

https://www.reddit.com/r/homeassistant/comments/s6i27l/i_managed_to_forward_the_tuyasmart_life_webrtc/

pergolafabio commented 1 year ago

Guys, i have a Wifi Pet Feeder, it also have a camera, when firing the command below, i get a true result, but no RTSP stream? what could be wrong?

image

pergolafabio commented 1 year ago

hey @mortenmoulder , i was trying your guide, i have a wifi pet feeder with camera, i tried the API explorer to catch the url, as in screenshot above, but it doesnt give me one, so tried your java script, but i have an typeerror : cannot read property of null (reading capturestream)

What could be wrong? the strange thing, i cant make the webview to work either, alwas a decoding issue, but thats maybe just a codec or local issue anyway

thnx

image

pergolafabio commented 1 year ago

hey @dantart , were you ever able to receive the camera stream somehow? in my case i can only retrieve stun/turn address,, there is no RTSP port open, also tried the API command with the php option or directly on api explorer itselft, but doesnt return any rtsp or rtsps address ... so it must be a p2p only stream

David-Woodthorpe commented 10 months ago

Is anyone still looking into this or found a solution? - any help would be greatly appreciated

pergolafabio commented 9 months ago

anyone still working on this one? My camera doesnt expose an RTSP stream, not local or not with API explorer, it uses webrtc + mqtt it seems

praegustator commented 4 months ago

hey @mortenmoulder , i was trying your guide, i have a wifi pet feeder with camera, i tried the API explorer to catch the url, as in screenshot above, but it doesnt give me one, so tried your java script, but i have an typeerror : cannot read property of null (reading capturestream)

I tracked down the error and changed

var videoStream = document.querySelector('.videoMain_2XS71565b7').captureStream();

to the proper class name

var videoStream = document.querySelector('.camera_videoMain__11n9u').captureStream();

and now am having a different error with starting the session. Will try to investigate it further, help is appreciated!

Centaron commented 4 months ago

I've long since given up. I spent some time years ago looking at some API code, but I'm not savy enough to figure anything out. I dismantled the camera but eventually gave up. I've got nothing. Good luck, though.

On Tue, Sep 19, 2023, 5:39 PM David Woodthorpe @.***> wrote:

Is anyone still looking into this or found a solution? - any help would be greatly appreciated

— Reply to this email directly, view it on GitHub https://github.com/codetheweb/tuyapi/issues/124#issuecomment-1726538839, or unsubscribe https://github.com/notifications/unsubscribe-auth/AIPDHO3DCIKXXW5BU6RIDTTX3IGK3ANCNFSM4GMEF66Q . You are receiving this because you were mentioned.Message ID: @.***>