{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Tesla.Car.Command (
Time(..), mkTime, fromTime,
Percent(..), mkPercent,
runCmd, runCmd', CommandResponse, Car,
(.=),
mkCommand, mkCommands, mkNamedCommands) where
import Control.Lens hiding ((.=))
import Control.Monad.IO.Class (MonadIO (..))
import Data.Aeson
import Data.Aeson.Lens (_Bool, _String, key)
import Data.Finite (Finite, getFinite, modulo, packFinite)
import Data.Text (Text)
import GHC.Read
import GHC.TypeNats
import Language.Haskell.TH
import Network.Wreq.Types (FormValue (..))
import Text.Casing (fromSnake, toCamel)
import Data.Aeson.Types (Pair)
import Tesla.Car
import Tesla.Internal.HTTP
import qualified Text.ParserCombinators.ReadPrec as TextParser
type CommandResponse = Either Text ()
newtype Time = Time (Finite 1440)
instance Show Time where show :: Time -> String
show (Time Finite 1440
t) = forall a. Show a => a -> String
show (forall a. Integral a => a -> Integer
toInteger Finite 1440
t)
instance Num Time where
fromInteger :: Integer -> Time
fromInteger = Finite 1440 -> Time
Time forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Integer -> Finite n
modulo
abs :: Time -> Time
abs = forall a. a -> a
id
signum :: Time -> Time
signum = forall a b. a -> b -> a
const Time
1
(Time Finite 1440
f1) * :: Time -> Time -> Time
* (Time Finite 1440
f2) = Finite 1440 -> Time
Time (Finite 1440
f1 forall a. Num a => a -> a -> a
* Finite 1440
f2)
(Time Finite 1440
f1) + :: Time -> Time -> Time
+ (Time Finite 1440
f2) = Finite 1440 -> Time
Time (Finite 1440
f1 forall a. Num a => a -> a -> a
+ Finite 1440
f2)
(Time Finite 1440
f1) - :: Time -> Time -> Time
- (Time Finite 1440
f2) = Finite 1440 -> Time
Time (Finite 1440
f1 forall a. Num a => a -> a -> a
- Finite 1440
f2)
instance FormValue Time where
renderFormValue :: Time -> ByteString
renderFormValue (Time Finite 1440
x) = forall a. FormValue a => a -> ByteString
renderFormValue (forall (n :: Nat). Finite n -> Integer
getFinite Finite 1440
x)
instance ToJSON Time where
toJSON :: Time -> Value
toJSON (Time Finite 1440
x) = forall a. ToJSON a => a -> Value
toJSON (forall (n :: Nat). Finite n -> Integer
getFinite Finite 1440
x)
mkTime :: Finite 24 -> Finite 60 -> Time
mkTime :: Finite 24 -> Finite 60 -> Time
mkTime Finite 24
h Finite 60
m = Finite 1440 -> Time
Time forall a b. (a -> b) -> a -> b
$ forall (n :: Nat). KnownNat n => Integer -> Finite n
modulo (forall a. Integral a => a -> Integer
toInteger Finite 24
h forall a. Num a => a -> a -> a
* Integer
60 forall a. Num a => a -> a -> a
+ forall a. Integral a => a -> Integer
toInteger Finite 60
m)
fromTime :: Time -> (Finite 24, Finite 60)
fromTime :: Time -> (Finite 24, Finite 60)
fromTime (Time Finite 1440
t) = forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap forall (m :: Nat) (n :: Nat).
(KnownNat m, KnownNat n, n <= m) =>
Finite m -> Finite n
f forall (m :: Nat) (n :: Nat).
(KnownNat m, KnownNat n, n <= m) =>
Finite m -> Finite n
f (Finite 1440
t forall a. Integral a => a -> a -> (a, a)
`divMod` Finite 1440
60)
where
f :: forall m n. (KnownNat m, KnownNat n, n <= m) => Finite m -> Finite n
f :: forall (m :: Nat) (n :: Nat).
(KnownNat m, KnownNat n, n <= m) =>
Finite m -> Finite n
f = forall (n :: Nat). KnownNat n => Integer -> Finite n
modulo forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> Integer
toInteger
newtype Percent = Percent (Finite 101)
instance Read Percent where
readPrec :: ReadPrec Percent
readPrec = forall a. Int -> ReadPrec a -> ReadPrec a
TextParser.prec Int
10 (forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. ReadPrec a
TextParser.pfail forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Integral n => n -> Maybe Percent
mkPercent @Int forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. Read a => ReadPrec a
readPrec)
instance Show Percent where show :: Percent -> String
show (Percent Finite 101
t) = forall a. Show a => a -> String
show (forall a. Integral a => a -> Integer
toInteger Finite 101
t)
mkPercent :: Integral n => n -> Maybe Percent
mkPercent :: forall n. Integral n => n -> Maybe Percent
mkPercent = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Finite 101 -> Percent
Percent forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat). KnownNat n => Integer -> Maybe (Finite n)
packFinite forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> Integer
toInteger
instance ToJSON Percent where
toJSON :: Percent -> Value
toJSON (Percent Finite 101
x) = forall a. ToJSON a => a -> Value
toJSON (forall (n :: Nat). Finite n -> Integer
getFinite Finite 101
x)
runCmd :: MonadIO m => String -> [Pair] -> Car m CommandResponse
runCmd :: forall (m :: * -> *).
MonadIO m =>
String -> [Pair] -> Car m CommandResponse
runCmd String
cmd [Pair]
p = do
Text
v <- forall (m :: * -> *). MonadReader CarEnv m => m Text
currentVehicleID
Value
j :: Value <- forall (m :: * -> *) j a.
(HasTeslaAuth m, FromJSON j, Postable a, MonadIO m) =>
String -> a -> m j
jpostAuth (Text -> ShowS
vehicleURL Text
v forall a b. (a -> b) -> a -> b
$ String
"command/" forall a. Semigroup a => a -> a -> a
<> String
cmd) ([Pair] -> Value
object [Pair]
p)
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ case Value
j forall s a. s -> Getting (First a) s a -> Maybe a
^? forall t. AsValue t => Key -> Traversal' t Value
key Key
"response" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. AsValue t => Key -> Traversal' t Value
key Key
"result" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. AsValue t => Prism' t Bool
_Bool of
Just Bool
True -> forall a b. b -> Either a b
Right ()
Maybe Bool
_ -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ Value
j forall s a. s -> Getting a s a -> a
^. forall t. AsValue t => Key -> Traversal' t Value
key Key
"response" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. AsValue t => Key -> Traversal' t Value
key Key
"reason" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. AsValue t => Prism' t Text
_String
runCmd' :: MonadIO m => String -> Car m CommandResponse
runCmd' :: forall (m :: * -> *). MonadIO m => String -> Car m CommandResponse
runCmd' = (forall (m :: * -> *).
MonadIO m =>
String -> [Pair] -> Car m CommandResponse
`runCmd` [])
instance FormValue Bool where
renderFormValue :: Bool -> ByteString
renderFormValue Bool
True = ByteString
"true"
renderFormValue Bool
False = ByteString
"false"
mkCommand :: String -> String -> Q [Dec]
mkCommand :: String -> String -> Q [Dec]
mkCommand String
s String
u = do
let m :: Name
m = String -> Name
mkName String
"m"
forall (f :: * -> *) a. Applicative f => a -> f a
pure [
Name -> Type -> Dec
SigD (String -> Name
mkName String
s) ([TyVarBndr Specificity] -> Cxt -> Type -> Type
ForallT [forall flag. Name -> flag -> TyVarBndr flag
PlainTV Name
m Specificity
inferredSpec] [Type -> Type -> Type
AppT (Name -> Type
ConT (String -> Name
mkName String
"MonadIO")) (Name -> Type
VarT Name
m)]
(Type -> Type -> Type
AppT (Type -> Type -> Type
AppT (Name -> Type
ConT (String -> Name
mkName String
"Car")) (Name -> Type
VarT Name
m)) (Name -> Type
ConT (String -> Name
mkName String
"CommandResponse")))),
Name -> [Clause] -> Dec
FunD (String -> Name
mkName String
s) [[Pat] -> Body -> [Dec] -> Clause
Clause [] (Exp -> Body
NormalB Exp
expr) []]]
where expr :: Exp
expr = [Pat] -> Exp -> Exp
LamE [] (Exp -> Exp -> Exp
AppE (Name -> Exp
VarE (String -> Name
mkName String
"runCmd'")) (Lit -> Exp
LitE (String -> Lit
StringL String
u)))
cmapM :: (Monoid b, Applicative f) => (a -> f b) -> [a] -> f b
cmapM :: forall b (f :: * -> *) a.
(Monoid b, Applicative f) =>
(a -> f b) -> [a] -> f b
cmapM a -> f b
f [a]
xs = forall a. Monoid a => [a] -> a
mconcat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse a -> f b
f [a]
xs
mkCommands :: [String] -> Q [Dec]
mkCommands :: [String] -> Q [Dec]
mkCommands [String]
targets = forall b (f :: * -> *) a.
(Monoid b, Applicative f) =>
(a -> f b) -> [a] -> f b
cmapM String -> Q [Dec]
easyCMD [String]
targets
where
prefix :: String
prefix = [String] -> String
commonPrefix [String]
targets
easyCMD :: String -> Q [Dec]
easyCMD :: String -> Q [Dec]
easyCMD String
target = do
let s :: String
s = forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix) String
target
mn :: String
mn = (Identifier String -> String
toCamel forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Identifier String
fromSnake) String
s
String -> String -> Q [Dec]
mkCommand String
mn String
target
commonPrefix :: [String] -> String
commonPrefix = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\(Char
x:String
xs) -> forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (forall a. Eq a => a -> a -> Bool
== Char
x) String
xs) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {f :: * -> *} {a}. (Foldable f, Functor f) => f [a] -> [f a]
tp
where
tp :: f [a] -> [f a]
tp f [a]
xs
| forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any forall (t :: * -> *) a. Foldable t => t a -> Bool
null f [a]
xs = []
| Bool
otherwise = (forall a. [a] -> a
head forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f [a]
xs) forall a. a -> [a] -> [a]
: f [a] -> [f a]
tp (forall a. [a] -> [a]
tail forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f [a]
xs)
mkNamedCommands :: [(String, String)] -> Q [Dec]
mkNamedCommands :: [(String, String)] -> Q [Dec]
mkNamedCommands = forall b (f :: * -> *) a.
(Monoid b, Applicative f) =>
(a -> f b) -> [a] -> f b
cmapM (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry String -> String -> Q [Dec]
mkCommand)