Pairing a Vistacam

@stickstickly - I’m unsure. I’ve only tested with the 8910w, but I expect it should work with most non-HD cameras. If it does not work, it probably wouldn’t be a big deal to create a new device controller.

The 9821 that I am buying is foscams 720p version. Are you saying that definitely won’t work since its an hd version?

@stickstickly

I have worked with enough different Foscams to tell you it definitely won’t work with your 9821 without some modifications. The MJPEG cameras (8910, 8907, 8918, etc…) use a very different set of command URLs than the HD H.264 models. There is also quite a bit of variation in the command URLs for the HD models. If you can find the command URLs for your camera (I would start at the forums at foscam.us), it would be relatively simple to find and replace the command URLs in @imbrian Foscam device to make it work with you camera.

http://www.ispyconnect.com/man.aspx?n=foscam

That link my help.

I’ve set it up, and configured both the new device type and the new smart app. I haven’t turned on the smart app, and I understand that I can turn on and off alarm status with it.

One thing, from the things page can I control the camera and take snapshots etc?

I was considering using your template, and having my foscam go to different presets depending upon a motion detection or vibration sensor.

Have you done any of that yet?

If anyone is curious, I got it to work with a FI8910W cam, I had to make one change to the Device type specific by @ImBrian to get it to work with that cam, the snapshots were coming across. If anyone wants that code change I can send it to them if they were curious.

I wouldn’t mind seeing that code. I have that cam. Thanks.

This is the change i made for the get request, ONLY to the device type so the take method would work.

/**
 *  Foscam  - FI8910W 
 *
 *  Author: danny@smartthings.com
 *  Author: brian@bevey.org
 *  Author: morgan@jedifan.com
 *  Date: 01/29/2014
 *
 *  Modified this to work with FI8910W
 *
 *  Modified example Foscam device type to support dynamic input of credentials
 *  and enable / disable motion alarm to easily integrate into homemade
 *  security systems (when away, mark "alarmStatus" as "on", when present, mark
 *  "alarmStatus" as "off".  For use with email or FTP image uploading built
 *  into Foscam cameras.
 *
 *  Capability: Image Capture, Polling
 *  Custom Attributes: setStatus, alarmStatus
 *  Custom Commands: alarmOn, alarmOff, toggleAlarm, left, right, up, down,
 *                   pause, set, preset, preset1, preset2, preset3
 */
 
preferences {
  input("username", "text", title: "Username", description: "Your Foscam username")
  input("password", "password", title: "Password", description: "Your Foscam password")
  input("ip", "text", title: "IP address", description: "The IP address of your Foscam")
  input("port", "text", title: "Port", description: "The port of your Foscam")
}

// for the UI
metadata {
  tiles {
    carouselTile("cameraDetails", "device.image", width: 3, height: 2) { }

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

    standardTile("take", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false, decoration: "flat") {
      state "take", label: "", action: "Image Capture.take", icon: "st.secondary.take", nextState:"taking"
    }

    standardTile("up", "device.image", width: 1, height: 1, canChangeIcon: false,  canChangeBackground: false, decoration: "flat") {
      state "take", label: "up", action: "up", icon: ""
    }

    standardTile("alarmStatus", "device.alarmStatus", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
      state "off", label: "off", action: "toggleAlarm", icon: "st.camera.dropcam-centered", backgroundColor: "#FFFFFF"
      state "on", label: "on", action: "toggleAlarm", icon: "st.camera.dropcam-centered",  backgroundColor: "#53A7C0"
    }

    standardTile("left", "device.image", width: 1, height: 1, canChangeIcon: false,  canChangeBackground: false, decoration: "flat") {
      state "take", label: "left", action: "left", icon: ""
    }

    standardTile("pause", "device.image", width: 1, height: 1, canChangeIcon: false,  canChangeBackground: false, decoration: "flat") {
      state "pause", label: "pause", action: "pause", icon: ""
    }
    
    standardTile("right", "device.image", width: 1, height: 1, canChangeIcon: false,  canChangeBackground: false, decoration: "flat") {
      state "take", label: "right", action: "right", icon: ""
    }

    standardTile("blank", "device.image", width: 1, height: 1, canChangeIcon: false,  canChangeBackground: false, decoration: "flat") {
      state "pause", label: "", action: "pause", icon: ""
    }

    standardTile("down", "device.image", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
      state "down", label: "down", action: "down", icon: ""
    }

    standardTile("set", "device.setStatus", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
      state "set", label: "set", action: "set", icon: "",  backgroundColor: "#FFFFFF"
      state "setting", label: "set mode", action: "set", icon: "", backgroundColor: "#53A7C0"
    }

    standardTile("preset1", "device.image", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
      state "preset1", label: "preset 1", action: "preset1", icon: ""
    }

    standardTile("preset2", "device.image", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
      state "preset2", label: "preset 2", action: "preset2", icon: ""
    }

    standardTile("preset3", "device.image", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
      state "preset3", label: "preset 3", action: "preset3", icon: ""
    }

    standardTile("refresh", "device.alarmStatus", inactiveLabel: false, decoration: "flat") {
      state "default", action:"polling.poll", icon:"st.secondary.refresh"
    }

    main "alarmStatus"
      details(["cameraDetails", "take", "up", "alarmStatus", "left", "pause", "right", "blank", "down", "set", "preset1", "preset2", "preset3", "refresh"])
  }
}

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

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

private take() {
  log.debug("Take a photo")

  httpGet("http://${settings.ip}:${settings.port}/snapshot.cgi?user=${settings.username}&pwd=${settings.password}&resolution=32&rate=0") {response ->        
    log.debug("Image captured")
    parseCameraResponse(response)
  }
}

def toggleAlarm() {
  if(device.currentValue("alarmStatus") == "on") {
    alarmOff()
  }

  else {
    alarmOn()
  }
}

private alarmOn() {
  api("set_alarm", "motion_armed=1") {
    log.debug("Alarm changed to: on")
    sendEvent(name: "alarmStatus", value: "on");
  }
}

private alarmOff() {
  api("set_alarm", "motion_armed=0") {
    log.debug("Alarm changed to: off")
    sendEvent(name: "alarmStatus", value: "off");
  }
}

def left() {
  api("decoder_control", "command=6") {
    log.debug("Executing 'left'")
  }
}

def right() {
  api("decoder_control", "command=4") {
    log.debug("Executing 'right'")
  }
}

def up() {
  api("decoder_control", "command=0") {
    log.debug("Executing 'up'")
  }
}

def down() {
  api("decoder_control", "command=2") {
    log.debug("Executing 'down'")
  }
}

def pause() {
  api("decoder_control", "command=1") {}
}

def preset1() {
  preset(1)
}

def preset2() {
  preset(2)
}

def preset3() {
  preset(3)
}

//go to a preset location
def preset(def num) {
  if(num == null) return

  if(device.currentValue("setStatus") == "setting") {
    setPreset(num)
  }

  else {
    log.debug("Go To Preset Location")
    //1 is 31, 2 is 33, 3 is 35
    def cmd = 30 + (num * 2) - 1

    api("decoder_control", "command=${cmd}") {}
  }
}

//set the preset number to the current location
def setPreset(def num) {
  log.debug("Set Preset")
  //1 is 30, 2 is 32, 3 is 34... 8 is 44
  int cmd = 28 + (num * 2)
  sendCmd(cmd)

  log.debug("Exit Set Mode")
  sendEvent(name: "setStatus", value: "set");
}

//toggle the the mode to set the preset
def set() {
  if(device.currentValue("setStatus") == "set") {
    log.debug("Entering Set Mode")
    sendEvent(name: "setStatus", value: "setting");
  }

  else {
    log.debug("Exit Set Mode")
    sendEvent(name: "setStatus", value: "set");
  }
}

def api(method, args = [], success = {}) {
  def methods = [
    "decoder_control": [uri: "http://${ip}:${port}/decoder_control.cgi${login()}&${args}", type: "post"],
    "snapshot": [uri: "http://${ip}:${port}/snapshot.cgi${login()}&${args}", type: "post"],
    "set_alarm": [uri: "http://${ip}:${port}/set_alarm.cgi${login()}&${args}", type: "post"],
    "reboot": [uri: "http://${ip}:${port}/reboot.cgi${login()}&${args}", type: "post"],
    "camera_control": [uri: "http://${ip}:${port}/camera_control.cgi${login()}&${args}", type: "post"],
    "get_params": [uri: "http://${ip}:${port}/get_params.cgi${login()}", type: "get"],
    "videostream": [uri: "http://${ip}:${port}/videostream.cgi${login()}", type: "get"]
  ]

  def request = methods.getAt(method)

  doRequest(request.uri, request.type, success)
}

private doRequest(uri, type, success) {
  log.debug(uri)

  if(type == "post") {
    httpPost(uri , "", success)
  }

  else if(type == "get") {
    httpGet(uri, success)
  }
}

private login() {
  return "?user=${username}&pwd=${password}"
}

def poll() {
  api("get_params", []) {
    def params = ""

    it.data.eachLine {
      if(it.startsWith("var alarm_motion_armed=0")) {
        log.info("Polled: Alarm off")
        sendEvent(name: "alarmStatus", value: "off");
      }

      if(it.startsWith("var alarm_motion_armed=1")) {
        log.info("Polled: Alarm on")
        sendEvent(name: "alarmStatus", value: "on");
      }
    }
  }
}

@ImBrian thanks for all your work with Foscam. Long story short, I had mine work for a few months using the code you’d written and securemyfoscam, then I broke it all trying to make securemyfoscam also change the preset.
So, I tried to rebuild it, then start from scratch using your instructions in this post. I could not make it work, and noticed it was the new auto added metadata. After tinkering and searching around the site, I found what to add, but thought you might want to update your github file for future users (until ST rolls out Foscam in labs…)

If anyone else needs it, just copy this code in (someone better than me might make sure it’s all correct…it does work though)

metadata {
	definition (name: "Foscam", author: "unknown") {
    	capability "Image Capture"
		capability "Polling"

		attribute "setStatus", "string"
		attribute "alarmStatus", "string"
        
		command "alarmOn"
		command "alarmOff"
		command "toggleAlarm"
		command "left"
		command "right"
		command "up"
		command "down"
        command "pause"
		command "set"
		command "preset"
		command "preset1"
        command "preset2"
		command "preset3"
	}

@erikmichael - it’s funny you should mention this today. Two days ago, I had to reconfigure my foscam and ran into this same issue. I hadn’t had a chance to try and troubleshoot it - so I ended up just disabling it in the meantime. Thanks for your notes - I’ll try and get this set up and update my device controller on github this weekend!

@ImBrian that’s awesome! You haven’t perhaps used securemyfoscam to change your preset, have you? I haven’t gotten back to working that out since I got the foscam working again.

@erikmichael - I did have it working before I made an edit and everything stopped working. I’ll make your suggested device controller changes and see if I can get it working.

My big use case is that when I’m at home, I think the camera is creepy - it points to the wall. If everyone is gone, there’s nobody to creep out - so it turns to the door.

@erikmichael - I’ve updated the foscam device controller per your recommendations (a huge thank-you for that, btw). I’ve just tested and it seems to work fine - and “Secure My Foscam” works as well - arms and disarms, pans to the correct preset.

If you’re having trouble with the panning to preset - it may be that the preset is never actually assigned. May be a bug there. Try setting a preset in the web UI for the camera itself and see if that remedies?

Now, to just get this to have local IP control instead having to have a hole in my firewall. Hrmm…

@imbrian

Updated code works well for me. Thank you!

If you look at the “Foscam” device type in the “Device Type Examples”, the very bottom appears to be what you need to get local IP access. Taking this code unaltered, I can get access to one of my Foscam’s that is not accessible through my firewall by using the local IP address in hex for the Device Network ID. The stock device type is very limited in that it only takes a picture.

I tried merging this with your device type but it is beyond my programming abilities.

@trotsky40 - My previous attempts at local foscam control kept (silently) failing. I’m wondering if those failures were due to the lack of the meta data just added. Without that meta data, my normal foscam controller worked, but inconsistently.

I have a “work in progress” device controller I’ll try again this weekend.

@ImBrian ahhh… I had never understood using the Simulator to setup your own smartapps, now I find that through the simulator I can setup the preset based on mode. Real nice!

I hope we can get the local control working, I hate having my cameras be open, even with unique accounts, passwords and random ports…

The two cameras I have so far are both baby monitors, so when we’re home they point at beds, but when we’re away they point to doors to see down hallways for the motion detection. Now it all works well!

@erikmichael - working on it as we speak. Some success.

@Imbrian, not sure if this makes a difference but on line 33 of foscam.groovy there is a spelling mistake.

attribute "alarmStats", "string"

It should read

attribute "alarmStatus", "string"

I have two foscam models that I would like to test out.

FI9821W v2 - indoor model pan,tilt, no zoom
FI9804 - outdoor model, no pan/tilt

If I read what @trotsky40 / Blake said I should be able to replace the command strings in groovy.foscam with the equivalent command strings from the models above correct? Is there anything else I should be aware of when testing this?

@trotsky40

I read on the dropcam blog post that you had the “Busrt When” smart app working with the foscams. Is this true? I see the command coming to the camera but do not see the picture being saved. Any ideas?