From 1b26a24ac839c80ee925766267d9c938b9b14bc1 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Sun, 25 Feb 2024 08:21:11 +0100
Subject: [PATCH] update project

---
 README.md                                     |   2 +-
 mkp/fritzbox_smarthome-0.9.0-20240225.mkp     | Bin 0 -> 23742 bytes
 source/agent_based/fritzbox_smarthome.py      |   8 +-
 .../agent_based/fritzbox_smarthome_sensor.py  |  94 +++++++++++++++++
 source/agent_based/inv_fritzbox_smarthome.py  |   6 +-
 .../agent_based/utils/fritzbox_smarthome.py   |  68 +++++++++++-
 source/gui/metrics/fritzbox_smarthome.py      |   2 +-
 .../check_parameters/fritzbox_smarthome.py    |  57 ++++++++++
 .../agent_fritzbox_smarthome.py               |  97 +-----------------
 source/packages/fritzbox_smarthome            |  11 +-
 10 files changed, 242 insertions(+), 103 deletions(-)
 create mode 100644 mkp/fritzbox_smarthome-0.9.0-20240225.mkp
 create mode 100644 source/agent_based/fritzbox_smarthome_sensor.py

diff --git a/README.md b/README.md
index 409b1f2..16a0e4f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/mkp/fritzbox_smarthome-0.8.17-20240125.mkp "fritzbox_smarthome-0.8.17-20240125.mkp"
+[PACKAGE]: ../../raw/master/mkp/fritzbox_smarthome-0.9.0-20240225.mkp "fritzbox_smarthome-0.9.0-20240225.mkp"
 # AVM Fritz!Box Smarthome
 
 This repository contains a additional check_MK Fritz!Box Agent which can gather informations over the AVM AHA HTTP Interface about SmartHome Devices connected to an Fritz!Box. 
diff --git a/mkp/fritzbox_smarthome-0.9.0-20240225.mkp b/mkp/fritzbox_smarthome-0.9.0-20240225.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..e89841908d89fae94e731e888dc89054cb2fc6b3
GIT binary patch
literal 23742
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
Rq&d$4^)(1;Bp@o%{{X1748;Hd

literal 0
HcmV?d00001

diff --git a/source/agent_based/fritzbox_smarthome.py b/source/agent_based/fritzbox_smarthome.py
index 95a42b5..c0b723b 100644
--- a/source/agent_based/fritzbox_smarthome.py
+++ b/source/agent_based/fritzbox_smarthome.py
@@ -10,7 +10,13 @@
 #
 # Based on the work of Maximilian Clemens, see https://github.com/MaximilianClemens/checkmk_fritzbox
 #
-#
+# http://ares.home.intern:49000/igddesc.xml
+# http://ares.home.intern:49000/igdconnSCPD.xml
+# http://ares.home.intern:49000/igdicfgSCPD.xml
+# http://ares.home.intern:49000/igddslSCPD.xml
+# http://ares.home.intern:49000/igdupnp
+# http://ares.home.intern:49000/iupnp
+
 
 import json
 from typing import Dict
diff --git a/source/agent_based/fritzbox_smarthome_sensor.py b/source/agent_based/fritzbox_smarthome_sensor.py
new file mode 100644
index 0000000..797059c
--- /dev/null
+++ b/source/agent_based/fritzbox_smarthome_sensor.py
@@ -0,0 +1,94 @@
+#!/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  : 2024-02-23
+# File  : fritzbox_smarthome_sensor.py (check plugin)
+#
+#
+
+from time import localtime, strftime
+from typing import Dict
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    Service,
+    register,
+    Result,
+    State,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import CheckResult, DiscoveryResult
+from cmk.base.plugins.agent_based.utils.fritzbox_smarthome import AvmSmartHomeDevice, AVM_TIME_FORMAT
+
+
+def discovery_fritzbox_smarthome_sensor_single(
+        section: AvmSmartHomeDevice | Dict[str, AvmSmartHomeDevice]
+) -> DiscoveryResult:
+    if isinstance(section, AvmSmartHomeDevice):
+        if section.alert is not None:
+            yield Service()
+
+
+def discovery_fritzbox_smarthome_sensor_multiple(
+        section: AvmSmartHomeDevice | Dict[str, AvmSmartHomeDevice]
+) -> DiscoveryResult:
+    if not isinstance(section, AvmSmartHomeDevice):
+        for device_id, device in section.items():
+            if device.alert is not None:
+                yield Service(item=str(device_id))
+
+
+def check_fritzbox_smarthome_sensor_single(
+        params, section: AvmSmartHomeDevice | Dict[str, AvmSmartHomeDevice]
+) -> CheckResult:
+    if not isinstance(section, AvmSmartHomeDevice) or section.alert is None:
+        return
+
+    def _get_status(status: int):
+        _state = {
+            0: ('closed', params.get('state', {}).get('closed', 0)),
+            1: ('open', params.get('state', {}).get('open', 0)),
+        }
+        return _state.get(status, (f'unknown ({status})', 3))
+
+    state_readable, state = _get_status(section.alert.state)
+    yield Result(state=State(state), summary=f'State: {state_readable}')
+    if section.alert.last_changed_time_stamp is not None:
+        yield Result(
+            state=State.OK,
+            summary=f'Last changed: {strftime(AVM_TIME_FORMAT, localtime(section.alert.last_changed_time_stamp))}'
+        )
+
+
+def check_fritzbox_smarthome_sensor_multiple(
+        item, params, section: AvmSmartHomeDevice | Dict[str, AvmSmartHomeDevice]
+) -> CheckResult:
+    if isinstance(section, Dict):
+        try:
+            yield from check_fritzbox_smarthome_sensor_single(params, section[item])
+        except KeyError:
+            return
+
+
+register.check_plugin(
+    name='fritzbox_smarthome_sensor_single',
+    service_name='Sensor',
+    sections=['fritzbox_smarthome'],
+    discovery_function=discovery_fritzbox_smarthome_sensor_single,
+    check_function=check_fritzbox_smarthome_sensor_single,
+    check_ruleset_name='fritzbox_smarthome_sensor_single',
+    check_default_parameters={}
+)
+
+
+register.check_plugin(
+    name='fritzbox_smarthome_sensor_multiple',
+    service_name='Smarthome Sensor %s',
+    sections=['fritzbox_smarthome'],
+    discovery_function=discovery_fritzbox_smarthome_sensor_multiple,
+    check_function=check_fritzbox_smarthome_sensor_multiple,
+    check_ruleset_name='fritzbox_smarthome_sensor_multiple',
+    check_default_parameters={}
+)
diff --git a/source/agent_based/inv_fritzbox_smarthome.py b/source/agent_based/inv_fritzbox_smarthome.py
index 0f77bf5..5d2102c 100644
--- a/source/agent_based/inv_fritzbox_smarthome.py
+++ b/source/agent_based/inv_fritzbox_smarthome.py
@@ -12,7 +12,7 @@
 from typing import Dict
 from cmk.base.plugins.agent_based.agent_based_api.v1 import register, TableRow
 from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import InventoryResult
-from cmk.base.plugins.agent_based.utils.fritzbox_smarthome import AvmSmartHomeDevice
+from cmk.base.plugins.agent_based.utils.fritzbox_smarthome import AvmSmartHomeDevice, HAN_FUN_UNIT_TYPE
 
 
 def _add_avm_smarthome_device(device: AvmSmartHomeDevice):
@@ -26,7 +26,9 @@ def _add_avm_smarthome_device(device: AvmSmartHomeDevice):
             'fw_version': device.fw_version,
             'manufacturer': device.manufacturer,
             'product_name': device.product_name,
-            'functions': ', '.join(device.functions)
+            'functions': ', '.join(device.functions),
+            'unit_id': device.unit.device_id if device.unit else None,
+            'unit_type': HAN_FUN_UNIT_TYPE.get(device.unit.unit_type) if device.unit else None
         }
     )
 
diff --git a/source/agent_based/utils/fritzbox_smarthome.py b/source/agent_based/utils/fritzbox_smarthome.py
index 9669cea..c886fa1 100644
--- a/source/agent_based/utils/fritzbox_smarthome.py
+++ b/source/agent_based/utils/fritzbox_smarthome.py
@@ -13,7 +13,7 @@
 #
 
 from dataclasses import dataclass
-from typing import Any, List, Dict
+from typing import Any, Dict, Final, List
 from os import environ
 from pathlib import Path
 from json import loads, dumps
@@ -82,6 +82,19 @@ class AvmSwitch:
     state: int | None
 
 
+@dataclass(frozen=True)
+class AvmUnit:
+    device_id: str
+    unit_type: int
+    interfaces: int
+
+
+@dataclass(frozen=True)
+class AvmAlert:
+    state: int
+    last_changed_time_stamp: int
+
+
 @dataclass(frozen=True)
 class AvmSmartHomeDevice:
     fbm: int | None
@@ -105,10 +118,13 @@ class AvmSmartHomeDevice:
     tx_busy: int | None = None
     buttons: list[AvmButton] | None = None
     humidity: AvmHumidity | None = None
+    unit: AvmUnit | None = None
+    alert: AvmAlert | None = None
 
 
 _AVM_ADAPTIVE_HEATING_ACTIVE = 'adaptiveHeatingActive'
 _AVM_ADAPTIVE_HEATING_RUNNING = 'adaptiveHeatingRunning'
+_AVM_ALERT = 'alert'
 _AVM_BATTERY = 'battery'
 _AVM_BATTERY_LOW = 'batterylow'
 _AVM_BOOST_ACTIVE = 'boostactive'
@@ -118,12 +134,16 @@ _AVM_DEVICE_LOCK = 'devicelock'
 _AVM_END_PERIOD = 'endperiod'
 _AVM_ENERGY = 'energy'
 _AVM_ERROR_CODE = 'errorcode'
+_AVM_ETSI_DEVICE_ID = 'etsideviceid'
+_AVM_ETSI_UNIT_INFO = "etsiunitinfo"
 _AVM_FUNCTION_BIT_MASK = 'functionbitmask'
 _AVM_FW_REVISION = 'fwversion'
 _AVM_HOLIDAY_ACTIVE = 'holidayactive'
 _AVM_HUMIDITY = 'humidity'
 _AVM_ID = 'id'
 _AVM_IDENTIFIER = 'identifier'
+_AVM_INTERFACES = 'interfaces'
+_AVM_LAST_ALERT_CHG_TIME_STAMP = 'lastalertchgtimestamp'
 _AVM_LAST_PRESSED_TIME_STAMP = 'lastpressedtimestamp'
 _AVM_LOCK = 'lock'
 _AVM_MANUFACTURER = 'manufacturer'
@@ -148,6 +168,7 @@ _AVM_TEMP_ECONOMIC = 'absenk'
 _AVM_TEMP_TARGET = 'tsoll'
 _AVM_THERMOSTAT = 'hkr'
 _AVM_TX_BUSY = 'txbusy'
+_AVM_UNIT_TYPE = 'unittype'
 _AVM_VOLTAGE = 'voltage'
 _AVM_WINDOW_OPEN_ACTIV = 'windowopenactiv'
 _AVM_WINDOW_OPEN_ACTIVE_END_TIME = 'windowopenactiveendtime'
@@ -156,6 +177,42 @@ _OMD_ROOT = environ["OMD_ROOT"]
 
 AVM_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
 
+HAN_FUN_UNIT_TYPE: Final = {
+    273: 'Simple Button',
+    256: 'Simple on/off switchable',
+    257: 'Simple on//ff switch',
+    262: 'AC outlet',
+    263: 'AC outlet, simple power metering',
+    264: 'Simple light',
+    265: 'Dimmable light ',
+    266: 'Dimmer switch ',
+    277: 'Colour blub',
+    278: 'Dimmable color blub',
+    281: 'Blind',
+    282: 'Lamellar',
+    512: 'Simple detector',
+    513: 'Door open/close detector',
+    514: 'Window open/close detector',
+    515: 'Motion detector',
+    518: 'Flood detector',
+    519: 'Glas break detector',
+    520: 'Vibration detector',
+    640: 'Siren',
+
+}
+
+HAN_FUN_INTERFACE: Final = {
+    277: 'Keep alive',
+    256: 'Alert',
+    512: 'On/off',
+    513: 'Level control',
+    514: 'color control',
+    516: 'Open/cloe',
+    517: 'Open/close config',
+    772: 'Simple button',
+    1024: 'SUOTA Update',
+}
+
 
 class FritzBoxValueStore:
     """
@@ -336,6 +393,15 @@ def parse_avm_smarthome_device(raw_device: Dict[str, Any]) -> AvmSmartHomeDevice
             rel_humidity=_get_int(raw_device[_AVM_HUMIDITY].get(_AVM_REL_HUMIDITY))
         ) if raw_device.get(_AVM_HUMIDITY) else None,
         buttons=_get_buttons(raw_device),
+        unit=AvmUnit(
+            device_id=raw_device[_AVM_ETSI_UNIT_INFO][_AVM_ETSI_DEVICE_ID],
+            unit_type=_get_int(raw_device[_AVM_ETSI_UNIT_INFO][_AVM_UNIT_TYPE]),
+            interfaces=_get_int(raw_device[_AVM_ETSI_UNIT_INFO][_AVM_INTERFACES]),
+        ) if raw_device.get(_AVM_ETSI_UNIT_INFO) else None,
+        alert=AvmAlert(
+            state=_get_int(raw_device[_AVM_ALERT].get(_AVM_STATE)),
+            last_changed_time_stamp=_get_int(raw_device[_AVM_ALERT].get(_AVM_LAST_ALERT_CHG_TIME_STAMP))
+        ) if raw_device.get(_AVM_ALERT) else None
     )
 
 
diff --git a/source/gui/metrics/fritzbox_smarthome.py b/source/gui/metrics/fritzbox_smarthome.py
index dd1872e..9f9a085 100644
--- a/source/gui/metrics/fritzbox_smarthome.py
+++ b/source/gui/metrics/fritzbox_smarthome.py
@@ -199,4 +199,4 @@ perfometer_info.append({
     "type": "linear",
     'segments': ['battery'],
     'total': 100,
-})
\ No newline at end of file
+})
diff --git a/source/gui/wato/check_parameters/fritzbox_smarthome.py b/source/gui/wato/check_parameters/fritzbox_smarthome.py
index eed2e85..15031fe 100644
--- a/source/gui/wato/check_parameters/fritzbox_smarthome.py
+++ b/source/gui/wato/check_parameters/fritzbox_smarthome.py
@@ -12,6 +12,7 @@
 
 from cmk.gui.i18n import _
 from cmk.gui.valuespec import (
+    Alternative,
     Dictionary,
     Integer,
     MonitoringState,
@@ -160,3 +161,59 @@ rulespec_registry.register(
         item_spec=lambda: TextInput(title=_('Device-ID')),
     )
 )
+
+
+def _parameter_valuespec_fritzbox_smarthome_sensor():
+    return Dictionary(
+        title=_('Parameter'),
+        elements=[
+            ('state',
+             Alternative(
+                 title=_('Sensor state'),
+                 elements=[
+                     Dictionary(
+                         title=_('Sensor closed'),
+                         optional_keys=False,
+                         elements=[
+                             ('closed',
+                              MonitoringState(
+                                  title=_('Monitoring state (closed)'),
+                                  default_value=0,
+                              )),
+                         ]),
+                     Dictionary(
+                         title=_('Sensor open'),
+                         optional_keys=False,
+                         elements=[
+                             ('open',
+                              MonitoringState(
+                                  title=_('Monitoring state (open)'),
+                                  default_value=0,
+                              ))
+                         ]),
+                 ]
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithoutItem(
+        check_group_name="fritzbox_smarthome_sensor_single",
+        group=RulespecGroupCheckParametersApplications,
+        match_type="dict",
+        parameter_valuespec=_parameter_valuespec_fritzbox_smarthome_sensor,
+        title=lambda: _('Fritz!Box Smarthome Sensor')
+    )
+)
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name="fritzbox_smarthome_sensor_multiple",
+        group=RulespecGroupCheckParametersApplications,
+        match_type="dict",
+        parameter_valuespec=_parameter_valuespec_fritzbox_smarthome_sensor,
+        title=lambda: _('Fritz!Box Smarthome Sensor (with Device-ID)'),
+        item_spec=lambda: TextInput(title=_('Device-ID')),
+    )
+)
diff --git a/source/lib/python3/cmk/special_agents/agent_fritzbox_smarthome.py b/source/lib/python3/cmk/special_agents/agent_fritzbox_smarthome.py
index f335250..5af2a5f 100644
--- a/source/lib/python3/cmk/special_agents/agent_fritzbox_smarthome.py
+++ b/source/lib/python3/cmk/special_agents/agent_fritzbox_smarthome.py
@@ -6,6 +6,8 @@
 #             changed to return the complete XML response back as json
 # 2023-12-28: added data/option for testing
 # 2024-01-11: reworked to support PBKDF2
+# 2024-02-21: fixed XML2json -< overwrite data with info from child
+#             removed test data
 
 
 from argparse import ArgumentParser, RawTextHelpFormatter
@@ -107,8 +109,9 @@ def parse_xml_to_json(xml):
                     index += 1
 
     for child in list(xml):
-        for key in child.keys():
-            response[key] = child.get(key)
+        # for key in child.keys():
+        #     print(f'key: {key}')
+        #     response[key] = child.get(key)
 
         if len(list(child)) > 0:
             response[child.tag] = parse_xml_to_json(child)
@@ -244,96 +247,6 @@ def check_fritzbox_smarthome(args):
     xml_device_list = str_to_xml(response_read)
     devices = []
 
-    if args.testing:
-        __switch_01 = {
-            'identifier': '08761 0116372',
-            'id': '99',
-            'functionbitmask': '35712',
-            'fwversion': '04.26',
-            'manufacturer': 'AVM',
-            'productname': 'FRITZ!DECT 200',
-            'present': '1',
-            'txbusy': '0',
-            'name': 'TV-living_room',
-            'switch': {
-                'state': '1',
-                'mode': 'manuell',
-                'lock': '0',
-                'devicelock': '0'
-            },
-            'simpleonoff': {
-                'state': '1'
-            },
-            'powermeter': {
-                'voltage': '235814',
-                'power': '4220',
-                'energy': '145427'
-            },
-            'temperature': {
-                'celsius': '190',
-                'offset': '0'
-            }
-        }
-        __repeater_01 = {
-            'identifier': '11657 0057950',
-            'id': '98',
-            'functionbitmask': '1024',
-            'fwversion': '04.16',
-            'manufacturer': 'AVM',
-            'productname': 'FRITZ!DECT Repeater 100',
-            'present': '0',
-            'txbusy': '0',
-            'name': 'FRITZ!DECT Rep 100 #1'
-        }
-        __repeater_02 = {
-            'identifier': '11657 0170905',
-            'id': '97',
-            'functionbitmask': '1280',
-            'fwversion': '04.25',
-            'manufacturer': 'AVM',
-            'productname': 'FRITZ!DECT Repeater 100',
-            'present': '1',
-            'txbusy': '0',
-            'name': 'FRITZ!DECT Repeater 100 #2',
-            'temperature': {
-                'celsius': '245',
-                'offset': '0'
-            }
-        }
-        __thermostat_01 = {
-            'identifier': '13979 0878454',
-            'id': '96',
-            'functionbitmask': '320',
-            'fwversion': '05.16',
-            'manufacturer': 'AVM',
-            'productname': 'Comet DECT',
-            'present': '1',
-            'name': 'Temp02',
-            'temperature': {
-                'celsius': '210',
-                'offset': '-10'
-            },
-            'hkr': {
-                'tist': '42',
-                'tsoll': '32',
-                'absenk': '32',
-                'komfort': '38',
-                'lock': '1',
-                'devicelock': '1',
-                'errorcode': '0',
-                'batterylow': '0',
-                'nextchange': {
-                    'endperiod': '1704888000',
-                    'tchange': '32'
-                }
-            }
-        }
-
-        # devices.append(__switch_01)
-        # devices.append(__repeater_01)
-        # devices.append(__repeater_02)
-        # devices.append(__thermostat_01)
-
     for xml_device in xml_device_list.findall('device'):
         devices.append(parse_xml_to_json(xml_device))
 
diff --git a/source/packages/fritzbox_smarthome b/source/packages/fritzbox_smarthome
index 5c03fcf..953a8c7 100644
--- a/source/packages/fritzbox_smarthome
+++ b/source/packages/fritzbox_smarthome
@@ -7,15 +7,15 @@
                 '\n'
                 'I have rewritten this package for use with CMK 2.2.0x. As I '
                 'do not have access to all smart home \n'
-                'devices, I have only implemented the checks for the following '
-                'devices:\n'
+                'devices. This package supports the following devices:\n'
                 '\n'
                 ' - FRITZ!DECT Repeater 100\n'
                 ' - FRITZ!DECT 200/210\n'
                 ' - FRITZ!DECT 301/302\n'
+                ' - FRITZ!DECT 350\n'
                 ' - FRITZ!DECT 440\n'
                 '\n'
-                'So if you want the package to be extended to support your '
+                'If you want the package to be extended to support your '
                 'sensors as well, see\n'
                 'https://thl-cmk.hopto.org/gitlab/checkmk/various/fritzbox_smarthome/-/blob/master/CONTRIBUTING.md\n'
                 '\n',
@@ -32,7 +32,8 @@
                            'fritzbox_smarthome_power_socket.py',
                            'fritzbox_smarthome_switch.py',
                            'fritzbox_smarthome_button.py',
-                           'fritzbox_smarthome_humidity.py'],
+                           'fritzbox_smarthome_humidity.py',
+                           'fritzbox_smarthome_sensor.py'],
            'agents': ['special/agent_fritzbox_smarthome'],
            'checkman': ['fritzbox_smarthome'],
            'checks': ['agent_fritzbox_smarthome'],
@@ -54,7 +55,7 @@
                    'plugins/views/fritzbox_smarthome.py']},
  'name': 'fritzbox_smarthome',
  'title': 'Fritz!Box SmartHome',
- 'version': '0.8.17-20240125',
+ 'version': '0.9.0-20240225',
  'version.min_required': '2.2.0b1',
  'version.packaged': '2.2.0p17',
  'version.usable_until': '2.3.0b1'}
-- 
GitLab