Sleepiq single sleeper crash (#24941)
* Update sleepyq to 0.7 Fixes crash when working with a single sleeper. * sleepiq: Handle null side definitions These happen if no sleeper is defined for a side of the bed. Don't create sensors for null sides; they'll crash every time we try to use them. * sleepiq: Fix urls mocked to match sleepyq 0.7 * sleepi: Fix test_sensor.TestSleepIQSensorSetup Sleepyq 0.7 throws on empty strings, so we have to specify them. * sleepiq: Test for ValueError thrown by sleepyq 0.7 * sleepiq: Drop no longer used HTTPError import * sleepiq: Add tests for single sleeper case * sleepiq: Shorten comments to not overflow line length * sleepiq: Use formatted string literals for adding suffixes to test files * sleepiq: Use str.format() for test suffixingpull/25005/head
parent
adbec5bffc
commit
628e12c944
|
@ -1,7 +1,6 @@
|
|||
"""Support for SleepIQ from SleepNumber."""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -53,7 +52,7 @@ def setup(hass, config):
|
|||
try:
|
||||
DATA = SleepIQData(client)
|
||||
DATA.update()
|
||||
except HTTPError:
|
||||
except ValueError:
|
||||
message = """
|
||||
SleepIQ failed to login, double check your username and password"
|
||||
"""
|
||||
|
|
|
@ -12,9 +12,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
data.update()
|
||||
|
||||
dev = list()
|
||||
for bed_id, _ in data.beds.items():
|
||||
for bed_id, bed in data.beds.items():
|
||||
for side in sleepiq.SIDES:
|
||||
dev.append(IsInBedBinarySensor(data, bed_id, side))
|
||||
if getattr(bed, side) is not None:
|
||||
dev.append(IsInBedBinarySensor(data, bed_id, side))
|
||||
add_entities(dev)
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Sleepiq",
|
||||
"documentation": "https://www.home-assistant.io/components/sleepiq",
|
||||
"requirements": [
|
||||
"sleepyq==0.6"
|
||||
"sleepyq==0.7"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
|
|
|
@ -13,9 +13,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
data.update()
|
||||
|
||||
dev = list()
|
||||
for bed_id, _ in data.beds.items():
|
||||
for bed_id, bed in data.beds.items():
|
||||
for side in sleepiq.SIDES:
|
||||
dev.append(SleepNumberSensor(data, bed_id, side))
|
||||
if getattr(bed, side) is not None:
|
||||
dev.append(SleepNumberSensor(data, bed_id, side))
|
||||
add_entities(dev)
|
||||
|
||||
|
||||
|
|
|
@ -1671,7 +1671,7 @@ skybellpy==0.4.0
|
|||
slacker==0.13.0
|
||||
|
||||
# homeassistant.components.sleepiq
|
||||
sleepyq==0.6
|
||||
sleepyq==0.7
|
||||
|
||||
# homeassistant.components.xmpp
|
||||
slixmpp==1.4.2
|
||||
|
|
|
@ -332,7 +332,7 @@ rxv==0.6.0
|
|||
simplisafe-python==3.4.2
|
||||
|
||||
# homeassistant.components.sleepiq
|
||||
sleepyq==0.6
|
||||
sleepyq==0.7
|
||||
|
||||
# homeassistant.components.smhi
|
||||
smhi-pkg==1.0.10
|
||||
|
|
|
@ -30,6 +30,7 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase):
|
|||
'username': self.username,
|
||||
'password': self.password,
|
||||
}
|
||||
self.DEVICES = []
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop everything that was started."""
|
||||
|
@ -56,3 +57,21 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase):
|
|||
right_side = self.DEVICES[0]
|
||||
assert 'SleepNumber ILE Test2 Is In Bed' == right_side.name
|
||||
assert 'off' == right_side.state
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_setup_single(self, mock):
|
||||
"""Test for successfully setting up the SleepIQ platform."""
|
||||
mock_responses(mock, single=True)
|
||||
|
||||
setup_component(self.hass, 'sleepiq', {
|
||||
'sleepiq': self.config})
|
||||
|
||||
sleepiq.setup_platform(self.hass,
|
||||
self.config,
|
||||
self.add_entities,
|
||||
MagicMock())
|
||||
assert 1 == len(self.DEVICES)
|
||||
|
||||
right_side = self.DEVICES[0]
|
||||
assert 'SleepNumber ILE Test1 Is In Bed' == right_side.name
|
||||
assert 'on' == right_side.state
|
||||
|
|
|
@ -10,21 +10,25 @@ import homeassistant.components.sleepiq as sleepiq
|
|||
from tests.common import load_fixture, get_test_home_assistant
|
||||
|
||||
|
||||
def mock_responses(mock):
|
||||
def mock_responses(mock, single=False):
|
||||
"""Mock responses for SleepIQ."""
|
||||
base_url = 'https://api.sleepiq.sleepnumber.com/rest/'
|
||||
base_url = 'https://prod-api.sleepiq.sleepnumber.com/rest/'
|
||||
if single:
|
||||
suffix = '-single'
|
||||
else:
|
||||
suffix = ''
|
||||
mock.put(
|
||||
base_url + 'login',
|
||||
text=load_fixture('sleepiq-login.json'))
|
||||
mock.get(
|
||||
base_url + 'bed?_k=0987',
|
||||
text=load_fixture('sleepiq-bed.json'))
|
||||
text=load_fixture('sleepiq-bed{}.json'.format(suffix)))
|
||||
mock.get(
|
||||
base_url + 'sleeper?_k=0987',
|
||||
text=load_fixture('sleepiq-sleeper.json'))
|
||||
mock.get(
|
||||
base_url + 'bed/familyStatus?_k=0987',
|
||||
text=load_fixture('sleepiq-familystatus.json'))
|
||||
text=load_fixture('sleepiq-familystatus{}.json'.format(suffix)))
|
||||
|
||||
|
||||
class TestSleepIQ(unittest.TestCase):
|
||||
|
@ -61,7 +65,7 @@ class TestSleepIQ(unittest.TestCase):
|
|||
@requests_mock.Mocker()
|
||||
def test_setup_login_failed(self, mock):
|
||||
"""Test the setup if a bad username or password is given."""
|
||||
mock.put('https://api.sleepiq.sleepnumber.com/rest/login',
|
||||
mock.put('https://prod-api.sleepiq.sleepnumber.com/rest/login',
|
||||
status_code=401,
|
||||
json=load_fixture('sleepiq-login-failed.json'))
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||
'username': self.username,
|
||||
'password': self.password,
|
||||
}
|
||||
self.DEVICES = []
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop everything that was started."""
|
||||
|
@ -41,10 +42,7 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||
mock_responses(mock)
|
||||
|
||||
assert setup_component(self.hass, 'sleepiq', {
|
||||
'sleepiq': {
|
||||
'username': '',
|
||||
'password': '',
|
||||
}
|
||||
'sleepiq': self.config
|
||||
})
|
||||
|
||||
sleepiq.setup_platform(self.hass,
|
||||
|
@ -60,3 +58,22 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||
right_side = self.DEVICES[0]
|
||||
assert 'SleepNumber ILE Test2 SleepNumber' == right_side.name
|
||||
assert 80 == right_side.state
|
||||
|
||||
@requests_mock.Mocker()
|
||||
def test_setup_sigle(self, mock):
|
||||
"""Test for successfully setting up the SleepIQ platform."""
|
||||
mock_responses(mock, single=True)
|
||||
|
||||
assert setup_component(self.hass, 'sleepiq', {
|
||||
'sleepiq': self.config
|
||||
})
|
||||
|
||||
sleepiq.setup_platform(self.hass,
|
||||
self.config,
|
||||
self.add_entities,
|
||||
MagicMock())
|
||||
assert 1 == len(self.DEVICES)
|
||||
|
||||
right_side = self.DEVICES[0]
|
||||
assert 'SleepNumber ILE Test1 SleepNumber' == right_side.name
|
||||
assert 40 == right_side.state
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"beds" : [
|
||||
{
|
||||
"dualSleep" : false,
|
||||
"base" : "FlexFit",
|
||||
"sku" : "AILE",
|
||||
"model" : "ILE",
|
||||
"size" : "KING",
|
||||
"isKidsBed" : false,
|
||||
"sleeperRightId" : "-80",
|
||||
"accountId" : "-32",
|
||||
"bedId" : "-31",
|
||||
"registrationDate" : "2016-07-22T14:00:58Z",
|
||||
"serial" : null,
|
||||
"reference" : "95000794555-1",
|
||||
"macAddress" : "CD13A384BA51",
|
||||
"version" : null,
|
||||
"purchaseDate" : "2016-06-22T00:00:00Z",
|
||||
"sleeperLeftId" : "0",
|
||||
"zipcode" : "12345",
|
||||
"returnRequestStatus" : 0,
|
||||
"name" : "ILE",
|
||||
"status" : 1,
|
||||
"timezone" : "US/Eastern"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"beds" : [
|
||||
{
|
||||
"bedId" : "-31",
|
||||
"rightSide" : {
|
||||
"alertId" : 0,
|
||||
"lastLink" : "00:00:00",
|
||||
"isInBed" : true,
|
||||
"sleepNumber" : 40,
|
||||
"alertDetailedMessage" : "No Alert",
|
||||
"pressure" : -16
|
||||
},
|
||||
"status" : 1,
|
||||
"leftSide" : null
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue