Core: camera.local_file_update_file_path only updates one camera

Created on 24 Feb 2019  路  12Comments  路  Source: home-assistant/core

Home Assistant release with the issue: 0.88.1

Last working Home Assistant release (if known): Unknown

Operating environment (Hass.io/Docker/Windows/etc.): Python Virtual Environment - Centos 7

Component/platform: https://www.home-assistant.io/components/camera.local_file/

Description of problem:
Same issue as https://github.com/home-assistant/home-assistant/issues/14532

Node-RED calls to camera.local_file_update_file_path appears to only update the first camera updated.

Problem-relevant configuration.yaml entries and (fill out even if it seems unimportant):

camera:
  - platform: local_file
    name: "Carport"
    file_path: /srv/homeassistant/.homeassistant/Blank.jpg

  - platform: local_file
    name: "Master Bath Door"
    file_path: /srv/homeassistant/.homeassistant/Blank.jpg

  - platform: local_file
    name: "Drive Gate"
    file_path: /srv/homeassistant/.homeassistant/Blank.jpg

  - platform: local_file
    name: "Front Door"
    file_path: /srv/homeassistant/.homeassistant/Blank.jpg

Traceback (if applicable):


Additional information:

Here is the Node-RED flow making the call:

[
    {
        "id": "5bb78d64.9c6cc4",
        "type": "change",
        "z": "149e5773.99ecf9",
        "name": "Set Filename",
        "rules": [
            {
                "t": "set",
                "p": "filename",
                "pt": "msg",
                "to": "topic",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 510,
        "y": 140,
        "wires": [
            [
                "11c03854.6c2e38",
                "371f061e.7c91ba"
            ]
        ]
    },
    {
        "id": "11c03854.6c2e38",
        "type": "string",
        "z": "149e5773.99ecf9",
        "name": "Generate Image Filename",
        "methods": [
            {
                "name": "getRightMost",
                "params": [
                    {
                        "type": "str",
                        "value": "/"
                    }
                ]
            },
            {
                "name": "replaceAll",
                "params": [
                    {
                        "type": "str",
                        "value": " "
                    },
                    {
                        "type": "str",
                        "value": "_"
                    }
                ]
            },
            {
                "name": "ensureLeft",
                "params": [
                    {
                        "type": "str",
                        "value": "/srv/homeassistant/.homeassistant/www/"
                    }
                ]
            }
        ],
        "prop": "filename",
        "propout": "filename",
        "object": "msg",
        "objectout": "msg",
        "x": 730,
        "y": 140,
        "wires": [
            [
                "18c00627.ec3f2a"
            ]
        ]
    },
    {
        "id": "18c00627.ec3f2a",
        "type": "file",
        "z": "149e5773.99ecf9",
        "name": "Save Image",
        "filename": "",
        "appendNewline": false,
        "createDir": false,
        "overwriteFile": "true",
        "x": 950,
        "y": 140,
        "wires": [
            []
        ]
    },
    {
        "id": "cf763c92.0d785",
        "type": "string",
        "z": "149e5773.99ecf9",
        "name": "Determine Camera",
        "methods": [
            {
                "name": "getRightMost",
                "params": [
                    {
                        "type": "str",
                        "value": "/"
                    }
                ]
            },
            {
                "name": "delRightMost",
                "params": [
                    {
                        "type": "str",
                        "value": "_01"
                    }
                ]
            },
            {
                "name": "replaceAll",
                "params": [
                    {
                        "type": "str",
                        "value": " "
                    },
                    {
                        "type": "str",
                        "value": "_"
                    }
                ]
            }
        ],
        "prop": "topic",
        "propout": "camera",
        "object": "msg",
        "objectout": "msg",
        "x": 310,
        "y": 140,
        "wires": [
            [
                "5bb78d64.9c6cc4"
            ]
        ]
    },
    {
        "id": "e9ca92a.32b557",
        "type": "api-call-service",
        "z": "149e5773.99ecf9",
        "name": "Update Camera Filename",
        "server": "bd0ac36a.ed0df",
        "service_domain": "camera",
        "service": "local_file_update_file_path",
        "data": "{\"entity_id\":\"camera.{{camera}}\",\"file_path\":\"/srv/homeassistant/.homeassistant/www/{{filename}}\"}",
        "render_data": true,
        "mergecontext": "",
        "output_location": "",
        "output_location_type": "none",
        "x": 990,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "371f061e.7c91ba",
        "type": "string",
        "z": "149e5773.99ecf9",
        "name": "Generate Image Filename",
        "methods": [
            {
                "name": "getRightMost",
                "params": [
                    {
                        "type": "str",
                        "value": "/"
                    }
                ]
            },
            {
                "name": "replaceAll",
                "params": [
                    {
                        "type": "str",
                        "value": " "
                    },
                    {
                        "type": "str",
                        "value": "_"
                    }
                ]
            }
        ],
        "prop": "filename",
        "propout": "filename",
        "object": "msg",
        "objectout": "msg",
        "x": 730,
        "y": 200,
        "wires": [
            [
                "e9ca92a.32b557",
                "e7d2eab8.a7d658"
            ]
        ]
    },
    {
        "id": "e7d2eab8.a7d658",
        "type": "debug",
        "z": "149e5773.99ecf9",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "x": 930,
        "y": 260,
        "wires": []
    },
    {
        "id": "bd0ac36a.ed0df",
        "type": "server",
        "z": "",
        "name": "Home Assistant",
        "legacy": false,
        "hassio": false,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open"
    }
]

One example of a payload (truncated):

{  
   "topic":"/2019/02/23/Drive Gate_01_20190223220623.jpg",
   "payload":[  ],
   "_msgid":"e0ce20cf.465a2",
   "camera":"Drive_Gate",
   "filename":"Drive_Gate_01_20190223220623.jpg"
}

Second example with a different camera (truncated):

{  
   "topic":"/2019/02/23/Carport_01_20190223220626.jpg",
   "payload":[  ],
   "_msgid":"5f2eb03b.04e01",
   "camera":"Carport",
   "filename":"Carport_01_20190223220626.jpg"
}

Both examples updated the camera.drive_gate.file_path

bug local_file stale

All 12 comments

@Landrash Something you can help with?

The component was rewritten after my contribution so I'm not of any help.

Just viewing the example I would try to replicate it on a simpler basis to do some further testing without Node Red since this isn't a setup I even imagined .

I did a bit more debugging; it's pretty simple to reproduce.

  1. Create two local_filecameras, each with a unique path
  2. Make a manual service call to CAMERA.LOCAL_FILE_UPDATE_FILE_PATH, specifying the first camera and a new file path--it will be updated as expected.
  3. Make a manual service call to CAMERA.LOCAL_FILE_UPDATE_FILE_PATH, specifying the second camera and a secondary file path--the first camera path is updated with the file path in the second call.

The problem seems to be related to the following code:

    def update_file_path_service(call):
        """Update the file path."""
        file_path = call.data.get(CONF_FILE_PATH)
        camera.update_file_path(file_path)
        return True

In the context, the camera object is not related in any way to the entity_id in the call. I know almost nothing about coding in HASS but I did do a fair amount of debugging and once the first call came through to update a file path, that was the camera that was updated each time thereafter, no matter which entity_idwas specified.

Blame @robmarkcole

Hello,

I reproduct this bug.
i'm Update file_path by API.

curl -X POST -H "Authorization: Bearer xxxxx " -H "Content-Type: application/json" -d '{"entity_id": "camera.2cam", "file_path": "/home/homeassistant/.homeassistant/www/cameras/cam1/01_20190308090536.jpg"}' https://xxxx:8123/api/services/camera/local_file_update_file_path

Result :

[{"attributes": {"access_token": "xxxx", "entity_picture": "/api/camera_proxy/camera.1cam?token=xxxx", "file_path": "/home/homeassistant/.homeassistant/www/cameras/cam1/01_20190308090536.jpg", "friendly_name": "1cam", "supported_features": 0}, "context": {"id": "da1d219fa63d4ccbbd7ebf6d9208fcd5", "parent_id": null, "user_id": null}, "entity_id": "camera.1cam", "last_changed": "2019-03-27T22:21:12.353680+00:00", "last_updated": "2019-03-27T22:22:23.731442+00:00", "state": "idle"}]

In result entity_id is camera.1cam and not camera.2cam send in POST

Regards

@robmarkcole Are there any plans to look into this issue? It's simple to reproduce at this point. Obviously, I have no idea how complex it is to fix outside knowing it's beyond my capabilities.

If not, I get it; however, having this work would make dealing with multiple camera feeds and Tensorflow much easier when motion is handled externally and just a static JPEG is being handed off.

Thanks for your attention.

@ratsputin I had a quick look, and don't see anything obvious. I could easily spend half to a full day chasing and fixing this and I just don't have the bandwidth at the moment.

@robmarkcole Thanks so much for taking a quick look at this. You saved me beating my head against the wall trying to track down the issue with my limited knowledge. I'll work around this with a more brute-force method.

Cheers!

Proposed solution: check camera.entity_id before update.

UPDATE: done this and discovered that the camera.entity_id attr is NOT CORRECT when I have multiple cameras. Below I call the service with data for camera.local_file, _2, _3 but the camera.entity_id is ALWAYS camera.local_file_3

2019-04-27 16:21:48 WARNING (SyncWorker_18) [homeassistant.components.local_file.camera] XXX UPDATE ENTITY: ['camera.local_file']
2019-04-27 16:21:48 WARNING (SyncWorker_18) [homeassistant.components.local_file.camera] XXX camera.entity_id : camera.local_file_3
2019-04-27 16:25:53 WARNING (SyncWorker_19) [homeassistant.components.local_file.camera] XXX UPDATE ENTITY: ['camera.local_file_2']
2019-04-27 16:25:53 WARNING (SyncWorker_19) [homeassistant.components.local_file.camera] XXX camera.entity_id : camera.local_file_3
2019-04-27 16:26:04 WARNING (SyncWorker_6) [homeassistant.components.local_file.camera] XXX UPDATE ENTITY: ['camera.local_file_3']
2019-04-27 16:26:04 WARNING (SyncWorker_6) [homeassistant.components.local_file.camera] XXX camera.entity_id : camera.local_file_3
2019-04-27 16:26:04 WARNING (SyncWorker_6) [homeassistant.components.local_file.camera] updating entity XXX

The service should get the correct camera object like here, can reuse facebox approach

OK the following appears to resolve this issue:

def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Camera that works with local files."""
    if DATA_LOCAL_FILE not in hass.data:
        hass.data[DATA_LOCAL_FILE] = []

    file_path = config[CONF_FILE_PATH]
    camera = LocalFile(config[CONF_NAME], file_path)
    hass.data[DATA_LOCAL_FILE].append(camera)

    def update_file_path_service(call):
        """Update the file path."""
        file_path = call.data.get(CONF_FILE_PATH)
        entity_ids = call.data.get(ATTR_ENTITY_ID)
        cameras = hass.data[DATA_LOCAL_FILE]

        for camera in cameras:
            if camera.entity_id in entity_ids:
                camera.update_file_path(file_path)
        return True

All changes here @ratsputin can you try this modified file?

@robmarkcole Yes, this is brilliant! It absolutely fixed the issue; thanks so much!

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.
Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 馃憤
This issue now has been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

flsabourin picture flsabourin  路  3Comments

kirichkov picture kirichkov  路  3Comments

moskovskiy82 picture moskovskiy82  路  3Comments

coolriku picture coolriku  路  3Comments

MartinHjelmare picture MartinHjelmare  路  3Comments