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. (Until STs fixes this bug for IP-to-Hex Conversion) See this thread for more info on the issue with IP addresses.