@DarcRanger - Here is my version of @pstuart’s ps_Ubi which has been modified to support multiple Ubis.
Once you have the device type installed and published, you create multiple Ubi devices, one for each Ubi you have, so each Ubi becomes a “thing”. When you configure each device you need to specify which “Ubi number” it is (1, 2, 3, …), based upon the order in which it appears in the Ubi portal.
Note that I’ve also changed the code to work with temperatures in Celsius rather than Fahrenheit (we use the metric system here downunder). If you need Fahrenheit then hopefully you can see what needs changing back in the code.
/**
* sn_Ubi
*
* Portions Copyright 2014 patrick@patrickstuart.com
* Portions Copyright 2014 Steven Newnham
*
* 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.
*
* Based upon ps_Ubi by Patrick Stuart
* Changes support multiple Ubis and use of temperatures in Celsius
*
*/
preferences {
input("username", "text", title: "Username", description: "Your Ubi Portal username (usually an email address)")
input("password", "password", title: "Password", description: "Your Ubi password")
input("ubinumber", "number", title: "Ubi number", description: "Which Ubi is this in the Portal (1, 2, 3, etc.)")
}
metadata {
definition (name: "sn_Ubi", namespace: "snewnham", author: "Steven Newnham") {
capability "Polling"
capability "Relative Humidity Measurement"
capability "Illuminance Measurement"
capability "Temperature Measurement"
attribute "airPressure", "string"
attribute "soundLevel", "string"
}
simulator {
}
// Note: Value entries for background colours changed to match Celsius scale
// Not a direct Fahrenheit to Celsius conversion as original values
// didn't make much sense at the high end
tiles {
valueTile("temperature", "device.temperature", width: 1, height: 1, canChangeIcon: false) {
state("temperature", label: '${currentValue}°', unit:"C", backgroundColors: [
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 25, color: "#44b621"],
[value: 30, color: "#f1d801"],
[value: 35, color: "#d04e00"],
[value: 40, color: "#bc2323"]
]
)
}
valueTile("humidity", "device.humidity", inactiveLabel: false) {
state "default", label:'${currentValue}%', unit:"Humidity"
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false) {
state "luminosity", label:'${currentValue}lux', unit:"Light"
}
valueTile("airPressure", "device.airPressure", inactiveLabel: false) {
state "default", label:'${currentValue}Kpa', unit:"Air Pressure"
}
valueTile("soundLevel", "device.soundLevel", inactiveLabel: false) {
state "default", label:'${currentValue}db', unit:"Sound"
}
standardTile("refresh", "device.poll", inactiveLabel: false, decoration: "flat") {
state "default", action:"polling.poll", icon:"st.secondary.refresh"
}
main "temperature"
details(["temperature", "humidity", "illuminance", "airPressure", "soundLevel", "refresh"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'humidity' attribute
// TODO: handle 'illuminance' attribute
// TODO: handle 'temperature' attribute
// TODO: handle 'carbonMonoxide' attribute
}
// handle commands
def poll() {
// log.debug "Executing 'poll'"
// TODO: handle 'poll' command
login()
}
def login() {
def params = [
uri: 'https://portal.theubi.com/login.do',
headers: [
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'sdch',
'Host': 'portal.theubi.com',
'DNT': '1',
'Origin': 'https://portal.theubi.com/login.jsp',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36'
],
body: [j_username: username, j_password: password]
]
data.cookies = ''
httpPost(params) { response ->
log.debug "Request was successful, $response.status"
//log.debug response.headers
response.getHeaders('Set-Cookie').each {
String cookie = it.value.split(';')[0]
//log.debug "Adding cookie to collection: $cookie"
data.cookies = data.cookies + cookie + ';'
}
//log.debug "Cookies: $data.cookies"
}
def params2 = [
uri: "https://portal.theubi.com/room/",
headers: [
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'plain',
'Cookie': data.cookies
],
]
httpGet(params2) { response2 ->
log.debug "Request was successful, $response2.status"
def doc = response2.data
def x = new StringWriter()
doc[0].children[1].children[6].children[1].writeTo(x)
def linesAsList = x.toString().minus(" ").split( /\n|\r|\n\r|\r\n/ ).collect { it.replace( "'", '' ) }
// log.debug linesAsList
def v = [:]
// Calculate an offset into the list of lines based upon which Ubi we're after
int ubiOffset = (ubinumber.toInteger() - 1) * 15;
// Following was original code - based on Ubi Portal reporting temps in Fahrenheit
// v.temp = linesAsList[6].minus("document.write(toFahrenheit(").minus("));") //temp in C
// v.temp = Math.round((Double.parseDouble(v.temp) * 1.8 + 32)*100) /100 // Temp in F
// This is my code - based on Ubi Portal reporting temps in Celsius and wanting to report in Celsius
v.temp = linesAsList[(ubiOffset + 4)].minus("document.write(").minus(".toFixed(2));") //temp in C
v.temp = Math.round(Double.parseDouble(v.temp))
v.humidity = Double.parseDouble(linesAsList[(ubiOffset + 11)].minus("Humidity").minus("%")) // humidity
v.airPressure = linesAsList[(ubiOffset + 12)].minus("Air Pressure").minus("KPa") //Air Pressure
//v.airPressure = Double.parseDouble(v.airPressure) / 100// into bar
v.soundLevel = Double.parseDouble(linesAsList[(ubiOffset + 13)].minus("Sound level").minus("dB")) //Sound Level
v.lightLevel = Double.parseDouble(linesAsList[(ubiOffset + 14)].minus("Light level").minus("lux")) //Light Level
log.debug v
sendEvent(name: 'temperature', value: v.temp, unit: "C")
sendEvent(name: 'humidity', value: v.humidity)
sendEvent(name: 'illuminance', value: v.lightLevel, unit: "lux")
sendEvent(name: 'airPressure', value: v.airPressure.toString())
sendEvent(name: 'soundLevel', value: v.soundLevel)
}
}
You should be aware that this is screen-scraping the Ubi Portal HTML page, so it has a high likelihood of breaking in the future as changes occur to the Ubi Portal website. Also, each Ubi device will fetch a copy of the page, so it’s not the most efficient.
@pstuart has an API based approach in the works, pending the release of the API functionality by the Ubi powers that be - that will be a much better long term approach once it becomes available.