Tracing
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{ mkDerivation, aeson, annotated-exception, async, base, bytestring
|
{ mkDerivation, aeson, annotated-exception, async, base, bytestring
|
||||||
, hedgehog, hspec, hspec-hedgehog, lens, lens-aeson, lib, network
|
, hedgehog, hspec, hspec-hedgehog, lens, lens-aeson, lib, network
|
||||||
, stm, text, time, websockets
|
, stm, text, time, uuid, websockets
|
||||||
}:
|
}:
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
pname = "home-assistant-controller";
|
pname = "home-assistant-controller";
|
||||||
@@ -10,7 +10,7 @@ mkDerivation {
|
|||||||
isExecutable = true;
|
isExecutable = true;
|
||||||
libraryHaskellDepends = [
|
libraryHaskellDepends = [
|
||||||
aeson annotated-exception async base bytestring lens lens-aeson
|
aeson annotated-exception async base bytestring lens lens-aeson
|
||||||
network stm text time websockets
|
network stm text time uuid websockets
|
||||||
];
|
];
|
||||||
executableHaskellDepends = [ base ];
|
executableHaskellDepends = [ base ];
|
||||||
testHaskellDepends = [
|
testHaskellDepends = [
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ library
|
|||||||
, stm
|
, stm
|
||||||
, async
|
, async
|
||||||
, annotated-exception
|
, annotated-exception
|
||||||
|
, uuid
|
||||||
|
|
||||||
-- Directories containing source files.
|
-- Directories containing source files.
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
|
|||||||
+15
-7
@@ -8,9 +8,9 @@ module AFRP
|
|||||||
, events
|
, events
|
||||||
, switch
|
, switch
|
||||||
, preMapAccum
|
, preMapAccum
|
||||||
, preMapAccumUTCTime
|
, preMapAccumRequest
|
||||||
, mapAccum
|
, mapAccum
|
||||||
, mapAccumUTCTime
|
, mapAccumRequest
|
||||||
, changes
|
, changes
|
||||||
, whenA
|
, whenA
|
||||||
, filterA
|
, filterA
|
||||||
@@ -18,6 +18,7 @@ module AFRP
|
|||||||
, (>>|)
|
, (>>|)
|
||||||
, toEvent
|
, toEvent
|
||||||
, lMerge
|
, lMerge
|
||||||
|
, Request(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Category (Category(..), (>>>))
|
import Control.Category (Category(..), (>>>))
|
||||||
@@ -27,9 +28,16 @@ import Data.Time (UTCTime)
|
|||||||
import Control.Monad.Fix (MonadFix (mfix))
|
import Control.Monad.Fix (MonadFix (mfix))
|
||||||
import Data.Either (fromLeft)
|
import Data.Either (fromLeft)
|
||||||
import Data.Bool (bool)
|
import Data.Bool (bool)
|
||||||
|
import Data.UUID (UUID)
|
||||||
|
|
||||||
|
data Request = Request
|
||||||
|
{ requestTime :: !UTCTime
|
||||||
|
, requestTraceId :: !UUID
|
||||||
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
newtype Mealy eff a b = Mealy
|
newtype Mealy eff a b = Mealy
|
||||||
{ runMealy :: forall m. MonadFix m => (forall x. eff x -> m x) -> UTCTime -> a -> m (b, Mealy eff a b) }
|
{ runMealy :: forall m. MonadFix m => (forall x. eff x -> m x) -> Request -> a -> m (b, Mealy eff a b) }
|
||||||
|
|
||||||
eff :: (a -> eff b) -> Mealy eff a b
|
eff :: (a -> eff b) -> Mealy eff a b
|
||||||
eff f = Mealy $ \nt _ x ->
|
eff f = Mealy $ \nt _ x ->
|
||||||
@@ -101,8 +109,8 @@ preMapAccum f x extract = go x
|
|||||||
let next = f b a
|
let next = f b a
|
||||||
in pure (extract b, go next)
|
in pure (extract b, go next)
|
||||||
|
|
||||||
preMapAccumUTCTime :: (UTCTime -> x -> a -> x) -> x -> (x -> b) -> Mealy eff a b
|
preMapAccumRequest :: (Request -> x -> a -> x) -> x -> (x -> b) -> Mealy eff a b
|
||||||
preMapAccumUTCTime f x extract = go x
|
preMapAccumRequest f x extract = go x
|
||||||
where
|
where
|
||||||
go b = Mealy $ \_ t a ->
|
go b = Mealy $ \_ t a ->
|
||||||
let next = f t b a
|
let next = f t b a
|
||||||
@@ -115,8 +123,8 @@ mapAccum f x extract = go x
|
|||||||
let next = f b a
|
let next = f b a
|
||||||
in pure (extract next, go next)
|
in pure (extract next, go next)
|
||||||
|
|
||||||
mapAccumUTCTime :: (UTCTime -> x -> a -> x) -> x -> (x -> b) -> Mealy eff a b
|
mapAccumRequest :: (Request -> x -> a -> x) -> x -> (x -> b) -> Mealy eff a b
|
||||||
mapAccumUTCTime f x extract = go x
|
mapAccumRequest f x extract = go x
|
||||||
where
|
where
|
||||||
go b = Mealy $ \_ t a ->
|
go b = Mealy $ \_ t a ->
|
||||||
let next = f t b a
|
let next = f t b a
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ module HomeAssistant.Controller
|
|||||||
, Presence(..)
|
, Presence(..)
|
||||||
, presence
|
, presence
|
||||||
, debug
|
, debug
|
||||||
|
, traceEvent
|
||||||
, switch
|
, switch
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import AFRP (Mealy, eff, Event(..), hold, events, changes, filterA, (>>|), toEvent)
|
import AFRP (Mealy (..), eff, Event(..), hold, events, changes, filterA, (>>|), toEvent, Request)
|
||||||
import Control.Arrow (Arrow(..), returnA)
|
import Control.Arrow (Arrow(..), returnA)
|
||||||
import Control.Category ((>>>))
|
import Control.Category ((>>>))
|
||||||
import Data.Aeson (Value)
|
import Data.Aeson (Value)
|
||||||
@@ -49,6 +50,7 @@ data Service = Service
|
|||||||
data HASSEff a where
|
data HASSEff a where
|
||||||
CallService :: Service -> HASSEff ()
|
CallService :: Service -> HASSEff ()
|
||||||
Debug :: Show a => a -> HASSEff ()
|
Debug :: Show a => a -> HASSEff ()
|
||||||
|
Trace :: Show a => Request -> a -> HASSEff ()
|
||||||
|
|
||||||
type HASS a b = Mealy HASSEff a b
|
type HASS a b = Mealy HASSEff a b
|
||||||
|
|
||||||
@@ -60,6 +62,11 @@ debug = proc x -> do
|
|||||||
eff Debug -< x
|
eff Debug -< x
|
||||||
returnA -< x
|
returnA -< x
|
||||||
|
|
||||||
|
traceEvent :: Show a => HASS (Event a) (Event a)
|
||||||
|
traceEvent = Mealy $ \nt req -> \case
|
||||||
|
Event a -> nt (Trace req a) >>= \() -> pure (Event a, traceEvent)
|
||||||
|
Tick -> pure (Tick, traceEvent)
|
||||||
|
|
||||||
ruuviTemperatures :: Mealy eff (Event Value) Double
|
ruuviTemperatures :: Mealy eff (Event Value) Double
|
||||||
ruuviTemperatures = entityRead @Double "sensor.ruuvitag_b168_temperature" >>> hold 0
|
ruuviTemperatures = entityRead @Double "sensor.ruuvitag_b168_temperature" >>> hold 0
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ data IkeaQuickButton
|
|||||||
| ShortClickOff
|
| ShortClickOff
|
||||||
| DoubleClickOff
|
| DoubleClickOff
|
||||||
| LongClickOff
|
| LongClickOff
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
|
||||||
toIkeaQuickButton :: T.Text -> Maybe IkeaQuickButton
|
toIkeaQuickButton :: T.Text -> Maybe IkeaQuickButton
|
||||||
@@ -74,25 +75,26 @@ ikeaQuickButton entityId =
|
|||||||
>>| arr (maybe (Left ()) Right . eventType)
|
>>| arr (maybe (Left ()) Right . eventType)
|
||||||
>>> toEvent
|
>>> toEvent
|
||||||
where
|
where
|
||||||
eventType v = v ^? key "event" . key "data" . key "new_state" . key "state" . _String . to toIkeaQuickButton . traversed
|
eventType v = v ^? key "event" . key "data" . key "new_state" . key "attributes" . key "event_type" . _String . to toIkeaQuickButton . traversed
|
||||||
|
|
||||||
|
|
||||||
data BedroomControls
|
data BedroomControls
|
||||||
= Masse IkeaQuickButton
|
= Masse IkeaQuickButton
|
||||||
| Enishen IkeaQuickButton
|
| Enishen IkeaQuickButton
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
|
||||||
bedroomButton :: HASS (Event Value) (Event BedroomControls)
|
bedroomButton :: HASS (Event Value) (Event BedroomControls)
|
||||||
bedroomButton = (masseButton &&& enishenButton) >>> arr (uncurry lMerge)
|
bedroomButton = (masseButton &&& enishenButton) >>> arr (uncurry lMerge)
|
||||||
where
|
where
|
||||||
masseButton = fmap Masse <$> ikeaQuickButton "event.bedroom_quick_remote_masse_action"
|
masseButton = fmap Masse <$> ikeaQuickButton "event.bedroom_quick_remote_masse_action"
|
||||||
enishenButton = fmap Enishen <$> ikeaQuickButton "event.bedroom_quick_remote_jemina_action"
|
enishenButton = fmap Enishen <$> ikeaQuickButton "event.bedroom_quick_jemina_action"
|
||||||
|
|
||||||
bedroomButtonController :: HASS (Event Value) ()
|
bedroomButtonController :: HASS (Event Value) ()
|
||||||
bedroomButtonController = proc x -> do
|
bedroomButtonController = proc x -> do
|
||||||
ev <- bedroomButton -< x
|
ev <- bedroomButton >>> traceEvent -< x
|
||||||
case ev of
|
case ev of
|
||||||
Event (Masse ShortClickOn) -> callService (activateScene "scene.makuuhuone_masse") -< ()
|
Event (Masse ShortClickOn) -> callService (activateScene "scene.makuuhuone_masse") -< () -- this should be on release
|
||||||
Event (Masse DoubleClickOn) -> callService (activateScene "scene.makuuhuone_keski") -< ()
|
Event (Masse DoubleClickOn) -> callService (activateScene "scene.makuuhuone_keski") -< ()
|
||||||
Event (Masse LongClickOn) -> callService (activateScene "scene.makuuhuone_kirkas") -< ()
|
Event (Masse LongClickOn) -> callService (activateScene "scene.makuuhuone_kirkas") -< ()
|
||||||
Event (Enishen ShortClickOn) -> callService (activateScene "scene.makuuhuone_jemina") -< ()
|
Event (Enishen ShortClickOn) -> callService (activateScene "scene.makuuhuone_jemina") -< ()
|
||||||
@@ -114,4 +116,4 @@ bedroomDrawerController = proc x -> do
|
|||||||
Event Closed -> callService (switch [entity] False) -< ()
|
Event Closed -> callService (switch [entity] False) -< ()
|
||||||
_ -> returnA -< ()
|
_ -> returnA -< ()
|
||||||
where
|
where
|
||||||
entity = "switch.bedroom_drawer_light_masse"
|
entity = "bedroom_drawer_light_masse"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module HomeAssistant.Runtime
|
|||||||
, runController
|
, runController
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import AFRP (Event (..), Mealy (..))
|
import AFRP (Event (..), Mealy (..), Request (..))
|
||||||
import Control.Concurrent.Async (async, waitAny)
|
import Control.Concurrent.Async (async, waitAny)
|
||||||
import Control.Concurrent.STM (atomically, dupTChan, readTChan)
|
import Control.Concurrent.STM (atomically, dupTChan, readTChan)
|
||||||
import Data.Aeson (Value)
|
import Data.Aeson (Value)
|
||||||
@@ -27,11 +27,13 @@ import HomeAssistant.Runtime.Supervisor (defaultBackoff, supervised)
|
|||||||
import Network.Socket (withSocketsDo)
|
import Network.Socket (withSocketsDo)
|
||||||
import System.Environment (getEnv)
|
import System.Environment (getEnv)
|
||||||
import HomeAssistant.Controller.Bedroom (bedroomPresenceController, bedroomButtonController, bedroomDrawerController)
|
import HomeAssistant.Controller.Bedroom (bedroomPresenceController, bedroomButtonController, bedroomDrawerController)
|
||||||
|
import Data.UUID (UUID)
|
||||||
|
import qualified Data.UUID.V4 as UUID.V4
|
||||||
|
|
||||||
step :: (forall x. eff x -> IO x) -> Mealy eff a b -> a -> IO (b, Mealy eff a b)
|
step :: (forall x. eff x -> IO x) -> UUID -> Mealy eff a b -> a -> IO (b, Mealy eff a b)
|
||||||
step nt (Mealy f) a = do
|
step nt trace (Mealy f) a = do
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
f nt now a
|
f nt (Request now trace) a
|
||||||
|
|
||||||
data Controller = forall b. Controller T.Text (HASS (Event Value) b)
|
data Controller = forall b. Controller T.Text (HASS (Event Value) b)
|
||||||
|
|
||||||
@@ -52,8 +54,9 @@ runController bus (Controller _name machine) = do
|
|||||||
where
|
where
|
||||||
go inbound f = do
|
go inbound f = do
|
||||||
msg <- atomically (readTChan inbound)
|
msg <- atomically (readTChan inbound)
|
||||||
|
uuid <- UUID.V4.nextRandom
|
||||||
-- (_, f') <- step (channelHassEval bus) f (Event msg)
|
-- (_, f') <- step (channelHassEval bus) f (Event msg)
|
||||||
(_, f') <- step (dryRunHassEval (busGen bus)) f (Event msg)
|
(_, f') <- step (dryRunHassEval (busGen bus)) uuid f (Event msg)
|
||||||
go inbound f'
|
go inbound f'
|
||||||
|
|
||||||
defaultMain :: IO ()
|
defaultMain :: IO ()
|
||||||
@@ -74,3 +77,4 @@ dryRunHassEval gen = \case
|
|||||||
callId <- generateCallId gen
|
callId <- generateCallId gen
|
||||||
print (callId, x)
|
print (callId, x)
|
||||||
Debug x -> print x
|
Debug x -> print x
|
||||||
|
Trace req x -> print (req, x)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ channelHassEval :: Bus -> HASSEff a -> IO a
|
|||||||
channelHassEval bus = \case
|
channelHassEval bus = \case
|
||||||
CallService svc -> atomically $ writeTChan (busOutbound bus) svc
|
CallService svc -> atomically $ writeTChan (busOutbound bus) svc
|
||||||
Debug x -> print x
|
Debug x -> print x
|
||||||
|
Trace req x -> print (req, x)
|
||||||
|
|
||||||
newtype CallIdGen = CallIdGen { generateCallId :: IO Int }
|
newtype CallIdGen = CallIdGen { generateCallId :: IO Int }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user