I have removed the redundant host parsing and the prefs entry for it. This will work if you simply enter the correct device network ID in the device (i.e. 0A00001A:1A2D for 10.0.0.26:6701). This uses the same hex conversion as my other device-types so I’m pretty sure it will work with any IP/port. Thanks @pstuart for the image parsing!
metadata {
definition (name: "D-Link Camera", namespace: "soletc.com", author: "Scottin Pollock") {
capability "Image Capture"
capability "Sensor"
capability "Actuator"
}
preferences {
input("CameraPath", "string", title:"Camera Path to Image", description: "Please enter the path to the image", defaultValue: "/image/jpeg.cgi", required: true, displayDuringSetup: true)
input("CameraAuth", "bool", title:"Does Camera require User Auth?", description: "Please choose if the camera requires authentication (only basic is supported)", defaultValue: true, displayDuringSetup: true)
input("CameraUser", "string", title:"Camera User", description: "Please enter your camera's username", required: false, displayDuringSetup: true)
input("CameraPassword", "string", title:"Camera Password", description: "Please enter your camera's password", required: false, displayDuringSetup: true)
}
simulator {
}
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.camera", backgroundColor: "#FFFFFF", nextState:"taking"
state "taking", label:'Taking', action: "", icon: "st.camera.take-photo", backgroundColor: "#53a7c0"
state "image", label: "Take", action: "Image Capture.take", icon: "st.camera.camera", backgroundColor: "#FFFFFF", nextState:"taking"
}
main "camera"
details(["cameraDetails", "take"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def map = stringToMap(description)
def result = []
if (map.bucket && map.key)
{ //got a s3 pointer
putImageInS3(map)
}
else if (map.headers && map.body)
{ //got device info response
def headerString = new String(map.headers.decodeBase64())
if (headerString.contains("404 Not Found")) {
state.snapshot = "/snapshot.cgi"
}
if (map.body) {
def bodyString = new String(map.body.decodeBase64())
def body = new XmlSlurper().parseText(bodyString)
def productName = body?.productName?.text()
if (productName)
{
log.trace "Product Name: $productName"
state.snapshot = ""
}
}
}
result
}
def putImageInS3(map) {
def s3ObjectContent
try {
def imageBytes = getS3Object(map.bucket, map.key + ".jpg")
if(imageBytes)
{
s3ObjectContent = imageBytes.getObjectContent()
def bytes = new ByteArrayInputStream(s3ObjectContent.bytes)
storeImage(getPictureName(), bytes)
}
}
catch(Exception e) {
log.error e
}
finally {
//explicitly close the stream
if (s3ObjectContent) { s3ObjectContent.close() }
}
}
// handle commands
def take() {
def userpassascii = "${CameraUser}:${CameraPassword}"
def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
def path = CameraPath //"/image/jpeg.cgi"
log.debug "path is: $path"
log.debug "Requires Auth: $CameraAuth"
if (CameraAuth) {
def hubAction = new physicalgraph.device.HubAction(
method: "GET",
path: path,
headers: [HOST:getHostAddress(), Authorization:userpass]
)
hubAction.options = [outputMsgToS3:true]
hubAction
}
else
{
def hubAction = new physicalgraph.device.HubAction(
method: "GET",
path: path,
headers: [HOST:getHostAddress()]
)
hubAction.options = [outputMsgToS3:true]
hubAction
}
}
private getPictureName() {
def pictureUuid = java.util.UUID.randomUUID().toString().replaceAll('-', '')
return device.deviceNetworkId + "_$pictureUuid" + ".jpg"
}
private Long converIntToLong(ipAddress) {
log.debug "from 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) {
log.debug
Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
[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
}