diff --git a/.github/workflows/ci-build-and-test.yml b/.github/workflows/ci-build-and-test.yml
index e0f05b3..b8594f6 100644
--- a/.github/workflows/ci-build-and-test.yml
+++ b/.github/workflows/ci-build-and-test.yml
@@ -22,4 +22,4 @@ jobs:
dotnet-version: '9.0.x'
- name: 🛠️ Build code
- run: dotnet build --configuration Release -p:TreatWarningsAsErrors=true
\ No newline at end of file
+ run: dotnet build CodeCasa.Showcase.sln --configuration Release -p:TreatWarningsAsErrors=true
\ No newline at end of file
diff --git a/CodeCasa.Showcase.withLocalCodeCasa.sln b/CodeCasa.Showcase.withLocalCodeCasa.sln
new file mode 100644
index 0000000..4cb1045
--- /dev/null
+++ b/CodeCasa.Showcase.withLocalCodeCasa.sln
@@ -0,0 +1,181 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 18
+VisualStudioVersion = 18.1.11312.151
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Dashboard", "src\CodeCasa.Dashboard\CodeCasa.Dashboard.csproj", "{D734015F-45B7-4689-A151-C279A5F6A61A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.AutoGenerated", "src\CodeCasa.AutoGenerated\CodeCasa.AutoGenerated.csproj", "{338F0D10-B628-451B-86D5-B22393778D7C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Automations", "src\CodeCasa.Automations\CodeCasa.Automations.csproj", "{69E23803-F031-4294-8C32-3DBA59A3A08E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.NetDaemon.Utilities", "src\CodeCasa.NetDaemon.Utilities\CodeCasa.NetDaemon.Utilities.csproj", "{AF4EB14B-3F32-4DBD-8552-56CE2A470E48}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Entities", "Entities", "{B8417343-120D-42CE-9802-F9584E63E3AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Shared", "src\CodeCasa.Shared\CodeCasa.Shared.csproj", "{2497FDAA-46A9-4D2F-8411-98EE08FA2D23}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.CustomEntities.Core", "src\CodeCasa.CustomEntities.Core\CodeCasa.CustomEntities.Core.csproj", "{601FA957-4116-4DB6-AA17-DF358DB4D149}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.CustomEntities.Automation", "src\CodeCasa.CustomEntities.Automation\CodeCasa.CustomEntities.Automation.csproj", "{F91714FE-A475-4680-BF70-7B50E163DA3C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCasa", "CodeCasa", "{69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Abstractions", "..\CodeCasa\src\CodeCasa.Abstractions\CodeCasa.Abstractions.csproj", "{EA05C3BC-A411-AFC7-0820-739AC4800BAA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.AutomationPipelines", "..\CodeCasa\src\CodeCasa.AutomationPipelines\CodeCasa.AutomationPipelines.csproj", "{DA77B96C-7E87-8A51-0A48-F818D85AA7BD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.AutomationPipelines.Lights", "..\CodeCasa\src\CodeCasa.AutomationPipelines.Lights\CodeCasa.AutomationPipelines.Lights.csproj", "{9D3D66D6-1263-F2D8-3252-56CD60CEAE9B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.AutomationPipelines.Lights.NetDaemon", "..\CodeCasa\src\CodeCasa.AutomationPipelines.Lights.NetDaemon\CodeCasa.AutomationPipelines.Lights.NetDaemon.csproj", "{D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Lights", "..\CodeCasa\src\CodeCasa.Lights\CodeCasa.Lights.csproj", "{946F6E93-4745-4E88-1EB2-D412F7FA4069}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Lights.NetDaemon", "..\CodeCasa\src\CodeCasa.Lights.NetDaemon\CodeCasa.Lights.NetDaemon.csproj", "{DF7DB0BF-3AEE-805F-16EE-74237FDC24FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Lights.NetDaemon.Scenes", "..\CodeCasa\src\CodeCasa.Lights.NetDaemon.Scenes\CodeCasa.Lights.NetDaemon.Scenes.csproj", "{01488D66-79A9-E199-2032-6E5108834C0D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.NetDaemon.Extensions.Observables", "..\CodeCasa\src\CodeCasa.NetDaemon.Extensions.Observables\CodeCasa.NetDaemon.Extensions.Observables.csproj", "{770317DB-B681-DE60-54DF-E221B3F39C48}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.NetDaemon.RuntimeState", "..\CodeCasa\src\CodeCasa.NetDaemon.RuntimeState\CodeCasa.NetDaemon.RuntimeState.csproj", "{D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.NetDaemon.TypedEntities", "..\CodeCasa\src\CodeCasa.NetDaemon.TypedEntities\CodeCasa.NetDaemon.TypedEntities.csproj", "{781677A8-D8B6-EBE7-6C4D-08961A68CBCD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Notifications.InputSelect.NetDaemon", "..\CodeCasa\src\CodeCasa.Notifications.InputSelect.NetDaemon\CodeCasa.Notifications.InputSelect.NetDaemon.csproj", "{A48B5B2A-216A-A78B-C449-66372044C6F1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Notifications.Lights", "..\CodeCasa\src\CodeCasa.Notifications.Lights\CodeCasa.Notifications.Lights.csproj", "{0F0DD0FE-7475-D32D-FF81-79D9E837CD21}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Notifications.Phone.NetDaemon", "..\CodeCasa\src\CodeCasa.Notifications.Phone.NetDaemon\CodeCasa.Notifications.Phone.NetDaemon.csproj", "{5E27A3C9-DEC8-EE85-3AD0-2AC35879186F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.NetDaemon.Sensors.Composite", "..\CodeCasa\src\CodeCasa.NetDaemon.Sensors.Composite\CodeCasa.NetDaemon.Sensors.Composite.csproj", "{C52ABD0A-8097-D982-629D-F57CCD5A4AA8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Lights.Timelines", "..\CodeCasa\src\CodeCasa.Lights.Timelines\CodeCasa.Lights.Timelines.csproj", "{F0A38131-55E6-85EB-84A7-43B29068C457}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCasa.Mqtt", "src\CodeCasa.Mqtt\CodeCasa.Mqtt.csproj", "{E67C8206-7782-4548-9DB8-CB0DA6B330AC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D734015F-45B7-4689-A151-C279A5F6A61A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D734015F-45B7-4689-A151-C279A5F6A61A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D734015F-45B7-4689-A151-C279A5F6A61A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D734015F-45B7-4689-A151-C279A5F6A61A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {338F0D10-B628-451B-86D5-B22393778D7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {338F0D10-B628-451B-86D5-B22393778D7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {338F0D10-B628-451B-86D5-B22393778D7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {338F0D10-B628-451B-86D5-B22393778D7C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {69E23803-F031-4294-8C32-3DBA59A3A08E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {69E23803-F031-4294-8C32-3DBA59A3A08E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {69E23803-F031-4294-8C32-3DBA59A3A08E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {69E23803-F031-4294-8C32-3DBA59A3A08E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF4EB14B-3F32-4DBD-8552-56CE2A470E48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF4EB14B-3F32-4DBD-8552-56CE2A470E48}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF4EB14B-3F32-4DBD-8552-56CE2A470E48}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF4EB14B-3F32-4DBD-8552-56CE2A470E48}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2497FDAA-46A9-4D2F-8411-98EE08FA2D23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2497FDAA-46A9-4D2F-8411-98EE08FA2D23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2497FDAA-46A9-4D2F-8411-98EE08FA2D23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2497FDAA-46A9-4D2F-8411-98EE08FA2D23}.Release|Any CPU.Build.0 = Release|Any CPU
+ {601FA957-4116-4DB6-AA17-DF358DB4D149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {601FA957-4116-4DB6-AA17-DF358DB4D149}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {601FA957-4116-4DB6-AA17-DF358DB4D149}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {601FA957-4116-4DB6-AA17-DF358DB4D149}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F91714FE-A475-4680-BF70-7B50E163DA3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F91714FE-A475-4680-BF70-7B50E163DA3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F91714FE-A475-4680-BF70-7B50E163DA3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F91714FE-A475-4680-BF70-7B50E163DA3C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EA05C3BC-A411-AFC7-0820-739AC4800BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EA05C3BC-A411-AFC7-0820-739AC4800BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EA05C3BC-A411-AFC7-0820-739AC4800BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EA05C3BC-A411-AFC7-0820-739AC4800BAA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA77B96C-7E87-8A51-0A48-F818D85AA7BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA77B96C-7E87-8A51-0A48-F818D85AA7BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA77B96C-7E87-8A51-0A48-F818D85AA7BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA77B96C-7E87-8A51-0A48-F818D85AA7BD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9D3D66D6-1263-F2D8-3252-56CD60CEAE9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9D3D66D6-1263-F2D8-3252-56CD60CEAE9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9D3D66D6-1263-F2D8-3252-56CD60CEAE9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9D3D66D6-1263-F2D8-3252-56CD60CEAE9B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {946F6E93-4745-4E88-1EB2-D412F7FA4069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {946F6E93-4745-4E88-1EB2-D412F7FA4069}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {946F6E93-4745-4E88-1EB2-D412F7FA4069}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {946F6E93-4745-4E88-1EB2-D412F7FA4069}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DF7DB0BF-3AEE-805F-16EE-74237FDC24FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DF7DB0BF-3AEE-805F-16EE-74237FDC24FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DF7DB0BF-3AEE-805F-16EE-74237FDC24FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DF7DB0BF-3AEE-805F-16EE-74237FDC24FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01488D66-79A9-E199-2032-6E5108834C0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01488D66-79A9-E199-2032-6E5108834C0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01488D66-79A9-E199-2032-6E5108834C0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01488D66-79A9-E199-2032-6E5108834C0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {770317DB-B681-DE60-54DF-E221B3F39C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {770317DB-B681-DE60-54DF-E221B3F39C48}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {770317DB-B681-DE60-54DF-E221B3F39C48}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {770317DB-B681-DE60-54DF-E221B3F39C48}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {781677A8-D8B6-EBE7-6C4D-08961A68CBCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {781677A8-D8B6-EBE7-6C4D-08961A68CBCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {781677A8-D8B6-EBE7-6C4D-08961A68CBCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {781677A8-D8B6-EBE7-6C4D-08961A68CBCD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A48B5B2A-216A-A78B-C449-66372044C6F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A48B5B2A-216A-A78B-C449-66372044C6F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A48B5B2A-216A-A78B-C449-66372044C6F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A48B5B2A-216A-A78B-C449-66372044C6F1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0F0DD0FE-7475-D32D-FF81-79D9E837CD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F0DD0FE-7475-D32D-FF81-79D9E837CD21}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0F0DD0FE-7475-D32D-FF81-79D9E837CD21}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F0DD0FE-7475-D32D-FF81-79D9E837CD21}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5E27A3C9-DEC8-EE85-3AD0-2AC35879186F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5E27A3C9-DEC8-EE85-3AD0-2AC35879186F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5E27A3C9-DEC8-EE85-3AD0-2AC35879186F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5E27A3C9-DEC8-EE85-3AD0-2AC35879186F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C52ABD0A-8097-D982-629D-F57CCD5A4AA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C52ABD0A-8097-D982-629D-F57CCD5A4AA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C52ABD0A-8097-D982-629D-F57CCD5A4AA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C52ABD0A-8097-D982-629D-F57CCD5A4AA8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F0A38131-55E6-85EB-84A7-43B29068C457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F0A38131-55E6-85EB-84A7-43B29068C457}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F0A38131-55E6-85EB-84A7-43B29068C457}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F0A38131-55E6-85EB-84A7-43B29068C457}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E67C8206-7782-4548-9DB8-CB0DA6B330AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E67C8206-7782-4548-9DB8-CB0DA6B330AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E67C8206-7782-4548-9DB8-CB0DA6B330AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E67C8206-7782-4548-9DB8-CB0DA6B330AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {338F0D10-B628-451B-86D5-B22393778D7C} = {B8417343-120D-42CE-9802-F9584E63E3AF}
+ {601FA957-4116-4DB6-AA17-DF358DB4D149} = {B8417343-120D-42CE-9802-F9584E63E3AF}
+ {F91714FE-A475-4680-BF70-7B50E163DA3C} = {B8417343-120D-42CE-9802-F9584E63E3AF}
+ {EA05C3BC-A411-AFC7-0820-739AC4800BAA} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {DA77B96C-7E87-8A51-0A48-F818D85AA7BD} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {9D3D66D6-1263-F2D8-3252-56CD60CEAE9B} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {D1431BA6-C9FA-D3F9-E9F4-3FDE8A2AEB9E} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {946F6E93-4745-4E88-1EB2-D412F7FA4069} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {DF7DB0BF-3AEE-805F-16EE-74237FDC24FB} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {01488D66-79A9-E199-2032-6E5108834C0D} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {770317DB-B681-DE60-54DF-E221B3F39C48} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {D72EED6A-8CD3-CDB6-7E7E-1781005CD6D8} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {781677A8-D8B6-EBE7-6C4D-08961A68CBCD} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {A48B5B2A-216A-A78B-C449-66372044C6F1} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {0F0DD0FE-7475-D32D-FF81-79D9E837CD21} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {5E27A3C9-DEC8-EE85-3AD0-2AC35879186F} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {C52ABD0A-8097-D982-629D-F57CCD5A4AA8} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ {F0A38131-55E6-85EB-84A7-43B29068C457} = {69FE0431-17B3-4A14-ABAE-BA106D3BF6DF}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C77A270A-D381-419D-AEA1-1592AA2B4B6E}
+ EndGlobalSection
+EndGlobal
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 0000000..6c48631
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,39 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 458687a..5b70467 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A smart home implementation example using C# and NetDaemon.
This repository explores creative and powerful ways to use a rich programming language like C# for home automation. From custom logic to seamless integrations, you'll find practical examples and unique ideas to elevate your smart home setup. Stay tuned for ongoing updates and new features!
-## 📖 Table of Contents
+## 📖 Table of Contents
- [Architectures & Implementations](#🛠️-architectures--implementations)
- [Blazor Frontend (NSPanel Pro)](#blazor-frontend-nspanel-pro)
- [People](#people)
@@ -14,6 +14,9 @@ This repository explores creative and powerful ways to use a rich programming la
- [Input Select Notifications](#input-select-notifications)
- [Automation Pipelines](#automation-pipelines)
- [Projects Overview](#🔧-projects-overview)
+- [Local Debugging with CodeCasa Projects](#local-debugging-with-codecasa-projects)
+ - [CodeCasa.Showcase.withLocalCodeCasa.sln](#codecasashowcasewithlocalcodecasasln)
+ - [Requirements](#requirements)
## 🛠️ Architectures & Implementations
@@ -146,3 +149,17 @@ These projects combine existing entities into compound entities or creates entir
### 🛠️ NetDaemon Utilities (`CodeCasa.NetDaemon.Utilities`)
A collection of utility classes for working with NetDaemon entities. These utilities are tailored to the use-cases of this project but may be useful for similar implementations in other projects.
+
+## Local Debugging with CodeCasa Projects
+
+This repository can optionally use **local versions of the CodeCasa libraries** for debugging instead of the NuGet packages.
+
+### `CodeCasa.Showcase.withLocalCodeCasa.sln`
+
+- A local solution file that **includes all showcase projects and any local CodeCasa projects**.
+- Opening this solution **automatically activates the project reference replacement**, so NuGet packages are replaced with local projects.
+- Breakpoints in CodeCasa projects work normally, and projects appear in Solution Explorer.
+
+### Requirements
+
+- You must **checkout the [CodeCasa repository](https://github.com/DevJasperNL/CodeCasa)** as a sibling of this repo (same parent directory as this repo).
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/BinarySensorAttributes.cs b/src/CodeCasa.AutoGenerated/BinarySensorAttributes.cs
new file mode 100644
index 0000000..8d2a64e
--- /dev/null
+++ b/src/CodeCasa.AutoGenerated/BinarySensorAttributes.cs
@@ -0,0 +1,24 @@
+using System.Text.Json.Serialization;
+
+namespace CodeCasa.AutoGenerated;
+
+public partial record BinarySensorAttributes
+{
+ [JsonPropertyName("device_class")]
+ public string? DeviceClass { get; init; }
+
+ [JsonPropertyName("friendly_name")]
+ public string? FriendlyName { get; init; }
+
+ [JsonPropertyName("entity_id")]
+ public IReadOnlyList? EntityId { get; init; }
+
+ [JsonPropertyName("icon")]
+ public string? Icon { get; init; }
+
+ [JsonPropertyName("restored")]
+ public bool? Restored { get; init; }
+
+ [JsonPropertyName("supported_features")]
+ public double? SupportedFeatures { get; init; }
+}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/BinarySensorEntities.cs b/src/CodeCasa.AutoGenerated/BinarySensorEntities.cs
new file mode 100644
index 0000000..6e8ec33
--- /dev/null
+++ b/src/CodeCasa.AutoGenerated/BinarySensorEntities.cs
@@ -0,0 +1,24 @@
+using NetDaemon.HassModel;
+
+namespace CodeCasa.AutoGenerated;
+
+public partial class BinarySensorEntities
+{
+ private readonly IHaContext _haContext;
+
+ public BinarySensorEntities(IHaContext haContext)
+ {
+ _haContext = haContext;
+ }
+
+ /// Enumerates all binary_sensor entities currently registered (at runtime) in Home Assistant as BinarySensorEntity
+ public IEnumerable EnumerateAll() => _haContext.GetAllEntities()
+ .Where(e => e.EntityId.StartsWith("binary_sensor.")).Select(e => new BinarySensorEntity(e));
+
+ ///Bathroom Motion Sensor Occupancy
+ public BinarySensorEntity BathroomMotionSensorOccupancy => new(_haContext, "binary_sensor.bathroom_motion_sensor_occupancy");
+ ///Office Motion Sensor Occupancy
+ public BinarySensorEntity OfficeMotionSensorOccupancy => new(_haContext, "binary_sensor.office_motion_sensor_occupancy");
+ ///Upstairs Hallway Attic Motion Sensor Occupancy
+ public BinarySensorEntity UpstairsHallwayAtticMotionSensorOccupancy => new(_haContext, "binary_sensor.upstairs_hallway_attic_motion_sensor_occupancy");
+}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/BinarySensorEntity.cs b/src/CodeCasa.AutoGenerated/BinarySensorEntity.cs
new file mode 100644
index 0000000..03b9b6d
--- /dev/null
+++ b/src/CodeCasa.AutoGenerated/BinarySensorEntity.cs
@@ -0,0 +1,15 @@
+using NetDaemon.HassModel;
+using NetDaemon.HassModel.Entities;
+
+namespace CodeCasa.AutoGenerated;
+
+public partial record BinarySensorEntity : Entity, BinarySensorAttributes>, IBinarySensorEntityCore
+{
+ public BinarySensorEntity(IHaContext haContext, string entityId) : base(haContext, entityId)
+ {
+ }
+
+ public BinarySensorEntity(IEntityCore entity) : base(entity)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/CodeCasa.AutoGenerated.csproj b/src/CodeCasa.AutoGenerated/CodeCasa.AutoGenerated.csproj
index a773f5b..39289d3 100644
--- a/src/CodeCasa.AutoGenerated/CodeCasa.AutoGenerated.csproj
+++ b/src/CodeCasa.AutoGenerated/CodeCasa.AutoGenerated.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/src/CodeCasa.AutoGenerated/Extensions/GeneratedExtensions.cs b/src/CodeCasa.AutoGenerated/Extensions/GeneratedExtensions.cs
index 57cb376..7d72c44 100644
--- a/src/CodeCasa.AutoGenerated/Extensions/GeneratedExtensions.cs
+++ b/src/CodeCasa.AutoGenerated/Extensions/GeneratedExtensions.cs
@@ -10,12 +10,14 @@ public static IServiceCollection AddHomeAssistantGenerated(this IServiceCollecti
return serviceCollection
.AddTransient()
.AddTransient()
+ .AddTransient()
.AddTransient()
.AddTransient()
.AddTransient()
.AddTransient()
.AddTransient()
.AddTransient()
+ .AddTransient()
.AddTransient();
}
}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/LightAttributes.cs b/src/CodeCasa.AutoGenerated/LightAttributes.cs
index b272a2c..52da3cc 100644
--- a/src/CodeCasa.AutoGenerated/LightAttributes.cs
+++ b/src/CodeCasa.AutoGenerated/LightAttributes.cs
@@ -7,12 +7,12 @@ public partial record LightAttributes
[JsonPropertyName("supported_color_modes")]
public IReadOnlyList? SupportedColorModes { get; init; }
- [JsonPropertyName("friendly_name")]
- public string? FriendlyName { get; init; }
-
[JsonPropertyName("supported_features")]
public double? SupportedFeatures { get; init; }
+ [JsonPropertyName("color_mode")]
+ public string? ColorMode { get; init; }
+
[JsonPropertyName("min_color_temp_kelvin")]
public double? MinColorTempKelvin { get; init; }
@@ -25,39 +25,39 @@ public partial record LightAttributes
[JsonPropertyName("max_mireds")]
public double? MaxMireds { get; init; }
- [JsonPropertyName("effect_list")]
- public IReadOnlyList? EffectList { get; init; }
-
- [JsonPropertyName("color_mode")]
- public string? ColorMode { get; init; }
-
[JsonPropertyName("brightness")]
- public object? Brightness { get; init; }
+ public double? Brightness { get; init; }
[JsonPropertyName("color_temp_kelvin")]
- public object? ColorTempKelvin { get; init; }
+ public double? ColorTempKelvin { get; init; }
[JsonPropertyName("color_temp")]
- public object? ColorTemp { get; init; }
+ public double? ColorTemp { get; init; }
[JsonPropertyName("hs_color")]
- public object? HsColor { get; init; }
+ public IReadOnlyList? HsColor { get; init; }
[JsonPropertyName("rgb_color")]
- public object? RgbColor { get; init; }
+ public IReadOnlyList? RgbColor { get; init; }
[JsonPropertyName("xy_color")]
- public object? XyColor { get; init; }
+ public IReadOnlyList? XyColor { get; init; }
[JsonPropertyName("entity_id")]
public IReadOnlyList? EntityId { get; init; }
- [JsonPropertyName("icon")]
- public string? Icon { get; init; }
+ [JsonPropertyName("effect_list")]
+ public IReadOnlyList? EffectList { get; init; }
- [JsonPropertyName("restored")]
- public bool? Restored { get; init; }
+ [JsonPropertyName("color")]
+ public object? Color { get; init; }
[JsonPropertyName("effect")]
public object? Effect { get; init; }
+
+ [JsonPropertyName("icon")]
+ public string? Icon { get; init; }
+
+ [JsonPropertyName("friendly_name")]
+ public string? FriendlyName { get; init; }
}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/LightEntities.cs b/src/CodeCasa.AutoGenerated/LightEntities.cs
index 2e1c67b..dbdd1a3 100644
--- a/src/CodeCasa.AutoGenerated/LightEntities.cs
+++ b/src/CodeCasa.AutoGenerated/LightEntities.cs
@@ -26,5 +26,4 @@ public LightEntities(IHaContext haContext)
public LightEntity BackyardPergolaStringLights => new(_haContext, "light.backyard_pergola_string_lights");
///Backyard Porch Kerosene Light
public LightEntity BackyardPorchStringLights => new(_haContext, "light.backyard_porch_string_lights");
- ///Backyard String Lights
}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/SceneEntities.cs b/src/CodeCasa.AutoGenerated/SceneEntities.cs
new file mode 100644
index 0000000..2f06f77
--- /dev/null
+++ b/src/CodeCasa.AutoGenerated/SceneEntities.cs
@@ -0,0 +1,46 @@
+using NetDaemon.HassModel;
+using NetDaemon.HassModel.Entities;
+using System.Text.Json.Serialization;
+
+namespace CodeCasa.AutoGenerated;
+
+public partial class SceneEntities
+{
+ private readonly IHaContext _haContext;
+ public SceneEntities(IHaContext haContext)
+ {
+ _haContext = haContext;
+ }
+
+ /// Enumerates all scene entities currently registered (at runtime) in Home Assistant as SceneEntity
+ public IEnumerable EnumerateAll() => _haContext.GetAllEntities().Where(e => e.EntityId.StartsWith("scene.")).Select(e => new SceneEntity(e));
+
+ ///Living Room Ambiance
+ public SceneEntity LivingRoomAmbiance => new(_haContext, "scene.living_room_ambiance");
+}
+
+public partial record SceneEntity : Entity, SceneAttributes>, ISceneEntityCore
+{
+ public SceneEntity(IHaContext haContext, string entityId) : base(haContext, entityId)
+ {
+ }
+
+ public SceneEntity(IEntityCore entity) : base(entity)
+ {
+ }
+}
+
+public partial record SceneAttributes
+{
+ [JsonPropertyName("entity_id")]
+ public IReadOnlyList? EntityId { get; init; }
+
+ [JsonPropertyName("id")]
+ public string? Id { get; init; }
+
+ [JsonPropertyName("icon")]
+ public string? Icon { get; init; }
+
+ [JsonPropertyName("friendly_name")]
+ public string? FriendlyName { get; init; }
+}
\ No newline at end of file
diff --git a/src/CodeCasa.AutoGenerated/SensorAttributes.cs b/src/CodeCasa.AutoGenerated/SensorAttributes.cs
new file mode 100644
index 0000000..e814148
--- /dev/null
+++ b/src/CodeCasa.AutoGenerated/SensorAttributes.cs
@@ -0,0 +1,243 @@
+using System.Text.Json.Serialization;
+
+namespace CodeCasa.AutoGenerated;
+
+public partial record SensorAttributes
+{
+ [JsonPropertyName("icon")]
+ public string? Icon { get; init; }
+
+ [JsonPropertyName("friendly_name")]
+ public string? FriendlyName { get; init; }
+
+ [JsonPropertyName("assumed_state")]
+ public bool? AssumedState { get; init; }
+
+ [JsonPropertyName("time")]
+ public string? Time { get; init; }
+
+ [JsonPropertyName("device_class")]
+ public string? DeviceClass { get; init; }
+
+ [JsonPropertyName("restored")]
+ public bool? Restored { get; init; }
+
+ [JsonPropertyName("supported_features")]
+ public double? SupportedFeatures { get; init; }
+
+ [JsonPropertyName("attribution")]
+ public string? Attribution { get; init; }
+
+ [JsonPropertyName("Local Time")]
+ public string? LocalTime { get; init; }
+
+ [JsonPropertyName("Package")]
+ public string? Package { get; init; }
+
+ [JsonPropertyName("Time in Milliseconds")]
+ public double? TimeinMilliseconds { get; init; }
+
+ [JsonPropertyName("device_id")]
+ public string? DeviceId { get; init; }
+
+ [JsonPropertyName("device_name")]
+ public string? DeviceName { get; init; }
+
+ [JsonPropertyName("auth_token")]
+ public string? AuthToken { get; init; }
+
+ [JsonPropertyName("ip_address")]
+ public string? IpAddress { get; init; }
+
+ [JsonPropertyName("available")]
+ public bool? Available { get; init; }
+
+ [JsonPropertyName("next_alarm_status")]
+ public string? NextAlarmStatus { get; init; }
+
+ [JsonPropertyName("alarm_volume")]
+ public double? AlarmVolume { get; init; }
+
+ [JsonPropertyName("alarms")]
+ public IReadOnlyList