I wanted a matrix that would work on a dash, mobile, or tablet. This matrix is setup for ten cameras. The large view is hidden from the selection view when displayed.
Every 10 seconds the large view rotates. If you click on any camera in the selection view it will halt the patrol for 45 second and then resume.
Mobile view
Dash full page view
First you will need to install the conditional card from hacs.
You will need to create a counter. Name the counter frontend_cams
if you want to use the entity included with code provided. Use 1 through how ever many cams you want to use. For the setup shown it would be 1 to 10.
Individual card
type: vertical-stack
cards:
- type: vertical-stack
cards:
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 0.9
below: 1.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_mailbox_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 1.9
below: 2.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_front_step_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 2.9
below: 3.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_front_garden_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 3.9
below: 4.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_first_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 4.9
below: 5.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_second_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 5.9
below: 6.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_third_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 6.9
below: 7.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_laundry_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 7.9
below: 8.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_shop_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 8.9
below: 9.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_middle_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 9.9
below: 10.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_back_yard_main
aspect_ratio: 16 x 9
- square: false
type: grid
cards:
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 1
- condition: numeric_state
entity: counter.frontend_cams
above: 1
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_mailbox_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 1
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 2
- condition: numeric_state
entity: counter.frontend_cams
above: 2
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_front_step_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 2
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 3
- condition: numeric_state
entity: counter.frontend_cams
above: 3
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_front_garden_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 3
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 4
- condition: numeric_state
entity: counter.frontend_cams
above: 4
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_first_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 4
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 5
- condition: numeric_state
entity: counter.frontend_cams
above: 5
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_second_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 5
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 6
- condition: numeric_state
entity: counter.frontend_cams
above: 6
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_third_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 6
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 7
- condition: numeric_state
entity: counter.frontend_cams
above: 7
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_laundry_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 7
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 8
- condition: numeric_state
entity: counter.frontend_cams
above: 8
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_shop_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 8
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 9
- condition: numeric_state
entity: counter.frontend_cams
above: 9
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_middle_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 9
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 10
- condition: numeric_state
entity: counter.frontend_cams
above: 10
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_back_yard_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 10
aspect_ratio: 16 x 9
columns: 3
Full page
type: horizontal-stack
cards:
- square: false
type: grid
cards:
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 1
- condition: numeric_state
entity: counter.frontend_cams
above: 1
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_mailbox_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 1
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 2
- condition: numeric_state
entity: counter.frontend_cams
above: 2
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_front_step_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 2
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 3
- condition: numeric_state
entity: counter.frontend_cams
above: 3
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_front_garden_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 3
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 4
- condition: numeric_state
entity: counter.frontend_cams
above: 4
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_first_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 4
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 5
- condition: numeric_state
entity: counter.frontend_cams
above: 5
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_second_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 5
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 6
- condition: numeric_state
entity: counter.frontend_cams
above: 6
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_third_floor_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 6
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 7
- condition: numeric_state
entity: counter.frontend_cams
above: 7
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_laundry_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 7
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 8
- condition: numeric_state
entity: counter.frontend_cams
above: 8
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_shop_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 8
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 9
- condition: numeric_state
entity: counter.frontend_cams
above: 9
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_middle_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 9
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: or
conditions:
- condition: numeric_state
entity: counter.frontend_cams
below: 10
- condition: numeric_state
entity: counter.frontend_cams
above: 10
card:
camera_view: auto
type: picture-glance
entities: []
camera_image: camera.xvr_back_yard_main
tap_action:
action: call-service
service: counter.set_value
target:
entity_id: counter.frontend_cams
data:
value: 10
aspect_ratio: 16 x 9
columns: 3
- type: vertical-stack
cards:
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 0.9
below: 1.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_mailbox_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 1.9
below: 2.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_front_step_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 2.9
below: 3.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_front_garden_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 3.9
below: 4.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_first_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 4.9
below: 5.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_second_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 5.9
below: 6.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_third_floor_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 6.9
below: 7.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_laundry_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 7.9
below: 8.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_shop_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 8.9
below: 9.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_middle_main
aspect_ratio: 16 x 9
- type: conditional
conditions:
- condition: numeric_state
entity: counter.frontend_cams
above: 9.9
below: 10.1
card:
camera_view: live
type: picture-glance
entities: []
camera_image: camera.xvr_back_yard_main
aspect_ratio: 16 x 9
That will give you the cards, now the automation, I apologize I am not very well versed in jinga so I can only supply a nodered version. I will give you the steps on how the automation should be setup.
-
A time based automation that every 10 seconds (adjust this for how fast the main image changes) calls the service
counter.increment
forcounter.frontend_cams
-
When the counter reaches 10 use
counter.reset
to return to 1 -
You will need to create a binary sensor from an event action This entity will be used as a condition, this entity must be off for the counter to increment. How long you set this sensor to stay on, is how long the main screen will hold the selected camera.
Event you are looking for:
{
"domain": "counter",
"service": "set_value",
"service_data": {
"entity_id": [
"counter.frontend_cams"
]
}
}
Nodered users. To adjust the time of patrol, change time in the inject node. For how long the the main screen will hold when selected change time value in trigger node.
If you need to adjust the count of cameras, open the function node, where you see count === 10
change 10 to the total number of cameras.
[{"id":"6d333ecfbab3a392","type":"function","z":"60f2d2277843c698","name":"function 6","func":"var count = context.get(\"fccount\" || 1 );\n\nmsg = {};\n\nif( count === 10 ) {\n count = 1;\n msg.payload = {\n \"domain\": \"counter\",\n \"service\": \"reset\",\n // \"target\": {\n // \"entity_id\": \"input_number.frontend_cams\",\n // }\n }\n} else {\n count += 1;\n msg.payload = {\n \"domain\": \"counter\",\n \"service\": \"increment\",\n // \"target\": {\n // \"entity_id\": \"input_number.frontend_cams\"\n // }\n }\n};\n\ncontext.set(\"fccount\", count); //store it\nnode.status({ text: count });\n\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":340,"wires":[["330998b81649d1fb"]]},{"id":"a8097c8b69bfcc8d","type":"inject","z":"60f2d2277843c698","name":"patrol time","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":750,"y":340,"wires":[["6d333ecfbab3a392"]]},{"id":"a702397e9ab9d11f","type":"api-call-service","z":"60f2d2277843c698","name":"","server":"6b1110b5.183a4","version":5,"debugenabled":false,"domain":"","service":"","areaId":[],"deviceId":[],"entityId":["counter.frontend_cams"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1310,"y":340,"wires":[[]]},{"id":"824e94f10f3a28d0","type":"server-events","z":"60f2d2277843c698","name":"","server":"6b1110b5.183a4","version":3,"exposeAsEntityConfig":"","eventType":"call_service","eventData":"{\"domain\":\"counter\",\"service\":\"set_value\",\"service_data\":{\"entity_id\":[\"counter.frontend_cams\"]}}","waitForRunning":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"}],"x":710,"y":260,"wires":[["b662f7bd1bdce176"]]},{"id":"b662f7bd1bdce176","type":"trigger","z":"60f2d2277843c698","name":"hold main screen","op1":"stop","op2":"allow","op1type":"str","op2type":"str","duration":"45","extend":true,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":920,"y":260,"wires":[["330998b81649d1fb"]]},{"id":"330998b81649d1fb","type":"traffic","z":"60f2d2277843c698","name":"","property_allow":"payload","filter_allow":"allow","ignore_case_allow":false,"negate_allow":false,"send_allow":false,"property_stop":"payload","filter_stop":"stop","ignore_case_stop":false,"negate_stop":false,"send_stop":false,"default_start":true,"differ":false,"x":1130,"y":340,"wires":[["a702397e9ab9d11f"]]},{"id":"6b1110b5.183a4","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]
Final note, you’ll need to get your streams working well. I am using the WebRTC addon.