Repository: Vaskivskyi/asusrouter (language: python)

Issue:
"Enable block all devices" toggle
Hi,

Thank you for this wonderful library. I tried running the example script and enabling/disabling parental controls, and everything worked like a charm with my Asus-Merlin AXE-16000.

I am trying to toggle internet access to the whole network and there is a setting for it in parental controls, called 'Enable block all devices", however, I do not see any way of toggling it through this project. Is there a way this functionality can be supported?

![image](https://github.com/Vaskivskyi/asusrouter/assets/567867/a7135ea9-8a1d-47f9-a450-811bed1b15e3)



Discussion / hints:
Hello, yes, for sure. This feature can be added. Also, this should not take too much time to implement

For not the library contains something I was using or users of my Home Assistant integration asked for.

However, I am always open to implementing more features and making the library compatible with more devices.

P.S. Are you using Merlin 388.4?
Hi, I am running 388.1, and yeah, I tried `MULTIFILTER_BLOCK_ALL` instead of `MULTIFILTER_ALL` and it worked! Thank you again, this library really rocks, and now I am on  my way of implementing total blackout for my network based on a schedule. how nice. Just need to get my home assistant updated, as I see you only support latest versions.  

P.S. Enjoy some coffee ;) best of luck with this project. 
Thanks (:



Unfortunately, Home Assistant is implementing a bit too many changes from time to time. For now, I am not planning on moving further than 2023.10+ as it is currently so that at least several HA main releases will be supported

Fix patch:
diff --git a/asusrouter/modules/data_finder.py b/asusrouter/modules/data_finder.py
index 4e86275..200eafb 100644
--- a/asusrouter/modules/data_finder.py
+++ b/asusrouter/modules/data_finder.py
@@ -19,6 +19,7 @@
     MAP_WIREGUARD_SERVER,
 )
 from asusrouter.modules.parental_control import (
+    KEY_PARENTAL_CONTROL_BLOCK_ALL,
     KEY_PARENTAL_CONTROL_MAC,
     KEY_PARENTAL_CONTROL_NAME,
     KEY_PARENTAL_CONTROL_STATE,
@@ -110,6 +111,7 @@ def __init__(
         for key, _, _ in [converters.safe_unpack_keys(element)]
     ],
     "parental_control": [
+        KEY_PARENTAL_CONTROL_BLOCK_ALL,
         KEY_PARENTAL_CONTROL_MAC,
         KEY_PARENTAL_CONTROL_NAME,
         KEY_PARENTAL_CONTROL_STATE,
diff --git a/asusrouter/modules/endpoint/hook.py b/asusrouter/modules/endpoint/hook.py
index 1145cee..89e8851 100644
--- a/asusrouter/modules/endpoint/hook.py
+++ b/asusrouter/modules/endpoint/hook.py
@@ -12,11 +12,13 @@
 from asusrouter.modules.endpoint.error import AccessError
 from asusrouter.modules.led import AsusLED
 from asusrouter.modules.parental_control import (
+    KEY_PARENTAL_CONTROL_BLOCK_ALL,
     KEY_PARENTAL_CONTROL_MAC,
     KEY_PARENTAL_CONTROL_STATE,
     KEY_PARENTAL_CONTROL_TYPE,
     MAP_PARENTAL_CONTROL_ITEM,
     MAP_PARENTAL_CONTROL_TYPE,
+    AsusBlockAll,
     AsusParentalControl,
     ParentalControlRule,
 )
@@ -335,6 +337,11 @@ def process_parental_control(data: dict[str, Any]) -> dict[str, Any]:
         safe_int(data.get(KEY_PARENTAL_CONTROL_STATE), default=-999)
     )
 
+    # Block all
+    parental_control["block_all"] = AsusBlockAll(
+        safe_int(data.get(KEY_PARENTAL_CONTROL_BLOCK_ALL), default=-999)
+    )
+
     # Rules
     rules = {}
 
diff --git a/asusrouter/modules/parental_control.py b/asusrouter/modules/parental_control.py
index 67fa9f6..f2d8bbb 100644
--- a/asusrouter/modules/parental_control.py
+++ b/asusrouter/modules/parental_control.py
@@ -11,6 +11,7 @@
 
 _LOGGER = logging.getLogger(__name__)
 
+KEY_PARENTAL_CONTROL_BLOCK_ALL = "MULTIFILTER_BLOCK_ALL"
 KEY_PARENTAL_CONTROL_MAC = "MULTIFILTER_MAC"
 KEY_PARENTAL_CONTROL_NAME = "MULTIFILTER_DEVICENAME"
 KEY_PARENTAL_CONTROL_STATE = "MULTIFILTER_ALL"
@@ -51,21 +52,38 @@ class AsusParentalControl(IntEnum):
     ON = 1
 
 
+class AsusBlockAll(IntEnum):
+    """Asus block all state."""
+
+    UNKNOWN = -999
+    OFF = 0
+    ON = 1
+
+
 async def set_state(
     callback: Callable[..., Awaitable[bool]],
-    state: AsusParentalControl,
+    state: AsusParentalControl | AsusBlockAll,
     **kwargs: Any,
 ) -> bool:
     """Set the parental control state."""
 
     # Check if state is available and valid
-    if not isinstance(state, AsusParentalControl) or not state.value in (0, 1):
-        _LOGGER.debug("No state found in arguments")
+    if not isinstance(
+        state, (AsusParentalControl, AsusBlockAll)
+    ) or not state.value in (0, 1):
         return False
 
-    arguments = {
-        KEY_PARENTAL_CONTROL_STATE: 1 if state == AsusParentalControl.ON else 0
-    }
+    service_arguments = {}
+
+    match state:
+        case a if isinstance(a, AsusParentalControl):
+            service_arguments = {
+                KEY_PARENTAL_CONTROL_STATE: 1 if state == AsusParentalControl.ON else 0
+            }
+        case a if isinstance(a, AsusBlockAll):
+            service_arguments = {
+                KEY_PARENTAL_CONTROL_BLOCK_ALL: 1 if state == AsusBlockAll.ON else 0
+            }
 
     # Get the correct service call
     service = "restart_firewall"
@@ -73,7 +91,7 @@ async def set_state(
     # Call the service
     return await callback(
         service=service,
-        arguments=arguments,
+        arguments=service_arguments,
         apply=True,
         expect_modify=kwargs.get("expect_modify", False),
     )
diff --git a/asusrouter/modules/state.py b/asusrouter/modules/state.py
index f1881a5..3b6778f 100644
--- a/asusrouter/modules/state.py
+++ b/asusrouter/modules/state.py
@@ -10,7 +10,7 @@
 
 from asusrouter.modules.connection import ConnectionState
 from asusrouter.modules.data import AsusData, AsusDataState
-from asusrouter.modules.parental_control import AsusParentalControl
+from asusrouter.modules.parental_control import AsusBlockAll, AsusParentalControl
 from asusrouter.modules.port_forwarding import AsusPortForwarding
 from asusrouter.modules.system import AsusSystem
 from asusrouter.modules.vpnc import AsusVPNC
@@ -37,6 +37,7 @@ class AsusState(Enum):
     """Asus state."""
 
     NONE = AsusStateNone
+    BLOCK_ALL = AsusBlockAll
     CONNECTION = ConnectionState
     LED = AsusLED
     OPENVPN_CLIENT = AsusOVPNClient
@@ -52,6 +53,7 @@ class AsusState(Enum):
 
 AsusStateMap: dict[AsusState, Optional[AsusData]] = {
     AsusState.NONE: None,
+    AsusState.BLOCK_ALL: AsusData.PARENTAL_CONTROL,
     AsusState.CONNECTION: None,
     AsusState.LED: AsusData.LED,
     AsusState.OPENVPN_CLIENT: AsusData.OPENVPN_CLIENT,


Test patch:
diff --git a/tests/modules/test_parental_control.py b/tests/modules/test_parental_control.py
index c0474b8..7f79d67 100644
--- a/tests/modules/test_parental_control.py
+++ b/tests/modules/test_parental_control.py
@@ -5,7 +5,9 @@
 import pytest
 
 from asusrouter.modules.parental_control import (
+    KEY_PARENTAL_CONTROL_BLOCK_ALL,
     KEY_PARENTAL_CONTROL_STATE,
+    AsusBlockAll,
     AsusParentalControl,
     set_state,
 )
@@ -20,6 +22,8 @@
         # Correct states
         (AsusParentalControl.ON, True, True, {KEY_PARENTAL_CONTROL_STATE: 1}),
         (AsusParentalControl.OFF, False, True, {KEY_PARENTAL_CONTROL_STATE: 0}),
+        (AsusBlockAll.ON, True, True, {KEY_PARENTAL_CONTROL_BLOCK_ALL: 1}),
+        (AsusBlockAll.OFF, False, True, {KEY_PARENTAL_CONTROL_BLOCK_ALL: 0}),
         # Wrong states
         (AsusParentalControl.UNKNOWN, False, False, {}),
         (None, False, False, {}),
diff --git a/tests/test_data/rt_ax88u_merlin_388/hook_003.content b/tests/test_data/rt_ax88u_merlin_388/hook_003.content
index 8a56de4..536ce54 100644
--- a/tests/test_data/rt_ax88u_merlin_388/hook_003.content
+++ b/tests/test_data/rt_ax88u_merlin_388/hook_003.content
@@ -1,4 +1,5 @@
 {
+"MULTIFILTER_BLOCK_ALL":"0",
 "MULTIFILTER_MAC":"00:00:00:00:00:01&#6200:00:00:00:00:02&#6200:00:00:00:00:03&#6200:00:00:00:00:04&#6200:00:00:00:00:05&#6200:00:00:00:00:06&#6200:00:00:00:00:07&#6200:00:00:00:00:08",
 "MULTIFILTER_DEVICENAME":"FakeName001&#62FakeName002&#62FakeName003&#62FakeName004&#62FakeName005&#62FakeName006&#62FakeName007&#62FakeName008",
 "MULTIFILTER_ALL":"1",
diff --git a/tests/test_data/rt_ax88u_merlin_388/hook_003.py b/tests/test_data/rt_ax88u_merlin_388/hook_003.py
index 75105e4..8de2e7b 100644
--- a/tests/test_data/rt_ax88u_merlin_388/hook_003.py
+++ b/tests/test_data/rt_ax88u_merlin_388/hook_003.py
@@ -1,10 +1,15 @@
 """Result of processing hook_003.content."""
 
 from asusrouter import AsusData
-from asusrouter.modules.parental_control import AsusParentalControl, ParentalControlRule
+from asusrouter.modules.parental_control import (
+    AsusBlockAll,
+    AsusParentalControl,
+    ParentalControlRule,
+)
 
 expected_result = {
     AsusData.PARENTAL_CONTROL: {
+        "block_all": AsusBlockAll.OFF,
         "state": AsusParentalControl.ON,
         "rules": {
             "00:00:00:00:00:01": ParentalControlRule(