├── checkman
└── fritzbox_smarthome
├── checks
├── agent_fritzbox_smarthome
└── fritzbox_smarthome
├── web
└── plugins
│ ├── wato
│ ├── parameters_agent_fritzbox_smarthome.py
│ └── parameters_check_fritzbox_smarthome.py
│ └── metrics
│ └── metrics_check_fritzbox_smarthome.py
├── README.md
├── agents
└── special
│ └── agent_fritzbox_smarthome
└── LICENSE
/checkman/fritzbox_smarthome:
--------------------------------------------------------------------------------
1 | title: Fritz!Box Smarthome
2 | agents: fritzbox_smarthome
3 | catalog: hw/network/avm
4 | license: GPL
5 | distribution: check_mk
6 | description:
7 | Comes with a new agent for Fritz!Box smarthome devices. Some values are configurable.
8 | Feel free to report bugs at https://github.com/MaximilianClemens/checkmk_fritzbox/issues/
9 |
10 | inventory:
11 | fritzbox smarthome devices
12 |
--------------------------------------------------------------------------------
/checks/agent_fritzbox_smarthome:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 | import shlex
4 |
5 | def agent_fritzbox_smarthome_arguments(params, hostname, ipaddress):
6 | args = shlex.quote(ipaddress)
7 | args += " " + shlex.quote(params["username"])
8 | args += " " + shlex.quote(params["password"])
9 |
10 | if "port" in params:
11 | args += " --port " + str(params["port"])
12 |
13 | if "protocol" in params:
14 | if str(params["protocol"]) == '1':
15 | args += " --protocol https"
16 | else:
17 | args += " --protocol http"
18 |
19 | if "ssl" in params:
20 | args += " --ignore_ssl"
21 |
22 | return args
23 |
24 | special_agent_info['fritzbox_smarthome'] = agent_fritzbox_smarthome_arguments
25 |
--------------------------------------------------------------------------------
/web/plugins/wato/parameters_agent_fritzbox_smarthome.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 |
4 | from cmk.gui.watolib.rulespecs import Rulespec
5 | from cmk.gui.plugins.wato.utils import rulespec_registry, HostRulespec
6 | from cmk.gui.plugins.wato.special_agents.common import RulespecGroupDatasourceProgramsHardware
7 |
8 | def _factory_default_special_agents_fritzbox_smarthome():
9 | # No default, do not use setting if no rule matches
10 | return Rulespec.FACTORY_DEFAULT_UNUSED
11 |
12 | def _valuespec_special_agents_fritzbox_smarthome():
13 | return Dictionary(
14 | title=_("Check state of Fritz!Box Smarthome Devices"),
15 | help=_("This rule selects the Fritz!Box agent, which uses HTTP to gather information "
16 | "about configuration and connection status information."),
17 | elements=[
18 | ('username',
19 | TextAscii(
20 | title = _('Username'),
21 | ),
22 | ),
23 | ('password',
24 | Password(
25 | title = _('Password'),
26 | ),
27 | ),
28 | ('port',
29 | Integer(
30 | title = _('Port'),
31 | default_value = 80,
32 | ),
33 | ),
34 | ('protocol',
35 | Alternative(
36 | title = _('Protocol'),
37 | style = 'dropdown',
38 | elements = [
39 | FixedValue(
40 | 0,
41 | totext = '',
42 | title = _('HTTP'),
43 | ),
44 | FixedValue(
45 | 1,
46 | totext = '',
47 | title = _('HTTPS'),
48 | )
49 | ]),
50 | ),
51 | ( 'ssl', FixedValue(
52 | 0,
53 | totext = 'Agent will ignore SSL errors',
54 | title = _('Ignore SSL errors'),
55 | )
56 | ),
57 | ],
58 | optional_keys=['port', 'protocol', 'ssl'],
59 | )
60 |
61 | rulespec_registry.register(
62 | HostRulespec(
63 | factory_default=_factory_default_special_agents_fritzbox_smarthome(),
64 | group=RulespecGroupDatasourceProgramsHardware,
65 | name="special_agents:fritzbox_smarthome",
66 | valuespec=_valuespec_special_agents_fritzbox_smarthome,
67 | ))
68 |
--------------------------------------------------------------------------------
/web/plugins/metrics/metrics_check_fritzbox_smarthome.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 |
4 | ### HKR
5 | metric_info["hkr_windowopenactiv"] = {
6 | "title" : _("Window Open"),
7 | "color": "#7192ad", #
8 | "unit" : "count",
9 | }
10 |
11 | metric_info["hkr_battery"] = {
12 | "title" : _("Batterystate"),
13 | "color": "#7192ad", #
14 | "unit" : "%",
15 | }
16 |
17 | metric_info["hkr_tsoll"] = {
18 | "title" : _("Temperature Should"),
19 | "color": "#40ff00",
20 | "unit" : "c",
21 | }
22 |
23 | metric_info["hkr_absenk"] = {
24 | "title" : _("Temperature Saving"),
25 | "color": "#0080ff",
26 | "unit" : "c",
27 | }
28 |
29 | metric_info["hkr_komfort"] = {
30 | "title" : _("Temperature Comfort"),
31 | "color": "#ffbf00",
32 | "unit" : "c",
33 | }
34 |
35 | metric_info["ref_temperature"] = {
36 | "title" : _("Temperature"),
37 | "color": "#009999",
38 | "unit" : "c",
39 | }
40 |
41 | graph_info["fritzbox_smarthome_temperature"] = {
42 | "title" : _("Temperature Thermostat"),
43 | "metrics" : [
44 | ( "ref_temperature", "area" ),
45 | ( "hkr_komfort", "line" ),
46 | ( "hkr_absenk", "line" ),
47 | ( "hkr_tsoll", "line" ),
48 | ],
49 | "optional_metrics" : [ "hkr_tsoll", ],
50 | }
51 |
52 | perfometer_info.append({
53 | "type" : "logarithmic",
54 | "metric" : "ref_temperature",
55 | "half_value" : 0.5,
56 | "exponent" : 7,
57 | })
58 |
59 | ### Powermeter
60 |
61 | unit_info["kwh"] = {
62 | "title" : _("Electrical Energy"),
63 | "symbol" : _("kWh"),
64 | "render" : lambda v: physical_precision(v, 3, _("kWh")),
65 | }
66 |
67 |
68 | metric_info["powermeter_power"] = {
69 | "title" : _("Power"),
70 | "color": "#7192ad", #
71 | "unit" : "w", #watt
72 | }
73 |
74 | metric_info["powermeter_energy"] = {
75 | "title" : _("Consumption"),
76 | #"help": _("Consumption since Commissioning")
77 | "color": "#7192ad", #
78 | "unit" : "kwh", #kWh
79 | }
80 |
81 | metric_info["powermeter_voltage"] = {
82 | "title" : _("Voltage"),
83 | "color": "#7192ad", #
84 | "unit" : "v", #volt
85 | }
86 |
87 | perfometer_info.append({
88 | "type" : "logarithmic",
89 | "metric" : "powermeter_power",
90 | "half_value" : 5,
91 | "exponent" : 3,
92 | })
93 |
94 |
95 | ### Switch
96 | metric_info["switch_state"] = {
97 | "title" : _("Switch State"),
98 | "color": "#7192ad",
99 | "unit" : "count",
100 | }
101 |
102 | ### Temperature
103 |
104 | metric_info["temperature_celsius"] = {
105 | "title" : _("Temperature Calculated"),
106 | "color": "#009999",
107 | "unit" : "c",
108 | }
109 |
110 | metric_info["temperature_offset"] = {
111 | "title" : _("Temperature Offset"),
112 | "color": "#cc9900",
113 | "unit" : "c",
114 | }
115 |
116 | metric_info["temperature_real"] = {
117 | "title" : _("Temperature Measured"),
118 | "color": "#990000",
119 | "unit" : "c",
120 | }
121 |
122 | graph_info["fritzbox_smarthome_temperature_real"] = {
123 | "title" : _("Temperature Sensor"),
124 | "metrics" : [
125 | #( "temperature_real", "line" ),
126 | ( "temperature_celsius", "area" ),
127 | ( "temperature_offset", "stack" )
128 | ],
129 | }
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Archive State
2 |
3 | The agent and checks have been recreated for Checkmk 2.4.0. You can find the updated version here: [checkmk\_fritzbox\_smarthome](https://github.com/MaximilianClemens/checkmk_fritzbox_smarthome).
4 | All further development will take place in that repository.
5 |
6 |
7 | # checkmk_fritzbox
8 | This repository contains a additional [check_MK](https://mathias-kettner.com/) Fritz!Box Agent which can gather informations over the AVM AHA HTTP Interface about SmartHome Devices connected to an Fritz!Box. In the first version this was a modification this was a modification of the normal checkmk fritzbox agent now it is seperated from it.
9 | It also provides a Check for parsing the output, and WATO-Pages for configuring thresholds.
10 |
11 | ## CLI Usage
12 | ```
13 | ./agents/special/agent_fritzbox_smarthome --help
14 | usage: agent_fritzbox_smarthome [-h] [--debug] [--username [USERNAME]]
15 | [--password [PASSWORD]] [--port [PORT]]
16 | [--protocol [{http,https}]]
17 | host
18 |
19 | Check_MK Fritz!Box Smarthome Agent
20 |
21 | positional arguments:
22 | host Host name or IP address of your Fritz!Box
23 |
24 | optional arguments:
25 | -h, --help show this help message and exit
26 | --debug Debug mode: let Python exceptions come through
27 | --username [USERNAME]
28 | --password [PASSWORD]
29 | --port [PORT]
30 | --protocol [{http,https}]
31 | ```
32 |
33 | ## Tested Devices
34 | * AVM FRITZ!DECT210 (FW 04.16)
35 | * Switching Socket
36 | * Function Values: powermeter, temperature, switch
37 | * AVM FRITZ!DECT200 (FW 04.16)
38 | * Switching Socket
39 | * Function Values: powermeter, temperature, switch
40 | * AVM FRITZ!DECT301 (FW: 04.88)
41 | * Thermostat
42 | * Function Values: temperature, hkr
43 | * AVM FRITZ!DECTRepeater100 (FW 04.16)
44 | * DECTRepeater
45 | * Function Values: temperature
46 | * AVM FRITZ!DECT400 (FW: 04.90)
47 | * Button
48 | * Function Values: button
49 | * Eurotronic CometDECT (FW 03.54)
50 | * Thermostat
51 | * Function Values: temperature, hkr
52 |
53 | ## Function Value implementation:
54 | * base (this means generic device infos)
55 | * Graphs: None
56 | * Status: When Device present OK, else WARN
57 | * powermeter
58 | * Graphs: Consumption (kWh), Voltage (V), Power (W)
59 | * Status: Always okay
60 | * temperature
61 | * Graphs: Temperature Sensor
62 | * Status: Always okay
63 | * switch
64 | * Graphs: Switch State
65 | * Status: Always okay
66 | * hkr
67 | * Graphs: Temperature Thermostat, Battery, Window Open
68 | * Status: Compare against default params
69 | * button
70 | * Nothing yet (no idea what to check here)
71 |
72 | ## How to setup
73 | * ensure you are working with checkmk 1.6
74 | * Install current package
75 | * wget the latest version from https://github.com/MaximilianClemens/checkmk_fritzbox/releases
76 | * then: mkp install /var/check_mk/packages/fritzbox_smarthome-xyz.mkp
77 | * Configure:
78 | * Create a new Host for your fritzbox
79 | * at DATA SOURCES > Check_MK Agent select "No Checkmk agent, all configured agents"
80 | * Save & Finish
81 | * Host & Service Parameters
82 | * search for fritz
83 | * Create an new rule in "Check state of Fritz!Box Smarthome Devices"
84 | * Enter Credentials, Port and Protocol
85 | * Explicit Host :
86 | * Save
87 | * (re)-inventory the (fritzbox) host, the smarthome devices should now be detected
88 |
89 | ## Credits
90 | * Gerold Gruber / [edv2g](https://edv2g.de/)
91 | * Maximilian Clemens / [gamma.red](https://gamma.red/)
92 |
93 | ## Informations
94 | [AVM - AHA-HTTP-Interface Dokumentation](https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AHA-HTTP-Interface.pdf)
95 |
--------------------------------------------------------------------------------
/agents/special/agent_fritzbox_smarthome:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 |
4 |
5 | import getopt, sys, socket, traceback, re, pprint, ssl
6 | from urllib.request import urlopen
7 | import argparse
8 | import xml.etree.ElementTree as ET
9 | import hashlib
10 |
11 | def parse_args():
12 | parser = argparse.ArgumentParser(description='Check_MK Fritz!Box Smarthome Agent')
13 | parser.add_argument('host', help='Host name or IP address of your Fritz!Box')
14 | parser.add_argument('username')
15 | parser.add_argument('password')
16 |
17 | parser.add_argument('--debug', action='store_true', default=False,
18 | help='Debug mode: let Python exceptions come through')
19 |
20 | parser.add_argument('--port', nargs='?', type=int, default=80)
21 | parser.add_argument('--ignore_ssl', action='store_true', default=False)
22 | parser.add_argument('--protocol', nargs='?', choices=['http', 'https'], default='http')
23 | args = parser.parse_args()
24 |
25 | return args
26 |
27 | def check_fritzbox_smarthome(args):
28 | base_address = '%s://%s:%d' % (args.protocol, args.host, args.port)
29 |
30 | ctx = ssl.create_default_context()
31 | if args.ignore_ssl:
32 | ctx.check_hostname = False
33 | ctx.verify_mode = ssl.CERT_NONE
34 |
35 | # CALL /login_sid.lua
36 | # and grab challenge
37 | response = urlopen(base_address + '/login_sid.lua', context=ctx)
38 | if args.password:
39 | xml_login = ET.fromstring(response.read())
40 | challenge = xml_login.find('Challenge').text
41 | blocktime = int(xml_login.find('BlockTime').text)
42 | if blocktime > 0:
43 | sys.stdout.write('<<>>')
44 | sys.stdout.write('Login blocked for %d secs' % blocktime)
45 | raise Exception('Login blocked for %d secs' % blocktime)
46 |
47 | # create challenge_response (hash with md5: '-')
48 | # TODO: check if challenge is PBKDF2 (startswith $2)
49 | digest = hashlib.md5()
50 | digest.update(challenge.encode('utf-16le'))
51 | digest.update('-'.encode('utf-16le'))
52 | digest.update(args.password.encode('utf-16le'))
53 |
54 | challenge_response = challenge + '-' + digest.hexdigest()
55 |
56 | # CALL /login_sid.lua?username=&response=
57 | # and grab sessionid
58 | if args.username:
59 | response = urlopen(base_address + '/login_sid.lua?username=%s&response=%s' % (args.username, challenge_response), context=ctx)
60 | else:
61 | response = urlopen(base_address + '/login_sid.lua?response=%s' % (challenge_response), context=ctx)
62 |
63 | xml_login_solve = ET.fromstring(response.read())
64 | sessionid = xml_login_solve.find('SID').text
65 |
66 | blocktime = int(xml_login_solve.find('BlockTime').text)
67 | if blocktime > 0:
68 | raise Exception('Login blocked for %d secs\n' % blocktime)
69 |
70 | if args.password and sessionid == '0000000000000000':
71 | raise Exception('Check credentials\n')
72 |
73 | # Write check header
74 | sys.stdout.write('<<>>\n')
75 |
76 | # CALL /webservices/homeautoswitch.lua?switchcmd=getdevicelistinfos&sid=
77 | # and convert response to check output
78 | response = urlopen(base_address + '/webservices/homeautoswitch.lua?switchcmd=getdevicelistinfos&sid=%s' % (sessionid), context=ctx)
79 | response_read = response.read()
80 | if args.debug:
81 | sys.stdout.write('Raw XML:\n')
82 | sys.stdout.write(response_read)
83 |
84 | xml_devicelist = ET.fromstring(response_read)
85 | for device in xml_devicelist.findall('device'):
86 | sys.stdout.write('id=%s\n' % device.get('id'))
87 | sys.stdout.write('base|functionbitmask=%s\n' % device.get('functionbitmask'))
88 | sys.stdout.write('base|fwversion=%s\n' % device.get('fwversion'))
89 | sys.stdout.write('base|identifier=%s\n' % device.get('identifier').replace(' ',''))
90 | sys.stdout.write('base|manufacturer=%s\n' % device.get('manufacturer'))
91 | sys.stdout.write('base|productname=%s\n' % device.get('productname').replace(' ',''))
92 | sys.stdout.write('base|present=%s\n' % device.find('present').text)
93 | sys.stdout.write('base|name=%s\n' % device.find('name').text.encode('ascii','ignore').decode('ascii'))
94 | #sys.stdout.write('humidity|rel_humidity=35\n') # test
95 |
96 | for subelement in device.findall('*'):
97 | if subelement.tag == 'name':
98 | continue
99 | if subelement.tag == 'present':
100 | continue
101 | for detailelement in subelement.findall('*'):
102 | sys.stdout.write('%s|%s=%s\n' % (subelement.tag, detailelement.tag, detailelement.text))
103 |
104 | if __name__ == '__main__':
105 | args = parse_args()
106 | try:
107 | check_fritzbox_smarthome(args)
108 | except:
109 | if args.debug:
110 | raise
111 | sys.stderr.write('fritzbox_smarthome\n %s\n' % traceback.format_exc())
112 | sys.exit(2)
113 |
--------------------------------------------------------------------------------
/web/plugins/wato/parameters_check_fritzbox_smarthome.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 |
4 | from typing import Type, Optional, List
5 | from cmk.gui.i18n import _
6 | from cmk.gui.valuespec import (
7 | Alternative,
8 | Dictionary,
9 | Integer,
10 | Tuple,
11 | FixedValue,
12 | TextAscii,
13 | Checkbox,
14 | )
15 | from cmk.gui.plugins.wato.utils import (
16 | RulespecGroupCheckParametersApplications,
17 | CheckParameterRulespecWithItem,
18 | rulespec_registry,
19 | )
20 |
21 |
22 | def _parameter_valuespec_fritzbox_smarthome():
23 | return Dictionary(
24 | title = _('Parameter'),
25 | optional_keys = [],
26 | elements = [
27 | ( 'present', Alternative(
28 | title = _('Offline Devices'),
29 | style = 'dropdown',
30 | elements = [
31 | FixedValue(
32 | 0,
33 | totext = '',
34 | title = _('show as OK'),
35 | ),
36 | FixedValue(
37 | 1,
38 | totext = '',
39 | title = _('show as WARN'),
40 | ),
41 | FixedValue(
42 | 2,
43 | totext = '',
44 | title = _('show as CRIT'),
45 | ),
46 | ])
47 | ),
48 |
49 | ( 'hkr', Dictionary(
50 | title = _('Thermostat (battery settings are also here)'),
51 | elements = [
52 | ('hkr_bat_always', FixedValue(True, totext='Batterystate will be shown in Status Details', title = _('Show Batterystate always'))),
53 | ('hkr_warn', Dictionary(
54 | title = _('Thresholds for WARN'),
55 | optional_keys = [ 'hkr_diff_soll', 'hkr_bat_below' ],
56 | elements = [
57 | ('hkr_diff_soll', Integer(label = _('by'), title = _('Deviation from the target temperature'), unit = u'°C', default_value = 5)),
58 | ('hkr_bat_below', Integer(label = _('less than'), title = _('Battery'), unit = u'%', default_value = 50)),
59 | ('hkr_flags', Tuple(
60 | title = _('Flags'),
61 | elements = [
62 | Checkbox(title = _('On Errorstate'), default_value = False),
63 | Checkbox(title = _('On Batterywarning'), default_value = False),
64 | Checkbox(title = _('On Window open'), default_value = False),
65 | ]
66 | )),
67 | ]
68 | )
69 | ),
70 | ('hkr_crit', Dictionary(
71 | title = _('Thresholds for CRIT'),
72 | optional_keys = [ 'hkr_diff_soll', 'hkr_bat_below' ],
73 | elements = [
74 | ('hkr_diff_soll', Integer(label = _('by'), title = _('Deviation from the target temperature'), unit = u'°C', default_value = 10)),
75 | ('hkr_bat_below', Integer(label = _('less than'), title = _('Battery'), unit = u'%', default_value = 30)),
76 | ('hkr_flags', Tuple(
77 | title = _('Flags'),
78 | elements = [
79 | Checkbox(title = _('On Errorstate'), default_value = True),
80 | Checkbox(title = _('On Batterywarning'), default_value = False),
81 | Checkbox(title = _('On Window open'), default_value = False),
82 | ]
83 | )),
84 | ]
85 | )
86 | ),
87 | ])
88 | ),
89 |
90 | ( 'humidity', Dictionary(
91 | title = _('Humidity'),
92 |
93 | elements = [
94 | ('humidity_warn', Tuple(
95 | title = _('Thresholds for WARN'),
96 | elements = [
97 | Integer(label = _('higher than'), unit = u'%', default_value = 60),
98 | Integer(label = _('lesser than'), unit = u'%', default_value = 40),
99 | ]
100 | )),
101 | ('humidity_crit', Tuple(
102 | title = _('Thresholds for CRIT'),
103 | elements = [
104 | Integer(label = _('higher than'), unit = u'%', default_value = 70),
105 | Integer(label = _('lesser than'), unit = u'%', default_value = 30),
106 | ]
107 | )),
108 | ])
109 | ),
110 |
111 | # temperature
112 | ]
113 | )
114 |
115 | def _item_spec_fritzbox_smarthome_devices():
116 | return TextAscii(title=_("Device-ID"))
117 |
118 | rulespec_registry.register(
119 | CheckParameterRulespecWithItem(
120 | check_group_name="fritzbox_smarthome",
121 | group=RulespecGroupCheckParametersApplications,
122 | item_spec=_item_spec_fritzbox_smarthome_devices,
123 | match_type="dict",
124 | parameter_valuespec=_parameter_valuespec_fritzbox_smarthome,
125 | title=lambda: _('Settings for Fritz!Box Smarthome Devices')
126 | )
127 | )
128 |
--------------------------------------------------------------------------------
/checks/fritzbox_smarthome:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 |
4 |
5 | factory_settings['fritzbox_smarthome_default_levels'] = {
6 | 'present': 1,
7 | 'hkr': {
8 | 'hkr_bat_always': False,
9 | 'hkr_warn' : {
10 | 'hkr_bat_below' : 30,
11 | 'hkr_diff_soll': 5,
12 | 'hkr_flags': [True, True, False]
13 | },
14 | 'hkr_crit' : {
15 | 'hkr_bat_below' : 20,
16 | 'hkr_diff_soll': 8,
17 | 'hkr_flags': [True, True, False]
18 | },
19 | },
20 | 'switch': {},
21 | 'powermeter': {},
22 | 'temperature': {},
23 | 'humidity': {
24 | 'humidity_crit': (70, 30),
25 | 'humidity_warn': (60, 40)
26 | }
27 | }
28 |
29 |
30 | def nested_update(d, u):
31 | for k, v in u.items():
32 | if isinstance(v, collections.Mapping):
33 | d[k] = nested_update(d.get(k, {}), v)
34 | else:
35 | d[k] = v
36 | return d
37 |
38 | def parse_fritzbox_smarthome(info):
39 | devices = {}
40 | current_device_id = None
41 |
42 | for line in info:
43 | fullline = ' '.join(line)
44 | if fullline.startswith('id='):
45 | current_device_id = fullline.split('=')[1]
46 | devices[current_device_id] = {}
47 | continue
48 | else:
49 | group = fullline.split('|')[0]
50 | item = fullline.split('|')[1].split('=')[0]
51 | value = fullline.split('|')[1].split('=')[1]
52 | if group not in devices[current_device_id].keys():
53 | devices[current_device_id][group] = {}
54 | devices[current_device_id][group][item] = value
55 |
56 | return devices
57 |
58 | def smarthome_helper_hkr(data, params):
59 | data['hkr']['tist'] = float(data['hkr']['tist'])/2.0
60 | data['hkr']['tsoll'] = float(data['hkr']['tsoll'])/2.0
61 | data['hkr']['absenk'] = float(data['hkr']['absenk'])/2.0
62 | data['hkr']['komfort'] = float(data['hkr']['komfort'])/2.0
63 |
64 | check_status = 0
65 | msg_data = []
66 | perf_data = []
67 |
68 | if (int(data['hkr']['summeractive']) == 0):
69 | msg_data.append('Thermostat Temperature {}°C (Should: {}°C)'.format(data['hkr']['tist'], data['hkr']['tsoll']))
70 | else:
71 | msg_data.append('Thermostat Temperature {}°C (Summer-Mode)'.format(data['hkr']['tist']))
72 |
73 | tist = data['hkr']['tist']
74 | if 'temperature' in data.keys():
75 | # use Temperature Sensor if given (refernced value)
76 | temperature_celsius = float(data['temperature']['celsius'])/10.0
77 | temperature_offset = float(data['temperature']['offset'])/10.0
78 | tist = temperature_celsius
79 | #perf_data.append(('temperature_celsius', temperature_celsius))
80 | #perf_data.append(('temperature_offset', temperature_offset))
81 |
82 | diff = (data['hkr']['tsoll']-tist)
83 | if diff < 0:
84 | diff = diff *-1
85 |
86 | perf_data.append(('hkr_windowopenactiv', data['hkr']['windowopenactiv']))
87 | perf_data.append(('hkr_battery', data['hkr']['battery'],
88 | params['hkr_warn']['hkr_bat_below'],
89 | params['hkr_crit']['hkr_bat_below'], 0, 100))
90 |
91 | #perf_data.append(('hkr_tist', data['hkr']['tist']))
92 | if (not data['hkr']['summeractive']):
93 | perf_data.append(('hkr_tsoll', data['hkr']['tsoll']))
94 | else:
95 | perf_data.append(('hkr_tsoll', 0))
96 |
97 | perf_data.append(('hkr_absenk', data['hkr']['absenk']))
98 | perf_data.append(('hkr_komfort', data['hkr']['komfort']))
99 |
100 | perf_data.append(('ref_temperature', tist))
101 | bat_added = False
102 |
103 | if (not data['hkr']['summeractive']):
104 | if float(params['hkr_crit']['hkr_diff_soll']) < diff:
105 | check_status = 2 if check_status < 2 else check_status
106 | msg_data.append('Difference to High ({})'.format(diff))
107 | elif float(params['hkr_warn']['hkr_diff_soll']) < diff:
108 | check_status = 1 if check_status < 1 else check_status
109 | msg_data.append('Difference to High ({})'.format(diff))
110 |
111 | if float(params['hkr_crit']['hkr_bat_below']) > float(data['hkr']['battery']):
112 | check_status = 2 if check_status < 2 else check_status
113 | msg_data.append('Battery low ({}%)!'.format(data['hkr']['battery']))
114 | bat_added = True
115 | elif float(params['hkr_warn']['hkr_bat_below']) > float(data['hkr']['battery']):
116 | check_status = 1 if check_status < 1 else check_status
117 | msg_data.append('Battery low ({}%)!'.format(data['hkr']['battery']))
118 | bat_added = True
119 |
120 | if params['hkr_crit']['hkr_flags'][0] and data['hkr']['errorcode'] != str(0):
121 | check_status = 2 if check_status < 2 else check_status
122 | msg_data.append('Errorcode: {}'.format(data['hkr']['errorcode']))
123 | elif params['hkr_warn']['hkr_flags'][0] and data['hkr']['errorcode'] != str(0):
124 | check_status = 1 if check_status < 1 else check_status
125 | msg_data.append('Errorcode: {}'.format(data['hkr']['errorcode']))
126 |
127 | if params['hkr_crit']['hkr_flags'][1] and data['hkr']['batterylow'] != str(0):
128 | check_status = 2 if check_status < 2 else check_status
129 | msg_data.append('Batterywarning ({}%)'.format(data['hkr']['battery']))
130 | bat_added = True
131 | elif params['hkr_warn']['hkr_flags'][1] and data['hkr']['batterylow'] != str(0):
132 | check_status = 1 if check_status < 1 else check_status
133 | msg_data.append('Batterywarning ({}%)'.format(data['hkr']['battery']))
134 | bat_added = True
135 |
136 | if not bat_added and params['hkr_bat_always']:
137 | msg_data.append('Battery at {}%'.format(data['hkr']['battery']))
138 |
139 | if params['hkr_crit']['hkr_flags'][2] and data['hkr']['windowopenactiv'] != str(0):
140 | check_status = 2 if check_status < 2 else check_status
141 | elif params['hkr_warn']['hkr_flags'][2] and data['hkr']['windowopenactiv'] != str(0):
142 | check_status = 1 if check_status < 1 else check_status
143 |
144 | if data['hkr']['windowopenactiv'] == "1":
145 | msg_data.append('Window is open')
146 |
147 | return (msg_data, perf_data, check_status)
148 |
149 | def smarthome_helper_powermeter(data, params):
150 |
151 | data['powermeter']['power'] = float(data['powermeter']['power'])/1000
152 | data['powermeter']['energy'] = float(data['powermeter']['energy'])/1000
153 | data['powermeter']['voltage'] = float(data['powermeter']['voltage'])/1000
154 |
155 | check_status = 0
156 | msg_data = []
157 | perf_data = []
158 |
159 | perf_data.append(('powermeter_power', data['powermeter']['power'])) # Leistung
160 | perf_data.append(('powermeter_energy', data['powermeter']['energy'])) # Verbauch (consumption)
161 | perf_data.append(('powermeter_voltage', data['powermeter']['voltage'])) # Spannung
162 | msg_data.append('Power: {}W, Consumption: {}kWh, Voltage: {}V'.format(data['powermeter']['power'], data['powermeter']['energy'], data['powermeter']['voltage']))
163 |
164 | return (msg_data, perf_data, check_status)
165 |
166 | def smarthome_helper_temperature(data, params):
167 |
168 | check_status = 0
169 | msg_data = []
170 | perf_data = []
171 |
172 | temperature_celsius = float(data['temperature']['celsius'])/10.0
173 | temperature_offset = float(data['temperature']['offset'])/10.0
174 |
175 | perf_data.append(('temperature_celsius', temperature_celsius))
176 | perf_data.append(('temperature_offset', temperature_offset*-1))
177 | #perf_data.append(('temperature_real', (temperature_celsius+(temperature_offset*-1))))
178 |
179 | return (msg_data, perf_data, check_status)
180 |
181 | def smarthome_helper_humidity(data, params):
182 |
183 | check_status = 0
184 | msg_data = []
185 | perf_data = []
186 |
187 | humidity = int(data['humidity']['rel_humidity'])
188 |
189 | if int(params['humidity_crit'][0]) < humidity: # High crit
190 | check_status = 2 if check_status < 2 else check_status
191 | msg_data.append('Humidity is {}% (to high!)'.format(humidity))
192 | elif int(params['humidity_crit'][1]) > humidity: # Low crit
193 | check_status = 2 if check_status < 2 else check_status
194 | msg_data.append('Humidity is {}% (to low!)'.format(humidity))
195 | elif int(params['humidity_warn'][0]) < humidity: # High warn
196 | check_status = 1 if check_status < 1 else check_status
197 | msg_data.append('Humidity is {}% (to high!)'.format(humidity))
198 | elif int(params['humidity_warn'][1]) > humidity: # Low warn
199 | check_status = 1 if check_status < 1 else check_status
200 | msg_data.append('Humidity is {}% (to low!)'.format(humidity))
201 | else:
202 | msg_data.append('Humidity is {}%'.format(humidity))
203 |
204 | perf_data.append(('humidity', humidity))
205 |
206 | return (msg_data, perf_data, check_status)
207 |
208 | def smarthome_helper_switch(data, params):
209 |
210 | check_status = 0
211 | msg_data = []
212 | perf_data = []
213 |
214 | switch_status = 'ON' if data['switch']['state'] == str(1) else 'OFF'
215 | msg_data.append('State: {} ({})'.format(switch_status, data['switch']['mode']))
216 |
217 | perf_data.append(('switch_state', data['switch']['state']))
218 |
219 | return (msg_data, perf_data, check_status)
220 |
221 |
222 | def inventory_fritzbox_smarthome(info):
223 | devices = parse_fritzbox_smarthome(info)
224 |
225 | for device_key, device in devices.items():
226 | device_type = 'Unknown'
227 | fbm = int(device['base']['functionbitmask'])
228 | if fbm >> 0 & 1:
229 | device_type = 'HANFUNDevice'
230 | elif fbm >> 13 & 1:
231 | device_type = 'HANFUNUnit'
232 | elif fbm >> 4 & 1:
233 | device_type = 'AlarmSensor'
234 | elif fbm >> 5 & 1:
235 | device_type = 'Button'
236 | elif fbm >> 6 & 1:
237 | device_type = 'Thermostat'
238 | elif fbm >> 9 & 1:
239 | device_type = 'Switch'
240 | elif fbm >> 7 & 1:
241 | device_type = 'Powermeter'
242 | elif fbm >> 10 & 1:
243 | device_type = 'DECTRepeater'
244 | elif fbm >> 8 & 1:
245 | device_type = 'TemperatureSensor'
246 | elif fbm >> 11 & 1:
247 | device_type = 'Microphone'
248 | elif fbm >> 17 & 1:
249 | device_type = 'Light'
250 | elif fbm >> 2 & 1:
251 | device_type = 'Light'
252 | yield ('{} {} {}'.format(device_key, device_type, device['base']['name']), None)
253 |
254 | def check_fritzbox_smarthome(item, params, info):
255 | devices = parse_fritzbox_smarthome(info)
256 |
257 | #prepared params
258 |
259 | pparams = {}
260 | pparams = nested_update(pparams, factory_settings['fritzbox_smarthome_default_levels'])
261 | if params:
262 | pparams = nested_update(pparams, params)
263 |
264 | device = None
265 | msg_data = []
266 | perf_data = []
267 | check_status = 0
268 |
269 | # Find current device
270 | for device_key, device_n in devices.items():
271 | if item.startswith(device_key + " "):
272 | device = device_n
273 | break
274 |
275 | if not device:
276 | return 3, 'DEVICE NOT FOUND'
277 |
278 | if int(device['base']['present']) == 0:
279 | if int(pparams['present']) == 1: #WARN
280 | check_status = 1 if check_status < 1 else check_status
281 | if int(pparams['present']) == 2: #CRIT
282 | check_status = 2 if check_status < 2 else check_status
283 | msg_data.append('Not Present')
284 |
285 | msg_data.append('{} {} (FW: {})'.format(device['base']['manufacturer'], device['base']['productname'], device['base']['fwversion']))
286 |
287 | if int(device['base']['present']) != 0:
288 | fbm = int(device['base']['functionbitmask'])
289 | if fbm >> 0 & 1: #HANFUNDevice
290 | pass
291 | if fbm >> 4 & 1: #AlarmSensor
292 | #alert
293 | pass
294 | if fbm >> 5 & 1: #Taster
295 | pass
296 | if fbm >> 6 & 1: #Thermostat
297 | r = smarthome_helper_hkr(device, pparams['hkr'])
298 | msg_data.extend(r[0])
299 | perf_data.extend(r[1])
300 | check_status = r[2] if check_status < r[2] else check_status
301 | if fbm >> 9 & 1: #Schaltsteckdose
302 | r = smarthome_helper_switch(device, pparams['switch'])
303 | msg_data.extend(r[0])
304 | perf_data.extend(r[1])
305 | check_status = r[2] if check_status < r[2] else check_status
306 | if fbm >> 7 & 1: #Powermeter
307 | r = smarthome_helper_powermeter(device, pparams['powermeter'])
308 | msg_data.extend(r[0])
309 | perf_data.extend(r[1])
310 | check_status = r[2] if check_status < r[2] else check_status
311 | if fbm >> 8 & 1: #TemperatureSensor
312 | r = smarthome_helper_temperature(device, pparams['temperature'])
313 | msg_data.extend(r[0])
314 | perf_data.extend(r[1])
315 | check_status = r[2] if check_status < r[2] else check_status
316 | if fbm >> 10 & 1: #DECTRepeater
317 | pass
318 | if fbm >> 11 & 1: #Microphone
319 | pass
320 | if fbm >> 13 & 1: #HANFUNUnit
321 | pass
322 |
323 | if 'humidity' in device.keys():
324 | # seems related for functionbit 5 only (AVMButton)
325 | # so this may change in a future release
326 | r = smarthome_helper_humidity(device, pparams['humidity'])
327 | msg_data.extend(r[0])
328 | perf_data.extend(r[1])
329 | check_status = r[2] if check_status < r[2] else check_status
330 |
331 | return check_status, ', '.join(msg_data), perf_data
332 |
333 | check_info['fritzbox_smarthome'] = {
334 | 'inventory_function' : inventory_fritzbox_smarthome,
335 | 'check_function' : check_fritzbox_smarthome,
336 | 'service_description' : 'SmartDevice %s',
337 | 'group' : 'fritzbox_smarthome',
338 | 'default_levels_variable' : 'fritzbox_smarthome_default_levels',
339 | 'has_perfdata' : True,
340 | }
341 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------