{"id":31,"date":"2017-12-08T05:48:19","date_gmt":"2017-12-08T05:48:19","guid":{"rendered":"https:\/\/ta-laboratories.com\/blog\/?p=31"},"modified":"2018-08-05T15:32:07","modified_gmt":"2018-08-05T15:32:07","slug":"lorex-lnz4001-ptz-ipcam-control-with-raspberry-pi","status":"publish","type":"post","link":"https:\/\/ta-laboratories.com\/blog\/2017\/12\/08\/lorex-lnz4001-ptz-ipcam-control-with-raspberry-pi\/","title":{"rendered":"LOREX LNZ4001 PTZ ipcam control with Raspberry Pi"},"content":{"rendered":"<p><strong>Controlling and streaming a LOREX PTZ ipcam using Raspberry pi with Flask, Motion and AJAX.<\/strong><\/p>\n<p><strong>You will need<\/strong><\/p>\n<ul>\n<li>1 PTZ network cam<\/li>\n<li>1 Raspberry pi<\/li>\n<li>1 USB Wi-Fi dongle<\/li>\n<li>1 Cat5 Ethernet cord<\/li>\n<\/ul>\n<p><strong>The principle of this tutorial should remain the same for different ipcam manufacturers however the commands used may change. I used wireshark to sniff network traffic as I made requests from a browser to the ipcameras built in webserver.<br \/>\n<a href=\"https:\/\/www.wireshark.org\/download.html\">https:\/\/www.wireshark.org\/download.html<\/a> <\/strong><\/p>\n<p><strong>Commands like this may change&#8230;<\/strong><\/p>\n<pre>http:\/\/192.168.1.xxx\/cgi-bin\/operator\/ptzset?move=upleft&amp;move=repeat\r\n\r\n<\/pre>\n<p><strong>Network Layout<\/strong><br \/>\n<img decoding=\"async\" class=\"alignnone size-medium wp-image-60\" src=\"https:\/\/ta-laboratories.com\/blog\/wp-content\/uploads\/2017\/12\/FullSizeRender.jpg\" alt=\"\" \/><br \/>\n<strong>First we need to set the ip of the camera to static through its built in web interface follow manufactures instructions for this. We will use the address\u00a0192.168.2.9 <\/p>\n<p>Now in the network interfaces config, the USB wifi dongle will be assigned a static IP of\u00a0192.168.1.10 and the pi&#8217;s ethernet port will go to 192.168.2.1<br \/>\n<\/strong><\/p>\n<pre>$ sudo nano \/etc\/network\/interfaces\r\n\r\n<\/pre>\n<p><strong>This is what my \/etc\/network\/interfaces looks like.<\/strong><\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:90%;height:300px;\"><div class=\"python codecolorer\">auto lo<br \/>\niface lo inet loopback<br \/>\n<br \/>\nauto eth0<br \/>\nallow-hotplug eth0<br \/>\niface eth0 inet static<br \/>\naddress 192.168.2.1<br \/>\nnetmask 255.255.255.0<br \/>\nnetwork 192.168.2.1<br \/>\nbroadcast 192.168.2.255<br \/>\n<br \/>\nauto wlan0<br \/>\nallow-hotplug wlan0<br \/>\niface wlan0 inet manual<br \/>\nwpa-roam \/etc\/wpa_supplicant\/wpa_supplicant.<span class=\"me1\">conf<\/span><br \/>\niface wlan0 inet static<br \/>\naddress 192.168.1.10<br \/>\nnetmask 255.255.255.0<br \/>\nnetwork 192.168.1.0<br \/>\nbroadcast 192.168.1.255<br \/>\ngateway 192.168.1.1<\/div><\/div>\n<p><strong>Next we need to install motion <a href=\"https:\/\/github.com\/Motion-Project\/motion\">https:\/\/github.com\/Motion-Project\/motion<\/a><\/strong><\/p>\n<pre>$ sudo apt-get install motion\r\n\r\n<\/pre>\n<p><strong>Change this in the\u00a0\/etc\/motion\/motion.conf<\/strong><\/p>\n<pre>$ sudo nano \/etc\/motion\/motion.conf<\/pre>\n<ul>\n<li>daemon on<\/li>\n<li>stream_localhost off<\/li>\n<li>netcam_url value http:\/\/192.168.2.9\/video.mjpg (change to the path of your cams video stream)<\/li>\n<li>netcam_userpass user:pass (username:password)<\/li>\n<\/ul>\n<p><strong>Install Flask <a href=\"http:\/\/flask.pocoo.org\/\">http:\/\/flask.pocoo.org\/<\/a><\/strong><\/p>\n<pre>$ sudo apt-get install python-pip<\/pre>\n<pre>$ sudo pip install Flask\r\n\r\n<\/pre>\n<p><strong>Remove ifplugd so the pi doesn&#8217;t disable wifi when the ethernet jack is plugged in <a href=\"https:\/\/github.com\/BillTompkins\/pi-spiexpansion\/wiki\/Remove-ifplugd\">https:\/\/github.com\/BillTompkins\/pi-spiexpansion\/wiki\/Remove-ifplugd<\/a><\/strong><\/p>\n<pre>$ sudo apt-get remove ifplugd \r\n\r\n<\/pre>\n<p><strong>Allow IP forwarding<\/strong><\/p>\n<pre>$ sudo nano \/etc\/sysctl.conf\r\n\r\n<\/pre>\n<ul>\n<li><strong>Find and uncomment &#8211;\u00a0<\/strong> net.ipv4.ip_forward=1<\/li>\n<\/ul>\n<p><strong>Run this command so we dont have to reboot.<\/strong><\/p>\n<pre>$ sudo sh -c \"echo 1 &gt; \/proc\/sys\/net\/ipv4\/ip_forward\"\r\n\r\n<\/pre>\n<p><strong>Modify IP tables and NAT to allow traffic from wlan to ethernet.<\/strong><\/p>\n<pre>$ sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQURADE\r\n\r\n<\/pre>\n<pre>$ sudo iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT\r\n\r\n<\/pre>\n<pre>$ sudo iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT\r\n\r\n<\/pre>\n<p><strong>Don&#8217;t know if this is 100% necessary but I will include it anyways.<\/strong><\/p>\n<pre>$ sudo apt-get install dnsmasq\r\n\r\n<\/pre>\n<pre>$ sudo nano \/etc\/dnsmasq.conf\r\n\r\n<\/pre>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><div class=\"python codecolorer\">interface<span class=\"sy0\">=<\/span>eth0 &nbsp; &nbsp; &nbsp;<span class=\"co1\"># Use interface eth0<\/span><br \/>\nlisten-address<span class=\"sy0\">=<\/span>192.168.2.1 <span class=\"co1\"># listen on<\/span><br \/>\n<span class=\"co1\"># Bind to the interface to make sure we aren't sending things<\/span><br \/>\n<span class=\"co1\"># elsewhere<\/span><br \/>\nbind-interfaces<br \/>\nserver<span class=\"sy0\">=<\/span>8.8.8.8 &nbsp; &nbsp; &nbsp; <span class=\"co1\"># Forward DNS requests to Google DNS<\/span><br \/>\ndomain-needed &nbsp; &nbsp; &nbsp; &nbsp;<span class=\"co1\"># Don't forward short names<\/span><br \/>\n<span class=\"co1\"># Never forward addresses in the non-routed address spaces.<\/span><br \/>\nbogus-priv<br \/>\n<span class=\"co1\"># Assign IP addresses between 192.168.2.2 and 192.168.2.100 with a<\/span><br \/>\n<span class=\"co1\"># 12 hour lease time<\/span><br \/>\ndhcp-<span class=\"kw2\">range<\/span><span class=\"sy0\">=<\/span>192.168.2.2<span class=\"sy0\">,<\/span>192.168.2.100<span class=\"sy0\">,<\/span>12h<\/div><\/div>\n<p><strong>Now that all the back end should be up and working lets write some code.<\/strong><\/p>\n<p><strong>First create a new folder<\/strong><\/p>\n<pre>$ sudo mkdir ipcam_control\r\n\r\n<\/pre>\n<p><strong>Navigate into that folder<\/strong><\/p>\n<pre>$ cd ipcam_control\r\n\r\n<\/pre>\n<p><strong>Create a new Python script<\/strong><\/p>\n<pre>~\/ipcam_control $ sudo nano webcam.py\r\n\r\n<\/pre>\n<p><strong>Copy and paste this code into the webcam.py file<\/strong><br \/>\n<strong> Change the ip address and command of the get request to match your camera, admin:admin is default username and password for the LOREX.<\/strong><br \/>\n<strong> ctrl+O to save ctrl+X to exit back to the command line.<\/strong><\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:90%;\"><div class=\"python codecolorer\"><span class=\"kw1\">from<\/span> flask <span class=\"kw1\">import<\/span> Flask<br \/>\n<span class=\"kw1\">from<\/span> flask <span class=\"kw1\">import<\/span> render_template<span class=\"sy0\">,<\/span> request<br \/>\n<span class=\"kw1\">from<\/span> requests.<span class=\"me1\">auth<\/span> <span class=\"kw1\">import<\/span> HTTPBasicAuth<br \/>\n<span class=\"kw1\">import<\/span> requests<br \/>\napp <span class=\"sy0\">=<\/span> Flask<span class=\"br0\">&#40;<\/span>__name__<span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"kw1\">print<\/span> &amp;quot<span class=\"sy0\">;<\/span>Done&amp;quot<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"sy0\">@<\/span>app.<span class=\"me1\">route<\/span><span class=\"br0\">&#40;<\/span>&amp;quot<span class=\"sy0\">;<\/span>\/&amp;quot<span class=\"sy0\">;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"kw1\">def<\/span> index<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>:<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> render_template<span class=\"br0\">&#40;<\/span><span class=\"st0\">'index.html'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"co1\">#PTZcam<\/span><br \/>\n<span class=\"sy0\">@<\/span>app.<span class=\"me1\">route<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'\/ptzUpleft'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"kw1\">def<\/span> ptzUpleft<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>:<br \/>\n&nbsp; &nbsp; requests.<span class=\"me1\">get<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'http:\/\/192.168.2.9\/cgi-bin\/operator\/ptzset?move=upleft&amp;amp;amp;move=repeat'<\/span><span class=\"sy0\">,<\/span> auth<span class=\"sy0\">=<\/span>HTTPBasicAuth<span class=\"br0\">&#40;<\/span><span class=\"st0\">'admin'<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'admin'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"st0\">'true'<\/span><br \/>\n<br \/>\n<span class=\"kw1\">if<\/span> __name__ <span class=\"sy0\">==<\/span> &amp;quot<span class=\"sy0\">;<\/span>__main__&amp;quot<span class=\"sy0\">;<\/span>:<br \/>\n&nbsp;<span class=\"kw1\">print<\/span> &amp;quot<span class=\"sy0\">;<\/span>Start&amp;quot<span class=\"sy0\">;<\/span><br \/>\n&nbsp;app.<span class=\"me1\">run<\/span><span class=\"br0\">&#40;<\/span>host<span class=\"sy0\">=<\/span><span class=\"st0\">'0.0.0.0'<\/span><span class=\"sy0\">,<\/span>port<span class=\"sy0\">=<\/span><span class=\"nu0\">8000<\/span><span class=\"br0\">&#41;<\/span><\/div><\/div>\n<p><strong>Now create a new sub directory called templates, flask looks for the index.html file in this folder.<\/strong><\/p>\n<pre>$ sudo mkdir templates\r\n\r\n<\/pre>\n<p><strong>Change to templates directory<\/strong><\/p>\n<pre> ~\/ipcam_control $ cd templates\r\n\r\n<\/pre>\n<p><strong>Create new html file.<\/strong><\/p>\n<pre>$ sudo nano index.html\r\n\r\n<\/pre>\n<p><strong>Copy and paste this code into index.html<\/strong><\/p>\n<div class=\"codecolorer-container html4strict default\" style=\"overflow:auto;white-space:nowrap;width:90%;height:300px;\"><div class=\"html4strict codecolorer\"><span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/div.html\"><span class=\"kw2\">div<\/span><\/a> <\/span><br \/>\n<span class=\"sc2\"> <span class=\"kw3\">style<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;-moz-user-select: none; -webkit-user-select: none; -ms-user-select:none; user-select:none;-o-user-select:none;&quot;<\/span> <\/span><br \/>\n<span class=\"sc2\"> unselectable<span class=\"sy0\">=<\/span><span class=\"st0\">&quot;on&quot;<\/span><\/span><br \/>\n<span class=\"sc2\"> onselectstart<span class=\"sy0\">=<\/span><span class=\"st0\">&quot;return false;&quot;<\/span> <\/span><br \/>\n<span class=\"sc2\"> <span class=\"kw3\">onmousedown<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;return false;&quot;<\/span>&gt;<\/span><br \/>\n<br \/>\n<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.1.1\/jquery.min.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a>&gt;<\/span><br \/>\n<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/br.html\"><span class=\"kw2\">br<\/span><\/a>&gt;<\/span>PTZ CONTORLS<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/br.html\"><span class=\"kw2\">br<\/span><\/a>&gt;<\/span><br \/>\n<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/img.html\"><span class=\"kw2\">img<\/span><\/a> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;http:\/\/yourip:8081&gt;<\/span><\/span><br \/>\n<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/table.html\"><span class=\"kw2\">table<\/span><\/a> <span class=\"kw3\">style<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;width: 306px;&quot;<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/tbody.html\"><span class=\"kw2\">tbody<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/tr.html\"><span class=\"kw2\">tr<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/td.html\"><span class=\"kw2\">td<\/span><\/a> <span class=\"kw3\">style<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;text-align: right&quot;<\/span>&gt;&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/button.html\"><span class=\"kw2\">button<\/span><\/a> <span class=\"kw3\">href<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;#&quot;<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;ptzLF&quot;<\/span> <span class=\"kw3\">style<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;font-size: 20px; text-decoration: none;&quot;<\/span>&gt;<\/span><span class=\"sc1\">&amp;#8598;<\/span><span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/button.html\"><span class=\"kw2\">button<\/span><\/a>&gt;&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/td.html\"><span class=\"kw2\">td<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/tr.html\"><span class=\"kw2\">tr<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/tbody.html\"><span class=\"kw2\">tbody<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/table.html\"><span class=\"kw2\">table<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/div.html\"><span class=\"kw2\">div<\/span><\/a>&gt;<\/span><br \/>\n&nbsp;<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a>&gt;<\/span><br \/>\n<br \/>\n$( document ).ready(function(){<br \/>\n&nbsp; &nbsp; $(&quot;#ptzRR&quot;).on(&quot;mousedown&quot;, function() {<br \/>\n&nbsp; &nbsp; $.get('\/ptzRR');<br \/>\n&nbsp; &nbsp; }).on('mouseup', function() {<br \/>\n&nbsp; &nbsp; $.get('\/ptzStop');<br \/>\n&nbsp; &nbsp; });<br \/>\n});<br \/>\n<br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a>&gt;<\/span><\/div><\/div>\n<p><strong>Reboot the pi for good measure<\/strong><\/p>\n<pre>$ sudo reboot\r\n\r\n<\/pre>\n<p><strong>Now when the command line is available again navigate back to your project folder created earlier.<\/strong><\/p>\n<pre>$ cd ipcam_control\r\n\r\n<\/pre>\n<p><strong>Now launch your application<\/strong><\/p>\n<pre>~\/ipcam_control $ sudo python webcam.py\r\n\r\n<\/pre>\n<p><strong>Once that is up and running open a browser on any computer or device connected to the 192.168.1.x network, go to the pi&#8217;s IP address and port 8000, for this tutorial we use http:\/\/192.168.1.10:8000. You should see a video stream and a single button linked to command the camera, similar to the ones pictured below.<br \/>\n<\/strong><\/p>\n<p><strong>Thanks for reading!<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-66\" src=\"https:\/\/ta-laboratories.com\/blog\/wp-content\/uploads\/2017\/12\/screenshot.jpg\" alt=\"\" width=\"1000\" height=\"585\" \/><\/p>\n<p><strong><img decoding=\"async\" class=\"alignnone size-medium wp-image-60\" src=\"https:\/\/ta-laboratories.com\/blog\/wp-content\/uploads\/2017\/12\/FullSizeRender1.jpg\" alt=\"\" \/><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Controlling and streaming a LOREX PTZ ipcam using Raspberry pi with Flask, Motion and AJAX. You will need 1 PTZ network cam 1 Raspberry pi 1 USB Wi-Fi dongle 1 Cat5 Ethernet cord The principle of this tutorial should remain&#8230; <a href=\"https:\/\/ta-laboratories.com\/blog\/2017\/12\/08\/lorex-lnz4001-ptz-ipcam-control-with-raspberry-pi\/\" class=\"read-more\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":262,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,14,4],"tags":[6,9,8,7],"class_list":["post-31","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming","category-python","category-raspberry-pi","tag-electronics","tag-hacking","tag-python","tag-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":119,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"predecessor-version":[{"id":296,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions\/296"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/media\/262"}],"wp:attachment":[{"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ta-laboratories.com\/blog\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}