1 """Support for fetching WiFi associations through SNMP."""
3 from __future__
import annotations
7 from typing
import TYPE_CHECKING
9 from pysnmp.error
import PySnmpError
10 from pysnmp.hlapi.asyncio
import (
18 import voluptuous
as vol
21 DOMAIN
as DEVICE_TRACKER_DOMAIN,
22 PLATFORM_SCHEMA
as DEVICE_TRACKER_PLATFORM_SCHEMA,
35 DEFAULT_AUTH_PROTOCOL,
38 DEFAULT_PRIV_PROTOCOL,
43 from .util
import RequestArgsType, async_create_request_cmd_args
45 _LOGGER = logging.getLogger(__name__)
47 PLATFORM_SCHEMA = DEVICE_TRACKER_PLATFORM_SCHEMA.extend(
49 vol.Required(CONF_BASEOID): cv.string,
50 vol.Required(CONF_HOST): cv.string,
51 vol.Optional(CONF_COMMUNITY, default=DEFAULT_COMMUNITY): cv.string,
52 vol.Inclusive(CONF_AUTH_KEY,
"keys"): cv.string,
53 vol.Inclusive(CONF_PRIV_KEY,
"keys"): cv.string,
59 hass: HomeAssistant, config: ConfigType
60 ) -> SnmpScanner |
None:
61 """Validate the configuration and return an SNMP scanner."""
62 scanner =
SnmpScanner(config[DEVICE_TRACKER_DOMAIN])
63 await scanner.async_init(hass)
65 return scanner
if scanner.success_init
else None
69 """Queries any SNMP capable Access Point for connected devices."""
72 """Initialize the scanner and test the target device."""
73 host = config[CONF_HOST]
74 community = config[CONF_COMMUNITY]
75 baseoid = config[CONF_BASEOID]
76 authkey = config.get(CONF_AUTH_KEY)
77 authproto = DEFAULT_AUTH_PROTOCOL
78 privkey = config.get(CONF_PRIV_KEY)
79 privproto = DEFAULT_PRIV_PROTOCOL
83 target = UdpTransportTarget((host, DEFAULT_PORT), timeout=DEFAULT_TIMEOUT)
87 target = Udp6TransportTarget(
88 (host, DEFAULT_PORT), timeout=DEFAULT_TIMEOUT
90 except PySnmpError
as err:
91 _LOGGER.error(
"Invalid SNMP host: %s", err)
94 if authkey
is not None or privkey
is not None:
102 authKey=authkey
or None,
103 privKey=privkey
or None,
104 authProtocol=authproto,
105 privProtocol=privproto,
109 community, mpModel=SNMP_VERSIONS[DEFAULT_VERSION]
113 self.
request_argsrequest_args: RequestArgsType |
None =
None
119 """Make a one-off read to check if the target device is reachable and readable."""
127 """Scan for new devices and return a list with found device IDs."""
129 return [client[
"mac"]
for client
in self.
last_resultslast_results
if client.get(
"mac")]
132 """Return the name of the given device or None if we don't know."""
137 """Ensure the information from the device is up to date.
139 Return boolean if scanning successful.
151 """Fetch MAC addresses from access point via SNMP."""
156 engine, auth_data, target, context_data, object_type = self.
request_argsrequest_args
157 walker = bulkWalkCmd(
165 lexicographicMode=
False,
167 async
for errindication, errstatus, errindex, res
in walker:
169 _LOGGER.error(
"SNMPLIB error: %s", errindication)
173 "SNMP error: %s at %s",
174 errstatus.prettyPrint(),
175 errindex
and res[
int(errindex) - 1][0]
or "?",
179 for _oid, value
in res:
180 if not isEndOfMib(res):
182 mac = binascii.hexlify(value.asOctets()).decode(
"utf-8")
183 except AttributeError:
185 _LOGGER.debug(
"Found MAC address: %s", mac)
186 mac =
":".join([mac[i : i + 2]
for i
in range(0, len(mac), 2)])
187 devices.append({
"mac": mac})
None async_init(self, HomeAssistant hass)
str|None async_get_device_name(self, str device)
def _async_update_info(self)
def async_get_snmp_data(self)
def __init__(self, config)
def async_scan_devices(self)
SnmpScanner|None async_get_scanner(HomeAssistant hass, ConfigType config)
RequestArgsType async_create_request_cmd_args(HomeAssistant hass, UsmUserData|CommunityData auth_data, UdpTransportTarget|Udp6TransportTarget target, str object_id)