How does a Device Type get access to Hub properties?


(Gavin Cameron) #1

Hi,

I’m creating a Device Type to allow me to control some devices that I have connected to a VeraLite.

I can quite happily turn the devices on and off using HubAction but I would like to add a subscription so I get notified of any changes on the VeraLite.

To setup the subscription I need to know to know the IP and Port of the Hub but I can’t for the life of me work out how to get this information.

The examples seem to say I can do something like
def ip= device.hub.getDataValue(“localIP”)
def port= device.hub.getDataValue(“localSrvPortTCP”)
or use device.deviceNetworkId

But I get errors saying
java.lang.NullPointerException: Cannot get property ‘hub’ on null object
or
java.lang.NullPointerException: Cannot get property ‘deviceNetworkId’ on null object

What am I missing here? Do I need to do something special to get access to the Hub Data?

Thanks
Gavin


How does a SmartApp get hub properties and information?
(Geko) #2

Make sure your device is actually associated with a hub. For example:

def hubIp = device.hub.getDataValue("localIP")
log.debug "Hub IP: ${hubIp}"

This code writes the following to the IDE log:

10:11:01 PM PDT: debug Hub IP: 192.168.1.117

(Gavin Cameron) #3

Thanks, but with your code I’m still getting the error
java.lang.NullPointerException: Cannot get property ‘hub’ on null object

In a Device Type how do I see if device is associated with a Hub?


(Geko) #4

In the IDE click on “My Devices”, then click on your device. You should see “Hub” in the device properties. Where do you call this function from?


(Gavin Cameron) #5

I have a Device which is associated with my Hub and Location called “Vera Switch Node 4” which is of type “Vera Switch” which is the Device Type I am writing and where I’m hitting the problem.

I’m wanting to get the Hub IP address from within my Device Type code.


(Geko) #6

So my question was were exactly in your code do you call that function from? Can you post entire function block?


(Gavin Cameron) #7

Sorry, here’s the whole Device Type code so far - it’s my first try so please be nice :smile:

Error is occurring in getHostAddress at line 75 - it’s lines 78 & 79 that are giving me the error when uncommented.

    /**
 *  Vera Switch
 *
 *  Copyright 2014 Gavin Cameron
 *
 *  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: "Vera Switch", namespace: "gavin@gcameron.org", author: "Gavin Cameron") {
		capability "Switch"
		capability "Energy Meter"
        capability "Polling"
	}

	simulator {
		// TODO: define status and reply messages here
	}

	tiles {
		// TODO: define your main and details tiles here
	}
}

preferences {
  input("ipaddr" , "text", title: "IP Address", description: "IP Address of the vera unit this switch is attached to")
  input("port" , "text", title: "IP Port", description: "IP Port on the vera unit to communicate on")
  input("devid", "number", title: "Device ID", description: "Device ID of switch on Vera")
  
  command "on"
  command "off"
  command "getStatus"
  
  attribute "status", "string"
}

// parse events into attributes
def parse(String description) {
	log.debug "Parsing '${description}'"
	// TODO: handle 'switch' attribute
	// TODO: handle 'energy' attribute
}

// private methods
private String convertIPtoHex(ipAddress) { 
    String hex = ipAddress.tokenize( '.' ).collect {  String.format( '%02x', it.toInteger() ) }.join()
    log.debug "IP address entered is $ipAddress and the converted hex code is $hex"
    return hex
}

private String convertPortToHex(port) {
	String hexport = port.toString().format( '%04x', port.toInteger() )
    log.debug "Port number entered is $port and the converted hex code is $hexport"
    return hexport
}

private Integer convertHexToInt(hex) {
	Integer.parseInt(hex,16)
}


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

private getHostAddress() {
	log.info "getHostAddress"
    
    //def hubIp = device.hub.getDataValue("localIP")
	//log.debug "Hub IP: ${hubIp}"
    
    //log.info device.deviceNetworkId
    
	//def myip= device.hub.getDataValue("localIP")
	//def myport= device.getDataValue("localSrvPortTCP")
    
    //log.info "${ip}:${port}"
    
	//def parts = device.deviceNetworkID.split(":")
	//def ip = convertHexToIP(parts[0])
	//def port = convertHexToInt(parts[1])
	//return ip + ":" + port
}

// handle commands
def on() {
	log.debug "Executing 'on'"
    
    def ip = "${ipaddr}:${port}"
    def iphex = convertIPtoHex(ipaddr)+":"+convertPortToHex(port)
    
    log.debug "IP = ${ip}, HEX IP = ${iphex}"
    
    try {
    	def res = new physicalgraph.device.HubAction("""GET /data_request?id=lu_action&DeviceNum=${devid}&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1 HTTP/1.1\r\nHOST: ${ip}\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${iphex}")
	}
    catch (Exception e) 
    {
    	log.debug "Hit Exception on $res"
    	log.debug e
    }
}

def off() {
	log.debug "Executing 'off'"
    
    def ip = "${ipaddr}:${port}"
    def iphex = convertIPtoHex(ipaddr)+":"+convertPortToHex(port)
    
    log.debug "IP = ${ip}, HEX IP = ${iphex}"
    
 	try {
    	def res = new physicalgraph.device.HubAction("""GET /data_request?id=lu_action&DeviceNum=${devid}&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0 HTTP/1.1\r\nHOST: ${ip}\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${iphex}")
	}
    catch (Exception e) 
    {
    	log.debug "Hit Exception on $res"
    	log.debug e
    }
}

def getStatus() {
	log.debug "Executing getStatus"
    
    def myAddr = getHostAddress()
    
    def ip = "${ipaddr}:${port}"
    def iphex = convertIPtoHex(ipaddr)+":"+convertPortToHex(port)
    
    log.debug "IP = ${ip}, HEX IP = ${iphex}"
    
    try {
    	def res = new physicalgraph.device.HubAction("""GET /data_request?id=lu_status&DeviceNum=${devid}&serviceId=urn:upnp-org:serviceId:SwitchPower1 HTTP/1.1\r\nHOST: ${ip}\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${iphex}")
	}
    catch (Exception e) 
    {
    	log.debug "Hit Exception on $res"
    	log.debug e
    }
}

subscribeAction("/statusUpdate")

private subscribeAction(path, callbackPath="") {
	def myAddr = getHostAddress()
    def result = new physicalgraph.device.HubAction(
        method: "SUBSCRIBE",
        path: path,
        headers: [
            HOST: ip,
            CALLBACK: "<http://${myAddr}/notify$callbackPath>",
            NT: "upnp:event",
            TIMEOUT: "Second-3600"])
    result
}

(Geko) #8

Line 151:

subscribeAction("/statusUpdate")

You’re calling a function outside of the device context. That’s why your ‘device’ variable is undefined. You cannot do that. You can only execute code from the command handlers or from the parse() method.


(Gavin Cameron) #9

Ahhhhhhhhhhhh - that makes sense now.

Further question - where would I put the call to subscribeAction in my code? Is there an installed() method (or something similar) that would allow me to do what I want?

If not, do you have some advice on how I subscribe to updates from Vera unit?


(Geko) #10

I sold my Vera some time ago :), but I’m also interested in getting LAN callbacks to work for my other projects. No one have figured out yet to my knowledge. At least I have not seen any working code. The most commonly used method to push events to ST is via REST endpoint (a.k.a. Web Services SmartApp). An advantage of this method is that you don’t actually need a hub. You can push your data from anywhere. You can combine these two methods - use Hub for downstream commands and REST endpoint for upstream events.