Local HTML5 Chicken Webcam PWA

A picture of a USB cable connected to a phone to signify local HTML5 Webcam PWA

Create And Install Locally Hosted WebRTC PWA

Learn how to build and set up a PWA application that uses WebRTC to display video from a device camera and take photos at a defined interval for upload to a locally hosted server.

Continuous screen time is needed for the mobile web browser and camera use. On Android devices, navigate to Settings > Display > Screen Timeout and set the timeout longer and if applicable set “Keep screen on while viewing”. On some Android devices, enable “Keep screen on while charging” in the “Developer Options”. For iOS devices, navigate to Settings -> Display & Brightness > Auto-Lock and set to a longer timeout or if applicable set to “Never”. On all devices, dim the screen to save to battery usage, the screen brightness settings are found in the Accessibility portion of Settings.

Remotely debug your Android device via a wireless connection. You need to select “Enable USB Debugging” in the “Developer Options” of your Android device. The USB cable will be needed in order to run some ADB commands for WiFi connection from you workstation. On the workstation, open the Google Chrome web browser and navigate to “chrome://inspect#devices”. With both Discover USB devices and Discover network targets enabled, enable port forwarding based on the workstation port number. Port forwarding can be performed on the router instead of using ADB and the chrome view, which will allow other devices such as the iPhone to be used.

Next, you need to navigate to the Android device Google Chrome web browser and enter the URL and port number. For this tutorial, the port number is original set by the PHP built-in web server. PHP also receives the images at a specified interval. PHP can be replaced with another HTTP web server and framework for handling image uploads. JavaScript is used for the client side of the application

An SSL Certificate will not be needed since the URL will contain localhost and a port number.

Requirements For Locally Hosted PWA

Glossary:

IP

Internet Protocol address is a numerical label that is assigned to a device connected to a computer network.

Wi-Fi

Wireless network protocols based on the IEEE 802.11 standards for local area networks.

WLAN

Wireless LAN is a computer network that links 2 or more devices.

TCP/IP

Transmission Control Protocol/Internet Protocol is a framework for computer networking.

USB

Universal Serial Bus is a standard for digital data transmission and power delivery between electronics.

ADB

Android Debug Bridge.

PWA

Progressive Web App is built using web platforms to provide platform-specific experiences.

Android Devices

Recording Devices
Name Description Recording Power
Sony Xperia XA1 Ultra Updated to Android 8.0 and latest web browser. Takes photos and videos on front and back cameras. USB Type-C 2.0 10W charging
Samsung Galaxy S21 FE 5G Updated to Android 14.0 and default camera application. Takes photos and videos on front and back cameras. USB Type-C 2.0 <25W charging
Name Description Example

HTML Take Photo Every 3 Seconds (Includes iOS Fix)

<!DOCTYPE html>
<html>

<head>
	<title>Chicken Security Cam</title>
	<meta name="viewport" content="width=device-width, initial-scale=1" />
	<style>
		button { color: blue; background: red; }
		video { width:100%; height: auto; max-height: 100%; }	
	</style>
	<link rel="manifest" href="/chicken-cam-pwa-manifest.json" />
</head>

<body>
	<select></select>
	<button type="button">Record</button>
	<video muted playsinline></video>	
	<script src="/chicken-cam-pwa.js"></script>
</body>

</html>

JavaScript Take Photo Every 3 Seconds And Register PWA Service Worker

(() => {
	let str = null;
	let iid = null;
	let ppt = null;
	let vid = document.querySelector('video');
	let btn = document.querySelector('button');
	let sel = document.querySelector('select');
	let cts = {
	  video: {
			width: {min: 1920, ideal: 3840, max: 7680},
			height: {min: 1080, ideal: 2160, max: 4320}
	  },
	  audio: false
	};
	navigator.mediaDevices.getUserMedia(cts).then(() => {
		navigator.mediaDevices.enumerateDevices().then((devices) => {
			let vds = devices.filter(device => device.kind == 'videoinput');
			let opt = vds.map(vd => {
				return `<option value="${vd.deviceId}">${vd.label}</option>`; 
			});
			sel.innerHTML = `<option value="">Select Camera</option>` + opt.join('');
		});
	});
	if ("serviceWorker" in navigator) {
		window.addEventListener("load", () => {
			// Register Server Worker
			navigator.serviceWorker
			.register("./chicken-cam-pwa-service-worker.js")
			.then(res => console.log("Service Worker Registered"))
			.catch(err => console.log("Service Worker Not Registered", err));
		});
	}
	sel.addEventListener('change', (evt) => {
		if (str !== null) {
			 str.getTracks().forEach(track => {
				  track.stop();
				  vid.srcObject.removetrack(track);
			 });
			 vid.pause();
			 vid.src = '';
			 str = null;
		} 
		if (sel.value !== "") {
			 cts.video.deviceId = sel.value;
			 navigator.mediaDevices.getUserMedia(cts).then((stream) => {
				 str = stream;
				 vid.srcObject = stream;
				 vid.play();
			 });
		}
	});
	btn.addEventListener('click', (evt) => {
		if (btn.innerHTML === 'Record') {
			 btn.innerHTML = 'Recording';
			 iid = setInterval(() => {
				  let canvas = document.createElement('canvas');
				  let context = canvas.getContext('2d');
				  canvas.width = vid.videoWidth;
				  canvas.height = vid.videoHeight;
				  context.drawImage(vid, 0, 0, canvas.width, canvas.height);
				  canvas.toBlob((blob) => {
						let file = new File([blob], 'image.png', {type: blob.type});
						let fd = new FormData();
						fd.append('image', file);
						fetch('save-hi-res.php', {
							 method: 'POST',
							 body: fd
						})
						 .then(response => response.json())
						 .then(data => console.log(data))
						 .catch(error => console.error(error));
				  })
			 }, 3000);
		} else {
			 btn.innerHTML = 'Record';
			 clearInterval(iid);
		}
	});
})();

JavaScript Service Worker Install

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open('chicken-cam-pwa').then((cache) => {
            return cache.addAll([
                '/',
                '/chicken-cam-pwa.html',
                '/chicken-cam-pwa.js',
                '/hi-res.html'
            ]);
        })
    );
});

self.addEventListener("fetch", fetchEvent => {
  fetchEvent.respondWith(
    caches.match(fetchEvent.request).then(res => {
      return res || fetch(fetchEvent.request);
    })
  );
});

JSON Manifest

{
  "name": "Chicken Security Camera",
  "short_name": "Chicken Cam",
  "start_url": "chicken-cam-pwa.html",
  "display": "standalone",
  "icons": [
    {
      "src": "chicken-cam-pwa.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "screenshots": [
    {
      "src": "chicken-cam-pwa-screenshot.avif",
      "sizes": "1080x1920",
      "form_factor": "narrow",
      "label": "Desktop view showing chicken security camera"
    },
    {
      "src": "chicken-cam-pwa-screenshot-wide.avif",
      "sizes": "1920x1080",
      "form_factor": "wide",
      "label": "Desktop view showing chicken security camera"
    }
  ]
}

JavaScript Refresh Photo Every 3 Seconds

// Reload Every 3 Seconds
setInterval(function(){
   let img = document.querySelector('img');
   if ( !img.src.includes('?') ) {
      img.src = `${img.src}?${Date.now()}`;
   } else {
      img.src = img.src.slice(0, img.src.indexOf('?') + 1) + Date.now();
   }        
}, 3000);

PHP Upload Photo

if ( !empty($_FILES['image']) ) {
   $file = $_FILES['image']['tmp_name'];
   $destination = dirname(__FILE__) . '/image.png';
   if (move_uploaded_file($file, $destination) ) {
      echo json_encode(['status' => 'OK']);
   }
}
die();

Download

The PHP scripting language can be downloaded from Downloads & Installation Instructions and installed on your workstation.

The ADB tool can be downloaded as part of the SDK Platform Tools for Download SDK Platform Tools and decompressed into a folder on your workstation.

PHP HTTP Server

php -S localhost:8000

ADB Wireless Connection

# Command Line #
adb tcpip 5555
adb tcpip connect [Android Device IP Address]
adb devices

ADB Wireless Command Line Setup
Android Debug Bridge (ADB) Command Line Setup For Wireless Setup

Chrome Browser DevTools Devices Port Forward
Google Chrome Web Browser DevTools Devices Listed And Port Forwarding Setup

Chrome Browser Remote Debug For Android
Google Chrome Web Browser DevTools Remote Debug For Android Devices

PWA Install Prompts
PWA Install Prompts For Both Desktop And Mobile

PWA Uninstall Menu
PWA Uninstall Menu For Both Desktop And Mobile

PWA Uninstall Prompts
PWA Uninstall Prompts For Both Desktop And Mobile


Usage

You can use any IDE or text editor and the web browser to compile and execute JavaScript code. For this tutorial, the OjamboShop.com Learning JavaScript Course Web IDE can be used to input and compile JavaScript code for the HTML5 Security Camera.

Open Source

JavaScript follows the ECMAScript standard and is licensed under the W3C Software License by web browser vendors and runtime environment vendors.

PHP scripting language is licensed under the PHP License by The PHP Group. The Zend Engine is a compiler and runtime environment for PHP and is licensed under the Zend Engine License.

Live Stream

Every day, you can join a live stream and ask questions. Check Ojambo.com for details and instructions.

Learn Programming Courses:

Get the Learning JavaScript Course or the Learning PHP Course for your web browser on any device.

OjamboShop.com Learning JavaScript Course
OjamboShop.com Learning JavaScript Interactive Online Course

OjamboShop.com Learning PHP Course
OjamboShop.com Learning PHP Interactive Online Course

Learn Programming Books:

Learning JavaScript Book is available as Learning JavaScript Paperback or Learning JavaScript Ebook.

Learning PHP Book is available as Learning JavaScript Ebook.

OjamboShop.com Learning JavaScript Book Announcement
OjamboShop.com Learning JavaScript Ebook And Paperback Announcement

OjamboShop.com Learning PHP Book Announcement
OjamboShop.com Learning PHP Ebook Announcement

Conclusion:

Port forward the locally hosted port to your Android device using ADB for a wireless connection. The PWA application can be debugged or installed on the Android device without having an SSL Certificate due to the localhost URL. For iOS devices, the video tag must have muted and playsinline attrbiutes for the preview.

If you enjoy this article, consider supporting me by purchasing one of my OjamboShop.com Online Programming Courses or publications at Edward Ojambo Programming Books or simply donate here Ojambo.com Donate

References:

Leave a Reply

Your email address will not be published. Required fields are marked *