Repository: home-assistant-libs/zwave-js-server-python (language: python)

Issue:
PEP 585: Use generic typing
e.g. `dict` instead of `Dict`

https://peps.python.org/pep-0585/


Discussion / hints:

Fix patch:
diff --git a/scripts/generate_multilevel_sensor_constants.py b/scripts/generate_multilevel_sensor_constants.py
index 5121ed316..fb048a43e 100755
--- a/scripts/generate_multilevel_sensor_constants.py
+++ b/scripts/generate_multilevel_sensor_constants.py
@@ -8,7 +8,6 @@
 import subprocess
 from collections import defaultdict
 from collections.abc import Callable, Mapping
-from typing import List
 
 import requests
 from slugify import slugify
@@ -119,9 +118,9 @@ def generate_int_enum_class_definition(
     get_id_func: Callable | None = None,
     docstring_info: str = "",
     base_class: str = "IntEnum",
-) -> List[str]:
+) -> list[str]:
     """Generate an IntEnum class definition as an array of lines of string."""
-    class_def: List[str] = []
+    class_def: list[str] = []
     class_def.append(f"class {class_name}({base_class}):")
     docstring = (
         f'"""Enum for known {docstring_info} multilevel sensor types."""'.replace(
@@ -138,9 +137,9 @@ def generate_int_enum_class_definition(
     return class_def
 
 
-def generate_int_enum_base_class(class_name: str, docstring: str) -> List[str]:
+def generate_int_enum_base_class(class_name: str, docstring: str) -> list[str]:
     """Generate an IntEnum base class definition."""
-    class_def: List[str] = []
+    class_def: list[str] = []
     class_def.append(f"class {class_name}(IntEnum):")
     class_def.append(f"\t{docstring}")
     return class_def
@@ -159,7 +158,6 @@ def generate_int_enum_base_class(class_name: str, docstring: str) -> List[str]:
     "# ----------------------------------------------------------------------------------- #",
     "",
     "from enum import IntEnum",
-    "from typing import Dict, List, Type",
     'CC_SPECIFIC_SCALE = "scale"',
     'CC_SPECIFIC_SENSOR_TYPE = "sensorType"',
 ]
@@ -203,8 +201,8 @@ def generate_int_enum_base_class(class_name: str, docstring: str) -> List[str]:
 
 
 multilevel_sensor_type_to_scale_map_line = (
-    "MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: Dict[MultilevelSensorType, "
-    "Type[MultilevelSensorScaleType]] = {"
+    "MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: dict[MultilevelSensorType, "
+    "type[MultilevelSensorScaleType]] = {"
 )
 for sensor_name, sensor_def in sensors.items():
     multilevel_sensor_type_to_scale_map_line += (
@@ -217,7 +215,7 @@ def generate_int_enum_base_class(class_name: str, docstring: str) -> List[str]:
 
 for unit_name, unit_enums in unit_name_to_enum_map.items():
     lines.append(
-        f"UNIT_{unit_name}: List[MultilevelSensorScaleType] = [{','.join(sorted(unit_enums))}]"
+        f"UNIT_{unit_name}: list[MultilevelSensorScaleType] = [{','.join(sorted(unit_enums))}]"
     )
 
 lines.extend(
diff --git a/scripts/run_mock_server.py b/scripts/run_mock_server.py
index 0b970663d..89b31a23e 100644
--- a/scripts/run_mock_server.py
+++ b/scripts/run_mock_server.py
@@ -5,7 +5,7 @@
 import logging
 from collections import defaultdict
 from collections.abc import Hashable
-from typing import Any, DefaultDict, List, Optional, Union
+from typing import Any, Optional, Union
 
 from aiohttp import WSMsgType, web, web_request
 
@@ -45,9 +45,9 @@ class MockZwaveJsServer:
 
     def __init__(
         self,
-        network_state_dump: List[dict],
-        events_to_replay: List[dict],
-        command_results: DefaultDict[HashableDict, list],
+        network_state_dump: list[dict],
+        events_to_replay: list[dict],
+        command_results: defaultdict[HashableDict, list],
     ) -> None:
         """Initialize class."""
         self.network_state_dump = network_state_dump
@@ -221,7 +221,7 @@ def sanitize_msg(msg: dict) -> HashableDict:
 
 
 def add_command_result(
-    command_results: DefaultDict[HashableDict, list],
+    command_results: defaultdict[HashableDict, list],
     record: dict,
 ) -> None:
     """Add a command result to command_results map."""
@@ -293,14 +293,14 @@ def main() -> None:
     args = get_args()
 
     with open(args.network_state_path, "r", encoding="utf8") as fp:
-        network_state_dump: List[dict] = json.load(fp)
+        network_state_dump: list[dict] = json.load(fp)
 
     events_to_replay = []
-    command_results: DefaultDict[HashableDict, list] = defaultdict(list)
+    command_results: defaultdict[HashableDict, list] = defaultdict(list)
 
     if args.combined_replay_dump_path:
         with open(args.combined_replay_dump_path, "r", encoding="utf8") as fp:
-            records: List[dict] = json.load(fp)
+            records: list[dict] = json.load(fp)
 
             for record in records:
                 if record.get("record_type") not in ("event", "command"):
diff --git a/zwave_js_server/client.py b/zwave_js_server/client.py
index 2d6e58cd3..d9b52a6fc 100644
--- a/zwave_js_server/client.py
+++ b/zwave_js_server/client.py
@@ -8,7 +8,7 @@
 from datetime import datetime
 from operator import itemgetter
 from types import TracebackType
-from typing import Any, DefaultDict, Dict, List, Optional, cast
+from typing import Any, Optional, cast
 
 from aiohttp import ClientSession, ClientWebSocketResponse, WSMsgType, client_exceptions
 
@@ -55,7 +55,7 @@ def __init__(
         ws_server_url: str,
         aiohttp_session: ClientSession,
         schema_version: int = MAX_SERVER_SCHEMA_VERSION,
-        additional_user_agent_components: Optional[Dict[str, str]] = None,
+        additional_user_agent_components: Optional[dict[str, str]] = None,
         record_messages: bool = False,
     ):
         """Initialize the Client class."""
@@ -73,11 +73,11 @@ def __init__(
         }
         self._logger = logging.getLogger(__package__)
         self._loop = asyncio.get_running_loop()
-        self._result_futures: Dict[str, asyncio.Future] = {}
+        self._result_futures: dict[str, asyncio.Future] = {}
         self._shutdown_complete_event: Optional[asyncio.Event] = None
         self._record_messages = record_messages
-        self._recorded_commands: DefaultDict[str, dict] = defaultdict(dict)
-        self._recorded_events: List[dict] = []
+        self._recorded_commands: defaultdict[str, dict] = defaultdict(dict)
+        self._recorded_events: list[dict] = []
 
     def __repr__(self) -> str:
         """Return the representation."""
@@ -96,7 +96,7 @@ def recording_messages(self) -> bool:
 
     async def async_send_command(
         self,
-        message: Dict[str, Any],
+        message: dict[str, Any],
         require_schema: Optional[int] = None,
     ) -> dict:
         """Send a command and get a response."""
@@ -118,7 +118,7 @@ async def async_send_command(
             self._result_futures.pop(message_id)
 
     async def async_send_command_no_wait(
-        self, message: Dict[str, Any], require_schema: Optional[int] = None
+        self, message: dict[str, Any], require_schema: Optional[int] = None
     ) -> None:
         """Send a command without waiting for the response."""
         if require_schema is not None and require_schema > self.schema_version:
@@ -303,7 +303,7 @@ def begin_recording_messages(self) -> None:
 
         self._record_messages = True
 
-    def end_recording_messages(self) -> List[dict]:
+    def end_recording_messages(self) -> list[dict]:
         """End recording messages and return messages that were recorded."""
         if not self._record_messages:
             raise InvalidState("Not recording messages")
@@ -411,7 +411,7 @@ def _handle_incoming_message(self, msg: dict) -> None:
         event = Event(type=msg["event"]["event"], data=msg["event"])
         self.driver.receive_event(event)  # type: ignore
 
-    async def _send_json_message(self, message: Dict[str, Any]) -> None:
+    async def _send_json_message(self, message: dict[str, Any]) -> None:
         """Send a message.
 
         Raises NotConnected if client not connected.
diff --git a/zwave_js_server/const/command_class/humidity_control.py b/zwave_js_server/const/command_class/humidity_control.py
index d63b46944..acfa83c83 100644
--- a/zwave_js_server/const/command_class/humidity_control.py
+++ b/zwave_js_server/const/command_class/humidity_control.py
@@ -5,7 +5,6 @@
 and Humidity Control Setpoint CCs.
 """
 from enum import IntEnum
-from typing import Dict, List
 
 HUMIDITY_CONTROL_MODE_PROPERTY = "mode"
 HUMIDITY_CONTROL_OPERATING_STATE_PROPERTY = "state"
@@ -47,7 +46,7 @@ class HumidityControlSetpointType(IntEnum):
     AUTO = 3
 
 
-HUMIDITY_CONTROL_MODE_SETPOINT_MAP: Dict[int, List[HumidityControlSetpointType]] = {
+HUMIDITY_CONTROL_MODE_SETPOINT_MAP: dict[int, list[HumidityControlSetpointType]] = {
     HumidityControlMode.OFF: [],
     HumidityControlMode.HUMIDIFY: [HumidityControlSetpointType.HUMIDIFIER],
     HumidityControlMode.DEHUMIDIFY: [HumidityControlSetpointType.DEHUMIDIFIER],
diff --git a/zwave_js_server/const/command_class/meter.py b/zwave_js_server/const/command_class/meter.py
index 42c63d1e0..cd2cd0d78 100644
--- a/zwave_js_server/const/command_class/meter.py
+++ b/zwave_js_server/const/command_class/meter.py
@@ -1,6 +1,5 @@
 """Constants for Meter CC."""
 from enum import IntEnum
-from typing import Dict, List, Type
 
 VALUE_PROPERTY = "value"
 
@@ -70,7 +69,7 @@ class HeatingScale(MeterScaleType):
 
 CoolingScale = HeatingScale
 
-METER_TYPE_TO_SCALE_ENUM_MAP: Dict[MeterType, Type[MeterScaleType]] = {
+METER_TYPE_TO_SCALE_ENUM_MAP: dict[MeterType, type[MeterScaleType]] = {
     MeterType.ELECTRIC: ElectricScale,
     MeterType.GAS: GasScale,
     MeterType.WATER: WaterScale,
@@ -78,7 +77,7 @@ class HeatingScale(MeterScaleType):
     MeterType.COOLING: CoolingScale,
 }
 
-ENERGY_TOTAL_INCREASING_METER_TYPES: List[MeterScaleType] = [
+ENERGY_TOTAL_INCREASING_METER_TYPES: list[MeterScaleType] = [
     ElectricScale.KILOWATT_HOUR,
     ElectricScale.KILOVOLT_AMPERE_HOUR,
     ElectricScale.KILOVOLT_AMPERE_REACTIVE_HOUR,
@@ -86,46 +85,46 @@ class HeatingScale(MeterScaleType):
     CoolingScale.KILOWATT_HOUR,
     ElectricScale.PULSE_COUNT,
 ]
-POWER_METER_TYPES: List[MeterScaleType] = [
+POWER_METER_TYPES: list[MeterScaleType] = [
     ElectricScale.WATT,
     ElectricScale.KILOVOLT_AMPERE_REACTIVE,
 ]
-POWER_FACTOR_METER_TYPES: List[MeterScaleType] = [ElectricScale.POWER_FACTOR]
-VOLTAGE_METER_TYPES: List[MeterScaleType] = [ElectricScale.VOLT]
-CURRENT_METER_TYPES: List[MeterScaleType] = [ElectricScale.AMPERE]
-GAS_METER_TYPES: List[MeterScaleType] = [
+POWER_FACTOR_METER_TYPES: list[MeterScaleType] = [ElectricScale.POWER_FACTOR]
+VOLTAGE_METER_TYPES: list[MeterScaleType] = [ElectricScale.VOLT]
+CURRENT_METER_TYPES: list[MeterScaleType] = [ElectricScale.AMPERE]
+GAS_METER_TYPES: list[MeterScaleType] = [
     GasScale.CUBIC_METER,
     GasScale.CUBIC_FEET,
     GasScale.PULSE_COUNT,
 ]
-WATER_METER_TYPES: List[MeterScaleType] = [
+WATER_METER_TYPES: list[MeterScaleType] = [
     WaterScale.CUBIC_METER,
     WaterScale.CUBIC_FEET,
     WaterScale.US_GALLON,
     WaterScale.PULSE_COUNT,
 ]
 
-UNIT_KILOWATT_HOUR: List[MeterScaleType] = [
+UNIT_KILOWATT_HOUR: list[MeterScaleType] = [
     ElectricScale.KILOWATT_HOUR,
     HeatingScale.KILOWATT_HOUR,
     CoolingScale.KILOWATT_HOUR,
 ]
-UNIT_KILOVOLT_AMPERE_HOUR: List[MeterScaleType] = [ElectricScale.KILOVOLT_AMPERE_HOUR]
-UNIT_WATT: List[MeterScaleType] = [ElectricScale.WATT]
-UNIT_PULSE_COUNT: List[MeterScaleType] = [
+UNIT_KILOVOLT_AMPERE_HOUR: list[MeterScaleType] = [ElectricScale.KILOVOLT_AMPERE_HOUR]
+UNIT_WATT: list[MeterScaleType] = [ElectricScale.WATT]
+UNIT_PULSE_COUNT: list[MeterScaleType] = [
     ElectricScale.PULSE_COUNT,
     GasScale.PULSE_COUNT,
     WaterScale.PULSE_COUNT,
 ]
-UNIT_VOLT: List[MeterScaleType] = [ElectricScale.VOLT]
-UNIT_AMPERE: List[MeterScaleType] = [ElectricScale.AMPERE]
-UNIT_POWER_FACTOR: List[MeterScaleType] = [ElectricScale.POWER_FACTOR]
-UNIT_KILOVOLT_AMPERE_REACTIVE: List[MeterScaleType] = [
+UNIT_VOLT: list[MeterScaleType] = [ElectricScale.VOLT]
+UNIT_AMPERE: list[MeterScaleType] = [ElectricScale.AMPERE]
+UNIT_POWER_FACTOR: list[MeterScaleType] = [ElectricScale.POWER_FACTOR]
+UNIT_KILOVOLT_AMPERE_REACTIVE: list[MeterScaleType] = [
     ElectricScale.KILOVOLT_AMPERE_REACTIVE
 ]
-UNIT_KILOVOLT_AMPERE_REACTIVE_HOUR: List[MeterScaleType] = [
+UNIT_KILOVOLT_AMPERE_REACTIVE_HOUR: list[MeterScaleType] = [
     ElectricScale.KILOVOLT_AMPERE_REACTIVE_HOUR
 ]
-UNIT_CUBIC_METER: List[MeterScaleType] = [GasScale.CUBIC_METER, WaterScale.CUBIC_METER]
-UNIT_CUBIC_FEET: List[MeterScaleType] = [GasScale.CUBIC_FEET, WaterScale.CUBIC_FEET]
-UNIT_US_GALLON: List[MeterScaleType] = [WaterScale.US_GALLON]
+UNIT_CUBIC_METER: list[MeterScaleType] = [GasScale.CUBIC_METER, WaterScale.CUBIC_METER]
+UNIT_CUBIC_FEET: list[MeterScaleType] = [GasScale.CUBIC_FEET, WaterScale.CUBIC_FEET]
+UNIT_US_GALLON: list[MeterScaleType] = [WaterScale.US_GALLON]
diff --git a/zwave_js_server/const/command_class/multilevel_sensor.py b/zwave_js_server/const/command_class/multilevel_sensor.py
index 1f19fd640..d91ae6328 100644
--- a/zwave_js_server/const/command_class/multilevel_sensor.py
+++ b/zwave_js_server/const/command_class/multilevel_sensor.py
@@ -6,7 +6,6 @@
 # ----------------------------------------------------------------------------------- #
 
 from enum import IntEnum
-from typing import Dict, List, Type
 
 CC_SPECIFIC_SCALE = "scale"
 CC_SPECIFIC_SENSOR_TYPE = "sensorType"
@@ -534,8 +533,8 @@ class WeightScale(MultilevelSensorScaleType):
     POUNDS = 1
 
 
-MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: Dict[
-    MultilevelSensorType, Type[MultilevelSensorScaleType]
+MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: dict[
+    MultilevelSensorType, type[MultilevelSensorScaleType]
 ] = {
     MultilevelSensorType.ACCELERATION_X_AXIS: AccelerationScale,
     MultilevelSensorType.ACCELERATION_Y_AXIS: AccelerationScale,
@@ -627,103 +626,103 @@ class WeightScale(MultilevelSensorScaleType):
     MultilevelSensorType.WEIGHT: WeightScale,
 }
 
-UNIT_ABSOLUTE_HUMIDITY: List[MultilevelSensorScaleType] = [
+UNIT_ABSOLUTE_HUMIDITY: list[MultilevelSensorScaleType] = [
     HumidityScale.ABSOLUTE_HUMIDITY
 ]
-UNIT_ACIDITY: List[MultilevelSensorScaleType] = [AcidityScale.ACIDITY]
-UNIT_AMPERE: List[MultilevelSensorScaleType] = [CurrentScale.AMPERE]
-UNIT_A_WEIGHTED_DECIBELS: List[MultilevelSensorScaleType] = [
+UNIT_ACIDITY: list[MultilevelSensorScaleType] = [AcidityScale.ACIDITY]
+UNIT_AMPERE: list[MultilevelSensorScaleType] = [CurrentScale.AMPERE]
+UNIT_A_WEIGHTED_DECIBELS: list[MultilevelSensorScaleType] = [
     LoudnessScale.A_WEIGHTED_DECIBELS
 ]
-UNIT_BEATS_PER_MINUTE: List[MultilevelSensorScaleType] = [
+UNIT_BEATS_PER_MINUTE: list[MultilevelSensorScaleType] = [
     HeartRateScale.BEATS_PER_MINUTE
 ]
-UNIT_BECQUEREL_PER_CUBIC_METER: List[MultilevelSensorScaleType] = [
+UNIT_BECQUEREL_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [
     RadonConcentrationScale.BECQUEREL_PER_CUBIC_METER
 ]
-UNIT_BODY_MASS_INDEX: List[MultilevelSensorScaleType] = [
+UNIT_BODY_MASS_INDEX: list[MultilevelSensorScaleType] = [
     BodyMassIndexScale.BODY_MASS_INDEX
 ]
-UNIT_BODY_WAVE: List[MultilevelSensorScaleType] = [SeismicMagnitudeScale.BODY_WAVE]
-UNIT_BREATHS_PER_MINUTE: List[MultilevelSensorScaleType] = [
+UNIT_BODY_WAVE: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.BODY_WAVE]
+UNIT_BREATHS_PER_MINUTE: list[MultilevelSensorScaleType] = [
     RespiratoryRateScale.BREATHS_PER_MINUTE
 ]
-UNIT_BTU_H: List[MultilevelSensorScaleType] = [PowerScale.BTU_H]
-UNIT_CELSIUS: List[MultilevelSensorScaleType] = [TemperatureScale.CELSIUS]
-UNIT_CENTIMETER: List[MultilevelSensorScaleType] = [DistanceScale.CENTIMETER]
-UNIT_CUBIC_FEET_PER_MINUTE: List[MultilevelSensorScaleType] = [
+UNIT_BTU_H: list[MultilevelSensorScaleType] = [PowerScale.BTU_H]
+UNIT_CELSIUS: list[MultilevelSensorScaleType] = [TemperatureScale.CELSIUS]
+UNIT_CENTIMETER: list[MultilevelSensorScaleType] = [DistanceScale.CENTIMETER]
+UNIT_CUBIC_FEET_PER_MINUTE: list[MultilevelSensorScaleType] = [
     AirFlowScale.CUBIC_FEET_PER_MINUTE
 ]
-UNIT_CUBIC_METER: List[MultilevelSensorScaleType] = [TankCapacityScale.CUBIC_METER]
-UNIT_CUBIC_METER_PER_HOUR: List[MultilevelSensorScaleType] = [
+UNIT_CUBIC_METER: list[MultilevelSensorScaleType] = [TankCapacityScale.CUBIC_METER]
+UNIT_CUBIC_METER_PER_HOUR: list[MultilevelSensorScaleType] = [
     AirFlowScale.CUBIC_METER_PER_HOUR
 ]
-UNIT_DECIBEL: List[MultilevelSensorScaleType] = [LoudnessScale.DECIBEL]
-UNIT_DEGREES: List[MultilevelSensorScaleType] = [DirectionScale.DEGREES]
-UNIT_DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW: List[
+UNIT_DECIBEL: list[MultilevelSensorScaleType] = [LoudnessScale.DECIBEL]
+UNIT_DEGREES: list[MultilevelSensorScaleType] = [DirectionScale.DEGREES]
+UNIT_DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW: list[
     MultilevelSensorScaleType
 ] = [AnglePositionScale.DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW]
-UNIT_DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW: List[
+UNIT_DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW: list[
     MultilevelSensorScaleType
 ] = [AnglePositionScale.DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW]
-UNIT_DENSITY: List[MultilevelSensorScaleType] = [DensityScale.DENSITY]
-UNIT_DIASTOLIC: List[MultilevelSensorScaleType] = [BloodPressureScale.DIASTOLIC]
-UNIT_DIMENSIONLESS_VALUE: List[MultilevelSensorScaleType] = [
+UNIT_DENSITY: list[MultilevelSensorScaleType] = [DensityScale.DENSITY]
+UNIT_DIASTOLIC: list[MultilevelSensorScaleType] = [BloodPressureScale.DIASTOLIC]
+UNIT_DIMENSIONLESS_VALUE: list[MultilevelSensorScaleType] = [
     GeneralPurposeScale.DIMENSIONLESS_VALUE
 ]
-UNIT_EUROPEAN_MACROSEISMIC: List[MultilevelSensorScaleType] = [
+UNIT_EUROPEAN_MACROSEISMIC: list[MultilevelSensorScaleType] = [
     SeismicIntensityScale.EUROPEAN_MACROSEISMIC
 ]
-UNIT_FAHRENHEIT: List[MultilevelSensorScaleType] = [TemperatureScale.FAHRENHEIT]
-UNIT_FEET: List[MultilevelSensorScaleType] = [DistanceScale.FEET, TideLevelScale.FEET]
-UNIT_GALLONS: List[MultilevelSensorScaleType] = [TankCapacityScale.GALLONS]
-UNIT_HERTZ: List[MultilevelSensorScaleType] = [
+UNIT_FAHRENHEIT: list[MultilevelSensorScaleType] = [TemperatureScale.FAHRENHEIT]
+UNIT_FEET: list[MultilevelSensorScaleType] = [DistanceScale.FEET, TideLevelScale.FEET]
+UNIT_GALLONS: list[MultilevelSensorScaleType] = [TankCapacityScale.GALLONS]
+UNIT_HERTZ: list[MultilevelSensorScaleType] = [
     FrequencyScale.HERTZ,
     RotationScale.HERTZ,
 ]
-UNIT_IMPEDANCE: List[MultilevelSensorScaleType] = [MoistureScale.IMPEDANCE]
-UNIT_INCHES_OF_MERCURY: List[MultilevelSensorScaleType] = [
+UNIT_IMPEDANCE: list[MultilevelSensorScaleType] = [MoistureScale.IMPEDANCE]
+UNIT_INCHES_OF_MERCURY: list[MultilevelSensorScaleType] = [
     AirPressureScale.INCHES_OF_MERCURY
 ]
-UNIT_INCHES_PER_HOUR: List[MultilevelSensorScaleType] = [RainRateScale.INCHES_PER_HOUR]
-UNIT_JOULE: List[MultilevelSensorScaleType] = [BasisMetabolicRateScale.JOULE]
-UNIT_KILOGRAM: List[MultilevelSensorScaleType] = [
+UNIT_INCHES_PER_HOUR: list[MultilevelSensorScaleType] = [RainRateScale.INCHES_PER_HOUR]
+UNIT_JOULE: list[MultilevelSensorScaleType] = [BasisMetabolicRateScale.JOULE]
+UNIT_KILOGRAM: list[MultilevelSensorScaleType] = [
     MassScale.KILOGRAM,
     WeightScale.KILOGRAM,
 ]
-UNIT_KILOHERTZ: List[MultilevelSensorScaleType] = [FrequencyScale.KILOHERTZ]
-UNIT_KILOPASCAL: List[MultilevelSensorScaleType] = [
+UNIT_KILOHERTZ: list[MultilevelSensorScaleType] = [FrequencyScale.KILOHERTZ]
+UNIT_KILOPASCAL: list[MultilevelSensorScaleType] = [
     AirPressureScale.KILOPASCAL,
     PressureScale.KILOPASCAL,
     WaterPressureScale.KILOPASCAL,
 ]
-UNIT_LIEDU: List[MultilevelSensorScaleType] = [SeismicIntensityScale.LIEDU]
-UNIT_LITER: List[MultilevelSensorScaleType] = [TankCapacityScale.LITER]
-UNIT_LITER_PER_HOUR: List[MultilevelSensorScaleType] = [WaterFlowScale.LITER_PER_HOUR]
-UNIT_LOCAL: List[MultilevelSensorScaleType] = [SeismicMagnitudeScale.LOCAL]
-UNIT_LUX: List[MultilevelSensorScaleType] = [IlluminanceScale.LUX]
-UNIT_MERCALLI: List[MultilevelSensorScaleType] = [SeismicIntensityScale.MERCALLI]
-UNIT_METER: List[MultilevelSensorScaleType] = [
+UNIT_LIEDU: list[MultilevelSensorScaleType] = [SeismicIntensityScale.LIEDU]
+UNIT_LITER: list[MultilevelSensorScaleType] = [TankCapacityScale.LITER]
+UNIT_LITER_PER_HOUR: list[MultilevelSensorScaleType] = [WaterFlowScale.LITER_PER_HOUR]
+UNIT_LOCAL: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.LOCAL]
+UNIT_LUX: list[MultilevelSensorScaleType] = [IlluminanceScale.LUX]
+UNIT_MERCALLI: list[MultilevelSensorScaleType] = [SeismicIntensityScale.MERCALLI]
+UNIT_METER: list[MultilevelSensorScaleType] = [
     DistanceScale.METER,
     TideLevelScale.METER,
 ]
-UNIT_METER_PER_SQUARE_SECOND: List[MultilevelSensorScaleType] = [
+UNIT_METER_PER_SQUARE_SECOND: list[MultilevelSensorScaleType] = [
     AccelerationScale.METER_PER_SQUARE_SECOND
 ]
-UNIT_MICROGRAM_PER_CUBIC_METER: List[MultilevelSensorScaleType] = [
+UNIT_MICROGRAM_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [
     ParticulateMatter10Scale.MICROGRAM_PER_CUBIC_METER,
     ParticulateMatter25Scale.MICROGRAM_PER_CUBIC_METER,
 ]
-UNIT_MILLIAMPERE: List[MultilevelSensorScaleType] = [CurrentScale.MILLIAMPERE]
-UNIT_MILLIGRAM_PER_LITER: List[MultilevelSensorScaleType] = [
+UNIT_MILLIAMPERE: list[MultilevelSensorScaleType] = [CurrentScale.MILLIAMPERE]
+UNIT_MILLIGRAM_PER_LITER: list[MultilevelSensorScaleType] = [
     WaterChlorineLevelScale.MILLIGRAM_PER_LITER
 ]
-UNIT_MILLIMETER_HOUR: List[MultilevelSensorScaleType] = [RainRateScale.MILLIMETER_HOUR]
-UNIT_MILLIVOLT: List[MultilevelSensorScaleType] = [
+UNIT_MILLIMETER_HOUR: list[MultilevelSensorScaleType] = [RainRateScale.MILLIMETER_HOUR]
+UNIT_MILLIVOLT: list[MultilevelSensorScaleType] = [
     VoltageScale.MILLIVOLT,
     WaterOxidationReductionPotentialScale.MILLIVOLT,
 ]
-UNIT_MOLE_PER_CUBIC_METER: List[MultilevelSensorScaleType] = [
+UNIT_MOLE_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [
     CarbonMonoxideLevelScale.MOLE_PER_CUBIC_METER,
     FormaldehydeLevelScale.MOLE_PER_CUBIC_METER,
     MethaneDensityScale.MOLE_PER_CUBIC_METER,
@@ -732,17 +731,17 @@ class WeightScale(MultilevelSensorScaleType):
     SoilSalinityScale.MOLE_PER_CUBIC_METER,
     VolatileOrganicCompoundLevelScale.MOLE_PER_CUBIC_METER,
 ]
-UNIT_MOMENT: List[MultilevelSensorScaleType] = [SeismicMagnitudeScale.MOMENT]
-UNIT_MPH: List[MultilevelSensorScaleType] = [VelocityScale.MPH]
-UNIT_M_S: List[MultilevelSensorScaleType] = [VelocityScale.M_S]
-UNIT_NEWTON: List[MultilevelSensorScaleType] = [AppliedForceOnTheSensorScale.NEWTON]
-UNIT_OHM_METER: List[MultilevelSensorScaleType] = [ElectricalResistivityScale.OHM_METER]
-UNIT_PARTS_MILLION: List[MultilevelSensorScaleType] = [
+UNIT_MOMENT: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.MOMENT]
+UNIT_MPH: list[MultilevelSensorScaleType] = [VelocityScale.MPH]
+UNIT_M_S: list[MultilevelSensorScaleType] = [VelocityScale.M_S]
+UNIT_NEWTON: list[MultilevelSensorScaleType] = [AppliedForceOnTheSensorScale.NEWTON]
+UNIT_OHM_METER: list[MultilevelSensorScaleType] = [ElectricalResistivityScale.OHM_METER]
+UNIT_PARTS_MILLION: list[MultilevelSensorScaleType] = [
     CarbonDioxideLevelScale.PARTS_MILLION,
     CarbonMonoxideLevelScale.PARTS_MILLION,
     VolatileOrganicCompoundLevelScale.PARTS_MILLION,
 ]
-UNIT_PERCENTAGE_VALUE: List[MultilevelSensorScaleType] = [
+UNIT_PERCENTAGE_VALUE: list[MultilevelSensorScaleType] = [
     AnglePositionScale.PERCENTAGE_VALUE,
     GeneralPurposeScale.PERCENTAGE_VALUE,
     HumidityScale.PERCENTAGE_VALUE,
@@ -750,36 +749,36 @@ class WeightScale(MultilevelSensorScaleType):
     MoistureScale.PERCENTAGE_VALUE,
     PercentageScale.PERCENTAGE_VALUE,
 ]
-UNIT_PICOCURIES_PER_LITER: List[MultilevelSensorScaleType] = [
+UNIT_PICOCURIES_PER_LITER: list[MultilevelSensorScaleType] = [
     RadonConcentrationScale.PICOCURIES_PER_LITER
 ]
-UNIT_POUNDS: List[MultilevelSensorScaleType] = [WeightScale.POUNDS]
-UNIT_POUND_PER_SQUARE_INCH: List[MultilevelSensorScaleType] = [
+UNIT_POUNDS: list[MultilevelSensorScaleType] = [WeightScale.POUNDS]
+UNIT_POUND_PER_SQUARE_INCH: list[MultilevelSensorScaleType] = [
     PressureScale.POUND_PER_SQUARE_INCH
 ]
-UNIT_POWER_LEVEL: List[MultilevelSensorScaleType] = [RfSignalStrengthScale.POWER_LEVEL]
-UNIT_REVOLUTIONS_PER_MINUTE: List[MultilevelSensorScaleType] = [
+UNIT_POWER_LEVEL: list[MultilevelSensorScaleType] = [RfSignalStrengthScale.POWER_LEVEL]
+UNIT_REVOLUTIONS_PER_MINUTE: list[MultilevelSensorScaleType] = [
     RotationScale.REVOLUTIONS_PER_MINUTE
 ]
-UNIT_RSSI: List[MultilevelSensorScaleType] = [RfSignalStrengthScale.RSSI]
-UNIT_SECOND: List[MultilevelSensorScaleType] = [TimeScale.SECOND]
-UNIT_SHINDO: List[MultilevelSensorScaleType] = [SeismicIntensityScale.SHINDO]
-UNIT_SIEMENS_PER_METER: List[MultilevelSensorScaleType] = [
+UNIT_RSSI: list[MultilevelSensorScaleType] = [RfSignalStrengthScale.RSSI]
+UNIT_SECOND: list[MultilevelSensorScaleType] = [TimeScale.SECOND]
+UNIT_SHINDO: list[MultilevelSensorScaleType] = [SeismicIntensityScale.SHINDO]
+UNIT_SIEMENS_PER_METER: list[MultilevelSensorScaleType] = [
     ElectricalConductivityScale.SIEMENS_PER_METER
 ]
-UNIT_SURFACE_WAVE: List[MultilevelSensorScaleType] = [
+UNIT_SURFACE_WAVE: list[MultilevelSensorScaleType] = [
     SeismicMagnitudeScale.SURFACE_WAVE
 ]
-UNIT_SYSTOLIC: List[MultilevelSensorScaleType] = [BloodPressureScale.SYSTOLIC]
-UNIT_UNITLESS: List[MultilevelSensorScaleType] = [UnitlessScale.UNITLESS]
-UNIT_UV_INDEX: List[MultilevelSensorScaleType] = [UltravioletScale.UV_INDEX]
-UNIT_VOLT: List[MultilevelSensorScaleType] = [VoltageScale.VOLT]
-UNIT_VOLUME_WATER_CONTENT: List[MultilevelSensorScaleType] = [
+UNIT_SYSTOLIC: list[MultilevelSensorScaleType] = [BloodPressureScale.SYSTOLIC]
+UNIT_UNITLESS: list[MultilevelSensorScaleType] = [UnitlessScale.UNITLESS]
+UNIT_UV_INDEX: list[MultilevelSensorScaleType] = [UltravioletScale.UV_INDEX]
+UNIT_VOLT: list[MultilevelSensorScaleType] = [VoltageScale.VOLT]
+UNIT_VOLUME_WATER_CONTENT: list[MultilevelSensorScaleType] = [
     MoistureScale.VOLUME_WATER_CONTENT
 ]
-UNIT_WATER_ACTIVITY: List[MultilevelSensorScaleType] = [MoistureScale.WATER_ACTIVITY]
-UNIT_WATT: List[MultilevelSensorScaleType] = [PowerScale.WATT]
-UNIT_WATT_PER_SQUARE_METER: List[MultilevelSensorScaleType] = [
+UNIT_WATER_ACTIVITY: list[MultilevelSensorScaleType] = [MoistureScale.WATER_ACTIVITY]
+UNIT_WATT: list[MultilevelSensorScaleType] = [PowerScale.WATT]
+UNIT_WATT_PER_SQUARE_METER: list[MultilevelSensorScaleType] = [
     SolarRadiationScale.WATT_PER_SQUARE_METER
 ]
 
diff --git a/zwave_js_server/const/command_class/thermostat.py b/zwave_js_server/const/command_class/thermostat.py
index dfa59b8cc..6639e25a0 100644
--- a/zwave_js_server/const/command_class/thermostat.py
+++ b/zwave_js_server/const/command_class/thermostat.py
@@ -5,7 +5,6 @@
 Operating State, Thermostat Setback, and Thermostat Setpoint CCs.
 """
 from enum import IntEnum
-from typing import Dict, List
 
 THERMOSTAT_MODE_PROPERTY = "mode"
 THERMOSTAT_SETPOINT_PROPERTY = "setpoint"
@@ -89,7 +88,7 @@ class ThermostatSetpointType(IntEnum):
     ThermostatMode.AUTO_CHANGE_OVER,
 ]
 
-THERMOSTAT_MODE_SETPOINT_MAP: Dict[int, List[ThermostatSetpointType]] = {
+THERMOSTAT_MODE_SETPOINT_MAP: dict[int, list[ThermostatSetpointType]] = {
     ThermostatMode.OFF: [],
     ThermostatMode.HEAT: [ThermostatSetpointType.HEATING],
     ThermostatMode.COOL: [ThermostatSetpointType.COOLING],
diff --git a/zwave_js_server/dump.py b/zwave_js_server/dump.py
index 5fac8d139..652c41570 100644
--- a/zwave_js_server/dump.py
+++ b/zwave_js_server/dump.py
@@ -1,6 +1,6 @@
 """Dump helper."""
 import asyncio
-from typing import Dict, List, Optional
+from typing import Optional
 
 import aiohttp
 
@@ -11,9 +11,9 @@
 async def dump_msgs(
     url: str,
     session: aiohttp.ClientSession,
-    additional_user_agent_components: Optional[Dict[str, str]] = None,
+    additional_user_agent_components: Optional[dict[str, str]] = None,
     timeout: Optional[float] = None,
-) -> List[dict]:
+) -> list[dict]:
     """Dump server state."""
     client = await session.ws_connect(url, compress=15, max_msg_size=0)
     msgs = []
diff --git a/zwave_js_server/event.py b/zwave_js_server/event.py
index 110ecf9db..b25e729d2 100644
--- a/zwave_js_server/event.py
+++ b/zwave_js_server/event.py
@@ -1,7 +1,7 @@
 """Provide Event base classes for Z-Wave JS."""
 import logging
 from dataclasses import dataclass, field
-from typing import Callable, Dict, List, Literal
+from typing import Callable, Literal
 
 from pydantic import BaseModel
 
@@ -28,7 +28,7 @@ class EventBase:
 
     def __init__(self) -> None:
         """Initialize event base."""
-        self._listeners: Dict[str, List[Callable]] = {}
+        self._listeners: dict[str, list[Callable]] = {}
 
     def on(  # pylint: disable=invalid-name
         self, event_name: str, callback: Callable
diff --git a/zwave_js_server/exceptions.py b/zwave_js_server/exceptions.py
index 1d6368ecc..ebf68b7eb 100644
--- a/zwave_js_server/exceptions.py
+++ b/zwave_js_server/exceptions.py
@@ -1,5 +1,5 @@
 """Exceptions for zwave-js-server."""
-from typing import TYPE_CHECKING, List, Optional
+from typing import TYPE_CHECKING, Optional
 
 from .const import RssiError
 
@@ -184,7 +184,7 @@ def __init__(self, error: "RssiError") -> None:
 class RepeaterRssiErrorReceived(BaseZwaveJSServerError):
     """Exception raised when an RSSI error is received in list of RSSIs."""
 
-    def __init__(self, rssi_list: List[int]) -> None:
+    def __init__(self, rssi_list: list[int]) -> None:
         """Initialize an RSSI error."""
         self.rssi_list = rssi_list
         rssi_errors = [item.value for item in RssiError]
diff --git a/zwave_js_server/firmware.py b/zwave_js_server/firmware.py
index 70995ddf8..c8b835c2a 100644
--- a/zwave_js_server/firmware.py
+++ b/zwave_js_server/firmware.py
@@ -1,6 +1,6 @@
 """Firmware update helper."""
 import asyncio
-from typing import Dict, List, Optional, cast
+from typing import Optional, cast
 
 import aiohttp
 
@@ -13,9 +13,9 @@
 async def update_firmware(
     url: str,
     node: Node,
-    updates: List[NodeFirmwareUpdateData],
+    updates: list[NodeFirmwareUpdateData],
     session: aiohttp.ClientSession,
-    additional_user_agent_components: Optional[Dict[str, str]] = None,
+    additional_user_agent_components: Optional[dict[str, str]] = None,
 ) -> bool:
     """Send updateFirmware command to Node."""
     client = Client(
@@ -44,7 +44,7 @@ async def controller_firmware_update_otw(
     url: str,
     firmware_file: ControllerFirmwareUpdateData,
     session: aiohttp.ClientSession,
-    additional_user_agent_components: Optional[Dict[str, str]] = None,
+    additional_user_agent_components: Optional[dict[str, str]] = None,
 ) -> bool:
     """
     Send firmwareUpdateOTW command to Controller.
diff --git a/zwave_js_server/model/association.py b/zwave_js_server/model/association.py
index 712a75cd1..c46fe2e47 100644
--- a/zwave_js_server/model/association.py
+++ b/zwave_js_server/model/association.py
@@ -1,6 +1,6 @@
 """Provide a model for the association."""
 from dataclasses import dataclass, field
-from typing import Dict, List, Optional
+from typing import Optional
 
 
 @dataclass
@@ -12,7 +12,7 @@ class AssociationGroup:
     multi_channel: bool
     label: str
     profile: Optional[int] = None
-    issued_commands: Dict[int, List[int]] = field(default_factory=dict)
+    issued_commands: dict[int, list[int]] = field(default_factory=dict)
 
 
 @dataclass
diff --git a/zwave_js_server/model/controller/__init__.py b/zwave_js_server/model/controller/__init__.py
index e7337eab6..a38d17faa 100644
--- a/zwave_js_server/model/controller/__init__.py
+++ b/zwave_js_server/model/controller/__init__.py
@@ -1,6 +1,6 @@
 """Provide a model for the Z-Wave JS controller."""
 from dataclasses import dataclass
-from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Union, cast
+from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
 
 from zwave_js_server.model.node.firmware import (
     NodeFirmwareUpdateFileInfo,
@@ -50,8 +50,8 @@ def __init__(self, client: "Client", state: dict) -> None:
         """Initialize controller."""
         super().__init__()
         self.client = client
-        self.nodes: Dict[int, Node] = {}
-        self._heal_network_progress: Optional[Dict[int, str]] = None
+        self.nodes: dict[int, Node] = {}
+        self._heal_network_progress: Optional[dict[int, str]] = None
         self._statistics = ControllerStatistics()
         self._firmware_update_progress: Optional[
             ControllerFirmwareUpdateProgress
@@ -155,7 +155,7 @@ def product_id(self) -> Optional[int]:
         return self.data.get("productId")
 
     @property
-    def supported_function_types(self) -> List[int]:
+    def supported_function_types(self) -> list[int]:
         """Return supported_function_types."""
         return self.data.get("supportedFunctionTypes", [])
 
@@ -180,7 +180,7 @@ def statistics(self) -> ControllerStatistics:
         return self._statistics
 
     @property
-    def heal_network_progress(self) -> Optional[Dict[int, str]]:
+    def heal_network_progress(self) -> Optional[dict[int, str]]:
         """Return heal network progress state."""
         return self._heal_network_progress
 
@@ -223,7 +223,7 @@ async def async_begin_inclusion(
         """Send beginInclusion command to Controller."""
         # Most functionality was introduced in Schema 8
         require_schema = 8
-        options: Dict[str, Any] = {"strategy": inclusion_strategy}
+        options: dict[str, Any] = {"strategy": inclusion_strategy}
         # forceSecurity can only be used with the default inclusion strategy
         if force_security is not None:
             if inclusion_strategy != InclusionStrategy.DEFAULT:
@@ -337,7 +337,7 @@ async def async_get_provisioning_entry(
             return ProvisioningEntry.from_dict(data["entry"])
         return None
 
-    async def async_get_provisioning_entries(self) -> List[ProvisioningEntry]:
+    async def async_get_provisioning_entries(self) -> list[ProvisioningEntry]:
         """Send getProvisioningEntries command to Controller."""
         data = await self.client.async_send_command(
             {
@@ -358,7 +358,7 @@ async def async_begin_exclusion(
         self, strategy: Optional[ExclusionStrategy] = None
     ) -> bool:
         """Send beginExclusion command to Controller."""
-        payload: Dict[str, Union[str, ExclusionStrategy]] = {
+        payload: dict[str, Union[str, ExclusionStrategy]] = {
             "command": "controller.begin_exclusion"
         }
         if strategy is not None:
@@ -396,7 +396,7 @@ async def async_replace_failed_node(
         """Send replaceFailedNode command to Controller."""
         # Most functionality was introduced in Schema 8
         require_schema = 8
-        options: Dict[str, Any] = {"strategy": inclusion_strategy}
+        options: dict[str, Any] = {"strategy": inclusion_strategy}
         # forceSecurity can only be used with the default inclusion strategy
         if force_security is not None:
             if inclusion_strategy != InclusionStrategy.DEFAULT:
@@ -473,7 +473,7 @@ async def async_is_failed_node(self, node: Node) -> bool:
 
     async def async_get_association_groups(
         self, source: AssociationAddress
-    ) -> Dict[int, AssociationGroup]:
+    ) -> dict[int, AssociationGroup]:
         """Send getAssociationGroups command to Controller."""
         source_data = {"nodeId": source.node_id}
         if source.endpoint is not None:
@@ -498,7 +498,7 @@ async def async_get_association_groups(
 
     async def async_get_associations(
         self, source: AssociationAddress
-    ) -> Dict[int, List[AssociationAddress]]:
+    ) -> dict[int, list[AssociationAddress]]:
         """Send getAssociations command to Controller."""
         source_data = {"nodeId": source.node_id}
         if source.endpoint is not None:
@@ -545,7 +545,7 @@ async def async_add_associations(
         self,
         source: AssociationAddress,
         group: int,
-        associations: List[AssociationAddress],
+        associations: list[AssociationAddress],
         wait_for_result: bool = False,
     ) -> None:
         """Send addAssociations command to Controller."""
@@ -575,7 +575,7 @@ async def async_remove_associations(
         self,
         source: AssociationAddress,
         group: int,
-        associations: List[AssociationAddress],
+        associations: list[AssociationAddress],
         wait_for_result: bool = False,
     ) -> None:
         """Send removeAssociations command to Controller."""
@@ -616,7 +616,7 @@ async def async_remove_node_from_all_associations(
         else:
             await self.client.async_send_command_no_wait(cmd)
 
-    async def async_get_node_neighbors(self, node: Node) -> List[int]:
+    async def async_get_node_neighbors(self, node: Node) -> list[int]:
         """Send getNodeNeighbors command to Controller to get node's neighbors."""
         data = await self.client.async_send_command(
             {
@@ -624,7 +624,7 @@ async def async_get_node_neighbors(self, node: Node) -> List[int]:
                 "nodeId": node.node_id,
             }
         )
-        return cast(List[int], data["neighbors"])
+        return cast(list[int], data["neighbors"])
 
     async def async_grant_security_classes(
         self, inclusion_grant: InclusionGrant
@@ -683,7 +683,7 @@ async def async_restore_nvm(self, file: bytes) -> None:
             require_schema=14,
         )
 
-    async def async_get_power_level(self) -> Dict[str, int]:
+    async def async_get_power_level(self) -> dict[str, int]:
         """Send getPowerlevel command to Controller."""
         data = await self.client.async_send_command(
             {"command": "controller.get_powerlevel"}, require_schema=14
@@ -727,7 +727,7 @@ async def async_set_rf_region(self, rf_region: RFRegion) -> bool:
 
     async def async_get_known_lifeline_routes(
         self,
-    ) -> Dict[Node, ControllerLifelineRoutes]:
+    ) -> dict[Node, ControllerLifelineRoutes]:
         """Send getKnownLifelineRoutes command to Controller."""
         data = await self.client.async_send_command(
             {"command": "controller.get_known_lifeline_routes"}, require_schema=16
@@ -753,7 +753,7 @@ async def async_is_any_ota_firmware_update_in_progress(self) -> bool:
 
     async def async_get_available_firmware_updates(
         self, node: Node, api_key: str, include_prereleases: bool = False
-    ) -> List[NodeFirmwareUpdateInfo]:
+    ) -> list[NodeFirmwareUpdateInfo]:
         """Send getAvailableFirmwareUpdates command to Controller."""
         data = await self.client.async_send_command(
             {
@@ -768,7 +768,7 @@ async def async_get_available_firmware_updates(
         return [NodeFirmwareUpdateInfo.from_dict(update) for update in data["updates"]]
 
     async def async_firmware_update_ota(
-        self, node: Node, updates: List[NodeFirmwareUpdateFileInfo]
+        self, node: Node, updates: list[NodeFirmwareUpdateFileInfo]
     ) -> bool:
         """Send firmwareUpdateOTA command to Controller."""
         data = await self.client.async_send_command(
diff --git a/zwave_js_server/model/controller/data_model.py b/zwave_js_server/model/controller/data_model.py
index a8ff2801e..fcffc5118 100644
--- a/zwave_js_server/model/controller/data_model.py
+++ b/zwave_js_server/model/controller/data_model.py
@@ -1,5 +1,5 @@
 """Data model for a Z-Wave JS controller."""
-from typing import List, TypedDict
+from typing import TypedDict
 
 from .statistics import ControllerStatisticsDataType
 
@@ -21,7 +21,7 @@ class ControllerDataType(TypedDict, total=False):
     manufacturerId: int
     productType: int
     productId: int
-    supportedFunctionTypes: List[int]
+    supportedFunctionTypes: list[int]
     sucNodeId: int
     supportsTimers: bool
     isHealNetworkActive: bool
diff --git a/zwave_js_server/model/controller/event_model.py b/zwave_js_server/model/controller/event_model.py
index e23fb4fc0..ea03525da 100644
--- a/zwave_js_server/model/controller/event_model.py
+++ b/zwave_js_server/model/controller/event_model.py
@@ -1,5 +1,5 @@
 """Provide a model for the Z-Wave JS controller's events."""
-from typing import Dict, Literal, Type, TypedDict
+from typing import Literal, TypedDict
 
 from ...event import BaseEventModel
 from ..node.data_model import FoundNodeDataType, NodeDataType
@@ -66,14 +66,14 @@ class HealNetworkDoneEventModel(BaseControllerEventModel):
     """Model for `heal network done` event data."""
 
     event: Literal["heal network done"]
-    result: Dict[int, str]
+    result: dict[int, str]
 
 
 class HealNetworkProgressEventModel(BaseControllerEventModel):
     """Model for `heal network progress` event data."""
 
     event: Literal["heal network progress"]
-    progress: Dict[int, str]
+    progress: dict[int, str]
 
 
 class InclusionAbortedEventModel(BaseControllerEventModel):
@@ -165,7 +165,7 @@ class ValidateDSKAndEnterPINEventModel(BaseControllerEventModel):
     dsk: str
 
 
-CONTROLLER_EVENT_MODEL_MAP: Dict[str, Type["BaseControllerEventModel"]] = {
+CONTROLLER_EVENT_MODEL_MAP: dict[str, type["BaseControllerEventModel"]] = {
     "exclusion failed": ExclusionFailedEventModel,
     "exclusion started": ExclusionStartedEventModel,
     "exclusion stopped": ExclusionStoppedEventModel,
diff --git a/zwave_js_server/model/controller/inclusion_and_provisioning.py b/zwave_js_server/model/controller/inclusion_and_provisioning.py
index 439395e16..0a7c2b144 100644
--- a/zwave_js_server/model/controller/inclusion_and_provisioning.py
+++ b/zwave_js_server/model/controller/inclusion_and_provisioning.py
@@ -1,6 +1,6 @@
 """Provide a model for the Z-Wave JS controller's inclusion/provisioning data structures."""
 from dataclasses import dataclass
-from typing import Any, Dict, List, Optional, TypedDict
+from typing import Any, Optional, TypedDict
 
 from ...const import Protocols, ProvisioningEntryStatus, QRCodeVersion, SecurityClass
 
@@ -9,7 +9,7 @@ class InclusionGrantDataType(TypedDict):
     """Representation of an inclusion grant data dict type."""
 
     # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L48-L56
-    securityClasses: List[int]
+    securityClasses: list[int]
     clientSideAuth: bool
 
 
@@ -17,7 +17,7 @@ class InclusionGrantDataType(TypedDict):
 class InclusionGrant:
     """Representation of an inclusion grant."""
 
-    security_classes: List[SecurityClass]
+    security_classes: list[SecurityClass]
     client_side_auth: bool
 
     def to_dict(self) -> InclusionGrantDataType:
@@ -43,12 +43,12 @@ class ProvisioningEntry:
     """Class to represent the base fields of a provisioning entry."""
 
     dsk: str
-    security_classes: List[SecurityClass]
-    requested_security_classes: Optional[List[SecurityClass]] = None
+    security_classes: list[SecurityClass]
+    requested_security_classes: Optional[list[SecurityClass]] = None
     status: ProvisioningEntryStatus = ProvisioningEntryStatus.ACTIVE
-    additional_properties: Optional[Dict[str, Any]] = None
+    additional_properties: Optional[dict[str, Any]] = None
 
-    def to_dict(self) -> Dict[str, Any]:
+    def to_dict(self) -> dict[str, Any]:
         """Return PlannedProvisioning data dict from self."""
         data = {
             "dsk": self.dsk,
@@ -63,7 +63,7 @@ def to_dict(self) -> Dict[str, Any]:
         return data
 
     @classmethod
-    def from_dict(cls, data: Dict[str, Any]) -> "ProvisioningEntry":
+    def from_dict(cls, data: dict[str, Any]) -> "ProvisioningEntry":
         """Return ProvisioningEntry from data dict."""
         cls_instance = cls(
             dsk=data["dsk"],
@@ -100,14 +100,14 @@ class QRProvisioningInformationMixin:
     application_version: str
     max_inclusion_request_interval: Optional[int]
     uuid: Optional[str]
-    supported_protocols: Optional[List[Protocols]]
+    supported_protocols: Optional[list[Protocols]]
 
 
 @dataclass
 class QRProvisioningInformation(ProvisioningEntry, QRProvisioningInformationMixin):
     """Representation of provisioning information retrieved from a QR code."""
 
-    def to_dict(self) -> Dict[str, Any]:
+    def to_dict(self) -> dict[str, Any]:
         """Return QRProvisioningInformation data dict from self."""
         data = {
             "version": self.version.value,
@@ -138,7 +138,7 @@ def to_dict(self) -> Dict[str, Any]:
         return data
 
     @classmethod
-    def from_dict(cls, data: Dict[str, Any]) -> "QRProvisioningInformation":
+    def from_dict(cls, data: dict[str, Any]) -> "QRProvisioningInformation":
         """Return QRProvisioningInformation from data dict."""
         cls_instance = cls(
             version=QRCodeVersion(data["version"]),
diff --git a/zwave_js_server/model/device_class.py b/zwave_js_server/model/device_class.py
index d8e7d21a6..4e5f45b7e 100644
--- a/zwave_js_server/model/device_class.py
+++ b/zwave_js_server/model/device_class.py
@@ -5,7 +5,7 @@
 """
 
 from dataclasses import dataclass
-from typing import List, TypedDict
+from typing import TypedDict
 
 
 class DeviceClassItemDataType(TypedDict):
@@ -21,8 +21,8 @@ class DeviceClassDataType(TypedDict):
     basic: DeviceClassItemDataType
     generic: DeviceClassItemDataType
     specific: DeviceClassItemDataType
-    mandatorySupportedCCs: List[int]
-    mandatoryControlledCCs: List[int]
+    mandatorySupportedCCs: list[int]
+    mandatoryControlledCCs: list[int]
 
 
 @dataclass
@@ -56,11 +56,11 @@ def specific(self) -> DeviceClassItem:
         return DeviceClassItem(**self.data["specific"])
 
     @property
-    def mandatory_supported_ccs(self) -> List[int]:
+    def mandatory_supported_ccs(self) -> list[int]:
         """Return list of mandatory Supported CC id's."""
         return self.data["mandatorySupportedCCs"]
 
     @property
-    def mandatory_controlled_ccs(self) -> List[int]:
+    def mandatory_controlled_ccs(self) -> list[int]:
         """Return list of mandatory Controlled CC id's."""
         return self.data["mandatoryControlledCCs"]
diff --git a/zwave_js_server/model/device_config.py b/zwave_js_server/model/device_config.py
index b298143f3..80d6e0c0b 100644
--- a/zwave_js_server/model/device_config.py
+++ b/zwave_js_server/model/device_config.py
@@ -3,7 +3,7 @@
 
 https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig
 """
-from typing import Any, Dict, List, Literal, Optional, TypedDict, Union
+from typing import Any, Literal, Optional, TypedDict, Union
 
 
 class DeviceDeviceDataType(TypedDict, total=False):
@@ -73,7 +73,7 @@ class DeviceMetadataDataType(TypedDict, total=False):
     exclusion: str
     reset: str
     manual: str
-    comments: Union[CommentDataType, List[CommentDataType]]
+    comments: Union[CommentDataType, list[CommentDataType]]
 
 
 class DeviceMetadata:
@@ -109,7 +109,7 @@ def manual(self) -> Optional[str]:
         return self.data.get("manual")
 
     @property
-    def comments(self) -> List[CommentDataType]:
+    def comments(self) -> list[CommentDataType]:
         """Return list of comments about device."""
         comments = self.data.get("comments", [])
         if isinstance(comments, dict):
@@ -125,13 +125,13 @@ class DeviceConfigDataType(TypedDict, total=False):
     manufacturerId: str
     label: str
     description: str
-    devices: List[DeviceDeviceDataType]
+    devices: list[DeviceDeviceDataType]
     firmwareVersion: DeviceFirmwareVersionRangeDataType
-    associations: Dict[str, dict]
-    paramInformation: Dict[str, dict]
+    associations: dict[str, dict]
+    paramInformation: dict[str, dict]
     supportsZWavePlus: bool
     proprietary: dict
-    compat: Dict[str, Any]
+    compat: dict[str, Any]
     metadata: DeviceMetadataDataType
     isEmbedded: bool
 
@@ -176,7 +176,7 @@ def description(self) -> Optional[str]:
         return self.data.get("description")
 
     @property
-    def devices(self) -> List[DeviceDevice]:
+    def devices(self) -> list[DeviceDevice]:
         """Return list of product type and product ID combinations."""
         return self._devices
 
@@ -186,12 +186,12 @@ def firmware_version(self) -> DeviceFirmwareVersionRange:
         return self._firmware_version
 
     @property
-    def associations(self) -> Dict[str, dict]:
+    def associations(self) -> dict[str, dict]:
         """Return dict of association groups the device supports."""
         return self.data.get("associations", {})
 
     @property
-    def param_information(self) -> Dict[str, dict]:
+    def param_information(self) -> dict[str, dict]:
         """Return dictionary of configuration parameters the device supports."""
         return self.data.get("paramInformation", {})
 
@@ -206,7 +206,7 @@ def proprietary(self) -> dict:
         return self.data.get("proprietary", {})
 
     @property
-    def compat(self) -> Dict[str, dict]:
+    def compat(self) -> dict[str, dict]:
         """Return compatibility flags."""
         return self.data.get("compat", {})
 
diff --git a/zwave_js_server/model/driver.py b/zwave_js_server/model/driver.py
index 118ceda47..98985e7b6 100644
--- a/zwave_js_server/model/driver.py
+++ b/zwave_js_server/model/driver.py
@@ -1,5 +1,5 @@
 """Provide a model for the Z-Wave JS Driver."""
-from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, Union, cast
+from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
 
 from pydantic import create_model_from_typeddict
 
@@ -36,7 +36,7 @@ class AllNodesReadyEventModel(BaseDriverEventModel):
 )
 
 
-DRIVER_EVENT_MODEL_MAP: Dict[str, Type["BaseDriverEventModel"]] = {
+DRIVER_EVENT_MODEL_MAP: dict[str, type["BaseDriverEventModel"]] = {
     "all nodes ready": AllNodesReadyEventModel,
     "log config updated": LogConfigUpdatedEventModel,
     "logging": LoggingEventModel,
@@ -155,7 +155,7 @@ async def async_install_config_update(self) -> bool:
         return cast(bool, result["success"])
 
     async def async_set_preferred_scales(
-        self, scales: Dict[Union[str, int], Union[str, int]]
+        self, scales: dict[Union[str, int], Union[str, int]]
     ) -> None:
         """Send command to set preferred sensor scales."""
         await self._async_send_command(
diff --git a/zwave_js_server/model/endpoint.py b/zwave_js_server/model/endpoint.py
index 36cf173a4..4ecbbdcc7 100644
--- a/zwave_js_server/model/endpoint.py
+++ b/zwave_js_server/model/endpoint.py
@@ -4,7 +4,7 @@
 https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=endpoint-properties
 """
 
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, TypedDict, Union, cast
+from typing import TYPE_CHECKING, Any, Optional, TypedDict, Union, cast
 
 from ..const import NodeStatus
 from ..event import EventBase
@@ -27,7 +27,7 @@ class EndpointDataType(TypedDict, total=False):
     installerIcon: int
     userIcon: int
     endpointLabel: str
-    commandClasses: List[CommandClassInfoDataType]
+    commandClasses: list[CommandClassInfoDataType]
 
 
 class Endpoint(EventBase):
@@ -37,13 +37,13 @@ def __init__(
         self,
         client: "Client",
         data: EndpointDataType,
-        values: Dict[str, Union[ConfigurationValue, Value]],
+        values: dict[str, Union[ConfigurationValue, Value]],
     ) -> None:
         """Initialize."""
         super().__init__()
         self.client = client
         self.data: EndpointDataType = {}
-        self.values: Dict[str, Union[ConfigurationValue, Value]] = {}
+        self.values: dict[str, Union[ConfigurationValue, Value]] = {}
         self.update(data, values)
 
     def __repr__(self) -> str:
@@ -90,7 +90,7 @@ def user_icon(self) -> Optional[int]:
         return self.data.get("userIcon")
 
     @property
-    def command_classes(self) -> List[CommandClassInfo]:
+    def command_classes(self) -> list[CommandClassInfo]:
         """Return all CommandClasses supported on this node."""
         return [CommandClassInfo(cc) for cc in self.data["commandClasses"]]
 
@@ -102,7 +102,7 @@ def endpoint_label(self) -> Optional[str]:
     def update(
         self,
         data: EndpointDataType,
-        values: Dict[str, Union[ConfigurationValue, Value]],
+        values: dict[str, Union[ConfigurationValue, Value]],
     ) -> None:
         """Update the endpoint data."""
         self.data = data
@@ -123,7 +123,7 @@ async def async_send_command(
         require_schema: Optional[int] = None,
         wait_for_result: Optional[bool] = None,
         **cmd_kwargs: Any,
-    ) -> Optional[Dict[str, Any]]:
+    ) -> Optional[dict[str, Any]]:
         """
         Send an endpoint command. For internal use only.
 
diff --git a/zwave_js_server/model/log_message.py b/zwave_js_server/model/log_message.py
index 1dcd9f905..dbd5f3a69 100644
--- a/zwave_js_server/model/log_message.py
+++ b/zwave_js_server/model/log_message.py
@@ -1,5 +1,5 @@
 """Provide a model for a log message event."""
-from typing import List, Literal, Optional, TypedDict, Union
+from typing import Literal, Optional, TypedDict, Union
 
 from ..const import CommandClass
 
@@ -92,8 +92,8 @@ class LogMessageDataType(TypedDict, total=False):
 
     source: Literal["driver"]  # required
     event: Literal["logging"]  # required
-    message: Union[str, List[str]]  # required
-    formattedMessage: Union[str, List[str]]  # required
+    message: Union[str, list[str]]  # required
+    formattedMessage: Union[str, list[str]]  # required
     direction: str  # required
     level: str  # required
     context: LogMessageContextDataType  # required
@@ -114,7 +114,7 @@ def __init__(self, data: LogMessageDataType):
 
     def _process_message(
         self, field_name: Union[Literal["message"], Literal["formattedMessage"]]
-    ) -> List[str]:
+    ) -> list[str]:
         """Process a message and always return a list."""
         if isinstance(self.data[field_name], str):
             return str(self.data[field_name]).splitlines()
@@ -124,12 +124,12 @@ def _process_message(
         return [message.rstrip("\n") for message in self.data[field_name]]
 
     @property
-    def message(self) -> List[str]:
+    def message(self) -> list[str]:
         """Return message."""
         return self._process_message("message")
 
     @property
-    def formatted_message(self) -> List[str]:
+    def formatted_message(self) -> list[str]:
         """Return fully formatted message."""
         return self._process_message("formattedMessage")
 
diff --git a/zwave_js_server/model/node/__init__.py b/zwave_js_server/model/node/__init__.py
index fbf62477e..b4bc8078e 100644
--- a/zwave_js_server/model/node/__init__.py
+++ b/zwave_js_server/model/node/__init__.py
@@ -1,6 +1,6 @@
 """Provide a model for the Z-Wave JS node."""
 import logging
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
+from typing import TYPE_CHECKING, Any, Optional, Union, cast
 
 from ...const import (
     INTERVIEW_FAILED,
@@ -66,7 +66,7 @@
 _LOGGER = logging.getLogger(__package__)
 
 
-def _get_value_id_dict_from_value_data(value_data: ValueDataType) -> Dict[str, Any]:
+def _get_value_id_dict_from_value_data(value_data: ValueDataType) -> dict[str, Any]:
     """Return a value ID dict from ValueDataType."""
     data = {
         "commandClass": value_data["commandClass"],
@@ -92,8 +92,8 @@ def __init__(self, client: "Client", data: NodeDataType) -> None:
         self._device_config = DeviceConfig({})
         self._statistics = NodeStatistics(client, data.get("statistics"))
         self._firmware_update_progress: Optional[NodeFirmwareUpdateProgress] = None
-        self.values: Dict[str, Union[ConfigurationValue, Value]] = {}
-        self.endpoints: Dict[int, Endpoint] = {}
+        self.values: dict[str, Union[ConfigurationValue, Value]] = {}
+        self.endpoints: dict[int, Endpoint] = {}
         self.update(data)
 
     def __repr__(self) -> str:
@@ -168,7 +168,7 @@ def max_data_rate(self) -> Optional[int]:
         return self.data.get("maxDataRate")
 
     @property
-    def supported_data_rates(self) -> List[int]:
+    def supported_data_rates(self) -> list[int]:
         """Return the supported_data_rates."""
         return self.data.get("supportedDataRates", [])
 
@@ -299,7 +299,7 @@ def awaiting_manual_interview(self) -> bool:
         return self.interview_stage in (None, NOT_INTERVIEWED)
 
     @property
-    def command_classes(self) -> List[CommandClassInfo]:
+    def command_classes(self) -> list[CommandClassInfo]:
         """Return all CommandClasses supported on this node."""
         return self.endpoints[0].command_classes
 
@@ -381,7 +381,7 @@ def update(self, data: NodeDataType) -> None:
 
     def get_command_class_values(
         self, command_class: CommandClass, endpoint: Optional[int] = None
-    ) -> Dict[str, Union[ConfigurationValue, Value]]:
+    ) -> dict[str, Union[ConfigurationValue, Value]]:
         """Return all values for a given command class."""
         return {
             value_id: value
@@ -390,10 +390,10 @@ def get_command_class_values(
             and (endpoint is None or value.endpoint == endpoint)
         }
 
-    def get_configuration_values(self) -> Dict[str, ConfigurationValue]:
+    def get_configuration_values(self) -> dict[str, ConfigurationValue]:
         """Return all configuration values for a node."""
         return cast(
-            Dict[str, ConfigurationValue],
+            dict[str, ConfigurationValue],
             self.get_command_class_values(CommandClass.CONFIGURATION),
         )
 
@@ -412,7 +412,7 @@ async def async_send_command(
         require_schema: Optional[int] = None,
         wait_for_result: Optional[bool] = None,
         **cmd_kwargs: Any,
-    ) -> Optional[Dict[str, Any]]:
+    ) -> Optional[dict[str, Any]]:
         """
         Send a node command. For internal use only.
 
@@ -498,7 +498,7 @@ async def async_refresh_cc_values(self, command_class: CommandClass) -> None:
             require_schema=4,
         )
 
-    async def async_get_defined_value_ids(self) -> List[Value]:
+    async def async_get_defined_value_ids(self) -> list[Value]:
         """Send getDefinedValueIDs command to Node."""
         data = await self.async_send_command(
             "get_defined_value_ids", wait_for_result=True
diff --git a/zwave_js_server/model/node/data_model.py b/zwave_js_server/model/node/data_model.py
index b181ce34e..f9cadaa12 100644
--- a/zwave_js_server/model/node/data_model.py
+++ b/zwave_js_server/model/node/data_model.py
@@ -1,5 +1,5 @@
 """Data model for a Z-Wave JS node."""
-from typing import List, Literal, Optional, TypedDict, Union
+from typing import Literal, Optional, TypedDict, Union
 
 from ..device_class import DeviceClassDataType
 from ..device_config import DeviceConfigDataType
@@ -13,8 +13,8 @@ class FoundNodeDataType(TypedDict, total=False):
 
     nodeId: int
     deviceClass: DeviceClassDataType
-    supportedCCs: List[int]
-    controlledCCs: List[int]
+    supportedCCs: list[int]
+    controlledCCs: list[int]
 
 
 class NodeDataType(TypedDict, total=False):
@@ -35,7 +35,7 @@ class NodeDataType(TypedDict, total=False):
     isFrequentListening: Union[bool, str]
     isRouting: bool
     maxDataRate: int
-    supportedDataRates: List[int]
+    supportedDataRates: list[int]
     isSecure: Union[bool, Literal["unknown"]]
     supportsBeaming: bool
     supportsSecurity: bool
@@ -49,14 +49,14 @@ class NodeDataType(TypedDict, total=False):
     keepAwake: bool
     ready: bool
     label: str
-    endpoints: List[EndpointDataType]
+    endpoints: list[EndpointDataType]
     endpointCountIsDynamic: bool
     endpointsHaveIdenticalCapabilities: bool
     individualEndpointCount: int
     aggregatedEndpointCount: int
     interviewAttempts: int
     interviewStage: Optional[Union[int, str]]
-    values: List[ValueDataType]
+    values: list[ValueDataType]
     statistics: NodeStatisticsDataType
     highestSecurityClass: int
     isControllerNode: bool
diff --git a/zwave_js_server/model/node/event_model.py b/zwave_js_server/model/node/event_model.py
index 80551f98f..0b8717661 100644
--- a/zwave_js_server/model/node/event_model.py
+++ b/zwave_js_server/model/node/event_model.py
@@ -1,5 +1,5 @@
 """Provide a model for the Z-Wave JS node's events."""
-from typing import Dict, Literal, Optional, Type, Union
+from typing import Literal, Optional, Union
 
 from pydantic import BaseModel
 
@@ -199,7 +199,7 @@ class FirmwareUpdateProgressEventModel(BaseNodeEventModel):
     progress: NodeFirmwareUpdateProgressDataType
 
 
-NODE_EVENT_MODEL_MAP: Dict[str, Type["BaseNodeEventModel"]] = {
+NODE_EVENT_MODEL_MAP: dict[str, type["BaseNodeEventModel"]] = {
     "alive": AliveEventModel,
     "check lifeline health progress": CheckLifelineHealthProgressEventModel,
     "check route health progress": CheckRouteHealthProgressEventModel,
diff --git a/zwave_js_server/model/node/firmware.py b/zwave_js_server/model/node/firmware.py
index 4f59d2b0d..d511d9a95 100644
--- a/zwave_js_server/model/node/firmware.py
+++ b/zwave_js_server/model/node/firmware.py
@@ -1,7 +1,7 @@
 """Provide a model for Z-Wave firmware."""
 from dataclasses import asdict, dataclass
 from enum import IntEnum
-from typing import TYPE_CHECKING, List, Optional, TypedDict, Union, cast
+from typing import TYPE_CHECKING, Optional, TypedDict, Union, cast
 
 from ...const import VALUE_UNKNOWN
 from ...util.helpers import convert_bytes_to_base64
@@ -45,7 +45,7 @@ class NodeFirmwareUpdateCapabilitiesDataType(TypedDict, total=False):
     """Represent a firmware update capabilities dict type."""
 
     firmwareUpgradable: bool  # required
-    firmwareTargets: List[int]
+    firmwareTargets: list[int]
     continuesToFunction: Union[bool, str]
     supportsActivation: Union[bool, str]
 
@@ -54,7 +54,7 @@ class NodeFirmwareUpdateCapabilitiesDict(TypedDict, total=False):
     """Represent a dict from FirmwareUpdateCapabilities."""
 
     firmware_upgradable: bool  # required
-    firmware_targets: List[int]
+    firmware_targets: list[int]
     continues_to_function: Optional[bool]
     supports_activation: Optional[bool]
 
@@ -72,7 +72,7 @@ def firmware_upgradable(self) -> bool:
         return self.data["firmwareUpgradable"]
 
     @property
-    def firmware_targets(self) -> List[int]:
+    def firmware_targets(self) -> list[int]:
         """Return firmware targets."""
         if not self.firmware_upgradable:
             raise TypeError("Firmware is not upgradeable.")
@@ -239,7 +239,7 @@ class NodeFirmwareUpdateInfoDataType(TypedDict):
 
     version: str
     changelog: str
-    files: List[NodeFirmwareUpdateFileInfoDataType]
+    files: list[NodeFirmwareUpdateFileInfoDataType]
 
 
 @dataclass
@@ -248,7 +248,7 @@ class NodeFirmwareUpdateInfo:
 
     version: str
     changelog: str
-    files: List[NodeFirmwareUpdateFileInfo]
+    files: list[NodeFirmwareUpdateFileInfo]
 
     @classmethod
     def from_dict(
diff --git a/zwave_js_server/model/node/health_check.py b/zwave_js_server/model/node/health_check.py
index c8d15abaf..4ad11ff42 100644
--- a/zwave_js_server/model/node/health_check.py
+++ b/zwave_js_server/model/node/health_check.py
@@ -1,6 +1,6 @@
 """Provide a model for the Z-Wave JS node's health checks and power tests."""
 from dataclasses import dataclass
-from typing import List, Optional, TypedDict
+from typing import Optional, TypedDict
 
 from ...const import PowerLevel
 
@@ -22,7 +22,7 @@ class LifelineHealthCheckSummaryDataType(TypedDict):
     """Represent a lifeline health check summary data dict type."""
 
     # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/Types.ts#L211
-    results: List[LifelineHealthCheckResultDataType]
+    results: list[LifelineHealthCheckResultDataType]
     rating: int
 
 
@@ -86,7 +86,7 @@ def rating(self) -> int:
         return self._rating
 
     @property
-    def results(self) -> List[LifelineHealthCheckResult]:
+    def results(self) -> list[LifelineHealthCheckResult]:
         """Return lifeline health check results."""
         return self._results
 
@@ -107,7 +107,7 @@ class RouteHealthCheckSummaryDataType(TypedDict):
     """Represent a route health check summary data dict type."""
 
     # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/Types.ts#L274
-    results: List[RouteHealthCheckResultDataType]
+    results: list[RouteHealthCheckResultDataType]
     rating: int
 
 
@@ -169,7 +169,7 @@ def rating(self) -> int:
         return self._rating
 
     @property
-    def results(self) -> List[RouteHealthCheckResult]:
+    def results(self) -> list[RouteHealthCheckResult]:
         """Return route health check results."""
         return self._results
 
diff --git a/zwave_js_server/model/notification.py b/zwave_js_server/model/notification.py
index 849971e67..c59d607fb 100644
--- a/zwave_js_server/model/notification.py
+++ b/zwave_js_server/model/notification.py
@@ -4,7 +4,7 @@
 https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotnotificationquot
 """
 
-from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, TypedDict, Union
+from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union
 
 from ..const.command_class.multilevel_switch import MultilevelSwitchCommand
 from ..const.command_class.power_level import PowerLevelTestStatus
@@ -30,7 +30,7 @@ class EntryControlNotificationArgsDataType(TypedDict, total=False):
     eventTypeLabel: str  # required
     dataType: int  # required
     dataTypeLabel: str  # required
-    eventData: Union[str, Dict[str, Any]]
+    eventData: Union[str, dict[str, Any]]
 
 
 class EntryControlNotificationDataType(BaseNotificationDataType):
@@ -92,7 +92,7 @@ class NotificationNotificationArgsDataType(TypedDict, total=False):
     label: str  # required
     event: int  # required
     eventLabel: str  # required
-    parameters: Dict[str, Any]
+    parameters: dict[str, Any]
 
 
 class NotificationNotificationDataType(BaseNotificationDataType):
@@ -140,7 +140,7 @@ def event_label(self) -> str:
         return self.data["args"]["eventLabel"]
 
     @property
-    def parameters(self) -> Dict[str, Any]:
+    def parameters(self) -> dict[str, Any]:
         """Return installer icon property."""
         return self.data["args"].get("parameters", {})
 
diff --git a/zwave_js_server/model/statistics.py b/zwave_js_server/model/statistics.py
index 8d1802d34..c5e8d957d 100644
--- a/zwave_js_server/model/statistics.py
+++ b/zwave_js_server/model/statistics.py
@@ -1,6 +1,6 @@
 """Common models for statistics."""
 from dataclasses import dataclass
-from typing import TYPE_CHECKING, List, Optional, Tuple, TypedDict
+from typing import TYPE_CHECKING, Optional, TypedDict
 
 from zwave_js_server.exceptions import RepeaterRssiErrorReceived, RssiErrorReceived
 
@@ -15,20 +15,20 @@ class RouteStatisticsDataType(TypedDict, total=False):
     """Represent a route statistics data dict type."""
 
     protocolDataRate: int
-    repeaters: List[int]
+    repeaters: list[int]
     rssi: int
-    repeaterRSSI: List[int]
-    routeFailedBetween: List[int]
+    repeaterRSSI: list[int]
+    routeFailedBetween: list[int]
 
 
 class RouteStatisticsDict(TypedDict):
     """Represent a route statistics data dict type."""
 
     protocol_data_rate: int
-    repeaters: List["Node"]
+    repeaters: list["Node"]
     rssi: Optional[int]
-    repeater_rssi: List[int]
-    route_failed_between: Optional[Tuple["Node", "Node"]]
+    repeater_rssi: list[int]
+    route_failed_between: Optional[tuple["Node", "Node"]]
 
 
 @dataclass
@@ -46,7 +46,7 @@ def protocol_data_rate(self) -> ProtocolDataRate:
         return ProtocolDataRate(self.data["protocolDataRate"])
 
     @property
-    def repeaters(self) -> List["Node"]:
+    def repeaters(self) -> list["Node"]:
         """Return repeaters."""
         assert self.client.driver
         return [
@@ -64,7 +64,7 @@ def rssi(self) -> Optional[int]:
         return rssi
 
     @property
-    def repeater_rssi(self) -> List[int]:
+    def repeater_rssi(self) -> list[int]:
         """Return repeater RSSI."""
         repeater_rssi = self.data.get("repeaterRSSI", [])
         rssi_errors = [item.value for item in RssiError]
@@ -74,7 +74,7 @@ def repeater_rssi(self) -> List[int]:
         return repeater_rssi
 
     @property
-    def route_failed_between(self) -> Optional[Tuple["Node", "Node"]]:
+    def route_failed_between(self) -> Optional[tuple["Node", "Node"]]:
         """Return route failed between."""
         if (node_ids := self.data.get("routeFailedBetween")) is None:
             return None
diff --git a/zwave_js_server/model/value.py b/zwave_js_server/model/value.py
index db295d66a..d95e23a47 100644
--- a/zwave_js_server/model/value.py
+++ b/zwave_js_server/model/value.py
@@ -1,5 +1,5 @@
 """Provide a model for the Z-Wave JS value."""
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, TypedDict, Union
+from typing import TYPE_CHECKING, Any, Optional, TypedDict, Union
 
 from ..const import VALUE_UNKNOWN, CommandClass, ConfigurationValueType
 from ..event import Event
@@ -20,9 +20,9 @@ class MetaDataType(TypedDict, total=False):
     min: int
     max: int
     unit: str
-    states: Dict[int, str]
-    ccSpecific: Dict[str, Any]
-    valueChangeOptions: List[str]
+    states: dict[int, str]
+    ccSpecific: dict[str, Any]
+    valueChangeOptions: list[str]
     allowManualEntry: bool
     valueSize: int
 
@@ -134,12 +134,12 @@ def states(self) -> dict:
         return self.data.get("states", {})
 
     @property
-    def cc_specific(self) -> Dict[str, Any]:
+    def cc_specific(self) -> dict[str, Any]:
         """Return ccSpecific."""
         return self.data.get("ccSpecific", {})
 
     @property
-    def value_change_options(self) -> List[str]:
+    def value_change_options(self) -> list[str]:
         """Return valueChangeOptions."""
         return self.data.get("valueChangeOptions", [])
 
diff --git a/zwave_js_server/util/helpers.py b/zwave_js_server/util/helpers.py
index e1cabee60..1b11ce8b1 100644
--- a/zwave_js_server/util/helpers.py
+++ b/zwave_js_server/util/helpers.py
@@ -1,7 +1,7 @@
 """Generic Utility helper functions."""
 import base64
 import json
-from typing import Any, Dict, Union
+from typing import Any, Union
 
 from ..exceptions import UnparseableValue
 
@@ -22,7 +22,7 @@ def convert_base64_to_bytes(data: str) -> bytes:
     return base64.b64decode(data)
 
 
-def parse_buffer(value: Union[Dict[str, Any], str]) -> str:
+def parse_buffer(value: Union[dict[str, Any], str]) -> str:
     """Parse value from a buffer data type."""
     if isinstance(value, dict):
         return parse_buffer_from_dict(value)
@@ -33,7 +33,7 @@ def parse_buffer(value: Union[Dict[str, Any], str]) -> str:
     return value
 
 
-def parse_buffer_from_dict(value: Dict[str, Any]) -> str:
+def parse_buffer_from_dict(value: dict[str, Any]) -> str:
     """Parse value dictionary from a buffer data type."""
     if value.get("type") != "Buffer" or "data" not in value:
         raise UnparseableValue(f"Unparseable value: {value}") from ValueError(
diff --git a/zwave_js_server/util/lock.py b/zwave_js_server/util/lock.py
index 6757d36fa..110beea03 100644
--- a/zwave_js_server/util/lock.py
+++ b/zwave_js_server/util/lock.py
@@ -1,5 +1,5 @@
 """Utility functions for Z-Wave JS locks."""
-from typing import Dict, List, Optional, Union
+from typing import Optional, Union
 
 from ..const import CommandClass
 from ..const.command_class.lock import (
@@ -36,10 +36,10 @@ def get_code_slot_value(node: Node, code_slot: int, property_name: str) -> Value
 
 def _get_code_slots(
     node: Node, include_usercode: bool = False
-) -> List[Dict[str, Optional[Union[int, bool, str]]]]:
+) -> list[dict[str, Optional[Union[int, bool, str]]]]:
     """Get all code slots on the lock and optionally include usercode."""
     code_slot = 1
-    slots: List[Dict[str, Optional[Union[int, bool, str]]]] = []
+    slots: list[dict[str, Optional[Union[int, bool, str]]]] = []
 
     # Loop until we can't find a code slot
     while True:
@@ -72,12 +72,12 @@ def _get_code_slots(
         code_slot += 1
 
 
-def get_code_slots(node: Node) -> List[Dict[str, Optional[Union[int, bool, str]]]]:
+def get_code_slots(node: Node) -> list[dict[str, Optional[Union[int, bool, str]]]]:
     """Get all code slots on the lock and whether or not they are used."""
     return _get_code_slots(node, False)
 
 
-def get_usercodes(node: Node) -> List[Dict[str, Optional[Union[int, bool, str]]]]:
+def get_usercodes(node: Node) -> list[dict[str, Optional[Union[int, bool, str]]]]:
     """Get all code slots and usercodes on the lock."""
     return _get_code_slots(node, True)
 
@@ -90,7 +90,7 @@ def get_usercode(node: Node, code_slot: int) -> Optional[str]:
 
 async def get_usercode_from_node(
     node: Node, code_slot: int
-) -> Dict[str, Union[str, bool]]:
+) -> dict[str, Union[str, bool]]:
     """
     Fetch a usercode directly from a node.
 
diff --git a/zwave_js_server/util/multicast.py b/zwave_js_server/util/multicast.py
index a54bb3a65..3dae85fcd 100644
--- a/zwave_js_server/util/multicast.py
+++ b/zwave_js_server/util/multicast.py
@@ -1,5 +1,5 @@
 """Support for multicast commands."""
-from typing import Any, List, Optional, cast
+from typing import Any, Optional, cast
 
 from ..client import Client
 from ..const import TARGET_VALUE_PROPERTY, CommandClass
@@ -11,7 +11,7 @@
 async def _async_send_command(
     client: Client,
     command: str,
-    nodes: Optional[List[Node]] = None,
+    nodes: Optional[list[Node]] = None,
     require_schema: Optional[int] = None,
     **kwargs: Any,
 ) -> dict:
@@ -32,7 +32,7 @@ async def async_multicast_set_value(
     client: Client,
     new_value: Any,
     value_data: ValueDataType,
-    nodes: Optional[List[Node]] = None,
+    nodes: Optional[list[Node]] = None,
     options: Optional[dict] = None,
 ) -> bool:
     """Send a multicast set_value command."""
@@ -69,7 +69,7 @@ async def async_multicast_set_value(
 
 
 async def async_multicast_get_endpoint_count(
-    client: Client, nodes: Optional[List[Node]] = None
+    client: Client, nodes: Optional[list[Node]] = None
 ) -> int:
     """Send a multicast get_endpoint_count command."""
     result = await _async_send_command(
@@ -82,7 +82,7 @@ async def async_multicast_endpoint_supports_cc(
     client: Client,
     endpoint: int,
     command_class: CommandClass,
-    nodes: Optional[List[Node]] = None,
+    nodes: Optional[list[Node]] = None,
 ) -> bool:
     """Send a supports_cc command to a multicast endpoint."""
     result = await _async_send_command(
@@ -100,7 +100,7 @@ async def async_multicast_endpoint_get_cc_version(
     client: Client,
     endpoint: int,
     command_class: CommandClass,
-    nodes: Optional[List[Node]] = None,
+    nodes: Optional[list[Node]] = None,
 ) -> int:
     """Send a get_cc_version command to a multicast endpoint."""
     result = await _async_send_command(
@@ -119,8 +119,8 @@ async def async_multicast_endpoint_invoke_cc_api(
     endpoint: int,
     command_class: CommandClass,
     method_name: str,
-    args: Optional[List[Any]] = None,
-    nodes: Optional[List[Node]] = None,
+    args: Optional[list[Any]] = None,
+    nodes: Optional[list[Node]] = None,
 ) -> Any:
     """Send a invoke_cc_api command to a multicast endpoint."""
     result = await _async_send_command(
@@ -140,7 +140,7 @@ async def async_multicast_endpoint_supports_cc_api(
     client: Client,
     endpoint: int,
     command_class: CommandClass,
-    nodes: Optional[List[Node]] = None,
+    nodes: Optional[list[Node]] = None,
 ) -> bool:
     """Send a supports_cc_api command to a multicast endpoint."""
     result = await _async_send_command(
diff --git a/zwave_js_server/util/node.py b/zwave_js_server/util/node.py
index bc2901be0..9ab23ab70 100644
--- a/zwave_js_server/util/node.py
+++ b/zwave_js_server/util/node.py
@@ -1,7 +1,7 @@
 """Utility functions for Z-Wave JS nodes."""
 import json
 import logging
-from typing import Dict, Optional, Tuple, Union, cast
+from typing import Optional, Union, cast
 
 from ..const import CommandClass, CommandStatus, ConfigurationValueType
 from ..exceptions import (
@@ -29,7 +29,7 @@ async def async_set_config_parameter(
     new_value: Union[int, str],
     property_or_property_name: Union[int, str],
     property_key: Optional[Union[int, str]] = None,
-) -> Tuple[ConfigurationValue, CommandStatus]:
+) -> tuple[ConfigurationValue, CommandStatus]:
     """
     Set a value for a config parameter on this node.
 
@@ -87,7 +87,7 @@ async def async_set_config_parameter(
 async def async_bulk_set_partial_config_parameters(
     node: Node,
     property_: int,
-    new_value: Union[int, Dict[Union[int, str], Union[int, str]]],
+    new_value: Union[int, dict[Union[int, str], Union[int, str]]],
 ) -> CommandStatus:
     """Bulk set partial configuration values on this node."""
     config_values = node.get_configuration_values()
@@ -248,9 +248,9 @@ def _bulk_set_validate_and_transform_new_value(
 
 def _get_int_from_partials_dict(
     node: Node,
-    partial_param_values: Dict[str, ConfigurationValue],
+    partial_param_values: dict[str, ConfigurationValue],
     property_: int,
-    new_value: Dict[Union[int, str], Union[int, str]],
+    new_value: dict[Union[int, str], Union[int, str]],
 ) -> int:
     """Take an input dict for a set of partial values and compute the raw int value."""
     int_value = 0
@@ -308,7 +308,7 @@ def _get_int_from_partials_dict(
 
 
 def _validate_raw_int(
-    partial_param_values: Dict[str, ConfigurationValue], new_value: int
+    partial_param_values: dict[str, ConfigurationValue], new_value: int
 ) -> None:
     """
     Validate raw value against all partial values.


Test patch:
diff --git a/test/conftest.py b/test/conftest.py
index 362cf9a63..f4823b686 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -3,7 +3,6 @@
 import json
 from collections import deque
 from copy import deepcopy
-from typing import List, Tuple
 from unittest.mock import AsyncMock, Mock, patch
 
 import pytest
@@ -296,12 +295,12 @@ async def client_fixture(client_session, ws_client, uuid4):
 @pytest.fixture(name="mock_command")
 def mock_command_fixture(ws_client, client, uuid4):
     """Mock a command and response."""
-    mock_responses: List[Tuple[dict, dict, bool]] = []
-    ack_commands: List[dict] = []
+    mock_responses: list[tuple[dict, dict, bool]] = []
+    ack_commands: list[dict] = []
 
     def apply_mock_command(
         match_command: dict, response: dict, success: bool = True
-    ) -> List[dict]:
+    ) -> list[dict]:
         """Apply the mock command and response return value to the transport.
 
         Return the list with correctly acknowledged commands.