diff --git a/mkp/fritzbox_smarthome-0.8.8-20240109.mkp b/mkp/fritzbox_smarthome-0.8.8-20240109.mkp index 55f50e4a6086bd6befc34d4543250fdd1f40da67..581710903fe925e3e585000d1f839647ce19e431 100644 Binary files a/mkp/fritzbox_smarthome-0.8.8-20240109.mkp and b/mkp/fritzbox_smarthome-0.8.8-20240109.mkp differ diff --git a/source/agent_based/fritzbox_smarthome_power_meter.py b/source/agent_based/fritzbox_smarthome_power_meter.py index b7107eaf6e1352d2b999d5ceb8c768ecc6206943..d966c890ccdefd9fba24b9349b8d78c4bff6e469 100644 --- a/source/agent_based/fritzbox_smarthome_power_meter.py +++ b/source/agent_based/fritzbox_smarthome_power_meter.py @@ -9,14 +9,10 @@ # File : fritzbox_smarthome_power_meter.py (check plugin) # # -# import time + from time import localtime, time as time_now from typing import Dict -from os import environ -from pathlib import Path -from json import loads, dumps -from cmk.checkers import plugin_contexts from cmk.base.plugins.agent_based.agent_based_api.v1 import ( Metric, Result, @@ -27,58 +23,7 @@ from cmk.base.plugins.agent_based.agent_based_api.v1 import ( ) from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import CheckResult, DiscoveryResult from cmk.utils.render import physical_precision -from cmk.base.plugins.agent_based.utils.fritzbox_smarthome import AvmSmartHomeDevice - -OMD_ROOT = environ["OMD_ROOT"] - - -class FritzBoxValueStore: - """ - Persistent kind of value_store. Located under ~/var/fritzbox_smarthome/{hostname}_{service_description} - """ - def __init__(self): - self._host_name = plugin_contexts.host_name() - self._service_description = plugin_contexts.service_description().replace(' ', '_') - self._file = Path(f'{OMD_ROOT}/var/firtzbox_smarthome/{self._host_name}_{self._service_description}') - self._counters = {} - if self._file.exists(): - self._counters = loads(self._file.read_text()) - else: - self._counters = {} - - def get(self, key: str, default_value: int | str | float | bool | None = None): - """ - Get a value from the value store - Args: - key: the key in the value store - default_value: the default value to return if key not found - - Returns: - The value for key from the value store. If key not exists the default_value or None - """ - return self._counters.get(key, default_value) - - def set(self, key: str, value: str | int | float | None) -> None: - """ - Set a value in the value stare. Use "None" as value to remove a key. - Args: - key: the key in the value store - value: the value to set - """ - if value is None: - try: - self._counters.pop(key) - except KeyError: - pass - else: - self._counters[key] = value - - def save(self) -> None: - """ - Save the value_store as json to file - """ - self._file.parent.mkdir(exist_ok=True, parents=True) - self._file.write_text(dumps(self._counters)) +from cmk.base.plugins.agent_based.utils.fritzbox_smarthome import AvmSmartHomeDevice, FritzBoxValueStore def discovery_fritzbox_smarthome_voltage_single( diff --git a/source/agent_based/fritzbox_smarthome_power_socket.py b/source/agent_based/fritzbox_smarthome_power_socket.py index 3a96807994b16ed557fd397e1441437ba78f8307..63439f88f0d83e38c942c8522c86d463095f2914 100644 --- a/source/agent_based/fritzbox_smarthome_power_socket.py +++ b/source/agent_based/fritzbox_smarthome_power_socket.py @@ -46,14 +46,24 @@ def check_fritzbox_smarthome_power_socket_single( return def _get_status(status: int): - _switch_state = { - 0: 'off', - 1: 'on', + _state = { + 0: ('off', params.get('state', {}).get('off', 0)), + 1: ('on', params.get('state', {}).get('on', 0)), } - return _switch_state.get(status, f'unknown ({status})') + return _state.get(status, (f'unknown ({status})', 3)) - yield Result(state=State.OK, summary=f'State: {_get_status(section.switch.state)}') - yield Result(state=State.OK, summary=f'Mode: {section.switch.mode}') + state_readable, state = _get_status(section.switch.state) + yield Result(state=State(state), summary=f'State: {state_readable}') + + def _get_mode(mode: str): + _mode = { + 'manuell': ('manuell', params.get('mode', {}).get('manuell', 0)), + 'automatic': ('automatic', params.get('mode', {}).get('automatic', 0)), + } + return _mode.get(mode, (f'unknown ({mode})', 3)) + + mode_readable, mode = _get_mode(section.switch.mode) + yield Result(state=State(mode), summary=f'Mode: {mode_readable}') def check_fritzbox_smarthome_power_socket_multiple( @@ -72,7 +82,7 @@ register.check_plugin( sections=['fritzbox_smarthome'], discovery_function=discovery_fritzbox_smarthome_power_socket_single, check_function=check_fritzbox_smarthome_power_socket_single, - # check_ruleset_name='fritzbox_smarthome_power_socket', + check_ruleset_name='fritzbox_smarthome_power_socket_single', check_default_parameters={} ) @@ -83,6 +93,6 @@ register.check_plugin( sections=['fritzbox_smarthome'], discovery_function=discovery_fritzbox_smarthome_power_socket_multiple, check_function=check_fritzbox_smarthome_power_socket_multiple, - # check_ruleset_name='fritzbox_smarthome_power_socket', + check_ruleset_name='fritzbox_smarthome_power_socket_multiple', check_default_parameters={} ) diff --git a/source/agent_based/fritzbox_smarthome_thermostat.py b/source/agent_based/fritzbox_smarthome_thermostat.py index fcd62447e322d8ce81531bb0f9a3e78c04d1c123..9828c3c27adc800bb5c66a4af1dbdceeb097165a 100644 --- a/source/agent_based/fritzbox_smarthome_thermostat.py +++ b/source/agent_based/fritzbox_smarthome_thermostat.py @@ -65,7 +65,7 @@ def check_fritzbox_smarthome_thermostat_single( if thermostat.temp_target == 126.5: # == radiator off yield Result(state=State.OK, summary=f'Temperature current: {thermostat.temp_current}°C') - yield Result(state=State.OK, summary=f'Temperature target: radiator off') + yield Result(state=State(params.get('state_off', 0)), summary=f'Temperature target: radiator off') else: deviation = thermostat.temp_current - thermostat.temp_target if deviation == 0: diff --git a/source/agent_based/utils/fritzbox_smarthome.py b/source/agent_based/utils/fritzbox_smarthome.py index 25c4b8b25b5d0a0ec58a0aee4eac5734a9c524cf..b36185232ce42cf1a6a72f5ebdd1cce2d8d9bc5d 100644 --- a/source/agent_based/utils/fritzbox_smarthome.py +++ b/source/agent_based/utils/fritzbox_smarthome.py @@ -14,6 +14,11 @@ from dataclasses import dataclass from typing import Any, List, Dict +from os import environ +from pathlib import Path +from json import loads, dumps + +from cmk.checkers import plugin_contexts @dataclass(frozen=True) @@ -93,6 +98,57 @@ _AVM_TEMPERATURE = 'temperature' _AVM_SIMPLE_ON_OFF = 'simpleonoff' _AVM_NEXT_CHANGE = 'nextchange' +_OMD_ROOT = environ["OMD_ROOT"] + + +class FritzBoxValueStore: + """ + Persistent kind of value_store. Located under ~/var/fritzbox_smarthome/{hostname}_{service_description} + """ + def __init__(self): + self._host_name = plugin_contexts.host_name() + self._service_description = plugin_contexts.service_description().replace(' ', '_') + self._file = Path(f'{_OMD_ROOT}/var/firtzbox_smarthome/{self._host_name}_{self._service_description}') + self._counters = {} + if self._file.exists(): + self._counters = loads(self._file.read_text()) + else: + self._counters = {} + + def get(self, key: str, default_value: int | str | float | bool | None = None): + """ + Get a value from the value store + Args: + key: the key in the value store + default_value: the default value to return if key not found + + Returns: + The value for key from the value store. If key not exists the default_value or None + """ + return self._counters.get(key, default_value) + + def set(self, key: str, value: str | int | float | None) -> None: + """ + Set a value in the value stare. Use "None" as value to remove a key. + Args: + key: the key in the value store + value: the value to set + """ + if value is None: + try: + self._counters.pop(key) + except KeyError: + pass + else: + self._counters[key] = value + + def save(self) -> None: + """ + Save the value_store as json to file + """ + self._file.parent.mkdir(exist_ok=True, parents=True) + self._file.write_text(dumps(self._counters)) + def _get_battery_low(device: Dict[str, Any]) -> int | None: try: diff --git a/source/gui/wato/check_parameters/fritzbox_smarthome.py b/source/gui/wato/check_parameters/fritzbox_smarthome.py index 3dc4c80be4f1391ad7900ccb6e9b1e7c55aa6445..cf75d6a8dcb4e4f13d8c47a58f034b9035c44f50 100644 --- a/source/gui/wato/check_parameters/fritzbox_smarthome.py +++ b/source/gui/wato/check_parameters/fritzbox_smarthome.py @@ -73,6 +73,11 @@ def _parameter_valuespec_fritzbox_smarthome_thermostat(): Integer(title=_('Warning'), default_value=3, unit=_('°C')), Integer(title=_('Critical'), default_value=5, unit=_('°C')), ])), + ('state_off', + MonitoringState( + title=_('Monitoring state if thermostat is off'), + default_value=0, + )), ('state_on_error', MonitoringState( title=_('Monitoring state on error'), diff --git a/source/gui/wato/check_parameters/fritzbox_smarthome_power_coscket.py b/source/gui/wato/check_parameters/fritzbox_smarthome_power_coscket.py new file mode 100644 index 0000000000000000000000000000000000000000..d22482e551eb7b615a4f0ffa7f543e67bd4a8a9e --- /dev/null +++ b/source/gui/wato/check_parameters/fritzbox_smarthome_power_coscket.py @@ -0,0 +1,107 @@ +#!/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-01-09 +# File : fritzbox_smarthome_lock.py (WATO check plugin) +# + + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + MonitoringState, + TextInput, + Alternative, +) +from cmk.gui.plugins.wato.utils import ( + CheckParameterRulespecWithItem, + CheckParameterRulespecWithoutItem, + RulespecGroupCheckParametersApplications, + rulespec_registry, +) + + +def _parameter_valuespec_fritzbox_smarthome_power_socket(): + return Dictionary( + title=_('Parameter'), + elements=[ + ('state', + Alternative( + title=_('Power Socket state'), + elements=[ + Dictionary( + title=_('Switched On'), + optional_keys=False, + elements=[ + ('on', + MonitoringState( + title=_('Monitoring state'), + default_value=0, + )), + ]), + Dictionary( + title=_('Switched off'), + optional_keys=False, + elements=[ + ('off', + MonitoringState( + title=_('Monitoring state'), + default_value=0, + )) + ]), + ] + )), + ('mode', + Alternative( + title=_('Power Socket switching mode'), + elements=[ + Dictionary( + title=_('Manuell'), + optional_keys=False, + elements=[ + ('manuell', + MonitoringState( + title=_('Monitoring state'), + default_value=0, + )), + ]), + Dictionary( + title=_('Automatic'), + optional_keys=False, + elements=[ + ('automatic', + MonitoringState( + title=_('Monitoring state'), + default_value=0, + )) + ]), + ] + )), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithoutItem( + check_group_name="fritzbox_smarthome_power_socket_single", + group=RulespecGroupCheckParametersApplications, + match_type="dict", + parameter_valuespec=_parameter_valuespec_fritzbox_smarthome_power_socket, + title=lambda: _('Fritz!Box Smarthome Power socket') + ) +) + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name="fritzbox_smarthome_power_socket_multiple", + group=RulespecGroupCheckParametersApplications, + match_type="dict", + parameter_valuespec=_parameter_valuespec_fritzbox_smarthome_power_socket, + title=lambda: _('Fritz!Box Smarthome Power Socket (with Device-ID)'), + item_spec=lambda: TextInput(title=_('Device-ID')), + ) +) diff --git a/source/packages/fritzbox_smarthome b/source/packages/fritzbox_smarthome index bd5b1eb53f5e16b95ca07d28d4a3108d1dce4f48..adf1f5250b2aebe75394e695dc2b0d06bc6eb7e8 100644 --- a/source/packages/fritzbox_smarthome +++ b/source/packages/fritzbox_smarthome @@ -44,7 +44,8 @@ 'metrics/fritzbox_smarthome.py', 'wato/check_parameters/temperature_single.py', 'wato/check_parameters/voltage_single.py', - 'wato/check_parameters/fritzbox_smarthome_lock.py'], + 'wato/check_parameters/fritzbox_smarthome_lock.py', + 'wato/check_parameters/fritzbox_smarthome_power_coscket.py'], 'lib': ['python3/cmk/special_agents/agent_fritzbox_smarthome.py'], 'web': ['plugins/wato/agent_fritzbox_smarthome.py', 'plugins/views/fritzbox_smarthome.py']},