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

Ok, so this is getting really frustrating…

Removed my firewall and DMZ. reset my router to defaults. still cannot get the image to load… what is going on?!

Only thing I can think of now, is something is not right on your hub compared to others?

Remember the firewall rules, it needs to grab the local image requests from hub to camera, hub then sends image up to cloud. Could something be blocking the hub outbound to amazon s3?

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).