@patrick did you ever get your Sleep By Number bed working in Hubitat?
I never got it working on ST. Never tried on Hubitat.
I reach out to the Developer of the app for the SmartThings Sleep IQ app and now have it working in Hubitat. I have been using it for the last week and it works good. It works the same way that it did in Smartthings it shows presence in bed. There are two changes that you have to make and they are below.
Change 1: Before line 265 "httpPut(loginParams) { response ->" (in method doLogin) add a new line:
log.trace "doLogin() put request: $loginParams"
Change 2: Add two new fields to loginParams in the same method as above. Before line 257 "headers: [" add the new lines:
requestContentType: 'application/json',
contentType: 'application/json',
That's really cool! Could you post your working driver to this thread or GitHub?
Thanks!!
I can here is the app code.
/**
- Copyright 2015 Nathan Jacobson natecj@gmail.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.
*/
definition(
name: "SleepIQ Manager",
namespace: "natecj",
author: "Nathan Jacobson",
description: "Manage sleepers across multiple beds through your SleepIQ account.",
category: "Convenience",
iconUrl: "",
iconX2Url: ""
)
preferences {
page name: "rootPage"
page name: "findDevicePage"
page name: "selectDevicePage"
page name: "createDevicePage"
}
def rootPage() {
log.trace "rootPage()"
def devices = getChildDevices()
dynamicPage(name: "rootPage", install: true, uninstall: true) {
section("Settings") {
input("login", "text", title: "Username", description: "Your SleepIQ username")
input("password", "password", title: "Password", description: "Your SleepIQ password")
input("interval", "number", title: "Refresh Interval", description: "How many minutes between refresh", defaultValue: 15)
}
section("Devices") {
if (devices.size() > 0) {
devices.each { device ->
paragraph title: device.label, "${device.currentBedId} / ${device.currentMode}"
}
}
href "findDevicePage", title: "Create New Device", description: null
}
section {
label title: "Assign a name", required: false
mode title: "Set for specific mode(s)", required: false
}
}
}
def statusText(status) {
"Current Status: " + (status ? "Present" : "Not Present")
}
def findDevicePage() {
log.trace "findDevicePage()"
def responseData = getBedData()
log.debug "Response Data: $responseData"
dynamicPage(name: "findDevicePage") {
if (responseData.beds.size() > 0) {
responseData.beds.each { bed ->
section("Bed: ${bed.bedId}") {
def leftStatus = bed.leftSide.isInBed
def rightStatus = bed.rightSide.isInBed
def bothStatus = leftStatus && rightStatus
def eitherStatus = leftStatus || rightStatus
href "selectDevicePage", title: "Both Sides", description: statusText(bothStatus), params: [bedId: bed.bedId, mode: "Both", status: bothStatus]
href "selectDevicePage", title: "Either Side", description: statusText(eitherStatus), params: [bedId: bed.bedId, mode: "Either", status: eitherStatus]
href "selectDevicePage", title: "Left Side", description: statusText(leftStatus), params: [bedId: bed.bedId, mode: "Left", status: leftStatus]
href "selectDevicePage", title: "Right Side", description: statusText(rightStatus), params: [bedId: bed.bedId, mode: "Right", status: rightStatus]
}
}
} else {
section {
paragraph "No Beds Found"
}
}
}
}
def selectDevicePage(params) {
log.trace "selectDevicePage()"
settings.newDeviceName = null
dynamicPage(name: "selectDevicePage") {
section {
paragraph "Bed ID: ${params.bedId}"
paragraph "Mode: ${params.mode}"
paragraph "Status: ${params.present ? 'Present' : 'Not Present'}"
input "newDeviceName", "text", title: "Device Name", description: "What do you want to call this presence sensor?", defaultValue: ""
}
section {
href "createDevicePage", title: "Create Device", description: null, params: [bedId: params.bedId, mode: params.mode, status: params.status]
}
}
}
def createDevicePage(params) {
log.trace "createDevicePage()"
def deviceId = "Sleepiq.${params.bedId}.${params.mode}"
def device = addChildDevice("natecj", "SleepIQ Presence Sensor", deviceId, null, [label: settings.newDeviceName])
device.setStatus(params.status)
device.setBedId(params.bedId)
device.setMode(params.mode)
settings.newDeviceName = null
dynamicPage(name: "selectDevicePage") {
section {
paragraph "Name: ${device.name}"
paragraph "Label: ${device.label}"
paragraph "Bed ID: ${device.curentBedId}"
paragraph "Mode: ${device.currentMode}"
paragraph "Presence: ${device.currentPresnce}"
}
section {
href "rootPage", title: "Back to Device List", description: null
}
}
}
def installed() {
log.trace "installed()"
initialize()
}
def updated() {
log.trace "updated()"
unsubscribe()
unschedule()
initialize()
}
def initialize() {
log.trace "initialize()"
refreshChildDevices()
schedule("* /${settings.interval} * * * ?", "refreshChildDevices")
}
def refreshChildDevices() {
log.trace "refreshChildDevices()"
getBedData()
}
def getBedData() {
log.trace "getBedData()"
// Make request and wait for completion
state.requestData = null
doStatus()
while(state.requestData == null) { sleep ( 1000 ) }
def requestData = state.requestData
state.requestData = null
// Process data
processBedData(requestData)
// Return data
requestData
}
def processBedData(responseData) {
if (!responseData || responseData.size() == 0) {
return
}
for(def device : getChildDevices()) {
for(def bed : responseData.beds) {
if (device.currentBedId == bed.bedId) {
def statusMap = [:]
statusMap["Both"] = bed.leftSide.isInBed && bed.rightSide.isInBed
statusMap["Either"] = bed.leftSide.isInBed || bed.rightSide.isInBed
statusMap["Left"] = bed.leftSide.isInBed
statusMap["Right"] = bed.rightSide.isInBed
if (statusMap.containsKey(device.currentMode)) {
log.debug "Setting ${device.label} (${device.currentMode}) to ${statusMap[device.currentMode] ? "Present" : "Not Present"}"
device.setStatus(statusMap[device.currentMode])
}
break
}
}
}
}
private def ApiHost() { "api.sleepiq.sleepnumber.com" }
private def ApiUriBase() { "https://api.sleepiq.sleepnumber.com" }
private def ApiUserAgent() { "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36" }
private def doStatus(alreadyLoggedIn = false) {
log.trace "doStatus()"
// Login if there isnt an active session
if (!state.session || !state.session?.key) {
if (alreadyLoggedIn) {
log.error "doStatus() Already attempted login, giving up for now"
} else {
doLogin()
}
return
}
// Make the request
try {
def statusParams = [
uri: ApiUriBase() + '/rest/bed/familyStatus?_k=' + state.session?.key,
headers: [
'Content-Type': 'application/json;charset=UTF-8',
'Host': ApiHost(),
'User-Agent': ApiUserAgent(),
'Cookie': state.session?.cookies,
'DNT': '1',
],
]
httpGet(statusParams) { response ->
if (response.status == 200){
log.trace "doStatus() Success - Request was successful: ($response.status) $response.data"
state.requestData = response.data
} else {
log.trace "doStatus() Failure - Request was unsuccessful: ($response.status) $response.data"
state.session = null
state.requestData = [:]
}
}
} catch(Exception e) {
if (alreadyLoggedIn) {
log.error "doStatus() Error ($e)"
} else {
log.trace "doStatus() Error ($e)"
doLogin()
}
}
}
private def doLogin() {
log.trace "doLogin()"
state.session = null
state.requestData = [:]
try {
def loginParams = [
uri: ApiUriBase() + '/rest/login',
requestContentType: 'application/json',
contentType: 'application/json',
headers: [
'Content-Type': 'application/json;charset=UTF-8',
'Host': ApiHost(),
'User-Agent': ApiUserAgent(),
'DNT': '1',
],
body: '{"login":"' + settings.login + '","password":"' + settings.password + '"}='
]
log.trace "doLogin() put request: $loginParams"
httpPut(loginParams) { response ->
if (response.status==200) {
log.trace "doLogin() Success - Request was successful: ($response.status) $response.data"
state.session = [:]
state.session.key = response.data.key
state.session.cookies = ''
response.getHeaders('Set-Cookie').each {
state.session.cookies = state.session.cookies + it.value.split(';')[0] + ';'
}
doStatus(true)
} else {
log.trace "doLogin() Failure - Request was unsuccessful: ($response.status) $response.data"
state.session = null
state.requestData = [:]
}
}
} catch(Exception e) {
log.error "doLogin() Error ($e)"
state.session = null
state.requestData = [:]
}
}
Here is the driver.
/**
- SleepIQ Presence Sensor
- Copyright 2015 Nathan Jacobson
- 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: "SleepIQ Presence Sensor", namespace: "natecj", author: "Nathan Jacobson") {
capability "Presence Sensor"
capability "Switch"
capability "Polling"
command "arrived"
command "departed"
attribute "bedId", "String"
attribute "mode", "enum", ["Both", "Either", "Left", "Right"]
command "setStatus", ["string"]
command "setBedId", ["string"]
command "setMode", ["string"]
}
simulator {
status "present": "presence: present"
status "not present": "presence: not present"
status "on": "switch: on"
status "off": "switch: not off"
}
/*
preferences {
section("Settings:") {
input("mode", title: "Mode", "enum", required: false, defaultValue: "Either", options: ["Left", "Right", "Both", "Either"], description: "The side(s) of the bed to monitor")
}
}
*/
tiles {
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
state("not present", label:'not present', icon:"st.presence.tile.not-present", backgroundColor:"#ffffff", action:"arrived")
state("present", label:'present', icon:"st.presence.tile.present", backgroundColor:"#53a7c0", action:"departed")
}
standardTile("refresh", "device.poll", inactiveLabel: false, decoration: "flat") {
state "default", action:"polling.poll", icon:"st.secondary.refresh"
}
valueTile("bedId", "device.bedId", width: 3, height: 1) {
state "default", label: '${currentValue}'
}
valueTile("mode", "device.mode", width: 1, height: 1) {
state "default", label: '${currentValue}'
}
main "presence"
details(["presence", "refresh", "mode", "bedId"])
}
}
def installed() {
log.trace 'installed()'
}
def updated() {
log.trace 'updated()'
}
def poll() {
log.trace "poll()"
parent.refreshChildDevices()
}
def parse(String description) {
log.trace "parse() - Description: ${description}"
def results = []
/*
def pair = description.split(":")
results = createEvent(name: pair[0].trim(), value: pair[1].trim())
//results = createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed")
*/
log.debug "parse() - Results: ${results.inspect()}"
results
}
def arrived() {
log.trace "arrived()"
sendEvent(name: "presence", value: "present")
sendEvent(name: "switch", value: "on")
}
def departed() {
log.trace "departed()"
sendEvent(name: "presence", value: "not present")
sendEvent(name: "switch", value: "off")
}
def on() {
log.trace "on()"
arrived()
}
def off() {
log.trace "off()"
departed()
}
def setStatus(val) {
log.trace "setStatus($val)"
if (val) {
arrived()
} else {
departed()
}
}
def setBedId(val) {
log.trace "setBedId($val)"
sendEvent(name: "bedId", value: val)
}
def setMode(val) {
log.trace "setMode($val)"
sendEvent(name: "mode", value: val)
}
I can add the app just fine, but when I try to create device, it doesn't work with the following error:
For anyone else - I figured out the issue. Users have to be created for both sides of the bed using the SleepIQ app before adding a device.
I have users for both sides in the app so no concerns there
Where I tried to create a device for "Both" in the HE app, I got an error, however it did create the first device, which I discovered later.
I then went in and created the left side, got the same error, however it did create the device, now I have 2 for the same side
I then attempted to create the right side, got the same error, however the device was created
Then deleted the first left side device so I only have 1
Went back into the HE app and just selected done, it finally created the app in the HE portal
Same error every time
Rick
Thank you for pursuing Nathan Jacobson and getting his Smartthings app/DTH ported to Hubitat.
The following screenshot of the conditional part of a rule, part of my wake up routines, indicates why I'm so happy with this. From tomorrow, if I'm still in bed 45 minutes after I'm supposed to be up , Alexa will start bugging me.
@aaiyar your welcome. Glad you got it working. I will try to see what cause this error and see if we can get it fix?
I just repair line 162 on the app as I had extra spaces that should not have been there and may have been the cause of the errors and I have now remove the spaces, hopefully that will fix the issue.
@aaiyar, Ashok
I set this up a few days ago, have 1 device for me and my wife, yet I am not seeing anything in the event logs for either device
What am I missing?
Rick
@toy4rick are you pulling up the device and clicking the event button? I'm not seeing the mode or bedid on mine just the switch and presence.
Name | Value | Unit | Description Text | Source | Type | Date |
---|---|---|---|---|---|---|
switch | off | DEVICE | 2019-06-08 08:30:00.557 AM EDT | |||
presence | not present | DEVICE | 2019-06-08 08:30:00.557 AM EDT | |||
presence | present | DEVICE | 2019-06-08 12:00:01.281 AM EDT | |||
switch | on | DEVICE | 2019-06-08 12:00:01.281 AM EDT | |||
switch | off | DEVICE | 2019-06-07 07:10:41.333 AM EDT | |||
presence | not present | DEVICE | 2019-06-07 07:10:41.333 AM EDT | |||
switch | on | DEVICE | 2019-06-06 10:50:00.643 PM EDT | |||
presence | present | DEVICE | 2019-06-06 10:50:00.637 PM EDT | |||
switch | off | DEVICE | 2019-06-06 10:45:00.787 PM EDT | |||
presence | not present | DEVICE | 2019-06-06 10:45:00.787 PM EDT |
I wish I could tell you why aren't seeing anything in the event log. Here's what the event log looks like for the side I sleep on:
Here's what the SleepIQ Manager setup screen looks like, after 4 sensors are created (R, L, Either, Both):
Just to confirm - you are using the modifications that @leeonestop posted, correct?
@aaiyar I just set a right and left not both or either? is there a benefit to setting up other beside the right and left???
There is for me. I roll in bed, sometimes starting on one side and ending up on the other. In that situation, I want my wake routine to be based on either side being occupied.
There is also a possibility that both sides will be occupied, and when that happens, I don't want my wake up routine to run.
@leeonestop, yes, using the event button
@aaiyar, I created left and right. why would i need to create both and/or either? I'm not following
By creating Both and Either, won't I know have 6 unique devices for a 2 person bed?
Rick