diff --git a/agent_based/cisco_asyncos_license.py b/agent_based/cisco_asyncos_license.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d8bc5aa8e55fc35df297b971a87eebd36e68bea
--- /dev/null
+++ b/agent_based/cisco_asyncos_license.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2020-02-10
+#
+# monitors license status of Cisco IronPort Appliances (ESA/SMA/WSA)
+# Tested with: C380, M380, C370, M670, S370
+#
+# 2021-03-25: rewrite for CMK2.0
+#
+# sample snmpwalk:
+#
+# OMD[cmk16x]:~$ snmpwalk  -v2c -c public localhost -m ASYNCOS-MAIL-MIB -ObentU keyExpirationTable
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.1 = INTEGER: 1
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.2 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.3 = INTEGER: 3
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.4 = INTEGER: 4
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.5 = INTEGER: 5
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.6 = INTEGER: 6
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.7 = INTEGER: 7
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.8 = INTEGER: 8
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.9 = INTEGER: 9
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.10 = INTEGER: 10
+# .1.3.6.1.4.1.15497.1.1.1.12.1.1.11 = INTEGER: 11
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.1 = STRING: Bounce Verification
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.2 = STRING: Data Loss Prevention
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.3 = STRING: External Threat Feeds
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.4 = STRING: File Analysis
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.5 = STRING: File Reputation
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.6 = STRING: Incoming Mail Handling
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.7 = STRING: IronPort Anti-Spam
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.8 = STRING: IronPort Email Encryption
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.9 = STRING: McAfee
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.10 = STRING: Outbreak Filters
+# .1.3.6.1.4.1.15497.1.1.1.12.1.2.11 = STRING: Sophos Anti-Virus
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.1 = INTEGER: 1
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.2 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.3 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.4 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.5 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.6 = INTEGER: 1
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.7 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.8 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.9 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.10 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.3.11 = INTEGER: 2
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.1 = Gauge32: 0
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.2 = Gauge32: 0
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.3 = Gauge32: 32542740
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.4 = Gauge32: 32542804
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.5 = Gauge32: 32542804
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.6 = Gauge32: 0
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.7 = Gauge32: 32542740
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.8 = Gauge32: 0
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.9 = Gauge32: 1463722
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.10 = Gauge32: 32542740
+# .1.3.6.1.4.1.15497.1.1.1.12.1.4.11 = Gauge32: 32542740
+#
+# OMD[cmk16x]:~$ snmpwalk  -v2c -c public localhost -m ASYNCOS-MAIL-MIB  keyExpirationTable
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.1 = INTEGER: 1
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.2 = INTEGER: 2
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.3 = INTEGER: 3
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.4 = INTEGER: 4
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.5 = INTEGER: 5
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.6 = INTEGER: 6
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.7 = INTEGER: 7
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.8 = INTEGER: 8
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.9 = INTEGER: 9
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.10 = INTEGER: 10
+# ASYNCOS-MAIL-MIB::keyExpirationIndex.11 = INTEGER: 11
+# ASYNCOS-MAIL-MIB::keyDescription.1 = STRING: Bounce Verification
+# ASYNCOS-MAIL-MIB::keyDescription.2 = STRING: Data Loss Prevention
+# ASYNCOS-MAIL-MIB::keyDescription.3 = STRING: External Threat Feeds
+# ASYNCOS-MAIL-MIB::keyDescription.4 = STRING: File Analysis
+# ASYNCOS-MAIL-MIB::keyDescription.5 = STRING: File Reputation
+# ASYNCOS-MAIL-MIB::keyDescription.6 = STRING: Incoming Mail Handling
+# ASYNCOS-MAIL-MIB::keyDescription.7 = STRING: IronPort Anti-Spam
+# ASYNCOS-MAIL-MIB::keyDescription.8 = STRING: IronPort Email Encryption
+# ASYNCOS-MAIL-MIB::keyDescription.9 = STRING: McAfee
+# ASYNCOS-MAIL-MIB::keyDescription.10 = STRING: Outbreak Filters
+# ASYNCOS-MAIL-MIB::keyDescription.11 = STRING: Sophos Anti-Virus
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.1 = INTEGER: true(1)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.2 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.3 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.4 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.5 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.6 = INTEGER: true(1)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.7 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.8 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.9 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.10 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keyIsPerpetual.11 = INTEGER: false(2)
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.1 = Gauge32: 0
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.2 = Gauge32: 0
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.3 = Gauge32: 32542740
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.4 = Gauge32: 32542804
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.5 = Gauge32: 32542804
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.6 = Gauge32: 0
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.7 = Gauge32: 32542740
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.8 = Gauge32: 0
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.9 = Gauge32: 1463722
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.10 = Gauge32: 32542740
+# ASYNCOS-MAIL-MIB::keySecondsUntilExpire.11 = Gauge32: 32542740
+#
+
+import time
+from typing import Mapping, List, NamedTuple
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    check_levels,
+    Result,
+    SNMPTree,
+    contains,
+    State,
+    render,
+)
+
+
+def get_isperpetual(isperpetual):
+    s_status = {
+        '1': True,
+        '2': False
+    }
+    return s_status.get(isperpetual, False)
+
+
+class CiscoAsyncosLicense(NamedTuple):
+    perpetual: bool
+    secondsuntilexpire: int
+    daysuntilexpire: int
+    expiredate: str
+
+
+# [[
+#   ['Bounce Verification', '1', '0'],
+#   ['Data Loss Prevention', '2', '0'],
+#   ['External Threat Feeds', '2', '32542740'],
+#   ['File Analysis', '2', '32542804'],
+#   ['File Reputation', '2', '32542804'],
+#   ['Incoming Mail Handling', '1', '0'],
+#   ['IronPort Anti-Spam', '2', '32542740'],
+#   ['IronPort Email Encryption', '2', '0'],
+#   ['McAfee', '2', '1463722'],
+#   ['Outbreak Filters', '2', '32542740'],
+#   ['Sophos Anti-Virus', '2', '32542740']
+#  ]]
+def parse_cisco_asyncos_license(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosLicense]:
+    licenses = {}
+    for license, isperpetual, secondsuntilexpire in string_table[0]:
+        licenses.update({license: CiscoAsyncosLicense(
+            perpetual=get_isperpetual(isperpetual),
+            secondsuntilexpire=int(secondsuntilexpire),
+            daysuntilexpire=int(secondsuntilexpire) // 3600 // 24,
+            expiredate=time.strftime("%d %b %Y", time.localtime(time.time() + int(secondsuntilexpire)))
+        )})
+    return licenses
+
+
+# {
+#  'Bounce Verification': CiscoAsyncosLicense(perpetual=True, secondsuntilexpire=0, daysuntilexpire=0, expiredate='25 Mar 2021'),
+#  'Data Loss Prevention': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=0, daysuntilexpire=0, expiredate='25 Mar 2021'),
+#  'External Threat Feeds': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542740, daysuntilexpire=376, expiredate='06 Apr 2022'),
+#  'File Analysis': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542804, daysuntilexpire=376, expiredate='06 Apr 2022'),
+#  'File Reputation': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542804, daysuntilexpire=376, expiredate='06 Apr 2022'),
+#  'Incoming Mail Handling': CiscoAsyncosLicense(perpetual=True, secondsuntilexpire=0, daysuntilexpire=0, expiredate='25 Mar 2021'),
+#  'IronPort Anti-Spam': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542740, daysuntilexpire=376, expiredate='06 Apr 2022'),
+#  'IronPort Email Encryption': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=0, daysuntilexpire=0, expiredate='25 Mar 2021'),
+#  'McAfee': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=1463722, daysuntilexpire=16, expiredate='11 Apr 2021'),
+#  'Outbreak Filters': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542740, daysuntilexpire=376, expiredate='06 Apr 2022'),
+#  'Sophos Anti-Virus': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542740, daysuntilexpire=376, expiredate='06 Apr 2022')
+# }
+
+def discovery_cisco_asyncos_license(section: Mapping[str, CiscoAsyncosLicense]) -> DiscoveryResult:
+    yield Service()
+
+# Parameters({'expire': (400, 360), 'features_ignore': ['Data Loss Prevention']})
+def check_cisco_asyncos_license(params, section: Mapping[str, CiscoAsyncosLicense]) -> CheckResult:
+    features_ignore = params.get('features_ignore', [])
+    warn, crit = params.get('expire')
+    ignore_count = 0
+    for license in section.keys():
+        if section[license].perpetual:
+            yield Result(state=State.OK, notice='%s is perpetual (will not expire)' % license)
+        elif license in features_ignore:
+            yield Result(state=State.OK, notice='%s will expire at %s (%s days). Feature ignored!' % (license, section[license].expiredate, section[license].daysuntilexpire))
+            ignore_count += 1
+        elif section[license].secondsuntilexpire == 0:
+            yield  Result(state=State.CRIT, notice='%s has expired or is not licensed' % license)
+        else:
+            if section[license].daysuntilexpire < crit:
+                state = State.CRIT
+            elif section[license].daysuntilexpire < warn:
+                state = State.WARN
+            else:
+                state = State.OK
+
+            yield Result(state=state, notice='%s will expire at %s (%s days)' % (license, section[license].expiredate, section[license].daysuntilexpire))
+
+    yield Result(state=State.OK, summary='%d/%d Features found/ignored' % (len(section.keys()), ignore_count))
+
+register.snmp_section(
+    name='cisco_asyncos_license',
+    parse_function=parse_cisco_asyncos_license,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.15497.1.1.1.12.1',  # ASYNCOS-MAIL-MIB::keyExpirationEntry
+            oids=[
+                '2',  # keyDescription
+                '3',  # keyIsPerpetual
+                '4',  # keySecondsUntilExpire
+            ]
+        ),
+    ],
+    detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'),
+)
+
+register.check_plugin(
+    name='cisco_asyncos_license',
+    service_name='License',
+    discovery_function=discovery_cisco_asyncos_license,
+    check_function=check_cisco_asyncos_license,
+    check_default_parameters={'expire': (30, 7)},
+    check_ruleset_name='cisco_asyncos_license',
+)
diff --git a/agent_based/cisco_asyncos_resources.py b/agent_based/cisco_asyncos_resources.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f4cda0ba9c5f5ffa641fcc2318af5af468bde98
--- /dev/null
+++ b/agent_based/cisco_asyncos_resources.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2020-03-08
+#
+# monitors status Cisco IronPort Appliances (ESA) system resources
+# Tested with: C380, C370
+#
+# 2021-03-25: rewrite for CMK2.0
+#
+# .1.3.6.1.4.1.15497.1.1.1.6.0 = INTEGER: 1
+#
+# ASYNCOS-MAIL-MIB::resourceConservationReason.0 = INTEGER: noResourceConservation(1)
+#
+#
+from typing import Mapping, List, NamedTuple
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    check_levels,
+    Result,
+    SNMPTree,
+    contains,
+    State,
+    render,
+)
+
+
+def get_status_readable(st: str) -> str:
+    states = {
+        '1': 'none',
+        '2': 'memory shortage',
+        '3': 'queue space shortage',
+        '4': 'queue Full',
+    }
+    return states.get(st, st)
+
+
+def get_cmk_state(st: str) -> State:
+    states = {
+        '1': State.OK,
+        '2': State.WARN,
+        '3': State.WARN,
+        '4': State.CRIT,
+    }
+    return states.get(st, State.CRIT)
+
+
+class CiscoAsyncosResources(NamedTuple):
+    state: State
+    status_readable: str
+
+
+def parse_cisco_asyncos_bandwidth(string_table: List[StringTable]) -> CiscoAsyncosResources:
+    return CiscoAsyncosResources(
+        state=get_cmk_state(string_table[0][0][0]),
+        status_readable=get_status_readable(string_table[0][0][0])
+    )
+
+
+def discovery_cisco_asyncos_resources(section: CiscoAsyncosResources) -> DiscoveryResult:
+    yield Service()
+
+
+def check_cisco_asyncos_resources(section: CiscoAsyncosResources) -> CheckResult:
+    yield Result(state=section.state, notice='Resource conservation %s' % section.status_readable)
+
+
+register.snmp_section(
+    name='cisco_asyncos_resources',
+    parse_function=parse_cisco_asyncos_bandwidth,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.15497.1.1.1',  # ASYNCOS-MAIL-MIB
+            oids=[
+                '6',  # resourceConservationReason
+            ]
+        ),
+    ],
+    detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'),
+)
+
+register.check_plugin(
+    name='cisco_asyncos_resources',
+    service_name='Resources',
+    discovery_function=discovery_cisco_asyncos_resources,
+    check_function=check_cisco_asyncos_resources,
+)
diff --git a/checks/cisco_asyncos_resources b/checks/cisco_asyncos_resources
deleted file mode 100644
index 761a5bbfc8b1b37d01bcead341875183602632c0..0000000000000000000000000000000000000000
--- a/checks/cisco_asyncos_resources
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
-#
-# Author: Th.L.
-# Date: 08-03-2020
-#
-# monitors status Cisco IronPort Appliances (ESA) system resources
-# Tested with: C380, C370
-#
-# check_mk is free software;  you can redistribute it and/or modify it
-# under the  terms of the  GNU General Public License  as published by
-# the Free Software Foundation in version 2.  check_mk is  distributed
-# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
-# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
-# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
-# tails. You should have  received  a copy of the  GNU  General Public
-# License along with GNU Make; see the file  COPYING.  If  not,  write
-# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
-# Boston, MA 02110-1301 USA.
-#
-# .1.3.6.1.4.1.15497.1.1.1.6.0 = INTEGER: 1
-#
-# ASYNCOS-MAIL-MIB::resourceConservationReason.0 = INTEGER: noResourceConservation(1)
-#
-# sample info
-# [[u'1', u'1']]
-#
-
-
-def inventory_cisco_asyncos_resources(info):
-    if len(info[0]) == 1:
-        return [(None, None)]
-
-
-def check_cisco_asyncos_resources(_no_item, _no_params, info):
-    if len(info[0]) == 1:
-        recsourceStatus = info[0][0]
-        recsourceStatus = int(recsourceStatus)
-
-        if recsourceStatus == 1:
-            yield 0, 'no resource conservation'
-        elif recsourceStatus ==2:
-            yield 1, 'Resource conservation: memory shortage'
-        elif recsourceStatus ==3:
-            yield 1, 'Resource conservation: queue space shortage'
-        elif recsourceStatus == 4:
-            yield 2, 'Resource conservation: queue Full'
-
-
-check_info['cisco_asyncos_resources'] = {
-    'inventory_function': inventory_cisco_asyncos_resources,
-    'check_function': check_cisco_asyncos_resources,
-    'service_description': 'Resources',
-    'has_perfdata': False,
-    'snmp_info': (
-        '.1.3.6.1.4.1.15497.1.1.1',  # ASYNCOS-MAIL-MIB
-        [
-            '6',  # resourceConservationReason
-        ]),
-    'snmp_scan_function':  lambda oid: oid('.1.3.6.1.2.1.1.1.0').find('AsyncOS') != -1,
-    # 'snmp_scan_function': scan_cisco_asyncos,
-    # 'includes': ['cisco_asyncos.include'],
-}
diff --git a/cisco_asyncos.mkp b/cisco_asyncos.mkp
index d957f13594041c7efc82b37b452320063c94c037..048e9c6c3a99532a19865e7e3de65e825043c284 100644
Binary files a/cisco_asyncos.mkp and b/cisco_asyncos.mkp differ
diff --git a/packages/cisco_asyncos b/packages/cisco_asyncos
index 513ab34391ad3f1d2c98d6644cfc3b3d6550d291..96321b665aec7202204d5d85e86e6d1f0a0f8b4d 100644
--- a/packages/cisco_asyncos
+++ b/packages/cisco_asyncos
@@ -35,10 +35,10 @@
                            'cisco_asyncos_conn.py',
                            'cisco_asyncos_dns.py',
                            'cisco_asyncos_messageage.py',
-                           'cisco_asyncos_queue.py'],
-           'checks': ['cisco_asyncos_license',
-                      'cisco_asyncos_update',
-                      'cisco_asyncos_resources'],
+                           'cisco_asyncos_queue.py',
+                           'cisco_asyncos_resources.py',
+                           'cisco_asyncos_license.py'],
+           'checks': ['cisco_asyncos_update'],
            'web': ['plugins/wato/cisco_asyncos_license.py',
                    'plugins/wato/cisco_asyncos_queue.py',
                    'plugins/wato/cisco_asyncos_update.py',
diff --git a/web/plugins/wato/cisco_asyncos_license.py b/web/plugins/wato/cisco_asyncos_license.py
index 95fd5ef285406577ec1745977ab041f5b1ada685..bd4accbb849d41c04feb1596cb5b45058d4b4e11 100644
--- a/web/plugins/wato/cisco_asyncos_license.py
+++ b/web/plugins/wato/cisco_asyncos_license.py
@@ -1,31 +1,51 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 #
 #
-register_check_parameters(
-    subgroup_applications,
-    'cisco_asyncos_license',
-    _('Cisco AsyncOS license'),
-    Dictionary(
-       #  help=_(''),
-        elements=[
-            ('features_ignore',
-              ListOfStrings(
-                  title=_('license features to ignore'),
-                  orientation='vertical',
-                  help=_('there will be no warning/critical if this features are expired'
-                         'Examples: McAfee, IronPort Email Encryption, Data Loss Prevention, etc.'),
-              )
-             ),
-            ('expire',
-             Tuple(
-                 title=_('Levels for licence expiration in days'),
-                 elements=[
-                     Integer(title=_('Warning'), default_value=30, unit=_('days before expiration')),
-                     Integer(title=_('Critical'), default_value=7, unit=_('days before expiration')),
-                 ])),
-        ],
-    ),
-    None,
-    match_type='dict',
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    Integer,
+    TextAscii,
+    ListOfStrings,
+    Tuple,
 )
+
+from cmk.gui.plugins.wato import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+)
+
+
+def _parameter_valuespec_cisco_asyncos_license():
+    return Dictionary(elements=[
+        ('features_ignore',
+         ListOfStrings(
+             title=_('License features to ignore'),
+             orientation='vertical',
+             allow_empty=False,
+             # valuespec=Integer(minvalue=1, maxvalue=99),
+             help=_('there will be no warning/critical if this features are expired'
+                    'Examples: McAfee, IronPort Email Encryption, Data Loss Prevention, etc.'),
+         )
+         ),
+        ('expire',
+         Tuple(
+             title=_('Levels for licence expiration in days'),
+             elements=[
+                 Integer(title=_('Warning'), default_value=30, unit=_('days before expiration')),
+                 Integer(title=_('Critical'), default_value=7, unit=_('days before expiration')),
+             ])),
+    ])
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='cisco_asyncos_license',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('Cisco AsyncOS license'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_cisco_asyncos_license,
+        title=lambda: _('Cisco AsyncOS license'),
+    ))