Android IP Camera Device

Cool. Thanks, Rob.


Created a new device type with this code, and the ST device won’t open, get an error that says 'Sorry, but there was an unexpected error."

Like Toasty, I too am getting “Sorry, but there was an unexpected error” when I click on the device in my android app. I have the paid version and have ports properly forwarded. I can view the camera remotely using the ip address and forwarded port in a web browser. I have double checked that all info is correct in ST device settings and have already deleted and reinstalled the device type and the device.

UPDATE: I installed the record app and set up a rule to snap photos when my door opened
and it worked. I supposed this means that the device is properly configured. I still get an error and no control panel when I click on the device in the android app.

Any ideas would be greatly appreciated.

Exactly same problem here. I can access the camera though its ip address, so it’s properly configured ports and all. However I get the unexpected error message when I click on the device in the ST app. I am using ST v2 if that makes any difference.

Has anyone gotten this to work with the V2 hub? I get the same “Sorry, but there was an unexpected error” message.

I get the error too on Hub v2. If you click on the “Recently” tab under “Things” for your Camera you should see pictures it has taken. You can set it to take video, but you don’t see that under “Recently”. Videos and pictures are stored on the phones internal memory.

I tried this and get the error “Error loading tiles for %s”. Did I copy the code incorrectly?

@rob_a_landry

Are you the one or should we look for another? :slight_smile:

I’m getting the same error as @tbs26.

try to remove some of the tiles, strip it to bare camera functionality. Its temperature or battery what is breaking it, i moved to tasker for my N7 camera control so not sure now what exactly fixed it.

This is not crashing on N7:

1 Like

Lind Lau,
That gets me closer as I no longer have an error, just no video.

i just had photos in carousel, when u snap a photo in app it should appear there after a while, like i said i never bothered with video , as u can add feed directly to smarttiles and thats what im using for monitoring, app is pretty useless for that.

sorry, cant be more helpfull im noobie myslf :slight_smile:

It was a help, thanks! I am not getting video to Smarttiles either. Just a blank box. :cry:

can you access your feed via ip? eg. 192.168.1.22:909 ? ip should be listed somewhere in ur ruter, and port u can select in IP webcam app

if yes, try generic MJPEG. device you watching it on must be in the network otherwise u would need to forward port to your camera

In the generic MJPEG url of Smartiles, you have to put ‘http://<ipaddress>:<port>/video’. Note /video at the end.
Eg: http://92.156.44.13:8080/video
Actually I am seeing now it is said the very first post where it says: “http://username:password@{hostname or ip}:port/video”

Second edit: I can’t get it to work with user and pass in the URL. It works without adding them to the URL but the browser will prompt for user and pass at each new session.

Thanks Lind for the tip to use generic MJPEG. At least now I can see the feed in Smarttiles. I still can’t record though, but it’s one step forward.

Does this device type still work? I’m getting an error message after configuring the device on my phone.

https://drive.google.com/file/d/0B_Vtu1lA7G8lYVlWTmNOUTA3UVE/view?usp=sharing

When I am able to communicate I get Sorry, but there was an unexpected error" is this code still useable and is there an update? am I doing something incorrect? any info would help, thanks.

So, I have this semiworking using the striped down code. I don’t seem to be getting any sensor data. Is there a way to poll the webserver? I have sensor logging enabled.

ok, I’ve made some edits. Im looking at getting the mag sensor working.

This has lux working .

preferences
{
	input("username",	"text",		title: "Camera username",	description: "Username for web login")
	input("password",	"password",	title: "Camera password",	description: "Password for web login")
	input("url",		"text",		title: "IP or URL of camera",	description: "Do not include http://")
	input("port",		"text",		title: "Port",			description: "Port")
}

metadata {
	definition (name: "Android IP Camera Beta", author: "Alan", namespace: "alt") {
		capability "Image Capture"
		capability "Switch"
		capability "Actuator"
		capability "Battery"
       	capability "Illuminance Measurement"
		capability "Temperature Measurement"

		command "ledOn"
		command "ledOff"
		command "focusOn"
		command "focusOff"
		command "overlayOn"
		command "overlayOff"
		command "nightVisionOn"
		command "nightVisionOff"
		command "refresh"


	}

	tiles {
		carouselTile("cameraDetails", "device.image", width: 3, height: 2) { }

		standardTile("camera", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: true) {
			state("default", label: '', action: "Image Capture.take", icon: "st.camera.camera", backgroundColor: "#FFFFFF")
		}

		standardTile("take", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false, decoration: "flat") {
			state("take", label: 'Take Photo', action: "Image Capture.take", icon: "st.camera.take-photo", nextState:"taking")
			state("taking", label: 'Taking...', action: "Image Capture.take", icon: "st.camera.take-photo", backgroundColor: "#79b821")
		}

		standardTile("record", "device.switch", width: 1, height: 1) {
			state("recordOff", label: 'Record Off', action:"switch.on", icon:"st.switches.light.off", backgroundColor: "#ffffff")
			state("recordOn", label: 'Record On', action:"switch.off", icon:"st.switches.light.on", backgroundColor: "#79b821")
		}




		standardTile("led", "device.led", width: 1, height: 1) {
			state("ledOff", label: 'Led Off', action:"ledOn", icon:"st.switches.light.off", backgroundColor: "#ffffff")
			state("ledOn", label: 'Led On', action:"ledOff", icon:"st.switches.light.on", backgroundColor: "#79b821")
		}

		standardTile("focus", "device.focus", width: 1, height: 1) {
			state("focusOff", label: 'Focus Off', action:"focusOn", icon:"st.switches.light.off", backgroundColor: "#ffffff")
			state("focusOn", label: 'Focus On', action:"focusOff", icon:"st.switches.light.on", backgroundColor: "#79b821")
		}

		standardTile("overlay", "device.overlay", width: 1, height: 1) {
			state("overlayOff", label: 'Overlay Off', action:"overlayOn", icon:"st.switches.light.off", backgroundColor: "#ffffff")
			state("overlayOn", label: 'Overlay On', action:"overlayOff", icon:"st.switches.light.on", backgroundColor: "#79b821")
		}

		standardTile("nightVision", "device.nightVision", width: 1, height: 1) {
			state("nightVisionOff", label: 'Night Vision Off', action:"nightVisionOn", icon:"st.switches.light.off", backgroundColor: "#ffffff")
			state("nightVisionOn", label: 'Night Vision On', action:"nightVisionOff", icon:"st.switches.light.on", backgroundColor: "#79b821")
		}


		valueTile("battery", "device.battery", decoration: "flat", width: 1, height: 1) {
			state "battery", label:'${currentValue}% battery', unit:""
		}
        
		valueTile("light", "device.illuminance", inactiveLabel: false, width: 1, height: 1, decoration: "flat", wordWrap: true) {
			state "default", label:'Lux\n${currentValue}'
		}

		valueTile("magnetic", "device.magnetic", inactiveLabel: false, width: 1, height: 1, decoration: "flat", wordWrap: true) {
			state "default", label:'Mag\n${currentValue}'
		}
		valueTile("magy", "device.magy", inactiveLabel: false, width: 1, height: 1, decoration: "flat", wordWrap: true) {
			state "default", label:'Magy\n${currentValue}'
		}
		valueTile("magz", "device.magz", inactiveLabel: false, width: 1, height: 1, decoration: "flat", wordWrap: true) {
			state "default", label:'Magz\n${currentValue}'
		}
		main "camera"
		details(["cameraDetails","camera","take","record","led","focus","overlay","nightVision","battery","light","magnetic","magy","magz"])
	}
}


def parseCameraResponse(def response) {
	if(response.headers.'Content-Type'.contains("image/jpeg")) {
		def imageBytes = response.data

		if(imageBytes) {
			storeImage(getPictureName(), imageBytes)
		}
	} else {
		log.error("${device.label} could not capture an image.")
	}
}

private getPictureName() {
	def pictureUuid = java.util.UUID.randomUUID().toString().replaceAll('-', '')
	"image" + "_$pictureUuid" + ".jpg"
}

private take() {
	log.info("${device.label} taking photo")

	httpGet("http://${username}:${password}@${url}:${port}/photo_save_only.jpg"){
		httpGet("http://${username}:${password}@${url}:${port}/photo.jpg"){
			response -> log.info("${device.label} image captured")
			parseCameraResponse(response)
		}
	}
}

def on(theSwitch="record") {
	def sUrl
	switch ( theSwitch ) {
		case "led":
			sUrl = "enabletorch"
			break

		case "focus":
			sUrl = "focus"
			break

		case "overlay":
			sUrl = "settings/overlay?set=on"
			break

		case "nightVision":
			sUrl = "settings/night_vision?set=on"
			break

		default:
			sUrl = "/startvideo?force=1"
	}

	httpGet("http://${username}:${password}@${url}:${port}/${sUrl}"){
		response -> log.info("${device.label} ${theSwitch} On")
		sendEvent(name: "${theSwitch}", value: "${theSwitch}On")
	}

}

def off(theSwitch="record") {
	def sUrl
	switch ( theSwitch ) {
		case "led":
			sUrl = "disabletorch"
			break

		case "focus":
			sUrl = "nofocus"
			break

		case "overlay":
			sUrl = "settings/overlay?set=off"
			break

		case "nightVision":
			sUrl = "settings/night_vision?set=off"
			break

		default:
			sUrl = "stopvideo?force=1"
	}

	httpGet("http://${username}:${password}@${url}:${port}/${sUrl}"){
		response -> log.info("${device.label} ${theSwitch} Off")
		sendEvent(name: "${theSwitch}", value: "${theSwitch}Off")
	}

}

def ledOn() { on("led") }

def ledOff() { off("led") }

def focusOn() { on("focus") }

def focusOff() { off("focus") }

def overlayOn() { on("overlay") }

def overlayOff() { off("overlay") }

def nightVisionOn() { on("nightVision") }

def nightVisionOff() { off("nightVision") }

def installed() { runPeriodically(20*60, poll) }

def configure() { poll() }

def poll() { refresh() }

def refresh() { getSensors() }

def cToF(temp) {
	return temp * 1.8 + 32
}

def getSensors() {

	def params = [
		uri: "http://${username}:${password}@${url}:${port}",
		path: "/sensors.json",
		contentType: 'application/json'
	]

	log.debug "Params = ${params}"

	def theSensor
	def theUnit
	def theData
    def n

	try {
		httpGet(params) { 
			response -> log.debug "Start httpGet"
			response.data.each {
				key,value -> theSensor = key
				theUnit = value.unit
				if (value.data[0][1].size() == 1) {
					theData = value.data[0][1].first() 
					if (theSensor == "battery_level") {theSensor = "battery"}
					if (theSensor == "battery_temp") {
						theSensor = "device temperature"
						theUnit = "F"
						theData = cToF(theData as Integer)
                    }
					if (theSensor == "ambient_temp") {
						theSensor = "temperature"
						theUnit = "F"
						theData = cToF(theData as Integer)
                    }

                    if (theSensor == "battery_voltage") {
                    	theSensor = "battery Volt"
                    }
                    

					if (theSensor == "light") {
						theSensor = "illuminance"
						theUnit = "lux"
					}
		
					log.info "name: ${theSensor}, value: ${theData}, unit: ${theUnit}"
					sendEvent(name:"${theSensor}", value: theData as Integer, unit:"${theUnit}")
    
               } else { theData = value.data[0][1] }
				log.debug "${theSensor}: ${theUnit} ${theData}"
			}
		}
	}
	catch(e) { log.debug "$e" }
}

Are we able to detect motion as well? This seems interesting.