Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit 1b26a24a authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

update project

parent b774ca71
No related branches found
No related tags found
No related merge requests found
[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.
......
File added
......@@ -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
......
#!/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={}
)
......@@ -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
}
)
......
......@@ -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
)
......
......@@ -199,4 +199,4 @@ perfometer_info.append({
"type": "linear",
'segments': ['battery'],
'total': 100,
})
\ No newline at end of file
})
......@@ -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')),
)
)
......@@ -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))
......
......@@ -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'}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment