mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Remove vendor lookup for mac addresses (#13788)
* Remove vendor lookup for mac addresses * Fix tests
This commit is contained in:
parent
7595401dcb
commit
5ac52b74e0
@ -9,8 +9,6 @@ from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any, List, Sequence, Callable
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.setup import async_prepare_setup_platform
|
||||
@ -19,7 +17,6 @@ from homeassistant.loader import bind_hass
|
||||
from homeassistant.components import group, zone
|
||||
from homeassistant.config import load_yaml_config_file, async_log_exception
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers import config_per_platform, discovery
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
@ -76,7 +73,6 @@ ATTR_LOCATION_NAME = 'location_name'
|
||||
ATTR_MAC = 'mac'
|
||||
ATTR_NAME = 'name'
|
||||
ATTR_SOURCE_TYPE = 'source_type'
|
||||
ATTR_VENDOR = 'vendor'
|
||||
ATTR_CONSIDER_HOME = 'consider_home'
|
||||
|
||||
SOURCE_TYPE_GPS = 'gps'
|
||||
@ -328,14 +324,10 @@ class DeviceTracker(object):
|
||||
self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False,
|
||||
name=GROUP_NAME_ALL_DEVICES, add=[device.entity_id])
|
||||
|
||||
# lookup mac vendor string to be stored in config
|
||||
yield from device.set_vendor_for_mac()
|
||||
|
||||
self.hass.bus.async_fire(EVENT_NEW_DEVICE, {
|
||||
ATTR_ENTITY_ID: device.entity_id,
|
||||
ATTR_HOST_NAME: device.host_name,
|
||||
ATTR_MAC: device.mac,
|
||||
ATTR_VENDOR: device.vendor,
|
||||
})
|
||||
|
||||
# update known_devices.yaml
|
||||
@ -413,7 +405,6 @@ class Device(Entity):
|
||||
consider_home = None # type: dt_util.dt.timedelta
|
||||
battery = None # type: int
|
||||
attributes = None # type: dict
|
||||
vendor = None # type: str
|
||||
icon = None # type: str
|
||||
|
||||
# Track if the last update of this device was HOME.
|
||||
@ -423,7 +414,7 @@ class Device(Entity):
|
||||
def __init__(self, hass: HomeAssistantType, consider_home: timedelta,
|
||||
track: bool, dev_id: str, mac: str, name: str = None,
|
||||
picture: str = None, gravatar: str = None, icon: str = None,
|
||||
hide_if_away: bool = False, vendor: str = None) -> None:
|
||||
hide_if_away: bool = False) -> None:
|
||||
"""Initialize a device."""
|
||||
self.hass = hass
|
||||
self.entity_id = ENTITY_ID_FORMAT.format(dev_id)
|
||||
@ -451,7 +442,6 @@ class Device(Entity):
|
||||
self.icon = icon
|
||||
|
||||
self.away_hide = hide_if_away
|
||||
self.vendor = vendor
|
||||
|
||||
self.source_type = None
|
||||
|
||||
@ -567,51 +557,6 @@ class Device(Entity):
|
||||
self._state = STATE_HOME
|
||||
self.last_update_home = True
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_vendor_for_mac(self):
|
||||
"""Set vendor string using api.macvendors.com."""
|
||||
self.vendor = yield from self.get_vendor_for_mac()
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_vendor_for_mac(self):
|
||||
"""Try to find the vendor string for a given MAC address."""
|
||||
if not self.mac:
|
||||
return None
|
||||
|
||||
if '_' in self.mac:
|
||||
_, mac = self.mac.split('_', 1)
|
||||
else:
|
||||
mac = self.mac
|
||||
|
||||
if not len(mac.split(':')) == 6:
|
||||
return 'unknown'
|
||||
|
||||
# We only need the first 3 bytes of the MAC for a lookup
|
||||
# this improves somewhat on privacy
|
||||
oui_bytes = mac.split(':')[0:3]
|
||||
# bytes like 00 get truncates to 0, API needs full bytes
|
||||
oui = '{:02x}:{:02x}:{:02x}'.format(*[int(b, 16) for b in oui_bytes])
|
||||
url = 'http://api.macvendors.com/' + oui
|
||||
try:
|
||||
websession = async_get_clientsession(self.hass)
|
||||
|
||||
with async_timeout.timeout(5, loop=self.hass.loop):
|
||||
resp = yield from websession.get(url)
|
||||
# mac vendor found, response is the string
|
||||
if resp.status == 200:
|
||||
vendor_string = yield from resp.text()
|
||||
return vendor_string
|
||||
# If vendor is not known to the API (404) or there
|
||||
# was a failure during the lookup (500); set vendor
|
||||
# to something other then None to prevent retry
|
||||
# as the value is only relevant when it is to be stored
|
||||
# in the 'known_devices.yaml' file which only happens
|
||||
# the first time the device is seen.
|
||||
return 'unknown'
|
||||
except (asyncio.TimeoutError, aiohttp.ClientError):
|
||||
# Same as above
|
||||
return 'unknown'
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Add an entity."""
|
||||
@ -685,7 +630,6 @@ def async_load_config(path: str, hass: HomeAssistantType,
|
||||
vol.Optional('picture', default=None): vol.Any(None, cv.string),
|
||||
vol.Optional(CONF_CONSIDER_HOME, default=consider_home): vol.All(
|
||||
cv.time_period, cv.positive_timedelta),
|
||||
vol.Optional('vendor', default=None): vol.Any(None, cv.string),
|
||||
})
|
||||
try:
|
||||
result = []
|
||||
@ -697,6 +641,8 @@ def async_load_config(path: str, hass: HomeAssistantType,
|
||||
return []
|
||||
|
||||
for dev_id, device in devices.items():
|
||||
# Deprecated option. We just ignore it to avoid breaking change
|
||||
device.pop('vendor', None)
|
||||
try:
|
||||
device = dev_schema(device)
|
||||
device['dev_id'] = cv.slugify(dev_id)
|
||||
@ -772,7 +718,6 @@ def update_config(path: str, dev_id: str, device: Device):
|
||||
'picture': device.config_picture,
|
||||
'track': device.track,
|
||||
CONF_AWAY_HIDE: device.away_hide,
|
||||
'vendor': device.vendor,
|
||||
}}
|
||||
out.write('\n')
|
||||
out.write(dump(device))
|
||||
|
@ -24,9 +24,7 @@ from homeassistant.remote import JSONEncoder
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, fire_time_changed,
|
||||
patch_yaml_files, assert_setup_component, mock_restore_cache, mock_coro)
|
||||
|
||||
from ...test_util.aiohttp import mock_aiohttp_client
|
||||
patch_yaml_files, assert_setup_component, mock_restore_cache)
|
||||
|
||||
TEST_PLATFORM = {device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}}
|
||||
|
||||
@ -111,7 +109,6 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
self.assertEqual(device.config_picture, config.config_picture)
|
||||
self.assertEqual(device.away_hide, config.away_hide)
|
||||
self.assertEqual(device.consider_home, config.consider_home)
|
||||
self.assertEqual(device.vendor, config.vendor)
|
||||
self.assertEqual(device.icon, config.icon)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@ -173,124 +170,6 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
"55502f40dc8b7c769880b10874abc9d0.jpg?s=80&d=wavatar")
|
||||
self.assertEqual(device.config_picture, gravatar_url)
|
||||
|
||||
def test_mac_vendor_lookup(self):
|
||||
"""Test if vendor string is lookup on macvendors API."""
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
vendor_string = 'Raspberry Pi Foundation'
|
||||
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name')
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
text=vendor_string)
|
||||
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
assert aioclient_mock.call_count == 1
|
||||
|
||||
self.assertEqual(device.vendor, vendor_string)
|
||||
|
||||
def test_mac_vendor_mac_formats(self):
|
||||
"""Verify all variations of MAC addresses are handled correctly."""
|
||||
vendor_string = 'Raspberry Pi Foundation'
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
text=vendor_string)
|
||||
aioclient_mock.get('http://api.macvendors.com/00:27:eb',
|
||||
text=vendor_string)
|
||||
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180),
|
||||
True, 'test', mac, 'Test name')
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
self.assertEqual(device.vendor, vendor_string)
|
||||
|
||||
mac = '0:27:EB:00:00:00'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180),
|
||||
True, 'test', mac, 'Test name')
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
self.assertEqual(device.vendor, vendor_string)
|
||||
|
||||
mac = 'PREFIXED_B8:27:EB:00:00:00'
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180),
|
||||
True, 'test', mac, 'Test name')
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
self.assertEqual(device.vendor, vendor_string)
|
||||
|
||||
def test_mac_vendor_lookup_unknown(self):
|
||||
"""Prevent another mac vendor lookup if was not found first time."""
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name')
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
status=404)
|
||||
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
|
||||
self.assertEqual(device.vendor, 'unknown')
|
||||
|
||||
def test_mac_vendor_lookup_error(self):
|
||||
"""Prevent another lookup if failure during API call."""
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name')
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
status=500)
|
||||
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
|
||||
self.assertEqual(device.vendor, 'unknown')
|
||||
|
||||
def test_mac_vendor_lookup_exception(self):
|
||||
"""Prevent another lookup if exception during API call."""
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
|
||||
device = device_tracker.Device(
|
||||
self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name')
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
exc=asyncio.TimeoutError())
|
||||
|
||||
run_coroutine_threadsafe(device.set_vendor_for_mac(),
|
||||
self.hass.loop).result()
|
||||
|
||||
self.assertEqual(device.vendor, 'unknown')
|
||||
|
||||
def test_mac_vendor_lookup_on_see(self):
|
||||
"""Test if macvendor is looked up when device is seen."""
|
||||
mac = 'B8:27:EB:00:00:00'
|
||||
vendor_string = 'Raspberry Pi Foundation'
|
||||
|
||||
tracker = device_tracker.DeviceTracker(
|
||||
self.hass, timedelta(seconds=60), 0, {}, [])
|
||||
|
||||
with mock_aiohttp_client() as aioclient_mock:
|
||||
aioclient_mock.get('http://api.macvendors.com/b8:27:eb',
|
||||
text=vendor_string)
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
tracker.async_see(mac=mac), self.hass.loop).result()
|
||||
assert aioclient_mock.call_count == 1, \
|
||||
'No http request for macvendor made!'
|
||||
self.assertEqual(tracker.devices['b827eb000000'].vendor, vendor_string)
|
||||
|
||||
@patch(
|
||||
'homeassistant.components.device_tracker.DeviceTracker.see')
|
||||
@patch(
|
||||
@ -463,7 +342,6 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
'entity_id': 'device_tracker.hello',
|
||||
'host_name': 'hello',
|
||||
'mac': 'MAC_1',
|
||||
'vendor': 'unknown',
|
||||
}
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@ -495,9 +373,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
||||
timedelta(seconds=0))
|
||||
assert len(config) == 0
|
||||
|
||||
@patch('homeassistant.components.device_tracker.Device'
|
||||
'.set_vendor_for_mac', return_value=mock_coro())
|
||||
def test_see_state(self, mock_set_vendor):
|
||||
def test_see_state(self):
|
||||
"""Test device tracker see records state correctly."""
|
||||
self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN,
|
||||
TEST_PLATFORM))
|
||||
|
@ -123,7 +123,5 @@ def mock_device_tracker_conf():
|
||||
), patch(
|
||||
'homeassistant.components.device_tracker.async_load_config',
|
||||
side_effect=lambda *args: mock_coro(devices)
|
||||
), patch('homeassistant.components.device_tracker'
|
||||
'.Device.set_vendor_for_mac'):
|
||||
|
||||
):
|
||||
yield devices
|
||||
|
Loading…
x
Reference in New Issue
Block a user