Completed
Pull Request — master (#963)
by
unknown
01:02
created

Plugin.get_alert()   B

Complexity

Conditions 5

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
c 2
b 0
f 0
dl 0
loc 19
rs 8.5454
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2016 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""Wifi plugin."""
21
22
import base64
23
import operator
24
25
from glances.logger import logger
26
from glances.timer import getTimeSinceLastUpdate
27
from glances.plugins.glances_plugin import GlancesPlugin
28
29
import psutil
30
# Use the Wifi Python lib (https://pypi.python.org/pypi/wifi)
31
# Linux-only
32
try:
33
    from wifi.scan import Cell
34
    from wifi.exceptions import InterfaceError
35
except ImportError as e:
36
    logger.debug("Wifi library not found. Glances cannot grab Wifi info.")
37
    wifi_tag = False
38
else:
39
    wifi_tag = True
40
41
42
class Plugin(GlancesPlugin):
43
44
    """Glances Wifi plugin.
45
    Get stats of the current Wifi hotspots.
46
    """
47
48
    def __init__(self, args=None):
49
        """Init the plugin."""
50
        super(Plugin, self).__init__(args=args)
51
52
        # We want to display the stat in the curse interface
53
        self.display_curse = True
54
55
        # Init the stats
56
        self.reset()
57
58
    def get_key(self):
59
        """Return the key of the list.
60
61
        :returns: string -- SSID is the dict key
62
        """
63
        return 'ssid'
64
65
    def reset(self):
66
        """Reset/init the stats to an empty list.
67
68
        :returns: None
69
        """
70
        self.stats = []
71
72
    @GlancesPlugin._check_decorator
73
    @GlancesPlugin._log_result_decorator
74
    def update(self):
75
        """Update Wifi stats using the input method.
76
77
        Stats is a list of dict (one dict per hotspot)
78
79
        :returns: list -- Stats is a list of dict (hotspot)
80
        """
81
        # Reset stats
82
        self.reset()
83
84
        # Exist if we can not grab the stats
85
        if not wifi_tag:
86
            return self.stats
87
88
        if self.input_method == 'local':
89
            # Update stats using the standard system lib
90
91
            # Grab network interface stat using the PsUtil net_io_counter method
92
            try:
93
                netiocounters = psutil.net_io_counters(pernic=True)
94
            except UnicodeDecodeError:
95
                return self.stats
96
97
            for net in netiocounters:
98
                # Do not take hidden interface into account
99
                if self.is_hide(net):
100
                    continue
101
102
                # Grab the stats using the Wifi Python lib
103
                try:
104
                    wifi_cells = Cell.all(net)
105
                except InterfaceError:
106
                    # Not a Wifi interface
107
                    pass
108
                else:
109
                    for wifi_cell in wifi_cells:
110
                        hotspot = {
111
                            'key': self.get_key(),
112
                            'ssid': wifi_cell.ssid,
113
                            'signal': wifi_cell.signal,
114
                            'quality': wifi_cell.quality,
115
                            'encrypted': wifi_cell.encrypted,
116
                            'encryption_type': wifi_cell.encryption_type if wifi_cell.encrypted else None
117
                        }
118
                        # Add the hotspot to the list
119
                        self.stats.append(hotspot)
120
121
        elif self.input_method == 'snmp':
122
            # Update stats using SNMP
123
124
            # Not implemented yet
125
            pass
126
127
        return self.stats
128
129
    def get_alert(self, value):
130
        """Overwrite the default get_alert method.
131
        Alert is on signal quality where lower is better...
132
133
        :returns: string -- Signal alert
134
        """
135
136
        ret = 'OK'
137
        try:
138
            if value <= self.get_limit('critical', stat_name=self.plugin_name):
139
                ret = 'CRITICAL'
140
            elif value <= self.get_limit('warning', stat_name=self.plugin_name):
141
                ret = 'WARNING'
142
            elif value <= self.get_limit('careful', stat_name=self.plugin_name):
143
                ret = 'CAREFUL'
144
        except KeyError:
145
            ret = 'DEFAULT'
146
147
        return ret
148
149
    def update_views(self):
150
        """Update stats views."""
151
        # Call the father's method
152
        super(Plugin, self).update_views()
153
154
        # Add specifics informations
155
        # Alert on signal thresholds
156
        for i in self.stats:
157
            self.views[i[self.get_key()]]['signal']['decoration'] = self.get_alert(i['signal'])
158
            self.views[i[self.get_key()]]['quality']['decoration'] = self.views[i[self.get_key()]]['signal']['decoration']
159
160
    def msg_curse(self, args=None, max_width=None):
161
        """Return the dict to display in the curse interface."""
162
        # Init the return message
163
        ret = []
164
165
        # Only process if stats exist and display plugin enable...
166
        if not self.stats or args.disable_wifi or not wifi_tag:
167
            return ret
168
169
        # Max size for the interface name
170
        if max_width is not None and max_width >= 23:
171
            # Interface size name = max_width - space for encyption + quality
172
            ifname_max_width = max_width - 5
173
        else:
174
            ifname_max_width = 16
175
176
        # Build the string message
177
        # Header
178
        msg = '{:{width}}'.format('WIFI', width=ifname_max_width)
179
        ret.append(self.curse_add_line(msg, "TITLE"))
180
        msg = '{:>7}'.format('dBm')
181
        ret.append(self.curse_add_line(msg))
182
183
        # Hotspot list (sorted by name)
184
        for i in sorted(self.stats, key=operator.itemgetter(self.get_key())):
185
            # Do not display hotspot with no name (/ssid)
186
            if i['ssid'] == '':
187
                continue
188
            ret.append(self.curse_new_line())
189
            # New hotspot
190
            hotspotname = i['ssid']
191
            # Add the encryption type (if it is available)
192
            if i['encrypted']:
193
                hotspotname = hotspotname + ' {}'.format(i['encryption_type'])
194
            # Cut hotspotname if it is too long
195
            if len(hotspotname) > ifname_max_width:
196
                hotspotname = '_' + hotspotname[-ifname_max_width + 1:]
197
            # Add the new hotspot to the message
198
            msg = '{:{width}}'.format(hotspotname, width=ifname_max_width)
199
            ret.append(self.curse_add_line(msg))
200
            msg = '{:>7}'.format(i['signal'], width=ifname_max_width)
201
            ret.append(self.curse_add_line(msg,
202
                                           self.get_views(item=i[self.get_key()],
203
                                                          key='signal',
204
                                                          option='decoration')))
205
206
        return ret
207