Пример #1
0
    def _alarm(self, text):
        notification = DesktopNotification('Alarm!', text)
        notification.display()

        subprocess.Popen(['aplay', self.sound, '-q'],
                         stdout=subprocess.DEVNULL,
                         stderr=subprocess.DEVNULL)
Пример #2
0
    def _alarm(self, text):
        notification = DesktopNotification('Alarm!', text)
        notification.display()

        subprocess.Popen(['aplay',
                          self.sound,
                          '-q'],
                         stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Пример #3
0
    def _alarm(self, text):
        notification = DesktopNotification(title='Alarm!', body=text)
        notification.display()

        if self.sound is not None:
            subprocess.Popen(['mpv', '--really-quiet', self.sound],
                             stdout=subprocess.DEVNULL,
                             stderr=subprocess.DEVNULL)
Пример #4
0
    def _alarm(self, text):
        notification = DesktopNotification(title='Alarm!', body=text)
        notification.display()

        if self.sound is not None:
            subprocess.Popen(['aplay',
                              self.sound,
                              '-q'],
                             stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Пример #5
0
class BatteryChecker(IntervalModule):
    """
    This class uses the /sys/class/power_supply/…/uevent interface to check for the
    battery status.

    Setting ``battery_ident`` to ``ALL`` will summarise all available batteries
    and aggregate the % as well as the time remaining on the charge. This is
    helpful when the machine has more than one battery available.

    .. rubric:: Available formatters

    * `{remaining}` — remaining time for charging or discharging, uses TimeWrapper formatting, default format is `%E%h:%M`
    * `{percentage}` — battery percentage relative to the last full value
    * `{percentage_design}` — absolute battery charge percentage
    * `{consumption (Watts)}` — current power flowing into/out of the battery
    * `{status}`
    * `{no_of_batteries}` — The number of batteries included
    * `{battery_ident}` — the same as the setting
    * `{bar}` —bar displaying the relative percentage graphically
    * `{bar_design}` —bar displaying the absolute percentage graphically
    * `{glyph}` — A single character or string (selected from 'glyphs') representing the current battery percentage

    This module supports the :ref:`formatp <formatp>` extended string format
    syntax. By setting the ``FULL`` status to an empty string, and including
    brackets around the ``{status}`` formatter, the text within the brackets
    will be hidden when the battery is full, as can be seen in the below
    example:

    .. code-block:: python

        from i3pystatus import Status

        status = Status()

        status.register(
            'battery',
            interval=5,
            format='{battery_ident}: [{status} ]{percentage_design:.2f}%',
            alert=True,
            alert_percentage=15,
            status={
                'DPL': 'DPL',
                'CHR': 'CHR',
                'DIS': 'DIS',
                'FULL': '',
            }
        )

        # status.register(
        #     'battery',
        #     format='{status} {percentage:.0f}%',
        #     levels={
        #         25: "<=25",
        #         50: "<=50",
        #         75: "<=75",
        #     },
        # )

        status.run()

    """

    settings = (
        ("battery_ident",
         "The name of your battery, usually BAT0 or BAT1"), "format",
        ("not_present_text",
         "Text displayed if the battery is not present. No formatters are available"
         ), ("alert", "Display a libnotify-notification on low battery"),
        ("critical_level_command",
         "Runs a shell command in the case of a critical power state"),
        "critical_level_percentage", "alert_percentage", "alert_timeout",
        ("alert_format_title",
         "The title of the notification, all formatters can be used"),
        ("alert_format_body",
         "The body text of the notification, all formatters can be used"),
        ("path",
         "Override the default-generated path and specify the full path for a single battery"
         ), ("base_path",
             "Override the default base path for searching for batteries"),
        ("battery_prefix", "Override the default battery prefix"),
        ("status",
         "A dictionary mapping ('DPL', 'DIS', 'CHR', 'FULL') to alternative names"
         ),
        ("levels",
         "A dictionary mapping percentages of charge levels to corresponding names."
         ), ("color", "The text color"), ("full_color", "The full color"),
        ("charging_color", "The charging color"),
        ("critical_color", "The critical color"), ("not_present_color",
                                                   "The not present color."),
        ("not_present_text",
         "The text to display when the battery is not present. Provides {battery_ident} as formatting option"
         ), ("no_text_full", "Don't display text when battery is full - 100%"),
        ("glyphs",
         "Arbitrarily long string of characters (or array of strings) to represent battery charge percentage"
         ),
        ("use_design_percentage",
         "Use design percentage rather then absolute percentage for alerts"))

    battery_ident = "ALL"
    format = "{status} {remaining}"
    status = {
        "DPL": "DPL",
        "CHR": "CHR",
        "DIS": "DIS",
        "FULL": "FULL",
    }
    levels = None
    not_present_text = "Battery {battery_ident} not present"

    alert = False
    critical_level_command = ""
    critical_level_percentage = 1
    alert_percentage = 10
    alert_timeout = -1
    alert_format_title = "Low battery"
    alert_format_body = "Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!"
    color = "#ffffff"
    full_color = "#00ff00"
    charging_color = "#00ff00"
    critical_color = "#ff0000"
    not_present_color = "#ffffff"
    no_text_full = False
    glyphs = "▁▂▃▄▅▆▇█"
    use_design_percentage = False

    battery_prefix = 'BAT'
    base_path = '/sys/class/power_supply'
    path = None
    paths = []

    notification = None

    def percentage(self, batteries, design=False):
        total_now = [battery.wh_remaining() for battery in batteries]
        total_full = [battery.wh_total() for battery in batteries]
        return sum(total_now) / sum(total_full) * 100

    def consumption(self, batteries):
        consumption = 0
        for battery in batteries:
            if battery.consumption() is not None:
                consumption += battery.consumption()
        return consumption

    def abs_consumption(self, batteries):
        abs_consumption = 0
        for battery in batteries:
            if battery.consumption() is None:
                continue
            if battery.status() == 'Discharging':
                abs_consumption -= battery.consumption()
            elif battery.status() == 'Charging':
                abs_consumption += battery.consumption()
        return abs_consumption

    def battery_status(self, batteries):
        abs_consumption = self.abs_consumption(batteries)
        if abs_consumption > 0:
            return 'Charging'
        elif abs_consumption < 0:
            return 'Discharging'
        else:
            return batteries[-1].status()

    def remaining(self, batteries):
        wh_depleted = 0
        wh_remaining = 0
        abs_consumption = self.abs_consumption(batteries)
        for battery in batteries:
            wh_remaining += battery.wh_remaining()
            wh_depleted += battery.wh_depleted()
        if abs_consumption == 0:
            return 0
        elif abs_consumption > 0:
            return wh_depleted / self.consumption(batteries) * 60
        elif abs_consumption < 0:
            return wh_remaining / self.consumption(batteries) * 60

    def init(self):
        if not self.paths or (self.path and self.path not in self.paths):
            bat_dir = self.base_path
            if os.path.exists(bat_dir) and not self.path:
                _, dirs, _ = next(os.walk(bat_dir))
                all_bats = [
                    x for x in dirs if x.startswith(self.battery_prefix)
                ]
                for bat in all_bats:
                    self.paths.append(os.path.join(bat_dir, bat, 'uevent'))
            if self.path:
                self.paths = [self.path]

    def run(self):
        urgent = False
        color = self.color
        batteries = []

        for path in self.paths:
            if self.battery_ident == 'ALL' or path.find(
                    self.battery_ident) >= 0:
                try:
                    batteries.append(Battery.create(path))
                except FileNotFoundError:
                    pass

        if not batteries:
            format_dict = {'battery_ident': self.battery_ident}
            self.output = {
                "full_text": formatp(self.not_present_text, **format_dict),
                "color": self.not_present_color,
            }
            return
        if self.no_text_full:
            if self.battery_status(batteries) == "Full":
                self.output = {"full_text": ""}
                return

        fdict = {
            "battery_ident":
            self.battery_ident,
            "no_of_batteries":
            len(batteries),
            "percentage":
            self.percentage(batteries),
            "percentage_design":
            self.percentage(batteries, design=True),
            "consumption":
            self.consumption(batteries),
            "remaining":
            TimeWrapper(0, "%E%h:%M"),
            "glyph":
            make_glyph(self.percentage(batteries), self.glyphs),
            "bar":
            make_bar(self.percentage(batteries)),
            "bar_design":
            make_bar(self.percentage(batteries, design=True)),
            "vertical_bar":
            make_vertical_bar(self.percentage(batteries)),
            "vertical_bar_design":
            make_vertical_bar(self.percentage(batteries, design=True)),
        }

        status = self.battery_status(batteries)
        if status in ["Charging", "Discharging"]:
            remaining = self.remaining(batteries)
            fdict["remaining"] = TimeWrapper(remaining * 60, "%E%h:%M")
            if status == "Discharging":
                fdict["status"] = "DIS"
                if self.percentage(batteries) <= self.alert_percentage:
                    urgent = True
                    color = self.critical_color
            else:
                fdict["status"] = "CHR"
                color = self.charging_color
        elif status == 'Depleted':
            fdict["status"] = "DPL"
            color = self.critical_color
        else:
            fdict["status"] = "FULL"
            color = self.full_color
        if self.critical_level_command and fdict["status"] == "DIS" and fdict[
                "percentage"] <= self.critical_level_percentage:
            run_through_shell(self.critical_level_command, enable_shell=True)

        self.alert_if_low_battery(fdict)

        if self.levels and fdict['status'] == 'DIS':
            self.levels.setdefault(0, self.status.get('DPL', 'DPL'))
            self.levels.setdefault(100, self.status.get('FULL', 'FULL'))
            keys = sorted(self.levels.keys())
            index = bisect.bisect_left(keys, int(fdict['percentage']))
            fdict["status"] = self.levels[keys[index]]
        else:
            fdict["status"] = self.status[fdict["status"]]

        self.data = fdict
        self.output = {
            "full_text": formatp(self.format, **fdict),
            "instance": self.battery_ident,
            "urgent": urgent,
            "color": color,
        }

    def alert_if_low_battery(self, fdict):
        if self.use_design_percentage:
            percentage = fdict['percentage_design']
        else:
            percentage = fdict['percentage']

        if self.alert and fdict[
                "status"] == "DIS" and percentage <= self.alert_percentage:
            title, body = formatp(self.alert_format_title,
                                  **fdict), formatp(self.alert_format_body,
                                                    **fdict)
            if self.notification is None:
                self.notification = DesktopNotification(
                    title=title,
                    body=body,
                    icon="battery-caution",
                    urgency=2,
                    timeout=self.alert_timeout,
                )
                self.notification.display()
            else:
                self.notification.update(title=title, body=body)
Пример #6
0
class BatteryChecker(IntervalModule):
    """
    This class uses the /sys/class/power_supply/…/uevent interface to check for the
    battery status.

    Setting ``battery_ident`` to ``ALL`` will summarise all available batteries
    and aggregate the % as well as the time remaining on the charge. This is
    helpful when the machine has more than one battery available.

    .. rubric:: Available formatters

    * `{remaining}` — remaining time for charging or discharging, uses TimeWrapper formatting, default format is `%E%h:%M`
    * `{percentage}` — battery percentage relative to the last full value
    * `{percentage_design}` — absolute battery charge percentage
    * `{consumption (Watts)}` — current power flowing into/out of the battery
    * `{status}`
    * `{no_of_batteries}` — The number of batteries included
    * `{battery_ident}` — the same as the setting
    * `{bar}` —bar displaying the relative percentage graphically
    * `{bar_design}` —bar displaying the absolute percentage graphically

    This module supports the :ref:`formatp <formatp>` extended string format
    syntax. By setting the ``FULL`` status to an empty string, and including
    brackets around the ``{status}`` formatter, the text within the brackets
    will be hidden when the battery is full, as can be seen in the below
    example:

    .. code-block:: python

        from i3pystatus import Status

        status = Status()

        status.register(
            'battery',
            interval=5,
            format='{battery_ident}: [{status} ]{percentage_design:.2f}%',
            alert=True,
            alert_percentage=15,
            status = {
                'DPL': 'DPL',
                'CHR': 'CHR',
                'DIS': 'DIS',
                'FULL': '',
            }
        )

        status.run()

    """

    settings = (
        ("battery_ident", "The name of your battery, usually BAT0 or BAT1"),
        "format",
        ("not_present_text", "Text displayed if the battery is not present. No formatters are available"),
        ("alert", "Display a libnotify-notification on low battery"),
        ("critical_level_command", "Runs a shell command in the case of a critical power state"),
        "critical_level_percentage",
        "alert_percentage",
        "alert_timeout",
        ("alert_format_title", "The title of the notification, all formatters can be used"),
        ("alert_format_body", "The body text of the notification, all formatters can be used"),
        ("path", "Override the default-generated path and specify the full path for a single battery"),
        ("base_path", "Override the default base path for searching for batteries"),
        ("battery_prefix", "Override the default battery prefix"),
        ("status", "A dictionary mapping ('DPL', 'DIS', 'CHR', 'FULL') to alternative names"),
        ("color", "The text color"),
        ("full_color", "The full color"),
        ("charging_color", "The charging color"),
        ("critical_color", "The critical color"),
        ("not_present_color", "The not present color."),
        ("not_present_text",
         "The text to display when the battery is not present. Provides {battery_ident} as formatting option"),
        ("no_text_full", "Don't display text when battery is full - 100%"),
    )

    battery_ident = "ALL"
    format = "{status} {remaining}"
    status = {
        "DPL": "DPL",
        "CHR": "CHR",
        "DIS": "DIS",
        "FULL": "FULL",
    }
    not_present_text = "Battery {battery_ident} not present"

    alert = False
    critical_level_command = ""
    critical_level_percentage = 1
    alert_percentage = 10
    alert_timeout = -1
    alert_format_title = "Low battery"
    alert_format_body = "Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!"
    color = "#ffffff"
    full_color = "#00ff00"
    charging_color = "#00ff00"
    critical_color = "#ff0000"
    not_present_color = "#ffffff"
    no_text_full = False

    battery_prefix = 'BAT'
    base_path = '/sys/class/power_supply'
    path = None
    paths = []

    notification = None

    def percentage(self, batteries, design=False):
        total_now = [battery.wh_remaining() for battery in batteries]
        total_full = [battery.wh_total() for battery in batteries]
        return sum(total_now) / sum(total_full) * 100

    def consumption(self, batteries):
        consumption = 0
        for battery in batteries:
            if battery.consumption() is not None:
                consumption += battery.consumption()
        return consumption

    def abs_consumption(self, batteries):
        abs_consumption = 0
        for battery in batteries:
            if battery.consumption() is None:
                continue
            if battery.status() == 'Discharging':
                abs_consumption -= battery.consumption()
            elif battery.status() == 'Charging':
                abs_consumption += battery.consumption()
        return abs_consumption

    def battery_status(self, batteries):
        abs_consumption = self.abs_consumption(batteries)
        if abs_consumption > 0:
            return 'Charging'
        elif abs_consumption < 0:
            return 'Discharging'
        else:
            return batteries[-1].status()

    def remaining(self, batteries):
        wh_depleted = 0
        wh_remaining = 0
        abs_consumption = self.abs_consumption(batteries)
        for battery in batteries:
            wh_remaining += battery.wh_remaining()
            wh_depleted += battery.wh_depleted()
        if abs_consumption == 0:
            return 0
        elif abs_consumption > 0:
            return wh_depleted / self.consumption(batteries) * 60
        elif abs_consumption < 0:
            return wh_remaining / self.consumption(batteries) * 60

    def init(self):
        if not self.paths or (self.path and self.path not in self.paths):
            bat_dir = self.base_path
            if os.path.exists(bat_dir) and not self.path:
                _, dirs, _ = next(os.walk(bat_dir))
                all_bats = [x for x in dirs if x.startswith(self.battery_prefix)]
                for bat in all_bats:
                    self.paths.append(os.path.join(bat_dir, bat, 'uevent'))
            if self.path:
                self.paths = [self.path]

    def run(self):
        urgent = False
        color = self.color
        batteries = []

        for path in self.paths:
            if self.battery_ident == 'ALL' or path.find(self.battery_ident) >= 0:
                try:
                    batteries.append(Battery.create(path))
                except FileNotFoundError:
                    pass

        if not batteries:
            format_dict = {'battery_ident': self.battery_ident}
            self.output = {
                "full_text": formatp(self.not_present_text, **format_dict),
                "color": self.not_present_color,
            }
            return
        if self.no_text_full:
            if self.battery_status(batteries) == "Full":
                self.output = {
                    "full_text": ""
                }
                return

        fdict = {
            "battery_ident": self.battery_ident,
            "no_of_batteries": len(batteries),
            "percentage": self.percentage(batteries),
            "percentage_design": self.percentage(batteries, design=True),
            "consumption": self.consumption(batteries),
            "remaining": TimeWrapper(0, "%E%h:%M"),
            "bar": make_bar(self.percentage(batteries)),
            "bar_design": make_bar(self.percentage(batteries, design=True)),
        }

        status = self.battery_status(batteries)
        if status in ["Charging", "Discharging"]:
            remaining = self.remaining(batteries)
            fdict["remaining"] = TimeWrapper(remaining * 60, "%E%h:%M")
            if status == "Discharging":
                fdict["status"] = "DIS"
                if self.percentage(batteries) <= self.alert_percentage:
                    urgent = True
                    color = self.critical_color
            else:
                fdict["status"] = "CHR"
                color = self.charging_color
        elif status == 'Depleted':
            fdict["status"] = "DPL"
            color = self.critical_color
        else:
            fdict["status"] = "FULL"
            color = self.full_color
        if self.critical_level_command and fdict["status"] == "DIS" and fdict["percentage"] <= self.critical_level_percentage:
            run_through_shell(self.critical_level_command, enable_shell=True)

        if self.alert and fdict["status"] == "DIS" and fdict["percentage"] <= self.alert_percentage:
            title, body = formatp(self.alert_format_title, **fdict), formatp(self.alert_format_body, **fdict)
            if not self.notification:
                self.notification = DesktopNotification(
                    title=title,
                    body=body,
                    icon="battery-caution",
                    urgency=2,
                    timeout=self.alert_timeout,
                )
                self.notification.display()
            else:
                self.notification.update(title=title,
                                         body=body)

        fdict["status"] = self.status[fdict["status"]]

        self.data = fdict
        self.output = {
            "full_text": formatp(self.format, **fdict),
            "instance": self.battery_ident,
            "urgent": urgent,
            "color": color,
        }