Dropcam with On/Off capability

I extended the Dropcam device handler with the switch capability, allowing me to turn the camera on and off. My use case is that, although Dropcam is location aware and can automatically turn off when your phone is close, it currently cannot track more than one phone. With this device handler I am able to turn the camera off when either me or my wife get home (mode is set to ‘Home’). This also allows me to automatically turn the camera on at night.

Here is the code: https://github.com/FlorianZ/SmartDevices/blob/master/Dropcam.groovy

dope!

I pasted the app into the ide and got the following error

groovy.lang.MissingMethodException: No signature of method: script13983778252291035982242.metadata() is applicable for argument types: (script13983778252291035982242$_run_closure1) values: [script13983778252291035982242$_run_closure1@5ef7c05b]
Possible solutions: getMetadata(), getState(), setState(java.lang.Object), metaClass(groovy.lang.Closure)

is this device type still compatible with dropcam? what value do i enter for “device id” in preferences?

Sorry, I haven’t been maintaining this device handler. I am contemplating on adding the on/off capability to what is currently the official Dropcam device handler. I don’t know if there is a workflow for publishing changes to a device handler provided by SmartThings, but I think the on/off capability is a pretty useful feature.

does anyone have the complete source to the dropcam device type or the source to the dropcam connect app?

i’d like to properly integrate this feature and store the credentials more securely. thank you.

You can go to the IDE, My SmartApps, create a new SmartApp, click Browse SmartApps in the top right corner and find Dropcam (Connect) to check out the source code of the official app.

Your credentials are stored much more securely in the newer versions of the app. I created my device handler before storing credentials securely was available in apps / handlers.

If you get a chance to integrate the On/Off capability with the new device handler / app, definitely let us know. I’d love to use your code, if I may. Haven’t had a chance to get the feature integrated and I definitely miss it with the new handler. Maybe you can Publish your chances to get the integrated into the official code?

i can’t find the “browse” functionality when i create a new smartapp. does this still exist or how can i see it?

i also looked at the device type example for dropcam and it is incomplete. i’m mostly interested in how the device handler interacts with dropcam connect to use the credentials securely.

It looks complete to me. It’s just that most of the functionality is implemented in the Dropcam (Connect) SmartApp. The device handler is spawned as a child device of that app.

It should. I just tried it myself. Instead of creating a new app, have you tried clicking on an existing one to see if the link exists there? Also, you should be on the code editor tab, not the app settings.

i fee like i’m missing something…i’ve attached a screenshot of what i see. am i in the wrong place? can you send me the smartapp source code?

Looks like they are rolling out some sort of new IDE. I am still picking up the old one, which doesn’t have this feature removed. Did you check if there is any other way to browse existing Apps. Maybe it’s under Documentation now?

Also, I had to click on one of my existing SmartApp, before the link showed up. Creating a new app doesn’t show the link. Maybe you need to save the new app first, then go back to the code editor?

found it. after you create the app, the “browse” feature appears and i can see dropcam connect code. i “hacked” a device type to add the switch feature you provided, but leveraged the credentials/uid from the parent app:

metadata {
	// Automatically generated. Make future change here.
	definition (name: "Dropcam (Switch)", namespace: "we", author: "the people") {
		capability "Actuator"
		capability "Image Capture"
        capability "Switch"
        capability "Refresh"
        capability "Polling"
	}

	simulator {
		status "image": "raw:C45F5708D89A4F3CB1A7EEEE2E0C73D900, image:C45F5708D89A4F3CB1A7EEEE2E0C73D9, result:00"

		reply "take C45F5708D89A4F3CB1A7EEEE2E0C73D9": "raw:C45F5708D89A4F3CB1A7EEEE2E0C73D900, image:C45F5708D89A4F3CB1A7EEEE2E0C73D9, result:00"
	}

	tiles {
		standardTile("camera", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: true) {
			state "default", label: "", action: "", icon: "st.camera.dropcam-centered", backgroundColor: "#FFFFFF"
		}

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

		standardTile("take", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
			state "take", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
			state "taking", label:'Taking', action: "", icon: "st.camera.dropcam", backgroundColor: "#53a7c0"
			state "image", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
		}
        
        standardTile("switch", "device.switch", canChangeIcon: true) {
            state "on", label: 'On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
            state "off", label: 'Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
        }

        standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
            state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
        }


		main "camera"
		details(["cameraDetails", "take", "switch", "refresh"])
	}
}

def uninstalled() {
	parent?.removeChildFromSettings(this)
}

// parse events into attributes
def parse(String description)
{
	log.debug "Parsing '${description}'"
	// TODO: handle 'image' attribute
	// TODO: handle '' attribute

}

// handle commands
def take()
{
	if (!isStreamingEnabled())
    {
    	log.debug "unable to take picture, camera off"
        return
    }
    //else
    
	log.debug "Executing 'take'"

	def dni = device.deviceNetworkId
	log.debug "Executing 'take' with dni $dni"


	log.debug "Executing 'take' with dni $dni and parent $parent with app ${parent.installedSmartApp}"

	def imageBytes = parent.takePicture(dni, null)

	log.debug "got bytes"

	if(imageBytes)
	{
		storeImage(getPictureName(), imageBytes)
	}
}

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

//custom code
def updated() {
    refresh()
}

def on() {
    log.debug "Turning Dropcam on"
    setProperties("streaming.enabled", true)
    sendEvent(name: "switch", value: "on", isStateChange: true)
}

def off() {
    log.debug "Turning Dropcam off"
    setProperties("streaming.enabled", false)
    sendEvent(name: "switch", value: "off", isStateChange: true)
}

def poll() {
    refresh()
}

def refresh() {
    //log.debug "Refreshing Dropcam" +  getCameraUuid()
    //log.debug "parent qs: " + parent.validUserAgent()
    //log.debug "cookie: " + getCookieValue()
    
    log.debug "Refreshing Dropcam"
    
    //log.debug "streaming enabled: " + isStreamingEnabled()

    def items = getProperties()
    
    def streamingEnabled = isStreamingEnabled()
    
    if (streamingEnabled) {
        sendEvent(name: "switch", value: "on", isStateChange: true)
    } else {
        sendEvent(name: "switch", value: "off", isStateChange: true)
    }
    
    log.debug "Switch is now $streamingEnabled"

}

private getProperties() {
    
    def content
    httpGet(
        [
            uri: "https://www.dropcam.com",
            path: "/api/v1/dropcams.get_properties",
            query: [uuid: getCameraUuid()],
            headers: [Cookie: getCookieValue(), 'User-Agent': validUserAgent()],
            requestContentType: "application/x-www-form-urlencoded"
        ],
        { response -> content = response.data; log.debug "dropcams.get_properties response: '${response.data.inspect()}'" }
    )
    def props = content?.items
    if (props) {
        return props[0]
    }
    return [:]
}

private setProperties(key, value) {
    
    def success = false
    def uuid = getCameraUuid()
    httpPost(
        [
            uri: "https://www.dropcam.com",
            path: "/api/v1/dropcams.set_property",
            headers: [Cookie: getCookieValue(), 'User-Agent': validUserAgent()],
            requestContentType: "application/x-www-form-urlencoded",
            body: "uuid=$uuid&key=$key&value=$value"
        ],
        { response -> success = (response.status == 200); log.debug "dropcams.set_property response: '${response.data.inspect()}'" }
    )
    return success
}

private getCameraUuid() {
	device.deviceNetworkId.split(/\./)?.last()
}

private validUserAgent() {
    parent.validUserAgent()
}

private getCookieValue() {
    parent.state.cookie
}

private isStreamingEnabled()
{
	def items = getProperties()
    
    def streamingEnabled = items?.'streaming.enabled'
    
    if (streamingEnabled == null) {
    	return false
    }
    //else
    
    if (streamingEnabled) {
        return true
    } else {
        return false
    }

}
3 Likes

Fantastic! Thanks. Has it been working reliably for you? And do you mind updating the code on GitHub? You can create a pull request, or I’ll just update it from my working directory.

@gorf I get the following error when I try to paste into the ide

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
script14140201982581957144975.groovy: 92: unexpected token: } @ line 92, column 1.
}
^

@gorf I am also looking for this solution. I haven’t been able to get anything to simply turn off the Dropcams based on any trigger.
I get this error when creating a new device with this code.

Grails.validation.ValidationException: Validation error whilst flushing entity [physicalgraph.device.DeviceType]: - Field error in object ‘physicalgraph.device.DeviceType’ on field ‘author’: rejected value []; codes [physicalgraph.device.DeviceType.author.blank.error.physicalgraph.device.DeviceType.author,physicalgraph.device.DeviceType.author.blank.error.author,physicalgraph.device.DeviceType.author.blank.error.java.lang.String,physicalgraph.device.DeviceType.author.blank.error,deviceType.author.blank.error.physicalgraph.device.DeviceType.author,deviceType.author.blank.error.author,deviceType.author.blank.error.java.lang.String,deviceType.author.blank.error,physicalgraph.device.DeviceType.author.blank.physicalgraph.device.DeviceType.author,physicalgraph.device.DeviceType.author.blank.author,physicalgraph.device.DeviceType.author.blank.java.lang.String,physicalgraph.device.DeviceType.author.blank,deviceType.author.blank.physicalgraph.device.DeviceType.author,deviceType.author.blank.author,deviceType.author.blank.java.lang.String,deviceType.author.blank,blank.physicalgraph.device.DeviceType.author,blank.author,blank.java.lang.String,blank]; arguments [author,class physicalgraph.device.DeviceType]; default message [{0} cannot be blank]

sorry everyone. the validation error is asking you to specify an author. i’ve updated the sample code to include one so you should be able to paste it successfully.

so far this device type has been working for me. the only side effect i have noticed is that whatever saved pictures you create with the “take” action disappear when the camera is switched on/off. not sure if that matters to you or not.

Thanks. I can now create a new device type using the code. Any tricks to getting a new device created after that? When I try to configure the device on the mobile app under things, it asks to “name this device”, and when I tap Next I get “An unexpected error has occurred”. The device remains listed on the mobile app as "Not yet configured"
I tried removing it and starting over with same results. I am new to Smartthings and maybe its just the sequence that I am doing things in.
In the live log I get this;
error java.lang.NullPointerException: Cannot get property ‘state’ on null object @ line 139

i set mine up by using the dropcam (labs) under camera. afterward i went into the developer tools (where you setup the device type) and changed the device type for the dropcam device. select “my devices”, click the dropcam you configured through dropcam labs, edit the device and change the type.

@florianz
Do you have any DLink cameras?
I’m trying to turn my DLink cameras on and off by ST mode. Or just turn the motion on and off would be fine.
Can your code be modified to work with DLink?

scottinpollock wrote this simple app for DLink but it’s not working yet:
http://solutionsetcetera.com/stuff/STApps/DLinkMotionMode.groovy

Thanks