[1/2 SOLVED] How to use <iframe to resize IP cam stream in the Dashboard?

Hi all,
What I would like to do:

  • Enter the login and password to access the IP cam (server include)
  • show on my Dashboard live video, from my IP cam
  • resize the image size in Node Red

What I managed to do:


picture1 / with the @BartButenaers link Display camera ip in dashboard, I can resize the image so that it enters any widget using <img provided that I have already "unlocked" the cam somewhere else.
The problem is that no login / password is offered: I can not display the stream.

picture2 / With the node Template, I manage to ask the login and password to display the image of my camera using an <iframe
the problem: is that I can not resize the image for what enters the widget! Assencers appear on the right and on the bottom.

This the flow :

[{"id":"e96fffa.a3495","type":"ui_template","z":"1dec9bbc.37a314","group":"789cefa2.41562","name":"Display image","order":1,"width":"12","height":"9","format":"<img width=\"627\"  src=\"\n        http://192.168.1.5:59331/videostream.cgi?\n        \" \n/>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":690,"y":180,"wires":[[]]},{"id":"e6fc2d79.ecb12","type":"ui_template","z":"1dec9bbc.37a314","group":"789cefa2.41562","name":"video stream","order":1,"width":"12","height":"9","format":"\n<iframe \n        width=\"100%\" \n        height=\"100%\" \n  \n        src=\"\n        http://192.168.1.5:59331/videostream.cgi?\n\n        \"\n            >\n</iframe>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":700,"y":210,"wires":[[]]},{"id":"789cefa2.41562","type":"ui_group","z":"","name":"Default","tab":"87cf90d6.67f72","order":1,"disp":true,"width":"12","collapse":false},{"id":"87cf90d6.67f72","type":"ui_tab","z":"","name":"Home","icon":"home","order":1,"disabled":false,"hidden":false}]

How to mix both? That is: display the credencial dialog box at the start of the Dashboard (send by the Camera server) AND display the "image" of the size I defined in my Template node?

Someone got an idea ? Sorry for my poor html level .

Thanks

Hi Chris (@SuperNinja),

Your flow contains your two template nodes:


Is that the IP address of your camera server?

Showing a login popup for (every) camera at dashboard startup seems to be rather annoying to me. Surely it would get a very low wife-acceptance-factor :wink:

Can't you just specify the credentials (username/password) in the template node, i.e. inside the URL:

http://username:password@192.168.1.5:59331/videostream.cgi?

On the other hand, adding the credentials to your template node isn't really safe. E.g. when you export your flow to share here, everybody will see it ...

If I were you, I would try to store the credentials somehow (e.g. by using node-red-contrib-credentials ??) safe into Node-RED, and then inject those credentials into the url used in your template node. Or isn't something like that possible in your case?
Bart

Hi Bart,

Yes , this is the full IP with credential
http://192.168.1.5:59331/camera_control.cgi?param=0&value=32&user=XxXxX&pwd=XxXxX
This is what display when i open the Dashboard :


the number 2 is the template with <iframe
it's the only one that shows me the window of identification. What I would like to do is resize the picture so that the image appears without the assensors.
But I can not do it with iframe and my poor base in html lol

you're right, I had not thought about that, for now I have only one camera, but if I add ...
The goal is to display the Dashboard on an old Android tablet that would still be powered on. The credentials of each camera will be entered once at first boot, it's not annoying. My wife will call me when Node Red Crash and the tablet is blocked, and that's what I would like to avoid. :sweat_smile:

Hey Chris,
Unfortunately I have never worked with iframe's, so I hope someone else from the community can help you with this…
Good luck with it!
Bart

ok, i'll try. thanks Bart

The new question is :
how to modify the <iframecode so that the image in the dashboard is the size of the widget, in other words : to make the assensors disapear ? Like This :
image


<iframe 
        width="100%" 
        height="100%" 
  
        src="
        http://192.168.1.5:59331/videostream.cgi?
        "
            >
</iframe>

I think you should use style instead of iframes. I have made this dashboard layout based on ui templates. The code in the template for the live video view is as below. Obviously, this is thought as an "idea-input", if you want to experiment, you have to change the camera url's to what is matching your settings and video device types

As example I have also included an example of the view showing latest AI detection results when detecting a human person (my wife and myself) walking around/towards our house (in addition with a false alarm when the AI misjudged the thing a bit)

<!DOCTYPE html>
<html>
<style>
img {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 2px;
    width: 400px;
    height:300px;
}

.on { 
    border:4px inset;
    color:white;
    background:#FBF14D; 
}
    
.off {
    border:4px outset;
    color:white;
    background:#FBF14D; 
}

.norm {
    border:4px outset;
    color:white;
    background:#FBF14D; 
}
</style>

<script type="text/javascript">

//Make scope available in functions
var theScope = scope;

scope.$watch('msg', function(msg) {
    inMessage(msg.payload);
});

function updatePic() {
    document.getElementById('c11').src = "http://192.168.0.238:8081/";
    document.getElementById('c12').src = "http://192.168.0.238:8082/";
    document.getElementById('c22').src = "http://192.168.0.237:8082/";
    document.getElementById('c21').src = "http://192.168.0.237:8081/";
    document.getElementById('c31').src = "http://192.168.0.236:8081/";
    document.getElementById('c32').src = "http://192.168.0.236:8082/";
    document.getElementById('c41').src = "http://192.168.0.235:8081/";
    //alert('updated pics');
}

function inMessage(event) {
    //alert(event);
    if (event.match('checkWeb')) {
        updatePic();
    }
    if (event.match('Fast')) {
        document.getElementById("b4").style.backgroundColor="#FBF14D";
        document.getElementById("b4").style.color ="black";
        document.getElementById("b4").className = "on";
        document.getElementById("b4").innerHTML = "&nbsp;FAST STREAMING";

    }
    if (event.match('Normal')) {
        document.getElementById("b4").style.backgroundColor="#808080";
        document.getElementById("b4").style.color ="white";
        document.getElementById("b4").className = "off";
        document.getElementById("b4").innerHTML = "&nbsp;NORMAL STREAMING";
    }
    if (event.match('force')) {
        document.getElementById("b3").style.backgroundColor="#FBF14D";
        document.getElementById("b3").style.color ="black";
        document.getElementById("b3").className = "on";
        document.getElementById("b3").innerHTML = "&nbsp;FORCED DETECTION MODE";
    }
    if (event.match('resume')) {
        document.getElementById("b3").style.backgroundColor="#808080";
        document.getElementById("b3").style.color ="white";
        document.getElementById("b3").className = "off";
        document.getElementById("b3").innerHTML = "&nbsp;AUTO DETECTION MODE";
    }
    if (event.match('Latest capture: ')) {
        document.getElementById("latest").style.color ="black";
        document.getElementById("latest").innerHTML = "&nbsp;"+event;
    }
}

function ToggleMessage(eventname, el){
    if(el.className == "on") {
        el.className="off";
        theScope.send({payload:eventname});
        } 
    else {
        el.className="on";
        theScope.send({payload:eventname});
        } 
    return false;
}

function SendMessage(eventname, el){
    theScope.send({payload:eventname});
    return false;
}

</script>
<center>
<table>
		<!-- put the up address of your Pi's in this line: -->
    <tr><!-- Row 1 -->
    		<td style="text-align: center"><img src="http://192.168.0.236:8081/" id="c31" /></td>
   		    <td style="text-align: center"><img src="http://192.168.0.238:8082/" id="c12" /></td>
    		<td style="text-align: center"><img src="http://192.168.0.235:8081/" id="c41" /></td>
    		<td style="text-align: center"><img src="http://192.168.0.238:8081/" id="c11" /></td>
    </tr>
</table>
<table>
		<!-- put the up address of your Pi's in this line: -->
    <tr><!-- Row 2 -->
    		<td style="text-align: center"><img src="http://192.168.0.236:8082/" id="c32" /></td>
    		<td style="text-align: center"><img src="http://192.168.0.237:8082/" id="c22" /></td>
     		<td style="text-align: center"><img src="http://192.168.0.237:8081/" id="c21" /></td>
    </tr>
</table>
<br>
<div style="text-align:center" id="latest">&nbsp;Latest capture:&nbsp;</div>
<br>
<table width="100%" border="1">
  <tr><!-- Row 1 -->
        <td><div style="text-align:center"><button id="b1" class="norm" onMouseDown="SendMessage('Latest', this)" style="font-size:100%; background-color:#808080; height:60px; width:445px">&nbsp;SHOW LATEST&nbsp;</button></div></td>
        <td><div style="text-align:center"><button id="b2" class="norm" onMouseDown="SendMessage('Take snapshots', this)" style="font-size:100%; background-color:#808080; height:60px; width:445px">&nbsp;TAKE SNAPSHOTS&nbsp;</button></div></td>
        <td><div style="text-align:center"><button id="b3" class="off" onMouseDown="ToggleMessage('Detection', this)" style="font-size:100%; background-color:#808080; height:60px; width:445px">&nbsp;AUTO DETECTION MODE&nbsp;</button></div></td>
        <td><div style="text-align:center"><button id="b4" class="off" onMouseDown="ToggleMessage('Streaming', this)" style="font-size:100%; background-color:#808080; height:60px; width:445px">&nbsp;NORMAL STREAMING&nbsp;</button></div></td>
  </tr>
</table>
</center>
</html>
2 Likes

superb realization, I will try your flow, thank you

@krambriw,
i rapidely test your html code in the ui Templates and i got the same issue like if i use <img : the credential windows acces dos not appear !

At this time only <iframe working : but I can not adapt the size of my image to the widget, there are always the assensors

<iframe style="width:640px; height:500px;"  frameborder="0" scrolling="no" marginheight="0" marginwidth="0"
src="http://192.168.1.5:59331/videostream.cgi?
        user=xXXxx
        %26pwd=xXXxxx
        %26resolution=32
        %26rate=0"></iframe>

The result of this :

I'm sure i'm not so far from the goal !!

I'm not sure but could it be your browser setting that prevents pop-ups for the login?

I quickly found an interesting discussion about iframes and possible replacements

https://stackoverflow.com/questions/755795/are-iframes-html-obsolete

I've seen lots of forums that suggest the Object tag as a replacement for IFrame, which probably works in most cases.

For example, I had a PDF showing in an IFrame (because there were other things we need to show on the page besides only the PDF) and was able to get it to display fine using Object.

What was:

<iframe id="confirmed_pdf" class="current_pdf" src="/prescriptions/show_pdf?id=123" height="570" width="480"></iframe>

Became:

<object id="confirmed_pdf" class="current_pdf" data="/prescriptions/show_pdf?id=123" type="application/pdf" height="570" width="480">
  <p>[Show this message if displaying the PDF did not work]</p>
</object>

But Object was not a suitable replacement to fill the requirement to be able to print ONLY the PDF portion of the page.

An IFrame is like its own window within the page (a window within a window, basically), and once you get the window object, you can call .print() on it, like:

etc, etc

I think the css styles you need to look at are overflow-x and overflow-y
https://www.w3schools.com/cssref/css3_pr_overflow-x.asp

This is what i do :

<iframe style="
width:640px;
height:480px;
overflow: hidden;
margin: auto;
border:1px solid green;
"  
frameborder="0" scrolling="no" marginheight="0" marginwidth="0"
src="http://192.168.1.5:59331/videostream.cgi?
        user=XXxxXxXXXX
        %26pwd=XXXXxxxxXXx
        %26resolution=32
        %26rate=0"
        
></iframe>


Assensor is always here ....

@krambriw i test the Object tag but the login pop-up does not appear :roll_eyes:

How have you configured the size of the template and group nodes? By default those are set to "auto"

In this example, using your iframe code (just modified to fit settings for my camera) the scroll bar disappears if the size settings are modified

Increasing the size

The group "Flux direct" is 12 :

inside "Flux Direct" there is "Direct Stream"12x10 :

if i put size "Direct Stream" on "Auto" : i lost some pixel, and assensor is here again .

You are right , if i increase to 13 : assensor desapear ( i lost few little pixels to)

IN FACT

That means that if we use <iframe, we can not adapt an image to the widget: it's up to the widget to adapt to the image !!?
While <img fits as you want to the widget.

I do not understand that in the 21st century, we can not do that? :sweat_smile:

Or i have to be cunning to find another way than <iframe And that I can bring up the camera login window :thinking: ??!

Hi @krambriw

Sorry to interject, but WOW !!! - it's not often I see something and go, I'd love to do that with all my cameras !!!

But considering my NR skill level, this looks to be a step way beyond my current NR capabilitiy level, although I do know the URLs for most of my local IP camera feeds (but the others are Ring Cameras) . If it's not to much trouble is there a way I could (very gratefully) leverage your design - and just update it with my camera URLs - if so how would I do that ? (BTW what cameras are you using ?)

Thanks, well, yes my complete flow is a bit too complex to share "straight out of the box", besides the video stuff it also involves & depends on communication with various other system components across multiple raspberry pi's. But I think, during next week, I will try to make a simplified flow that can be shared and eventually become a starting point for new video projects

I think if you increase the hight as well, you well get those pixels back

Awesome thanks !

yes of course , without "auto" option , i could selec the width and height...

What blocks me is really the display of this window of autentification which appears automatically at the first connection to http://192.168.1.5:59331/videostream.cgi?user=XXxXxXX%26pwd=XXxxXxx%26resolution=32%26rate=0
Once authenticated, the Template Node will automatically display the image of the Cam (using <img that I can size as I want, without a pickup or loss of pixel).

Do you have an idea of Flow, so that the window of authentication appears at the start of the Dashboard?

I'm not really sure what is the exact problem blocking you so kind of guessing here. I guess that the login window appears first time when you try to use some camera control?

If you look at my example html code earlier up in this thread, part of the code is shown again below. What it does is listening for messages sent to the input of the template node. Specifically the function updatePic() is used to refresh all video frames at startup and then at a regular interval (using an inject node) without the need to refresh the whole page. So my thought is if this could be a way to "init" your views at the start of the dashboard. Now the case is you use iframes, I'm not sure if you are able to communicate this way to iframes since they are said to be "isolated pages" but it might be worth a try. In your case you might need to send some other command to initiate the login pop-up, I don't know. Best would be if you could find a correct url that makes the login in one shot, then you could skip iframes. I would try to design it in such way that the code in the template would be generic and the user name & password would be injected into the template node at startup

<script type="text/javascript">

//Make scope available in functions
var theScope = scope;

scope.$watch('msg', function(msg) {
    inMessage(msg.payload);
});

function updatePic() {
    document.getElementById('c11').src = "http://192.168.0.238:8081/";
    document.getElementById('c12').src = "http://192.168.0.238:8082/";
    document.getElementById('c22').src = "http://192.168.0.237:8082/";
    document.getElementById('c21').src = "http://192.168.0.237:8081/";
    document.getElementById('c31').src = "http://192.168.0.236:8081/";
    document.getElementById('c32').src = "http://192.168.0.236:8082/";
    document.getElementById('c41').src = "http://192.168.0.235:8081/";
    //alert('updated pics');
}

function inMessage(event) {
    //alert(event);
    if (event.match('checkWeb')) {
        updatePic();
    }

Actually, you can communicate with your iframes, you just have to add an id to them. Then you can as an idea send a command from the parent like this (besides that discourse doesn't like to be iframed)

Here you might have some possibilities to elaborate to find a url that brings up the login view or to find a way to provide the credentials

var new_url = "https://discourse.nodered.org/";
document.getElementById('nbr1').src = new_url;
<iframe id="nbr1" style="
width:640px;
height:480px;
overflow: hidden;
margin: auto;
border:1px solid green;
"  
frameborder="0" scrolling="no" marginheight="0" marginwidth="0"
src="http://192.168.1.5:59331/videostream.cgi?
        user=XXxxXxXXXX
        %26pwd=XXXXxxxxXXx
        %26resolution=32
        %26rate=0"
        
></iframe>