@@ -3,12 +3,15 @@ module StreamDeck.Homebridge.PluginAgent
33open Browser.Dom
44open StreamDeck.SDK
55open StreamDeck.SDK .PluginModel
6+ open System
67
78type PluginInnerState = {
89 replyAgent: MailboxProcessor < PluginOutEvent >
910 client: Client .HomebridgeClient option
11+ lastCharacteristicUpdate: DateTime
1012 characteristics: Map < string * string , Client .AccessoryServiceCharacteristic >
1113 visibleActions: Map < string , Domain .ActionSetting * int option >
14+ updateInterval: int
1215 timerId: float option
1316}
1417
@@ -39,15 +42,12 @@ let processKeyUp (state: PluginInnerState) (event: Dto.Event) (payload: Dto.Acti
3942 let targetValue = 1 - currentValue
4043
4144 match ! client.SetAccessoryCharacteristic accessoryId characteristicType targetValue with
42- | Ok accessory' ->
43- let ch ' = accessory' |> PiView.getCharacteristic characteristicType
44- let currentValue ' = ch'.value.Value :?> int
45-
46- if currentValue = currentValue' then
47- state.replyAgent.Post <| PluginOutEvent.ShowAlert event.context
48- else
49- state.replyAgent.Post
50- <| PluginOutEvent.SetState( event.context, currentValue')
45+ | Ok accessory ->
46+ let ch ' = accessory |> PiView.getCharacteristic characteristicType
47+ let updatedValue = ch'.value.Value :?> int
48+
49+ if targetValue = updatedValue then
50+ state.replyAgent.Post <| PluginOutEvent.ShowOk event.context
5151 | Error e -> onError e
5252 | _ -> onError $" Cannot find characteristic by id '{accessoryId}, {characteristicType}'."
5353 | _ -> onError " Action is not properly configured"
@@ -66,33 +66,45 @@ let processKeyUp (state: PluginInnerState) (event: Dto.Event) (payload: Dto.Acti
6666 let ch = accessory |> PiView.getCharacteristic characteristicType
6767 let currentValue = ch.value.Value :?> float
6868
69- if abs( targetValue - currentValue) > 1e-8 then
70- state.replyAgent.Post <| PluginOutEvent.ShowAlert event.context
71- else
69+ if abs( targetValue - currentValue) < 1e-8 then
7270 state.replyAgent.Post <| PluginOutEvent.ShowOk event.context
7371 | Error e -> onError e
7472 | _ -> onError " Action is not properly configured"
7573 | _ -> onError $" Action {event.action} is not yet supported"
7674 }
7775
78- let updateState ( state : PluginInnerState ) = async {
79- let! accessories =
80- state.client
81- |> Option.map( fun client -> client.GetAccessories())
82- |> Option.defaultValue( async { return Error( " Homedbridge client is not set yet" ) })
83-
84- let characteristics =
85- match accessories with
86- | Error _ -> state.characteristics
87- | Ok( accessories) ->
88- accessories
89- |> Array.collect( fun accessory ->
90- accessory.serviceCharacteristics
91- |> Array.map( fun characteristic ->
92- let key = accessory.uniqueId, characteristic.`` type ``
93- key, characteristic))
94- |> Map.ofArray
76+ let updateAccessories ( state : PluginInnerState ) = async {
77+ let now = DateTime.Now
78+
79+ if now - state.lastCharacteristicUpdate < TimeSpan.FromSeconds 1.0 then
80+ return state
81+ else
82+ let! accessories =
83+ state.client
84+ |> Option.map( fun client -> client.GetAccessories())
85+ |> Option.defaultValue( async { return Error( " Homedbridge client is not set yet" ) })
86+
87+ let characteristics =
88+ match accessories with
89+ | Error _ -> state.characteristics
90+ | Ok( accessories) ->
91+ accessories
92+ |> Array.collect( fun accessory ->
93+ accessory.serviceCharacteristics
94+ |> Array.map( fun characteristic ->
95+ let key = accessory.uniqueId, characteristic.`` type ``
96+ key, characteristic))
97+ |> Map.ofArray
98+
99+ return
100+ { state with
101+ characteristics = characteristics
102+ lastCharacteristicUpdate = now
103+ }
104+ }
95105
106+ let updateActions ( state : PluginInnerState ) = async {
107+ let! state = updateAccessories state
96108
97109 let visibleActions =
98110 state.visibleActions
@@ -103,7 +115,7 @@ let updateState(state: PluginInnerState) = async {
103115 CharacteristicType = Some characteristicType
104116 },
105117 Some actionState ->
106- match characteristics |> Map.tryFind( accessoryId, characteristicType) with
118+ match state. characteristics |> Map.tryFind( accessoryId, characteristicType) with
107119 | Some( ch) when ch.value.IsSome ->
108120 let chValue = ch.value.Value :?> int
109121
@@ -117,14 +129,32 @@ let updateState(state: PluginInnerState) = async {
117129
118130 return
119131 { state with
120- characteristics = characteristics
121132 visibleActions = visibleActions
122133 }
123134}
124135
136+
125137let createPluginAgent () : MailboxProcessor < PluginInEvent > =
126138 let mutable agent : MailboxProcessor < PluginInEvent > option = None
127139
140+ let updateTimer ( state : PluginInnerState ) =
141+ if state.timerId.IsSome then
142+ window.clearTimeout( state.timerId.Value)
143+
144+ let timerId =
145+ if state.updateInterval = 0 then
146+ None
147+ else
148+ window.setInterval(
149+ ( fun _ -> agent.Value.Post( PluginInEvent.SystemDidWakeUp)),
150+ 1000 * state.updateInterval,
151+ [||]
152+ )
153+ |> Some
154+
155+ { state with timerId = timerId }
156+
157+
128158 agent <-
129159 MailboxProcessor.Start( fun inbox ->
130160 let rec idle () = async {
@@ -137,8 +167,10 @@ let createPluginAgent() : MailboxProcessor<PluginInEvent> =
137167 let state = {
138168 replyAgent = replyAgent
139169 client = None
170+ lastCharacteristicUpdate = DateTime.MinValue
140171 characteristics = Map.empty
141172 visibleActions = Map.empty
173+ updateInterval = 0
142174 timerId = None
143175 }
144176
@@ -155,23 +187,27 @@ let createPluginAgent() : MailboxProcessor<PluginInEvent> =
155187 match msg with
156188 | PluginInEvent.DidReceiveGlobalSettings settings ->
157189 let state =
158- { state with
159- client =
160- Domain.tryParse< Domain.GlobalSettings>( settings)
161- |> Option.map( Client.HomebridgeClient)
162- }
190+ match Domain.tryParse< Domain.GlobalSettings>( settings) with
191+ | Some( settings) ->
192+ { state with
193+ client = Some( Client.HomebridgeClient settings)
194+ updateInterval = settings.UpdateInterval
195+ }
196+ |> updateTimer
197+ | _ -> state
163198
164199 return ! loop state
165200 | PluginInEvent.KeyUp( event, payload) ->
166- let! state = updateState state
201+ let! state = updateActions state
167202 do ! processKeyUp state event payload
168- // TODO: update state of changed action
169203 return ! loop state
170204 | PluginInEvent.SystemDidWakeUp ->
171205 // Fake action triggered by timer to update buttons state
172- let! state = updateState state
206+ let! state = updateActions state
173207 return ! loop state
174208 | PluginInEvent.WillAppear( event, payload) ->
209+ let! state = updateActions state
210+
175211 let state =
176212 { state with
177213 visibleActions =
@@ -180,18 +216,8 @@ let createPluginAgent() : MailboxProcessor<PluginInEvent> =
180216 state.visibleActions
181217 |> Map.add event.context ( actionSetting, payload.state)
182218 | _ -> state.visibleActions
183- timerId =
184- match state.timerId with
185- | Some _ -> state.timerId
186- | None ->
187- Some(
188- window.setInterval(
189- ( fun _ -> agent.Value.Post( PluginInEvent.SystemDidWakeUp)),
190- 5_000 ,
191- [||]
192- )
193- )
194219 }
220+ |> updateTimer
195221
196222 return ! loop state
197223 | PluginInEvent.WillDisappear( event, _) ->
0 commit comments