Thanks to @mattw, this api is now functioning.
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"
}