• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Controller for Asus AXE11000 access point."""
2
3import time
4from acts import logger
5from selenium import webdriver
6from selenium.common.exceptions import NoSuchElementException
7from selenium.webdriver.chrome.options import Options
8from selenium.webdriver.support.ui import Select
9
10MOBLY_CONTROLLER_CONFIG_NAME = "AsusAXE11000AP"
11ACTS_CONTROLLER_REFERENCE_NAME = "access_points"
12
13# Access point UI parameters
14USERNAME = "login_username"
15PASSWORD = "login_passwd"
16SIGN_IN_ID = "button"
17APPLY_BUTTON = "apply_btn"
18APPLY_BUTTON_ID = "applyButton"
19WIRELESS_SETTINGS = "Advanced_Wireless_Content_menu"
20GENERAL_TAB = "Advanced_Wireless_Content_tab"
21PROFESSIONAL_TAB = "Advanced_WAdvanced_Content_tab"
22HE_MODE_ID = "he_mode_field"
23WL_UNIT = "wl_unit"
24WL_11AX = "wl_11ax"
25WL_RADIO = "wl_radio"
26WL_CLOSED = "wl_closed"
27RADIO = "radio"
28BAND_2G_CHANNEL = "band0_channel"
29BAND_5G_CHANNEL = "band1_channel"
30BAND_6G_CHANNEL = "band2_channel"
31BAND_2G_AUTH = "band0_auth_mode_x"
32BAND_5G_AUTH = "band1_auth_mode_x"
33BAND_6G_AUTH = "band2_auth_mode_x"
34BAND_2G_SSID = "band0_ssid"
35BAND_5G_SSID = "band1_ssid"
36BAND_6G_SSID = "band2_ssid"
37BAND_2G_PSK = "band0_wpa_psk"
38BAND_5G_PSK = "band1_wpa_psk"
39BAND_6G_PSK = "band2_wpa_psk"
40BAND_2G_RAD_IP = "band0_radius_ipaddr"
41BAND_5G_RAD_IP = "band1_radius_ipaddr"
42BAND_2G_RAD_PORT = "band0_radius_port"
43BAND_5G_RAD_PORT = "band1_radius_port"
44BAND_2G_RAD_KEY = "band0_radius_key"
45BAND_5G_RAD_KEY = "band1_radius_key"
46SMART_CONNECT = "smartcon_enable_field"
47BROWSER_WAIT_SHORT_TIMEOUT = 6
48BROWSER_WAIT_TIMEOUT = 15
49BROWSER_WAIT_LONG_TIMEOUT = 90
50BROWSER_WAIT_VERY_LONG_TIMEOUT = 180
51
52# Access point supported modes, channels
53VALID_BANDS = ["2g", "5g", "6g"]
54WL_BAND_VALUE = {"2g": "0", "5g": "1", "6g": "2"}
55CHANNELS_2G = {
56    0: "0",
57    1: "1",
58    2: "2",
59    3: "3",
60    4: "4",
61    5: "5",
62    6: "6",
63    7: "7",
64    8: "8",
65    9: "9",
66    10: "10",
67    11: "11"
68}
69CHANNELS_5G = {
70    0: "0",
71    36: "36/160",
72    40: "40/160",
73    44: "44/160",
74    48: "48/160",
75    52: "52/160",
76    56: "56/160",
77    60: "60/160",
78    64: "64/160",
79    100: "100/160",
80    104: "104/160",
81    108: "108/160",
82    112: "112/160",
83    116: "116/160",
84    120: "120/160",
85    124: "124/160",
86    128: "128/160",
87    132: "132/80",
88    136: "136/80",
89    140: "140/80",
90    144: "144/80",
91    149: "149/80",
92    153: "153/80",
93    157: "157/80",
94    161: "161/80",
95    165: "165"
96}
97CHANNELS_6G = {
98    0: "0",
99    37: "6g37/160",
100    53: "6g53/160",
101    69: "6g69/160",
102    85: "6g85/160",
103    101: "6g101/160",
104    117: "6g117/160",
105    133: "6g133/160",
106    149: "6g149/160",
107    165: "6g165/160",
108    181: "6g181/160",
109    197: "6g197/160",
110    213: "6g213/160"
111}
112
113
114def create(configs):
115  """Creates ap controllers from a json config."""
116  return [AsusAXE11000AP(c) for c in configs]
117
118
119def destroy(aps):
120  """Destroys a list of ap controllers."""
121  for ap in aps:
122    ap.reset_to_default_ap_settings()
123    ap.driver.quit()
124
125
126class AsusAXE11000AP(object):
127  """Asus AXE11000 AccessPoint controller.
128
129  Controller class for Asus AXE11000 6GHz AP. This class provides methods to
130  configure the AP with different settings required for 11ax and 6GHz testing.
131  The controller uses chrome webdriver to communicate with the AP.
132
133  The controller object is initiated in the test class. The ACTS test runner
134  calls this controller using the 'AsusAXE11000AP' keyword in the ACTS config
135  file. The AP is reset to default settings and this is handled during the
136  test teardown.
137
138  Attributes:
139    ip: IP address to reach the AP.
140    port: Port numnber to reach the AP.
141    protocol: Protcol to reach the AP (http/https).
142    username: Username to login to the AP.
143    password: Password to login to the AP.
144    config_page: web url to login to the AP.
145    ap_settings: AP settings configured at any given point.
146    default_ap_settings: Default AP settings before running the tests.
147    driver: chrome webdriver object to update the settings.
148  """
149
150  def __init__(self, config):
151    """Initialize AP.
152
153    Creates a chrome webdriver object based on the router parameters.
154    The webdriver will login to the router and goes to the wireless settings
155    page. This object will be used to change the router settings required for
156    the test cases. Required parameters are <ip_address>, <port>, <protocol>,
157    <admin_username> and <admin_password>.
158
159    Url: <procotol>://<ip_address>:<port>/Main_Login.asp
160    Login: <admin_username>/<admin_password>
161
162    Args:
163      config: dict, dictionary of router parameters required for webdriver.
164    """
165    self.ip = config["ip_address"]
166    self.port = config["port"]
167    self.protocol = config["protocol"]
168    self.username = config["admin_username"]
169    self.password = config["admin_password"]
170    lambda_msg = lambda msg: "[AsusAXE11000AP|%s] %s" % (self.ip, msg)
171    self.log = logger.create_logger(lambda_msg)
172    self.ap_settings = {"2g": {}, "5g": {}, "6g": {},}
173    self.config_page = (
174        "{protocol}://{ip_address}:{port}/Main_Login.asp").format(
175            protocol=self.protocol, ip_address=self.ip, port=self.port)
176    self.chrome_options = Options()
177    self.chrome_options.add_argument("--headless")
178    self.chrome_options.add_argument("--no-sandbox")
179    self.driver = webdriver.Chrome(options=self.chrome_options)
180    self.driver.implicitly_wait(BROWSER_WAIT_TIMEOUT*2)
181    self.driver.get(self.config_page)
182    self.driver.find_element_by_name(USERNAME).send_keys(self.username)
183    self.driver.find_element_by_name(PASSWORD).send_keys(self.password)
184    self.driver.find_element_by_id(SIGN_IN_ID).click()
185    self._wait_for_web_element(self.driver.find_element_by_id,
186                               WIRELESS_SETTINGS)
187    self.driver.find_element_by_id(WIRELESS_SETTINGS).click()
188    self._wait_for_web_element(self.driver.find_element_by_id, SMART_CONNECT)
189    self._update_ap_settings()
190    self.default_ap_settings = self.ap_settings.copy()
191
192  ### Helper methods ###
193
194  def _wait_for_web_element(self,
195                            find_element,
196                            element,
197                            attribute=None,
198                            value=None):
199    """Verifies click actions/selections work.
200
201    Args:
202      find_element: func(), webdriver method to call
203      element: str, web element to look for. Ex: id, class, name
204      attribute: str, attribute to get from a webelement
205      value: str, verify attribute is set to the correct value
206
207    Raises:
208      ValueError: An error occurred if expected attribute not found.
209    """
210    curr_time = time.time()
211    while time.time() < curr_time + BROWSER_WAIT_TIMEOUT*4:
212      time.sleep(2)
213      try:
214        x = find_element(element)
215        if attribute and str(value) not in x.get_attribute(attribute):
216          raise ValueError("Attribute is not set to the right value")
217        return
218      except NoSuchElementException:
219        pass
220    raise ValueError("Failed to find web element: %s" % element)
221
222  def _update_ap_settings_2g_band(self):
223    """Read settings configured on 2g band.
224
225    Parameters Updated:
226      security type: open, wpa2-psk, wpa3-sae or wpa2-ent.
227      ssid: SSID of the wifi network.
228      password: password of the wifi network (if psk or sae network).
229      radius server ip: Radius server IP addr (if ent network).
230      radius server port: Radius server Port number (if ent network).
231      radius server secret: Radius server secret (if ent network).
232      channel: 2G band channel.
233    """
234    dict_2g = {}
235    dict_2g["security"] = self.driver.find_element_by_name(
236        BAND_2G_AUTH).get_attribute("value")
237    dict_2g["SSID"] = self.driver.find_element_by_name(
238        BAND_2G_SSID).get_attribute("value")
239    if dict_2g["security"] == "psk2" or dict_2g["security"] == "sae":
240      dict_2g["password"] = self.driver.find_element_by_name(
241          BAND_2G_PSK).get_attribute("value")
242    elif dict_2g["security"] == "wpa2":
243      dict_2g["radius_ip_addr"] = self.driver.find_element_by_name(
244          BAND_2G_RAD_IP).get_attribute("value")
245      dict_2g["radius_port"] = self.driver.find_element_by_name(
246          BAND_2G_RAD_PORT).get_attribute("value")
247      dict_2g["radius_secret"] = self.driver.find_element_by_name(
248          BAND_2G_RAD_KEY).get_attribute("value")
249    channel_field = self._get_webdriver_elements_for_channels(band)
250    ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
251        "value")
252    channel = 0
253    for key, val in CHANNELS_2G.items():
254      if val == ch_val:
255        channel = key
256        break
257    self.ap_settings["2g"] = dict_2g.copy()
258    self.ap_settings["2g"]["channel"] = channel
259
260  def _update_ap_settings_5g_band(self):
261    """Read settings configured on 5g band.
262
263    Parameters Updated:
264      security type: open, wpa2-psk, wpa3-sae or wpa2-ent.
265      ssid: SSID of the wifi network.
266      password: password of the wifi network (if psk or sae network).
267      radius server ip: Radius server IP addr (if ent network).
268      radius server port: Radius server Port number (if ent network).
269      radius server secret: Radius server secret (if ent network).
270      channel: 5G band channel.
271    """
272    dict_5g = {}
273    dict_5g["security"] = self.driver.find_element_by_name(
274        BAND_5G_AUTH).get_attribute("value")
275    dict_5g["SSID"] = self.driver.find_element_by_name(
276        BAND_5G_SSID).get_attribute("value")
277    if dict_5g["security"] == "psk2" or dict_5g["security"] == "sae":
278      dict_5g["password"] = self.driver.find_element_by_name(
279          BAND_5G_PSK).get_attribute("value")
280    elif dict_5g["security"] == "wpa2":
281      dict_5g["radius_ip_addr"] = self.driver.find_element_by_name(
282          BAND_5G_RAD_IP).get_attribute("value")
283      dict_5g["radius_port"] = self.driver.find_element_by_name(
284          BAND_5G_RAD_PORT).get_attribute("value")
285      dict_2g["radius_secret"] = self.driver.find_element_by_name(
286          BAND_5G_RAD_KEY).get_attribute("value")
287    channel_field = self._get_webdriver_elements_for_channels(band)
288    ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
289        "value")
290    channel = 0
291    for key, val in CHANNELS_5G.items():
292      if val == ch_val:
293        channel = key
294        break
295    self.ap_settings["5g"] = dict_5g.copy()
296    self.ap_settings["5g"]["channel"] = channel
297
298  def _update_ap_settings_6g_band(self):
299    """Read settings configured on 6g band.
300
301    Parameters Updated:
302      security type: wpa3-owe, wpa3-sae.
303      ssid: SSID of the wifi network.
304      password: password of the wifi network (if sae network).
305      channel: 6G band channel.
306    """
307    dict_6g = {}
308    dict_6g["security"] = self.driver.find_element_by_name(
309        BAND_6G_AUTH).get_attribute("value")
310    dict_6g["SSID"] = self.driver.find_element_by_name(
311        BAND_6G_SSID).get_attribute("value")
312    if dict_6g["security"] == "sae":
313      dict_6g["password"] = self.driver.find_element_by_name(
314          BAND_6G_PSK).get_attribute("value")
315    channel_field = self._get_webdriver_elements_for_channels(band)
316    ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
317        "value")
318    channel = 0
319    for key, val in CHANNELS_6G.items():
320      if val == ch_val:
321        channel = key
322        break
323    self.ap_settings["6g"] = dict_6g.copy()
324    self.ap_settings["6g"]["channel"] = channel
325
326  def _update_ap_settings(self):
327    """Read AP settings of 2G, 5G and 6G bands.
328
329    This method reads the wifi network currently configured on any particular
330    band. The settings are updated to self.ap_settings object.
331    """
332    self.driver.refresh()
333    self._update_ap_settings_2g_band()
334    self._update_ap_settings_5g_band()
335    self._update_ap_settings_6g_band()
336
337  def _get_webdriver_elements_for_channels(self, band):
338    """Return webdriver elements for the band to configure channel.
339
340    Args:
341      band: str, Wifi band to configure. Ex: 2g, 5g, 6g.
342
343    Returns:
344      channel field for the specific band.
345    """
346    channel_field = BAND_2G_CHANNEL
347    if band == "5g":
348      channel_field = BAND_5G_CHANNEL
349    elif band == "6g":
350      channel_field = BAND_6G_CHANNEL
351    return channel_field
352
353  def _set_channel(self, band, channel):
354    """Configure channel on a specific band.
355
356    Args:
357      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
358      channel: int, Channel to set.
359
360    Raises:
361      ValueError: An error occurred due to invalid band or configuration.
362    """
363    band = band.lower()
364    if band not in VALID_BANDS:
365      raise ValueError("Band %s is not valid" % band)
366    if (band == "2g" and channel not in CHANNELS_2G) or (
367        band == "5g" and
368        channel not in CHANNELS_5G) or (band == "6g" and
369                                        channel not in CHANNELS_6G):
370      raise ValueError("Channel %s is not supported in band %s" %
371                       (channel, band))
372    channel_field = self._get_webdriver_elements_for_channels(band)
373    channels_val_dict = CHANNELS_6G
374    if band == "2g":
375      channels_val_dict = CHANNELS_2G
376    elif band == "5g":
377      channels_val_dict = CHANNELS_5G
378    channel = channels_val_dict[channel]
379
380    # Set channel
381    if self.driver.find_element_by_name(channel_field).get_attribute(
382        "value") != channel:
383      css_selector = "select[name=%s]" % channel_field
384      Select(self.driver.find_element_by_css_selector(
385          css_selector)).select_by_value(channel)
386      time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
387
388  def _configure_personal_network(self, band, auth, ssid=None, password=None):
389    """Configure wpa3 sae/wpa2 psk network on a specific band.
390
391    Args:
392      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
393      auth: str, WPA2 PSK or WPA3 SAE security.
394      ssid: str, ssid of the wifi network.
395      password: str, password of the wifi network.
396
397    Raises:
398      ValueError: An error occurred due to invalid band or configuration.
399    """
400    band = band.lower()
401    if band not in VALID_BANDS:
402      raise ValueError("Band %s is not valid" % band)
403    if band == "6g" and auth == "psk2":
404      raise ValueError("AP doesn't support WPA2 PSK on 6g band.")
405    (auth_field, ssid_field,
406     psk_field) = self._get_webdriver_elements_for_personal_auth(band)
407
408    # configure personal network
409    css_selector = "select[name=%s]" % auth_field
410    Select(self.driver.find_element_by_css_selector(
411        css_selector)).select_by_value(auth)
412    time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
413    if ssid:
414      self.driver.find_element_by_name(ssid_field).clear()
415      self.driver.find_element_by_name(ssid_field).send_keys(ssid)
416    if password:
417      self.driver.find_element_by_name(psk_field).clear()
418      self.driver.find_element_by_name(psk_field).send_keys(password)
419
420  def _configure_open_owe_network(self, band, auth, ssid=None):
421    """Configure wpa3 owe/open network on a specific band.
422
423    Args:
424      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
425      auth: str, WPA2 PSK or WPA3 SAE security.
426      ssid: str, ssid of the wifi network.
427
428    Raises:
429      ValueError: An error occurred due to invalid band or configuration.
430    """
431    band = band.lower()
432    if band not in VALID_BANDS:
433      raise ValueError("Band %s is not valid" % band)
434    if band == "6g" and auth == "open":
435      raise ValueError("AP doesn't support open network on 6g band.")
436    if (band == "2g" or band == "5g") and auth == "owe":
437      raise ValueError("AP doesn't support OWE on 2g and 5g bands.")
438    (auth_field, ssid_field,
439     _) = self._get_webdriver_elements_for_personal_auth(band)
440
441    # Configure wifi network
442    css_selector = "select[name=%s]" % auth_field
443    Select(self.driver.find_element_by_css_selector(
444        css_selector)).select_by_value(auth)
445    time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
446    if ssid:
447      self.driver.find_element_by_name(ssid_field).clear()
448      self.driver.find_element_by_name(ssid_field).send_keys(ssid)
449
450  def _configure_wpa2_ent_network(self, band, radius_ip, radius_port,
451                                  radius_secret, ssid=None):
452    """Configure wpa2 ent network on a specific band.
453
454    Args:
455      band: str, Wifi band to check. Ex: 2g, 5g.
456      radius_ip: str, radius server ip addr.
457      radius_port: str, radius server port number.
458      radius_secret: str, radius server secret.
459      ssid: str, ssid of the wifi network.
460
461    Raises:
462      ValueError: An error occurred due to invalid band or configuration.
463    """
464    band = band.lower()
465    if band not in VALID_BANDS:
466      raise ValueError("Band %s is not valid" % band)
467    if band == "6g":
468      raise ValueError("6GHz doesn't support enterprise network on this AP.")
469    (auth_field, ssid_field,
470     _) = self._get_webdriver_elements_for_personal_auth(band)
471    (rad_ip_field, rad_port_field,
472     rad_key_field) = self._get_webdriver_elements_for_ent_auth(band)
473
474    # Set enterprise network
475    css_selector = "select[name=%s]" % auth_field
476    Select(self.driver.find_element_by_css_selector(
477        css_selector)).select_by_value("wpa2")
478    time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
479    if ssid:
480      self.driver.find_element_by_name(ssid_field).clear()
481      self.driver.find_element_by_name(ssid_field).send_keys(ssid)
482    self.driver.find_element_by_name(rad_ip_field).clear()
483    self.driver.find_element_by_name(rad_ip_field).send_keys(radius_ip)
484    self.driver.find_element_by_name(rad_port_field).clear()
485    self.driver.find_element_by_name(rad_port_field).send_keys(radius_port)
486    self.driver.find_element_by_name(rad_key_field).clear()
487    self.driver.find_element_by_name(rad_key_field).send_keys(radius_secret)
488
489  def _get_webdriver_elements_for_personal_auth(self, band):
490    """Return webdriver elements for the band to configure personal auth.
491
492    Args:
493      band: str, Wifi band to configure. Ex: 2g, 5g, 6g.
494
495    Returns:
496      tuple of auth, ssid, psk field for the band.
497    """
498    auth_field = BAND_2G_AUTH
499    ssid_field = BAND_2G_SSID
500    psk_field = BAND_2G_PSK
501    if band == "5g":
502      auth_field = BAND_5G_AUTH
503      ssid_field = BAND_5G_SSID
504      psk_field = BAND_5G_PSK
505    elif band == "6g":
506      auth_field = BAND_6G_AUTH
507      ssid_field = BAND_6G_SSID
508      psk_field = BAND_6G_PSK
509    return (auth_field, ssid_field, psk_field)
510
511  def _get_webdriver_elements_for_ent_auth(self, band):
512    """Return webdriver elements for the band to configure ent auth.
513
514    Args:
515      band: str, Wifi band to configure. Ex: 2g, 5g, 6g.
516
517    Returns:
518      tuple of radius server IP, port, secret for the band.
519    """
520    rad_ip_field = BAND_2G_RAD_IP
521    rad_port_field = BAND_2G_RAD_PORT
522    rad_key_field = BAND_2G_RAD_KEY
523    if band == "5g":
524      rad_ip_field = BAND_5G_RAD_IP
525      rad_port_field = BAND_5G_RAD_PORT
526      rad_key_field = BAND_5G_RAD_KEY
527    return (rad_ip_field, rad_port_field, rad_key_field)
528
529  ### Methods to configure AP ###
530
531  def set_channel_and_apply(self, band, channel):
532    """Set channel for specific band.
533
534    Args:
535      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
536      channel: int, Channel to set.
537    """
538    # Go back to General tab in advanced settings
539    self.driver.find_element_by_id(GENERAL_TAB).click()
540    self._wait_for_web_element(self.driver.find_element_by_id, SMART_CONNECT)
541
542    channel_field = self._get_webdriver_elements_for_channels(band)
543    self._set_channel(band, channel)
544    self.driver.find_element_by_id(APPLY_BUTTON_ID).click()
545    time.sleep(BROWSER_WAIT_LONG_TIMEOUT)
546    self._wait_for_web_element(self.driver.find_element_by_name,
547                               channel_field, "value", channel)
548    self._update_ap_settings()
549
550  def get_configured_channel(self, band):
551    """Get the channel configured on specific band.
552
553    Args:
554      band: str, Wifi band to check. Ex: eg, 5g, 6g.
555
556    Returns:
557      Channel configured on the band.
558
559    Raises:
560      ValueError: An error occurred due to invalid band.
561    """
562    band = band.lower()
563    if band not in VALID_BANDS:
564      raise ValueError("Band %s is not valid" % band)
565    return self.ap_settings[band]["channel"]
566
567  def configure_ap(self, network_dict):
568    """Configure AP with settings for different bands.
569
570    Args:
571      network_dict: dict, dictionary that holds configuration for each band.
572    """
573    # Go back to General tab in advanced settings
574    self.driver.refresh()
575    self.driver.find_element_by_id(GENERAL_TAB).click()
576    self._wait_for_web_element(self.driver.find_element_by_id, SMART_CONNECT)
577
578    # configure wireless settings
579    self.log.info("Network dictionary: %s" % network_dict)
580    for band in network_dict:
581      security = network_dict[band]["security"]
582      ssid = network_dict[band]["SSID"] if "SSID" in network_dict[
583          band] else None
584      password = network_dict[band]["password"] if "password" in network_dict[
585          band] else None
586      if security == "open" or security == "owe":
587        self._configure_open_owe_network(band, security, ssid)
588      elif security == "psk2" or security == "sae":
589        self._configure_personal_network(band, security, ssid, password)
590      elif network_dict[band]["security"] == "wpa2":
591        self._configure_wpa2_ent_network(
592            band,
593            network_dict[band]["radius_server_ip"],
594            network_dict[band]["radius_server_port"],
595            network_dict[band]["radius_server_secret"],
596            ssid)
597
598    for band in network_dict:
599      if "channel" in network_dict[band]:
600        self._set_channel(band, network_dict[band]["channel"])
601    self.driver.find_element_by_id(APPLY_BUTTON_ID).click()
602    time.sleep(BROWSER_WAIT_LONG_TIMEOUT)
603
604    # update ap settings
605    self._update_ap_settings()
606
607    # configure hidden or 11ax mode
608    for band in network_dict:
609      apply_settings = False
610      if "hidden" in network_dict[band]:
611        res = self._configure_hidden_network(band, network_dict[band]["hidden"])
612        apply_settings = apply_settings or res
613      if "11ax" in network_dict[band]:
614        res = self._configure_11ax_mode(band, network_dict[band]["11ax"])
615        apply_settings = apply_settings or res
616      if apply_settings:
617        self.driver.find_element_by_id(APPLY_BUTTON).click()
618        time.sleep(BROWSER_WAIT_VERY_LONG_TIMEOUT)
619
620  def get_wifi_network(self, band):
621    """Get wifi network configured on the AP for the specific band.
622
623    Args:
624      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
625
626    Returns:
627      Wifi network as a dictionary.
628
629    Raises:
630      ValueError: An error occurred due to invalid band.
631    """
632    band = band.lower()
633    if band not in VALID_BANDS:
634      raise ValueError("Band %s is not valid" % band)
635    wifi_network = {}
636    wifi_network["SSID"] = self.ap_settings[band]["SSID"]
637    if "password" in self.ap_settings[band]:
638      wifi_network["password"] = self.ap_settings[band]["password"]
639    security = self.ap_settings[band]["security"]
640    if security == "sae" or security == "owe":
641      wifi_network["security"] = security
642    return wifi_network
643
644  def _configure_hidden_network(self, band, val):
645    """Configure hidden network for a specific band.
646
647    Args:
648      band: str, Wifi band to configure hidden network.
649      val: str, String value to configure.
650
651    Returns:
652      True if settings applied, False if not.
653
654    Raises:
655      ValueError: An error occurred due to invalid band.
656    """
657    band = band.lower()
658    if band not in VALID_BANDS:
659      raise ValueError("Band %s is not valid" % band)
660
661    # Go to Professional tab in advanced settings
662    self.driver.find_element_by_id(PROFESSIONAL_TAB).click()
663    self._wait_for_web_element(self.driver.find_element_by_id, HE_MODE_ID)
664
665    # Select the requested band from the drop down menu
666    css_selector = "select[name=%s]" % WL_UNIT
667    Select(
668        self.driver.find_element_by_css_selector(css_selector)).select_by_value(
669            WL_BAND_VALUE[band])  # (TODO: gmoturu@) find if selection worked
670    time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
671
672    # Configure hidden network
673    state = True if val == "1" else False
674    return_result = False
675    if self.driver.find_element_by_name(WL_CLOSED).is_selected() != state:
676      css_selector = "input[name='%s'][value='%s']" % (WL_CLOSED, val)
677      self.driver.find_element_by_css_selector(css_selector).click()
678      time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
679      return_result = True
680
681    return return_result
682
683  def configure_hidden_network_and_apply(self, band, state=True):
684    """Configure hidden network for a specific band.
685
686    Args:
687      band: str, Wifi band to configure hidden network.
688      state: bool, Set the wifi network as hidden if True, False if not.
689    """
690    val = "1" if state else "0"
691    if self._configure_hidden_network(band, val):
692      self.driver.find_element_by_id(APPLY_BUTTON).click()
693      time.sleep(BROWSER_WAIT_VERY_LONG_TIMEOUT)
694      if self.driver.find_element_by_name(WL_CLOSED).is_selected() != state:
695        raise ValueError("Failed to configure hidden network on band: %s" % band)
696
697      # Go back to General tab in advanced settings
698      self.driver.find_element_by_id(GENERAL_TAB).click()
699      self._wait_for_web_element(self.driver.find_element_by_id, SMART_CONNECT)
700
701  def _configure_11ax_mode(self, band, val):
702    """Configure 11ax mode on a specific band.
703
704    Args:
705      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
706      val: str, String value to configure.
707
708    Returns:
709      True if settings are applied, False if not.
710
711    Raises:
712      ValueError: An error occurred due to invalid band.
713    """
714    band = band.lower()
715    if band not in VALID_BANDS:
716      raise ValueError("Band %s is not valid" % band)
717
718    # Go to Professional tab in advanced settings
719    self.driver.find_element_by_id(PROFESSIONAL_TAB).click()
720    self._wait_for_web_element(self.driver.find_element_by_id, HE_MODE_ID)
721
722    # Select the requested band from the drop down menu
723    css_selector = "select[name=%s]" % WL_UNIT
724    Select(
725        self.driver.find_element_by_css_selector(css_selector)).select_by_value(
726            WL_BAND_VALUE[band])  # (TODO: gmoturu@) find if selection worked
727    time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
728
729    # Configure 11ax
730    return_result = False
731    if self.driver.find_element_by_name(WL_11AX).get_attribute(
732        "value") != val:
733      css_selector = "select[name=%s]" % WL_11AX
734      Select(self.driver.find_element_by_css_selector(
735          css_selector)).select_by_value(val)
736      time.sleep(BROWSER_WAIT_SHORT_TIMEOUT)
737      return_result = True
738
739    return return_result
740
741  def configure_11ax_mode_and_apply(self, band, state=True):
742    """Configure 11ax mode on a specific band.
743
744    Args:
745      band: str, Wifi band to check. Ex: 2g, 5g, 6g.
746      state: bool, Enable 11ax if True, disable if False
747    """
748    val = "1" if state else "0"
749    if self._configure_11ax_mode(band, val):
750      self.driver.find_element_by_id(APPLY_BUTTON).click()
751      time.sleep(BROWSER_WAIT_VERY_LONG_TIMEOUT)
752      self._wait_for_web_element(self.driver.find_element_by_name, WL_11AX,
753                                 "value", val)
754
755      # Go back to General tab in advanced settings
756      self.driver.find_element_by_id(GENERAL_TAB).click()
757      self._wait_for_web_element(self.driver.find_element_by_id, SMART_CONNECT)
758
759  def reset_to_default_ap_settings(self):
760    """Reset AP to the default settings."""
761    if self.default_ap_settings != self.ap_settings:
762      self.configure_ap(self.default_ap_settings)
763
764