diff --git a/README.md b/README.md
index 0cc147b81e952e6a19d36ee3632d54a23bd11d6c..20dce74051d6801983b6b7a7eb37b94818829cdc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/mkp/cisco_meraki-1.3.7-20241116.mkp "cisco_meraki-1.3.7-20241116.mkp"
+[PACKAGE]: ../../raw/master/mkp/cisco_meraki-1.4.1-20241217.mkp "cisco_meraki-1.4.1-20241217.mkp"
 [SDK]: ../../raw/master/mkp/MerakiSDK-1.52.0-20241116.mkp "MerakiSDK-1.52.0-20241116.mkp"
 # Cisco Meraki special agent
 
diff --git a/mkp/cisco_meraki-1.4.1-20241217.mkp b/mkp/cisco_meraki-1.4.1-20241217.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..517e79d7a5a922b5e93427c2db53138760c470c4
Binary files /dev/null and b/mkp/cisco_meraki-1.4.1-20241217.mkp differ
diff --git a/source/agent_based/cisco_meraki_org_device_status.py b/source/agent_based/cisco_meraki_org_device_status.py
index 56b1c6feff8c3d562e4fd8c93c704a8ac9e0efc5..5a0d4ac111013d1a1b06a0211ddaf790aa198f95 100644
--- a/source/agent_based/cisco_meraki_org_device_status.py
+++ b/source/agent_based/cisco_meraki_org_device_status.py
@@ -3,7 +3,7 @@
 # Copyright (C) 2022 Checkmk GmbH - License: GNU General Public License v2
 # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
 # conditions defined in the file COPYING, which is part of this source code package.
-
+from cmk.gui.forms import section
 # enhancements by thl-cmk[at]outlook[dot]com, https://thl-cmk.hopto.org
 # - made device status configurable via WATO
 # - added last_reported as check_levels, levels_upper can be configured via WATO
diff --git a/source/cmk_addons_plugins/meraki/agent_based/appliance_uplinks.py b/source/cmk_addons_plugins/meraki/agent_based/appliance_uplinks.py
index 7a093bf6ffadf5e3bc95ff813d5fe1c005eb2343..4fb45ed029fd10366be670aa12b0a51ef439bd4c 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/appliance_uplinks.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/appliance_uplinks.py
@@ -14,11 +14,12 @@
 # 2024-05-15: fixed typo in output of uplink.received (in -> In) (ThX to Rickard Eriksson)
 #             moved parse function to the dataclasses
 # 2024-05-19: reworked appliance uplinks usage
-# 2024-04-24: fixed, we can have no traffic if uplinc is not connected
+# 2024-04-24: fixed, we can have no traffic if uplink is not connected
 # 2024-06-29: refactored for CMK 2.3
-#             changed service name from "Appliance Uplink" to "Uplink"
+#             changed service name from 'Appliance Uplink' to 'Uplink'
 #             fixed render function for bandwidth -> uses now render.networkbandwidth
 # 2024-06-30: renamed from cisco_meraki_org_appliance_uplinks.py in to appliance_uplinks.py
+# 2024-12-13: added connecting to _STATUS_MAP
 
 from collections.abc import Mapping
 from dataclasses import dataclass
@@ -61,8 +62,8 @@ __appliance_uplinks = [
                 'publicIp': '20.197.135.251',
                 'secondaryDns': '9.9.9.9',
                 'status': 'active',
-                "received": 52320006,  # bytes
-                "sent": 52928038,  # bytes
+                'received': 52320006,  # bytes
+                'sent': 52928038,  # bytes
             },
             {
                 'gateway': '192.168.5.100',
@@ -78,7 +79,7 @@ __appliance_uplinks = [
     }
 ]
 
-_LAST_REPORTED_AT = "%Y-%m-%dT%H:%M:%SZ"
+_LAST_REPORTED_AT = '%Y-%m-%dT%H:%M:%SZ'
 
 
 @dataclass(frozen=True)
@@ -152,7 +153,7 @@ def parse_appliance_uplinks(string_table: StringTable) -> Appliance | None:
 
 
 agent_section_cisco_meraki_org_appliance_uplinks = AgentSection(
-    name="cisco_meraki_org_appliance_uplinks",
+    name='cisco_meraki_org_appliance_uplinks',
     parse_function=parse_appliance_uplinks,
 )
 
@@ -163,10 +164,11 @@ def discover_appliance_uplinks(section: Appliance) -> DiscoveryResult:
 
 
 _STATUS_MAP = {
-    "active": 0,
-    "failed": 2,
-    "not_connected": 1,
-    "ready": 0,
+    'active': 0,
+    'failed': 2,
+    'not_connected': 1,
+    'ready': 0,
+    'connecting': 1,
 }
 _TIMESPAN = 60
 
diff --git a/source/cmk_addons_plugins/meraki/agent_based/appliance_vpns.py b/source/cmk_addons_plugins/meraki/agent_based/appliance_vpns.py
index b163e2e8973d3df7a15e16bae1747ca9f8031855..38632f82eababbe95b45605ecd888125ca98b408 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/appliance_vpns.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/appliance_vpns.py
@@ -180,11 +180,11 @@ def check_appliance_vpns(item: str, params: Mapping[str, any], section: Mapping[
         return None
 
     if peer.reachability is not None and peer.reachability.lower() in ['reachable']:
-        yield Result(state=State.OK, summary=f'{peer.reachability}')
+        yield Result(state=State.OK, summary=f'Status: {peer.reachability}')
     else:
         yield Result(
             state=State(params.get('status_not_reachable', 1)),
-            summary=f'{peer.reachability}',
+            summary=f'Status: {peer.reachability}',
         )
 
     yield Result(state=State.OK, summary=f'Type: {peer.type}')
diff --git a/source/cmk_addons_plugins/meraki/agent_based/cellular_uplinks.py b/source/cmk_addons_plugins/meraki/agent_based/cellular_uplinks.py
index 2c9df386bac7c2b34713248dab4c659d6841fe95..c502b480df116d9fbf4992843c9e3d85e17bfd84 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/cellular_uplinks.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/cellular_uplinks.py
@@ -11,7 +11,7 @@
 # 2024-04-27: made data parsing more robust
 # 2024-06-29: refactored for CMK 2.3
 #             moved parse functions to class methods
-#             changed service name from "Cellular uplink" to "Uplink"
+#             changed service name from 'Cellular uplink' to 'Uplink'
 # 2024-06-30: renamed from cisco_meraki_org_cellular_uplinks.py in to cellular_uplinks.py
 
 from collections.abc import Mapping
@@ -35,39 +35,39 @@ from cmk_addons.plugins.meraki.lib.utils import get_int, load_json
 
 __cellular_uplinks = [
     {
-        "highAvailability": {
-            "enabled": False,
-            "role": "primary"
+        'highAvailability': {
+            'enabled': False,
+            'role': 'primary'
         },
-        "lastReportedAt": "2023-11-13T19:52:06Z",
-        "model": "MG41",
-        "networkId": "L_575897802350012343",
-        "serial": "QQQQ-XXXX-ZZZZ",
-        "uplinks": [
+        'lastReportedAt': '2023-11-13T19:52:06Z',
+        'model': 'MG41',
+        'networkId': 'L_575897802350012343',
+        'serial': 'QQQQ-XXXX-ZZZZ',
+        'uplinks': [
             {
-                "apn": "apn.name",
-                "connectionType": "lte",
-                "dns1": None,
-                "dns2": None,
-                "gateway": None,
-                "iccid": "89492027206012345518",
-                "interface": "cellular",
-                "ip": None,
-                "model": "integrated",
-                "provider": "provider.name",
-                "publicIp": "2.3.4.5",
-                "signalStat": {
-                    "rsrp": "-111",
-                    "rsrq": "-8"
+                'apn': 'apn.name',
+                'connectionType': 'lte',
+                'dns1': None,
+                'dns2': None,
+                'gateway': None,
+                'iccid': '89492027206012345518',
+                'interface': 'cellular',
+                'ip': None,
+                'model': 'integrated',
+                'provider': 'provider.name',
+                'publicIp': '2.3.4.5',
+                'signalStat': {
+                    'rsrp': '-111',
+                    'rsrq': '-8'
                 },
-                "signalType": None,
-                "status": "active"
+                'signalType': None,
+                'status': 'active'
             }
         ]
     }
 ]
 
-_LAST_REPORTED_AT = "%Y-%m-%dT%H:%M:%SZ"
+_LAST_REPORTED_AT = '%Y-%m-%dT%H:%M:%SZ'
 
 
 @dataclass(frozen=True)
@@ -159,7 +159,7 @@ def parse_cellular_uplinks(string_table: StringTable) -> CellularGateway | None:
 
 
 agent_section_cisco_meraki_org_cellular_uplinks = AgentSection(
-    name="cisco_meraki_org_cellular_uplinks",
+    name='cisco_meraki_org_cellular_uplinks',
     parse_function=parse_cellular_uplinks,
 )
 
diff --git a/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py b/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py
index 7ec77bfc4a5903b9ee28c1f46faa0319c2f5f9c0..f210421271e57701d52f4976a163ca19ee1a394b 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py
@@ -7,7 +7,7 @@
 # URL   : https://thl-cmk.hopto.org
 # Date  : 2023-11-11
 # File  : switch_ports_statuses.py (check plugin)
-
+from Cython.Shadow import returns
 # 2024-04-08: moved neighbour_name and neighbour_port to key columns
 # 2024-04-27: made data parsing more robust
 # 2024-05-12: added support for MerakiGetOrganizationSwitchPortsStatusesBySwitch (Early Access)
@@ -19,6 +19,14 @@
 #             try to match the output of a "normal" cmk interface service
 # 2024-06-30: renamed from cisco_meraki_switch_ports_statuses.py in to switch_ports_statuses.py
 # 2024-06-30: fixed discovery of (admin disabled) ports
+# 2024-11-17: changed operational/admin status to up/down from connected/disconnected, enabled/disabled
+#             incompatible change item from "Port %s" to "Interface %s" -> (Port is moved to %s)
+#               -> rediscover your devices (tabularasa)
+#             added interface inventory
+#             added hostlabel function for nvdct/has_lldp_neighbours
+# 2024-11-23  fixed crash on missing traffic data
+#             incompatible removed "Port" from item -> use only interface index
+# 2024-12-14: reworked output of port status
 
 # ToDo: create service label cmk/meraki/uplink:yes/no
 
@@ -39,6 +47,8 @@ from cmk.agent_based.v2 import (
     TableRow,
     check_levels,
     render,
+    HostLabelGenerator,
+    HostLabel,
 )
 
 from cmk_addons.plugins.meraki.lib.utils import get_float, get_int, load_json
@@ -51,6 +61,13 @@ class SwitchSecurePort:
     configOverrides: Mapping[any] | None
     enabled: bool | None
 
+    __secure_port =  {
+        "active": False,
+        "authenticationStatus": "Disabled",
+        "configOverrides": {},
+        "enabled": False,
+    }
+
     @classmethod
     def parse(cls, secure_port: Mapping[str, any] | None):
         return cls(
@@ -70,14 +87,26 @@ class SwitchPortCDP:
     device_port: str | None
     platform: str | None
     version: str | None
+    native_vlan: str | None
+
+    __cdp = {
+        "address": "172.24.10.1",
+        "capabilities": "Switch",
+        "deviceId": "149f43b14530",
+        "nativeVlan": 10,
+        "platform": "MS250-48FP",
+        "portId": "Port 49",
+        "version": "1",
+    }
 
     @classmethod
     def parse(cls, cdp: Mapping[str, str] | None):
         return cls(
-            device_id=str(cdp['deviceId']) if cdp.get('deviceId') is not None else None,
-            device_port=str(cdp['portId']) if cdp.get('portId') is not None else None,
             address=str(cdp['address']) if cdp.get('address') is not None else None,
             capabilities=str(cdp['capabilities']) if cdp.get('capabilities') is not None else None,
+            device_id=str(cdp['deviceId']) if cdp.get('deviceId') is not None else None,
+            device_port=str(cdp['portId']) if cdp.get('portId') is not None else None,
+            native_vlan=str(cdp['nativeVlan']) if cdp.get('nativeVlan') is not None else None,
             platform=str(cdp['platform']) if cdp.get('platform') is not None else None,
             version=str(cdp['version']) if cdp.get('version') is not None else None,
         ) if cdp else None
@@ -93,24 +122,36 @@ class SwitchPortLLDP:
     system_description: str | None
     system_name: str | None
 
+    __lldp = {
+        "chassisId": "14:9f:43:b1:45:30",
+        "managementAddress": "172.24.10.1",
+        "managementVlan": 10,
+        "portDescription": "Port 49",
+        "portId": "49",
+        "portVlan": 10,
+        "systemCapabilities": "S-VLAN Component of a VLAN Bridge",
+        "systemDescription": "Meraki MS250-48FP Cloud Managed PoE Switch",
+        "systemName": "Meraki MS250-48FP - DV1-R005",
+    }
+
     @classmethod
     def parse(cls, lldp: Mapping[str, str] | None):
         return cls(
+            cache_capabilities=str(lldp['systemCapabilities']) if lldp.get('systemCapabilities') is not None else None,
             chassis_id=str(lldp['chassisId']) if lldp.get('chassisId') is not None else None,
+            management_address=str(lldp['managementAddress']) if lldp.get('managementAddress') is not None else None,
+            port_description=str(lldp['portDescription']) if lldp.get('portDescription') is not None else None,
             port_id=str(lldp['portId']) if lldp.get('portId') is not None else None,
-            system_name=str(lldp['systemName']) if lldp.get('systemName') is not None else None,
             system_description=str(lldp['systemDescription']) if lldp.get('systemDescription') is not None else None,
-            port_description=str(lldp['portDescription']) if lldp.get('portDescription') is not None else None,
-            cache_capabilities=str(lldp['systemCapabilities']) if lldp.get('systemCapabilities') is not None else None,
-            management_address=str(lldp['managementAddress']) if lldp.get('managementAddress') is not None else None,
+            system_name=str(lldp['systemName']) if lldp.get('systemName') is not None else None,
         ) if lldp else None
 
 
 @dataclass(frozen=True)
 class SwitchPortUsage:
-    total: float
-    sent: float
     recv: float
+    sent: float
+    total: float
 
     @classmethod
     def parse(cls, usage: Mapping[str, float] | None):
@@ -124,9 +165,9 @@ class SwitchPortUsage:
 
         """
         return cls(
-            total=get_float(usage.get('total')) * 1000,
-            sent=get_float(usage.get('sent')) * 1000,
             recv=get_float(usage.get('recv')) * 1000,
+            sent=get_float(usage.get('sent')) * 1000,
+            total=get_float(usage.get('total')) * 1000,
         ) if usage else None
 
 
@@ -148,10 +189,11 @@ class SwitchPortTraffic:
 
         Returns:
         """
+
         return cls(
-            total=get_float(traffic.get('total')) * 1000,
-            sent=get_float(traffic.get('sent')) * 1000,
             recv=get_float(traffic.get('recv')) * 1000,
+            sent=get_float(traffic.get('sent')) * 1000,
+            total=get_float(traffic.get('total')) * 1000,
         ) if traffic else None
 
 
@@ -170,62 +212,92 @@ class SwitchPortSpanningTree:
         Returns:
 
         """
+
         if isinstance(spanning_tree, dict):
             return cls(
                 status=[str(status) for status in spanning_tree.get('statuses', [])]
             )
 
 
+def parse_admin_state(admin_state: bool | None) -> str | None:
+    state_map = {
+        True: 1,
+        False: 2,
+    }
+    return state_map.get(admin_state)
+
+
+def parse_operational_state(operational_state: str | None) -> str | None:
+    state_map = {
+        'connected': 1,
+        'disconnected': 2,
+    }
+    if isinstance(operational_state, str):
+        return state_map.get(operational_state.lower())
+
+
 @dataclass(frozen=True)
 class SwitchPort:
+    port_id: int  # needs to bee always there
+    admin_state: int | None
     cdp: SwitchPortCDP | None
     client_count: int | None
     duplex: str | None
-    enabled: bool | None
     errors: Sequence[str] | None
     is_up_link: bool | None
     lldp: SwitchPortLLDP | None
-    port_id: str | None
+    operational_state: int | None
     power_usage_in_wh: float | None
     secure_port: SwitchSecurePort | None
+    spanning_tree: SwitchPortSpanningTree | None
     speed: str | None
-    status: str | None
     traffic: SwitchPortTraffic | None
     usage: SwitchPortUsage | None
     warnings: Sequence[str]
-    spanning_tree: SwitchPortSpanningTree | None
+    # syntetic settings
+    alias: str | None
+    description: str | None
+    if_port_type: str | None
+    name: str | None
 
     @classmethod
     def parse(cls, port: Mapping[str, object]):
         return cls(
-            port_id=str(port['portId']) if port.get('portId') is not None else None,
+            port_id=int(port['portId']),  # needs to be always there
+            admin_state=parse_admin_state(port.get('enabled')),
+            cdp=SwitchPortCDP.parse(port.get('cdp')),
             client_count=get_int(port.get('clientCount')),
             duplex=str(port['duplex']) if port.get('duplex') is not None else None,
-            enabled=bool(port['enabled']) if port.get('enabled') is not None else None,
             errors=port['errors'] if port.get('errors') is not None else None,
             is_up_link=bool(port['isUplink']) if port.get('isUplink') is not None else None,
-            power_usage_in_wh=get_float(port.get('powerUsageInWh')),
-            speed=str(port['speed']) if port.get('speed') is not None else None,
-            status=str(port['status']) if port.get('status') is not None else None,
-            warnings=port['warnings'] if port.get('warnings') is not None else None,
             lldp=SwitchPortLLDP.parse(port.get('lldp')),
-            cdp=SwitchPortCDP.parse(port.get('cdp')),
+            operational_state=parse_operational_state(port.get('status')),
+            power_usage_in_wh=get_float(port.get('powerUsageInWh')),
             secure_port=SwitchSecurePort.parse(port.get('securePort')),
-            usage=SwitchPortUsage.parse(port.get('usageInKb')),
+            spanning_tree=SwitchPortSpanningTree.parse(port.get('spanningTree')),
+            speed=str(port['speed']) if port.get('speed') is not None else None,
             traffic=SwitchPortTraffic.parse((port.get('trafficInKbps'))),
-            spanning_tree=SwitchPortSpanningTree.parse(port.get('spanningTree'))
+            usage=SwitchPortUsage.parse(port.get('usageInKb')),
+            warnings=port['warnings'] if port.get('warnings') is not None else None,
+            # synthetic settings
+            alias=f'Port {port["portId"]}' if port.get('portId') is not None else None,
+            description=f'Port {port["portId"]}' if port.get('portId') is not None else None,
+            if_port_type='6 - ethernetCsmacd',
+            name=f'Port {port["portId"]}' if port.get('portId') is not None else None,
         )
 
 
-_admin_status = {
-    True: 'enabled',
-    False: 'disabled',
-}
-
-_is_up_link = {
-    True: 'yes',
-    False: 'no',
-}
+def host_label_meraki_switch_ports_statuses(section: Mapping[str, SwitchPort]) -> HostLabelGenerator:
+    """Host label function
+    Labels:
+        "nvdct/has_lldp_neighbours":
+            This label is set to "yes" for all hosts with LLDP neighbours
+    """
+    for port in section.values():
+        if port.lldp:
+            yield HostLabel(name="nvdct/has_lldp_neighbours", value="yes")
+            break
+    # only set LLDP label, Merkai CDP data are not usefully for NVDCT
 
 
 def parse_switch_ports_statuses(string_table: StringTable) -> Mapping[str, SwitchPort] | None:
@@ -235,33 +307,32 @@ def parse_switch_ports_statuses(string_table: StringTable) -> Mapping[str, Switc
     if isinstance(json_data, dict) and 'ports' in json_data.keys():
         json_data = json_data['ports']
 
-    return {port['portId']: SwitchPort.parse(port) for port in json_data}
+    return {port["portId"]: SwitchPort.parse(port) for port in json_data if port.get('portId', '').isdigit()}
 
 
 agent_section_cisco_meraki_org_switch_ports_statuses = AgentSection(
     name="cisco_meraki_org_switch_ports_statuses",
     parse_function=parse_switch_ports_statuses,
+    host_label_function=host_label_meraki_switch_ports_statuses,
 )
 
 
 def discover_switch_ports_statuses(params: Mapping[str, object], section: Mapping[str, SwitchPort]) -> DiscoveryResult:
-    discovered_port_states = params['discovered_port_states']
-    # adjust params, as we can not use True/False as keys anymore in rule sets :-(
-    if 'admin_enabled' in discovered_port_states:
-        discovered_port_states.append(True)
-        discovered_port_states.remove('admin_enabled')
-    if 'admin_disabled' in discovered_port_states:
-        discovered_port_states.append(False)
-        discovered_port_states.append('disabled')
-        discovered_port_states.remove('admin_disabled')
+    state_map = {
+        1: 'up',
+        2: 'down',
+    }
+    admin_port_states = params['admin_port_states']
+    operational_port_states = params['operational_port_states']
 
-    for port in section.values():
-        if port.enabled in discovered_port_states and port.status.lower() in discovered_port_states:
+    for item, port in section.items():
+        if state_map.get(port.admin_state) in admin_port_states and \
+                state_map.get(port.operational_state) in operational_port_states:
             yield Service(
-                item=port.port_id,
+                item=item,
                 parameters={
-                    'enabled': port.enabled,
-                    'status': port.status,
+                    'admin_state': port.admin_state,
+                    'operational_state': port.operational_state,
                     'speed': port.speed,
                 }
             )
@@ -272,82 +343,98 @@ def render_network_bandwidth_bits(value: int) -> str:
 
 
 def check_switch_ports_statuses(item: str, params: Mapping[str, any], section: Mapping[str, SwitchPort]) -> CheckResult:
-    def _status_changed(is_state: str, was_state: str, state: int, message: str):
-        if is_state != was_state:
-            is_state = is_state if is_state else 'N/A'
-            was_state = was_state if was_state else 'N/A'
-            yield Result(state=State(state), notice=f'{message}: from {was_state}, to {is_state}')
+    state_map = {
+        1: 'up',
+        2: 'down',
+    }
+
+    is_up_link = {
+        True: 'yes',
+        False: 'no',
+    }
+
+    def has_changed (is_state: int | str | None, was_state: int | str | None) -> bool:
+        if not is_state or not was_state:
+            # ignore if state is None -> meaning this change is expected. OP state down -> op -> speed None -> xxx
+            return False
+
+        if is_state == was_state:
+            return False
+
+        return True
 
     if (port := section.get(item)) is None:
         return
 
-    # check admin state changed
-    yield from _status_changed(
-        is_state=_admin_status[port.enabled],
-        was_state=_admin_status[params['enabled']],
-        message='Admin status changed',
-        state=params['state_admin_change'],
-    )
-
-    if port.enabled:  # check admin sate
-        yield Result(state=State.OK, notice=f'Admin status: {_admin_status[port.enabled]}')
-        # check operational status changed
-        yield from _status_changed(
-            is_state=port.status.lower(),
-            was_state=params['status'].lower(),
-            message='Operational status changed',
-            state=params['state_op_change']
+    if port.admin_state == 2:
+        yield Result(
+            state=State(params['state_disabled']),
+            summary=f'(admin {state_map.get(port.admin_state)})',
+            details=f'Admin status: {state_map.get(port.admin_state)}',
         )
-        if port.status.lower() == 'connected':  # check operational state
-            yield Result(state=State.OK, summary=f'({port.status})', details=f'Operational status: {port.status}')
-            # check speed changed
-            yield from _status_changed(
-                is_state=port.speed,
-                was_state=params['speed'],
-                message='Speed changed',
-                state=params['state_speed_change']
-            )
-            if params['speed'] == port.speed:  # only if speed unchanged
-                yield Result(state=State.OK, summary=f'Speed: {port.speed}')
-
-            if params.get('show_traffic'):
-                yield from check_levels(
-                    value=port.traffic.recv,  # Bits
-                    label='In',
-                    metric_name='if_in_bps',
-                    render_func=render_network_bandwidth_bits,  # Bytes
-                    # notice_only=True,
-                )
-                yield from check_levels(
-                    value=port.traffic.sent,  # Bits
-                    label='Out',
-                    metric_name='if_out_bps',
-                    render_func=render_network_bandwidth_bits,  # Bytes
-                    # notice_only=True,
-                )
-
-            if port.duplex.lower() == 'full':  # check duplex state
-                yield Result(state=State.OK, notice=f'Duplex: {port.duplex}')
-            else:
-                yield Result(state=State(params['state_not_full_duplex']), notice=f'Duplex: {port.duplex}')
-            yield Result(state=State.OK, notice=f'Clients: {port.client_count}')
-        else:
-            yield Result(
-                state=State(params['state_not_connected']),
-                summary=f'({port.status})',
-                details=f'Operational status: {port.status}'
-            )
     else:
+        yield Result(state=State.OK, notice=f'Admin status: {state_map.get(port.admin_state)}')
+
+    if has_changed(port.admin_state, params['admin_state']):
+        message = f'changed admin {state_map.get(params["admin_state"])} -> {state_map.get(port.admin_state)}'
+        yield Result(state=State(params['state_admin_change']), notice=message)
+
+    if port.admin_state == 2:  # down
+        return
+
+    if port.operational_state == 2:
         yield Result(
-            state=State(params['state_disabled']),
-            summary=f'({_admin_status[port.enabled].title()})',
-            details=f'Admin status: {_admin_status[port.enabled].title()}',
+            state=State(params['state_not_connected']),
+            summary=f'({state_map.get(port.operational_state)})',
+            details=f'Operational status: {state_map.get(port.operational_state)}'
+        )
+    else:
+        yield Result(
+            state=State.OK,
+            summary=f'({state_map.get(port.operational_state)})',
+            details=f'Operational status: {state_map.get(port.operational_state)}'
         )
 
+    if has_changed(port.operational_state, params['operational_state']):
+        message = f'changed {state_map.get(params["operational_state"])} -> {state_map.get(port.operational_state)}'
+        yield Result(state=State(params['state_op_change']), summary=message)
+
+    if port.operational_state == 2:
+        return
+
+    yield Result(state=State.OK, summary=f'Speed: {port.speed}')
+
+    if has_changed(port.speed, params['speed']):
+        message = f'changed {params["speed"]} -> {port.speed}'
+        yield Result(state=State(params['state_speed_change']), summary=message)
+
+
+    if params.get('show_traffic') and port.traffic:
+        yield from check_levels(
+            value=port.traffic.recv,  # Bits
+            label='In',
+            metric_name='if_in_bps',
+            render_func=render_network_bandwidth_bits,  # Bytes
+            # notice_only=True,
+        )
+        yield from check_levels(
+            value=port.traffic.sent,  # Bits
+            label='Out',
+            metric_name='if_out_bps',
+            render_func=render_network_bandwidth_bits,  # Bytes
+            # notice_only=True,
+        )
+
+        if port.duplex.lower() == 'full':  # check duplex state
+            yield Result(state=State.OK, notice=f'Duplex: {port.duplex}')
+        else:
+            yield Result(state=State(params['state_not_full_duplex']), notice=f'Duplex: {port.duplex}')
+        yield Result(state=State.OK, notice=f'Clients: {port.client_count}')
+
     if port.is_up_link:
-        yield Result(state=State.OK, summary='UP-Link', details=f'UP-Link: {_is_up_link[port.is_up_link]}')
+        yield Result(state=State.OK, summary='UP-Link', details=f'UP-Link: {is_up_link[port.is_up_link]}')
     else:
-        yield Result(state=State.OK, notice=f'UP-Link: {_is_up_link[port.is_up_link]}')
+        yield Result(state=State.OK, notice=f'UP-Link: {is_up_link[port.is_up_link]}')
 
     if port.power_usage_in_wh:
         yield Result(state=State.OK, summary=f'Power usage: {port.power_usage_in_wh} Wh')
@@ -368,7 +455,7 @@ def check_switch_ports_statuses(item: str, params: Mapping[str, any], section: M
 
 check_plugin_cisco_meraki_org_switch_ports_statuses = CheckPlugin(
     name='cisco_meraki_org_switch_ports_statuses',
-    service_name='Port %s',
+    service_name='Interface %s',
     discovery_function=discover_switch_ports_statuses,
     check_function=check_switch_ports_statuses,
     check_default_parameters={
@@ -382,11 +469,38 @@ check_plugin_cisco_meraki_org_switch_ports_statuses = CheckPlugin(
     check_ruleset_name='cisco_meraki_switch_ports_statuses',
     discovery_ruleset_name='discovery_cisco_meraki_switch_ports_statuses',
     discovery_default_parameters={
-        'discovered_port_states': ['admin_enabled', 'admin_disabled', 'connected', 'disconnected']
+        'admin_port_states': ['up', 'down'],
+        'operational_port_states': ['up', 'down'],
     }
 )
 
 
+def inventory_meraki_interfaces(section: Mapping[str, SwitchPort]) -> InventoryResult:
+    for port in section.values():
+        yield TableRow(
+            path=['networking', 'interfaces'],
+            key_columns={
+                "index": port.port_id,
+            },
+            inventory_columns={
+                **({'alias': port.alias} if port.alias else {}),
+                **({'description': port.description} if port.description else {}),
+                **({'name': port.name} if port.name else {}),
+                **({'admin_status': port.admin_state} if port.admin_state else {}),
+                **({'oper_status': port.operational_state} if port.operational_state else {}),
+                **({'speed': port.speed} if port.speed else {}),
+                **({'if_port_type': port.if_port_type} if port.if_port_type else {}),
+            },
+        )
+
+
+inventory_plugin_inv_meraki_interfaces = InventoryPlugin(
+    name='inv_meraki_interfaces',
+    sections=['cisco_meraki_org_switch_ports_statuses'],
+    inventory_function=inventory_meraki_interfaces,
+)
+
+
 def inventory_meraki_cdp_cache(section: Mapping[str, SwitchPort]) -> InventoryResult:
     path = ['networking', 'cdp_cache', 'neighbours']
 
@@ -394,14 +508,16 @@ def inventory_meraki_cdp_cache(section: Mapping[str, SwitchPort]) -> InventoryRe
         if cdp := port.cdp:
             key_columns = {
                 'local_port': port.port_id,
-                'neighbour_name': cdp.device_id,
+                'neighbour_name': '',
                 'neighbour_port': cdp.device_port,
             }
             neighbour = {
-                'neighbour_address': cdp.address,
-                'platform_details': cdp.version,
-                'platform': cdp.platform,
-                'capabilities': cdp.capabilities
+                **({'capabilities': cdp.capabilities} if cdp.capabilities else {}),
+                **({'native_vlan': cdp.native_vlan} if cdp.native_vlan else {}),
+                **({'neighbour_address': cdp.address} if cdp.address else {}),
+                **({'neighbour_id': cdp.device_id} if cdp.device_id else {}),
+                **({'platform': cdp.platform} if cdp.platform else {}),
+                **({'version': cdp.version} if cdp.version else {}),
             }
             yield TableRow(
                 path=path,
@@ -428,11 +544,11 @@ def inventory_meraki_lldp_cache(section: Mapping[str, SwitchPort]) -> InventoryR
                 'neighbour_port': lldp.port_id,
             }
             neighbour = {
-                'neighbour_id': lldp.chassis_id,
-                'system_description': lldp.system_description,
-                'port_description': lldp.port_description,
-                'capabilities': lldp.cache_capabilities,
-                'neighbour_address': lldp.management_address,
+                **({'capabilities': lldp.cache_capabilities} if lldp.cache_capabilities else {}),
+                **({'neighbour_address': lldp.management_address} if lldp.management_address else {}),
+                **({'neighbour_id': lldp.chassis_id} if lldp.chassis_id else {}),
+                **({'port_description': lldp.port_description} if lldp.port_description else {}),
+                **({'system_description': lldp.system_description} if lldp.system_description else {}),
             }
             yield TableRow(
                 path=path,
diff --git a/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py b/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py
index 5b65d48d91319810eb83b6be1a01f3f714ddb20a..2710ccccbd6bd41ff8bf172d9760b166270fb76f 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py
@@ -15,6 +15,7 @@
 # 2024-07-13: fixed crash on missing metrics (device dormant) ThX to Leon Buhleier
 # 2024-08-07: fixed crash on missing power value (unit only) ThX to Leon Buhleier
 # 2024-09-12: fixed missing SSID 0 ThX to Andreas Doehler
+# 2024-12-13: fixed crash if no valid data received (json_data = [[]])
 
 from collections.abc import Mapping
 from dataclasses import dataclass
@@ -64,7 +65,7 @@ class SSID:
 
 def parse_wireless_device_status(string_table: StringTable) -> Mapping[str, SSID] | None:
     json_data = load_json(string_table)
-    if (json_data := json_data[0]) is None:
+    if not (json_data := json_data[0]):
         return
 
     ssids = {}
@@ -78,7 +79,6 @@ def parse_wireless_device_status(string_table: StringTable) -> Mapping[str, SSID
         item = str(ssid_number) + ' on band ' + row.get('band')
 
         ssids[item] = SSID.parse(row)
-
     return ssids
 
 
diff --git a/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py b/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py
index 8ad1aa7c6b3233bb87574750ba832da63618226c..88cc8fefc76a256d2a5cf293aa6d37e8288056aa 100644
--- a/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py
+++ b/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py
@@ -12,6 +12,9 @@
 # 2024-06-29: refactored for CMK 2.3
 #             moved parse functions to class methods
 # 2024-06-30: renamed from cisco_meraki_org_wireless_ethernet_statuses.py in to wireless_ethernet_statuses.py
+# 2024-11-17: incompatible change item from "Port %s" to "Interface %s" -> rediscover your devices
+#             added interface inventory
+# 2024-12-12: fixed crash if speed is None
 
 # ToDo: create ruleset cisco_meraki_wireless_ethernet_statuses
 
@@ -28,6 +31,9 @@ from cmk.agent_based.v2 import (
     State,
     StringTable,
     render,
+    InventoryPlugin,
+    InventoryResult,
+    TableRow,
 )
 from cmk_addons.plugins.meraki.lib.utils import get_int, load_json
 
@@ -176,7 +182,7 @@ def check_wireless_ethernet_statuses(
 
 check_plugin_cisco_meraki_org_wireless_ethernet_statuses = CheckPlugin(
     name='cisco_meraki_org_wireless_ethernet_statuses',
-    service_name='Port %s',
+    service_name='Interface %s',
     discovery_function=discover_wireless_ethernet_statuses,
     check_function=check_wireless_ethernet_statuses,
     check_default_parameters={
@@ -187,3 +193,29 @@ check_plugin_cisco_meraki_org_wireless_ethernet_statuses = CheckPlugin(
     },
     # check_ruleset_name='cisco_meraki_wireless_ethernet_statuses',
 )
+
+
+def inventory_meraki_wireless_ethernet(section: Mapping[str, WirelessEthernetPort]) -> InventoryResult:
+    for port in section.values():
+        yield TableRow(
+            path=['networking', 'interfaces'],
+            key_columns={
+                "index": port.name.split(' ')[-1],
+            },
+            inventory_columns={
+                'alias': port.name,
+                'description': port.name,
+                'name': port.name,
+                'admin_status': 1,
+                'oper_status': 1,
+                **({'speed': render.nicspeed(port.speed)} if port.speed is not None else {}),
+                'if_port_type': '6 - ethernetCsmacd',
+            },
+        )
+
+
+inventory_plugin_inv_meraki_wireless_ethernet = InventoryPlugin(
+    name='inv_meraki_wireless_ethernet',
+    sections=['cisco_meraki_org_wireless_ethernet_statuses'],
+    inventory_function=inventory_meraki_wireless_ethernet,
+)
diff --git a/source/cmk_addons_plugins/meraki/lib/agent.py b/source/cmk_addons_plugins/meraki/lib/agent.py
index ef80ffec40072310c8b5ce29ed392d08b0f2b4b1..50516cab9144fb91b7938b72da60eacc39b6a532 100644
--- a/source/cmk_addons_plugins/meraki/lib/agent.py
+++ b/source/cmk_addons_plugins/meraki/lib/agent.py
@@ -40,14 +40,17 @@
 # 2024-09-12: added version check for min. Meraki SDK version
 # 2024-09-15: fixed MerakiGetOrganizationSwitchPortsStatusesBySwitch -> return only list of switches
 # 2024-11-16: fixed crash on missing items in MerakiGetOrganizationSwitchPortsStatusesBySwitch (ThX to Stephan Bergfeld)
+# 2024-11-23: added appliance port api call -> not yet active
+# 2024-12-13: fixed crash in SwitchPortStatus if response has no data (>Response [503}>)
 
 # ToDo: create inventory from Networks, is per organisation, not sure where/how to put this in the inventory
 # ToDo: list Connected Datacenters like Umbrella https://developer.cisco.com/meraki/api-v1/list-data-centers/
 # ToDo: https://developer.cisco.com/meraki/api-v1/list-tunnels/
+# ToDo: https://developer.cisco.com/meraki/api-v1/get-organization-wireless-clients-overview-by-device/
 
 # if the following is available (right now only with early access enabled)
-# ToDO: https://developer.cisco.com/meraki/api-v1/get-organization-switch-ports-statuses-by-switch/
-# ToDo: https://developer.cisco.com/meraki/api-v1/get-organization-switch-ports-overview/  # (done)
+# ToDO: https://developer.cisco.com/meraki/api-v1/get-organization-switch-ports-statuses-by-switch/ # (done)
+# ToDo: https://developer.cisco.com/meraki/api-v1/get-organization-switch-ports-overview/
 # TODo: https://developer.cisco.com/meraki/api-v1/get-organization-certificates/
 # ToDo: https://developer.cisco.com/meraki/api-v1/api-reference-early-access-api-platform-configure-firmwareupgrades-get-network-firmware-upgrades/
 
@@ -62,6 +65,7 @@ from argparse import Namespace
 from collections.abc import Iterable, Iterator, Mapping, Sequence
 from dataclasses import dataclass
 from enum import auto, Enum
+from json import JSONDecodeError
 from logging import getLogger
 from os import environ
 from pathlib import Path
@@ -89,6 +93,7 @@ from cmk_addons.plugins.meraki.lib.utils import (
 
     # parameter names
     _SEC_NAME_APPLIANCE_UPLINKS,
+    _SEC_NAME_APPLIANCE_PORTS,
     _SEC_NAME_APPLIANCE_UPLINKS_USAGE,
     _SEC_NAME_APPLIANCE_VPNS,
     _SEC_NAME_APPLIANCE_PERFORMANCE,
@@ -125,53 +130,55 @@ from cmk_addons.plugins.meraki.lib.utils import (
     _SEC_CACHE_SWITCH_PORTS_STATUSES,
     _SEC_CACHE_WIRELESS_DEVICE_STATUS,
     _SEC_CACHE_WIRELESS_ETHERNET_STATUSES,
+    _SEC_CACHE_APPLIANCE_PORTS,
 )
 
 _MERAKI_SDK_MIN_VERSION: Final = '1.46.0'
 
-_LOGGER = getLogger("agent_cisco_meraki")
+_LOGGER = getLogger('agent_cisco_meraki')
 
-_API_NAME_API: Final = "api"
-_API_NAME_DEVICE_NAME: Final = "name"
+_API_NAME_API: Final = 'api'
+_API_NAME_DEVICE_NAME: Final = 'name'
 _API_NAME_DEVICE_PRODUCT_TYPE: Final = 'productType'
-_API_NAME_DEVICE_SERIAL: Final = "serial"
+_API_NAME_DEVICE_SERIAL: Final = 'serial'
 _API_NAME_DEVICE_TYPE_APPLIANCE: Final = 'appliance'
 _API_NAME_DEVICE_TYPE_CAMERA: Final = 'camera'
 _API_NAME_DEVICE_TYPE_CELLULAR: Final = 'cellularGateway'
 _API_NAME_DEVICE_TYPE_SENSOR: Final = 'sensor'
 _API_NAME_DEVICE_TYPE_SWITCH: Final = 'switch'
 _API_NAME_DEVICE_TYPE_WIRELESS: Final = 'wireless'
-_API_NAME_ENABLED: Final = "enabled"
+_API_NAME_ENABLED: Final = 'enabled'
 _API_NAME_NETWORK_ID: Final = 'networkId'
-_API_NAME_ORGANISATION_ID: Final = "id"
-_API_NAME_ORGANISATION_NAME: Final = "name"
+_API_NAME_ORGANISATION_ID: Final = 'id'
+_API_NAME_ORGANISATION_NAME: Final = 'name'
 
-# map section parameter name to python name (do we really need this, why not use the name ("-" -> "_")?
+# map section parameter name to python name (do we really need this, why not use the name ('-' -> '_')?
 _SECTION_NAME_MAP = {
-    _SEC_NAME_APPLIANCE_UPLINKS: "appliance_uplinks",
-    _SEC_NAME_APPLIANCE_UPLINKS_USAGE: "appliance_uplinks_usage",
-    _SEC_NAME_APPLIANCE_VPNS: "appliance_vpns",
-    _SEC_NAME_APPLIANCE_PERFORMANCE: "appliance_performance",
-    _SEC_NAME_CELLULAR_UPLINKS: "cellular_uplinks",
-    _SEC_NAME_DEVICE_INFO: "device_info",
-    _SEC_NAME_DEVICE_STATUSES: "device_status",
-    _SEC_NAME_DEVICE_UPLINKS_INFO: "device_uplinks_info",
-    _SEC_NAME_LICENSES_OVERVIEW: "licenses_overview",
-    _SEC_NAME_NETWORKS: "networks",
-    _SEC_NAME_ORGANISATIONS: "organisations",
-    _SEC_NAME_ORG_API_REQUESTS: "api_requests_by_organization",
-    _SEC_NAME_SENSOR_READINGS: "sensor_readings",
-    _SEC_NAME_SWITCH_PORTS_STATUSES: "switch_ports_statuses",
-    _SEC_NAME_WIRELESS_DEVICE_STATUS: "wireless_device_status",
-    _SEC_NAME_WIRELESS_ETHERNET_STATUSES: "wireless_ethernet_statuses",
+    _SEC_NAME_APPLIANCE_UPLINKS: 'appliance_uplinks',
+    _SEC_NAME_APPLIANCE_UPLINKS_USAGE: 'appliance_uplinks_usage',
+    _SEC_NAME_APPLIANCE_PORTS: 'appliance_ports',
+    _SEC_NAME_APPLIANCE_VPNS: 'appliance_vpns',
+    _SEC_NAME_APPLIANCE_PERFORMANCE: 'appliance_performance',
+    _SEC_NAME_CELLULAR_UPLINKS: 'cellular_uplinks',
+    _SEC_NAME_DEVICE_INFO: 'device_info',
+    _SEC_NAME_DEVICE_STATUSES: 'device_status',
+    _SEC_NAME_DEVICE_UPLINKS_INFO: 'device_uplinks_info',
+    _SEC_NAME_LICENSES_OVERVIEW: 'licenses_overview',
+    _SEC_NAME_NETWORKS: 'networks',
+    _SEC_NAME_ORGANISATIONS: 'organisations',
+    _SEC_NAME_ORG_API_REQUESTS: 'api_requests_by_organization',
+    _SEC_NAME_SENSOR_READINGS: 'sensor_readings',
+    _SEC_NAME_SWITCH_PORTS_STATUSES: 'switch_ports_statuses',
+    _SEC_NAME_WIRELESS_DEVICE_STATUS: 'wireless_device_status',
+    _SEC_NAME_WIRELESS_ETHERNET_STATUSES: 'wireless_ethernet_statuses',
     # Early Access
-    _SEC_NAME_ORG_SWITCH_PORTS_STATUSES: "org_switch_ports_statuses",
+    _SEC_NAME_ORG_SWITCH_PORTS_STATUSES: 'org_switch_ports_statuses',
 }
 
 # _MIN_CACHE_INTERVAL = 300
 # _RANDOM_CACHE_INTERVAL = 300
 
-MerakiCacheFilePath = Path(tmp_dir) / "agents" / "agent_cisco_meraki"
+MerakiCacheFilePath = Path(tmp_dir) / 'agents' / 'agent_cisco_meraki'
 MerakiAPIData = Mapping[str, object]
 
 
@@ -235,7 +242,7 @@ class Section:
     piggyback: str | None = None
 
     def get_name(self) -> str:
-        return "_".join(["cisco_meraki", self.api_data_source.name, self.name])
+        return '_'.join(['cisco_meraki', self.api_data_source.name, self.name])
 
 
 class _Organisation(TypedDict):
@@ -258,13 +265,13 @@ class _Organisation(TypedDict):
 #
 # --\ DataCache
 #   |
-#   |--\ MerakiSection
+#   +--\ MerakiSection
 #      |  - adds cache_interval = 86400
 #      |  - adds get_validity_from_args = True
 #      |
-#      |--> MerakiGetOrganizations                          		           -> default 86400
+#      +--> MerakiGetOrganizations                          		           -> default 86400
 #      |
-#      |--\ MerakiSectionOrg
+#      +--\ MerakiSectionOrg
 #      |  |  - adds org_id parameter
 #      |  |
 #      |  |--> MerakiGetOrganization				                           -> default 86400
@@ -282,13 +289,20 @@ class _Organisation(TypedDict):
 #      |  |--> MerakiGetOrganizationCellularGatewayUplinkStatuses              -> ex. 60.
 #      |  |--> MerakiGetOrganizationSwitchPortsStatusesBySwitch                -> ex. 60+
 #      |
-#      |--\ MerakiSectionSerial
-#         |  - adds serial as parameter
-#         |  - sets cache_interval = 60 + randrange(300)
+#      +--\ MerakiSectionSerial
+#      |  |  - adds serial as parameter
+#      |  |  - sets cache_interval = 60
+#      |  |
+#      |  |--> MerakiGetDeviceSwitchPortsStatuses 	                           -> default 60+
+#      |  |--> MerakiGetDeviceWirelessStatus	                               -> default 60+
+#      |  |--> MerakiGetDeviceAppliancePerformance
+#      |
+#      +--\ MerakiSectionNetwork
+#         | - adds network id as parameter
+#         | - sets cache_interval = 60
 #         |
-#         |--> MerakiGetDeviceSwitchPortsStatuses 	                           -> default 60+
-#         |--> MerakiGetDeviceWirelessStatus	                               -> default 60+
-#         |--> MerakiGetDeviceAppliancePerformance
+#         |--> MerakiGetNetworkAppliancePorts
+#
 
 class MerakiSection(DataCache):
     def __init__(
@@ -305,7 +319,7 @@ class MerakiSection(DataCache):
 
     @property
     def name(self):
-        return "meraki_section"
+        return 'meraki_section'
 
     @property
     def cache_interval(self):
@@ -338,18 +352,29 @@ class MerakiSectionSerial(MerakiSection):
         super().__init__(config=config, cache_interval=cache_interval)
 
 
+class MerakiSectionNetwork(MerakiSection):
+    def __init__(
+            self,
+            config: MerakiConfig,
+            network_id: str,
+            cache_interval: int = 1,
+    ):
+        self._network_id = network_id
+        super().__init__(config=config, cache_interval=cache_interval)
+
+
 class MerakiGetOrganizations(MerakiSection):
     @property
     def name(self):
-        return "getOrganizations"
+        return 'getOrganizations'
 
     def get_live_data(self):
         try:
             return self._config.dashboard.organizations.getOrganizations(
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Get organisations: %r", e)
+            _LOGGER.debug('Get organisations: %r', e)
             return []
 
 
@@ -379,9 +404,9 @@ class MerakiGetOrganizationApiRequestsOverviewResponseCodesByInterval(MerakiSect
             # )
             return self._config.dashboard.organizations.getOrganizationApiRequestsOverviewResponseCodesByInterval(
                 self._org_id,
-                total_pages="all",
-                t0=strftime("%Y-%m-%dT%H:%M:%MZ", gmtime(now_time()-120)),
-                t1=strftime("%Y-%m-%dT%H:%M:%MZ", gmtime())
+                total_pages='all',
+                t0=strftime('%Y-%m-%dT%H:%M:%MZ', gmtime(now_time()-120)),
+                t1=strftime('%Y-%m-%dT%H:%M:%MZ', gmtime())
             )
 
         except meraki.APIError as e:
@@ -400,7 +425,7 @@ class MerakiGetOrganizationLicensesOverview(MerakiSectionOrg):
                 self._org_id,
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get license overview: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get license overview: %r', self._org_id, e)
             return []
 
 
@@ -413,10 +438,10 @@ class MerakiGetOrganizationDevices(MerakiSectionOrg):
         try:
             return self._config.dashboard.organizations.getOrganizationDevices(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get devices: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get devices: %r', self._org_id, e)
             return {}
 
 
@@ -429,10 +454,10 @@ class MerakiGetOrganizationNetworks(MerakiSectionOrg):
         try:
             return self._config.dashboard.organizations.getOrganizationNetworks(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get networks: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get networks: %r', self._org_id, e)
             return []
 
 
@@ -445,10 +470,10 @@ class MerakiGetOrganizationDevicesStatuses(MerakiSectionOrg):
         try:
             return self._config.dashboard.organizations.getOrganizationDevicesStatuses(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get device statuses: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get device statuses: %r', self._org_id, e)
             return []
 
 
@@ -461,10 +486,10 @@ class MerakiGetOrganizationDevicesUplinksAddressesByDevice(MerakiSectionOrg):
         try:
             return self._config.dashboard.organizations.getOrganizationDevicesUplinksAddressesByDevice(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get device statuses: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get device statuses: %r', self._org_id, e)
             return []
 
 
@@ -477,10 +502,10 @@ class MerakiGetOrganizationApplianceUplinkStatuses(MerakiSectionOrg):
         try:
             return self._config.dashboard.appliance.getOrganizationApplianceUplinkStatuses(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get Appliance uplink status by network: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get Appliance uplink status by network: %r', self._org_id, e)
             return []
 
 
@@ -490,17 +515,17 @@ class MerakiGetOrganizationApplianceUplinksUsageByNetwork(MerakiSectionOrg):
         return f'getOrganizationApplianceUplinksUsageByNetwork_{self._org_id}'
 
     def get_live_data(self):
-        if meraki.__version__ < "1.39.0":
+        if meraki.__version__ < '1.39.0':
             _LOGGER.debug(f'Meraki SDK is to old. Installed: {meraki.__version__}, excepted: 1.39.0')
             return []
         try:
             return self._config.dashboard.appliance.getOrganizationApplianceUplinksUsageByNetwork(
                 organizationId=self._org_id,
-                total_pages="all",
+                total_pages='all',
                 timespan=60  # default=86400 (one day), maximum=1209600 (14 days), needs to match value in check
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get Appliance uplink usage by network: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get Appliance uplink usage by network: %r', self._org_id, e)
             return []
 
 
@@ -513,11 +538,11 @@ class MerakiGetOrganizationApplianceVpnStatuses(MerakiSectionOrg):
         try:
             return self._config.dashboard.appliance.getOrganizationApplianceVpnStatuses(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
 
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get Appliance VPN status by network: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get Appliance VPN status by network: %r', self._org_id, e)
             return []
 
 
@@ -532,7 +557,7 @@ class MerakiGetDeviceAppliancePerformance(MerakiSectionSerial):
             return self._config.dashboard.appliance.getDeviceAppliancePerformance(
                 self._serial)
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Serial: %r: Get appliance device performance: %r",
+            _LOGGER.debug('Serial: %r: Get appliance device performance: %r',
                           self._serial, e)
             return []
 
@@ -546,10 +571,10 @@ class MerakiGetOrganizationSensorReadingsLatest(MerakiSectionOrg):
         try:
             return self._config.dashboard.sensor.getOrganizationSensorReadingsLatest(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get sensor readings: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get sensor readings: %r', self._org_id, e)
             return []
 
 
@@ -562,11 +587,11 @@ class MerakiGetDeviceSwitchPortsStatuses(MerakiSectionSerial):
         try:
             return self._config.dashboard.switch.getDeviceSwitchPortsStatuses(
                 self._serial,
-                # total_pages="all",
+                # total_pages='all',
                 timespan=max(self._config.timespan, 900),
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Serial: %r: Get Switch Port Statuses: %r", self._serial, e)
+            _LOGGER.debug('Serial: %r: Get Switch Port Statuses: %r', self._serial, e)
             return []
 
 
@@ -576,16 +601,16 @@ class MerakiGetOrganizationWirelessDevicesEthernetStatuses(MerakiSectionOrg):
         return f'getOrganizationWirelessDevicesEthernetStatuses_{self._org_id}'
 
     def get_live_data(self):
-        if meraki.__version__ < "1.39.0":
+        if meraki.__version__ < '1.39.0':
             _LOGGER.debug(f'Meraki SDK is to old. Installed: {meraki.__version__}, expceted: 1.39.0')
             return []
         try:
             return self._config.dashboard.wireless.getOrganizationWirelessDevicesEthernetStatuses(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Organisation ID: %r: Get wireless devices ethernet statuses: %r", self._org_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get wireless devices ethernet statuses: %r', self._org_id, e)
             return []
 
 
@@ -598,7 +623,7 @@ class MerakiGetDeviceWirelessStatus(MerakiSectionSerial):
         try:
             return self._config.dashboard.wireless.getDeviceWirelessStatus(self._serial)
         except meraki.exceptions.APIError as e:
-            _LOGGER.debug("Serial: %r: Get wireless device status: %r", self._serial, e)
+            _LOGGER.debug('Serial: %r: Get wireless device status: %r', self._serial, e)
             return []
 
 
@@ -611,7 +636,7 @@ class MerakiGetOrganizationCellularGatewayUplinkStatuses(MerakiSectionOrg):
         try:
             return self._config.dashboard.cellularGateway.getOrganizationCellularGatewayUplinkStatuses(
                 self._org_id,
-                total_pages="all",
+                total_pages='all',
             )
         except meraki.exceptions.APIError as e:
             _LOGGER.debug('Organisation ID: %r: Get cellular gateways uplink statuses: %r', self._org_id, e)
@@ -652,12 +677,32 @@ class MerakiGetOrganizationSwitchPortsStatusesBySwitch(MerakiSectionOrg):
         except RequestException as e:
             _LOGGER.debug('Organisation ID: %r: Get Ports statuses by switch: %r', self._org_id, e)
             return []
-        _response = response.json()
+        try:
+            _response = response.json()
+        except JSONDecodeError:
+            _LOGGER.debug('Organisation ID: %r: Get Ports statuses by switch: %r', self._org_id, response)
+            return []
         if _response:
             return _response.get('items', [])
         return []
 
 
+class MerakiGetNetworkAppliancePorts(MerakiSectionNetwork):
+    @property
+    def name(self):
+        return f'getNetworkAppliancePorts_{self._network_id}'
+
+    def get_live_data(self):
+        try:
+            return self._config.dashboard.appliance.getNetworkAppliancePorts(
+                self._network_id,
+                # total_pages='all',
+            )
+        except meraki.exceptions.APIError as e:
+            _LOGGER.debug('Network ID: %r: Get appliance ports: %r', self._network_id, e)
+            return []
+
+
 #
 # Main run
 #
@@ -737,7 +782,7 @@ class MerakiOrganisation:
                 device_piggyback = device[_API_NAME_DEVICE_NAME]
             except KeyError as e:
                 _LOGGER.debug(
-                    "Organisation ID: %r: Get device piggyback: %r", self.organisation_id, e
+                    'Organisation ID: %r: Get device piggyback: %r', self.organisation_id, e
                 )
                 continue
 
@@ -872,6 +917,60 @@ class MerakiOrganisation:
                             piggyback=self._adjust_piggyback(host=piggyback),
                             )
 
+            # if _SEC_NAME_APPLIANCE_PORTS not in self.config.excluded_sections and networks:
+            #     for network in networks:
+            #         appliance_ports_by_network = MerakiGetNetworkAppliancePorts(
+            #             config=self.config,
+            #             network_id=network.get('id'),
+            #             cache_interval=30,
+            #         ).get_data(use_cache=self.config.use_cache)
+            #         __ports = [
+            #             {
+            #                 'number': 5,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': True,
+            #                 'allowedVlans': 'all'
+            #             },
+            #             {
+            #                 'number': 6,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': True,
+            #                 'allowedVlans': 'all'
+            #             },
+            #             {
+            #                 'number': 7,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': False,
+            #                 'vlan': 1,
+            #                 'allowedVlans': 'all'},
+            #             {
+            #                 'number': 8,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': True,
+            #                 'allowedVlans': 'all'
+            #             },
+            #             {
+            #                 'number': 9,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': False,
+            #                 'vlan': 10,
+            #                 'allowedVlans': 'all'
+            #             },
+            #             {
+            #                 'number': 10,
+            #                 'enabled': True,
+            #                 'type': 'trunk',
+            #                 'dropUntaggedTraffic': False,
+            #                 'vlan': 10,
+            #                 'allowedVlans': 'all'
+            #             }
+            #         ]
+
         if devices_by_type.get(_API_NAME_DEVICE_TYPE_SWITCH):
             if _SEC_NAME_SWITCH_PORTS_STATUSES not in self.config.excluded_sections:
                 for switch in devices_by_type[_API_NAME_DEVICE_TYPE_SWITCH]:
@@ -982,8 +1081,8 @@ class MerakiOrganisation:
                 return None
             licenses_overview.update(
                 {
-                    "organisation_id": self.organisation_id,
-                    "organisation_name": self.organisation_name,
+                    'organisation_id': self.organisation_id,
+                    'organisation_name': self.organisation_name,
                 }
             )
             return licenses_overview
@@ -1000,8 +1099,8 @@ class MerakiOrganisation:
         def _update_device(device: dict[str, object]) -> MerakiAPIData:
             device.update(
                 {
-                    "organisation_id": self.organisation_id,
-                    "organisation_name": self.organisation_name,
+                    'organisation_id': self.organisation_id,
+                    'organisation_name': self.organisation_name,
                     'network_name': self._networks.get(device.get(_API_NAME_NETWORK_ID)).name,
                 }
             )
@@ -1027,7 +1126,7 @@ class MerakiOrganisation:
                 _LOGGER.debug(f'Host without name _get_device_piggyback serial: {serial}')
                 return None
         except KeyError as e:
-            _LOGGER.debug("Organisation ID: %r: Get device piggyback: %r", self.organisation_id, e)
+            _LOGGER.debug('Organisation ID: %r: Get device piggyback: %r', self.organisation_id, e)
             return None
 
     @staticmethod
@@ -1076,8 +1175,9 @@ def _write_sections(sections: Iterable[Section]) -> None:
 @dataclass(frozen=True)
 class CachePerSection:
     appliance_performance: int
-    appliance_uplinks_usage: int
+    appliance_ports: int
     appliance_uplinks: int
+    appliance_uplinks_usage: int
     appliance_vpns: int
     cellular_uplinks: int
     device_info: int
@@ -1110,39 +1210,39 @@ class Args(Namespace):
 def parse_arguments(argv: Sequence[str] | None) -> Args:
     parser = create_default_argument_parser(description=__doc__)
 
-    parser.add_argument("hostname")
+    parser.add_argument('hostname')
     parser.add_argument(
-        "apikey",
-        help="API key for the Meraki API dashboard access.",
+        'apikey',
+        help='API key for the Meraki API dashboard access.',
     )
 
-    parser.add_argument("--proxy", type=str)
+    parser.add_argument('--proxy', type=str)
 
     # parser.add_argument(
-    #     "--sections",
-    #     nargs="+",
+    #     '--sections',
+    #     nargs='+',
     #     choices=list(_SECTION_NAME_MAP),
     #     default=list(_SECTION_NAME_MAP),
-    #     help="Explicit sections that are collected.",
+    #     help='Explicit sections that are collected.',
     # )
 
     parser.add_argument(
-        "--excluded-sections",
-        nargs="*",
+        '--excluded-sections',
+        nargs='*',
         choices=list(_SECTION_NAME_MAP),
         default=[],
-        help="Sections that are excluded form data collected.",
+        help='Sections that are excluded form data collected.',
     )
 
     parser.add_argument(
-        "--orgs",
-        nargs="+",
+        '--orgs',
+        nargs='+',
         default=[],
-        help="Explicit organisation IDs that are checked.",
+        help='Explicit organisation IDs that are checked.',
     )
 
     # parser.add_argument(
-    #     "--prefix-suffix",
+    #     '--prefix-suffix',
     #     nargs=5,
     #     action='append',
     #     default=[],
@@ -1168,13 +1268,14 @@ def parse_arguments(argv: Sequence[str] | None) -> Args:
 
     parser.add_argument(
         '--cache-per-section',
-        nargs="+",
+        nargs='+',
         type=int,
-        help="List of cache time per section in minutes",
+        help='List of cache time per section in minutes',
         default=[
             _SEC_CACHE_APPLIANCE_PERFORMANCE,
-            _SEC_CACHE_APPLIANCE_UPLINKS_USAGE,
+            _SEC_CACHE_APPLIANCE_PORTS,
             _SEC_CACHE_APPLIANCE_UPLINKS,
+            _SEC_CACHE_APPLIANCE_UPLINKS_USAGE,
             _SEC_CACHE_APPLIANCE_VPNS,
             _SEC_CACHE_CELLULAR_UPLINKS,
             _SEC_CACHE_DEVICE_INFO,
@@ -1182,13 +1283,13 @@ def parse_arguments(argv: Sequence[str] | None) -> Args:
             _SEC_CACHE_DEVICE_UPLINKS_INFO,
             _SEC_CACHE_LICENSES_OVERVIEW,
             _SEC_CACHE_NETWORKS,
+            _SEC_CACHE_ORGANISATIONS,
             _SEC_CACHE_ORG_API_REQUESTS,
             _SEC_CACHE_ORG_SWITCH_PORTS_STATUSES,
-            _SEC_CACHE_ORGANISATIONS,
             _SEC_CACHE_SENSOR_READINGS,
             _SEC_CACHE_SWITCH_PORTS_STATUSES,
             _SEC_CACHE_WIRELESS_DEVICE_STATUS,
-            _SEC_CACHE_WIRELESS_ETHERNET_STATUSES
+            _SEC_CACHE_WIRELESS_ETHERNET_STATUSES,
         ]
     )
 
diff --git a/source/cmk_addons_plugins/meraki/lib/utils.py b/source/cmk_addons_plugins/meraki/lib/utils.py
index 810af8679a6934857233ada91dab85ca4687af15..2301c95996f5a4436484f3db6aa791417910c34b 100644
--- a/source/cmk_addons_plugins/meraki/lib/utils.py
+++ b/source/cmk_addons_plugins/meraki/lib/utils.py
@@ -23,23 +23,24 @@ from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import CheckResul
 MerakiAPIData = Mapping[str, object]
 
 # parameter names for agent options
-_SEC_NAME_ORGANISATIONS: Final = "_organisations"  # internal use runs always
-_SEC_NAME_DEVICE_INFO: Final = "_device_info"  # Not configurable, needed for piggyback
-_SEC_NAME_NETWORKS: Final = "_networks"  # internal use, runs always, needed for network names
-_SEC_NAME_ORG_API_REQUESTS: Final = "api-requests-by-organization"  # internal use, runs always
-
-_SEC_NAME_APPLIANCE_UPLINKS: Final = "appliance-uplinks"
-_SEC_NAME_APPLIANCE_UPLINKS_USAGE: Final = "appliance-uplinks-usage"
-_SEC_NAME_APPLIANCE_VPNS: Final = "appliance-vpns"
-_SEC_NAME_APPLIANCE_PERFORMANCE: Final = "appliance-performance"
-_SEC_NAME_CELLULAR_UPLINKS: Final = "cellular-uplinks"
-_SEC_NAME_DEVICE_STATUSES: Final = "device-status"
-_SEC_NAME_DEVICE_UPLINKS_INFO: Final = "device-uplinks-info"
-_SEC_NAME_LICENSES_OVERVIEW: Final = "licenses-overview"
-_SEC_NAME_SENSOR_READINGS: Final = "sensor-readings"
-_SEC_NAME_SWITCH_PORTS_STATUSES: Final = "switch-ports-statuses"
-_SEC_NAME_WIRELESS_DEVICE_STATUS: Final = "wireless-device-status"
-_SEC_NAME_WIRELESS_ETHERNET_STATUSES: Final = "wireless-ethernet-statuses"
+_SEC_NAME_ORGANISATIONS: Final = '_organisations'  # internal use runs always
+_SEC_NAME_DEVICE_INFO: Final = '_device_info'  # Not configurable, needed for piggyback
+_SEC_NAME_NETWORKS: Final = '_networks'  # internal use, runs always, needed for network names
+_SEC_NAME_ORG_API_REQUESTS: Final = 'api-requests-by-organization'  # internal use, runs always
+
+_SEC_NAME_APPLIANCE_UPLINKS: Final = 'appliance-uplinks'
+_SEC_NAME_APPLIANCE_PORTS: Final = 'appliance-ports'
+_SEC_NAME_APPLIANCE_UPLINKS_USAGE: Final = 'appliance-uplinks-usage'
+_SEC_NAME_APPLIANCE_VPNS: Final = 'appliance-vpns'
+_SEC_NAME_APPLIANCE_PERFORMANCE: Final = 'appliance-performance'
+_SEC_NAME_CELLULAR_UPLINKS: Final = 'cellular-uplinks'
+_SEC_NAME_DEVICE_STATUSES: Final = 'device-status'
+_SEC_NAME_DEVICE_UPLINKS_INFO: Final = 'device-uplinks-info'
+_SEC_NAME_LICENSES_OVERVIEW: Final = 'licenses-overview'
+_SEC_NAME_SENSOR_READINGS: Final = 'sensor-readings'
+_SEC_NAME_SWITCH_PORTS_STATUSES: Final = 'switch-ports-statuses'
+_SEC_NAME_WIRELESS_DEVICE_STATUS: Final = 'wireless-device-status'
+_SEC_NAME_WIRELESS_ETHERNET_STATUSES: Final = 'wireless-ethernet-statuses'
 
 
 # api cache defaults per section
@@ -60,22 +61,21 @@ _SEC_CACHE_SENSOR_READINGS = 0
 _SEC_CACHE_SWITCH_PORTS_STATUSES = 0
 _SEC_CACHE_WIRELESS_DEVICE_STATUS = 30
 _SEC_CACHE_WIRELESS_ETHERNET_STATUSES = 30
-
-
+_SEC_CACHE_APPLIANCE_PORTS = 30
 
 # Early Access
-_SEC_NAME_ORG_SWITCH_PORTS_STATUSES: Final = "org-switch-ports-statuses"
+_SEC_NAME_ORG_SWITCH_PORTS_STATUSES: Final = 'org-switch-ports-statuses'
 
 
 @dataclass(frozen=True)
 class MerakiNetwork:
-    id: str  # "N_24329156",
-    name: str  # "Main Office",
-    product_types: Sequence[str]  # ["appliance", "switch", "wireless"]
-    time_zone: str  # "America/Los_Angeles",
-    tags: Sequence[str]  # [ "tag1", "tag2" ],
-    enrollment_string: str | None  # "my-enrollment-string",
-    notes: str  # "Additional description of the network",
+    id: str  # 'N_24329156',
+    name: str  # 'Main Office',
+    product_types: Sequence[str]  # ['appliance', 'switch', 'wireless']
+    time_zone: str  # 'America/Los_Angeles',
+    tags: Sequence[str]  # [ 'tag1', 'tag2' ],
+    enrollment_string: str | None  # 'my-enrollment-string',
+    notes: str  # 'Additional description of the network',
     is_bound_to_config_template: bool  # false
     organisation_id: str
     organisation_name: str
@@ -97,7 +97,7 @@ def check_last_reported_ts(
     if (age := time.time() - last_reported_ts) < 0:
         yield Result(
             state=State.OK,
-            summary="Negative timespan since last report time.",
+            summary='Negative timespan since last report time.',
         )
         return
     if levels_upper:
diff --git a/source/cmk_addons_plugins/meraki/rulesets/switch_ports_statuses.py b/source/cmk_addons_plugins/meraki/rulesets/switch_ports_statuses.py
index 3cea6f758399ab1aae5ec9efe18d8f6ed2f252f3..5c2f580a360e54d38831d46a41962e42c4f4c6de 100644
--- a/source/cmk_addons_plugins/meraki/rulesets/switch_ports_statuses.py
+++ b/source/cmk_addons_plugins/meraki/rulesets/switch_ports_statuses.py
@@ -15,6 +15,10 @@
 # 2024-06-27: refactored for CMK 2.3
 # 2024-06-30: renamed from cisco_meraki_switch_ports_statuses.py in to switch_ports_statuses.py
 #             added params from discovery as render only
+# 2024-11-17: incompatible change to match changed port status check -> recreate your discovery rule
+# 2024-11-23: added missing discovery parameters admin_state and operational_state
+#             removed discovery parameters 'enabled' and 'status'
+#             reference to section organization_switch_ports removed, missing traffic, lldp, cdp, stp, ...
 
 from cmk.rulesets.v1 import Label, Title, Help
 from cmk.rulesets.v1.form_specs import (
@@ -29,11 +33,6 @@ from cmk.rulesets.v1.form_specs import (
 )
 from cmk.rulesets.v1.rule_specs import CheckParameters, DiscoveryParameters, HostAndItemCondition, Topic
 
-from cmk_addons.plugins.meraki.lib.utils import (
-    _SEC_NAME_ORG_SWITCH_PORTS_STATUSES,
-    _SEC_NAME_SWITCH_PORTS_STATUSES,
-)
-
 
 def _parameter_form():
     return Dictionary(
@@ -55,17 +54,17 @@ def _parameter_form():
                 )),
             'state_speed_change': DictElement(
                 parameter_form=ServiceState(
-                    title=Title('Monitoring state if speed is changed'),
+                    title=Title('Monitoring state if speed has changed'),
                     prefill=DefaultValue(ServiceState.WARN),
                 )),
             'state_admin_change': DictElement(
                 parameter_form=ServiceState(
-                    title=Title('Monitoring state if admin state is changed'),
+                    title=Title('Monitoring state if admin state has changed'),
                     prefill=DefaultValue(ServiceState.WARN),
                 )),
             'state_op_change': DictElement(
                 parameter_form=ServiceState(
-                    title=Title('Monitoring state if operational state is changed'),
+                    title=Title('Monitoring state if operational state has changed'),
                     prefill=DefaultValue(ServiceState.WARN),
                 )),
             'show_traffic': DictElement(
@@ -76,23 +75,20 @@ def _parameter_form():
                     help_text=Help(
                         'Use only with cache disabled in the Meraki special agent settings. '
                         'Depending on your Meraki organization size (in terms of number of switches) '
-                        'this will exceeds the limits of the allowed API requests per second. You can try to '
-                        'enable "Early Access" in the Meraki dashboard. In the Meraki special agent settings '
-                        f'switch from "{_SEC_NAME_SWITCH_PORTS_STATUSES}" to "{_SEC_NAME_ORG_SWITCH_PORTS_STATUSES}". '
-                        'This will fetch all the switch data with one API request instead of one request for each '
-                        'switch.'
+                        'this will exceeds the limits of the allowed API requests per second.'
                     ),
                 )),
             # params from discovery
-            'enabled': DictElement(
+            'admin_state': DictElement(
                 render_only=True,
                 parameter_form=String(
                     title=Title('Discovered admin state')
-                )),
-            'status': DictElement(
+                )
+            ),
+            'operational_state': DictElement(
                 render_only=True,
                 parameter_form=String(
-                    title=Title('Discovered status')
+                    title=Title('Discovered operational state')
                 )
             ),
             'speed': DictElement(
@@ -100,7 +96,7 @@ def _parameter_form():
                 parameter_form=String(
                     title=Title('Discovered speed')
                 )
-            )
+            ),
         },
     )
 
@@ -117,33 +113,42 @@ rule_spec_cisco_meraki_switch_ports_statuses = CheckParameters(
 def _discovery_form():
     return Dictionary(
         elements={
-            'discovered_port_states': DictElement(
+            'operational_port_states': DictElement(
                 parameter_form=MultipleChoice(
-                    title=Title('Select Ports to discover'),
+                    title=Title('Match port states'),
                     elements=[
                         MultipleChoiceElement(
-                            title=Title('Admin enabled'),
-                            name='admin_enabled',
+                            title=Title('1 - up'),
+                            name='up',
                         ),
                         MultipleChoiceElement(
-                            title=Title('Admin disabled'),
-                            name='admin_disabled',
+                            title=Title('2 - down'),
+                            name='down',
                         ),
+                    ],
+                    help_text=Help('Apply this rule only to interfaces whose port state is listed below.'),
+                    prefill=DefaultValue([
+                        'up',
+                        'down',
+                    ])
+                )),
+            'admin_port_states': DictElement(
+                parameter_form=MultipleChoice(
+                    title=Title('Match admin states'),
+                    elements=[
                         MultipleChoiceElement(
-                            title=Title('Connected'),
-                            name='connected',
+                            title=Title('1 - up'),
+                            name='up',
                         ),
                         MultipleChoiceElement(
-                            title=Title('Disconnected'),
-                            name='disconnected',
+                            title=Title('2 - down'),
+                            name='down',
                         ),
                     ],
-                    help_text=Help('Select the port states for discovery'),
+                    help_text=Help('Apply this rule only to interfaces whose admin state is listed below'),
                     prefill=DefaultValue([
-                        'admin_enabled',
-                        'admin_disabled',
-                        'connected',
-                        'disconnected',
+                        'up',
+                        'down',
                     ])
                 )),
         },
diff --git a/source/packages/cisco_meraki b/source/packages/cisco_meraki
index 21fb4c5e2211b498062e91125b9a9870cd1249f2..0687aaf2b189236c125c5ba846f8038ebc1de7f5 100644
--- a/source/packages/cisco_meraki
+++ b/source/packages/cisco_meraki
@@ -63,7 +63,7 @@
            'web': ['plugins/views/cisco_meraki.py']},
  'name': 'cisco_meraki',
  'title': 'Cisco Meraki special agent',
- 'version': '1.3.7-20241116',
+ 'version': '1.4.1-20241217',
  'version.min_required': '2.3.0b1',
  'version.packaged': 'cmk-mkp-tool 0.2.0',
  'version.usable_until': '2.4.0b1'}