Add second remote

This commit is contained in:
Sven van Heugten 2026-03-15 17:31:50 +01:00
parent 48c58b610c
commit 8cde891ba2
8 changed files with 51 additions and 11 deletions

View file

@ -11,7 +11,10 @@ type BedroomControllingRemoteInteraction =
| RemotePressedOffButton | RemotePressedOffButton
| RemotePressedLeftButton | RemotePressedLeftButton
type LivingRoomControllingRemoteAction = | RemotePressedRightButton type LivingRoomControllingRemoteAction =
| RemotePressedRightButton
| LivingRoomRemotePressedOnButton
| LivingRoomRemotePressedOffButton
type HumanInteraction = type HumanInteraction =
| LightPoweredOn of Light | LightPoweredOn of Light
@ -145,6 +148,16 @@ type FakeHome() =
Payload = @"{ ""action"": ""arrow_right_click"" }" } Payload = @"{ ""action"": ""arrow_right_click"" }" }
|> ReceivedZigbeeEvent |> ReceivedZigbeeEvent
|> onEventPublished.Trigger |> onEventPublished.Trigger
| LivingRoomControllingRemoteInteraction LivingRoomRemotePressedOnButton ->
{ Topic = $"zigbee2mqtt/{livingRoomRemoteControlFriendlyName.Get}"
Payload = @"{ ""action"": ""on"" }" }
|> ReceivedZigbeeEvent
|> onEventPublished.Trigger
| LivingRoomControllingRemoteInteraction LivingRoomRemotePressedOffButton ->
{ Topic = $"zigbee2mqtt/{livingRoomRemoteControlFriendlyName.Get}"
Payload = @"{ ""action"": ""off"" }" }
|> ReceivedZigbeeEvent
|> onEventPublished.Trigger
| TimeChanged newTime -> newTime |> Event.TimeChanged |> onEventPublished.Trigger | TimeChanged newTime -> newTime |> Event.TimeChanged |> onEventPublished.Trigger
type FakeHome with type FakeHome with

View file

@ -40,7 +40,11 @@ let private genRemoteInteraction =
[ Gen.elements [ RemotePressedOnButton; RemotePressedOffButton; RemotePressedLeftButton ] [ Gen.elements [ RemotePressedOnButton; RemotePressedOffButton; RemotePressedLeftButton ]
|> Gen.map BedroomControllingRemoteInteraction |> Gen.map BedroomControllingRemoteInteraction
Gen.constant (LivingRoomControllingRemoteInteraction RemotePressedRightButton) ] Gen.elements
[ RemotePressedRightButton
LivingRoomRemotePressedOnButton
LivingRoomRemotePressedOffButton ]
|> Gen.map LivingRoomControllingRemoteInteraction ]
let private genInteraction = let private genInteraction =
Gen.frequency [ 4, genTimeChanged; 1, genHumanInteraction; 1, genRemoteInteraction ] Gen.frequency [ 4, genTimeChanged; 1, genHumanInteraction; 1, genRemoteInteraction ]

View file

@ -98,11 +98,16 @@ type NightLightTests() =
let livingRoomLightsToggledOn = let livingRoomLightsToggledOn =
interactions interactions
|> Seq.filter (function |> Seq.choose (function
| Interaction.LivingRoomControllingRemoteInteraction RemotePressedRightButton -> true | Interaction.LivingRoomControllingRemoteInteraction interaction -> Some interaction
| _ -> false) | _ -> None)
|> Seq.length |> Seq.fold
|> fun rightPresses -> rightPresses % 2 = 0 (fun state interaction ->
match interaction with
| RemotePressedRightButton -> not state
| LivingRoomRemotePressedOnButton -> true
| LivingRoomRemotePressedOffButton -> false)
true
let isExpectedOn light = let isExpectedOn light =
match light with match light with

View file

@ -83,6 +83,8 @@ let lights =
let remoteControlFriendlyName = DeviceFriendlyName "Fjärrkontroll" let remoteControlFriendlyName = DeviceFriendlyName "Fjärrkontroll"
let livingRoomRemoteControlFriendlyName = DeviceFriendlyName "Living Room Remote"
type internal State = type internal State =
| On | On
| Off | Off

View file

@ -111,6 +111,14 @@ type NightLightStateMachine private (maybeState: NightLightState option) =
currentState currentState
|> withInvertedStateFor LivingRoomWallLamp |> withInvertedStateFor LivingRoomWallLamp
|> withInvertedStateFor LivingRoomFloorLamp |> withInvertedStateFor LivingRoomFloorLamp
| PressedLivingRoomOn ->
currentState
|> withStateFor LivingRoomWallLamp On
|> withStateFor LivingRoomFloorLamp On
| PressedLivingRoomOff ->
currentState
|> withStateFor LivingRoomWallLamp Off
|> withStateFor LivingRoomFloorLamp Off
NightLightStateMachine(Some newNightLightState), NightLightStateMachine(Some newNightLightState),
generateZigbeeCommandsForDifference (Some currentState) newNightLightState generateZigbeeCommandsForDifference (Some currentState) newNightLightState

View file

@ -15,7 +15,6 @@ let generateStateCommand state light =
| On -> "ON" | On -> "ON"
| Off -> "OFF" | Off -> "OFF"
if (lightProps light).Bulb = IkeaBulb then
commandObj["transition"] <- 0 commandObj["transition"] <- 0
commandObj.ToJsonString() |> toZigbeeCommand light commandObj.ToJsonString() |> toZigbeeCommand light

View file

@ -9,6 +9,8 @@ type Action =
| PressedOff | PressedOff
| PressedLeft | PressedLeft
| PressedRight | PressedRight
| PressedLivingRoomOn
| PressedLivingRoomOff
type ZigbeeEvent = type ZigbeeEvent =
| DeviceAnnounce of DeviceFriendlyName | DeviceAnnounce of DeviceFriendlyName
@ -41,5 +43,12 @@ let parseZigbeeEvent (message: Message) =
| Some(JsonValue.String "arrow_right_click") -> Ok(ButtonPress PressedRight) | Some(JsonValue.String "arrow_right_click") -> Ok(ButtonPress PressedRight)
| Some _ -> Error InvalidActionField | Some _ -> Error InvalidActionField
| None -> Error MissingActionField | None -> Error MissingActionField
| "zigbee2mqtt/Living Room Remote" ->
return!
match jsonValue.TryGetProperty "action" with
| Some(JsonValue.String "on") -> Ok(ButtonPress PressedLivingRoomOn)
| Some(JsonValue.String "off") -> Ok(ButtonPress PressedLivingRoomOff)
| Some _ -> Error InvalidActionField
| None -> Error MissingActionField
| _ -> return! Error <| UnknownTopic message.Topic | _ -> return! Error <| UnknownTopic message.Topic
} }

View file

@ -1,4 +1,4 @@
open System open System
open System.Text open System.Text
open System.Threading open System.Threading
open System.Threading.Tasks open System.Threading.Tasks
@ -103,7 +103,7 @@ let mainAsync _ =
:> Task) :> Task)
do! do!
[ "zigbee2mqtt/bridge/event"; $"zigbee2mqtt/{remoteControlFriendlyName.Get}" ] [ "zigbee2mqtt/bridge/event"; $"zigbee2mqtt/{remoteControlFriendlyName.Get}"; $"zigbee2mqtt/{livingRoomRemoteControlFriendlyName.Get}" ]
|> Seq.map (fun topic -> async { return! mqttClient.SubscribeAsync topic |> Async.AwaitTask }) |> Seq.map (fun topic -> async { return! mqttClient.SubscribeAsync topic |> Async.AwaitTask })
|> Async.Sequential |> Async.Sequential
|> Async.Ignore |> Async.Ignore