8000 0.7.5rc1 by balloob · Pull Request #506 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

0.7.5rc1 #506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 109 commits into from
Oct 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
321a603
Add a light & switch rfxtrx support
badele Sep 27, 2015
174aeac
Fix duplicate devices insertion
badele Sep 27, 2015
d64f0dd
Refactoring the code for pylint & flake test
badele Sep 29, 2015
cc47e39
Add send capability
badele Sep 29, 2015
db509cc
Add a light & switch rfxtrx sender capability
badele Oct 2, 2015
7f71706
Log RFXCOM events
badele Oct 3, 2015
6d53944
Support RGB colors
alanbowman Oct 4, 2015
3b49d1e
Update version to 0.7.5dev0
balloob Oct 6, 2015
32f1791
Check flake & pylint style
badele Oct 6, 2015
047cff6
Add blinkstick support
alanbowman Sep 29, 2015
0fb9e1b
Initial commit of snmp device tracker
tomduijf Oct 6, 2015
df7fbf6
Added constants needed for snmp
tomduijf Oct 6, 2015
e535f50
Merge branch 'master' into dev_tracker_snmp
tomduijf Oct 6, 2015
87599df
add some new media types
maddox Oct 7, 2015
dcf5233
add new properties for Channel or Playlist
maddox Oct 7, 2015
d454cad
add a play_media function
maddox Oct 7, 2015
e64846e
add ability to support play_media
maddox Oct 7, 2015
d17174d
play_media as a service
maddox Oct 7, 2015
4be33bb
add a way to play a playlist with the client
maddox Oct 7, 2015
e84ddb0
return what playlist is playing
maddox Oct 7, 2015
1b22f71
implement play_media
maddox Oct 7, 2015
bdb42bf
support play_media
maddox Oct 7, 2015
9012ba5
add play_media service to tests
maddox Oct 7, 2015
ad549be
support play_media for state restoration (for scenes)
maddox Oct 7, 2015
6afb846
avoid key errors
maddox Oct 7, 2015
c4f8017
silence warning
maddox Oct 7, 2015
6c4b2fd
derp
maddox Oct 7, 2015
bb997de
COMMMMAAAAAAAAAAAA
maddox Oct 7, 2015
25a6906
import it from the right place
maddox Oct 7, 2015
1c4ac60
fix typo while were in here
maddox Oct 7, 2015
faa3e98
module level play_media
maddox Oct 7, 2015
dbcc3a7
style
maddox Oct 7, 2015
c83324d
nope
maddox Oct 7, 2015
26939ce
style
maddox Oct 7, 2015
5e0a4c3
Merge pull request #487 from balloob/media-player-play-media
balloob Oct 7, 2015
6ab4b80
Merge branch 'dev' into itunes-play-media
maddox Oct 7, 2015
9a3c76c
these are required
maddox Oct 7, 2015
8533888
wrap it
maddox Oct 7, 2015
c2fe977
style
maddox Oct 7, 2015
3b58e86
style
maddox Oct 7, 2015
ffbaf0c
simpler
maddox Oct 7, 2015
9d4aa7e
Update tests for RGB color support
alanbowman Oct 7, 2015
a58382e
Fixed b/octet to mac adress conversion
tomduijf Oct 7, 2015
11fc521
Replace REQUIREMENTS by DEPENDENCIES variable
badele Oct 7, 2015
496e4cf
Exclude rfxtrx component files
badele Oct 7, 2015
46f5ef5
Refactoring test instance type
badele Oct 7, 2015
a5dae78
Refactoring the rfxtrx components
badele Oct 7, 2015
17865c7
Added # comment for Sensor
Oct 7, 2015
469f35d
various fixes, initial working version
tomduijf Oct 7, 2015
9377b64
removed debug logging
tomduijf Oct 7, 2015
d149f9d
Update doc string (Fix #491)
fabaff Oct 7, 2015
d556e59
Updated misc files and code styling
tomduijf Oct 7, 2015
7cb0f80
fixed loop
tomduijf Oct 7, 2015
ae6f651
styling and version for requirement
tomduijf Oct 7, 2015
4673a82
Merge pull request #490 from CCOSTAN/patch-3
balloob Oct 8, 2015
1b4ef38
Merge pull request #471 from alanbowman/blinkstick_support
balloob Oct 8, 2015
c189960
Merge branch 'pr/483' into dev
balloob Oct 8, 2015
213a1fe
Various fixes, CI validation
tomduijf Oct 8, 2015
729f596
Merge branch 'dev' into dev_tracker_snmp
tomduijf Oct 8, 2015
4edbdab
Merge remote-tracking branch 'upstream/master' into dev
tomduijf Oct 8, 2015
4f0f7ef
Merge remote-tracking branch 'upstream/dev' into dev
tomduijf Oct 8, 2015
bf9b179
Update docstrings
fabaff Oct 8, 2015
050f90d
merge with upstream
tomduijf Oct 8, 2015
6d3f18d
Update docstrings
fabaff Oct 8, 2015
06cac7f
Update docstrings
fabaff Oct 8, 2015
d8aefb5
Update docstrings
fabaff Oct 8, 2015
3b7f6d3
Update docstrings
fabaff Oct 8, 2015
9f10ab5
Update logger output
fabaff Oct 8, 2015
85bf6cb
Added pylint disables
tomduijf Oct 8, 2015
fe37a6a
Merge remote-tracking branch 'upstream/dev' into dev_tracker_snmp
tomduijf Oct 8, 2015
721c1d0
styling fix for flake
tomduijf Oct 8, 2015
a015df7
Test for media_content_id KeyError
MagnusKnutas Oct 8, 2015
61c9557
Logging with info
MagnusKnutas Oct 8, 2015
75c3e42
Removes log for cleanup
MagnusKnutas Oct 8, 2015
05cec77
Merge pull request #495 from kennedyshead/dev
balloob Oct 8, 2015
5322789
Ability to store icons/pictures in config_dir/www for e.g. device_tra…
tomduijf Oct 8, 2015
ee23c0f
cleaner logging
tomduijf Oct 8, 2015
f682fd7
Merge remote-tracking branch 'upstream/dev' into dev_tracker_snmp
tomduijf Oct 8, 2015
ad417bf
Merge remote-tracking branch 'upstream/dev' into local_www
tomduijf Oct 8, 2015
39ced09
Merge pull request #493 from tomduijf/dev_tracker_snmp
balloob Oct 8, 2015
cbf94aa
Merge remote-tracking branch 'upstream/dev' into local_www
tomduijf Oct 8, 2015
455a591
Merge pull request #496 from tomduijf/local_www
balloob Oct 8, 2015
e0149c4
Merge pull request #488 from balloob/itunes-play-media
balloob Oct 8, 2015
28b107f
Move details from header to docs
fabaff Oct 8, 2015
45f0911
move play_media to the top so it catches first
maddox Oct 9, 2015
cb2943c
Merge pull request #499 from balloob/handle-states-for-media-player
balloob Oct 9, 2015
dc5f0ef
NMap: fix hostname resolver
balloob Oct 9, 2015
0624725
Ignore nmap style issue - pylint bug
balloob Oct 9, 2015
9f33b8f
DDWRT - match multiple output variants
balloob Oct 9, 2015
8a04e1f
Device tracker configuration fix
balloob Oct 9, 2015
47fc1de
Fix throttle to work on instance-level
balloob Oct 9, 2015
be8089b
Cleanup arest
balloob Oct 9, 2015
fe5bb89
Add telegram notifier
fabaff Oct 9, 2015
3ef5e7c
Add telegram
fabaff Oct 9, 2015
9f6ce86
Add telegram
fabaff Oct 9, 2015
e29f857
Update header (docstring)
fabaff Oct 9, 2015
526a163
Update link
fabaff Oct 9, 2015
db53e46
Add link to docs and remove configuration details
fabaff Oct 9, 2015
f8efe3f
Update link to docs
fabaff Oct 9, 2015
c2c18bd
Merge pull request #501 from fabaff/telegram
balloob Oct 9, 2015
8fc2f5f
Update and equalize comments
fabaff Oct 9, 2015
7432bbd
Merge pull request #500 from balloob/arest-fix
fabaff Oct 9, 2015
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
7 changes: 6 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ omit =
homeassistant/components/zwave.py
homeassistant/components/*/zwave.py

homeassistant/components/rfxtrx.py
homeassistant/components/*/rfxtrx.py

homeassistant/components/ifttt.py
homeassistant/components/browser.py
homeassistant/components/camera/*
Expand All @@ -39,11 +42,13 @@ omit =
homeassistant/components/device_tracker/thomson.py
homeassistant/components/device_tracker/tomato.py
homeassistant/components/device_tracker/tplink.py
homeassistant/components/device_tracker/snmp.py
homeassistant/components/discovery.py
homeassistant/components/downloader.py
homeassistant/components/keyboard.py
homeassistant/components/light/hue.py
homeassistant/components/light/limitlessled.py
homeassistant/components/light/blinksticklight.py
homeassistant/components/media_player/cast.py
homeassistant/components/media_player/denon.py
homeassistant/components/media_player/itunes.py
Expand All @@ -60,6 +65,7 @@ omit =
homeassistant/components/notify/slack.py
homeassistant/components/notify/smtp.py
homeassistant/components/notify/syslog.py
homeassistant/components/notify/telegram.py
homeassistant/components/notify/xmpp.py
homeassistant/components/sensor/arest.py
homeassistant/components/sensor/bitcoin.py
Expand All @@ -71,7 +77,6 @@ omit =
homeassistant/components/sensor/mysensors.py
homeassistant/components/sensor/openweathermap.py
homeassistant/components/sensor/rest.py
homeassistant/components/sensor/rfxtrx.py
homeassistant/components/sensor/rpi_gpio.py
homeassistant/components/sensor/sabnzbd.py
homeassistant/components/sensor/swiss_public_transport.py
Expand Down
7 changes: 5 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
recursive-exclude tests *
recursive-include homeassistant services.yaml
include README.md
include LICENSE
graft homeassistant
prune homeassistant/components/frontend/www_static/home-assistant-polymer
recursive-exclude * *.py[co]
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ Check out [the website](https://home-assistant.io) for [a demo][demo], installat

Examples of devices it can interface it:

* Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), and [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/)
* Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/) and any SNMP capable Linksys WAP/WRT
*
* [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, [Edimax](http://www.edimax.com/) switches, [Efergy](https://efergy.com) energy monitoring, RFXtrx sensors, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors
* [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Kodi (XBMC)](http://kodi.tv/), and iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api))
* Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/)
* [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Plex](https://plex.tv/), [Kodi (XBMC)](http://kodi.tv/), and iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api))
* Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [RFXtrx](http://www.rfxcom.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/)
* Interaction with [IFTTT](https://ifttt.com/)
* Integrate data from the [Bitcoin](https://bitcoin.org) network, meteorological data from [OpenWeatherMap](http://openweathermap.org/) and [Forecast.io](https://forecast.io/), [Transmission](http://www.transmissionbt.com/), or [SABnzbd](http://sabnzbd.org).
* [See full list of supported devices](https://home-assistant.io/components/)

Expand All @@ -29,8 +31,8 @@ Built home automation on top of your devices:
* Turn on the lights when people get home after sun set
* Turn on lights slowly during sun set to compensate for less light
* Turn off all lights and devices when everybody leaves the house
* Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects
* Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), and [Jabber (XMPP)](http://xmpp.org)
* Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects like [OwnTracks](http://owntracks.org/)
* Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), [Telegram](https://telegram.org/), and [Jabber (XMPP)](http://xmpp.org)

The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](https://home-assistant.io/developers/architecture.html) and the [section on creating your own components](https://home-assistant.io/developers/creating_components.html).

Expand Down
3 changes: 3 additions & 0 deletions config/configuration.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ automation:
service: light.turn_off
entity_id: group.all_lights

# Sensors need to be added into the configuration.yaml as sensor:, sensor 2:, sensor 3:, etc.
# Each sensor label should be unique or your sensors might not load correctly.

sensor:
platform: systemmonitor
resources:
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/device_tracker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ def setup(hass, config):
os.remove(csv_path)

conf = config.get(DOMAIN, {})
if isinstance(conf, list):
conf = conf[0]
consider_home = timedelta(
seconds=util.convert(conf.get(CONF_CONSIDER_HOME), int,
DEFAULT_CONSIDER_HOME))
Expand Down
76 changes: 38 additions & 38 deletions homeassistant/components/device_tracker/ddwrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
_LOGGER = logging.getLogger(__name__)

_DDWRT_DATA_REGEX = re.compile(r'\{(\w+)::([^\}]*)\}')
_MAC_REGEX = re.compile(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})')


# pylint: disable=unused-argument
Expand Down Expand Up @@ -77,7 +78,7 @@ def __init__(self, config):

self.last_results = {}

self.mac2name = None
self.mac2name = {}

# Test the router is accessible
url = 'http://{}/Status_Wireless.live.asp'.format(self.host)
Expand All @@ -98,30 +99,33 @@ def get_device_name(self, device):

with self.lock:
# if not initialised and not already scanned and not found
if self.mac2name is None or device not in self.mac2name:
if device not in self.mac2name:
url = 'http://{}/Status_Lan.live.asp'.format(self.host)
data = self.get_ddwrt_data(url)

if not data:
return
return None

dhcp_leases = data.get('dhcp_leases', None)
if dhcp_leases:
# remove leading and trailing single quotes
cleaned_str = dhcp_leases.strip().strip('"')
elements = cleaned_str.split('","')
num_clients = int(len(elements)/5)
self.mac2name = {}
for idx in range(0, num_clients):
# this is stupid but the data is a single array
# every 5 elements represents one hosts, the MAC
# is the third element and the name is the first
mac_index = (idx * 5) + 2
if mac_index < len(elements):
mac = elements[mac_index]
self.mac2name[mac] = elements[idx * 5]

return self.mac2name.get(device, None)

if not dhcp_leases:
return None

# remove leading and trailing single quotes
cleaned_str = dhcp_leases.strip().strip('"')
elements = cleaned_str.split('","')
num_clients = int(len(elements)/5)
self.mac2name = {}
for idx in range(0, num_clients):
# this is stupid but the data is a single array
# every 5 elements represents one hosts, the MAC
# is the third element and the name is the first
mac_index = (idx * 5) + 2
if mac_index < len(elements):
mac = elements[mac_index]
self.mac2name[mac] = elements[idx * 5]

return self.mac2name.get(device)

@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
Expand All @@ -141,29 +145,25 @@ def _update_info(self):
if not data:
return False

if data:
self.last_results = []
active_clients = data.get('active_wireless', None)
if active_clients:
# This is really lame, instead of using JSON the DD-WRT UI
# uses its own data format for some reason and then
# regex's out values so I guess I have to do the same,
# LAME!!!
self.last_results = []

active_clients = data.get('active_wireless', None)
if not active_clients:
return False

# remove leading and trailing single quotes
clean_str = active_clients.strip().strip("'")
elements = clean_str.split("','")
# This is really lame, instead of using JSON the DD-WRT UI
# uses its own data format for some reason and then
# regex's out values so I guess I have to do the same,
# LAME!!!

num_clients = int(len(elements)/9)
for idx in range(0, num_clients):
# get every 9th element which is the MAC address
index = idx * 9
if index < len(elements):
self.last_results.append(elements[index])
# remove leading and trailing single quotes
clean_str = active_clients.strip().strip("'")
elements = clean_str.split("','")

return True
self.last_results.extend(item for item in elements
if _MAC_REGEX.match(item))

return False
return True

def get_ddwrt_data(self, url):
""" Retrieve data from DD-WRT and return parsed result. """
Expand Down
28 changes: 15 additions & 13 deletions homeassistant/components/device_tracker/nmap_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,34 +117,36 @@ def _update_info(self):
scanner = PortScanner()

options = "-F --host-timeout 5"
exclude_targets = set()

if self.home_interval:
now = dt_util.now()
for host in self.last_results:
if host.last_update + self.home_interval > now:
exclude_targets.add(host)
if len(exclude_targets) > 0:
target_list = [t.ip for t in exclude_targets]
options += " --exclude {}".format(",".join(target_list))
boundary = dt_util.now() - self.home_interval
last_results = [device for device in self.last_results
if device.last_update > boundary]
if last_results:
# Pylint is confused here.
# pylint: disable=no-member
options += " --exclude {}".format(",".join(device.ip for device
in last_results))
else:
last_results = []

try:
result = scanner.scan(hosts=self.hosts, arguments=options)
except PortScannerError:
return False

now = dt_util.now()
self.last_results = []
for ipv4, info in result['scan'].items():
if info['status']['state'] != 'up':
continue
name = info['hostnames'][0] if info['hostnames'] else ipv4
name = info['hostnames'][0]['name'] if info['hostnames'] else ipv4
# Mac address only returned if nmap ran as root
mac = info['addresses'].get('mac') or _arp(ipv4)
if mac is None:
continue
device = Device(mac.upper(), name, ipv4, now)
self.last_results.append(device)
self.last_results.extend(exclude_targets)
last_results.append(Device(mac.upper(), name, ipv4, now))

self.last_results = last_results

_LOGGER.info("nmap scan successful")
return True
119 changes: 119 additions & 0 deletions homeassistant/components/device_tracker/snmp.py
C589
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""
homeassistant.components.device_tracker.snmp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports fetching WiFi associations
through SNMP.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.snmp.html
"""
import logging
from datetime import timedelta
import threading
import binascii

from homeassistant.const import CONF_HOST
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN

# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)

_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pysnmp==4.2.5']

CONF_COMMUNITY = "community"
CONF_BASEOID = "baseoid"


# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns an snmp scanner """
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_COMMUNITY, CONF_BASEOID]},
_LOGGER):
return None

scanner = SnmpScanner(config[DOMAIN])

return scanner if scanner.success_init else None


class SnmpScanner(object):
"""
This class queries any SNMP capable Acces Point for connected devices.
"""
def __init__(self, config):
self.host = config[CONF_HOST]
self.community = config[CONF_COMMUNITY]
self.baseoid = config[CONF_BASEOID]

self.lock = threading.Lock()

self.last_results = []

# Test the router is accessible
data = self.get_snmp_data()
self.success_init = data is not None

def scan_devices(self):
"""
Scans for new devices and return a list containing found device IDs.
"""

self._update_info()
return [client['mac'] for client in self.last_results]

# Supressing no-self-use warning
# pylint: disable=R0201
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
# We have no names
return None

@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the WAP is up to date.
Returns boolean if scanning successful.
"""
if not self.success_init:
return False

with self.lock:
data = self.get_snmp_data()
if not data:
return False

self.last_results = data
return True

def get_snmp_data(self):
""" Fetch mac addresses from WAP via SNMP. """
from pysnmp.entity.rfc3413.oneliner import cmdgen

devices = []

snmp = cmdgen.CommandGenerator()
errindication, errstatus, errindex, restable = snmp.nextCmd(
cmdgen.CommunityData(self.community),
cmdgen.UdpTransportTarget((self.host, 161)),
cmdgen.MibVariable(self.baseoid)
)

if errindication:
_LOGGER.error("SNMPLIB error: %s", errindication)
return
if errstatus:
_LOGGER.error('SNMP error: %s at %s', errstatus.prettyPrint(),
errindex and restable[-1][int(errindex)-1]
or '?')
return

for resrow in restable:
for _, val in resrow:
mac = binascii.hexlify(val.asOctets()).decode('utf-8')
mac = ':'.join([mac[i:i+2] for i in range(0, len(mac), 2)])
devices.append({'mac': mac})
return devices
Loading
0