Generic Camera Device using local connection (new version now available)

my network has zero protection as it sits now. its like I boiught a router took it out of the box and hooked it up

what does the output of your log look like when you snap a picture?

Also, im not the only one that is having this problem i don’t think. Im just the only one talking about it :stuck_out_tongue:

probably, it’s probably a stupid foscam config setting… Works for external access but not internal, go figure…

My logs are all screwed up right now cause I am testing a bunch of code changes… But I do get a response with a map and key for the image.

i officially give up. This must be why the STs team gave up on foscams…

Just gonna open my ports back up. whatevs

If someone with a foscam wants to either

A) send me one
B) allow me direct access via screenshare or teamviewer session

I can try to figure out why in the world this isn’t working on a local network.

Message me if you have a foscam, patience and a bit of trust I won’t screw up your network and a desire to see this working.

Well @pstuart figured it out!

Apparently the STs platform cannot handle 10.x.x.x IPs.

Fail

yeah, can’t freaking believe it… It’s a simple matter of padding the hex if it is a 2 digit starting ip, instead of 3 digits.

So local hubaction commands will not work if your ip address schema is below 100.x.x.x until this gets fixed.

So, doubt the answer is to ask everyone to change their ip addressing to 192.x.x.x but until this bug is fixed, that’s what it will take to use local devices in SmartThings.

Hopefully a developer or someone at ST can prioritize this fix, because I suspect it to be the cause of a lot of issues for IP device connectivity.

Been a long night, thanks to @tslagle13 for putting up with me remotely controlling his system to find this out…

This could just be my issue. I don’t get any line errors, just nothing happens. My network is 10.0.x.x

Excellent find! Though this doesn’t impact me, I agree this should be a prioritized fix.

It may not be this, it may be a simple hex to ip or ip to hex padded zero issue…

I’m working on writing a proper ip string to hex function. The one I found in the devicetypes samples is wrong.

This may be the issue, although I am not totally convinced. Don’t change your ip schema yet…

Logitech Alert 3rd party RTSP Authentication settings:

With security enabled:
rtsp://admin:Password@IP-ADDRESS:554/HighResolutionVideo

without:
rtsp://IP-ADDRESS:554/HighResolutionVideo

Oh, I wasn’t planning to. I’ll try padding the IP string and see in a moment and let you know if anything different happens

rstp will not work, this only works with URL paths that take a still image.

They have no way of doing it. Well, it doesn’t seem to matter much as their user forums are covered with rumors that they will be discontinued.

GOOD NEWS!!!

Thanks to the work the @pstuart did i was able to modify his code to allow local control of Insteon devices through Smartlinc!!! So now my Garage Door opener isn’t open to anyone outside the network. (assuming you change the internal port and don’t allow external access to that port)

Here is the code for both an Insteon Switch and a I/O Linc (Garage Opener)

Insteon Switch Code:

/**
 *  Insteon Switch (LOCAL)
 *
 *  Copyright 2014 patrick@patrickstuart.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
metadata {
	definition (name: "Insteon Switch (LOCAL)", namespace: "ps", author: "patrick@patrickstuart.com/tslagle13@gmail.com") {
		capability "Switch"
		capability "Sensor"
		capability "Actuator"
        
	}

    preferences {
    input("InsteonIP", "string", title:"Insteon IP Address", description: "Please enter your Insteon Hub IP Address", required: true, displayDuringSetup: true)
    input("InsteonPort", "string", title:"Insteon Port", description: "Please enter your Insteon Hub Port", defaultValue: 80 , required: true, displayDuringSetup: true)
    input("OnPath", "string", title:"Path to 'ON' Command", description: "Please enter the path to the 'ON' command", required: true, displayDuringSetup: true)
    input("OffPath", "bool", title:"Path to 'OFF' Command", description: "Please enter the path to the 'OFF' command", displayDuringSetup: true)
	}
    
	simulator {
		// status messages
		status "on": "on/off: 1"
		status "off": "on/off: 0"

		// reply messages
		reply "zcl on-off on": "on/off: 1"
		reply "zcl on-off off": "on/off: 0"
	}

	// UI tile definitions
	tiles {
		standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
			state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
			state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
		}

		main "switch"
		details "switch"
	}
}
// handle commands
def on() {
	//log.debug "Executing 'take'"
    sendEvent(name: "switch", value: "on")
    def host = InsteonIP
    def hosthex = convertIPToHex(host)
    def porthex = Long.toHexString(Long.parseLong((InsteonPort)))
    if (porthex.length() < 4) { porthex = "00" + porthex }
    
    //log.debug "Port in Hex is $porthex"
    //log.debug "Hosthex is : $hosthex"
    device.deviceNetworkId = "$hosthex:$porthex" 
    
    //log.debug "The device id configured is: $device.deviceNetworkId"
    
    def path = CameraPath //"/SnapshotJPEG?Resolution=640x480&Quality=Clarity"
    log.debug "path is: $OnPath"
    
    def headers = [:] //"HOST:" + getHostAddress() + ""
    headers.put("HOST", "$host:$InsteonPort")
    
    try {
    def hubAction = new physicalgraph.device.HubAction(
    	method: method,
    	path: OnPath,
    	headers: headers
        )  
    }
    catch (Exception e) 
    {
    log.debug "Hit Exception on $hubAction"
    log.debug e
    }
    }

def off() {
	//log.debug "Executing 'take'"
    sendEvent(name: "switch", value: "off")
    def host = InsteonIP
    def hosthex = convertIPToHex(host)
    def porthex = Long.toHexString(Long.parseLong((InsteonPort)))
    if (porthex.length() < 4) { porthex = "00" + porthex }
    
    //log.debug "Port in Hex is $porthex"
    //log.debug "Hosthex is : $hosthex"
    device.deviceNetworkId = "$hosthex:$porthex" 
    
    //log.debug "The device id configured is: $device.deviceNetworkId"
    
    def path = CameraPath //"/SnapshotJPEG?Resolution=640x480&Quality=Clarity"
    log.debug "path is: $OffPath"

    
    def headers = [:] //"HOST:" + getHostAddress() + ""
    headers.put("HOST", "$host:$InsteonPort")
    
    try {
    def hubAction = new physicalgraph.device.HubAction(
    	method: method,
    	path: OffPath,
    	headers: headers
        )
    }
    catch (Exception e) 
    {
    log.debug "Hit Exception on $hubAction"
    log.debug e
    }
    }

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

private Long converIntToLong(ipAddress) {
	long result = 0
	def parts = ipAddress.split("\\.")
    for (int i = 3; i >= 0; i--) {
        result |= (Long.parseLong(parts[3 - i]) << (i * 8));
    }

    return result & 0xFFFFFFFF;
}

private String convertIPToHex(ipAddress) {
	return Long.toHexString(converIntToLong(ipAddress));
}

private Integer convertHexToInt(hex) {
	Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
log.debug("Convert hex to ip: $hex") //	a0 00 01 6
	[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}

private getHostAddress() {
	def parts = device.deviceNetworkId.split(":")
    log.debug device.deviceNetworkId
	def ip = convertHexToIP(parts[0])
	def port = convertHexToInt(parts[1])
	return ip + ":" + port
}

I/O Linc (Garage Opener) Code:

 /**
 *  Insteon Garage Opener (LOCAL)
 *
 *  Copyright 2014 patrick@patrickstuart.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
metadata {
	definition (name: "Insteon Garage Opener (LOCAL)", namespace: "ps", author: "patrick@patrickstuart.com\tslagle13@gmail.com") {
		capability "Actuator"
		capability "Switch"
		capability "Momentary"
		capability "Sensor"
	}

    preferences {
    input("InsteonIP", "string", title:"Insteon IP Address", description: "Please enter your Insteon Hub IP Address", required: true, displayDuringSetup: true)
    input("InsteonPort", "string", title:"Insteon Port", description: "Please enter your Insteon Hub Port", defaultValue: 80 , required: true, displayDuringSetup: true)
    input("OnPath", "string", title:"Path to 'ON' Command", description: "Please enter the path to the 'ON' command", required: true, displayDuringSetup: true)
	}
    
	simulator {
	}

	// UI tile definitions
	tiles {
		standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
			state "off", label: 'Garage Door Opener', action: "momentary.push", backgroundColor: "#ffffff", nextState: "on"
			state "on", label: 'Garage Door Opener', action: "momentary.push", backgroundColor: "#53a7c0"
		}
		main "switch"
		details "switch"
	}
}
// handle commands
def push() {
	//log.debug "Executing 'take'"
    sendEvent(name: "switch", value: "on", isStateChange: true, display: false)
	sendEvent(name: "switch", value: "off", isStateChange: true, display: false)
	sendEvent(name: "momentary", value: "pushed", isStateChange: true)
    def host = InsteonIP
    def hosthex = convertIPToHex(host)
    def porthex = Long.toHexString(Long.parseLong((InsteonPort)))
    if (porthex.length() < 4) { porthex = "00" + porthex }
    
    //log.debug "Port in Hex is $porthex"
    //log.debug "Hosthex is : $hosthex"
    device.deviceNetworkId = "$hosthex:$porthex" 
    
    //log.debug "The device id configured is: $device.deviceNetworkId"
    
    def path = CameraPath //"/SnapshotJPEG?Resolution=640x480&Quality=Clarity"
    log.debug "path is: $OnPath"
    
    def headers = [:] //"HOST:" + getHostAddress() + ""
    headers.put("HOST", "$host:$InsteonPort")
    
    try {
    def hubAction = new physicalgraph.device.HubAction(
    	method: method,
    	path: OnPath,
    	headers: headers
        )  
    }
    catch (Exception e) 
    {
    log.debug "Hit Exception on $hubAction"
    log.debug e
    }
    }
    
def on() {
	push()
}

def off() {
	push()
}    

private Long converIntToLong(ipAddress) {
	long result = 0
	def parts = ipAddress.split("\\.")
    for (int i = 3; i >= 0; i--) {
        result |= (Long.parseLong(parts[3 - i]) << (i * 8));
    }

    return result & 0xFFFFFFFF;
}

private String convertIPToHex(ipAddress) {
	return Long.toHexString(converIntToLong(ipAddress));
}

private Integer convertHexToInt(hex) {
	Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
log.debug("Convert hex to ip: $hex") //	a0 00 01 6
	[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}

private getHostAddress() {
	def parts = device.deviceNetworkId.split(":")
    log.debug device.deviceNetworkId
	def ip = convertHexToIP(parts[0])
	def port = convertHexToInt(parts[1])
	return ip + ":" + port
}

Here is the info you need to make this work.

IP Address = IP Address of the Smartlinc
Port = Port the smartlinc communicates on
Path to On Command = /3?0262[DEVICE ID]0F11FF=I=3
Path to Off Command = /3?0262[DEVICE ID]0F13FF=I=3
Replace “[DEVICE ID]” with your switch’s ID found in the smartlinc control panel or on the physical device

I’ve tested all my Insteon Devices and they work. So as long as your IP range is above 100.x.x.x you should be able to use this code. If your IP range is something like 10.x.x.x this will not work.

Big thanks to Patrick Stuart!!!

1 Like

This was all Patrick. He’s da man!

https://github.com/pstuart/smartthings/blob/master/generic_camera.groovy

Ok, big update, I think I have fixed the issue with 10.x.x.x IP addressing with padding leading zeros to the hex code.

FYI, all HEX ip’s should be 8 characters in length, XX XX XX XX and all ports need to be XXXX in format.

So, if you had problems before and had 10.x.x.x ip addressing please try this new code.

I also added a bit more debugging to help troubleshoot any future problems.

pstuart I finally had some time to mess around with this last night as was able to get it to work! I was using the wrong path to take an image of what the camera was seeing.


I can change the path to tell what image size to pull and found 1280x720 to be best compromise between quality and how quick image shows up in ST (full size 2048 x 1536 did work just had to wait)

Pretty slick! Truly cannot express how awesome this is to have my MOBOTIX Camera integrated into SmartThings Patrick! Thank you again for the code & all of your help

Next up… any way I can use this to somehow pull and image and text me it when a door or motion sensor is triggered?

1 Like

Hello, I tried to use this with my smartlinc but simply is not working, device network ID is marked as c0a86420:0050 and log run is:

31387d14-ee3e-4dc5-a3bc-b22a39a1de22 16:43:03 CDT: debug path is: /3?0263E600P10263E280=I=3

I’m trying to use this to Turn On a X10 device (B2).

Not sure this will work with X10 stuff. You are quite litterally communicatiing directly with the switch with this code. You would need an insteon endpoint for this to work.

If you did some research to figure out what the X10 direct commands are you could probably make it work. The path i have above is specifically for insteon devices.

Please also keep in mind you have removed some of th necessary formatting from your path. For instance “0F13FF=I=3” MUST be present after the device ID in order for my code to work. 13F is the direct OFF command and and 11F is the direct ON command. This could also be your problem. When you create the path you need to replace only [DEVICE ID] in the path i provided.

You can test to make sure this works in a web browser if you type [IP]:]PORT]/[PATH] into a web browser this will work too. If it doesn’t work there you have a formatting problem with your URL, or this URL will not work with X10 devices.

Many thanks to this device!

I wanted to add a function to it.
There is another app called Sleepy Time that can use UP24 to change current mode of the hub, for example to good night mode once the button is pressed. Is it possible to integrate both function so that we can send http api (take a picture for example) once UP24 is clicked?

Any idea would be appreciated!
Thanks!