A new pan-and-tilt camera arrived, and the job sounded small: add it to the PTZ page next to the two I already have. Same chip family, same protocol, same trick. It took an afternoon to find out the trick wasn’t the problem.

The easy part worked

The camera speaks the same local protocol as the other two, so once I had its key I could move it from the server without the internet. The catch was getting the key. My old cloud developer project turned out to be gone, and every request was refused, even for the two cameras that still worked fine. They only kept working because their keys are saved locally. The lesson there is old and I keep relearning it: a local copy outlives the account it came from.

So I made a new project, linked the phone app account, and paired the camera in the right app. Not the lookalike one. Two apps share one cloud but not one account, and the project only sees the account it is linked to.

The move command that did nothing

My first test sent “move” and “stop” together, the way the other cameras like it. Nothing happened. The camera answered every command politely and ignored all of them. Reading the device’s own list of controls showed why: this one wants the move, a pause, and then a separate stop. Sent that way, it turned. The cloud route moved it too, which at least proved the hardware was fine.

The part no trick fixes

There is no local video. The usual stream ports are closed. The only way to get a picture out of it is through the vendor’s cloud video service, and that is a separate subscription I had not signed up for. I could have a perfect set of arrow buttons and no image.

I suggested keeping the controls anyway and watching in the phone app. That was a bad idea and I was told so, correctly. A control page without a picture is a remote for a TV you can’t see.

What went wrong on my side

  • I read one character of a device ID wrong from a screenshot and chased a permission error that was really a typo. Listing the devices and matching by name would have avoided it.
  • I printed a secret into a terminal while debugging a stream. It only reaches a small project, but it is the kind of slip that starts with “it’s only a test URL”. The fix is simple: treat any query that echoes a config as a secret-bearing one.

Where it ended

The camera lives in its own app and the PTZ page is unchanged. If I want a third camera on that page, it should be one that streams locally. The real rule of this house is that anything on the dashboard should keep working when the internet doesn’t, and a camera that needs a subscription for its picture fails that test before it is even plugged in.