83 lines
3.4 KiB
FSharp
83 lines
3.4 KiB
FSharp
module NightLight.Core.Core
|
|
|
|
open System
|
|
open NightLight.Core.Models
|
|
open NightLight.Core.PartsOfDay
|
|
open NightLight.Core.ZigbeeEvents
|
|
open NightLight.Core.ZigbeeCommands
|
|
open NightLight.Core.Moods
|
|
open FsToolkit.ErrorHandling
|
|
|
|
let internal tryFindLight friendlyName =
|
|
Seq.tryFind (fun light -> light.FriendlyName = friendlyName) lights
|
|
|
|
let internal generateZigbeeCommandsToFixLight state partOfDay light =
|
|
seq {
|
|
yield generateStateCommand state light
|
|
|
|
if state = On then
|
|
let color, brightness =
|
|
getDesiredMood light.Room partOfDay |> getDesiredColorAndBrightness light.Bulb
|
|
|
|
yield generateZigbeeCommand color brightness light
|
|
}
|
|
|
|
type NightLightStateMachine private (maybeTime: DateTime option, lightToState: Map<Light, State>) =
|
|
new() = NightLightStateMachine(None, lights |> Seq.map (fun light -> light, On) |> Map.ofSeq)
|
|
|
|
member this.OnEventReceived(event: Event) : Result<NightLightStateMachine * Message seq, OnEventReceivedError> =
|
|
result {
|
|
let maybePartOfDay = maybeTime |> Option.map getPartOfDay
|
|
let remoteControlledLights = lights |> Seq.filter _.ControlledWithRemote
|
|
|
|
let updateLightStateForRemoteControlledLights desiredLightState =
|
|
remoteControlledLights
|
|
|> Seq.fold (fun acc key -> Map.add key desiredLightState acc) lightToState
|
|
|
|
match event, maybePartOfDay with
|
|
| ReceivedZigbeeEvent payload, Some partOfDay ->
|
|
let! zigbeeEvent = parseZigbeeEvent payload |> Result.mapError ParseZigbeeEventError
|
|
|
|
return
|
|
match zigbeeEvent with
|
|
| DeviceAnnounce friendlyName ->
|
|
let maybeLight = tryFindLight friendlyName
|
|
|
|
this,
|
|
match maybeLight with
|
|
| Some light -> generateZigbeeCommandsToFixLight lightToState[light] partOfDay light
|
|
| None -> Seq.empty
|
|
| ButtonPress action ->
|
|
let desiredLightState =
|
|
match action with
|
|
| PressedOn -> On
|
|
| PressedOff -> Off
|
|
|
|
let newLightToState = updateLightStateForRemoteControlledLights desiredLightState
|
|
|
|
NightLightStateMachine(maybeTime, newLightToState),
|
|
remoteControlledLights
|
|
|> Seq.collect (fun light -> generateZigbeeCommandsToFixLight desiredLightState partOfDay light)
|
|
| TimeChanged newTime, maybePartOfDay ->
|
|
let newPartOfDay = getPartOfDay newTime
|
|
|
|
let partOfDayChanged = maybePartOfDay <> Some newPartOfDay
|
|
|
|
let newLightToState =
|
|
if partOfDayChanged && newPartOfDay = Day then
|
|
updateLightStateForRemoteControlledLights On
|
|
else
|
|
lightToState
|
|
|
|
let newState = NightLightStateMachine(Some newTime, newLightToState)
|
|
|
|
return
|
|
newState,
|
|
if partOfDayChanged then
|
|
lights
|
|
|> Seq.collect (fun light ->
|
|
generateZigbeeCommandsToFixLight newLightToState[light] newPartOfDay light)
|
|
else
|
|
Seq.empty
|
|
| _, None -> return! Error TimeIsUnknown
|
|
}
|