Amcrest IP Camera Component Enhancements - PTZ control and audio streaming

Well, first, even though the PR was accepted and merged, there’s now a suggestion for further changes. Not sure how that will go.

But, assuming this does eventually get fully merged, I have no idea if/when it will make it into an actual HA release. Also, if it does make a HA release, it will be part of the standard product, so there won’t be a need for an add-on or a custom component. Of course, I’ve only submitted a small part of all the enhancements I’ve made to the component so far. There’s no way to predict if they’ll accept all, or even any, of the PRs I still plan to submit with additional incremental improvements. So, in the mean time, at least I’m still using my custom component. :slight_smile:

1 Like

So far two PRs (21664 & 21720) have been submitted and accepted into HA’s dev branch. They serialize snapshot commands using a lock. They also bump the amcrest package to version 1.2.5. Together these changes should fix issues I believe have been around quite some time when using snapshot as the stream_source, which is the default.

Note that version 1.2.4 of the amcrest package was removed from pypi.org since it had a potential threading issue with requests.Session. If you happen to have an interim version of my custom amcrest HA component that points at 1.2.4, you should update to the latest.

These changes did not make the 0.89 release. If/when they make a HA release, I’ll post an update here.

UPDATE: Looks like the PRs made it into 0.90.0b0.

I’ve also updated my github repo accordingly.

The next HA PR I’m thinking of working on is to add the binary_sensor and at least deprecate the motion detector sensor, since the binary_sensor takes its place. I’m also thinking of removing the following attributes from the sensor components:

Build Date
Version
Serial Number

and adding comparable ones to the camera component.

If anyone has a preference as to whether that should be the next change submitted or something else, please let me know.

2 Likes

Thanks very much for the 1.2.5 update notice. I had only very recently changed from using rtsp to snapshot to see if there would be any performance improvement over a slow ISP/WAN connection, but I really can’t tell much difference.

Do you save video to an sdcard in your Amcrest cameras created from motion triggers? If so, what app or technique do you use to retrieve them for a specific alert?

The change from 1.2.3 to 1.2.5 in the amcrest package really only had to do with error handling. If the maximum number of retries was exceeded on a command transfer, the old version would not raise an exception but, e.g., the returned snapshot would just be empty.

The improvements in the snapshot handling were done in the HA amcrest component. If you’re using my latest custom component (just checked in), then you should have those changes. Or, if you’re using the standard component, you can get the updates from HA’s dev branch. These make sure that multiple threads attempting to get a snapshot from the camera don’t step on each other’s toes, resulting in errors that can slow things down. There can be (at least) three threads – the “thumbnail” picture on the frontend, the full picture in the “window” that appears “above” the thumbnail when you click on it, and a call to the camera.snapshot service, say in an automation.

I used to use motion detection in the cameras, and I had them set up to send an e-mail to me when motion was detected, strictly outside of HA. Inside HA I did use the binary_sensor to do other things when the cameras detected motion.

But now I use PIR sensors for motion detection, because it was just too difficult to get the camera motion detection to work well in all situations. So to get the snapshots now I came up with a combination of things, resulting in local_file cameras displaying the latest snapshot from each camera.

Here is part of the implementation from a package file:

camera:
  - platform: local_file
    name: LR IPC Last Motion
    file_path: /home/homeassistant/.homeassistant/snapshots/lr_ipc_motion_last.jpg
  - platform: local_file
    name: HF IPC Last Motion
    file_path: /home/homeassistant/.homeassistant/snapshots/hf_ipc_motion_last.jpg

shell_command:
  update_snaps: python3 /home/homeassistant/.homeassistant/update_snaps.py

automation:
  - alias: Foyer Snapshot
    trigger:
      - platform: numeric_state
        entity_id: sensor.foyer_burglar
        above: 0
    condition:
      - condition: template
        value_template: >
          {{ states('camera.lr_ipc') in ('streaming', 'recording') }}
    action:
      - wait_template: "{{ is_state('script.snap', 'off') }}"
      - service: script.snap
        data:
          camera: lr

  - alias: House Front Snapshot
    trigger:
      - platform: state
        entity_id: binary_sensor.hf_motion
        to: 'on'
    action:
      - wait_template: "{{ is_state('script.snap', 'off') }}"
      - service: script.snap
        data:
          camera: hf

script:
  snap:
    sequence:
      - service: camera.snapshot
        data_template:
          entity_id: camera.{{ camera }}_ipc
          filename: >
            /home/homeassistant/.homeassistant/snapshots/{{
              camera
            }}_ipc_motion_{{
              utcnow().strftime('%Y%m%d_%H%M%S')
            }}.jpg
      - service: shell_command.update_snaps

And here’s update_snaps.py:

#!/usr/bin/env python3

from glob import glob
import os


MAX_SNAPS = 25
SNAPS_DIR = '/home/homeassistant/.homeassistant/snapshots'
SNAPS = [('lr_ipc_motion_[0-9]*.jpg', 'lr_ipc_motion_last.jpg'),
         ('hf_ipc_motion_[0-9]*.jpg', 'hf_ipc_motion_last.jpg')]


for snap in SNAPS:
    snap_list = sorted(glob(os.path.join(SNAPS_DIR, snap[0])))
    snap_link = os.path.join(SNAPS_DIR, snap[1])
    try:
        os.remove(snap_link)
    except:
        pass
    if snap_list:
        os.symlink(snap_list[-1], snap_link)
        for f in snap_list[:-MAX_SNAPS]:
            os.remove(f)
    else:
        os.symlink('no_image.jpg', snap_link)

I’m in the process of updating this script so I can scroll through the available snapshots for each camera with buttons in the frontend, but that’s not ready for prime time yet. :slight_smile:

EDIT: I changed the file name timestamp from local time to UTC. It wasn’t an issue when going to DST, but it would have been later this year when coming from DST!

@pnbruckner great work so far!! you should expect to see both PR’s in the next beta that gets cut on Wednesday. Basically anything merged into dev before the first beta is cut will make it into that release, if the beta was already cut then the code change will be in the next release.

If you are submitting a code change that is a direct fix to an issue introduced by a previous code change (in master) you can comment in the new PR to include it in the next hot fix. They are pretty good about getting those fixes out :slight_smile:

Personally I am in favor of switching the sensor to a binary_sensor and also removing the build version etc…

Looking forward to the continued improvement!!

1 Like

Thanks for all the clarifications @pnbruckner - that was quite helpful.

I also appreciate the detail in how you are handling motion events. You’ve given me quite a bit to chew on. I was not familiar with this local_file camera platform at all.

Thanks!

1 Like

FYI, I’m done updating my custom amcrest component to be compatible with the latest & greatest (which is discussed a bit more above.) I’ve just now made a few more minor changes and updated custom_components.json so it can be installed via custom_updater. The “element” name is “amcrest”, and that’s all you need to install via custom_updater – that one install will load all the files into custom_components/amcrest. This requires the use of HA version 0.86 or later.

3 Likes

Thanks for this Phil!!

Hi all! (@danny, sorry for stealing your topic! :blush:)

I released a new version of the amcrest pypi.org package (1.3.0) that adds some commands that used to be in my custom component. It also fixes (or hopefully fixes) a bug related to retrieving storage usage information when no SD card is present (or possibly when it’s not formatted as well.) I’m getting ready to submit I’ve submitted the next batch of changes to HA’s amcrest component (see PR #22418), and I’ve updated my custom component accordingly as well. The updated custom component is available via my PR #122 if anyone would like to try it out before I release it.

1 Like

So @pnbruckner do how do I run the ptz preset.

I see command service_goto_present. Just curious if you could help.

First you need to define the preset. I did that for my cameras by using their web interface. Then you can do this:

service: camera.amcrest_goto_preset
entity_id: camera.xxx
data:
  preset: 1

This service, so far, is only in my custom component. I hope to eventually submit it as part of the standard component, but first my latest set of changes need to be accepted, and then there is probably one or two other small sets of changes I want to submit before getting to adding the new services.

If I don’t see amcrest_goto_present in the services does that mean I need to update amcrest files?

Are you using my custom component? If so, that has pretty much always been there. If you’re using the standard component, then as I said, it hasn’t been added yet.

EDIT: If you would like to use my custom component, but don’t know how to, let me know.

Where did you enter that command at? I see set_preset now. I have present on camera ready. Just issues calling present within hassio

Sorry, I’m not following you.

If you’re using my custom component (i.e., placed copies of the files from my github repo into <config>/custom_components/amcrest), then on the Services page, you should see a camera.amcrest_goto_preset service listed, and you can call it from there if you like.

What I showed above would be how you’d call it from a script or automation.

See image. This is the script.

Hi Phil/@pnbruckner -

I’ve got your latest PR #122 amcrest code installed, and in my first test, I added the -sdcard sensor to a camera with NO sdcard installed.

The first issue is the code got into a relatively tight loop trying to getDeviceAllInfo and in a very sort while, generated 100’s of duplicate errors/attempts…

Query failed due to error 400 Client Error: Bad Request for url: http://192.168.2.21:80/cgi-bin/storageDevice.cgi?action=getDeviceAllInfo
10:34 AM deps/lib/python3.7/site-packages/amcrest/http.py (ERROR) - message first occured at 10:19 AM and shows up 575 times

Trying again due to error 400 Client Error: Bad Request for url: http://192.168.2.21:80/cgi-bin/storageDevice.cgi?action=getDeviceAllInfo
10:34 AM deps/lib/python3.7/site-packages/amcrest/http.py (WARNING) - message first occured at 10:19 AM and shows up 575 times

So clearly, the Dahua/Amcrest firmware has no error checking in this situation. I suggest first determining what storage is actually available in the camera first, via:

10.2.1 GetStorageDeviceCollect
URL Syntax http:// <ip> /cgi-bin/storageDevice.cgi?action=factory.getCollect
Comment: Get all the storage device names

Response: A list of all device names:
list[0]=”/dev/sda0”
list[1]=”/dev/sda1”
list[2]=”/dev/sg1”

This will return NOTHING (with no errors) if the camera has no sdcard installed. (Note: for my NVR, this command returned: list[0]=/dev/sda

There’s something else weird going on here. I’ll have to do some testing when I get home and can remove the SD card from one of my cameras. It should definitely not be trying to send that command that often, even if it does fail. If the camera doesn’t like that command and returns error 400, you should only see one warning and one error per sensor update, and the sensor should just have ‘unknown’ values.

So are you saying this is worse than it was before?

Oh, you’re using the automation editor. I don’t, but I would think the service data should be {preset: 4}.

yep. It didn’t get into a tight retry loop before (using either an earlier version of your custom component or the standard one).

EDIT: The sensor is actually being created with some known and unknown values…

sensor.north_drive_camera_sd_used unknown
Build Date: build:2018-05-23

Version: 2.640.0000002.0.R
Serial Number: xxxxxx0C8153
Total: unknown GB
Used: unknown GB
unit_of_measurement: %
friendly_name: North Drive Camera_SD Used
icon: mdi:mdi:sd