[Local Agent] Sync go/nest-cl/275332 and go/nest-cl/278096: Refactor
command handlers to align with GDM Matter capabilities.

Change-Id: I4df4705ef59328483f021ea8651948bb326ff538
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/__init__.py b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/__init__.py
new file mode 100644
index 0000000..6d6d126
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_door_lock.py b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_door_lock.py
new file mode 100644
index 0000000..8d25d43
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_door_lock.py
@@ -0,0 +1,90 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for DoorLock cluster handler."""
+from parameterized import parameterized
+from typing import Any
+import unittest
+from unittest import mock
+
+from gazoo_device import errors
+from gazoo_device.capabilities.matter_clusters import door_lock_pw_rpc
+
+from local_agent.translation_layer.command_handlers import base
+from local_agent.translation_layer.command_handlers.cluster_handlers import door_lock
+
+
+_FAKE_ERROR_MSG = 'fake-error-msg'
+LOCKED = door_lock_pw_rpc.LockState.LOCKED.value
+UNLOCKED = door_lock_pw_rpc.LockState.UNLOCKED.value
+
+
+class DummyHandler(base.BaseCommandHandler, door_lock.DoorLockHandler):
+    """Dummy handler for testing DoorLock cluster handler."""
+
+    def __init__(self, dut: Any) -> None:
+        super().__init__(dut)
+        self.endpoint = self.dut.door_lock
+
+
+class DoorLockHandlerTest(unittest.TestCase):
+    """Unit tests for DoorLock cluster handler."""
+
+    def setUp(self):
+        super().setUp()
+        self.mock_dut = mock.Mock()
+        self.handler = DummyHandler(self.mock_dut)
+
+    @parameterized.expand([(LOCKED, True), (UNLOCKED, False)])
+    def test_get_is_locked_on_success(self, locked_state, expected_ret):
+        """Verifies get_is_locked on success."""
+        self.handler.endpoint.door_lock.lock_state = locked_state
+
+        self.assertEqual(expected_ret, self.handler._get_is_locked({}))
+
+    def test_get_is_locked_on_failure(self):
+        """Verifies get_is_locked on failure."""
+        mock_state = mock.PropertyMock(
+            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
+        type(self.handler.endpoint.door_lock).lock_state = mock_state
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._get_is_locked({})
+
+    def test_set_lock_on_success(self):
+        """Verifies set_lock on success."""
+        self.handler._set_lock({})
+        self.handler.endpoint.door_lock.lock_door.assert_called_once()
+
+    def test_set_lock_on_failure(self):
+        """Verifies set_lock on failure."""
+        self.handler.endpoint.door_lock.lock_door.side_effect = (
+            errors.DeviceError(_FAKE_ERROR_MSG))
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._set_lock({})
+
+    def test_set_unlock_on_success(self):
+        """Verifies set_unlock on success."""
+        self.handler._set_unlock({})
+        self.handler.endpoint.door_lock.unlock_door.assert_called_once()
+
+    def test_set_unlock_on_failure(self):
+        """Verifies set_unlock on failure."""
+        self.handler.endpoint.door_lock.unlock_door.side_effect = (
+            errors.DeviceError(_FAKE_ERROR_MSG))
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._set_unlock({})
+
+
+if __name__ == '__main__':
+    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_level.py b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_level.py
new file mode 100644
index 0000000..0880701
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_level.py
@@ -0,0 +1,77 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for Level cluster handler."""
+from typing import Any
+import unittest
+from unittest import mock
+
+from gazoo_device import errors
+
+from local_agent.translation_layer.command_handlers import base
+from local_agent.translation_layer.command_handlers.cluster_handlers import level
+
+
+_FAKE_ERROR_MSG = 'fake-error-msg'
+_FAKE_LEVEL = 108
+
+
+
+class DummyHandler(base.BaseCommandHandler, level.LevelControlHandler):
+    """Dummy handler for testing Level Control cluster handler."""
+
+    def __init__(self, dut: Any) -> None:
+        super().__init__(dut)
+        self.endpoint = self.dut.on_off_light
+
+
+class LevelControlHandlerTest(unittest.TestCase):
+    """Unit tests for Level Control cluster handler."""
+
+    def setUp(self):
+        super().setUp()
+        self.mock_dut = mock.Mock()
+        self.handler = DummyHandler(self.mock_dut)
+
+    def test_get_level_on_success(self):
+        """Verifies the _get_level method on success."""
+        self.handler.endpoint.level.current_level = _FAKE_LEVEL
+        self.assertEqual(_FAKE_LEVEL, self.handler._get_level({}))
+
+    def test_get_level_on_failure(self):
+        """Verifies the _get_level method on failure."""
+        mock_current_level= mock.PropertyMock(
+            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
+        type(self.handler.endpoint.level).current_level = mock_current_level
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._get_level({})
+
+    @mock.patch.object(base.BaseCommandHandler, 'validate_key_in_params')
+    def test_set_level_on_success(self, mock_validate_key_in_params):
+        """Verifies the _set_level method on success."""
+        self.handler._set_level({'level': _FAKE_LEVEL})
+        self.handler.endpoint.level.move_to_level.assert_called_once_with(
+            level=_FAKE_LEVEL)
+
+    @mock.patch.object(base.BaseCommandHandler, 'validate_key_in_params')
+    def test_set_level_on_failure(self, mock_validate_key_in_params):
+        """Verifies the _set_level method on failure."""
+        self.handler.endpoint.level.move_to_level.side_effect = (
+            errors.DeviceError(_FAKE_ERROR_MSG))
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._set_level({'level': _FAKE_LEVEL})
+
+
+if __name__ == '__main__':
+    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_on_off.py b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_on_off.py
new file mode 100644
index 0000000..61d098d
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_cluster_handlers/test_on_off.py
@@ -0,0 +1,85 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for OnOff cluster handler."""
+from typing import Any
+import unittest
+from unittest import mock
+
+from gazoo_device import errors
+
+from local_agent.translation_layer.command_handlers import base
+from local_agent.translation_layer.command_handlers.cluster_handlers import on_off
+
+
+_FAKE_ERROR_MSG = 'fake-error-msg'
+
+
+
+class DummyHandler(base.BaseCommandHandler, on_off.OnOffHandler):
+    """Dummy handler for testing OnOff cluster handler."""
+
+    def __init__(self, dut: Any) -> None:
+        super().__init__(dut)
+        self.endpoint = self.dut.on_off_light
+
+
+class OnOffHandlerTest(unittest.TestCase):
+    """Unit tests for OnOff cluster handler."""
+
+    def setUp(self):
+        super().setUp()
+        self.mock_dut = mock.Mock()
+        self.handler = DummyHandler(self.mock_dut)
+
+    def test_get_on_off_on_success(self):
+        """Verifies the _get_on_off method on success."""
+        self.handler.endpoint.on_off.onoff = True
+        self.assertEqual(on_off.LIGHT_ON, self.handler._get_on_off({}))
+
+    def test_get_on_off_on_failure(self):
+        """Verifies the _get_on_off method on failure."""
+        mock_onoff= mock.PropertyMock(
+            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
+        type(self.handler.endpoint.on_off).onoff = mock_onoff
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._get_on_off({})        
+
+    def test_set_on_on_success(self):
+        """Verifies the _set_on method on success."""
+        self.handler._set_on({})
+        self.handler.endpoint.on_off.on.assert_called_once()        
+
+    def test_set_on_on_failure(self):
+        """Verifies the _set_on method on failure."""        
+        self.handler.endpoint.on_off.on.side_effect = (
+            errors.DeviceError(_FAKE_ERROR_MSG))
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._set_on({})
+
+    def test_set_off_on_success(self):
+        """Verifies the _set_off method on success."""
+        self.handler._set_off({})
+        self.handler.endpoint.on_off.off.assert_called_once()             
+
+    def test_set_off_on_failure(self):
+        """Verifies the _set_off method on failure."""
+        self.handler.endpoint.on_off.off.side_effect = (
+            errors.DeviceError(_FAKE_ERROR_MSG))
+        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
+            self.handler._set_off({})
+
+
+if __name__ == '__main__':
+    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_door_lock.py b/local_agent/tests/unit_tests/test_command_handlers/test_door_lock.py
new file mode 100644
index 0000000..900397c
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_door_lock.py
@@ -0,0 +1,36 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for DoorLock endpoint command handlers."""
+import unittest
+from unittest import mock
+
+from local_agent.translation_layer.command_handlers import door_lock
+
+
+class DoorLockCommandHandlerTest(unittest.TestCase):
+    """Unit tests for DoorLockCommandHandler."""
+
+    def setUp(self):
+        super().setUp()
+        self.mock_dut = mock.Mock()
+        self.handler = door_lock.DoorLockCommandHandler(self.mock_dut)
+
+    def test_endpoint_initialization(self):
+        """Verifies if endpoint instance is initialized successfully."""
+        self.assertEqual(self.mock_dut.door_lock, self.handler.endpoint)
+
+
+if __name__ == '__main__':
+    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_light.py b/local_agent/tests/unit_tests/test_command_handlers/test_light.py
deleted file mode 100644
index ee02fe8..0000000
--- a/local_agent/tests/unit_tests/test_command_handlers/test_light.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Unit tests for light command handlers."""
-from parameterized import parameterized
-import unittest
-from unittest import mock
-
-from gazoo_device import errors
-
-from local_agent.translation_layer.command_handlers import light
-
-
-_FAKE_BRIGHTNESS = 100
-_FAKE_HUE = 10
-_FAKE_SATURATION = 10
-_FAKE_ERROR_MSG = 'fake-error-msg'
-
-
-class LightCommandHandlerTest(unittest.TestCase):
-    """Unit tests for LightCommandHandler."""
-
-    def setUp(self):
-        super().setUp()
-        self.dut = mock.Mock()
-        self.handler = light.LightCommandHandler(self.dut)
-
-    @parameterized.expand([(True, 'on'), (False, 'off')])
-    def test_01_get_on_off_on_success(self, light_state, expected_state):
-        """Verifies get_on_off on success."""
-        self.dut.pw_rpc_light.state = light_state
-
-        state = self.handler._get_on_off({})
-
-        self.assertEqual(expected_state, state)
-
-    def test_01_get_on_off_on_failure(self):
-        """Verifies get_on_off on failure."""
-        mock_state = mock.PropertyMock(
-            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
-        type(self.dut.pw_rpc_light).state = mock_state
-        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
-            self.handler._get_on_off({})
-
-    def test_02_set_on_on_success(self):
-        """Verifies set_on on success."""
-        self.handler._set_on({})
-        self.dut.pw_rpc_light.on.assert_called_once()
-
-    def test_02_set_on_on_failure(self):
-        """Verifies set_on on failure."""
-        self.dut.pw_rpc_light.on.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_on({})
-
-    def test_03_set_off_on_success(self):
-        """Verifies set_off on success."""
-        self.handler._set_off({})
-        self.dut.pw_rpc_light.off.assert_called_once()
-
-    def test_03_set_off_on_failure(self):
-        """Verifies set_off on failure."""
-        self.dut.pw_rpc_light.off.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_off({})
-
-    def test_04_get_brightness_on_success(self):
-        """Verifies get_brightness on success."""
-        self.dut.pw_rpc_light.brightness = _FAKE_BRIGHTNESS
-
-        brightness = self.handler._get_brightness({})
-
-        self.assertEqual(_FAKE_BRIGHTNESS, brightness)
-
-    def test_04_get_brightness_on_failure(self):
-        """Verifies get_brightness on failure."""
-        mock_state = mock.PropertyMock(
-            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
-        type(self.dut.pw_rpc_light).brightness = mock_state
-        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
-            self.handler._get_brightness({})
-
-    @mock.patch.object(light.LightCommandHandler, 'validate_key_in_params')
-    def test_05_set_brightness_on_success(self, mock_validate_key_in_params):
-        """Verifies set_brightness on success."""
-        self.handler._set_brightness({'level': _FAKE_BRIGHTNESS})
-
-        mock_validate_key_in_params.assert_called_once()
-        self.dut.pw_rpc_light.on.assert_called_once_with(level=_FAKE_BRIGHTNESS)
-
-    @mock.patch.object(light.LightCommandHandler, 'validate_key_in_params')
-    def test_05_set_brightness_on_failure(self, mock_validate_key_in_params):
-        """Verifies set_brightness on failure."""
-        self.dut.pw_rpc_light.on.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_brightness({'level': _FAKE_BRIGHTNESS})
-
-    def test_06_get_color_on_success(self):
-        """Verifies get_color on success."""
-        self.dut.pw_rpc_light.color.hue = _FAKE_HUE
-        self.dut.pw_rpc_light.color.saturation = _FAKE_SATURATION
-        expected_response = {'hue': _FAKE_HUE, 'saturation': _FAKE_SATURATION}
-
-        color = self.handler._get_color({})
-
-        self.assertEqual(expected_response, color)
-
-    def test_06_get_color_on_failure(self):
-        """Verifies get_color on failure."""
-        mock_state = mock.PropertyMock(
-            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
-        type(self.dut.pw_rpc_light.color).hue = mock_state
-        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
-            self.handler._get_color({})
-
-    @mock.patch.object(light.LightCommandHandler, 'validate_key_in_params')
-    def test_07_set_color_on_success(self, mock_validate_key_in_params):
-        """Verifies set_color on success."""
-        params = {'hue': _FAKE_HUE, 'saturation': _FAKE_SATURATION}
-
-        self.handler._set_color(params)
-
-        self.assertEqual(2, mock_validate_key_in_params.call_count)
-        self.dut.pw_rpc_light.on.assert_called_once_with(
-            hue=_FAKE_HUE, saturation=_FAKE_SATURATION)
-
-    @mock.patch.object(light.LightCommandHandler, 'validate_key_in_params')
-    def test_07_set_color_on_failure(self, mock_validate_key_in_params):
-        """Verifies set_color on failure."""
-        params = {'hue': _FAKE_HUE, 'saturation': _FAKE_SATURATION}
-        self.dut.pw_rpc_light.on.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_color(params)
-
-
-if __name__ == '__main__':
-    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_lock.py b/local_agent/tests/unit_tests/test_command_handlers/test_lock.py
deleted file mode 100644
index 393e7a3..0000000
--- a/local_agent/tests/unit_tests/test_command_handlers/test_lock.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Unit tests for lock command handlers."""
-from parameterized import parameterized
-import unittest
-from unittest import mock
-
-from gazoo_device import errors
-
-from local_agent.translation_layer.command_handlers import lock
-
-
-_FAKE_ERROR_MSG = 'fake-error-msg'
-
-
-class LockCommandHandlerTest(unittest.TestCase):
-    """Unit tests for LockCommandHandler."""
-
-    def setUp(self):
-        super().setUp()
-        self.dut = mock.Mock()
-        self.handler = lock.LockCommandHandler(self.dut)
-
-    @parameterized.expand([(True,), (False,)])
-    def test_01_get_is_locked_on_success(self, locked_state):
-        """Verifies get_is_locked on success."""
-        self.dut.pw_rpc_lock.state = locked_state
-
-        is_locked = self.handler._get_is_locked({})
-
-        self.assertEqual(locked_state, is_locked)
-
-    def test_01_get_is_locked_on_failure(self):
-        """Verifies get_is_locked on failure."""
-        mock_state = mock.PropertyMock(
-            side_effect=errors.DeviceError(_FAKE_ERROR_MSG))
-        type(self.dut.pw_rpc_lock).state = mock_state
-        with self.assertRaisesRegex(errors.DeviceError, _FAKE_ERROR_MSG):
-            self.handler._get_is_locked({})
-
-    def test_02_set_lock_on_success(self):
-        """Verifies set_lock on success."""
-        self.handler._set_lock({})
-        self.dut.pw_rpc_lock.lock.assert_called_once()
-
-    def test_02_set_lock_on_failure(self):
-        """Verifies set_lock on failure."""
-        self.dut.pw_rpc_lock.lock.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_lock({})
-
-    def test_03_set_unlock_on_success(self):
-        """Verifies set_unlock on success."""
-        self.handler._set_unlock({})
-        self.dut.pw_rpc_lock.unlock.assert_called_once()
-
-    def test_03_set_unlock_on_failure(self):
-        """Verifies set_unlock on failure."""
-        self.dut.pw_rpc_lock.unlock.side_effect = errors.DeviceError('')
-        with self.assertRaises(errors.DeviceError):
-            self.handler._set_unlock({})
-
-
-if __name__ == '__main__':
-    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_command_handlers/test_on_off_light.py b/local_agent/tests/unit_tests/test_command_handlers/test_on_off_light.py
new file mode 100644
index 0000000..c6947fc
--- /dev/null
+++ b/local_agent/tests/unit_tests/test_command_handlers/test_on_off_light.py
@@ -0,0 +1,37 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Unit tests for OnOffLight endpoint command handler."""
+import unittest
+from unittest import mock
+
+from local_agent.translation_layer.command_handlers import on_off_light
+
+
+class OnOffLightCommandHandlerTest(unittest.TestCase):
+    """Unit tests for OnOffLightCommandHandler."""
+
+    def setUp(self):
+        super().setUp()
+        self.mock_dut = mock.Mock()
+        self.handler = on_off_light.OnOffLightCommandHandler(self.mock_dut)
+
+    def test_endpoint_initialization(self):
+        """Verifies if endpoint instance is initialized successfully."""
+        self.assertEqual(self.mock_dut.on_off_light, self.handler.endpoint)
+
+
+
+if __name__ == '__main__':
+    unittest.main(failfast=True)
diff --git a/local_agent/tests/unit_tests/test_translation_layer.py b/local_agent/tests/unit_tests/test_translation_layer.py
index 3113780..09e6b53 100644
--- a/local_agent/tests/unit_tests/test_translation_layer.py
+++ b/local_agent/tests/unit_tests/test_translation_layer.py
@@ -188,8 +188,7 @@
         self, mock_validate):
         """Verifies _update_handlers_cls_map creation on success."""
         fake_handler = mock.Mock(SUPPORTED_METHODS={_SET_ON,})
-        fake_capabilities_map = {
-            _FAKE_CAPABILITY: [fake_handler]}
+        fake_capabilities_map = {_FAKE_CAPABILITY: fake_handler}
         translation_layer.GDM_CAPABILITIES_TO_COMMAND_HANDLERS = (
             fake_capabilities_map)
         self.translator.update_handlers_cls_map(
diff --git a/local_agent/translation_layer/command_handlers/cluster_handlers/__init__.py b/local_agent/translation_layer/command_handlers/cluster_handlers/__init__.py
new file mode 100644
index 0000000..d46dbae
--- /dev/null
+++ b/local_agent/translation_layer/command_handlers/cluster_handlers/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/local_agent/translation_layer/command_handlers/lock.py b/local_agent/translation_layer/command_handlers/cluster_handlers/door_lock.py
similarity index 75%
rename from local_agent/translation_layer/command_handlers/lock.py
rename to local_agent/translation_layer/command_handlers/cluster_handlers/door_lock.py
index af1c707..f1d5033 100644
--- a/local_agent/translation_layer/command_handlers/lock.py
+++ b/local_agent/translation_layer/command_handlers/cluster_handlers/door_lock.py
@@ -1,4 +1,4 @@
-# Copyright 2021 Google LLC
+# Copyright 2022 Google LLC
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,25 +12,24 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for lock command handler."""
+"""Module for DoorLock cluster command handling."""
 from typing import Any, Dict
 
 from gazoo_device import errors
+from gazoo_device.capabilities.matter_clusters import door_lock_pw_rpc
 
 from local_agent import logger as logger_module
-from local_agent.translation_layer.command_handlers import base
 
 
 logger = logger_module.get_logger()
 
-PWRPC_LOCK_CAPABILITY = 'pw_rpc_lock'
+LOCKED = door_lock_pw_rpc.LockState.LOCKED.value
 
 
-class LockCommandHandler(base.BaseCommandHandler):
-    """Lock device command handler
+class DoorLockHandler:
+    """Mixin for Matter DoorLock cluster handler.
 
-    Smart Home LockUnlock Trait Schema:
-    https://developers.google.com/assistant/smarthome/traits/lockunlock
+    The mixin assumes self.dut and self.endpoint are set.
     """
 
     _GET_IS_LOCKED = 'getIsLocked'
@@ -39,17 +38,17 @@
     SUPPORTED_METHODS = {_GET_IS_LOCKED, _SET_LOCK, _SET_UNLOCK}
 
     def _get_is_locked(self, params: Dict[str, Any]) -> bool:
-        """Returns if the device is locked or not.
+        """Queries the LockState attribute of the device.
 
         Returns:
             True if the device is locked, false otherwise.
 
         Raises:
-            DeviceError: getting locked state fails.
+            DeviceError: getting LockState attribute fails.
         """
         del params  # not used
         try:
-            return self.dut.pw_rpc_lock.state
+            return self.endpoint.door_lock.lock_state == LOCKED
         except errors.DeviceError as exc:
             logger.exception(f'Getting locked state of {self.dut.name} failed.')
             raise exc
@@ -62,7 +61,7 @@
         """
         del params  # not used
         try:
-            self.dut.pw_rpc_lock.lock()
+            self.endpoint.door_lock.lock_door()
         except errors.DeviceError as exc:
             logger.exception(f'Locking {self.dut.name} failed.')
             raise exc
@@ -75,7 +74,7 @@
         """
         del params  # not used
         try:
-            self.dut.pw_rpc_lock.unlock()
+            self.endpoint.door_lock.unlock_door()
         except errors.DeviceError as exc:
             logger.exception(f'Unlocking {self.dut.name} failed.')
             raise exc
diff --git a/local_agent/translation_layer/command_handlers/cluster_handlers/level.py b/local_agent/translation_layer/command_handlers/cluster_handlers/level.py
new file mode 100644
index 0000000..fdcc28c
--- /dev/null
+++ b/local_agent/translation_layer/command_handlers/cluster_handlers/level.py
@@ -0,0 +1,66 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for Level Control cluster command handling."""
+from typing import Any, Dict
+
+from gazoo_device import errors
+
+from local_agent import logger as logger_module
+
+
+logger = logger_module.get_logger()
+
+
+class LevelControlHandler:
+    """Mixin for Matter Level Control cluster handler.
+
+    The mixin assumes self.dut and self.endpoint are set.
+    """
+
+    _GET_LEVEL = 'getLevel'
+    _SET_LEVEL = 'setLevel'
+
+    SUPPORTED_METHODS = {_GET_LEVEL, _SET_LEVEL}
+
+    def _get_level(self, params: Dict[str, Any]) -> str:
+        """Queries the CurrentLevel attribute on the device.
+
+        Returns:
+            The current level.
+
+        Raises:
+            DeviceError: getting CurrentLevel attribute fails.
+        """
+        del params  # not used
+        try:
+            return self.endpoint.level.current_level
+        except errors.DeviceError as exc:
+            logger.exception(
+                f'Getting CurrentLevel attribute of {self.dut.name} failed.')
+            raise exc
+
+    def _set_level(self, params: Dict[str, Any]) -> None:
+        """Set the CurrentLevel attribute on the device.
+
+        Raises:
+            DeviceError: setting CurrentLevel attribute fails.
+        """
+        self.validate_key_in_params(
+            params=params, param_key='level', expected_type=int)
+        try:
+            self.endpoint.level.move_to_level(level=params['level'])
+        except errors.DeviceError as exc:
+            logger.exception(f'Turning {self.dut.name} on failed.')
+            raise exc
diff --git a/local_agent/translation_layer/command_handlers/cluster_handlers/on_off.py b/local_agent/translation_layer/command_handlers/cluster_handlers/on_off.py
new file mode 100644
index 0000000..f2cbc35
--- /dev/null
+++ b/local_agent/translation_layer/command_handlers/cluster_handlers/on_off.py
@@ -0,0 +1,82 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for OnOff cluster command handling."""
+from typing import Any, Dict
+
+from gazoo_device import errors
+
+from local_agent import logger as logger_module
+
+
+logger = logger_module.get_logger()
+
+# OnOff Response States:
+LIGHT_ON = 'on'
+LIGHT_OFF = 'off'
+
+
+class OnOffHandler:
+    """Mixin for Matter OnOff cluster handler.
+
+    The mixin assumes self.dut and self.endpoint are set.
+    """
+
+    _GET_ONOFF = 'getOnOff'
+    _SET_ON = 'setOn'
+    _SET_OFF = 'setOff'
+
+    SUPPORTED_METHODS = {_GET_ONOFF, _SET_ON, _SET_OFF}
+
+    def _get_on_off(self, params: Dict[str, Any]) -> str:
+        """Queries the OnOff attribute of the device.
+
+        Returns:
+           'on' if the device is in on state, 'off' if it's in off state.
+
+        Raises:
+            DeviceError: getting light state fails.
+        """
+        del params  # not used
+        try:
+            return LIGHT_ON if self.endpoint.on_off.onoff else LIGHT_OFF
+        except errors.DeviceError as exc:
+            logger.exception(f'Getting OnOff attribute of {self.dut.name} failed.')
+            raise exc
+
+    def _set_on(self, params: Dict[str, Any]) -> None:
+        """Turns on the device.
+
+        Raises:
+            DeviceError: turning light on fails.
+        """
+        del params  # not used
+        try:
+            self.endpoint.on_off.on()
+        except errors.DeviceError as exc:
+            logger.exception(f'Turning {self.dut.name} on failed.')
+            raise exc
+
+    def _set_off(self, params: Dict[str, Any]) -> None:
+        """Turns off of the device.
+
+        Raises:
+            DeviceError: turning light off fails.
+        """
+        del params  # not used
+        try:
+            self.endpoint.on_off.off()
+        except errors.DeviceError as exc:
+            logger.exception(f'Turning {self.dut.name} off failed.')
+            raise exc
diff --git a/local_agent/translation_layer/command_handlers/door_lock.py b/local_agent/translation_layer/command_handlers/door_lock.py
new file mode 100644
index 0000000..7372d97
--- /dev/null
+++ b/local_agent/translation_layer/command_handlers/door_lock.py
@@ -0,0 +1,33 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for DoorLock endpoint command handler."""
+from typing import Any
+
+from local_agent.translation_layer.command_handlers import base
+from local_agent.translation_layer.command_handlers.cluster_handlers import door_lock
+
+
+ENDPOINT_CAPABILITY = 'door_lock'
+
+
+class DoorLockCommandHandler(
+    base.BaseCommandHandler, door_lock.DoorLockHandler):
+    """Command handler for DoorLock endpoint."""
+
+    SUPPORTED_METHODS = door_lock.DoorLockHandler.SUPPORTED_METHODS
+
+    def __init__(self, dut: Any) -> None:
+        super().__init__(dut)
+        self.endpoint = self.dut.door_lock
diff --git a/local_agent/translation_layer/command_handlers/handler_registry.py b/local_agent/translation_layer/command_handlers/handler_registry.py
index ef0cad0..e68da93 100644
--- a/local_agent/translation_layer/command_handlers/handler_registry.py
+++ b/local_agent/translation_layer/command_handlers/handler_registry.py
@@ -20,13 +20,15 @@
 import immutabledict
 
 from local_agent.translation_layer.command_handlers import common
-from local_agent.translation_layer.command_handlers import light
-from local_agent.translation_layer.command_handlers import lock
+from local_agent.translation_layer.command_handlers import on_off_light
+from local_agent.translation_layer.command_handlers import door_lock
 
 
-# GDM capability -> set of acceptable command handlers
+# GDM capability -> Matter endpoint command handlers
+# TODO(b/216406955): Make command handler mapping dynamic generated
 GDM_CAPABILITIES_TO_COMMAND_HANDLERS = immutabledict.immutabledict({
-    common.PWRPC_COMMON_CAPABILITY: {common.CommonCommandHandler,},
-    light.PWRPC_LIGHT_CAPABILITY: {light.LightCommandHandler,},
-    lock.PWRPC_LOCK_CAPABILITY: {lock.LockCommandHandler,}
+    common.PWRPC_COMMON_CAPABILITY: common.CommonCommandHandler,
+    on_off_light.ENDPOINT_CAPABILITY: on_off_light.OnOffLightCommandHandler,
+    door_lock.ENDPOINT_CAPABILITY: door_lock.DoorLockCommandHandler
+    # TODO(b/216407280) Add color temperature command handler.
 })
diff --git a/local_agent/translation_layer/command_handlers/light.py b/local_agent/translation_layer/command_handlers/light.py
deleted file mode 100644
index bc4a1a6..0000000
--- a/local_agent/translation_layer/command_handlers/light.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Module for light command handler."""
-from typing import Any, Dict
-
-from gazoo_device import errors
-
-from local_agent import logger as logger_module
-from local_agent.translation_layer.command_handlers import base
-
-
-logger = logger_module.get_logger()
-
-PWRPC_LIGHT_CAPABILITY = 'pw_rpc_light'
-
-# OnOff Response States:
-LIGHT_ON = 'on'
-LIGHT_OFF = 'off'
-
-
-class LightCommandHandler(base.BaseCommandHandler):
-    """Lighting device command handler
-
-    Smart Home OnOff Trait Schema:
-    https://developers.google.com/assistant/smarthome/traits/onoff
-    """
-
-    _GET_STATE = 'getOnOff'
-    _SET_STATE_ON = 'setOn'
-    _SET_STATE_OFF = 'setOff'
-    _GET_BRIGHTNESS = 'getBrightness'
-    _SET_BRIGHTNESS = 'setBrightness'
-    _GET_COLOR = 'getColor'
-    _SET_COLOR = 'setColor'
-
-    SUPPORTED_METHODS = {
-        _GET_STATE,
-        _SET_STATE_ON,
-        _SET_STATE_OFF,
-        _GET_BRIGHTNESS,
-        _SET_BRIGHTNESS,
-        _GET_COLOR,
-        _SET_COLOR}
-
-    def _get_on_off(self, params: Dict[str, Any]) -> str:
-        """Queries the light state of the device.
-
-        Returns:
-            The light state.
-
-        Raises:
-            DeviceError: getting light state fails.
-        """
-        del params  # not used
-        try:
-            return LIGHT_ON if self.dut.pw_rpc_light.state else LIGHT_OFF
-        except errors.DeviceError as exc:
-            logger.exception(f'Getting light state of {self.dut.name} failed.')
-            raise exc
-
-    def _set_on(self, params: Dict[str, Any]) -> None:
-        """Turns on the light of the device.
-
-        Raises:
-            DeviceError: turning light on fails.
-        """
-        del params  # not used
-        try:
-            self.dut.pw_rpc_light.on()
-        except errors.DeviceError as exc:
-            logger.exception(f'Turning {self.dut.name} on failed.')
-            raise exc
-
-    def _set_off(self, params: Dict[str, Any]) -> None:
-        """Turns off the light of the device.
-
-        Raises:
-            DeviceError: turning light off fails.
-        """
-        del params  # not used
-        try:
-            self.dut.pw_rpc_light.off()
-        except errors.DeviceError as exc:
-            logger.exception(f'Turning {self.dut.name} off failed.')
-            raise exc
-
-    def _get_brightness(self, params: Dict[str, Any]) -> int:
-        """Queries the current brightness level of the device.
-
-        Returns:
-            The current brightness level.
-
-        Raises:
-            DeviceError: getting light brightness fails.
-        """
-        del params  # not used
-        try:
-            return self.dut.pw_rpc_light.brightness
-        except errors.DeviceError as exc:
-            logger.exception(
-                f'Getting light brightness of {self.dut.name} failed.')
-            raise exc
-
-    def _set_brightness(self, params: Dict[str, Any]) -> None:
-        """Sets the current brightness level of the device.
-
-        Raises:
-            DeviceError: setting brightness level fails.
-        """
-        self.validate_key_in_params(
-            params=params, param_key='level', expected_type=int)
-
-        try:
-            self.dut.pw_rpc_light.on(level=params['level'])
-        except errors.DeviceError as exc:
-            logger.exception(
-                f'Setting light brightness of {self.dut.name} failed.')
-            raise exc
-
-    def _get_color(self, params: Dict[str, Any]) -> Dict[str, int]:
-        """Gets the current lighting color of the device.
-
-        Returns:
-            The current hue and saturation values in dict.
-
-        Raises:
-            DeviceError: getting color fails.
-        """
-        del params
-        try:
-            hue = self.dut.pw_rpc_light.color.hue
-            saturation = self.dut.pw_rpc_light.color.saturation
-        except errors.DeviceError as exc:
-            logger.exception(
-               f'Getting light color of {self.dut.name} failed.')
-            raise exc
-        return {'hue': hue, 'saturation': saturation}
-
-    def _set_color(self, params: Dict[str, Any]) -> None:
-        """Sets the lighting color to specific hue and saturation.
-
-        Raises:
-            DeviceError: setting color fails.
-        """
-        self.validate_key_in_params(
-            params=params, param_key='hue', expected_type=int)
-        self.validate_key_in_params(
-            params=params, param_key='saturation', expected_type=int)
-
-        try:
-            hue = params['hue']
-            saturation = params['saturation']
-            self.dut.pw_rpc_light.on(hue=hue, saturation=saturation)
-        except errors.DeviceError as exc:
-            logger.exception(
-               f'Setting light color of {self.dut.name} failed.')
-            raise exc
diff --git a/local_agent/translation_layer/command_handlers/on_off_light.py b/local_agent/translation_layer/command_handlers/on_off_light.py
new file mode 100644
index 0000000..d33c76c
--- /dev/null
+++ b/local_agent/translation_layer/command_handlers/on_off_light.py
@@ -0,0 +1,41 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for OnOffLight endpoint command handler."""
+from typing import Any, Dict
+
+from gazoo_device import errors
+
+from local_agent import logger as logger_module
+from local_agent.translation_layer.command_handlers import base
+from local_agent.translation_layer.command_handlers.cluster_handlers import level
+from local_agent.translation_layer.command_handlers.cluster_handlers import on_off
+
+
+logger = logger_module.get_logger()
+
+ENDPOINT_CAPABILITY = 'on_off_light'
+
+
+class OnOffLightCommandHandler(
+    base.BaseCommandHandler, level.LevelControlHandler, on_off.OnOffHandler):
+    """Command handler for OnOffLight endpoint."""
+
+    SUPPORTED_METHODS = (
+        level.LevelControlHandler.SUPPORTED_METHODS |
+        on_off.OnOffHandler.SUPPORTED_METHODS)
+
+    def __init__(self, dut: Any) -> None:
+        super().__init__(dut)
+        self.endpoint = self.dut.on_off_light
diff --git a/local_agent/translation_layer/gdm_manager.py b/local_agent/translation_layer/gdm_manager.py
index c047ecc..18fdbfa 100644
--- a/local_agent/translation_layer/gdm_manager.py
+++ b/local_agent/translation_layer/gdm_manager.py
@@ -21,7 +21,6 @@
 
 from local_agent import errors as agent_errors
 from local_agent import logger as logger_module
-from local_agent.translation_layer.command_handlers import light
 
 
 logger = logger_module.get_logger()
diff --git a/local_agent/translation_layer/translation_layer.py b/local_agent/translation_layer/translation_layer.py
index 04576fe..0bfc78c 100644
--- a/local_agent/translation_layer/translation_layer.py
+++ b/local_agent/translation_layer/translation_layer.py
@@ -163,8 +163,8 @@
 
         matched_handlers = set()
         for capability in capabilities:
-            for handler in GDM_CAPABILITIES_TO_COMMAND_HANDLERS.get(
-                capability, []):
+            handler = GDM_CAPABILITIES_TO_COMMAND_HANDLERS.get(capability)
+            if handler is not None:
                 matched_handlers.add(handler)
         matched_handlers = list(matched_handlers)