Skip to content

Instantly share code, notes, and snippets.

@schauveau
Last active June 11, 2024 07:26
Show Gist options
  • Save schauveau/c4ff736ae46f9d21527ef1eccee5baa1 to your computer and use it in GitHub Desktop.
Save schauveau/c4ff736ae46f9d21527ef1eccee5baa1 to your computer and use it in GitHub Desktop.
Notes about TP-Link Tapo C500 and Linux

TP-Link Tapo C500 and Linux

Those are my notes about using the TP-Link Tapo C500 camera in my Linux environment.

More precisely, my Linux system are

  • a Debian Testing desktop pc
  • a few raspberry pi
  • an Asustor NAS that is running a highly customized Linux

Tapo C500 technical summary

RTSP Streaming

The camera is using the default rtsp port (554) and provides 2 profiles accessible with the followng URLS

  • rtsp://username:password@camera_ip/stream1
    • The resolution can be 1920x1024, 1280x720 or 640x360
    • As far as know, there is no way to specify it in the URL.
    • It can only be done via Onvif or the Android app
  • rtsp://username:password@camera_ip/stream2
    • This is always 640x360

nmap

nmap reports the following

PORT     STATE SERVICE
443/tcp  open  https
554/tcp  open  rtsp
1024/tcp open  kdm                  (can also be 1025) 
2020/tcp open  xinupageserver
8800/tcp open  sunwebadmin

Port 443 (https)

That port can be opened with a web browser or with curl -v -k https:\\camera_ip but produces an error 404.

That could be a hidden web interface or something related to the HTTP transport mode of RTSP

TO BE INVESTIGATED.

Port 554 (rtsp)

This is the default RTSP port so nothing unusual.

Port 1024 or 1025

The port number changes over time.

This is probably used to sent notifications event to the Onvif clients.

See also port 8800 below.

Port 2020

This is the ONVIF port (non-standard)

Port 8800

After opening it with nc camera_ic 8800 I once got the following reply:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
  <SOAP-ENV:Header>
    <wsa:MessageID>urn:uuid:388f2f01-57ac-4929-9a8f-5e0319e3cff8</wsa:MessageID>
    <wsa:To SOAP-ENV:mustUnderstand="true">http://192.168.1.26:1024/event-1024_1024</wsa:To>
    <wsa:Action SOAP-ENV:mustUnderstand="true">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest</wsa:Action>
    <wsa5:Action SOAP-ENV:mustUnderstand="true">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse</wsa5:Action>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <tev:PullMessagesResponse>
      <tev:CurrentTime>2024-01-26T10:33:08Z</tev:CurrentTime>
      <tev:TerminationTime>2024-01-26T10:34:08Z</tev:TerminationTime>
    </tev:PullMessagesResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

That message is obviously related to the event mechanism (e.g. a movement was detected) of ONVIF.

The URL on the 4 line also tells me that port 1024 is used to send those events.

TODO: Check for port 8800 in the ONVIF description of the available services.

Display with mpv

mpv rtsp://username:password@camera_ip/stream1 --profile=low-latency --untimed

The two options --profile=low-latency --untimed reduces the latency from about 3s to 1s.

See

Display with ffplay

ffplay rtsp://username:password@camera_ip/stream1 -rtsp_transport tcp -flags +low_delay -fflags +nobuffer

The option -fflags +nobuffer reduces the latency from about 3s to less than 1s.

If the option -rtsp_transport tcp is not set, then ffplay is probably using UDP and the bottom of the image is usually corrupted.

https://www.reddit.com/r/ffmpeg/comments/u741n7/remove_delay_on_ffplay_for_capture_device/

Record with ffmpeg

Using onvif-gui, onvif-util and libonvif1

See https://github.com/sr99622/libonvif

On Debian, use apt install onvif-tools libonvif1 libonvif-dev but be aware that this is version 1.4.2.

In the current github trunk, onvif-gui was rewritten from C++ to Python.

TODO: install and test the latest github version.

onvif-gui (1.4.2 from Debian)

A simple tool to control Onvif camera.

Press the discovery button (near the bottom right) and double click on a discovered camera to enable streaming.

Can be used to change the resolution of stream1, move the camera (PTZ) and do a lot of other things.

Unfortunately, the output is often corrupted probably because it uses UDP transport.

TODO: Fill a ticket to request TCP (but test the trunk first)

Stream as HSL m3u8 using ffmpeg

I got some success with the following script

#!/bin/bash

# Customize the RTSP uri as needed
RTSP_URI="rtsp://xxxxxxx:yyyyyyyy@tapo500.local/stream1"   # large view
#RTSP_URI="rtsp://xxxxxxx:yyyyyyyy@tapo500.local/stream2"  # small preview

## See https://ffmpeg.org/ffmpeg-formats.html#hls-2 for more HLS muxer options

# Notes:
#  - By default, libx264 will insert a keyframe every 250 frames
#    which is problematic because segments are split at a keyframe
#    so -hls_time 6 will be mostly ignored and the segment duration
#    will be around 15s.
#    The solution is to force keyframe even DELAY seconds with
#       -force_key_frames "expr:gte(t,n_forced*DELAY)"
#    where delay is a factor of the -hls_time value. 
#    See also https://www.reddit.com/r/ffmpeg/comments/nam6hg/mp4_to_hls_how_to_set_time_segments_properly/
#    It is also possible to use '-hls_flags split_by_time' but then
#    the segments will not start at a keyframe.


CMD=(
    ffmpeg
    ############ RTSP options ############   
    -rtsp_transport tcp    
    -i "$RTSP_URI" 
    ############ Audio settings ############
    -c:a aac
    -b:a 160000
    -ac 2
    ############ Video settings ############
    -s 800x600
    -c:v libx264
    -b:v 200000
    ############ HLS Output ############
    -y
    -force_key_frames "expr:gte(t,n_forced*2)"  
    -hls_time 6
    # Only keep 10 segments on disk
    -hls_list_size 10            
    -hls_flags delete_segments
    -hls_allow_cache 0
    #-start_number 1
    ###### and finally, the output HLS file 
    playlist.m3u8          
)

echo "#" "${CMD[@]}" 
"${CMD[@]}"

FFMPEG will generate start generating some TS files and a file playlist.m3u8.

It is possible to watch the m3u8 stream locally for example using mpv:

mpv playlist.m3u8

The whole directory can also be accessed remotely using your http server (Apache, ...). If you do not have a http server, then start a simple one with python3 -m http.server in the directory containing the files and watch the stream with

mpv http://localhost:8000/playlist.m3u8

Simple ONVIF queries using curl

ONVIF is a typical http based protocol using POST queries.

The protocol used to pass the password is quite complex but a few queries do not require authentication.

For instance, the GetCapabilities can performed as follow

Create a file request.xml such as

<?xml version=1.0' encoding='utf-8'>
<soap-env:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <soap-env:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"></GetCapabilities>
    </soap-env:Body>
</soap-env:Envelope>

and then

curl -s -S -k -X POST --header 'Content-Type: text/xml; charset=utf-8' -d @request.xml http://192.168.1.26:2020/onvif/service 

You may want to pipe the output in xmllint - -format to make it more readable.

Similarly, the GetServices query provides a shorter list of the supported services.

Analysis of GetCapabilities and GetServices responses

GetServices Response

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
  <SOAP-ENV:Body>
    <tds:GetServicesResponse>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver10/device/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver10/media/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver10/events/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver20/analytics/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver20/imaging/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver20/ptz/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
      <tds:Service>
        <tds:Namespace>http://www.onvif.org/ver10/deviceIO/wsdl</tds:Namespace>
        <tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
        <tds:Version>
          <tt:Major>2</tt:Major>
          <tt:Minor>20</tt:Minor>
        </tds:Version>
      </tds:Service>
    </tds:GetServicesResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The supported services are device, media, events, analytics, imaging, ptz and deviceIO. See https://www.onvif.org/specs/DocMap.html for their respective specifications.

  • device is the core service.
  • media is about controlling the video and audio streams. This is where you can change the resolution of stream1.
  • events is about the event notifications (e.g. a movement was detected, camera tempering, ...)
  • analytics is about the image analysis (e.g. detect persons, track movements, ...)
  • imaging is about the image and camera settings (e.g. brightness, focus, ...)
  • ptz is about Pan, Tilt and Zoom
  • deviceIO is about the input and output audio, video and relay.

What is obviously missing is the recording service. The Tapo android app must be using an extension to access the sd-card content.

Each service should have a GetServiceCapabilities or something similar to get more details but that requires authentication.

However, the GetCapabilities query gives some details about each service without auth. See Below.

GetCapabilities Response

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" 
                   xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
                   xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" 
                   xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" 
                   xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
                   xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
                   xmlns:wsa5="http://www.w3.org/2005/08/addressing"
                   xmlns:xmime="http://tempuri.org/xmime.xsd"
                   xmlns:xop="http://www.w3.org/2004/08/xop/include" 
                   xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" 
                   xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
                   xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2"
                   xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
                   xmlns:tt="http://www.onvif.org/ver10/schema" 
                   xmlns:ter="http://www.onvif.org/ver10/error" 
                   xmlns:tns1="http://www.onvif.org/ver10/topics" 
                   xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
                   xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" 
                   xmlns:trt="http://www.onvif.org/ver10/media/wsdl" 
                   xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
                   xmlns:tdn="http://www.onvif.org/ver10/network/wsdl"
                   xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" 
                   xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"
                   xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
                   xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
                   xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" 
                   xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
  <SOAP-ENV:Body>
    <tds:GetCapabilitiesResponse>
      <tds:Capabilities>
        <tt:Analytics>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
          <tt:RuleSupport>true</tt:RuleSupport>
          <tt:AnalyticsModuleSupport>true</tt:AnalyticsModuleSupport>
        </tt:Analytics>
        <tt:Device>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
          <tt:Network>
            <tt:IPFilter>false</tt:IPFilter>
            <tt:ZeroConfiguration>false</tt:ZeroConfiguration>
            <tt:IPVersion6>false</tt:IPVersion6>
            <tt:DynDNS>false</tt:DynDNS>
            <tt:Extension>
              <tt:Dot11Configuration>true</tt:Dot11Configuration>
            </tt:Extension>
          </tt:Network>
          <tt:System>
            <tt:DiscoveryResolve>false</tt:DiscoveryResolve>
            <tt:DiscoveryBye>true</tt:DiscoveryBye>
            <tt:RemoteDiscovery>false</tt:RemoteDiscovery>
            <tt:SystemBackup>false</tt:SystemBackup>
            <tt:SystemLogging>false</tt:SystemLogging>
            <tt:FirmwareUpgrade>false</tt:FirmwareUpgrade>
            <tt:SupportedVersions>
              <tt:Major>20</tt:Major>
              <tt:Minor>6</tt:Minor>
            </tt:SupportedVersions>
            <tt:Extension>
              <tt:HttpFirmwareUpgrade>false</tt:HttpFirmwareUpgrade>
              <tt:HttpSystemBackup>false</tt:HttpSystemBackup>
              <tt:HttpSystemLogging>false</tt:HttpSystemLogging>
              <tt:HttpSupportInformation>false</tt:HttpSupportInformation>
            </tt:Extension>
          </tt:System>
          <tt:IO/>
          <tt:Security>
            <tt:TLS1.1>false</tt:TLS1.1>
            <tt:TLS1.2>false</tt:TLS1.2>
            <tt:OnboardKeyGeneration>false</tt:OnboardKeyGeneration>
            <tt:AccessPolicyConfig>false</tt:AccessPolicyConfig>
            <tt:X.509Token>false</tt:X.509Token>
            <tt:SAMLToken>false</tt:SAMLToken>
            <tt:KerberosToken>false</tt:KerberosToken>
            <tt:RELToken>false</tt:RELToken>
          </tt:Security>
        </tt:Device>
        <tt:Events>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
          <tt:WSSubscriptionPolicySupport>true</tt:WSSubscriptionPolicySupport>
          <tt:WSPullPointSupport>true</tt:WSPullPointSupport>
          <tt:WSPausableSubscriptionManagerInterfaceSupport>false</tt:WSPausableSubscriptionManagerInterfaceSupport>
        </tt:Events>
        <tt:Imaging>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
        </tt:Imaging>
        <tt:Media>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
          <tt:StreamingCapabilities>
            <tt:RTPMulticast>false</tt:RTPMulticast>
            <tt:RTP_TCP>true</tt:RTP_TCP>
            <tt:RTP_RTSP_TCP>true</tt:RTP_RTSP_TCP>
          </tt:StreamingCapabilities>
        </tt:Media>
        <tt:PTZ>
          <tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
        </tt:PTZ>
        <tt:Extension>
          <tt:DeviceIO>
            <tt:XAddr/>
            <tt:VideoSources>0</tt:VideoSources>
            <tt:VideoOutputs>0</tt:VideoOutputs>
            <tt:AudioSources>1</tt:AudioSources>
            <tt:AudioOutputs>1</tt:AudioOutputs>
            <tt:RelayOutputs>0</tt:RelayOutputs>
          </tt:DeviceIO>
          <hikxsd:hikCapabilities>
            <hikxsd:XAddr>http://192.168.1.26:2020/onvif/service</hikxsd:XAddr>
            <hikxsd:PTZ3DZoomSupport>true</hikxsd:PTZ3DZoomSupport>
            <hikxsd:PTZPatternSupport>false</hikxsd:PTZPatternSupport>
            <hikxsd:IOInputSupport>false</hikxsd:IOInputSupport>
            <hikxsd:PrivacyMaskSupport>false</hikxsd:PrivacyMaskSupport>
            <hikxsd:Language>2</hikxsd:Language>
          </hikxsd:hikCapabilities>
        </tt:Extension>
      </tds:Capabilities>
    </tds:GetCapabilitiesResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

In Media/StreamingCapability we have RTPMulticast (i,e. RTSP over UDP), RTP_TCP and RTP_RTSP_TCP so http and websocket are obviously not supported. See also section 5.1.1.3 of https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf

Device/Network/IPVersion6 is false so no IPv6

There are a few extensions but I do not see anything that could be related to recording or to SD card storage.

@eddub
Copy link

eddub commented Jun 10, 2024

Hi, so are you able to get this camera's feed and record it on a Linux or NAS device? Thanks
Found this info re tapo cameras: https://www.tapo.com/uk/faq/34/

@schauveau
Copy link
Author

Yeah. Viewing and recording should work fine on Linux with any tool that supports rstp streams. Just make sure that you enable the options to reduce the latency. See the examples with mpv and ffplay.

I also have a ffmpeg command to convert the rstp stream to a m3u8 stream which is easier to integrate in a web page. I will update my README.

My main problem is with my Asustor NAS that refuses to display the live stream. The problem is not with the TAPO camera which uses ONVIF, a very common protocol, but because the Asustor "Surveillance Center" app relies on an external control plugin that only exists on Windows and Mac (welcome back to the 20th century). Simply speaking, Asustor sucks on Linux.

The onvif protocol is pretty standard and can be used to control the camera using onvif-gui or in python scripts using the onvif-zeep module.

The only thing that does not work well from Linux is accessing the recordings on the camera sd-card. That feature is not implemented using standard ONVIF requests. The recordings can only be accessed using the official ANDROID app. I believe that this done via an encrypted connection to one of the undocumented open ports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment