Implement FakeHome
This commit is contained in:
parent
83b716a509
commit
fc069edf31
4 changed files with 150 additions and 0 deletions
81
NightLight.Core.Tests/FakeHome.fs
Normal file
81
NightLight.Core.Tests/FakeHome.fs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
namespace NightLight.Core.Tests
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Text.RegularExpressions
|
||||||
|
open NightLight.Core.Models
|
||||||
|
open FsToolkit.ErrorHandling
|
||||||
|
open FSharp.Data
|
||||||
|
|
||||||
|
type HumanInteraction =
|
||||||
|
| LightTurnedOn of Light
|
||||||
|
| LightTurnedOff of Light
|
||||||
|
|
||||||
|
type Interaction =
|
||||||
|
| HumanInteraction of HumanInteraction
|
||||||
|
| TimeChanged of DateTime
|
||||||
|
|
||||||
|
type LightState =
|
||||||
|
| Off
|
||||||
|
| On of Brightness: byte
|
||||||
|
|
||||||
|
type FakeLight(light: Light) =
|
||||||
|
let mutable hasPower = false
|
||||||
|
let mutable brightness: byte = 255uy
|
||||||
|
|
||||||
|
member _.LightWithState = light, if hasPower then On brightness else Off
|
||||||
|
|
||||||
|
member _.TurnOn() = hasPower <- true
|
||||||
|
|
||||||
|
member _.TurnOff() = hasPower <- false
|
||||||
|
|
||||||
|
member _.SetBrightness(newBrightness: byte) =
|
||||||
|
if hasPower then
|
||||||
|
brightness <- newBrightness
|
||||||
|
|
||||||
|
type FakeHome(now: DateTime) =
|
||||||
|
let nightLightStateMachine = NightLightStateMachine now
|
||||||
|
|
||||||
|
let friendlyNameToFakeLight =
|
||||||
|
lights
|
||||||
|
|> Seq.map (fun light -> light.FriendlyName, FakeLight light)
|
||||||
|
|> Map.ofSeq
|
||||||
|
|
||||||
|
let processCommand command =
|
||||||
|
option {
|
||||||
|
let! friendlyName =
|
||||||
|
let m = Regex.Match(command.Topic, "^zigbee2mqtt/(.+)/set$")
|
||||||
|
if m.Success then Some m.Groups.[1].Value else None
|
||||||
|
|
||||||
|
let! fakeLight = Map.tryFind friendlyName friendlyNameToFakeLight
|
||||||
|
|
||||||
|
let parsedPayload = JsonValue.Parse command.Payload
|
||||||
|
|
||||||
|
match parsedPayload.TryGetProperty "brightness" with
|
||||||
|
| Some(JsonValue.Number newBrightness) -> fakeLight.SetBrightness(byte newBrightness)
|
||||||
|
| None -> ()
|
||||||
|
| value -> failwith $"Unexpected brightness value {value}"
|
||||||
|
}
|
||||||
|
|> ignore
|
||||||
|
|
||||||
|
member _.LightStates = friendlyNameToFakeLight.Values |> Seq.map _.LightWithState
|
||||||
|
|
||||||
|
member _.Interact(interaction: Interaction) : Result<unit, ParseEventError> =
|
||||||
|
result {
|
||||||
|
match interaction with
|
||||||
|
| HumanInteraction(LightTurnedOn light) ->
|
||||||
|
friendlyNameToFakeLight[light.FriendlyName].TurnOn()
|
||||||
|
|
||||||
|
do!
|
||||||
|
{ Topic = "zigbee2mqtt/bridge/event"
|
||||||
|
Payload =
|
||||||
|
$@"{{
|
||||||
|
""type"": ""device_announce"",
|
||||||
|
""data"": {{ ""friendly_name"": ""{light.FriendlyName}"" }}
|
||||||
|
}}" }
|
||||||
|
|> nightLightStateMachine.SendMessage
|
||||||
|
| HumanInteraction(LightTurnedOff light) -> friendlyNameToFakeLight[light.FriendlyName].TurnOff()
|
||||||
|
| TimeChanged time -> do! nightLightStateMachine.ChangeTime time
|
||||||
|
|
||||||
|
nightLightStateMachine.TransmittedCommands |> Seq.iter processCommand
|
||||||
|
nightLightStateMachine.ClearTransmittedCommands()
|
||||||
|
}
|
||||||
27
NightLight.Core.Tests/NightLight.Core.Tests.fsproj
Normal file
27
NightLight.Core.Tests/NightLight.Core.Tests.fsproj
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="NightLightStateMachine.fs" />
|
||||||
|
<Compile Include="FakeHome.fs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||||
|
<PackageReference Include="FsCheck" Version="3.3.0" />
|
||||||
|
<PackageReference Include="FsCheck.Xunit" Version="3.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../NightLight.Core/NightLight.Core.fsproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
28
NightLight.Core.Tests/NightLightStateMachine.fs
Normal file
28
NightLight.Core.Tests/NightLightStateMachine.fs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
namespace NightLight.Core.Tests
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Collections.Generic
|
||||||
|
open FsToolkit.ErrorHandling
|
||||||
|
open NightLight.Core.Models
|
||||||
|
open NightLight.Core.Core
|
||||||
|
|
||||||
|
type NightLightStateMachine(now: DateTime) =
|
||||||
|
let mutable state = { Time = now }
|
||||||
|
|
||||||
|
let transmittedCommands = new List<Message>()
|
||||||
|
|
||||||
|
let sendEvent event =
|
||||||
|
result {
|
||||||
|
let! newState, commands = onEventReceived state event
|
||||||
|
state <- newState
|
||||||
|
transmittedCommands.AddRange commands
|
||||||
|
}
|
||||||
|
|
||||||
|
member _.TransmittedCommands = transmittedCommands.AsReadOnly()
|
||||||
|
|
||||||
|
member _.SendMessage message =
|
||||||
|
ReceivedZigbeeEvent message |> sendEvent
|
||||||
|
|
||||||
|
member _.ChangeTime time = TimeChanged time |> sendEvent
|
||||||
|
|
||||||
|
member _.ClearTransmittedCommands() = transmittedCommands.Clear()
|
||||||
|
|
@ -4,6 +4,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NightLight", "NightLight\Ni
|
||||||
EndProject
|
EndProject
|
||||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NightLight.Core", "NightLight.Core\NightLight.Core.fsproj", "{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}"
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NightLight.Core", "NightLight.Core\NightLight.Core.fsproj", "{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "NightLight.Core.Tests", "NightLight.Core.Tests\NightLight.Core.Tests.fsproj", "{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -38,6 +40,18 @@ Global
|
||||||
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x64.Build.0 = Release|Any CPU
|
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x86.ActiveCfg = Release|Any CPU
|
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x86.Build.0 = Release|Any CPU
|
{FE406BDE-B6C1-4BDA-A29D-54D50A7828A9}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{23C7B106-B1B8-49A8-B2CF-22C078C8DDB3}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue