{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
module Tesla
( authenticate, refreshAuth, AuthResponse(..),
Product(..), vehicleName, vehicleID, energyID, _ProductVehicle, _ProductEnergy, _ProductPowerWall,
VehicleID, vehicles, products,
EnergyID, energyIDs,
fromToken, authOpts, baseURL,
decodeProducts
) where
import Control.Lens
import Control.Monad.IO.Class (MonadIO (..))
import Data.Aeson (Value (..))
import Data.Aeson.Lens (key, _Array, _Integer, _String)
import Data.Foldable (asum)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (catMaybes)
import Data.Text (Text)
import Network.Wreq (FormParam (..))
import Tesla.Auth
import Tesla.Internal.HTTP
baseURL :: String
baseURL = "https://owner-api.teslamotors.com/"
authURL :: String
authURL = baseURL <> "oauth/token"
authRefreshURL :: String
authRefreshURL = baseURL <> "oauth/token"
productsURL :: String
productsURL = baseURL <> "api/1/products"
authenticate :: AuthInfo -> IO AuthResponse
authenticate AuthInfo{..} =
jpostWith defOpts authURL ["grant_type" := ("password" :: String),
"client_id" := _clientID,
"client_secret" := _clientSecret,
"email" := _email,
"password" := _password]
refreshAuth :: AuthInfo -> AuthResponse -> IO AuthResponse
refreshAuth AuthInfo{..} AuthResponse{..} =
jpostWith defOpts authRefreshURL ["grant_type" := ("refresh_token" :: String),
"client_id" := _clientID,
"client_secret" := _clientSecret,
"refresh_token" := _refresh_token]
type VehicleID = Text
type EnergyID = Integer
data Product = ProductVehicle { _vehicleName :: Text, _vehicleID :: VehicleID }
| ProductEnergy { _energyID :: EnergyID }
| ProductPowerWall deriving (Show, Read, Eq)
makePrisms ''Product
makeLenses ''Product
decodeProducts :: Value -> [Product]
decodeProducts = catMaybes . toListOf (key "response" . _Array . folded . to prod)
where
prod o = asum [ prodCar, prodSolar, Nothing ]
where
prodCar = ProductVehicle <$> (o ^? key "display_name" . _String) <*> (o ^? key "id_s" . _String)
prodSolar = ProductEnergy <$> (o ^? key "energy_site_id" . _Integer)
products :: MonadIO m => AuthInfo -> m [Product]
products ai = decodeProducts <$> jgetWith (authOpts ai) productsURL
vehicles :: MonadIO m => AuthInfo -> m (Map Text Text)
vehicles = fmap (Map.fromList . toListOf (folded . _ProductVehicle)) . products
energyIDs :: MonadIO m => AuthInfo -> m [EnergyID]
energyIDs = fmap (toListOf $ folded . _ProductEnergy) . products