Skip to content
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

Bugfix/fix update guest network #32

Merged
merged 3 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
225 changes: 50 additions & 175 deletions compal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
from .models import (
BandSetting,
FilterAction,
GuestNetworkEnabling,
GuestNetworkProperties,
GuestNetworkSettings,
InterfaceGuestNetworkSettings,
NatMode,
PortForward,
Proto,
Expand Down Expand Up @@ -1037,198 +1038,72 @@ def __xml_value(interface, attr, coherce=True):
except (TypeError, ValueError):
return val

@staticmethod
def __band_guest_networks(xml, band):
"""
Get the wifi guest network settings for the given band (2g, 5g)
"""
assert band in (
"2g",
"5g",
)

all_interfaces = list()
interfaces = xml.iter("Interface" + ("" if band == "2g" else "5G"))
for interface in interfaces:

def guest_xv(attr, coherce=True):
"""
xml value for the given band
"""
try:
return WifiGuestNetworkSettings.__xml_value(
interface, f"{attr}{band.upper()}", coherce
)
except AttributeError:
return WifiGuestNetworkSettings.__xml_value(
interface, f"{attr}{band}", coherce
)

all_interfaces.append(
InterfaceGuestNetworkSettings(
radio=band,
enable=guest_xv("Enable"),
ssid=guest_xv("BSSID"),
guest_mac=guest_xv("GuestMac"),
hidden=guest_xv("HideNetwork"),
re_key=guest_xv("GroupRekeyInterval"),
security=guest_xv("SecurityMode"),
pre_shared_key=guest_xv("PreSharedKey"),
wpa_algorithm=guest_xv("WpaAlgorithm"),
)
)

return all_interfaces

@property
def wifi_guest_network_settings(self):
"""
Read the wifi guest network settings
Read the current wifi guest network settings for all wifi bands (2g and 5g).
"""
xml = self.wifi_guest_network_settings_xml
guest_networks_2g = WifiGuestNetworkSettings.__band_guest_networks(xml, "2g")
guest_networks_5g = WifiGuestNetworkSettings.__band_guest_networks(xml, "5g")

return GuestNetworkSettings(
guest_networks_2g,
guest_networks_5g,
)

@staticmethod
def __compare_wifi_settings(old_settings, new_settings, interface_index, changes):
"""
Compare two settings objects for changes and
return:
bln_changes: True if there were changes
changes: Python dict that contains the changes
"""

def iterate_changes(old_settings, new_settings, changes):
for attr, old_value in old_settings.__dict__.items():
if isinstance(old_value, BandSetting):
changes.update({attr: {}})
iterate_changes(
getattr(old_settings, attr),
getattr(new_settings, attr),
changes[attr],
)
else:
new_value = getattr(new_settings, attr)
if old_value != new_value:
changes.update({attr: f"{old_value} -> {new_value}"})
bln_changes[0] = True

changes = {}
bln_changes = [False]
iterate_changes(
old_settings.guest_networks_2g[interface_index],
new_settings.guest_networks_2g[interface_index],
changes,
)
iterate_changes(
old_settings.guest_networks_5g[interface_index],
new_settings.guest_networks_5g[interface_index],
changes,
)
return bln_changes[0], changes

def __check_router_status(self, new_guest_network_settings, interface_index, debug):
"""
Checks if (1) the new user settings were changed in the router (via checking
the getter fun:307 [WIRELESSGUESTNETWORK] in the router-xml-file), (2) prints out a
progress bar and (3) prints out if the process was successful.
"""
router_settings = None

progress = 0
# the compal modem returns 7 entries per band, the only used element is index 2
one_and_only_relevant_index = 2

def print_progress_bar(progress, total, postfix=""):
progress = total if progress > total else progress
per_progress = int(progress / total * 100)
postfix = f"[{postfix}]" if postfix != "" else ""
print(
f"\r|{'█' * progress}{'-' * (total - progress)}| {per_progress}%, {progress}sec\t{postfix}",
end="",
)
interfaces = {
"2g": list(xml.iter("Interface"))[one_and_only_relevant_index],
"5g": list(xml.iter("Interface5G"))[one_and_only_relevant_index],
}

total = 24
bln_changes = True
changes = ""
if debug:
print("\n--- WAITING FOR ROUTER TO UPDATE ---")
while progress < total and bln_changes is True:
time.sleep(3)
if debug:
print_progress_bar(progress, total, changes)
def guest_xv(band, attr, coherce=True):
"""
xml value for the given band
"""
try:
router_settings = self.wifi_guest_network_settings
bln_changes, changes = self.__compare_wifi_settings(
router_settings,
new_guest_network_settings,
interface_index,
changes,
return WifiGuestNetworkSettings.__xml_value(
interfaces[band], f"{attr}{band.upper()}", coherce
)
except Exception as e:
changes = str(e)
if debug:
if not bln_changes:
print("\n\n--- ROUTER SUCESSFULLY UPDATED ALL NEW WIFI SETTINGS! ---")
else:
print("\n\n--- CHANGES THAT DID NOT GET SET ---")
_, changes = self.__compare_wifi_settings(
router_settings, new_guest_network_settings, interface_index
except AttributeError:
return WifiGuestNetworkSettings.__xml_value(
interfaces[band], f"{attr}{band}", coherce
)
print(changes)
return bln_changes

def update_interface_guest_network_settings(
self, new_guest_network_settings, interface_index, debug=True
):
"""
Method for updating the wifi guest network settings. Uses fun:308.
"""
len_2g_list = len(new_guest_network_settings.guest_networks_2g)
len_5g_list = len(new_guest_network_settings.guest_networks_5g)
assert len_2g_list == len_5g_list
assert 0 <= interface_index < len_2g_list

def transform_interface(interface_settings):
out = []
out.extend(
[
("Interface", interface_index + 1),
("Enable", interface_settings.enable),
("Ssid", interface_settings.ssid),
("Hiden", interface_settings.hidden),
("Rekey", interface_settings.re_key),
("Security", interface_settings.security),
("PSkey", interface_settings.pre_shared_key),
("Wpaalg", interface_settings.wpa_algorithm),
]
)

# Prefix 'wl', Postfix the band
return [(f"wl{k}{interface_settings.radio}", v) for (k, v) in out]

out_s = [] # change
for item_2g, item_5g in zip(
transform_interface(
new_guest_network_settings.guest_networks_2g[interface_index]
return GuestNetworkSettings(
GuestNetworkEnabling(
guest_xv("2g", "Enable") == 1, guest_xv("2g", "GuestMac")
),
transform_interface(
new_guest_network_settings.guest_networks_5g[interface_index]
GuestNetworkEnabling(
guest_xv("5g", "Enable") == 1, guest_xv("5g", "GuestMac")
),
):
out_s.append(item_2g)
out_s.append(item_5g)
GuestNetworkProperties(
guest_xv("2g", "BSSID"),
guest_xv("2g", "HideNetwork"),
guest_xv("2g", "GroupRekeyInterval"),
guest_xv("2g", "SecurityMode"),
guest_xv("2g", "PreSharedKey"),
guest_xv("2g", "WpaAlgorithm"),
),
)

out_settings = OrderedDict(out_s)
def update_wifi_guest_network_settings(self, properties, enable):
"""
Method for updating the wifi guest network settings. Uses fun:308.
The given properties are applied to all wifi bands (2g and 5g).
The enabling has only effect on wifi bands that are currently switched on.
Requires at least firmware CH7465LG-NCIP-6.15.30-1p3-1-NOSH.
"""
out_settings = OrderedDict(
[
("wlEnable", 1 if enable else 2),
("wlSsid", properties.ssid),
("wlHiden", properties.hidden),
("wlRekey", properties.re_key),
("wlSecurity", properties.security),
("wlPSkey", properties.pre_shared_key),
("wlWpaalg", properties.wpa_algorithm),
]
)
self.modem.xml_setter(
SetFunction.WIFI_GUEST_NETWORK_CONFIGURATION, out_settings
)
return self.__check_router_status(
new_guest_network_settings, interface_index, debug
)


class DHCPSettings:
Expand Down
18 changes: 10 additions & 8 deletions compal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ class RadioSettings:


@dataclass
class InterfaceGuestNetworkSettings:
# read-only fields
radio: str
guest_mac: str
# editable-fields
enable: Optional[int] = None
class GuestNetworkEnabling:
enabled: Optional[bool] = None
guest_mac: Optional[str] = None


@dataclass
class GuestNetworkProperties:
ssid: Optional[str] = None
hidden: Optional[int] = None
re_key: Optional[int] = None
Expand All @@ -60,8 +61,9 @@ class InterfaceGuestNetworkSettings:

@dataclass
class GuestNetworkSettings:
guest_networks_2g: List[InterfaceGuestNetworkSettings] = None
guest_networks_5g: List[InterfaceGuestNetworkSettings] = None
enabling_2g: GuestNetworkEnabling
enabling_5g: GuestNetworkEnabling
properties: GuestNetworkProperties


class FilterAction(Enum):
Expand Down
17 changes: 7 additions & 10 deletions examples/guest_fun.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,15 @@ def modem_setup(host, passwd):
guest = WifiGuestNetworkSettings(modem)
settings = guest.wifi_guest_network_settings

# Change enabling state of the 3rd (index 2) 2g-interface (the one also editable via the UI)
interface_index = 2
old_enabling_state = settings.guest_networks_2g[interface_index].enable
pprint.pprint('Current GUEST-NETWORK state: ' + ('ON' if old_enabling_state == 1 else 'OFF'))
old_enabling_state = settings.enabling_2g.enabled
pprint.pprint('Current GUEST-NETWORK state: ' + ('ON' if old_enabling_state else 'OFF'))

settings.guest_networks_2g[interface_index].enable = 1 if old_enabling_state == 2 else 2
guest.update_interface_guest_network_settings(settings, interface_index)
guest.update_wifi_guest_network_settings(settings.properties, not old_enabling_state)

new_enabling_state = guest.wifi_guest_network_settings.guest_networks_2g[interface_index].enable
pprint.pprint('New GUEST-NETWORK state: ' + ('ON' if new_enabling_state == 1 else 'OFF'))

pprint.pprint(guest.wifi_guest_network_settings)
settings = guest.wifi_guest_network_settings
new_enabling_state = settings.enabling_2g.enabled
pprint.pprint('New GUEST-NETWORK state: ' + ('ON' if new_enabling_state else 'OFF'))
pprint.pprint(settings)

modem.logout()

Expand Down