summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Benjamin Barenblat <benjamin@barenblat.name>2016-06-01 22:14:18 -0400
committerGravatar Benjamin Barenblat <benjamin@barenblat.name>2016-06-01 22:14:18 -0400
commit90d8edafaa3a0756df8773f2a320ebfc23a7d8e3 (patch)
tree7cd39c2adcbf31f72a189bf861b377c812dc6f04 /src
Initial commitHEADmaster
Create a basic but functional power manager, as well as a systemd unit file.
Diffstat (limited to 'src')
-rw-r--r--src/Config.hs57
-rw-r--r--src/Main.hs42
-rw-r--r--src/Pandora.hs51
3 files changed, 150 insertions, 0 deletions
diff --git a/src/Config.hs b/src/Config.hs
new file mode 100644
index 0000000..b025106
--- /dev/null
+++ b/src/Config.hs
@@ -0,0 +1,57 @@
+-- Copyright 2016 Benjamin Barenblat
+--
+-- Licensed under the Apache License, Version 2.0 (the “License”); you may not
+-- use this file except in compliance with the License. You may obtain a copy
+-- of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
+-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-- License for the specific language governing permissions and limitations under
+-- the License.
+
+-- | Application configuration.
+
+module Config
+ ( Config(..)
+ , load
+ ) where
+
+import Control.Applicative ((<$>))
+import Data.Bifunctor (bimap)
+import qualified Data.ConfigFile as ConfigFile
+
+data Config = Config
+ { stopCapacity :: Int
+ -- ^ percentage charge required to enter the “fully charged” state
+ , stopCurrent :: Int
+ -- ^ maximum charge current (in microamperes, µA) to remain in the
+ -- “fully charged” state
+ , startCapacity :: Int
+ -- ^ percentage at or below which charging will begin
+ } deriving (Eq, Show)
+
+defaultConfig :: Config
+defaultConfig = Config
+ { stopCapacity = 99
+ , stopCurrent = 80000
+ , startCapacity = 95
+ }
+
+configFilePath :: FilePath
+configFilePath = "/etc/pndpowerd.conf"
+
+load :: IO (Either String Config)
+load =
+ bimap show parse <$> ConfigFile.readfile ConfigFile.emptyCP configFilePath
+
+parse :: ConfigFile.ConfigParser -> Config
+parse serialized =
+ let get field name = either (const $ field defaultConfig) id $
+ ConfigFile.get serialized "DEFAULT" name
+ in Config { stopCapacity = get stopCapacity "stopCapacity"
+ , stopCurrent = get stopCurrent "stopCurrent"
+ , startCapacity = get startCapacity "startCapacity"
+ }
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
index 0000000..6b015a2
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,42 @@
+-- Copyright 2016 Benjamin Barenblat
+--
+-- Licensed under the Apache License, Version 2.0 (the “License”); you may not
+-- use this file except in compliance with the License. You may obtain a copy
+-- of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
+-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-- License for the specific language governing permissions and limitations under
+-- the License.
+
+module Main where
+
+import Control.Applicative ((<$>))
+import Control.Concurrent (threadDelay)
+import Control.Monad (forever, when)
+import Data.Either.Utils (forceEither)
+import qualified Config
+import qualified Pandora
+
+main :: IO ()
+main = do
+ config <- forceEither <$> Config.load
+ forever $ do
+ percent <- Pandora.chargePercent
+ current <- Pandora.chargeCurrent
+ chargingEnabled <- Pandora.chargingEnabled
+ if chargingEnabled
+ && Config.stopCapacity config <= percent
+ && 0 < current
+ && current < Config.stopCurrent config
+ then Pandora.setCharging False
+ else when (not chargingEnabled
+ && percent <= Config.stopCapacity config) $
+ Pandora.setCharging True
+ threadDelay (secondsToMicroseconds 60)
+
+secondsToMicroseconds :: Int -> Int
+secondsToMicroseconds = (* 1000000)
diff --git a/src/Pandora.hs b/src/Pandora.hs
new file mode 100644
index 0000000..f8ea754
--- /dev/null
+++ b/src/Pandora.hs
@@ -0,0 +1,51 @@
+-- Copyright 2016 Benjamin Barenblat
+--
+-- Licensed under the Apache License, Version 2.0 (the “License”); you may not
+-- use this file except in compliance with the License. You may obtain a copy
+-- of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
+-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-- License for the specific language governing permissions and limitations under
+-- the License.
+
+module Pandora
+ ( chargePercent
+ , chargeCurrent
+ , chargingEnabled
+ , setCharging
+ ) where
+
+import Control.Applicative ((<$>))
+import System.FilePath ((</>))
+
+fuelGauge :: String
+fuelGauge = "/sys/class/power_supply/bq27500-0"
+
+acCharger :: String
+acCharger = "/sys/class/power_supply/twl4030_ac"
+
+chargePercent :: IO Int
+chargePercent = read <$> readFile (fuelGauge </> "capacity")
+
+-- | Determines the charge current in microamperes (µA).
+chargeCurrent :: IO Int
+chargeCurrent = read <$> readFile (fuelGauge </> "current_now")
+
+chargingEnabled :: IO Bool
+chargingEnabled = do
+ t <- readFile (acCharger </> "enable")
+ return $ case t of
+ "0\n" -> False
+ "1\n" -> True
+ _ -> error "no parse"
+
+setCharging :: Bool -> IO ()
+setCharging = writeFile (acCharger </> "enable") . showAsInt
+
+showAsInt :: Bool -> String
+showAsInt False = "0"
+showAsInt True = "1"