I wanted to be able to pause any Blue Iris camera if there was a lot of activity going on such as mowing the yard, etc. that I didn’t care about so that I didn’t get 100’s of alerts and video clips. The REST api calls to Blue Iris to pause/unpause the cameras was straight forward, but getting the the state for “isPaused” from Blue Iris for any of the cameras was a different story with the use of Session ID’s and Response ID’s needed to make the REST calls using JSON.
HA Cameras
I used REST api calls to pause/unpause the cameras. (This is the straight forward part) I stored the REST URL’s in my secrets.yaml since they contain usernames and passwords
rest.yaml
frontporch_pause:
url: !secret frontporch_pause
method: GET
frontporch_unpause:
url: !secret frontporch_unpause
method: GET
secrets.yaml
frontporch_pause: 'http://192.168.1.13:81/admin?camera=fps&pause=-1&user=xxx&pw=xxx'
frontporch_unpause: 'http://192.168.1.13:81/admin?camera=fps&pause=0&user=xxx&pw=xxx'
I then created a dummy input_boolean (bi_pause_check) that is turned on as part of the camera pause and un-pause scripts to trigger the node-red flow upon state change. This will then update the cameras input_boolean (bi_fpsstate) with the paused state of the camera.
input_boolean.yaml
bi_pause_check:
name: BI Pause Check
initial: off
bi_fpsstate:
name: Front Porch Paused
initial: off
scripts.yaml
frontporch_pause_on:
sequence:
- service: rest_command.frontporch_pause
- service: homeassistant.turn_on
entity_id: input_boolean.bi_pause_check
frontporch_pause_off:
sequence:
- service: rest_command.frontporch_unpause
- service: homeassistant.turn_on
entity_id: input_boolean.bi_pause_check
The node-red flow below is triggered by the input_boolean.bi_pause_check and is also triggered every 5 mins to check state so that if someone manually pauses/unpauses the camera from Blue Iris itself that change would get reflected in HA.
I had to install the Credentials node which is used to hold your username and password that you setup for API access to Blue Iris so you may have to do the same. The credentials node does not export your username and password if you want to share your flow.
Blue Iris Node Red Flow
[{"id":"4fd4d833.c97508","type":"tab","label":"Blue Iris","disabled":false,"info":""},{"id":"d651c3f5.ae4ce","type":"server-state-changed","z":"4fd4d833.c97508","name":"Is BI Pause Check: ON","server":"5d9ca5ff.74e9ec","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.bi_pause_check","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"x":160,"y":160,"wires":[["bb29efe3.a5a2","3b6fe560.56770a"],[]]},{"id":"f681ecbd.5e22a","type":"http request","z":"4fd4d833.c97508","name":"Get BI Session ID","method":"POST","ret":"obj","paytoqs":false,"url":"http://192.168.1.13:81/json","tls":"","persist":true,"proxy":"","authType":"","x":650,"y":160,"wires":[["d112bc38.556c9"]]},{"id":"bb29efe3.a5a2","type":"template","z":"4fd4d833.c97508","name":"Set Login Cmd","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"cmd\":\"login\"}","output":"json","x":420,"y":160,"wires":[["f681ecbd.5e22a"]]},{"id":"2c5d8e3f.2afc22","type":"inject","z":"4fd4d833.c97508","name":"Get State Every 5 Mins","topic":"","payload":"","payloadType":"date","repeat":"300","crontab":"","once":true,"onceDelay":0.1,"x":150,"y":100,"wires":[["bb29efe3.a5a2"]]},{"id":"298c5810.8022b8","type":"function","z":"4fd4d833.c97508","name":"Set MD5 Hash Paylod","func":"p=msg.payload\nflow.set('bisession',p.session);\nmsg.payload = msg.username + \":\" + p.session + \":\" + msg.password;\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":220,"wires":[["7af00351.80c76c"]]},{"id":"7af00351.80c76c","type":"exec","z":"4fd4d833.c97508","command":"echo -n ","addpay":true,"append":"| md5sum","useSpawn":"false","timer":"","oldrc":false,"name":"MD5 Hash Session","x":690,"y":220,"wires":[["a6f296e2.a3e078"],[],[]]},{"id":"a6f296e2.a3e078","type":"function","z":"4fd4d833.c97508","name":"Set BI Login Payload","func":"var sesid = flow.get('bisession') || 0;\nvar str = msg.payload;\nvar resid = str.substring(0, str.length-4);\nflow.set('biresponse', resid);\nmsg.payload = '{\"cmd\":\"login\",\"session\":\"' + sesid + '\",\"response\":\"' + resid + '\"}';\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":280,"wires":[["9ec0f71a.561448"]]},{"id":"f111cd24.3dfbd","type":"http request","z":"4fd4d833.c97508","name":"Login to BI","method":"POST","ret":"obj","paytoqs":false,"url":"http://192.168.1.13:81/json","tls":"","persist":true,"proxy":"","authType":"","x":750,"y":280,"wires":[["d05b73a8.446b8"]]},{"id":"9ec0f71a.561448","type":"json","z":"4fd4d833.c97508","name":"Convert to JSON","property":"payload","action":"","pretty":true,"x":530,"y":280,"wires":[["f111cd24.3dfbd"]]},{"id":"d05b73a8.446b8","type":"function","z":"4fd4d833.c97508","name":"Set BI CamList Payload","func":"var sesid = flow.get('bisession') || 0;\nvar resid = flow.get('biresponse') || 0;\nmsg.payload = '{\"cmd\":\"camlist\",\"session\":\"' + sesid + '\",\"response\":\"' + resid + '\"}';\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":340,"wires":[["5f32582a.a139d8"]]},{"id":"5f32582a.a139d8","type":"json","z":"4fd4d833.c97508","name":"Convert to JSON","property":"payload","action":"","pretty":true,"x":610,"y":340,"wires":[["a197a493.b413b8"]]},{"id":"a197a493.b413b8","type":"http request","z":"4fd4d833.c97508","name":"Get Cam Status","method":"POST","ret":"obj","paytoqs":false,"url":"http://192.168.1.13:81/json","tls":"","persist":true,"proxy":"","authType":"","x":840,"y":340,"wires":[["c8e8816e.02b15"]]},{"id":"40d5458c.c74fec","type":"json","z":"4fd4d833.c97508","name":"Convert to JSON","property":"payload","action":"","pretty":true,"x":850,"y":400,"wires":[["cc39595f.d995a8","2acb8b86.a37ce4","6a2b3cb2.62ba24","dce1d75d.bb3a28"]]},{"id":"cc39595f.d995a8","type":"function","z":"4fd4d833.c97508","name":"Set Front Porch State","func":"p=msg.payload;\nvar fpsstate = p.fpsstate;\nif ( fpsstate == 'true' ) {\n msg.payload = 'on';\n}\nelse {\n msg.payload = 'off'\n}\nreturn msg;","outputs":1,"noerr":0,"x":1112,"y":310,"wires":[["c37962ee.847fe"]]},{"id":"2acb8b86.a37ce4","type":"function","z":"4fd4d833.c97508","name":"Set Driveway State","func":"p=msg.payload;\nvar dsstate = p.dsstate;\nif ( dsstate == 'true' ) {\n msg.payload = 'on';\n}\nelse {\n msg.payload = 'off'\n}\nreturn msg;","outputs":1,"noerr":0,"x":1102,"y":370,"wires":[["6d8463b3.32f27c"]]},{"id":"6a2b3cb2.62ba24","type":"function","z":"4fd4d833.c97508","name":"Set Garage State","func":"p=msg.payload;\nvar gsstate = p.gsstate;\nif ( gsstate == 'true' ) {\n msg.payload = 'on';\n}\nelse {\n msg.payload = 'off'\n}\nreturn msg;","outputs":1,"noerr":0,"x":1102,"y":430,"wires":[["cdc20e9f.9d77a"]]},{"id":"dce1d75d.bb3a28","type":"function","z":"4fd4d833.c97508","name":"Set Backyard State","func":"p=msg.payload;\nvar bsstate = p.bsstate;\nif ( bsstate == 'true' ) {\n msg.payload = 'on';\n}\nelse {\n msg.payload = 'off'\n}\nreturn msg;","outputs":1,"noerr":0,"x":1102,"y":490,"wires":[["1d6feacd.ec2b55"]]},{"id":"3b6fe560.56770a","type":"api-call-service","z":"4fd4d833.c97508","name":"Set BI Pause Check: OFF","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bi_pause_check","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":450,"y":100,"wires":[[]]},{"id":"c37962ee.847fe","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Front Porch Paused State","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_{{payload}}","entityId":"input_boolean.bi_fpsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1382,"y":310,"wires":[[]]},{"id":"6d8463b3.32f27c","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Driveway Paused State","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_{{payload}}","entityId":"input_boolean.bi_dsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1372,"y":370,"wires":[[]]},{"id":"cdc20e9f.9d77a","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Garage Paused State","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_{{payload}}","entityId":"input_boolean.bi_gsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1362,"y":430,"wires":[[]]},{"id":"1d6feacd.ec2b55","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Backyard Paused State","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_{{payload}}","entityId":"input_boolean.bi_bsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1372,"y":490,"wires":[[]]},{"id":"758a6dbe.8bbae4","type":"comment","z":"4fd4d833.c97508","name":"Get BI Camera Pause States","info":"","x":140,"y":40,"wires":[]},{"id":"505fe94b.551ec8","type":"bigtimer","z":"4fd4d833.c97508","outtopic":"","outpayload1":"1","outpayload2":"","name":"Is it 10:00pm?","comment":"","lat":"38.429722","lon":"-90.5744","starttime":"1320","endtime":"10001","starttime2":0,"endtime2":0,"startoff":"0","endoff":0,"startoff2":0,"endoff2":0,"offs":0,"outtext1":"","outtext2":"","timeout":1440,"sun":true,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"jan":true,"feb":true,"mar":true,"apr":true,"may":true,"jun":true,"jul":true,"aug":true,"sep":true,"oct":true,"nov":true,"dec":true,"day1":0,"month1":0,"day2":0,"month2":0,"day3":0,"month3":0,"day4":0,"month4":0,"day5":0,"month5":0,"day6":0,"month6":0,"day7":"","month7":"","day8":"","month8":"","day9":"","month9":"","day10":"","month10":"","day11":"","month11":"","day12":"","month12":"","d1":0,"w1":0,"d2":0,"w2":0,"d3":0,"w3":0,"d4":0,"w4":0,"d5":0,"w5":0,"d6":0,"w6":0,"xday1":0,"xmonth1":0,"xday2":0,"xmonth2":0,"xday3":0,"xmonth3":0,"xday4":0,"xmonth4":0,"xday5":0,"xmonth5":0,"xday6":0,"xmonth6":0,"xd1":0,"xw1":0,"xd2":0,"xw2":0,"xd3":0,"xw3":0,"xd4":0,"xw4":0,"xd5":0,"xw5":0,"xd6":0,"xw6":0,"suspend":false,"random":false,"repeat":false,"atstart":false,"odd":false,"even":false,"x":100,"y":600,"wires":[["3daa6bbc.2a7744","f6998dcf.b63b1","f6332b98.556c38","757da0a0.0e47d"],[],[]]},{"id":"3daa6bbc.2a7744","type":"api-current-state","z":"4fd4d833.c97508","name":"Front Porch Paused: YES","server":"5d9ca5ff.74e9ec","version":1,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.bi_fpsstate","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":390,"y":510,"wires":[["2ec6bf7f.3799b"],[]]},{"id":"f6998dcf.b63b1","type":"api-current-state","z":"4fd4d833.c97508","name":"Driveway Paused: YES","server":"5d9ca5ff.74e9ec","version":1,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.bi_dsstate","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":390,"y":570,"wires":[["1cb4d5c1.ea8a9a"],[]]},{"id":"f6332b98.556c38","type":"api-current-state","z":"4fd4d833.c97508","name":"Garage Paused: YES","server":"5d9ca5ff.74e9ec","version":1,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.bi_gsstate","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":380,"y":630,"wires":[["bd98c1ae.9c99f"],[]]},{"id":"757da0a0.0e47d","type":"api-current-state","z":"4fd4d833.c97508","name":"Backyard Paused: YES","server":"5d9ca5ff.74e9ec","version":1,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.bi_bsstate","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":390,"y":690,"wires":[["607daf83.4358f"],[]]},{"id":"2ec6bf7f.3799b","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Front Porch Pause: OFF","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bi_fpsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":720,"y":510,"wires":[[]]},{"id":"1cb4d5c1.ea8a9a","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Driveway Pause: OFF","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bi_dsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":710,"y":570,"wires":[[]]},{"id":"bd98c1ae.9c99f","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Garage Pause: OFF","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bi_gsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":710,"y":630,"wires":[[]]},{"id":"607daf83.4358f","type":"api-call-service","z":"4fd4d833.c97508","name":"Set Backyard Pause: OFF","server":"5d9ca5ff.74e9ec","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bi_bsstate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":710,"y":690,"wires":[[]]},{"id":"b7c3f80b.3b948","type":"inject","z":"4fd4d833.c97508","name":"","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":530,"wires":[["3daa6bbc.2a7744","f6998dcf.b63b1","f6332b98.556c38","757da0a0.0e47d"]]},{"id":"c8e8816e.02b15","type":"function","z":"4fd4d833.c97508","name":"Set BI CamList Payload","func":"p=msg.payload;\nvar fpsstate = '';\nvar dsstate = '';\nvar gsstate = '';\nvar bsstate = '';\n\nfor (i = 1; i < p.data.length; i=i+1) {\n if (p.data[i].optionValue == 'fps') {\n fpsstate = p.data[i].isPaused\n }\n if (p.data[i].optionValue == 'ds') {\n dsstate = p.data[i].isPaused\n }\n if (p.data[i].optionValue == 'gs') {\n gsstate = p.data[i].isPaused\n }\n if (p.data[i].optionValue == 'bs') {\n bsstate = p.data[i].isPaused\n }\n}\n\n//Reset Flow Variables\nflow.set('bisession','0');\nflow.set('biresponse', '0');\nmsg.payload = '{\"fpsstate\":\"' + fpsstate + '\",\"dsstate\":\"' + dsstate + '\",\"gsstate\":\"' + gsstate + '\",\"bsstate\":\"' + bsstate + '\"}';\nreturn msg;","outputs":1,"noerr":0,"x":590,"y":400,"wires":[["40d5458c.c74fec"]]},{"id":"d112bc38.556c9","type":"credentials","z":"4fd4d833.c97508","name":"Bi Credentials","props":[{"value":"username","type":"msg"},{"value":"password","type":"msg"}],"x":200,"y":220,"wires":[["298c5810.8022b8"]]},{"id":"de38d094.87056","type":"comment","z":"4fd4d833.c97508","name":"Un-Pause All Cameras at 10:00PM","info":"","x":160,"y":460,"wires":[]},{"id":"5d9ca5ff.74e9ec","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
In the “Set BI CamList Payload” node, you will see I’m parsing the “isPaused” value for 4 cameras. I loop through all the cameras and parse for the short names of the cameras I am interested in as I have 11 camera streams and don’t care about the others. The array pulled in will change based on if a camera is enable/disabled and other factors so looping through the data and looking at “optionValue” which is the short name of the camera ensures I pull the state for the correct camera.
The EXEC Node (The one with the gear icon) sends a command to the CLI to generate the md5hash of username:sessionid:password in order to get the Blue Iris Response ID required to make more authenticated calls to the API.
My flow also has a timer that will unpause all cameras at 10:00PM in case I forget to unpause them manually.
I also used custom-button-card on my tablet view page so the icon and label changes with state…I’m sure you can use other cards, but this was my preference.
ui-lovelace.yaml
### Front Porch
- type: horizontal-stack
cards:
- type: 'custom:button-card'
entity: camera.front_porch
class: camera
show_name: true
show_icon: false
show_entity_picture: true
styles:
card:
- height: 76px
- type: 'custom:button-card'
entity: script.frontporch_pause_on
show_name: false
show_label: true
icon: >
[[[
if (states['input_boolean.bi_fpsstate'].state == 'off')
return "mdi:pause-circle";
else
return "mdi:play";
]]]
label: >
[[[
if (states['input_boolean.bi_fpsstate'].state == 'off')
return "Pause";
else
return "Resume";
]]]
styles:
card:
- height: 76px
tap_action:
action: call-service
service: input_boolean.toggle
service_data:
entity_id: input_boolean.bi_fpsstate
Hope this helps someone looking to do similar things. There are many camera attributes pulled in from the camlist API call that I’m sure could be used in other ways as well.