Generic IP camera code just not working


(Roy Donaldson) #1

I’m trying to connect up to my Cisco IP cameras. They give back a jpeg image when you do a basic http request to them. I have tested this request using the exact link my Device Handler is calling and it pulls the image back.

Can anyone tell me why, this code just does not work:

/** Generic IP Camera
*

  • rdonalds
  • Generic IP Camera pull app

*/

metadata {
definition (name: “GenericIPCamera”, namespace: “”, author: “Roy Donaldson”) {
capability “Image Capture”
}

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

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"
        }
main "camera"
details(["cameraDetails","take"])
}

}

def parseCameraResponse(def response) {
def imageBytes = response.data

    if(imageBytes) {
        storeImage(getPictureName(), imageBytes)
        log.info("Stored image")
    }
} 

private getPictureName() {
response = “image.jpg”
}

private take() {
log.info("${device.label} taking photo")
log.info(“http://${username}:${password}@${url}:${port}/img/mjpeg.cgi”)

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

}


(Dan) #2

I’m no expert, but I believe the network response from the camera is funneled to a parse() function in the device type handler. Try adding a parse() function instead of parseCameraResponse().


(JZst) #3

Ditto… I’ve never seen parseCameraResponse() and verified again here: http://docs.smartthings.com/en/latest/smartapp-developers-guide/calling-web-services-in-smartapps.html

Pull up my user in this community and check out the few devices/posts that you should use as references. FYI, the image is stored on S3 cloud and never referred to again other than storing the image. Seems that ST implicitly paints any device.image tile with the image — but no expert just based on my long examination of code & behavior.


(Roy Donaldson) #4

Ok, tried to update this a bit more, but still can’t get it to work. Can anyone off some help on this:

/** Generic IP Camera
*

  • rdonalds
  • Generic IP Camera pull app

*/

metadata {
definition (name: “GenericIPCamera”, namespace: “roydonaldson11”, author: “Roy Donaldson”) {
capability “Image Capture”
}
simulator {
}
preferences {
input(“username”, “text”, title: “Camera username”, description: “Username for web login”, required: true)
input(“password”, “password”, title: “Camera password”, description: “Password for web login”, required: true)
input(“url”, “text”, title: “IP or URL of camera”, description: “Do not include http://”, required: true)
input(“port”, “text”, title: “Port”, description: “Port”, required: true)
}
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”
}
main "camera"
details([“cameraDetails”,“take”])
}
}

def parse(def response) {
log.debug “description: ${response}”
def imageBytes = response.data
log.info(“parse entered”)
if(imageBytes) {
storeImageInS3(getPictureName(), imageBytes)
log.info(“Stored image”)
}
else {
log.info"Nothing stored"
}
}

private getPictureName() {
response = “image.jpg”
}

private take() {
log.info("${device.label} : taking photo")
log.info(“http://${username}:${password}@${url}:${port}/img/mjpeg.cgi”)

httpGet("http://${username}:${password}@${url}:${port}/img/mjpeg.cgi"){
    log.info("${device.label} : image captured")
}

}


(codersaur) #5

If you are using httpGet() the response doesn’t come back via parse(), it comes straight back to the closure method defined…

E.g. you might want to do something like this…

def params = [
    uri: "http://${username}:${password}@${url}:${port}",
    path: "/img/mjpeg.cgi"
    // Define any other headers you want to send.
]

try {
    httpGet(params){ resp ->
        log.debug "Response status: ${resp.status}"   
        log.debug "response contentType: ${resp.contentType}"

        def imageBytes = resp.data

        // Do something with imageBytes...

    }
} catch (e) {
    log.debug "something went wrong: $e"
}

Note, looking at your code, I’m unsure where storeImageInS3() is defined, what it returns, or how you reference the image subsequently…


(Kevin) #6

@zcapr17 is correct, you should still have a parse method defined, but it is not used in this type of device handler so it can be left empty. You do not need to define storeImageInS3() because it is an internal SmartThings command.

I’m pretty sure that when you press the tiles, nothing at all is happening because the action needs to be “imageCapture.take”, not “Image Capture.take”. I think if you make this change, the first version you posted will work.


(Roy Donaldson) #7

I’ve managed to get the code now working. However, 2 things fail:

  • Image size limit when using StoreImage or StoreImageinS3. Seems to limit at 1Mb file size, which is useless.

  • When I drop the filesize, I must have hit a time when the platform was not running well, as it just started throwing spurious log errors at that time.


(Kevin) #8

I posted a list of questions about storing images and the carousel tile in the private lounge 11 days ago and they said they’d give me some answers last week, but they didn’t.

I asked them for a status earlier this morning and I included the question below.

  • It looks like there’s a file size limit of a little over 1MB for storing images which is a problem for a lot of cameras. Are there any conversion commands that allow you to resize the image before storing it?

If they give me a response, I’ll post it here.


(Kevin) #9

They responded to my question about a conversion tool for images:

At the moment we do not have conversion commands for image. We are looking at various options on best to covert image files, and the timing of this feature is still needs to be worked out.