Sinope thermostats api - Working! Modes and presence driver in post #2

Thanks to @mattw, this api is now functioning. :slight_smile:

A workaround for the "one device per ip" limitation in Hubitat is to add a 3rd designation for the Device Network ID field. This can be the name of your stat, or just a unique number series, whichever is more convenient for your own system.

For example, 192.168.0.1:16021:Den

The code ignores the designation after the second : and it allows the IP to be used by multiple devices. Future updates to Hubitat may break this!

preferences {
	input("email", "text", title: "E-mail", description: "Your neviwebĀ® account login e-mail")
	input("password", "password", title: "Password", description: "Your neviwebĀ® account login password")
	input("gatewayname", "text", title: "Network Name:", description: "Name of your neviwebĀ® network")
	input("devicename", "text", title: "Device Name:", description: "Name of your neviwebĀ® thermostat")
}

metadata {
	definition (name: "Sinope technologie Thermostat", namespace: "Sinope Technologie", author: "Mathieu Virole") {
		capability "Polling"
		capability "Thermostat"
		capability "Temperature Measurement"
		capability "Sensor"
        
		command "heatingSetpointUp"
		command "heatingSetpointDown"
        command "heatingSetpoint"

		attribute "temperatureUnit", "string"
	}

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

def setHeatingSetpoint(newSetpoint) {
	
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}

	if(device.data.error==true){
		logout()
	}else{
		def temperatureUnit = device.currentValue('temperatureUnit')
		def temperature
		log.info("setHeatingSetpoint -> Value :: ${newSetpoint}Ā° ${temperatureUnit}")

		if (newSetpoint!=null){
			newSetpoint=newSetpoint.toDouble().round(2)
		}else{
			newSetpoint=null
		}
		
		switch (temperatureUnit) {
			case "celsius":
	         	temperature = newSetpoint    
	        break;

	        case "fahrenheit":
				temperature = fToC(newSetpoint)
			break;
	    }
		
	    log.info("setHeatingSetpoint _ STEP2 -> NEW Value :: ${temperature}Ā° C")
		//sendEvent(name: 'heatingSetpoint', value: newSetpoint, unit: temperatureUnit)
    	
def params = [
	uri: "${device.data.server}",
	path: "api/device/${device.data.deviceId}/setpoint",
	requestContentType: "application/json",
	headers: ["Content-Type": "application/json", 'Session-Id' : device.data.auth.session],
 	body: ['temperature': temperature]
]

		log.warn(params)
		
	    httpPut(params){
	    	resp ->resp.data
	      	log.info("setHeatingSetpoint -> API response :: ${resp.data}") 
	    }

       	poll() 
	}
}		

def heatingSetpointUp(){
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}
	if(device.data.error==true){
		logout()
	}else{
       	def newSetpoint = FormatTemp(device.data.status.setpoint)
       	def temperatureUnit = device.currentValue('temperatureUnit')
        if (newSetpoint != null){
			switch (temperatureUnit) {
			
				case "celsius":
			        newSetpoint = newSetpoint + 0.5
			        if (newSetpoint >= 30) {
						newSetpoint = 30
					}     
			    break;

			    case "fahrenheit":
					newSetpoint = device.currentValue("heatingSetpoint") + 1
					if (newSetpoint >= 86) {
						newSetpoint = 86
					} 
				break;
			}

		}
		setHeatingSetpoint(newSetpoint)
	}
}

def heatingSetpointDown(){
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}
	if(device.data.error==true){
		logout()
	}else{
		def newSetpoint = FormatTemp(device.data.status.setpoint)
        def temperatureUnit = device.currentValue('temperatureUnit')
		if (newSetpoint != null){
			switch (temperatureUnit) {
					
				case "celsius":
		         	newSetpoint = device.currentValue("heatingSetpoint") - 0.5
		         	if (newSetpoint <= 5) {
						newSetpoint = 5
					}      
		        break;
		       
		        default:
					newSetpoint = device.currentValue("heatingSetpoint") - 1
					if (newSetpoint <= 41) {
						newSetpoint = 41
					}  
				break;
			}
		}
		setHeatingSetpoint(newSetpoint)
	}
}

def poll() {
	if(!isLoggedIn()) {
		login()
	}else{
		if(device.data.error==true){
			logout()
		}else{
			DeviceData()
			runIn(200, poll)
		}	
	}
}

def login() {
	device.data.server="https://neviweb.com/"
    def params = [
        uri: "${device.data.server}",
        path: 'api/login',
        requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
        body: ["email": settings.email, "password": settings.password, "stayConnected": "0"]
    ]
    httpPost(params) { resp ->
        device.data.auth = resp.data
        if (device.data.auth.error){
        	log.warn(device.data.auth.error)
        	sendEvent(name: 'temperature', value: "ERROR LOGIN", state: temperatureType)
        	log.error("Authentification failed or request error")
        	device.data.error=true
        	logout()
    	}else{
    		log.info("login and password :: OK")
        	device.data.error=false
        	gatewayId()
    	} 
    }
}

def logout() {
      	def params = [
			uri: "${device.data.server}",
	        path: "api/logout",
	       	requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
	        headers: ['Session-Id' : device.data.auth.session]
    	]
        httpGet(params) {resp ->
			device.data.auth = resp.data
        }
        log.info("logout :: OK")  
}

def gatewayId(){
	def params = [
		uri: "${device.data.server}",
        path: "api/gateway",
       	requestContentType: "application/json, text/javascript, */*; q=0.01",
        headers: ['Session-Id' : device.data.auth.session]
    ]
    httpGet(params) { response ->
        device.data.gateway_list = response.data
    }
    def gatewayName=settings.gatewayname
	gatewayName=gatewayName.toLowerCase().replaceAll("\\s", "")
	for(var in device.data.gateway_list){

    	def name_gateway=var.name
    	name_gateway=name_gateway.toLowerCase().replaceAll("\\s", "")

    	if(name_gateway==gatewayName){
    		device.data.gatewayId=var.id
    		log.info("gateway ID is :: ${device.data.gatewayId}")
    		device.data.error=false
    		deviceId()
    	}
    }
    if (device.data?.gatewayId==null){
    	sendEvent(name: 'temperature', value: "ERROR GATEWAY", state: temperatureType)
    	log.error("no gateway with this name or request error")
    	device.data.error=true
    	logout()
    }
}

def deviceId(){

	def params = [
		uri: "${device.data.server}",
        path: "api/device",
        query: ['gatewayId' : device.data.gatewayId],
       	requestContentType: "application/json, text/javascript, */*; q=0.01",
        headers: ['Session-Id' : device.data.auth.session]
   	]
    httpGet(params) {resp ->
		device.data.devices_list = resp.data
    }
    def deviceName=settings.devicename
	deviceName=deviceName.toLowerCase().replaceAll("\\s", "")
    for(var in device.data.devices_list){
    	def name_device=var.name
    	name_device=name_device.toLowerCase().replaceAll("\\s", "")
    	if(name_device==deviceName){
    		device.data.deviceId=var.id
    		log.info("device ID is :: ${device.data.deviceId}")
    		DeviceData()
    		device.data.error=false
    	}	
    }
    if (device.data?.deviceId==null){
    	sendEvent(name: 'temperature', value: "ERROR DEVICE", state: temperatureType)
    	log.error("no device with this name or request error")
    	device.data.error=true
    	logout()
    }	
}

def isLoggedIn() {
	log.info ("Is it login?")
	if (device.data?.auth?.session!=null){
		try{
			def params = [
				uri: "${device.data.server}",
			    path: "api/gateway",
			   	requestContentType: "application/json, text/javascript, */*; q=0.01",
			    headers: ['Session-Id' : device.data.auth.session]
			]
			httpGet(params) {resp ->
			    if(resp.data.sessionExpired==true){
			    	log.info "No session Expired"
			    	device.data.auth=""
			    }
			}
			if(!device.data.auth) {
				return false
				log.error("not pass log")
			} else {
				if (device.data?.deviceId!=null){
					return true
				}else{
					return false
					log.error("not device or gateway with this name")
				}
			}
		}catch (e){
			log.error(e)
			return false
		}
	}else{
		return false
	}
}

def DeviceData(){
	def temperature
    def heatingSetpoint
    def range
	def temperatureUnit

   	def params = [
		uri: "${device.data.server}api/device/${device.data.deviceId}/data?force=1",
		requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
        headers: ['Session-Id' : device.data.auth.session]
    ]

    httpGet(params) {resp ->
		device.data.status = resp.data
    }

    log.info("Data device is :: ${device.data.status}")

    if(device.data?.auth?.user?.format?.temperature == "c"){
    	temperatureUnit = "celsius"
    }else{
    	temperatureUnit = "fahrenheit"
    }
    
    sendEvent(name: "temperatureUnit",   value: temperatureUnit)
    
    switch (temperatureUnit) {

        case "celsius":
        	log.info("celsius temperature")
        	temperature = FormatTemp(device.data.status.temperature)
        	heatingSetpoint = FormatTemp(device.data.status.setpoint)
        break;

        case "fahrenheit":
        	log.info("fahrenheit temperature")
        	temperature = FormatTemp(device.data.status.temperature)
        	heatingSetpoint = FormatTemp(device.data.status.setpoint)
        break;
    }
    
	sendEvent(name: 'temperature', value: temperature, unit: temperatureUnit)	
	sendEvent(name: 'heatingSetpoint', value: heatingSetpoint, unit: temperatureUnit)
        sendEvent(name: 'thermostatOperatingState', value: "${device.data.status.heatLevel}")
	sendEvent(name: "thermostatMode", value: "heat")
}

def FormatTemp(temp){
	def temperatureUnit = device.latestValue('temperatureUnit')
	if (temp!=null){
		float i=Float.valueOf(temp)
		switch (temperatureUnit) {
	        case "celsius":
				return (Math.round(i*2)/2).toDouble().round(2)
				log.warn((Math.round(i*2)/2).toDouble().round(2))
	        break;

	        case "fahrenheit":
	        	return (Math.ceil(cToF(i))).toDouble().round(2)
	        	log.warn(Math.ceil(cToF(i)).toDouble().round(2))
	        break;
	    }
    }else{
    	return null
    }
}

def cToF(temp) {
	return ((( 9 * temp ) / 5 ) + 32)
	log.info "celsius -> fahrenheit"
}

def fToC(temp) {
	return ((( temp - 32 ) * 5 ) / 9)
	log.info "fahrenheit -> celsius"
}

Iā€™ve started working on adding into the basic Sinope driver the modifications to add modes and presence from infofiendā€™s driver. My results so far are below. At the moment ā€œcoolā€ or ā€œoffā€ do not function, and give an error code 1001, whatever that means.

preferences {
	input("email", "text", title: "E-mail", description: "Your neviwebĀ® account login e-mail")
	input("password", "password", title: "Password", description: "Your neviwebĀ® account login password")
	input("gatewayname", "text", title: "Network Name:", description: "Name of your neviwebĀ® network")
	input("devicename", "text", title: "Device Name:", description: "Name of your neviwebĀ® thermostat")
    input("heatModeSP", "number", title: "Heat Mode Increase:", description: "Default degrees to raise setpoint if mode changes to heat: ")
    input("emerHeatModeSP", "number", title: "Emergency Heat Mode Increase:", description: "Setting ThermostatMode to emergencyHeat will raise setpoint by this many degrees: ")

}

metadata {
	definition (name: "Sinope technologie Thermostat - Modes", namespace: "Sinope Technologie", author: "Mathieu Virole") {
//		Code from infofiend added to Sinope standard thermostat to support presence and mode
//		Code modified by LoganFraser aka oldernstone for use on Hubitat     
        capability "Polling"
		capability "Thermostat"
		capability "Temperature Measurement"
		capability "Sensor"
		capability "Thermostat Mode"
        
		attribute "temperatureUnit", "string"
        attribute "thermMode", "string"
        attribute "thermPresence", "string"        
        attribute "thermLoad", "string"
        		
        command "heatingSetpointUp"
		command "heatingSetpointDown"
        command "heatingSetpoint"
        command "presenceHome"
        command "presenceAway"
        command "setPresence", ["string"]
        command "setThermostatMode", ["string"]
        command "auto"
        command "off"
        command "cool"
        command "heat"
        command "emergencyHeat"
        command "poll"
    }

	simulator {
		// TODO: define status and reply messages here
	}
}
//		PRESENCE FUNCTIONS
def presenceAway() {
	log.trace "presenceAway: "
    sendEvent(name: 'thermMode', value: "Updating", isStateChange: true)
    if (state.myPresence != "Away") {
		unschedule(logout)    
        state.myPresence == "Away"
		setPresence('Away')
    }    
}

def presenceHome() {
	log.trace "presenceHome: "
    state.myModeST = device.currentValue("thermostatMode")
    sendEvent(name: 'thermMode', value: "Updating", isStateChange: true)
    if (state.myPresence != "Home") {
    	unschedule(logout)
        state.myPresence == "Home"	    
        setPresence('Home')
	}
}

private setPresence(status) {
	log.trace "setPresence(${status}: "    
//    sendEvent(name: "thermPresence", value: "Updating", isStateChange:true)
    
	if(!isLoggedIn()) {
		log.debug "Need to login"
        login()
	}
	if(device.data.error==true){
		logout()
	} else { 
    	def myBody = [mode: 3]
        
        switch (status) {
                
			case "Home":
				log.trace "setPresence: Home"        
            	log.debug "Switching Presence to Home" 
                def myMode = state.myModeST
                switch ( myMode ) {
                	case "off":
		            	log.debug "thermostatMode is Off - Setting data.status.mode = 0"                     
	                	myBody = [mode: 0]
                        break;
                    case "heat":
		            	log.debug "thermostatMode is Heat - Setting data.status.mode = 2"                    
	                	myBody = [mode: 2]
                        break;
                    case "emergency heat":
		            	log.debug "thermostatMode is Emergency Heat - data.status.mode = 131"                    
                    	myBody = [mode: 131]
                        break;
                    case "auto":
		            	log.debug "thermostatMode is Auto - data.status.mode = 3"                    
                    	myBody = [mode: 3]
                        break;    
				}
                
	            def putParams = [
					uri: "https://neviweb.com/api/device/${device.data.deviceId}/mode",
        			requestContentType: "application/json",
                    headers: ['Session-Id' : device.data.auth.session],
            		body: myBody
	    		]
    	        httpPut(putParams)	{resp ->
					log.debug resp.data
				}
            	sendEvent(name:"thermPresence", value: "Home", display: true, isStateChange: true)
				sendEvent(name:"thermostatMode", value: "${myMode}", display: false)
	            break;
            
			case "Away":
				log.trace "setPresence: Away "        
	            myBody = [mode: 5]
            	state.lastPresence = device.currentValue("thermPresence") 
    	        log.debug "Switching Presence to Away / thermostatMode to Auto"
                log.debug "Setting device.data.status.mode = 5"
        	    def putParams = [
					uri: "https://neviweb.com/api/device/${device.data.deviceId}/mode",
    	    		requestContentType: "application/json",
                    headers: ['Session-Id' : device.data.auth.session],
	        	    body: myBody
    			]
        	    
				httpPut(putParams)	{resp ->
					log.debug resp.data
				}	
            	
            	sendEvent(name:"thermPresence", value: "Away", display: true, isStateChange: true)
				sendEvent(name:"thermostatMode", value: "Auto", display: false, isStateChange: true)

        	    break;
		}
 
	poll ()
	}
}
def setHeatingSetpoint(newSetpoint) {
	
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}

	if(device.data.error==true){
		logout()
	}else{
		def temperatureUnit = device.currentValue('temperatureUnit')
		def temperature
		log.info("setHeatingSetpoint -> Value :: ${newSetpoint}Ā° ${temperatureUnit}")

		if (newSetpoint!=null){
			newSetpoint=newSetpoint.toDouble().round(2)
		}else{
			newSetpoint=null
		}
		
		switch (temperatureUnit) {
			case "celsius":
	         	temperature = newSetpoint    
	        break;

	        case "fahrenheit":
				temperature = fToC(newSetpoint)
			break;
	    }
		
	    log.info("setHeatingSetpoint _ STEP2 -> NEW Value :: ${temperature}Ā° C")
		//sendEvent(name: 'heatingSetpoint', value: newSetpoint, unit: temperatureUnit)
    	
		def params = [
			uri: "${device.data.server}",
			path: "api/device/${device.data.deviceId}/setpoint",
            requestContentType: "application/json",
			headers: ["Content-Type": "application/json",'Session-Id' : device.data.auth.session],
		 	body: ['temperature': temperature]
		]

		log.warn(params)
		
	    httpPut(params){
	    	resp ->resp.data
	      	log.info("setHeatingSetpoint -> API response :: ${resp.data}") 
	    }

       	poll() 
	}
}		

def heatingSetpointUp(){
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}
	if(device.data.error==true){
		logout()
	}else{
       	def newSetpoint = FormatTemp(device.data.status.setpoint)
       	def temperatureUnit = device.currentValue('temperatureUnit')
        if (newSetpoint != null){
			switch (temperatureUnit) {
			
				case "celsius":
			        newSetpoint = newSetpoint + 1
			        if (newSetpoint >= 30) {
						newSetpoint = 30
					}     
			    break;

			    case "fahrenheit":
					newSetpoint = device.currentValue("heatingSetpoint") + 1
					if (newSetpoint >= 86) {
						newSetpoint = 86
					} 
				break;
			}

		}
		setHeatingSetpoint(newSetpoint)
	}
}

def heatingSetpointDown(){
	if(!isLoggedIn()) {
		log.info "Need to login"
		login()
	}
	if(device.data.error==true){
		logout()
	}else{
		def newSetpoint = FormatTemp(device.data.status.setpoint)
        def temperatureUnit = device.currentValue('temperatureUnit')
		if (newSetpoint != null){
			switch (temperatureUnit) {
					
				case "celsius":
		         	newSetpoint = device.currentValue("heatingSetpoint") - 1
		         	if (newSetpoint <= 5) {
						newSetpoint = 5
					}      
		        break;
		       
		        default:
					newSetpoint = device.currentValue("heatingSetpoint") - 1
					if (newSetpoint <= 41) {
						newSetpoint = 41
					}  
				break;
			}
		}
		setHeatingSetpoint(newSetpoint)
	}
}
//	THERMOSTAT MODE FUNCTIONS
def setThermostatMode(inMode) {
	log.trace "setThermostatMode(${inMode}): "    
    
	switch (inMode) {		
    		case "off":
//            	off()
				sendEvent(name:"thermostatMode", value: "off", display: true, isStateChange: true)
				break;
                
    		case "auto":
//            	auto()
				sendEvent(name:"thermostatMode", value: "auto", display: true, isStateChange: true)
				break;
                
    		case "cool":
//            	off()
				sendEvent(name:"thermostatMode", value: "off", description: "Cool Mode not applicable", display: true, isStateChange: true)
				break;
                
    		case "heat":
//            	heat()				              
				sendEvent(name:"thermostatMode", value: "heat", display: true, isStateChange: true)
				break;
                
    		case "emergency heat": 			
//				emergencyHeat()
                sendEvent(name:"thermostatMode", value: "emergency heat", display: true, isStateChange: true)
				break;
                
	}
}    

def off() {
	log.trace "off():"
//	unschedule(logout)
    
    if(!isLoggedIn()) {
        log.debug "Need to login"
        login()
    }
	if(device.data.error==true){
		logout()
	} else {
    
	    state.lastSetpoint = device.currentValue('heatingSetpoint')
	               
	    def putParams = [
    	    uri: "https://neviweb.com/api/device/${device.data.deviceId}/mode",
        	requestContentType: "application/json",
            headers: ['Session-Id' : device.data.auth.session],
	        body: ['mode': 0]
    	]
	    httpPut(putParams) { resp ->
			log.debug resp.data
		}

		poll ()
	}
}

def cool() {
	off()
}

def auto() {
	log.trace "auto():"
    
    if(!isLoggedIn()) {
        log.debug "Need to login"
        login()
    }	
	
    if (device.data.error==true) {
		logout()
	} else {   
        	
        def myPresence = device.currentValue("thermPresence")
       	def myBody = []
        if (myPresence == "Home") {
			myBody = ['mode': 3]	                          		    
        } else {
	        myBody = ['mode': 5]
        }    
    
    	def putParams = [
    	    uri: "https://neviweb.com/api/device/${device.data.deviceId}/mode",
        	requestContentType: "application/json",
            headers: ['Session-Id' : device.data.auth.session],
	      	body: myBody
    	]
            
	    httpPut(putParams) { resp ->
			log.debug resp.data
		}
        
		poll()

	}
}        


def heat(inSP) {
	log.trace "heat( ${inSP} ):"
    state.thermMode = "heat"


	def newSP = inSP
    
    if (!inSP || newSP == null) {
	    def curTemp = device.currentValue('temperature') as Number
        log.debug "curTemp = ${curTemp}"
    
   		if (heatModeSP) {
       		newSP = curTemp + heatModeSP
        } else {
    	            
    		if ( temperatureUnit == "celsius" ) {
   				newSP = curTemp + 1
			} else { 
   	    	   	newSP = curTemp + 3
       	    }
		} 
	} 
    log.debug "heat() sending newSetpoint of ${newSP} to setHeatingSetpoint."
	setHeatingSetpoint(newSP)
    
}
          


def emergencyHeat(inSP) {
	log.trace "emergencyHeat( ${inSP} ):"   	
    state.thermMode = "emergencyHeat"

	def newSP = inSP
    
    if (!inSP || newSP == null) {
	    def curTemp = device.currentValue('temperature') as Number
        log.debug "curTemp = ${curTemp}"
    
   		if (emerHeatModeSP) {
       		newSP = curTemp + emerHeatModeSP
        } else {
    	            
    		if ( temperatureUnit == "celsius" ) {
   				newSP = curTemp + 3
			} else { 
   	    	   	newSP = curTemp + 10
       	    }
		} 
	} 

	log.debug "emergencyHeat() sending newSetpoint of ${newSP} to setHeatingSetpoint."   
	setHeatingSetpoint(newSP)
}



def poll() {
	if(!isLoggedIn()) {
		login()
	}else{
		if(device.data.error==true){
			logout()
		}else{
			DeviceData()
			runIn(200, poll)
		}	
	}
}

def login() {
	device.data.server="https://neviweb.com/"
    def params = [
        uri: "${device.data.server}",
        path: 'api/login',
        requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
        body: ["email": settings.email, "password": settings.password, "stayConnected": "0"]
    ]
    httpPost(params) { resp ->
        device.data.auth = resp.data
        if (device.data.auth.error){
        	log.warn(device.data.auth.error)
        	sendEvent(name: 'temperature', value: "ERROR LOGIN", state: temperatureType)
        	log.error("Authentification failed or request error")
        	device.data.error=true
        	logout()
    	}else{
    		log.info("login and password :: OK")
        	device.data.error=false
        	gatewayId()
    	} 
    }
}

def logout() {
      	def params = [
			uri: "${device.data.server}",
	        path: "api/logout",
	       	requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
	        headers: ['Session-Id' : device.data.auth.session]
    	]
        httpGet(params) {resp ->
			device.data.auth = resp.data
        }
        log.info("logout :: OK")  
}

def gatewayId(){
	def params = [
		uri: "${device.data.server}",
        path: "api/gateway",
       	requestContentType: "application/json, text/javascript, */*; q=0.01",
        headers: ['Session-Id' : device.data.auth.session]
    ]
    httpGet(params) { response ->
        device.data.gateway_list = response.data
    }
    def gatewayName=settings.gatewayname
	gatewayName=gatewayName.toLowerCase().replaceAll("\\s", "")
	for(var in device.data.gateway_list){

    	def name_gateway=var.name
    	name_gateway=name_gateway.toLowerCase().replaceAll("\\s", "")

    	if(name_gateway==gatewayName){
    		device.data.gatewayId=var.id
    		log.info("gateway ID is :: ${device.data.gatewayId}")
    		device.data.error=false
    		deviceId()
    	}
    }
    if (device.data?.gatewayId==null){
    	sendEvent(name: 'temperature', value: "ERROR GATEWAY", state: temperatureType)
    	log.error("no gateway with this name or request error")
    	device.data.error=true
    	logout()
    }
}

def deviceId(){

	def params = [
		uri: "${device.data.server}",
        path: "api/device",
        query: ['gatewayId' : device.data.gatewayId],
       	requestContentType: "application/json, text/javascript, */*; q=0.01",
        headers: ['Session-Id' : device.data.auth.session]
   	]
    httpGet(params) {resp ->
		device.data.devices_list = resp.data
    }
    def deviceName=settings.devicename
	deviceName=deviceName.toLowerCase().replaceAll("\\s", "")
    for(var in device.data.devices_list){
    	def name_device=var.name
    	name_device=name_device.toLowerCase().replaceAll("\\s", "")
    	if(name_device==deviceName){
    		device.data.deviceId=var.id
    		log.info("device ID is :: ${device.data.deviceId}")
    		DeviceData()
    		device.data.error=false
    	}	
    }
    if (device.data?.deviceId==null){
    	sendEvent(name: 'temperature', value: "ERROR DEVICE", state: temperatureType)
    	log.error("no device with this name or request error")
    	device.data.error=true
    	logout()
    }	
}

def isLoggedIn() {
	log.info ("Is it login?")
	if (device.data?.auth?.session!=null){
		try{
			def params = [
				uri: "${device.data.server}",
			    path: "api/gateway",
			   	requestContentType: "application/json, text/javascript, */*; q=0.01",
			    headers: ['Session-Id' : device.data.auth.session]
			]
			httpGet(params) {resp ->
			    if(resp.data.sessionExpired==true){
			    	log.info "No session Expired"
			    	device.data.auth=""
			    }
			}
			if(!device.data.auth) {
				return false
				log.error("not pass log")
			} else {
				if (device.data?.deviceId!=null){
					return true
				}else{
					return false
					log.error("not device or gateway with this name")
				}
			}
		}catch (e){
			log.error(e)
			return false
		}
	}else{
		return false
	}
}

def DeviceData(){
	def temperature
    def heatingSetpoint
    def range
	def temperatureUnit

   	def params = [
		uri: "${device.data.server}api/device/${device.data.deviceId}/data?force=1",
		requestContentType: "application/x-www-form-urlencoded; charset=UTF-8",
        headers: ['Session-Id' : device.data.auth.session]
    ]

    httpGet(params) {resp ->
		device.data.status = resp.data
    }

    log.info("Data device is :: ${device.data.status}")

    if(device.data?.auth?.user?.format?.temperature == "c"){
    	temperatureUnit = "celsius"
    }else{
    	temperatureUnit = "fahrenheit"
    }
    
    sendEvent(name: "temperatureUnit",   value: temperatureUnit)
    
    switch (temperatureUnit) {

        case "celsius":
        	log.info("celsius temperature")
        	temperature = FormatTemp(device.data.status.temperature)
        	heatingSetpoint = FormatTemp(device.data.status.setpoint)
        break;

        case "fahrenheit":
        	log.info("fahrenheit temperature")
        	temperature = FormatTemp(device.data.status.temperature)
        	heatingSetpoint = FormatTemp(device.data.status.setpoint)
        break;
    }
    
	sendEvent(name: 'temperature', value: temperature, unit: temperatureUnit)	
	sendEvent(name: 'heatingSetpoint', value: heatingSetpoint, unit: temperatureUnit)
        sendEvent(name: 'thermostatOperatingState', value: "${device.data.status.heatLevel}")
	sendEvent(name: "thermostatMode", value: "heat")
}

def FormatTemp(temp){
	def temperatureUnit = device.latestValue('temperatureUnit')
	if (temp!=null){
		float i=Float.valueOf(temp)
		switch (temperatureUnit) {
	        case "celsius":
				return (Math.round(i*2)/2).toDouble().round(2)
				log.warn((Math.round(i*2)/2).toDouble().round(2))
	        break;

	        case "fahrenheit":
	        	return (Math.ceil(cToF(i))).toDouble().round(2)
	        	log.warn(Math.ceil(cToF(i)).toDouble().round(2))
	        break;
	    }
    }else{
    	return null
    }
}

def cToF(temp) {
	return ((( 9 * temp ) / 5 ) + 32)
	log.info "celsius -> fahrenheit"
}

def fToC(temp) {
	return ((( temp - 32 ) * 5 ) / 9)
	log.info "fahrenheit -> celsius"
}

Was the ā€œdataā€ variable defined anywhere?

Hereā€™s the entirety of the API. I didnā€™t see any data variable defined, but maybe itā€™s a built-in from the smartthings side?

Use device.data, or store this in state.

1 Like

Awesome. After replacing data with device.data throughout the code, Iā€™m getting successful login. Next glitch:

Error:
Cannot get property ā€˜authā€™ on null object on line 220

The error is on the second line here:

def gatewayId(){
	def params = [
		uri: "${device.data.server}",
        path: "api/gateway",
       	requestContentType: "application/json, text/javascript, */*; q=0.01",
        headers: ['Session-Id' : data.auth.session]
    ]
    httpGet(params) { response ->
        device.data.gateway_list = response.data
    }

You need to prepend any references to data with device. This needs to be done in all places.

1 Like

Does that include resp.data and response.data, or just variables that begin with data. ?

Just data. data.xyx becomes device.data.xyz

Yep, figured that out. So Iā€™m making progress. I have current states reporting, temperature, temperatureunit, thermostatmode, heatingsetpoint displaying correct values.

Commands are throwing errors though.
If I try heating setpoint up, I get the following:

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.458:errorNo signature of method: dev15189219171011453974004.httpPut() is applicable for argument types: (java.util.LinkedHashMap, dev15189219171011453974004$_setHeatingSetpoint_closure3) values: [[uri:https://neviweb.com/, path:api/device/82925/setpoint, headers:[...], ...], ...] on line 95

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.438:warn[uri:https://neviweb.com/, path:api/device/82925/setpoint, headers:[Session-Id:9BkR9kTc8ILfDtvruTP2QlC8Z3oH6LCViC70J3N], body:[temperature:23.0]]

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.434:infosetHeatingSetpoint _ STEP2 -&gt; NEW Value :: 23.0Ā° C

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.432:infosetHeatingSetpoint -&gt; Value :: 23.0Ā° celsius

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.425:infocelsius temperature

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:06.424:infoData device is :: [errorCode:null, setpoint:22.00, temperature:20.99, heatLevel:69, mode:2, alarm:0, rssi:48]

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:05.647:infodevice ID is :: 82925

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:05.038:infogateway ID is :: 13682

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:04.486:infologin and password :: OK

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:03.953:infoNeed to login

[dev:34](http://192.168.2.105/logs#dev34)2018-02-18 10:35:03.952:errorgroovy.lang.MissingPropertyException: No such property: device for class: groovyx.net.http.HttpResponseDecorator

Line 95 is
httpPut(params){
resp ->resp.data
log.info(ā€œsetHeatingSetpoint -> API response :: ${resp.data}ā€)
}

Iā€™ve gone through this from the beginning again. I was worried Iā€™d screwed up an edit somewhere, so I started from the original code again and replaced all instances of data. with device.data. and data? with device.data?

Iā€™m still getting an error with the httpPut from before.

[dev:55](http://192.168.2.105/logs#dev55)2018-02-18 17:57:48.172:errorNo signature of method: dev15190054320221567460192.httpPut() is applicable for argument types: (java.util.LinkedHashMap, dev15190054320221567460192$_setHeatingSetpoint_closure3) values: [[uri:https://neviweb.com/, path:api/device/82931/setpoint, headers:[...], ...], ...] on line 68

[dev:55](http://192.168.2.105/logs#dev55)2018-02-18 17:57:48.163:warn[uri:https://neviweb.com/, path:api/device/82931/setpoint, headers:[Session-Id:qpNergFdqrh6dQxN2qoBQKZHBAwygCyKsrqH8BGS], body:[temperature:10.5]]

Iā€™m posting the full modified api on the first post for other people to use. Thanks to @mattw for the error solution!

I am using the DTH by infofiend and only one easy error on Hubitat. Which could be easily correct. I havenā€™t played too much to get it working. Link below to the DTH. I find this one is much richer than the one by SINOPE and been using it for a while now with ST.

[UPDATE] Sinope Electric Baseboard Thermostat - full integration - Community Created Device Types - SmartThings Community infofiend

I tried that one this morning but I couldnā€™t get it to compile. I got a java error. I figured a less featured one would be easier to get working initially.

The error is
No signature of method: Script1.include() is applicable for argument types: (java.lang.String) values: [asynchttp_v1] Possible solutions: installed(), evaluate(java.lang.String)

Just comment out the line ā€œasynchttp_v1ā€

Yep, did that, but trying to adjust temperature gives the same error as the other API (after replacing the 100 or so data.* with device.data.*)

:errorNo signature of method: dev15192336643321758788909.httpPut() is applicable for argument types: (java.util.LinkedHashMap, dev15192336643321758788909$_setHeatingSetpoint_closure5) values: [[uri:https://neviweb.com/api/device/82931/setpoint, headers:[ā€¦], ā€¦], ā€¦] on line 293

@mike.maxwell Any chance you could look into the java error above? It works in smartthings to set temp and increase/decrease. This is the last device type I need to get connected.

Edit: until I buy more things. :smiley:

I contacted Sinope and they have open api documentation for local control to their hub, so Iā€™m going to request that and then see about learning how to get the control side of their devices working.

My priority is being able to set home/away modes from Hubitat. I already have schedules setup for the thermostats though the web interface.

That would be awesome. I have 11 of the neviweb thermostats and infloor heating model as well. Unfortunately I know nothing about code to give you any help.

I received the API filesā€¦ Itā€™s going to take parsing of raw communications to get local control working. Iā€™m a lot out of my league. Iā€™m going to see if thereā€™s anyone willing to take it on as a side project. Iā€™d be willing to pay something for their efforts.