mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
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 suffixing
This commit is contained in:
parent
adbec5bffc
commit
628e12c944
@ -1,7 +1,6 @@
|
|||||||
"""Support for SleepIQ from SleepNumber."""
|
"""Support for SleepIQ from SleepNumber."""
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from requests.exceptions import HTTPError
|
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ def setup(hass, config):
|
|||||||
try:
|
try:
|
||||||
DATA = SleepIQData(client)
|
DATA = SleepIQData(client)
|
||||||
DATA.update()
|
DATA.update()
|
||||||
except HTTPError:
|
except ValueError:
|
||||||
message = """
|
message = """
|
||||||
SleepIQ failed to login, double check your username and password"
|
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()
|
data.update()
|
||||||
|
|
||||||
dev = list()
|
dev = list()
|
||||||
for bed_id, _ in data.beds.items():
|
for bed_id, bed in data.beds.items():
|
||||||
for side in sleepiq.SIDES:
|
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)
|
add_entities(dev)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Sleepiq",
|
"name": "Sleepiq",
|
||||||
"documentation": "https://www.home-assistant.io/components/sleepiq",
|
"documentation": "https://www.home-assistant.io/components/sleepiq",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"sleepyq==0.6"
|
"sleepyq==0.7"
|
||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": []
|
"codeowners": []
|
||||||
|
@ -13,9 +13,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
data.update()
|
data.update()
|
||||||
|
|
||||||
dev = list()
|
dev = list()
|
||||||
for bed_id, _ in data.beds.items():
|
for bed_id, bed in data.beds.items():
|
||||||
for side in sleepiq.SIDES:
|
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)
|
add_entities(dev)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1671,7 +1671,7 @@ skybellpy==0.4.0
|
|||||||
slacker==0.13.0
|
slacker==0.13.0
|
||||||
|
|
||||||
# homeassistant.components.sleepiq
|
# homeassistant.components.sleepiq
|
||||||
sleepyq==0.6
|
sleepyq==0.7
|
||||||
|
|
||||||
# homeassistant.components.xmpp
|
# homeassistant.components.xmpp
|
||||||
slixmpp==1.4.2
|
slixmpp==1.4.2
|
||||||
|
@ -332,7 +332,7 @@ rxv==0.6.0
|
|||||||
simplisafe-python==3.4.2
|
simplisafe-python==3.4.2
|
||||||
|
|
||||||
# homeassistant.components.sleepiq
|
# homeassistant.components.sleepiq
|
||||||
sleepyq==0.6
|
sleepyq==0.7
|
||||||
|
|
||||||
# homeassistant.components.smhi
|
# homeassistant.components.smhi
|
||||||
smhi-pkg==1.0.10
|
smhi-pkg==1.0.10
|
||||||
|
@ -30,6 +30,7 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase):
|
|||||||
'username': self.username,
|
'username': self.username,
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
}
|
}
|
||||||
|
self.DEVICES = []
|
||||||
|
|
||||||
def tearDown(self): # pylint: disable=invalid-name
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
@ -56,3 +57,21 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase):
|
|||||||
right_side = self.DEVICES[0]
|
right_side = self.DEVICES[0]
|
||||||
assert 'SleepNumber ILE Test2 Is In Bed' == right_side.name
|
assert 'SleepNumber ILE Test2 Is In Bed' == right_side.name
|
||||||
assert 'off' == right_side.state
|
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
|
from tests.common import load_fixture, get_test_home_assistant
|
||||||
|
|
||||||
|
|
||||||
def mock_responses(mock):
|
def mock_responses(mock, single=False):
|
||||||
"""Mock responses for SleepIQ."""
|
"""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(
|
mock.put(
|
||||||
base_url + 'login',
|
base_url + 'login',
|
||||||
text=load_fixture('sleepiq-login.json'))
|
text=load_fixture('sleepiq-login.json'))
|
||||||
mock.get(
|
mock.get(
|
||||||
base_url + 'bed?_k=0987',
|
base_url + 'bed?_k=0987',
|
||||||
text=load_fixture('sleepiq-bed.json'))
|
text=load_fixture('sleepiq-bed{}.json'.format(suffix)))
|
||||||
mock.get(
|
mock.get(
|
||||||
base_url + 'sleeper?_k=0987',
|
base_url + 'sleeper?_k=0987',
|
||||||
text=load_fixture('sleepiq-sleeper.json'))
|
text=load_fixture('sleepiq-sleeper.json'))
|
||||||
mock.get(
|
mock.get(
|
||||||
base_url + 'bed/familyStatus?_k=0987',
|
base_url + 'bed/familyStatus?_k=0987',
|
||||||
text=load_fixture('sleepiq-familystatus.json'))
|
text=load_fixture('sleepiq-familystatus{}.json'.format(suffix)))
|
||||||
|
|
||||||
|
|
||||||
class TestSleepIQ(unittest.TestCase):
|
class TestSleepIQ(unittest.TestCase):
|
||||||
@ -61,7 +65,7 @@ class TestSleepIQ(unittest.TestCase):
|
|||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_setup_login_failed(self, mock):
|
def test_setup_login_failed(self, mock):
|
||||||
"""Test the setup if a bad username or password is given."""
|
"""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,
|
status_code=401,
|
||||||
json=load_fixture('sleepiq-login-failed.json'))
|
json=load_fixture('sleepiq-login-failed.json'))
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||||||
'username': self.username,
|
'username': self.username,
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
}
|
}
|
||||||
|
self.DEVICES = []
|
||||||
|
|
||||||
def tearDown(self): # pylint: disable=invalid-name
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
@ -41,10 +42,7 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||||||
mock_responses(mock)
|
mock_responses(mock)
|
||||||
|
|
||||||
assert setup_component(self.hass, 'sleepiq', {
|
assert setup_component(self.hass, 'sleepiq', {
|
||||||
'sleepiq': {
|
'sleepiq': self.config
|
||||||
'username': '',
|
|
||||||
'password': '',
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
sleepiq.setup_platform(self.hass,
|
sleepiq.setup_platform(self.hass,
|
||||||
@ -60,3 +58,22 @@ class TestSleepIQSensorSetup(unittest.TestCase):
|
|||||||
right_side = self.DEVICES[0]
|
right_side = self.DEVICES[0]
|
||||||
assert 'SleepNumber ILE Test2 SleepNumber' == right_side.name
|
assert 'SleepNumber ILE Test2 SleepNumber' == right_side.name
|
||||||
assert 80 == right_side.state
|
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
|
||||||
|
27
tests/fixtures/sleepiq-bed-single.json
vendored
Normal file
27
tests/fixtures/sleepiq-bed-single.json
vendored
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
17
tests/fixtures/sleepiq-familystatus-single.json
vendored
Normal file
17
tests/fixtures/sleepiq-familystatus-single.json
vendored
Normal file
@ -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…
x
Reference in New Issue
Block a user