Initial commit
This commit is contained in:
commit
284fdc1261
16 changed files with 448 additions and 0 deletions
13
NightLight/Dockerfile
Normal file
13
NightLight/Dockerfile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
WORKDIR /app
|
||||
COPY NightLight.sln ./
|
||||
COPY NightLight.Core/NightLight.Core.fsproj NightLight.Core/
|
||||
COPY NightLight/NightLight.fsproj NightLight/
|
||||
RUN dotnet restore
|
||||
COPY . ./
|
||||
RUN dotnet publish NightLight/NightLight.fsproj --no-restore -c Release -o out
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:9.0
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/out .
|
||||
ENTRYPOINT ["dotnet", "NightLight.dll"]
|
||||
23
NightLight/NightLight.fsproj
Normal file
23
NightLight/NightLight.fsproj
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.4" />
|
||||
<PackageReference Include="MQTTnet" Version="5.0.1.1416" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../NightLight.Core/NightLight.Core.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
103
NightLight/Program.fs
Normal file
103
NightLight/Program.fs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
open System
|
||||
open System.Text
|
||||
open System.Threading.Tasks
|
||||
open Microsoft.Extensions.Logging
|
||||
open MQTTnet
|
||||
open MQTTnet.Protocol
|
||||
open NightLight.PartsOfDay
|
||||
open NightLight.ZigbeeEvents
|
||||
open NightLight.ZigbeeCommands
|
||||
open NightLight.Core
|
||||
|
||||
let private generateMqttMessage zigbeeCommand =
|
||||
match zigbeeCommand with
|
||||
| ZigbeeCommand(topic, payload) ->
|
||||
MqttApplicationMessageBuilder()
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
.Build()
|
||||
|
||||
let private publishZigbeeCommands (mqttClient: IMqttClient) (logger: ILogger) (commands: ZigbeeCommand seq) =
|
||||
async {
|
||||
commands
|
||||
|> Seq.iter (fun command ->
|
||||
match command with
|
||||
| ZigbeeCommand(topic, payload) ->
|
||||
logger.LogInformation("Publishing message {Payload} to topic {Topic}...", payload, topic))
|
||||
|
||||
return!
|
||||
commands
|
||||
|> Seq.map generateMqttMessage
|
||||
|> Seq.map mqttClient.PublishAsync
|
||||
|> Seq.map Async.AwaitTask
|
||||
|> Async.Sequential
|
||||
|> Async.Ignore
|
||||
}
|
||||
|
||||
let private onMqttMessageReceived (mqttClient: IMqttClient) (logger: ILogger) (message: MqttApplicationMessage) =
|
||||
let payload = message.Payload
|
||||
let decodedPayload = Encoding.UTF8.GetString(&payload)
|
||||
|
||||
logger.LogInformation("Received message with payload {Payload}", decodedPayload)
|
||||
|
||||
let commandsResult =
|
||||
decodedPayload |> onZigbeeEventReceived (getPartOfDay DateTime.Now)
|
||||
|
||||
match commandsResult with
|
||||
| Ok commands -> publishZigbeeCommands mqttClient logger commands
|
||||
| Error UnknownType -> async.Return()
|
||||
| Error e ->
|
||||
logger.LogError("Error {Error} while processing {Payload}", e, payload)
|
||||
async.Return()
|
||||
|
||||
[<EntryPoint>]
|
||||
let mainAsync _ =
|
||||
// This is still a stateful mess. Needs to be cleaned up a lot.
|
||||
async {
|
||||
let loggerFactory =
|
||||
LoggerFactory.Create(fun builder -> builder.AddConsole().SetMinimumLevel LogLevel.Information |> ignore)
|
||||
|
||||
let logger = loggerFactory.CreateLogger "NightLight"
|
||||
|
||||
logger.LogInformation("Current system time is {Now}", DateTime.Now)
|
||||
|
||||
let mqttFactory = MqttClientFactory()
|
||||
|
||||
use mqttClient = mqttFactory.CreateMqttClient()
|
||||
|
||||
let server =
|
||||
match Environment.GetEnvironmentVariable "MQTT_SERVER" with
|
||||
| null -> "localhost"
|
||||
| value -> value
|
||||
|
||||
let mqttClientOptions = MqttClientOptionsBuilder().WithTcpServer(server).Build()
|
||||
|
||||
mqttClient.add_ApplicationMessageReceivedAsync (fun e ->
|
||||
onMqttMessageReceived mqttClient logger e.ApplicationMessage
|
||||
|> Async.StartAsTask
|
||||
:> Task)
|
||||
|
||||
do! mqttClient.ConnectAsync mqttClientOptions |> Async.AwaitTask |> Async.Ignore
|
||||
|
||||
do!
|
||||
mqttClient.SubscribeAsync "zigbee2mqtt/bridge/event"
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
|
||||
let mutable previousPartOfDay: PartOfDay option = None
|
||||
|
||||
while true do
|
||||
let currentPartOfDay = getPartOfDay DateTime.Now
|
||||
|
||||
if previousPartOfDay <> Some currentPartOfDay then
|
||||
do! onPartOfDayChanged currentPartOfDay |> publishZigbeeCommands mqttClient logger
|
||||
previousPartOfDay <- Some currentPartOfDay
|
||||
|
||||
do! Async.Sleep 10_000
|
||||
|
||||
do! mqttClient.DisconnectAsync() |> Async.AwaitTask
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
0
|
||||
Loading…
Add table
Add a link
Reference in a new issue