diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py
index b19d31967b..530ad02de4 100644
--- a/lib/logitech_receiver/hidpp20.py
+++ b/lib/logitech_receiver/hidpp20.py
@@ -1384,6 +1384,79 @@ def show(self):
 #
 
 
+class ExtendedDpi:
+    """Information about the DPI possibilities from EXTENDED_ADJUSTABLE_DPI feature"""
+
+    def __init__(self, device):
+        self._device = device
+        self.has_y = False
+        reply = device.feature_request(FEATURE.EXTENDED_ADJUSTABLE_DPI.feature, 0x10, 0x00)
+        self.levels = reply[1]
+        self.has_y = bool(reply[2] & 0x01)
+        self.has_lod = bool(reply[2] & 0x02)
+        self.has_profile = bool(reply[2] & 0x08)
+        dpilist_x = self.produce_dpi_list(FEATURE.EXTENDED_ADJUSTABLE_DPI, 0x20, device, 0)
+        dpilist_y = self.produce_dpi_list(FEATURE.EXTENDED_ADJUSTABLE_DPI, 0x20, device, 1) if self.has_y else []
+        print("DPY LIST X", dpilist_x)
+        print("DPY LIST Y", dpilist_y)
+        self.read()
+
+    @staticmethod
+    def produce_dpi_list(feature, function, device, direction):
+        reply = device.feature_request(feature, function, 0x00, direction, 0x00)
+        assert reply, "Oops, DPI list cannot be retrieved!"
+        dpi_bytes = reply[3:]
+        i = 1
+        while dpi_bytes[-2:] != b"\x00\x00":
+            reply = device.feature_request(feature, function, 0x00, direction, i)
+            assert reply, "Oops, DPI list cannot be retrieved!"
+            dpi_bytes += reply[3:]
+            i += 1
+        dpi_list = []
+        i = 0
+        while i < len(dpi_bytes):
+            val = _bytes2int(dpi_bytes[i : i + 2])
+            if val == 0:
+                break
+            if val >> 13 == 0b111:
+                step = val & 0x1FFF
+                last = _bytes2int(dpi_bytes[i + 2 : i + 4])
+                assert len(dpi_list) > 0 and last > dpi_list[-1], f"Invalid DPI list item: {val!r}"
+                dpi_list += range(dpi_list[-1] + step, last + 1, step)
+                i += 4
+            else:
+                dpi_list.append(val)
+                i += 2
+        return dpi_list
+
+    def read_list(self, reply, size):
+        list = []
+        for i in range(0, self.levels * size + 1, size):
+            if reply[i : i + 1] != b"\x00\x00":
+                list.append(_bytes2int(reply[i : i + size]))
+        return list
+
+    def read(self):
+        reply = self._device.feature_request(self.feature, 0x50, 0x00)
+        self.x = _bytes2int(reply[1:3])
+        self.y = _bytes2int(reply[5:7])
+        self.lod = reply[9]
+        self.default_x = _bytes2int(reply[3:5])
+        self.default_y = _bytes2int(reply[7:9])
+        self.x_list = self.read_list(self._device.feature_request(self.feature, 0x30, 0x00, 0)[2:], 2)
+        self.y_list = self.read_list(self._device.feature_request(self.feature, 0x30, 0x00, 1)[2:], 2)
+        self.lod_list = self.read_list(self._device.feature_request(self.feature, 0x40, 0x00)[1:], 1)
+
+    def set(self, x, y, lod):
+        self.x = x
+        self.y = y
+        self.lod = lod
+
+    def write_current(self):
+        data_bytes = _int2bytes(self.x, 2) + _int2bytes(self.y, 2) + _int2bytes(self.lod, 1)
+        return self._device.feature_request(self.feature, 0x60, 0x00, data_bytes)
+
+
 def feature_request(device, feature, function=0x00, *params, no_reply=False):
     if device.online and device.features:
         if feature in device.features:
diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py
index 540e36c663..ea18721197 100644
--- a/lib/logitech_receiver/settings_templates.py
+++ b/lib/logitech_receiver/settings_templates.py
@@ -950,71 +950,48 @@ def build(cls, setting_class, device):
             return validator
 
 
-class AdjustableDpi(_Setting):
-    """Pointer Speed feature"""
+def produce_dpi_list(feature, function, ignore, device, direction):
+    dpi_bytes = b""
+    for i in range(0, 0x100):  # there will be only a very few iterations performed
+        reply = device.feature_request(feature, function, 0x00, direction, i)
+        assert reply, "Oops, DPI list cannot be retrieved!"
+        dpi_bytes += reply[ignore:]
+        if dpi_bytes[-2:] == b"\x00\x00":
+            break
+    dpi_list = []
+    i = 0
+    while i < len(dpi_bytes):
+        val = _bytes2int(dpi_bytes[i : i + 2])
+        if val == 0:
+            break
+        if val >> 13 == 0b111:
+            step = val & 0x1FFF
+            last = _bytes2int(dpi_bytes[i + 2 : i + 4])
+            assert len(dpi_list) > 0 and last > dpi_list[-1], f"Invalid DPI list item: {val!r}"
+            dpi_list += range(dpi_list[-1] + step, last + 1, step)
+            i += 4
+        else:
+            dpi_list.append(val)
+            i += 2
+    return dpi_list
+
 
-    # Assume sensorIdx 0 (there is only one sensor)
+class AdjustableDpi(_Setting):
     name = "dpi"
     label = _("Sensitivity (DPI)")
     description = _("Mouse movement sensitivity")
     feature = _F.ADJUSTABLE_DPI
     rw_options = {"read_fnid": 0x20, "write_fnid": 0x30}
     choices_universe = _NamedInts.range(100, 4000, str, 50)
-    sensor_list_function = 0x10
-    sensor_list_bytes_ignore = 1
 
     class validator_class(_ChoicesV):
-        @staticmethod
-        def produce_dpi_list(setting_class, device, direction):
-            reply = device.feature_request(setting_class.feature, setting_class.sensor_list_function, 0x00, direction, 0x00)
-            assert reply, "Oops, DPI list cannot be retrieved!"
-            dpi_bytes = reply[setting_class.sensor_list_bytes_ignore :]
-            i = 1
-            while dpi_bytes[-2:] != b"\x00\x00":
-                reply = device.feature_request(setting_class.feature, setting_class.sensor_list_function, 0x00, direction, i)
-                assert reply, "Oops, DPI list cannot be retrieved!"
-                dpi_bytes += reply[setting_class.sensor_list_bytes_ignore :]
-                i += 1
-            dpi_list = []
-            i = 0
-            while i < len(dpi_bytes):
-                val = _bytes2int(dpi_bytes[i : i + 2])
-                if val == 0:
-                    break
-                if val >> 13 == 0b111:
-                    step = val & 0x1FFF
-                    last = _bytes2int(dpi_bytes[i + 2 : i + 4])
-                    assert len(dpi_list) > 0 and last > dpi_list[-1], f"Invalid DPI list item: {val!r}"
-                    dpi_list += range(dpi_list[-1] + step, last + 1, step)
-                    i += 4
-                else:
-                    dpi_list.append(val)
-                    i += 2
-            return dpi_list
-
         @classmethod
         def build(cls, setting_class, device):
-            y = False
-            if setting_class.feature == _F.EXTENDED_ADJUSTABLE_DPI:
-                reply = device.feature_request(setting_class.feature, 0x10, 0x00)
-                y = reply[2] & 0x01
-            reply = device.feature_request(setting_class.feature, setting_class.sensor_list_function, 0x00, 0x00, 0x00)
-            assert reply, "Oops, DPI list cannot be retrieved!"
-            dpilist_x = cls.produce_dpi_list(setting_class, device, 0)
-            dpilist_y = cls.produce_dpi_list(setting_class, device, 1) if y else []
-            print("DPY LIST X", dpilist_x)
-            print("DPY LIST Y", dpilist_y)
-            setting = cls(choices=_NamedInts.list(dpilist_x), byte_count=2, write_prefix_bytes=b"\x00") if dpilist_x else None
-            setting.y = y
+            dpilist = produce_dpi_list(setting_class.feature, 0x10, 1, device, 0)
+            setting = cls(choices=_NamedInts.list(dpilist), byte_count=2, write_prefix_bytes=b"\x00") if dpilist else None
+            setting.dpilist = dpilist
             return setting
 
-        def prepare_write(self, new_value, current_value=None):
-            data_bytes = super().prepare_write(new_value, current_value)
-            if self.y:
-                bytes = data_bytes[len(self._write_prefix_bytes) :]
-                data_bytes = self._write_prefix_bytes + bytes + bytes
-            return data_bytes
-
         def validate_read(self, reply_bytes):  # special validator to use default DPI if needed
             reply_value = _bytes2int(reply_bytes[1:3])
             if reply_value == 0:  # use default value instead
@@ -1024,14 +1001,78 @@ def validate_read(self, reply_bytes):  # special validator to use default DPI if
             return valid_value
 
 
-class ExtendedAdjustableDpi(AdjustableDpi):
-    # the extended version allows for two dimensions, longer dpi descriptions
-    # still assume only one sensor (and X only?)
+class ExtendedAdjustableDpi(_Setting):
+    # the extended version allows for two dimensions, longer dpi descriptions, but still assume only one sensor
     name = "dpi_extended"
     feature = _F.EXTENDED_ADJUSTABLE_DPI
     rw_options = {"read_fnid": 0x50, "write_fnid": 0x60}
-    sensor_list_function = 0x20
-    sensor_list_bytes_ignore = 3
+    keys_universe = _NamedInts(X=0, Y=1, LOD=2)
+    choices_universe = _NamedInts.range(100, 4000, str, 50)
+    choices_universe[0] = "LOW"
+    choices_universe[1] = "MEDIUM"
+    choices_universe[2] = "HIGH"
+    keys = _NamedInts(X=0, Y=1, LOD=2)
+
+    def write_key_value(self, key, value, save=True):
+        if isinstance(self._value, dict):
+            self._value[key] = value
+        else:
+            self._value = {key: value}
+        result = self.write(self._value, save)
+        return result[key] if isinstance(result, dict) else result
+
+    class validator_class(_ChoicesMapV):
+        @classmethod
+        def build(cls, setting_class, device):
+            reply = device.feature_request(setting_class.feature, 0x10, 0x00)
+            y = bool(reply[2] & 0x01)
+            lod = bool(reply[2] & 0x02)
+            choices_map = {}
+            dpilist_x = produce_dpi_list(setting_class.feature, 0x20, 3, device, 0)
+            choices_map[setting_class.keys["X"]] = _NamedInts.list(dpilist_x)
+            if y:
+                dpilist_y = produce_dpi_list(setting_class.feature, 0x20, 3, device, 1)
+                choices_map[setting_class.keys["Y"]] = _NamedInts.list(dpilist_y)
+            if lod:
+                choices_map[setting_class.keys["LOD"]] = _NamedInts(LOW=0, MEDIUM=1, HIGH=2)
+            validator = cls(choices_map=choices_map, byte_count=2, write_prefix_bytes=b"\x00")
+            validator.y = y
+            validator.lod = lod
+            validator.keys = setting_class.keys
+            return validator
+
+        def validate_read(self, reply_bytes):  # special validator to read entire setting
+            dpi_x = _bytes2int(reply_bytes[3:5]) if reply_bytes[1:3] == 0 else _bytes2int(reply_bytes[1:3])
+            assert dpi_x in self.choices[0], f"{self.__class__.__name__}: failed to validate dpi_x value {dpi_x:04X}"
+            value = {self.keys["X"]: dpi_x}
+            if self.y:
+                dpi_y = _bytes2int(reply_bytes[7:9]) if reply_bytes[5:7] == 0 else _bytes2int(reply_bytes[5:7])
+                assert dpi_y in self.choices[1], f"{self.__class__.__name__}: failed to validate dpi_y value {dpi_y:04X}"
+                value[self.keys["Y"]] = dpi_y
+            if self.lod:
+                lod = reply_bytes[9]
+                assert lod in self.choices[2], f"{self.__class__.__name__}: failed to validate lod value {lod:02X}"
+                value[self.keys["LOD"]] = lod
+            return value
+
+        def prepare_write(self, new_value, current_value=None):  # special preparer to write entire setting
+            data_bytes = self._write_prefix_bytes
+            if new_value[self.keys["X"]] not in self.choices[self.keys["X"]]:
+                raise ValueError(f"invalid value {new_value!r}")
+            data_bytes += _int2bytes(new_value[0], 2)
+            if self.y:
+                if new_value[self.keys["Y"]] not in self.choices[self.keys["Y"]]:
+                    raise ValueError(f"invalid value {new_value!r}")
+                data_bytes += _int2bytes(new_value[self.keys["Y"]], 2)
+            else:
+                data_bytes += b"\x00\x00"
+            if self.lod:
+                if new_value[self.keys["LOD"]] not in self.choices[self.keys["LOD"]]:
+                    raise ValueError(f"invalid value {new_value!r}")
+                data_bytes += _int2bytes(new_value[self.keys["LOD"]], 1)
+            else:
+                data_bytes += b"\x00"
+            return data_bytes
 
 
 class SpeedChange(_Setting):
diff --git a/tests/logitech_receiver/test_setting_templates.py b/tests/logitech_receiver/test_setting_templates.py
index ff9f447e66..d57c175d83 100644
--- a/tests/logitech_receiver/test_setting_templates.py
+++ b/tests/logitech_receiver/test_setting_templates.py
@@ -459,42 +459,45 @@ def mock_gethostname(mocker):
         hidpp.Response("01", 0x0C20),
         hidpp.Response("05", 0x0C30, "05"),
     ],
-    #    [
-    #        FeatureTest(settings_templates.AdjustableDpi, 800, 400, 0x30, "000190"),
-    #        common.NamedInts.list([400, 800, 1600]),
-    #        hidpp.Response("040003", 0x0000, "2201"),  # ADJUSTABLE_DPI
-    #        hidpp.Response("000190032006400000", 0x0410, "000000"),
-    #        hidpp.Response("000320", 0x0420),
-    #        hidpp.Response("000190", 0x0430, "000190"),
-    #    ],
-    #    [
-    #        FeatureTest(settings_templates.AdjustableDpi, 256, 512, 0x30, "000200"),
-    #        common.NamedInts.list([256, 512]),
-    #        hidpp.Response("040003", 0x0000, "2201"),  # ADJUSTABLE_DPI
-    #        hidpp.Response("000100e10002000000", 0x0410, "000000"),
-    #        hidpp.Response("000100", 0x0420),
-    #        hidpp.Response("000200", 0x0430, "000200"),
-    #    ],
-    #    [
-    #        FeatureTest(settings_templates.ExtendedAdjustableDpi, 256, 512, 0x60, "000200"),
-    #        common.NamedInts.list([256, 512]),
-    #        hidpp.Response("090000", 0x0000, "2202"),  # EXTENDED_ADJUSTABLE_DPI
-    #        hidpp.Response("000000", 0x0910, "00"),  # no y direction
-    #        hidpp.Response("0000000100e10002000000", 0x0920, "000000"),
-    #        hidpp.Response("000100", 0x0950),
-    #        hidpp.Response("000200", 0x0960, "000200"),
-    #    ],
-    #    [
-    #        FeatureTest(settings_templates.ExtendedAdjustableDpi, 0x64, 0x164, 0x60, "0001640164"),
-    #        common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),
-    #        hidpp.Response("090000", 0x0000, "2202"),  # EXTENDED_ADJUSTABLE_DPI
-    #        hidpp.Response("000001", 0x0910, "00"),  # supports y direction
-    #        hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"),
-    #        hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"),
-    #        hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"),
-    #        hidpp.Response("000064", 0x0950),
-    #        hidpp.Response("0001640164", 0x0960, "0001640164"),
-    #    ],
+    [
+        FeatureTest(settings_templates.AdjustableDpi, 800, 400, 0x30, "000190"),
+        common.NamedInts.list([400, 800, 1600]),
+        hidpp.Response("040003", 0x0000, "2201"),  # ADJUSTABLE_DPI
+        hidpp.Response("000190032006400000", 0x0410, "000000"),
+        hidpp.Response("000320", 0x0420),
+        hidpp.Response("000190", 0x0430, "000190"),
+    ],
+    [
+        FeatureTest(settings_templates.AdjustableDpi, 256, 512, 0x30, "000200"),
+        common.NamedInts.list([256, 512]),
+        hidpp.Response("040003", 0x0000, "2201"),  # ADJUSTABLE_DPI
+        hidpp.Response("000100e10002000000", 0x0410, "000000"),
+        hidpp.Response("000100", 0x0420),
+        hidpp.Response("000200", 0x0430, "000200"),
+    ],
+    [
+        FeatureTest(settings_templates.ExtendedAdjustableDpi, 256, 512, 0x60, "000200"),
+        common.NamedInts.list([256, 512]),
+        hidpp.Response("090000", 0x0000, "2202"),  # EXTENDED_ADJUSTABLE_DPI
+        hidpp.Response("000000", 0x0910, "00"),  # no y direction
+        hidpp.Response("0000000100e10002000000", 0x0920, "000000"),
+        hidpp.Response("000100", 0x0950),
+        hidpp.Response("000200", 0x0960, "000200"),
+    ],
+    [
+        FeatureTest(settings_templates.ExtendedAdjustableDpi, 0x64, 0x164, 0x60, "0001640164"),
+        common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),
+        hidpp.Response("090000", 0x0000, "2202"),  # EXTENDED_ADJUSTABLE_DPI
+        hidpp.Response("000001", 0x0910, "00"),  # supports y direction
+        hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"),
+        hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"),
+        hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"),
+        hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000100"),
+        hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000101"),
+        hidpp.Response("00000000000000000000000000000000", 0x0920, "000102"),
+        hidpp.Response("000064", 0x0950),
+        hidpp.Response("0001640164", 0x0960, "0001640164"),
+    ],
     [
         FeatureTest(settings_templates.Multiplatform, 0, 1, 0x30, "FF01"),
         common.NamedInts(**{"MacOS 0.1-0.5": 0, "iOS 0.1-0.7": 1, "Linux 0.2-0.9": 2, "Windows 0.3-0.9": 3}),