diff --git a/README.md b/README.md
index 6d6b581bd918709a6420e4f8691b8d7332eb8f8c..5ca281870c48d33326ebf8e8a03f4737c6aaa717 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/packagee-0.1.2-20230706.mkp "package-0.1.2-20230706.mkp"
+[PACKAGE]: ../../raw/master/vzlogger-0.0.1-230806.mkp "vzlogger-0.0.1-230806.mkp"
 # Title
 
 A short description about the plugin
diff --git a/agent_based/vzlogger.py b/agent_based/vzlogger.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a58833b1aa771a9ed023a18c4f9d4dc303a964f
--- /dev/null
+++ b/agent_based/vzlogger.py
@@ -0,0 +1,210 @@
+#!/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  : 2023-08-05
+# File  : vzlogger.py
+#
+# vzlogger
+#
+#
+# https://wiki.volkszaehler.org/software/controller/vzlogger
+#
+#
+# 2023-08-05: initial release
+
+import json
+import time
+from dataclasses import dataclass
+from typing import Dict, Mapping, Tuple, Optional, Any
+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,
+    Result,
+    State,
+    check_levels_predictive,
+    check_levels,
+)
+
+
+@dataclass
+class VzLoggerChannel:
+    uuid: str
+    interval: int
+    last: int
+    protocol: str
+    value: float
+    value_last: int
+
+
+_vzlogger_channel_types = {
+    'meter_reading': 'Meter reading',
+    'voltage': 'Voltage',
+    'electrical_power': 'Electrical Power',
+}
+
+
+def _render_voltage(value: float) -> str:
+    return f'{value:.2f} V'
+
+
+def _render_electrical_power(value: float) -> str:
+    return f'{value:.2f} W'
+
+
+def _render_meter_reading(value: float) -> str:
+    return f'{value:.0f} kWh'
+
+
+def _yield_channel_details(channel: VzLoggerChannel) -> CheckResult:
+    yield Result(state=State.OK, notice=f'UUID: {channel.uuid}')
+    yield Result(state=State.OK, notice=f'Interval: {channel.interval}')
+    yield Result(state=State.OK, notice=f'Last: {time.ctime(channel.last)}')
+    yield Result(state=State.OK, notice=f'Protocol: {channel.protocol}')
+    yield Result(state=State.OK, notice=f'Value: {channel.value}')
+    yield Result(state=State.OK, notice=f'Value last: {time.ctime(channel.value_last)}')
+
+
+def _yield_channel_value(
+        value: float,
+        label: str,
+        metric: str,
+        render_func: Any,
+        levels_upper: Optional[Tuple[int, int]] = None,
+        level_lower: Optional[Tuple[int, int]] = None,
+) -> CheckResult:
+    metric = metric.lower().replace(' ', '_').replace('-', '_')
+    yield from check_levels_predictive(
+        value=value,
+        label=label,
+        metric_name=f'{metric}',
+        render_func=render_func,
+        levels=levels_upper,
+        boundaries=(0, None),
+    ) if isinstance(levels_upper, dict) else check_levels(
+        value=value,
+        # label=label,
+        metric_name=f'{metric}',
+        render_func=render_func,
+        levels_upper=levels_upper,
+        levels_lower=level_lower,
+        # boundaries=(0, None),
+    )
+
+
+def parse_vzlogger(string_table: StringTable) -> Dict[str, VzLoggerChannel]:
+    section = {}
+    data = json.loads(string_table[0][0])
+    channels = data['data']
+    for channel in channels:
+        value_last, value = channel['tuples'][0]
+        section[channel['uuid']] = VzLoggerChannel(
+            uuid=channel['uuid'],
+            interval=channel['interval'],
+            last=channel['last'],
+            protocol=channel['protocol'],
+            value=value,
+            value_last=value_last,
+        )
+
+    return section
+
+
+def discovery_vzlogger(params: Mapping[str, any], section: Dict[str, VzLoggerChannel]) -> DiscoveryResult:
+    # add vzlogger channels with info from discovery rule vzlogger
+    for uuid, channel_type, item in params['channels']:
+        if uuid in section.keys():
+            yield Service(
+                item=f'{_vzlogger_channel_types.get(channel_type, uuid)} {item}',
+                parameters={
+                    'channel_type': channel_type,
+                    'uuid': uuid,
+                }
+            )
+            section.pop(uuid)
+
+    # add unknown vzlogger channels
+    for uuid in section.keys():
+        yield Service(
+            item=f'vzlogger {uuid}',
+            parameters={
+                'channel_type': 'unknown',
+                'uuid': uuid,
+            }
+        )
+
+
+def check_vzlogger(item: str, params: Mapping[str, any], section: Dict[str, VzLoggerChannel]) -> CheckResult:
+    try:
+        channel = section[params['uuid']]
+    except KeyError:
+        yield Result(state=State.UNKNOWN, summary=f'Data not found in section')
+        return
+
+    if params['channel_type'] == 'voltage':
+        yield from _yield_channel_value(
+            value=channel.value,
+            label=item[8:],
+            metric=item,
+            render_func=_render_voltage,
+            levels_upper=params.get('levels_upper'),
+            level_lower=params.get('levels_lower'),
+        )
+
+    elif params['channel_type'] == 'electrical_power':
+
+        yield from _yield_channel_value(
+            value=channel.value,
+            label=item[17:],
+            metric=item,
+            render_func=_render_electrical_power,
+            levels_upper=params.get('levels_upper'),
+            level_lower=params.get('levels_lower'),
+        )
+
+    elif params['channel_type'] == 'meter_reading':
+        yield from _yield_channel_value(
+            value=(channel.value/1000),
+            label=item[14:],
+            metric=item,
+            render_func=_render_meter_reading,
+            levels_upper=params.get('levels_upper'),
+            level_lower=params.get('levels_lower'),
+        )
+
+    elif params['channel_type'] not in _vzlogger_channel_types.keys():
+        yield Result(
+            state=State.UNKNOWN,
+            summary=f'Unknown channel type (see details)',
+            details=f'Please configure a channel type and item name in discovery rules -> vzlogger.'
+        )
+        yield from _yield_channel_details(channel)
+
+    else:
+        yield from _yield_channel_details(channel)
+        yield Result(state=State.UNKNOWN, summary=f'not yet implemented')
+
+
+register.agent_section(
+    name='vzlogger',
+    parse_function=parse_vzlogger,
+)
+
+register.check_plugin(
+    name='vzlogger',
+    service_name='%s',
+    discovery_function=discovery_vzlogger,
+    discovery_default_parameters={},
+    discovery_ruleset_name='discovery_vzlogger',
+    check_function=check_vzlogger,
+    check_default_parameters={},
+    check_ruleset_name='vzlogger',
+)
diff --git a/agents/special/agent_vzlogger b/agents/special/agent_vzlogger
new file mode 100755
index 0000000000000000000000000000000000000000..58e1812ec3a0f6a55fc5fec362090df01f4d2dcd
--- /dev/null
+++ b/agents/special/agent_vzlogger
@@ -0,0 +1,18 @@
+#!/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  : 2023-08-05
+# File  : vzlogger.py
+#
+# vzlogger
+#
+# 2023-08-05: initial relese
+#
+from cmk.special_agents.agent_vzlogger import main
+
+if __name__ == '__main__':
+    main()
diff --git a/checks/agent_vzlogger b/checks/agent_vzlogger
new file mode 100644
index 0000000000000000000000000000000000000000..94b4a8b25c8fb6976e558ae8e52fb8866510bcf1
--- /dev/null
+++ b/checks/agent_vzlogger
@@ -0,0 +1,33 @@
+#!/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  : 2023-08-05
+# File  : agent_vzlogger.py
+#
+# vzlogger
+#
+# 2023-08-05: initial release
+
+from typing import Mapping, Any
+
+
+def agent_vzlogger_arguments(params: Mapping[str, Any], hostname: str, ipaddress: str):
+    args = []
+    if params.get('port'):
+        args += ['--port', params['port']]
+    if params.get('timeout'):
+        args += ['--timeout', params['timeout']]
+    if params.get('testing'):
+        args += ['--testing']
+    if params.get('use_ip_address'):
+        args += [ipaddress]
+    else:
+        args += [hostname]
+    return args
+
+
+special_agent_info['vzlogger'] = agent_vzlogger_arguments
diff --git a/gui/wato/check_parameters/agent_vzlogger.py b/gui/wato/check_parameters/agent_vzlogger.py
new file mode 100644
index 0000000000000000000000000000000000000000..e056f731fe1e6f38bfd0790d5c8bbdfa50a2dcc9
--- /dev/null
+++ b/gui/wato/check_parameters/agent_vzlogger.py
@@ -0,0 +1,48 @@
+#!/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  : 2023-08-05
+# File  : vzlogger.py
+#
+# https://wiki.volkszaehler.org/software/controller/vzlogger
+#
+# 2023-08-05: initial release
+
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    ValueSpec,
+    Integer,
+    FixedValue,
+)
+
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.plugins.wato.special_agents.common import RulespecGroupDatasourceProgramsApps
+
+
+def _valuespec_special_agent_vzlogger() -> ValueSpec:
+    return Dictionary(
+        title=_("vzlogger"),
+        elements=[
+            ('port', Integer(title=_('Port'), default_value=8081, minvalue=1, maxvalue=65565)),
+            ('timeout', Integer(title=_('Connection timeout'), default_value=5, minvalue=1, maxvalue=59)),
+            ('use_ip_address', FixedValue(True, title=_('Use IP-Address instead of hostname'), totext='')),
+            ('testing', FixedValue(True, title=_('Use test data only'), totext='')),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupDatasourceProgramsApps,
+        name="special_agents:vzlogger",
+        valuespec=_valuespec_special_agent_vzlogger,
+    )
+)
diff --git a/gui/wato/check_parameters/vzlogger.py b/gui/wato/check_parameters/vzlogger.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4601d48cfc52276184895032d0bd283de7619fd
--- /dev/null
+++ b/gui/wato/check_parameters/vzlogger.py
@@ -0,0 +1,124 @@
+#!/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  : 2023-08-05
+# File  : vzlogger.py
+#
+# vzlogger
+#
+#
+# https://wiki.volkszaehler.org/software/controller/vzlogger
+#
+# 2023-08-05: initial release
+
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    ListOf,
+    TextUnicode,
+    Tuple,
+    DropdownChoice,
+    Integer,
+    TextAscii,
+)
+
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+    RulespecGroupCheckParametersDiscovery,
+    CheckParameterRulespecWithItem,
+    RulespecGroupCheckParametersApplications,
+    Levels,
+)
+
+
+def _parameter_valuespec_vzlogger():
+    return Dictionary(
+        title=_('vzlogger'),
+        elements=[
+            ('levels_upper',
+             Levels(
+                 title=_('Levels (upper)'),
+                 help=_('This sets the upper limits for the vzlogger channel.'),
+                 unit=_(''),
+             )),
+            ('levels_lower',
+             Tuple(
+                 title=_('Levels lower'),
+                 help=_('This sets the lower limits for the vzlogger channel. '
+                        'This will only be used if "Levels (upper)" is not using Predictive Levels.'
+                        ),
+                 elements=[
+                     Integer(title=_('Warning blow'), minvalue=0, unit=_('')),
+                     Integer(title=_('Critical below'), minvalue=0, unit=_('')),
+                 ]))
+
+        ],
+        optional_keys=False,
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name="vzlogger",
+        group=RulespecGroupCheckParametersApplications,
+        parameter_valuespec=_parameter_valuespec_vzlogger,
+        item_spec=lambda: TextAscii(title=_('vzlogger item')),
+    ))
+
+
+def _parameter_valuespec_discovery_vzlogger():
+    return Dictionary(
+        title=_('vzlogger'),
+        elements=[
+            ('channels',
+             ListOf(
+                 Tuple(
+                     orientation='horizontal',
+                     elements=[
+                         TextUnicode(
+                             title=_('UUID'),
+                             help=_(
+                                 'Value must (or better should) match the pattern '
+                                 '^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$'
+                                 '.'
+                             ),
+                             allow_empty=False,
+                             size=36,
+                         ),
+                         DropdownChoice(
+                             title=_('Channel type'),
+                             help=_('Defines what type of counter the channel delivers.'),
+                             choices=[
+                                 ('meter_reading', 'Meter reading'),
+                                 ('voltage', 'Voltage (V)'),
+                                 ('electrical_power', 'Electrical Power (W)'),
+                             ],
+                             sorted=True,
+                         ),
+                         TextUnicode(
+                             title=_('Service name (item)'),
+                             help=_('Name of the service in CMK. Must be unique within the channel type.'),
+                             allow_empty=False,
+                             size=30,
+                         ),
+                     ]),
+                 add_label=_('Add channel'),
+                 movable=False,
+                 title=_('Channels'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupCheckParametersDiscovery,
+        match_type='dict',
+        name='discovery_vzlogger',
+        valuespec=_parameter_valuespec_discovery_vzlogger,
+    ))
diff --git a/lib/python3/cmk/special_agents/agent_vzlogger.py b/lib/python3/cmk/special_agents/agent_vzlogger.py
new file mode 100644
index 0000000000000000000000000000000000000000..caa99224201a0a76f8a799515b7128ea4147d338
--- /dev/null
+++ b/lib/python3/cmk/special_agents/agent_vzlogger.py
@@ -0,0 +1,73 @@
+#!/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  : 2023-08-05
+# File  : vzlogger.py
+#
+# vzlogger
+#
+#
+# https://wiki.volkszaehler.org/software/controller/vzlogger
+#
+# 2023-08-05: initial release
+
+# from __future__ import annotations
+
+import requests
+import json
+import argparse
+from os import environ
+# import logging
+from collections.abc import Sequence
+
+
+from cmk.special_agents.utils.agent_common import (
+    special_agent_main,
+)
+from cmk.special_agents.utils.argument_parsing import Args, create_default_argument_parser
+
+
+def parse_arguments(argv: Sequence[str] | None) -> argparse.Namespace:
+    parser = create_default_argument_parser(description=__doc__)
+    parser.add_argument('hostname', type=str)
+    parser.add_argument('--port', type=int, default=8081)
+    parser.add_argument('--timeout', type=int, default=5)
+    parser.add_argument('--testing', const=True, required=False, action='store_const')
+    # parser.add_argument('--proxy', type=str)
+    return parser.parse_args(argv)
+
+
+def agent_vzlogger_main(args: Args) -> int:  # , retrurn=None
+    _vars = vars(args)
+    _base_dir = environ['OMD_ROOT']
+    vzlogger_file = f'{_base_dir}/vzlogger.json'
+
+    if _vars['testing']:
+        try:
+            with open(vzlogger_file, 'r') as file:
+                data = json.load(file)
+
+        except (FileNotFoundError, json.decoder.JSONDecodeError) as e:
+            print('Error retrieving data:', e)
+            exit()
+    else:
+        try:
+            response = requests.get(f'http://{_vars["hostname"]}:{_vars["port"]}/', timeout=_vars['timeout'])
+            response.raise_for_status()
+        except (requests.exceptions.RequestException, requests.exceptions.HTTPError) as e:
+            print('Error retrieving data:', e)
+            exit()
+        else:
+            data = response.json()
+
+    print('<<<vzlogger:sep(0)>>>')
+    print(json.dumps(data))
+    return 0
+
+
+def main() -> int:
+    return special_agent_main(parse_arguments, agent_vzlogger_main)
diff --git a/packages/vzlogger b/packages/vzlogger
new file mode 100644
index 0000000000000000000000000000000000000000..968c233c86c13e25166bc1331d1e8f4fef5054c5
--- /dev/null
+++ b/packages/vzlogger
@@ -0,0 +1,17 @@
+{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)',
+ 'description': 'Special agent for vzlogger (prototype)\n'
+                '\n'
+                ' https://wiki.volkszaehler.org/software/controller/vzlogger\n',
+ 'download_url': 'https://thl-cmk.hopto.org',
+ 'files': {'agent_based': ['vzlogger.py'],
+           'agents': ['special/agent_vzlogger'],
+           'checks': ['agent_vzlogger'],
+           'gui': ['wato/check_parameters/agent_vzlogger.py',
+                   'wato/check_parameters/vzlogger.py'],
+           'lib': ['python3/cmk/special_agents/agent_vzlogger.py']},
+ 'name': 'vzlogger',
+ 'title': 'vzlogger',
+ 'version': '0.0.1-230806',
+ 'version.min_required': '2.2.0b1',
+ 'version.packaged': '2.2.0p7',
+ 'version.usable_until': None}
diff --git a/vzlogger-0.0.1-230806.mkp b/vzlogger-0.0.1-230806.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..b06dfe620601b8008feb3874175f8322301b7e7b
Binary files /dev/null and b/vzlogger-0.0.1-230806.mkp differ