diff options
| author | Michal Zielonka <michal.zielonka.8001@gmail.com> | 2021-10-07 23:25:09 +0200 | 
|---|---|---|
| committer | Michal Zielonka <michal.zielonka.8001@gmail.com> | 2021-10-08 11:11:11 +0200 | 
| commit | b99a8a6833a1b38882b463fd72784cd6d6f91d9e (patch) | |
| tree | 9537dcfe5eff2108937bf9a2160a5f15a7a266e5 /src/Xmobar/Plugins/Monitors/Batt | |
| parent | a845465fec735d9818a61d078337653b5293da5c (diff) | |
| download | xmobar-b99a8a6833a1b38882b463fd72784cd6d6f91d9e.tar.gz xmobar-b99a8a6833a1b38882b463fd72784cd6d6f91d9e.tar.bz2 | |
try to reorganize modules per os
We should make better split os specify code for FreeBSD and Linux.
Idea comes from @liskin.
Diffstat (limited to 'src/Xmobar/Plugins/Monitors/Batt')
| -rw-r--r-- | src/Xmobar/Plugins/Monitors/Batt/Common.hs | 57 | ||||
| -rw-r--r-- | src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs | 46 | ||||
| -rw-r--r-- | src/Xmobar/Plugins/Monitors/Batt/Linux.hs | 130 | 
3 files changed, 233 insertions, 0 deletions
| diff --git a/src/Xmobar/Plugins/Monitors/Batt/Common.hs b/src/Xmobar/Plugins/Monitors/Batt/Common.hs new file mode 100644 index 0000000..3262b78 --- /dev/null +++ b/src/Xmobar/Plugins/Monitors/Batt/Common.hs @@ -0,0 +1,57 @@ +----------------------------------------------------------------------------- +-- | +-- Module      :  Plugins.Monitors.Batt.Common +-- Copyright   :  (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega +--                (c) 2010 Andrea Rossato, Petr Rockai +-- License     :  BSD-style (see LICENSE) +-- +-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org> +-- Stability   :  unstable +-- Portability :  unportable +-- +-- A battery monitor for Xmobar +-- +----------------------------------------------------------------------------- + +module Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..) +                                           , Result(..) +                                           , Status(..) +                                           , maybeAlert) where + +import System.Process (system) +import Control.Monad (unless, void) +import Xmobar.Plugins.Monitors.Common + +data Status = Charging | Discharging | Full | Idle | Unknown deriving (Read, Eq) +-- Result perc watts time-seconds Status +data Result = Result Float Float Float Status | NA + +data BattOpts = BattOpts +  { onString :: String +  , offString :: String +  , idleString :: String +  , posColor :: Maybe String +  , lowWColor :: Maybe String +  , mediumWColor :: Maybe String +  , highWColor :: Maybe String +  , lowThreshold :: Float +  , highThreshold :: Float +  , onLowAction :: Maybe String +  , actionThreshold :: Float +  , onlineFile :: FilePath +  , scale :: Float +  , onIconPattern :: Maybe IconPattern +  , offIconPattern :: Maybe IconPattern +  , idleIconPattern :: Maybe IconPattern +  , lowString :: String +  , mediumString :: String +  , highString :: String +  , incPerc :: Bool +  } + +maybeAlert :: BattOpts -> Float -> IO () +maybeAlert opts left = +  case onLowAction opts of +    Nothing -> return () +    Just x -> unless (isNaN left || actionThreshold opts < 100 * left) +                $ void $ system x diff --git a/src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs b/src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs new file mode 100644 index 0000000..2bb8618 --- /dev/null +++ b/src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs @@ -0,0 +1,46 @@ +----------------------------------------------------------------------------- +-- | +-- Module      :  Plugins.Monitors.Batt.FreeBSD +-- Copyright   :  (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega +--                (c) 2010 Andrea Rossato, Petr Rockai +-- License     :  BSD-style (see LICENSE) +-- +-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org> +-- Stability   :  unstable +-- Portability :  unportable +-- +-- A battery monitor for Xmobar +-- +----------------------------------------------------------------------------- + +module Xmobar.Plugins.Monitors.Batt.FreeBSD (readBatteries) where + +import Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..) +                                           , Result(..) +                                           , Status(..) +                                           , maybeAlert) + +import Control.Monad (unless) +import System.BSD.Sysctl (sysctlReadInt) + +battStatus :: Int -> Status +battStatus x +  | x == 1 = Discharging +  | x == 2 = Charging +  | otherwise = Unknown + +readBatteries :: BattOpts -> [String] -> IO Result +readBatteries opts _ = do +  lf <- sysctlReadInt "hw.acpi.battery.life" +  rt <- sysctlReadInt "hw.acpi.battery.rate" +  tm <- sysctlReadInt "hw.acpi.battery.time" +  st <- sysctlReadInt "hw.acpi.battery.state" +  acline <- sysctlReadInt "hw.acpi.acline" +  let p = fromIntegral lf / 100 +      w = fromIntegral rt +      t = fromIntegral tm * 60 +      ac = acline == 1 +      -- battery full when rate is 0 and on ac. +      sts = if w == 0 && ac then Full else battStatus $ fromIntegral st +  unless ac (maybeAlert opts p) +  return (Result p w t sts) diff --git a/src/Xmobar/Plugins/Monitors/Batt/Linux.hs b/src/Xmobar/Plugins/Monitors/Batt/Linux.hs new file mode 100644 index 0000000..454e7e9 --- /dev/null +++ b/src/Xmobar/Plugins/Monitors/Batt/Linux.hs @@ -0,0 +1,130 @@ +----------------------------------------------------------------------------- +-- | +-- Module      :  Plugins.Monitors.Batt.Linux +-- Copyright   :  (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega +--                (c) 2010 Andrea Rossato, Petr Rockai +-- License     :  BSD-style (see LICENSE) +-- +-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org> +-- Stability   :  unstable +-- Portability :  unportable +-- +-- A battery monitor for Xmobar +-- +----------------------------------------------------------------------------- + +module Xmobar.Plugins.Monitors.Batt.Linux (readBatteries) where + +import Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..) +                                           , Result(..) +                                           , Status(..) +                                           , maybeAlert) + +import Control.Monad (unless) +import Control.Exception (SomeException, handle) +import System.FilePath ((</>)) +import System.IO (IOMode(ReadMode), hGetLine, withFile) +import System.Posix.Files (fileExist) +import Data.List (sort, sortBy, group) +import Data.Maybe (fromMaybe) +import Data.Ord (comparing) +import Text.Read (readMaybe) + +data Files = Files +  { fFull :: String +  , fNow :: String +  , fVoltage :: String +  , fCurrent :: String +  , fStatus :: String +  , isCurrent :: Bool +  } | NoFiles deriving Eq + +data Battery = Battery +  { full :: !Float +  , now :: !Float +  , power :: !Float +  , status :: !String +  } + +sysDir :: FilePath +sysDir = "/sys/class/power_supply" + +safeFileExist :: String -> String -> IO Bool +safeFileExist d f = handle noErrors $ fileExist (d </> f) +  where noErrors = const (return False) :: SomeException -> IO Bool + +batteryFiles :: String -> IO Files +batteryFiles bat = +  do is_charge <- exists "charge_now" +     is_energy <- if is_charge then return False else exists "energy_now" +     is_power <- exists "power_now" +     plain <- exists (if is_charge then "charge_full" else "energy_full") +     let cf = if is_power then "power_now" else "current_now" +         sf = if plain then "" else "_design" +     return $ case (is_charge, is_energy) of +       (True, _) -> files "charge" cf sf is_power +       (_, True) -> files "energy" cf sf is_power +       _ -> NoFiles +  where prefix = sysDir </> bat +        exists = safeFileExist prefix +        files ch cf sf ip = Files { fFull = prefix </> ch ++ "_full" ++ sf +                                  , fNow = prefix </> ch ++ "_now" +                                  , fCurrent = prefix </> cf +                                  , fVoltage = prefix </> "voltage_now" +                                  , fStatus = prefix </> "status" +                                  , isCurrent = not ip} + +haveAc :: FilePath -> IO Bool +haveAc f = +  handle onError $ withFile (sysDir </> f) ReadMode (fmap (== "1") . hGetLine) +  where onError = const (return False) :: SomeException -> IO Bool + +readBattery :: Float -> Files -> IO Battery +readBattery _ NoFiles = return $ Battery 0 0 0 "Unknown" +readBattery sc files = +    do a <- grab $ fFull files +       b <- grab $ fNow files +       d <- grab $ fCurrent files +       s <- grabs $ fStatus files +       let sc' = if isCurrent files then sc / 10 else sc +           a' = max a b -- sometimes the reported max charge is lower than +       return $ Battery (3600 * a' / sc') -- wattseconds +                        (3600 * b / sc') -- wattseconds +                        (abs d / sc') -- watts +                        s -- string: Discharging/Charging/Full +    where grab f = handle onError $ withFile f ReadMode (fmap read . hGetLine) +          onError = const (return (-1)) :: SomeException -> IO Float +          grabs f = handle onError' $ withFile f ReadMode hGetLine +          onError' = const (return "Unknown") :: SomeException -> IO String + +-- sortOn is only available starting at ghc 7.10 +sortOn :: Ord b => (a -> b) -> [a] -> [a] +sortOn f = +  map snd . sortBy (comparing fst) . map (\x -> let y = f x in y `seq` (y, x)) + +mostCommonDef :: Eq a => a -> [a] -> a +mostCommonDef x xs = head $ last $ [x] : sortOn length (group xs) + +readBatteries :: BattOpts -> [String] -> IO Result +readBatteries opts bfs = +    do bfs' <- mapM batteryFiles bfs +       let bfs'' = filter (/= NoFiles) bfs' +       bats <- mapM (readBattery (scale opts)) (take 3 bfs'') +       ac <- haveAc (onlineFile opts) +       let sign = if ac then 1 else -1 +           ft = sum (map full bats) +           left = if ft > 0 then sum (map now bats) / ft else 0 +           watts = sign * sum (map power bats) +           time = if watts == 0 then 0 else max 0 (sum $ map time' bats) +           mwatts = if watts == 0 then 1 else sign * watts +           time' b = (if ac then full b - now b else now b) / mwatts +           statuses :: [Status] +           statuses = map (fromMaybe Unknown . readMaybe) +                          (sort (map status bats)) +           acst = mostCommonDef Unknown $ filter (Unknown/=) statuses +           racst | acst /= Unknown = acst +                 | time == 0 = Idle +                 | ac = Charging +                 | otherwise = Discharging +       unless ac (maybeAlert opts left) +       return $ if isNaN left then NA else Result left watts time racst | 
