Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
54dbdd6
Merge pull request #1 from home-assistant/dev
austinmroczek Apr 14, 2019
90483d2
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
austinmroczek Apr 18, 2019
51aa773
Bump skybellpy to 0.4.0
austinmroczek Apr 18, 2019
e18b4d2
Bump skybellpy to 0.4.0 in requirements_all.txt
austinmroczek Apr 22, 2019
d74156a
Added extra states for STATE_ALARM_TRIGGERED to allow users to know if
austinmroczek Apr 26, 2019
ad1cdb3
Merge branch 'dev' of https://github.com/austinmroczek/home-assistant…
austinmroczek Apr 26, 2019
5c5c052
Merge pull request #2 from home-assistant/dev
austinmroczek Apr 26, 2019
abcc85a
Fix const import
austinmroczek Apr 28, 2019
d303091
Fix const import
austinmroczek Apr 28, 2019
73f38eb
Fix const imports
austinmroczek Apr 28, 2019
5bec7e4
Bump total-connect-client to 0.26.
austinmroczek May 5, 2019
4862ff5
Catch details of alarm trigger in state attributes.
austinmroczek May 25, 2019
5068345
Merge branch 'dev' of
austinmroczek May 25, 2019
e7a13d4
Change state_attributes() to device_state_attributes()
austinmroczek May 30, 2019
53f20fb
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Jun 7, 2019
4bee662
Merge branch 'dev' of https://github.com/austinmroczek/home-assistant…
austinmroczek Jun 7, 2019
6a50e80
Move totalconnect component toward being a multi-platform integration…
austinmroczek Jun 8, 2019
37c34cf
Merge pull request #4 from home-assistant/dev
austinmroczek Jun 29, 2019
ad4c4c9
add missing total-connect alarm state mappings
austinmroczek Jun 29, 2019
e589317
Made recommended changes of MartinHjelmare at
austinmroczek Jun 30, 2019
aa22440
Update __init__.py
austinmroczek Jul 2, 2019
5cbfc98
Updates per MartinHjelmare comments
austinmroczek Jul 13, 2019
eb440cc
flake8/pydocstyle fixes
austinmroczek Jul 13, 2019
69425d7
Merge branch 'dev' of https://github.com/austinmroczek/home-assistant…
austinmroczek Jul 13, 2019
117ed1b
removed . at end of log message
austinmroczek Jul 13, 2019
14d3e2e
added blank line between logging and voluptuous
austinmroczek Jul 13, 2019
cd2b563
more fixes
austinmroczek Jul 14, 2019
2295b7c
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Nov 10, 2019
db6336b
Adding totalconnect zones as HA binary_sensors
austinmroczek Nov 10, 2019
e9a0e69
fix manifest.json
austinmroczek Nov 10, 2019
1bc164d
flake8/pydocstyle fixes. Added codeowner.
austinmroczek Nov 12, 2019
932e5b0
Update formatting per @springstan guidance.
austinmroczek Nov 16, 2019
bf7be02
Fixed pylint
austinmroczek Nov 16, 2019
f855154
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Dec 15, 2019
fcadf80
Add zone ID to log message for easier troubleshooting
austinmroczek Dec 15, 2019
a68576e
Account for bypassed zones in update()
austinmroczek Dec 19, 2019
a15b4de
More status handling fixes.
austinmroczek Dec 21, 2019
ea1510f
Fixed flake8 error
austinmroczek Dec 21, 2019
7f7ec1c
Another attempt at black/isort fixes.
austinmroczek Dec 21, 2019
4de1bcf
Bump total-connect-client to 0.50. Simplify code using new functions in
austinmroczek Jan 14, 2020
b66ba1f
Fix manifest file
austinmroczek Jan 14, 2020
4027382
Another manifest fix
austinmroczek Jan 14, 2020
656e88d
one more manifest fix
austinmroczek Jan 14, 2020
eca1045
more manifest changes.
austinmroczek Jan 14, 2020
750fc0b
sync up
austinmroczek Jan 15, 2020
fd927a3
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Jan 15, 2020
10f1642
Merge branch 'dev' of https://github.com/austinmroczek/home-assistant…
austinmroczek Jan 15, 2020
25f530b
fix indent
austinmroczek Jan 17, 2020
d9700f8
one more pylint fix
austinmroczek Jan 17, 2020
81f4cef
Hopefully the last pylint fix
austinmroczek Jan 17, 2020
6f0e779
make variable names understandable
austinmroczek Jan 18, 2020
c654941
create and fill dict in one step
austinmroczek Jan 18, 2020
1c32671
Fix name and attributes
austinmroczek Jan 18, 2020
35d3085
rename to logical variable in alarm_control_panel
austinmroczek Jan 18, 2020
c9b208d
Remove location_name from alarm_control_panel attributes since it is
austinmroczek Jan 19, 2020
10b555e
Multiple fixes to improve code per @springstan suggestions
austinmroczek Jan 19, 2020
19b0c63
Update homeassistant/components/totalconnect/binary_sensor.py
austinmroczek Jan 22, 2020
471b01a
Multiple changes per @MartinHjelmare review
austinmroczek Jan 31, 2020
ef06453
simplify alarm adding
austinmroczek Jan 31, 2020
0c1234e
Fix binary_sensor.py is_on
austinmroczek Jan 31, 2020
26f0bcd
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Feb 15, 2020
f9e6a69
Move DOMAIN to .const in line with examples.
austinmroczek Feb 15, 2020
464f3f8
Move to async_setup
austinmroczek Feb 15, 2020
28f4bd4
Simplify code using new features of total-connect-client 0.51
austinmroczek Feb 16, 2020
d3c8d24
First crack at config flow for totalconnect
austinmroczek Feb 17, 2020
0260a34
Merge remote-tracking branch 'upstream/dev' into dev
austinmroczek Feb 18, 2020
c798549
bump totalconnect to 0.52
austinmroczek Feb 20, 2020
e37fb88
use client.is_logged_in() to avoid total-connect-client details.
austinmroczek Feb 20, 2020
97590a0
updated generated/config_flow.py
austinmroczek Feb 20, 2020
6c192e4
use is_logged_in()
austinmroczek Feb 20, 2020
139c4f5
Hopefully final touches for config flow
austinmroczek Feb 22, 2020
425b890
Add tests for config flow
austinmroczek Feb 23, 2020
bcdc060
Updated requirements for test
austinmroczek Feb 23, 2020
b612388
Fixes to test_config_flow
austinmroczek Feb 23, 2020
15ab17f
Merge remote-tracking branch 'upstream/dev' into totalconnect-config-…
austinmroczek Feb 23, 2020
e6e8325
Removed leftover comments and code
austinmroczek Feb 23, 2020
1feab1e
fix const.py flake8 error
austinmroczek Feb 24, 2020
736e800
Simplify text per @Kane610 https://github.com/home-assistant/home-ass…
austinmroczek Feb 29, 2020
8ae81b2
Remove .get() to speed things up since the required items should always
austinmroczek Feb 29, 2020
2c21b3a
Merge branch 'totalconnect-config-flow' of https://github.com/austinm…
austinmroczek Feb 29, 2020
825cd86
Move CONF_USERNAME and CONF_PASSWORD into .const to eliminate extra I/O
austinmroczek Feb 29, 2020
7793619
Merge branch 'totalconnect-config-flow' of https://github.com/austinm…
austinmroczek Feb 29, 2020
0eb730e
Fix I/O async issues
austinmroczek Mar 2, 2020
dc541e5
Fix flake8 and black errors
austinmroczek Mar 3, 2020
ecf3881
Mock the I/O in tests.
austinmroczek Mar 3, 2020
74e65d7
Fix isort error
austinmroczek Mar 3, 2020
9f06454
Empty commit to re-start azure pipelines (per discord)
austinmroczek Mar 4, 2020
9bcd05f
bump total-connect-client to 0.53
austinmroczek Mar 4, 2020
a5c4c56
Update homeassistant/components/totalconnect/__init__.py
austinmroczek Mar 6, 2020
a93bfef
Update homeassistant/components/totalconnect/config_flow.py
austinmroczek Mar 6, 2020
4e7e98c
Fixes per @balloob comments
austinmroczek Mar 6, 2020
75ab1ae
Fix imports
austinmroczek Mar 6, 2020
9ed27ad
fix isort error
austinmroczek Mar 6, 2020
872130b
Fix async_unload_entry
austinmroczek Mar 6, 2020
234d805
Added async_setup so not breaking change. Fixed imports.
austinmroczek Mar 7, 2020
9e3a9a6
Update tests/components/totalconnect/test_config_flow.py
austinmroczek Mar 8, 2020
f5d1af5
Remove TotalConnectSystem() per @MartinHjelmare suggestion
austinmroczek Mar 8, 2020
bd20b20
Moved from is_logged_in() to is_valid_credentials()
austinmroczek Mar 8, 2020
0fe927c
Fix import in test
austinmroczek Mar 8, 2020
70ecea5
remove commented code and decorator
austinmroczek Mar 10, 2020
2b4ba2e
Update tests/components/totalconnect/test_config_flow.py
austinmroczek Mar 10, 2020
3396859
fix test_config_flow.py
austinmroczek Mar 10, 2020
85a7ec4
Merge remote-tracking branch 'upstream/dev' into totalconnect-config-…
austinmroczek Mar 10, 2020
f9afffc
bump total-connect-client to 0.54
austinmroczek Mar 10, 2020
dd62347
remove un-needed import of mock_coro
austinmroczek Mar 10, 2020
1115ec9
bump to total-connect-client 0.54.1
austinmroczek Mar 10, 2020
110f39c
Merge branch 'totalconnect-config-flow' of https://github.com/austinm…
austinmroczek Mar 10, 2020
c5f4ddf
re-add CONFIG_SCHEMA
austinmroczek Mar 10, 2020
ae483af
disable pylint on line 10 to avoid pylint bug
austinmroczek Mar 12, 2020
a99c112
Merge branch 'dev' into totalconnect-config-flow
austinmroczek Mar 28, 2020
8e29221
Merge branch 'dev' into totalconnect-config-flow
austinmroczek Apr 3, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions homeassistant/components/totalconnect/.translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"config": {
"abort": {
"already_configured": "Account already configured"
},
"error": {
"login": "Login error: please check your username & password"
},
"step": {
"user": {
"data": {
"password": "Password",
"username": "Username"
},
"title": "Total Connect"
}
},
"title": "Total Connect"
}
}
66 changes: 46 additions & 20 deletions homeassistant/components/totalconnect/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
"""The totalconnect component."""
import asyncio
import logging

from total_connect_client import TotalConnectClient
import voluptuous as vol

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers import discovery
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)

DOMAIN = "totalconnect"
PLATFORMS = ["alarm_control_panel", "binary_sensor"]

CONFIG_SCHEMA = vol.Schema(
Comment thread
austinmroczek marked this conversation as resolved.
Comment thread
austinmroczek marked this conversation as resolved.
{
Expand All @@ -20,39 +24,61 @@
vol.Required(CONF_PASSWORD): cv.string,
}
)
},
extra=vol.ALLOW_EXTRA,
}
)

TOTALCONNECT_PLATFORMS = ["alarm_control_panel", "binary_sensor"]

async def async_setup(hass: HomeAssistant, config: dict):
"""Set up by configuration file."""
if DOMAIN not in config:
return True

hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config[DOMAIN],
)
)

return True
Comment thread
austinmroczek marked this conversation as resolved.


def setup(hass, config):
"""Set up TotalConnect component."""
conf = config[DOMAIN]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Set up upon config entry in user interface."""
hass.data.setdefault(DOMAIN, {})

conf = entry.data
username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]

client = TotalConnectClient.TotalConnectClient(username, password)
client = await hass.async_add_executor_job(
TotalConnectClient.TotalConnectClient, username, password
)

if client.token is False:
if not client.is_valid_credentials():
_LOGGER.error("TotalConnect authentication failed")
return False

hass.data[DOMAIN] = TotalConnectSystem(username, password, client)
hass.data[DOMAIN][entry.entry_id] = client

for platform in TOTALCONNECT_PLATFORMS:
discovery.load_platform(hass, platform, DOMAIN, {}, config)
for component in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)
)

return True


class TotalConnectSystem:
"""TotalConnect System class."""
async def async_unload_entry(hass, entry: ConfigEntry):
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
]
)
)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

def __init__(self, username, password, client):
"""Initialize the TotalConnect system."""
self._username = username
self._password = password
self.client = client
return unload_ok
12 changes: 5 additions & 7 deletions homeassistant/components/totalconnect/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,17 @@
_LOGGER = logging.getLogger(__name__)


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an alarm control panel for a TotalConnect device."""
if discovery_info is None:
return

async def async_setup_entry(hass, entry, async_add_entities) -> None:
"""Set up TotalConnect alarm panels based on a config entry."""
alarms = []

client = hass.data[DOMAIN].client
client = hass.data[DOMAIN][entry.entry_id]

for location_id, location in client.locations.items():
location_name = location.location_name
alarms.append(TotalConnectAlarm(location_name, location_id, client))
add_entities(alarms)

async_add_entities(alarms, True)


class TotalConnectAlarm(alarm.AlarmControlPanel):
Expand Down
14 changes: 6 additions & 8 deletions homeassistant/components/totalconnect/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,22 @@
BinarySensorDevice,
)

from . import DOMAIN as TOTALCONNECT_DOMAIN
from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a sensor for a TotalConnect device."""
if discovery_info is None:
return

async def async_setup_entry(hass, entry, async_add_entities) -> None:
"""Set up TotalConnect device sensors based on a config entry."""
sensors = []

client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations
client_locations = hass.data[DOMAIN][entry.entry_id].locations

for location_id, location in client_locations.items():
for zone_id, zone in location.zones.items():
sensors.append(TotalConnectBinarySensor(zone_id, location_id, zone))
add_entities(sensors, True)

async_add_entities(sensors, True)


class TotalConnectBinarySensor(BinarySensorDevice):
Expand Down
60 changes: 60 additions & 0 deletions homeassistant/components/totalconnect/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""Config flow for the Total Connect component."""
import logging

from total_connect_client import TotalConnectClient
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME

from .const import DOMAIN # pylint: disable=unused-import

_LOGGER = logging.getLogger(__name__)


class TotalConnectConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Total Connect config flow."""

VERSION = 1

async def async_step_user(self, user_input=None):
"""Handle a flow initiated by the user."""
errors = {}

if user_input is not None:
# Validate user input
username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD]

await self.async_set_unique_id(username)
self._abort_if_unique_id_configured()

valid = await self.is_valid(username, password)

if valid:
# authentication success / valid
return self.async_create_entry(
title="Total Connect",
Comment thread
austinmroczek marked this conversation as resolved.
data={CONF_USERNAME: username, CONF_PASSWORD: password},
)
# authentication failed / invalid
errors["base"] = "login"

data_schema = vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
)

return self.async_show_form(
step_id="user", data_schema=data_schema, errors=errors
)

async def async_step_import(self, user_input):
Comment thread
austinmroczek marked this conversation as resolved.
"""Import a config entry."""
return await self.async_step_user(user_input)

async def is_valid(self, username="", password=""):
"""Return true if the given username and password are valid."""
client = await self.hass.async_add_executor_job(
TotalConnectClient.TotalConnectClient, username, password
)
return client.is_valid_credentials()
4 changes: 3 additions & 1 deletion homeassistant/components/totalconnect/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
"name": "Honeywell Total Connect Alarm",
"documentation": "https://www.home-assistant.io/integrations/totalconnect",
"requirements": ["total_connect_client==0.54.1"],
"codeowners": ["@austinmroczek"]
"dependencies": [],
"codeowners": ["@austinmroczek"],
"config_flow": true
}
20 changes: 20 additions & 0 deletions homeassistant/components/totalconnect/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"config": {
"title": "Total Connect",
"step": {
"user": {
"title": "Total Connect",
"data": {
"username": "Username",
"password": "Password"
}
}
},
"error": {
"login": "Login error: please check your username & password"
},
"abort": {
"already_configured": "Account already configured"
}
}
}
1 change: 1 addition & 0 deletions homeassistant/generated/config_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
"tellduslive",
"tesla",
"toon",
"totalconnect",
"tplink",
"traccar",
"tradfri",
Expand Down
3 changes: 3 additions & 0 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,9 @@ teslajsonpy==0.6.0
# homeassistant.components.toon
toonapilib==3.2.4

# homeassistant.components.totalconnect
total_connect_client==0.54.1

# homeassistant.components.transmission
transmissionrpc==0.11

Expand Down
1 change: 1 addition & 0 deletions tests/components/totalconnect/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the totalconnect component."""
104 changes: 104 additions & 0 deletions tests/components/totalconnect/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""Tests for the iCloud config flow."""
from unittest.mock import patch

from homeassistant import data_entry_flow
from homeassistant.components.totalconnect.const import DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME

from tests.common import MockConfigEntry

USERNAME = "username@me.com"
PASSWORD = "password"


async def test_user(hass):
"""Test user config."""
# no data provided so show the form
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)

assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"

# now data is provided, so check if login is correct and create the entry
with patch(
"homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient"
) as client_mock:
client_mock.return_value.is_valid_credentials.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)

assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY


async def test_import(hass):
"""Test import step with good username and password."""
with patch(
"homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient"
) as client_mock:
client_mock.return_value.is_valid_credentials.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)

assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY


async def test_abort_if_already_setup(hass):
"""Test abort if the account is already setup."""
MockConfigEntry(
domain=DOMAIN,
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
unique_id=USERNAME,
).add_to_hass(hass)

# Should fail, same USERNAME (import)
with patch(
"homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient"
) as client_mock:
client_mock.return_value.is_valid_credentials.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)

assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"

# Should fail, same USERNAME (flow)
with patch(
"homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient"
) as client_mock:
client_mock.return_value.is_valid_credentials.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)

assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"


async def test_login_failed(hass):
"""Test when we have errors during login."""
with patch(
"homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient"
) as client_mock:
client_mock.return_value.is_valid_credentials.return_value = False
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)

assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "login"}