IKEA buttons
This commit is contained in:
+8
-1
@@ -17,6 +17,7 @@ module AFRP
|
|||||||
, thenA
|
, thenA
|
||||||
, (>>|)
|
, (>>|)
|
||||||
, toEvent
|
, toEvent
|
||||||
|
, lMerge
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Category (Category(..), (>>>))
|
import Control.Category (Category(..), (>>>))
|
||||||
@@ -142,7 +143,13 @@ thenA f g = f >>> arr Left ||| g
|
|||||||
(>>|) :: (ArrowChoice cat, Arrow cat) => cat a (Either b1 c) -> cat c (Either b1 b2) -> cat a (Either b1 b2)
|
(>>|) :: (ArrowChoice cat, Arrow cat) => cat a (Either b1 c) -> cat c (Either b1 b2) -> cat a (Either b1 b2)
|
||||||
(>>|) = thenA
|
(>>|) = thenA
|
||||||
|
|
||||||
infixl 1 >>|
|
infixl 2 >>|
|
||||||
|
|
||||||
toEvent :: Mealy eff (Either () a) (Event a)
|
toEvent :: Mealy eff (Either () a) (Event a)
|
||||||
toEvent = arr (either (const Tick) Event)
|
toEvent = arr (either (const Tick) Event)
|
||||||
|
|
||||||
|
|
||||||
|
lMerge :: Event a -> Event a -> Event a
|
||||||
|
lMerge Tick Tick = Tick
|
||||||
|
lMerge (Event a) _ = Event a
|
||||||
|
lMerge Tick (Event a) = Event a
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ module HomeAssistant.Controller
|
|||||||
, lightController
|
, lightController
|
||||||
, Presence(..)
|
, Presence(..)
|
||||||
, presence
|
, presence
|
||||||
|
, debug
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import AFRP (Mealy, eff, Event(..), hold, events, changes, filterA, (>>|), toEvent)
|
import AFRP (Mealy, eff, Event(..), hold, events, changes, filterA, (>>|), toEvent)
|
||||||
@@ -46,12 +47,18 @@ data Service = Service
|
|||||||
|
|
||||||
data HASSEff a where
|
data HASSEff a where
|
||||||
CallService :: Service -> HASSEff ()
|
CallService :: Service -> HASSEff ()
|
||||||
|
Debug :: Show a => a -> HASSEff ()
|
||||||
|
|
||||||
type HASS a b = Mealy HASSEff a b
|
type HASS a b = Mealy HASSEff a b
|
||||||
|
|
||||||
callService :: Service -> HASS a ()
|
callService :: Service -> HASS a ()
|
||||||
callService service = eff (\_ -> CallService service)
|
callService service = eff (\_ -> CallService service)
|
||||||
|
|
||||||
|
debug :: Show a => HASS a a
|
||||||
|
debug = proc x -> do
|
||||||
|
eff Debug -< x
|
||||||
|
returnA -< x
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ module HomeAssistant.Controller.Bedroom where
|
|||||||
|
|
||||||
import HomeAssistant.Controller
|
import HomeAssistant.Controller
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import AFRP (Event (..))
|
import AFRP (Event (..), (>>|), toEvent, lMerge)
|
||||||
import Data.Aeson (Value, object, (.=))
|
import Data.Aeson (Value, object, (.=))
|
||||||
import Control.Arrow ((>>>), returnA)
|
import Control.Arrow ((>>>), returnA, arr, ArrowChoice (..), Arrow (..))
|
||||||
|
import Control.Lens ((^?), to, traversed)
|
||||||
|
import Data.Aeson.Lens (key, _String)
|
||||||
|
import qualified Data.Text.Lens as TL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,3 +48,54 @@ bedroomPresenceController = proc x -> do
|
|||||||
Event Occupied -> callService (activateScene "makuuhuone_lights_snapshot") -< ()
|
Event Occupied -> callService (activateScene "makuuhuone_lights_snapshot") -< ()
|
||||||
_ -> returnA -< ()
|
_ -> returnA -< ()
|
||||||
|
|
||||||
|
-- Ikea quick buttons are identified by different event types
|
||||||
|
data IkeaQuickButton
|
||||||
|
= ShortClickOn
|
||||||
|
| DoubleClickOn
|
||||||
|
| LongClickOn
|
||||||
|
| ShortClickOff
|
||||||
|
| DoubleClickOff
|
||||||
|
| LongClickOff
|
||||||
|
|
||||||
|
|
||||||
|
toIkeaQuickButton :: T.Text -> Maybe IkeaQuickButton
|
||||||
|
toIkeaQuickButton = \case
|
||||||
|
"1_initial_press" -> Just ShortClickOn
|
||||||
|
"1_double_press" -> Just DoubleClickOn
|
||||||
|
"1_long_press" -> Just LongClickOn
|
||||||
|
"2_initial_press" -> Just ShortClickOff
|
||||||
|
"2_double_press" -> Just DoubleClickOff
|
||||||
|
"2_long_press" -> Just LongClickOff
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
ikeaQuickButton :: T.Text -> HASS (Event Value) (Event IkeaQuickButton)
|
||||||
|
ikeaQuickButton entityId =
|
||||||
|
entityChangeEvent' entityId
|
||||||
|
>>| arr (maybe (Left ()) Right . eventType)
|
||||||
|
>>> toEvent
|
||||||
|
where
|
||||||
|
eventType v = v ^? key "event" . key "data" . key "new_state" . key "state" . _String . to toIkeaQuickButton . traversed
|
||||||
|
|
||||||
|
|
||||||
|
data BedroomControls
|
||||||
|
= Masse IkeaQuickButton
|
||||||
|
| Enishen IkeaQuickButton
|
||||||
|
|
||||||
|
|
||||||
|
bedroomButton :: HASS (Event Value) (Event BedroomControls)
|
||||||
|
bedroomButton = (masseButton &&& enishenButton) >>> arr (uncurry lMerge)
|
||||||
|
where
|
||||||
|
masseButton = fmap Masse <$> ikeaQuickButton "event.bedroom_quick_remote_masse_action"
|
||||||
|
enishenButton = fmap Enishen <$> ikeaQuickButton "event.bedroom_quick_remote_jemina_action"
|
||||||
|
|
||||||
|
bedroomButtonController :: HASS (Event Value) ()
|
||||||
|
bedroomButtonController = proc x -> do
|
||||||
|
ev <- bedroomButton -< x
|
||||||
|
case ev of
|
||||||
|
Event (Masse ShortClickOn) -> callService (activateScene "scene.makuuhuone_masse") -< ()
|
||||||
|
Event (Masse DoubleClickOn) -> callService (activateScene "scene.makuuhuone_keski") -< ()
|
||||||
|
Event (Masse LongClickOn) -> callService (activateScene "scene.makuuhuone_kirkas") -< ()
|
||||||
|
Event (Enishen ShortClickOn) -> callService (activateScene "scene.makuuhuone_jemina") -< ()
|
||||||
|
Event (Enishen DoubleClickOn) -> callService (activateScene "scene.makuuhuone_keski") -< ()
|
||||||
|
Event (Enishen LongClickOn) -> callService (activateScene "scene.makuuhuone_kirkas") -< ()
|
||||||
|
_ -> returnA -< ()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import HomeAssistant.Runtime.Connection (readerAction, writerAction)
|
|||||||
import HomeAssistant.Runtime.Supervisor (defaultBackoff, supervised)
|
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)
|
import HomeAssistant.Controller.Bedroom (bedroomPresenceController, bedroomButtonController)
|
||||||
|
|
||||||
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) -> Mealy eff a b -> a -> IO (b, Mealy eff a b)
|
||||||
step nt (Mealy f) a = do
|
step nt (Mealy f) a = do
|
||||||
@@ -36,7 +36,10 @@ step nt (Mealy f) a = do
|
|||||||
data Controller = forall b. Controller T.Text (HASS (Event Value) b)
|
data Controller = forall b. Controller T.Text (HASS (Event Value) b)
|
||||||
|
|
||||||
controllers :: [Controller]
|
controllers :: [Controller]
|
||||||
controllers = [Controller "bedroom-presence" bedroomPresenceController]
|
controllers =
|
||||||
|
[ Controller "bedroom-presence" bedroomPresenceController
|
||||||
|
, Controller "bedroom-button" bedroomButtonController
|
||||||
|
]
|
||||||
|
|
||||||
-- | Steps the machine for every inbound message; service calls go to the
|
-- | Steps the machine for every inbound message; service calls go to the
|
||||||
-- bus. A restart re-dups the inbound channel and starts from the machine's
|
-- bus. A restart re-dups the inbound channel and starts from the machine's
|
||||||
|
|||||||
Reference in New Issue
Block a user