Add dedupeBatch: collapse outbound calls per target

This commit is contained in:
2026-08-25 19:33:44 +03:00
parent 6bb96833e1
commit 3f5aa4735c
4 changed files with 85 additions and 23 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ data Request = Request
{ requestTime :: !UTCTime
, requestTimeZone :: !TimeZone
, requestTraceId :: !UUID
} deriving Show
} deriving (Show, Eq)
-- | The set of entity ids an arrow subscribes to. Static: it does not
-- change as the machine steps, so the runtime can read it once to build
+1 -1
View File
@@ -39,7 +39,7 @@ import qualified Data.Text.Lens as TL
import Data.Bool (bool)
data Target = EntityId !T.Text | AreaId !T.Text
deriving (Show,Eq)
deriving (Show,Eq,Ord)
data Service = Service
{ serviceDomain :: T.Text
+15
View File
@@ -5,6 +5,7 @@ module HomeAssistant.Runtime.Connection
( readerAction
, writerAction
, encodeService
, dedupeBatch
) where
import Control.Concurrent.STM
@@ -23,6 +24,8 @@ import Control.Lens ((^?))
import Control.Monad (forever, forM_)
import Data.Aeson (Value, eitherDecode, encode, object, (.=))
import Data.Aeson.Lens (key, _String)
import Data.List (sort)
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import qualified Data.Text as T
import Data.Void (Void)
@@ -119,6 +122,18 @@ encodeService callId Service{..} = object $
, "target" .= targetObject serviceTarget
] <> maybe [] (\d -> ["service_data" .= d]) serviceData
-- | Collapse a drained batch of outbound calls: the newest call per
-- `(domain, service, sorted-targets)` survives; older duplicates are
-- dropped. `serviceData` is not part of the key, so a newer `turn_on`
-- with different brightness supersedes an older one to the same target.
dedupeBatch :: [(Request, Service)] -> [(Request, Service)]
dedupeBatch = M.elems . foldl' ins M.empty
where
ins m (req, svc) = M.insert (dedupeKey svc) (req, svc) m
dedupeKey :: Service -> (T.Text, T.Text, [Target])
dedupeKey Service{..} = (serviceDomain, serviceName, sort serviceTarget)
-- | A single target encodes as a scalar; multiple encode as a list. Empty
-- lists are omitted so Home Assistant receives only populated keys.
targetObject :: [Target] -> Value