Issue with external tapo integration

Following your feedback (thanks @StephaneB, @JKBS64), I’ve made a major overhaul of the Tapo integration. Here’s what’s coming in the next version.

Camera IP addresses

This was the main issue, and it wasn’t just an ergonomics problem: automatic detection simply didn’t work.

  • Network scanning found no cameras. The request sent was not in the correct format, and the camera was not recognized in the response. Cameras are now found by their MAC address, as the Tapo app does.
  • Addresses could disappear. Gladys limits scans to one every 10 seconds. When a scan was refused (the « Too Many Requests » in your logs), cameras were left without an address, hence the TAPO_CAMERA_IP_UNKNOWN. A camera now keeps its last known address.
  • Manual entry was too strict. A name with a capital letter, an accent, or a different _ did not match.

And above all, it’s much simpler to configure:

  • New action « Set the IP address of a device », at the bottom of the Configuration screen: you choose the device from a list, type its IP, and Gladys immediately checks that it responds and captures an image. The IP is found in the Tapo app: device settings > Device info.
  • « Test connection » now displays a line per device: its address, where it comes from, and what to do if it’s missing.
  • Unfindable devices are reported directly on the configuration screen.

Small tip: reserve the IP of your cameras in your box (DHCP reservation), so that it doesn’t change after a power outage.

And via the cloud, without IP? I checked: it’s not possible. TP-Link provides no access to the image or stream of the cameras over the Internet to third-party applications. Even the Home Assistant integration goes only through the local network. The advantage is that your images never leave your home.

Doorbells

@JKBS64: your D235 did not appear because TP-Link classifies doorbells in a separate category in its cloud. This is fixed, it should now be discovered.

More reliability

I also fixed several cases where a camera could stop reporting movements without saying anything, or be temporarily blocked by too many connection attempts. Battery-powered cameras are also woken up less unnecessarily.

Private mode: attention, change

The integration now uses the standard private mode of the cameras in Gladys (the « Activated » command). Disabling a camera stops capture and display everywhere. On models that allow it, this also masks the lens, like the private mode of the Tapo app.

This requires Gladys 5.0 or higher. If you were using the old « private mode » switch in a scene, it continues to work. However, when you update the camera from the Discovery screen, you will need to adapt the scene, and the logic is reversed: « activated » means the camera is working.

New: Tapo plugs, bulbs and sensors

The integration is no longer limited to cameras:

  • Plugs (P100, P110…): on/off, and for models with measurement, power and consumption, compatible with Gladys’ energy tracking.
  • Power strips (P300, P304M…): each plug is controllable separately.
  • Bulbs and LED strips (L510, L530, L900, L920…): brightness, color and white.
  • Wall switches (S500, S505, dimmers S500D/S505D).
  • Sensors from the H100 hub: temperature/humidity (T310/T315), motion (T100), door opening (T110), water leak (T300), buttons (S200B/S200D) and thermostatic head (KE100).

Everything goes locally, with your usual Tapo account: nothing more to configure. The H200 hub is not yet supported.

Need testers

I don’t have all these devices at home. If you have plugs, bulbs, an H100 hub or a Tapo doorbell and you want to test, let me know here. And as usual, in case of trouble, paste the integration logs and the result of « Test connection », that’s what helps me the most.

Thanks for your patience :slightly_smiling_face:

If anyone is motivated to test, I can make a test dev image before making a release. Let me know.

@JKBS64, below is the procedure to test the dev image, you can put it on your Gladys without breaking anything.
When you tell me everything is okay and I validate the release, you can then delete this version and update the official version.

To install a dev version, you need to go to Integration => Install from GitHub

Then, you click on Developer mode

In Docker Image, you put:

ghcr.io/william-de71/gladys-tapo:dev

And in the manifest:

{
  "manifest_version": 1,
  "type": "device",
  "name": "Tapo",
  "description": {
    "en": "Your Tapo cameras, doorbells, plugs, bulbs and hub sensors in Gladys.",
    "fr": "Vos caméras, sonnettes, prises, ampoules et capteurs Tapo dans Gladys."
  },
  "version": "1.2.5",
  "docker_image": "ghcr.io/william-de71/gladys-tapo:dev",
  "gladys_version": ">=5.0.0",
  "categories": [
    "security",
    "lighting",
    "energy"
  ],
  "cover_image": "https://raw.githubusercontent.com/William-De71/gladys-tapo/master/cover.jpg",
  "transports": [
    "local",
    "cloud"
  ],
  "network_discovery": [
    {
      "type": "udp-active-broadcast",
      "ports": [
        20002
      ]
    }
  ],
  "config_schema": [
    {
      "key": "intro",
      "type": "section",
      "label": {
        "en": "Getting started",
        "fr": "Pour commencer"
      },
      "description": {
        "en": "This integration finds your devices through your TP-Link cloud account, then talks to them on your local network. Enter your Tapo account below, then go to the Discover screen and run a scan: your devices appear there, ready to be added.\n\nGladys locates each device on your network by itself. If one is reported as not found (another subnet or VLAN, broadcast filtered by your router), use the \"Set a device IP address\" action at the bottom of this page: pick the device, type its address — it is shown in the Tapo app, under the device settings > Device info.",
        "fr": "Cette intégration retrouve vos appareils via votre compte cloud TP-Link, puis dialogue avec eux sur votre réseau local. Renseignez votre compte Tapo ci-dessous, puis allez dans l'écran Découverte et lancez un scan : vos appareils y apparaissent, prêts à être ajoutés.\n\nGladys localise chaque appareil sur votre réseau toute seule. Si l'un d'eux est signalé introuvable (autre sous-réseau ou VLAN, broadcast filtré par votre routeur), utilisez l'action « Définir l'adresse IP d'un appareil » en bas de cette page : choisissez l'appareil, tapez son adresse — elle est affichée dans l'application Tapo, dans les paramètres de l'appareil > Infos sur l'appareil."
      },
      "links": [
        {
          "url": "https://www.tapo.com/en/",
          "label": {
            "en": "Tapo website",
            "fr": "Site Tapo"
          }
        }
      ]
    },
    {
      "key": "email",
      "type": "string",
      "label": {
        "en": "Tapo account email",
        "fr": "E-mail du compte Tapo"
      },
      "description": {
        "en": "The email address of your TP-Link / Tapo account, the one you use in the Tapo app.",
        "fr": "L'adresse e-mail de votre compte TP-Link / Tapo, celle que vous utilisez dans l'application Tapo."
      },
      "placeholder": {
        "en": "you@example.com",
        "fr": "vous@exemple.com"
      },
      "required": true
    },
    {
      "key": "password",
      "type": "secret",
      "label": {
        "en": "Tapo account password",
        "fr": "Mot de passe du compte Tapo"
      },
      "description": {
        "en": "The password of your TP-Link / Tapo account. It is used to list your devices, to talk to your plugs, lights and hubs on your network, and, for cameras without RTSP, to open the local stream.",
        "fr": "Le mot de passe de votre compte TP-Link / Tapo. Il sert à lister vos appareils, à dialoguer avec vos prises, lampes et hubs sur votre réseau, et, pour les caméras sans RTSP, à ouvrir le flux local."
      },
      "required": true
    },
    {
      "key": "region",
      "type": "select",
      "label": {
        "en": "Cloud region",
        "fr": "Région du cloud"
      },
      "description": {
        "en": "The TP-Link cloud server closest to you. Change it only if the connection test fails.",
        "fr": "Le serveur cloud TP-Link le plus proche de vous. À changer uniquement si le test de connexion échoue."
      },
      "required": false,
      "default": "europe",
      "options": [
        {
          "value": "europe",
          "label": {
            "en": "Europe",
            "fr": "Europe"
          }
        },
        {
          "value": "america",
          "label": {
            "en": "America",
            "fr": "Amérique"
          }
        },
        {
          "value": "asia",
          "label": {
            "en": "Asia",
            "fr": "Asie"
          }
        },
        {
          "value": "default",
          "label": {
            "en": "Worldwide",
            "fr": "Mondial"
          }
        }
      ]
    },
    {
      "key": "rtsp_section",
      "type": "section",
      "label": {
        "en": "Camera account (RTSP and ONVIF)",
        "fr": "Compte caméra (RTSP et ONVIF)"
      },
      "description": {
        "en": "Cameras that expose an RTSP stream need the camera account you created in the Tapo app (Camera settings > Advanced settings > Camera account). It is also what unlocks ONVIF, which lets a camera report a motion the instant it happens instead of being polled. This is NOT your Tapo account, and it is created PER CAMERA. The simplest way to enter it: use the \"Save a camera account\" action at the bottom of this page, once per camera. The two fields below only serve as a default, for users who reused the same credentials everywhere.",
        "fr": "Les caméras exposant un flux RTSP nécessitent le compte caméra créé dans l'application Tapo (Paramètres de la caméra > Paramètres avancés > Compte de la caméra). C'est aussi lui qui débloque ONVIF, qui permet à une caméra de signaler un mouvement à l'instant où il se produit au lieu d'être interrogée. Ce n'est PAS votre compte Tapo, et il se crée PAR CAMÉRA. Le plus simple pour le renseigner : utilisez l'action « Enregistrer le compte d'une caméra » en bas de cette page, une fois par caméra. Les deux champs ci-dessous ne servent que de valeur par défaut, si vous avez réutilisé les mêmes identifiants partout."
      }
    },
    {
      "key": "rtsp_username",
      "type": "string",
      "label": {
        "en": "Default account username",
        "fr": "Identifiant du compte par défaut"
      },
      "description": {
        "en": "Used for every RTSP camera that has no specific account below.",
        "fr": "Utilisé pour toutes les caméras RTSP n'ayant pas de compte spécifique ci-dessous."
      },
      "required": false
    },
    {
      "key": "rtsp_password",
      "type": "secret",
      "label": {
        "en": "Default account password",
        "fr": "Mot de passe du compte par défaut"
      },
      "description": {
        "en": "Used for every RTSP camera that has no specific account below.",
        "fr": "Utilisé pour toutes les caméras RTSP n'ayant pas de compte spécifique ci-dessous."
      },
      "required": false
    },
    {
      "key": "camera_accounts",
      "type": "secret",
      "label": {
        "en": "Accounts per camera (advanced)",
        "fr": "Comptes par caméra (avancé)"
      },
      "description": {
        "en": "Prefer the \"Save a camera account\" action below: the accounts it saves are stored separately and do not appear here. Format, if you type here: cameras separated by a comma, each as `name|username|password` (a password containing a comma must go through the action).",
        "fr": "Préférez l'action « Enregistrer le compte d'une caméra » ci-dessous : les comptes qu'elle enregistre sont stockés à part et n'apparaissent pas ici."
      }
    }
  ]
}
```{
      "key": "cameras",
      "type": "string",
      "label": {
        "en": "Cameras",
        "fr": "Caméras"
      },
      "description": {
        "en": "Format, if you type here: cameras separated by a comma, each in the form `name|identifier|password` (a password containing a comma must go through the action).",
        "fr": "Format, si vous saisissez ici : caméras séparées par une virgule, chacune sous la forme `nom|identifiant|motdepasse` (un mot de passe contenant une virgule doit passer par l'action)."
      },
      "placeholder": {
        "en": "Garden camera|gladys|MyPassword, Living room|gladys|OtherPassword",
        "fr": "Camera_jardin|gladys|MonMotDePasse, Camera_salon|gladys|AutreMotDePasse"
      },
      "required": false
    },
    {
      "key": "stream_quality",
      "type": "select",
      "label": {
        "en": "Image quality",
        "fr": "Qualité de l'image"
      },
      "description": {
        "en": "HD gives a sharper image, SD is lighter and faster to capture.",
        "fr": "HD donne une image plus nette, SD est plus légère et plus rapide à capturer."
      },
      "required": false,
      "default": "HD",
      "options": [
        {
          "value": "HD",
          "label": {
            "en": "HD",
            "fr": "HD"
          }
        },
        {
          "value": "SD",
          "label": {
            "en": "SD",
            "fr": "SD"
          }
        }
      ]
    },
    {
      "key": "advanced",
      "type": "section",
      "label": {
        "en": "Advanced",
        "fr": "Avancé"
      },
      "description": {
        "en": "Only needed in particular cases: the integration finds your devices and their addresses by itself.",
        "fr": "Utile seulement dans des cas particuliers : l'intégration trouve vos appareils et leurs adresses toute seule."
      }
    },
    {
      "key": "camera_ips",
      "type": "string",
      "label": {
        "en": "Manual addresses (advanced)",
        "fr": "Adresses manuelles (avancé)"
      },
      "description": {
        "en": "Prefer the \"Set a device IP address\" action at the bottom of the page: you pick the device in a list, and Gladys checks the address answers. If you type here instead: entries separated by commas, each as `name|ip` (or `name=ip`). The name is matched without regard to case, accents, spaces or underscores, and may also be the device's MAC address.",
        "fr": "Préférez l'action « Définir l'adresse IP d'un appareil » en bas de la page : vous choisissez l'appareil dans une liste, et Gladys vérifie que l'adresse répond. Si vous saisissez ici : entrées séparées par des virgules, chacune sous la forme `nom|ip` (ou `nom=ip`). Le nom est comparé sans tenir compte des majuscules, accents, espaces ou tirets bas, et peut aussi être l'adresse MAC de l'appareil."
      },
      "placeholder": {
        "en": "Garden camera|192.168.1.42, Living room|192.168.1.43",
        "fr": "Caméra jardin|192.168.1.42, Salon|192.168.1.43"
      },
      "required": false
    },
    {
      "key": "event_poll_interval",
      "type": "number",
      "label": {
        "en": "Event check interval (s)",
        "fr": "Intervalle de vérification des événements (s)"
      },
      "description": {
        "en": "How often the integration checks for a doorbell press or a motion detection. A shorter interval reacts faster but talks to your cameras more often. Only affects cameras without ONVIF: cameras that support it push their events instantly, with nothing to wait for.",
        "fr": "Fréquence à laquelle l'intégration vérifie un appui sonnette ou une détection de mouvement. Un intervalle plus court réagit plus vite mais sollicite davantage vos caméras. Ne concerne que les caméras sans ONVIF : celles qui le proposent remontent leurs événements instantanément, sans attente."
      },
      "required": false,
      "default": 20,
      "min": 5,
      "max": 300
    },
    {
      "key": "device_poll_interval",
      "type": "number",
      "label": {
        "en": "Plugs, lights and sensors check interval (seconds)",
        "fr": "Intervalle de lecture des prises, lampes et capteurs (secondes)"
      },
      "description": {
        "en": "How often the plugs, lights and the sensors of a hub are read. These devices push nothing: a button press or a door opening reaches Gladys at the next read. Each read is one short request per device on your network.",
        "fr": "La fréquence à laquelle les prises, lampes et capteurs d'un hub sont lus. Ces appareils ne préviennent pas d'eux-mêmes : un appui sur un bouton ou l'ouverture d'une porte remonte à la lecture suivante. Chaque lecture est une courte requête par appareil sur votre réseau."
      },
      "required": false,
      "default": 5,
      "min": 2,
      "max": 300
    },
    {
      "key": "capture_timeout",
      "type": "number",
      "label": {
        "en": "Capture timeout (s)",
        "fr": "Délai de capture (s)"
      },
      "description": {
        "en": "How long a camera is given to deliver an image. Cameras using the proprietary protocol — battery models waking from deep sleep — need more time than an RTSP one. Above 14s the dashboard live view may time out first, but the scheduled refresh still succeeds.",
        "fr": "Temps accordé à une caméra pour fournir une image. Les caméras utilisant le protocole propriétaire — modèles sur batterie sortant de veille — ont besoin de plus de temps qu'une caméra RTSP. Au-delà de 14 s, la vue live du tableau de bord peut expirer avant, mais le rafraîchissement automatique aboutit quand même."
      },
      "required": false,
      "default": 14,
      "min": 5,
      "max": 60
    },
    {
      "key": "image_refresh_interval",
      "type": "number",
      "label": {
        "en": "Image refresh interval (s)",
        "fr": "Intervalle de rafraîchissement des images (s)"
      },
      "description": {
        "en": "How often a new image is captured for the dashboard, on MAINS-POWERED cameras only. Battery and solar cameras have their own setting below, so keeping your wired images fresh costs nothing to the others.",
        "fr": "Fréquence à laquelle une nouvelle image est capturée pour le tableau de bord, pour les caméras SUR SECTEUR uniquement. Les caméras sur batterie ou solaires ont leur propre réglage ci-dessous : garder vos images filaires fraîches ne coûte donc rien aux autres."
      },
      "required": false,
      "default": 60,
      "min": 15,
      "max": 3600
    },
    {
      "key": "battery_section",
      "type": "section",
      "label": {
        "en": "Battery protection",
        "fr": "Protection de la batterie"
      },
      "description": {
        "en": "Capturing images is what drains a battery or solar camera. These settings apply ONLY to battery and solar models — wired cameras keep their own interval and are never throttled. Once a camera goes below the pause limit, capturing only resumes at the recharge level: a partial recharge would restart the drain, and repeated shallow cycles wear the battery faster.",
        "fr": "La capture d'images est ce qui vide une caméra sur batterie ou solaire. Ces réglages s'appliquent UNIQUEMENT aux modèles sur batterie ou solaires — les caméras filaires gardent leur propre intervalle et ne sont jamais ralenties. Une fois passée sous la limite de pause, la capture ne reprend qu'au niveau de recharge : une recharge partielle relancerait la décharge, et les cycles courts répétés usent la batterie plus vite."
      }
    },
    {
      "key": "battery_image_refresh_interval",
      "type": "number",
      "label": {
        "en": "Battery camera refresh interval (s)",
        "fr": "Intervalle de rafraîchissement des caméras sur batterie (s)"
      },
      "description": {
        "en": "How often a battery or solar camera is captured, independently of your wired cameras. Waking a camera up is what costs the battery, so this is the single most effective setting: 900s (15 min) lets a solar panel refill between two captures. Lower it only if your cameras recharge faster than they discharge.",
        "fr": "Fréquence à laquelle une caméra sur batterie ou solaire est capturée, indépendamment de vos caméras filaires. C'est le réveil de la caméra qui coûte de la batterie : ce réglage est donc le plus efficace de tous. 900 s (15 min) laisse à un panneau solaire le temps de recharger entre deux captures.[quote="alice, post:3, topic:42"]
How do I get started?
[/quote]

We're so glad you're here! Want to run your own Minecraft server? Just click the Get Started button below — it's easy.. Leave both fields empty to delete."
      },
      "timeout_seconds": 60,
      "fields": [
        {
          "key": "device",
          "type": "select",
          "source": "devices",
          "label": {
            "en": "Camera",
            "fr": "Caméra"
          },
          "description": {
            "en": "Only devices already added from the Discover screen are listed.",
            "fr": "Seuls les appareils déjà ajoutés depuis l'écran Découverte sont listés."
          },
          "required": true
        },
        {
          "key": "username",
          "type": "string",
          "label": {
            "en": "Camera account username",
            "fr": "Identifiant du compte caméra"
          },
          "description": {
            "en": "The username you set in the Tapo app, under Camera settings > Advanced settings > Camera account.",
            "fr": "L'identifiant défini dans l'application Tapo, sous Paramètres de la caméra > Paramètres avancés > Compte de la caméra."
          },
          "required": false
        },
        {
          "key": "password",
          "type": "string",
          "label": {
            "en": "Camera account password",
            "fr": "Mot de passe du compte caméra"
          },
          "description": {
            "en": "The matching password. It is stored encrypted with the other secrets; only this input box shows it as you type.",
            "fr": "Le mot de passe correspondant. Il est stocké chiffré avec les autres secrets ; seule cette case le montre pendant la saisie."
          },
          "required": false
        }
      ]
    },
    {
      "key": "refresh_images",
      "label": {
        "en": "Refresh the images",
        "fr": "Rafraîchir les images"
      },
      "timeout_seconds": 120
    }
  ]
}

So you end up with the integration of Dev in the store.

I tested this devt version and I approve the new UX for automatically detecting IPs :+1:. It’s great

There’s just maybe one little thing: a PTZ camera displayed on my dashboard has the following rendering on my iPhone when I switch to ‹ live › mode (I’m not at home to check if it’s the same on a computer…):

Is it possible to:

  • hide the ‹ play › button (since playback is already in progress)
  • move the movement cross to a corner of the image so it doesn’t interfere with the central view
  • reduce the height of the area below the image

ok I’ll check tomorrow.
thanks for your feedback.

@StephaneB, I’m afraid I can’t do anything as I don’t manage the camera widget since the integration.

I’ll move/copy your post to a dedicated topic to see what we can do on the Gladys core.

:tada: gladys-tapo 2.0.0 is available

Thanks to @StephaneB and @JKBS64 for your feedback

:sparkles: New Features

  • Plugs, multi-plugs, bulbs, switches, and sensors from the H100 hub: in addition to cameras and doorbells, the integration now manages the rest of the Tapo range locally (on/off, power and energy in kWh, brightness, color, white temperature, hub sensors…).
  • Reliable IP detection: each device is found on the network via its MAC address. If one of them is not found (other VLAN, filtered broadcast), the new action « Set a device’s IP address » allows you to choose it from a list and enter its address. Gladys immediately checks if it responds.
  • « Test connection » displays a line per device: its address, where it comes from, and what to do if it’s missing.
  • « Save a camera account »: the camera account (RTSP/ONVIF) is entered camera by camera in a small form, without syntax to remember.
  • Standard Gladys private mode (camera/enabled) instead of the old « privacy » switch.
  • Manual capture button for battery-powered cameras.
  • Interface translated into 4 languages: French, English, German, and Spanish, including documentation.
  • More robust: ONVIF subscriptions renewed, better recovery after a Gladys restart, doorbells better detected, protection against network freezes.

:warning: Before updating

  • Gladys 5.0 minimum is required.
  • Private mode: after updating a camera from the Discovery screen, the old « privacy » switch is replaced by the « Enabled » control, whose values are inverted (1 = active camera). Think to adapt your scenes that used the old switch.
  • Camera accounts and addresses already entered in the text fields continue to work.

:open_book: Full documentation and changelog: Release v2.0.0 · William-De71/gladys-tapo · GitHub

Don’t hesitate to give me your feedback, especially if you have plugs, bulbs, or an H100 hub: this part has not yet been tested on real hardware! :folded_hands: