
Research
/Security News
Critical Vulnerability in NestJS Devtools: Localhost RCE via Sandbox Escape
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
CodeCasa.NetDaemon.Extensions.Observables
Advanced tools
Collection of extension methods meant to enhance NetDaemon entities with stateful and boolean observables allowing for more robust implementations and a more intuitive coding experience.
A collection of .NET libraries focused on NetDaemon extensions and utilities.
Package | Description |
---|---|
CodeCasa.NetDaemon.Notifications.Phone | This library provides the PhoneNotificationEntity class, making it easy to create, update, and manage phone notifications in Home Assistant. |
CodeCasa.NetDaemon.Notifications.InputSelect | This library helps you turn a Home Assistant Dropdown/InputSelect helper entity into a dynamic notifications list. |
CodeCasa.NetDaemon.RuntimeState | This library provides the NetDaemonRuntimeStateService , which allows you to check and subscribe to the runtime state of NetDaemon . |
CodeCasa.NetDaemon.Extensions.Observables | Collection of extension methods meant to enhance NetDaemon entities with boolean observables allowing for a more intuitive coding experience. |
This library provides the PhoneNotificationEntity
class, making it easy to create, update, and manage phone notifications in Home Assistant.
Features include:
Define an entity for a specific phone:
public class JasperPhoneNotifications(NotifyServices notificationServices, IHaContext haContext)
: PhoneNotificationEntity(haContext, notificationServices.MobileAppPixel7);
Register the entity as a service:
serviceCollection.AddTransient<JasperPhoneNotifications>();
Use it to send notifications (with optional actions):
[NetDaemonApp]
internal class Example
{
public Example(
LightEntities lightEntities,
JasperPhoneNotifications jasperPhoneNotifications)
{
var notificationId = $"{nameof(Example)}_Notification"; // Note: Using an ID that is consistent between runs also ensures that old notifications are removed/replaced on phones when the app is reloaded.
lightEntities.OfficeLights.SubscribeOnOff(
() =>
{
jasperPhoneNotifications.Notify(new AndroidNotificationConfig
{
Message = "Hey Jasper, the office lights are on!",
StatusBarIcon = "mdi:lightbulb",
Actions =
[
new(() => lightEntities.OfficeLights.TurnOff(), "Click here to turn them off.")
]
}, notificationId);
},
() => jasperPhoneNotifications.RemoveNotification(notificationId));
}
}
This automation sends a notification to Jasper’s phone whenever the office lights are turned on. The notification includes a button that allows him to turn off the lights directly from the notification:
For a more advanced demo like the example below, check out: https://github.com/DevJasperNL/CodeCasa
This library helps you turn a Home Assistant Dropdown/InputSelect helper entity into a dynamic notifications list.
I always liked Android’s dynamic notifications and wished for something similar in Home Assistant. While HA has a built‑in notification panel, it’s limited and somewhat hidden away. I wanted to display rich, actionable notifications directly on my own dashboard—without too much hassle.
Originally built as a quick solution, this implementation worked so well that I decided to share it. It stores notifications as JSON entries in an input_select
entity, including fields like message, icon, color, and actions. The library handles adding, updating, removing, and even executing actions for you.
One of the biggest upsides of this approach is that it keeps everything inside Home Assistant itself: your notifications persist in the state of the input_select entity
, surviving reboots or refreshes.
You can render these notifications in a custom UI (like my Blazor dashboard) or even with native Home Assistant templating. By default, the library uses a standard JSON format for entries, but you can define your own if needed.
First, update your appsettings.json
with an InputSelectNotificationEntities
array containing the input select entities you want to use as notification lists.
Optionally, you can add an InputNumberEntityId
to store the current notification count (handy for templating in dashboards):
"InputSelectNotificationEntities": [
{
"InputSelectEntityId": "input_select.living_room_panel_notifications"
},
{
"InputSelectEntityId": "input_select.jasper_notifications",
"InputNumberEntityId": "input_number.jasper_notification_count"
}
]
Register the service in your DI container:
serviceCollection.AddInputSelectNotifications(configuration);
Note: As an alternative, you can also provide configuration directly in code when calling
AddInputSelectNotifications
.
Inject the corresponding IInputSelectNotificationEntity
service using the input select entity ID as the key, and use it to create, update, or remove notifications:
[NetDaemonApp]
internal class Example
{
public Example([FromKeyedServices("input_select.living_room_panel_notifications")] IInputSelectNotificationEntity livingRoomPanelDashboardNotifications)
{
var notificationId = $"{nameof(Example)}_Notification";
livingRoomPanelDashboardNotifications.Notify(new InputSelectDashboardNotificationConfig
{
Message = "This is a notification.",
SecondaryMessage = "Click me to delete me!.",
Icon = "mdi:lightbulb",
IconColor = Color.Yellow,
Action = () => livingRoomPanelDashboardNotifications.RemoveNotification(notificationId)
}, notificationId);
}
}
Alternatively, you can wrap it in the provided InputSelectNotificationEntity
class and register that instead:
public class LivingRoomPanelDashboardNotifications(
[FromKeyedServices("input_select.living_room_panel_notifications")] IInputSelectNotificationEntity inputSelectNotifications)
: InputSelectNotificationEntity(inputSelectNotifications);
serviceCollection.AddTransient<LivingRoomPanelDashboardNotifications>();
Then inject and use it just like any other service:
[NetDaemonApp]
internal class Example
{
public Example(LivingRoomPanelDashboardNotifications livingRoomPanelDashboardNotifications)
{
...
}
}
Finally, to trigger an action, make sure to raise the following event:
HaContext.SendEvent("notification_clicked", new { notificationEntity = InputSelectEntities.LivingRoomPanelNotifications.EntityId, notificationIndex = index });
To display the notification using native Home Assistant templating, please follow this setup guide. Result:
Example implementations (including visualisation in Blazor): https://github.com/DevJasperNL/CodeCasa
This library provides the NetDaemonRuntimeStateService
, which allows you to check and subscribe to the runtime state of NetDaemon
.
While this service isn’t necessary when using NetDaemonApp
classes for automations, it can be useful in contexts where you access NetDaemon entities outside of that scope — for example, in a (Blazor) UI or background service. In such cases, NetDaemonRuntimeStateService
helps determine whether the NetDaemon runtime is initialized and connected.
The service exposes three possible states:
Register the service:
builder.Services.AddNetDaemonRuntimeStateService();
Then use it, for example, in a Blazor component:
@inject NetDaemonRuntimeStateService NetDaemonRuntimeStateService
@code {
private bool _netDaemonInitialized;
private bool _netDaemonConnected;
protected override void OnInitialized()
{
NetDaemonRuntimeStateService.ConnectedChangesWithCurrent().Subscribe(state =>
{
_netDaemonInitialized = state != NetDaemonStates.Initializing;
_netDaemonConnected = state == NetDaemonStates.Connected;
InvokeAsync(StateHasChanged);
});
}
}
or in a BackgroundService
:
internal class ExampleService : BackgroundService
{
private readonly NetDaemonRuntimeStateService _netDaemonRuntimeStateService;
public ExampleService(NetDaemonRuntimeStateService netDaemonRuntimeStateService)
{
_netDaemonRuntimeStateService = netDaemonRuntimeStateService;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
// Wait for the NetDaemon runtime to be initialized.
await _netDaemonRuntimeStateService.WaitForInitializationAsync(cancellationToken);
if (cancellationToken.IsCancellationRequested)
{
return;
}
// Implement code that works with NetDaemon entities here.
}
}
Example Blazor/BackgroundServices implementations: https://github.com/DevJasperNL/CodeCasa
Collection of extension methods meant to enhance NetDaemon entities with boolean observables allowing for a more intuitive coding experience.
public Example(
SunEntities sunEntities,
CoverEntities coverEntities)
{
const int curtainCloseSunElevation = 1;
sunEntities.Sun
.ToBooleanObservable(e => e.Attributes?.Elevation <= curtainCloseSunElevation);
sunIsDown.SubscribeTrueFalse(
() =>
{
coverEntities.LivingRoomFrontWindowCurtain.CloseCover();
coverEntities.LivingRoomBackWindowCurtain.CloseCover();
},
() =>
{
coverEntities.LivingRoomFrontWindowCurtain.OpenCover();
coverEntities.LivingRoomBackWindowCurtain.OpenCover();
});
}
Breakdown:
sunEntities.Sun.ToBooleanObservable(e => e.Attributes?.Elevation <= curtainCloseSunElevation);
Create a stateful IObservable<bool>
from the sun entity Sun
which emits true
when Elevation
is smaller than curtainCloseSunElevation
, false
otherwise. Stateful in this context means that the observable will immediately emit the current value returned from the predicate when an observer is subscribed. (internally, the NetDaemon extension methods StateChangesWithCurrent
and StateAllChangesWithCurrent
are used for this.)
sunIsDown.SubscribeTrueFalse(
() =>
{
coverEntities.LivingRoomFrontWindowCurtain.CloseCover();
coverEntities.LivingRoomBackWindowCurtain.CloseCover();
},
() =>
{
coverEntities.LivingRoomFrontWindowCurtain.OpenCover();
coverEntities.LivingRoomBackWindowCurtain.OpenCover();
});
SubscribeTrueFalse
is an extension method on IObservable<bool>
that assigns an action for when true
is emitted as well as when false
is emitted.
This implementation will immediately open or close the covers depending on the initial result of the predicate as well as update whenever the result of the predicate changes.
This library contains a set of extension methods to convert entities to implementations of IObservable<bool>
. If no predicate is provided, the On
state is mapped to true, the Off
state is mapped to false
.
The usage of ToBooleanObservable
(or one of the aliases ToOnOffObservable
or ToOpenClosedObservable
) on an entity will use StateChanges
(or StateAllChanges
when a predicate is provided) to result in a stateful IObservable<bool>
.
In case a stateful observable is not desired, the method ToChangesOnlyBooleanObservable
can be used.
The use of stateful IObservable<bool>
implementations enables the use of logic operators and scheduling extensions provided by the Reactive.Boolean
library. This allows for improved readability of implementations.
For a more detailed documentation on extension methods for IObservable<bool>
, check out the documentation for Reactive.Boolean
here.
Example
The following example shows the usage of boolean (Not
, Or
and And
) and scheduling (LimitTrueDuration
) logic to write a complex automation that is still easy to understand and will trigger on startup.
var noOneAsleep = inputBooleanEntities.JasperAsleep.ToBooleanObservable()
.Or(inputBooleanEntities.AnonAsleep.ToBooleanObservable()).Not();
var closetDoorOpenShorterThanOneMin = binarySensorEntities.BedroomClosetDoorSensorContact
.ToOpenClosedObservable().LimitTrueDuration(TimeSpan.FromMinutes(5), scheduler);
noOneAsleep.And(closetDoorOpenShorterThanOneMin).SubscribeTrueFalse(
() => lightEntities.ClosetLight.TurnOn(),
() => lightEntities.ClosetLight.TurnOff());
Note that even though scheduling is mostly handled by the Reactive.Boolean
library, knowledge of the Entity
does improve some scheduling methods. In the cases of WhenTrueFor
and LimitTrueDuration
both LastChanged
and the passing of time are used to evaluate whether a true is emitted.
A breakdown of all scheduling extension methods this library enables for Entity
and IObservable<bool>
:
Returns an observable that won't emit false
for at least the provided timespan after an initial on
(true
) is emitted by the entity
.
If a false
is emitted during the provided timespan, it will be emitted immediately after the timer is completed.
Example Use Case
Turn on a light for at least 3 seconds after a button was pressed. If 3 seconds are passed, only keep it on if the button is still being pressed, but immediately turn if off if not.
// buttonPressed is a IObservable<bool>
var buttonPressed = buttonEntity.ToBooleanObservable(s => s.State == "pressed");
buttonPressed
.TrueForAtLeast(TimeSpan.FromSeconds(3), scheduler)
.SubscribeTrueFalse(
() => lightEntity.TurnOn(),
() => lightEntity.TurnOff());
Aliases:
OpenForAtLeast
/TrueForAtLeast
.
Returns an observable that delays the first off
(false
) that is emitted after an on
(true
) by the entity
for a duration of the provided timespan.
Example Use Case
Keep a light on for 3 more seconds after last motion was detected.
// motionDetected is a IObservable<bool>
var motionDetected = motionSensorEntity.ToBooleanObservable(s => s.State == "motion");
motionDetected
.PersistTrueFor(TimeSpan.FromSeconds(3), scheduler)
.SubscribeTrueFalse(
() => lightEntity.TurnOn(),
() => lightEntity.TurnOff());
Aliases:
PersistOpenFor
/PersistTrueFor
.
Returns an observable that emits true
once entity
does not emit off
(false
) for a minimum of the provided timespan.
When called on an Entity
, this method takes into account EntityState.LastChanged
, meaning the returned observable can emit true
even if the time did not pass during runtime.
Example Use Case
Send notification when washing machine power has been 0 for at least 1 minute.
// washingMachineCurrentIsZero is a IObservable<bool>
var washingMachineCurrentIsZero = washingMachineCurrentEntity.ToBooleanObservable(s => s.State == 0);
washingMachineCurrentIsZero
.WhenTrueFor(TimeSpan.FromMinutes(1), scheduler)
.SubscribeTrue(() => notificationEntity.Send("Washing machine is done!"));
Aliases:
WhenOpenFor
/WhenTrueFor
.
Returns an observable that will automatically emit false
if the entity
does not emit an off
(false
) itself within the provided timespan after emitting on
(true
).
When called on an Entity
, this method takes into account EntityState.LastChanged
, meaning the returned observable can emit false
even if the time did not pass during runtime.
Example Use Case
Keep closet lights on for a maximum amount of time.
// closetDoorOpen is a IObservable<bool>
var closetDoorOpen = closetDoorEntity.ToBooleanObservable(s => s.State == "open");
closetDoorOpen
.LimitTrueDuration(TimeSpan.FromMinutes(2), scheduler)
.SubscribeTrueFalse(
() => closetLightEntity.TurnOn(),
() => closetLightEntity.TurnOff());
Aliases:
LimitOpenDuration
/LimitCloseDuration
.
This library also implements the utility method RepeatWhenEntitiesBecomeAvailable<T>
. This method can be called on a IObservable<T>
to repeat a value when one of the provided entities become available.
Example
The following example will re-apply the correct state as soon as the plug becomes available (is plugged in).
const int nightTimeSunElevation = 0;
var nightTime = sunEntities.Sun
.ToBooleanObservable(e => e.Attributes?.Elevation <= nightTimeSunElevation);
nightTime
.RepeatWhenEntitiesBecomeAvailable(switchEntities.LivingRoomChristmasTreeLights)
.SubscribeTrueFalse(
() => switchEntities.LivingRoomChristmasTreeLights.TurnOn(),
() => switchEntities.LivingRoomChristmasTreeLights.TurnOff());
FAQs
Collection of extension methods meant to enhance NetDaemon entities with stateful and boolean observables allowing for more robust implementations and a more intuitive coding experience.
We found that codecasa.netdaemon.extensions.observables demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
Product
Customize license detection with Socket’s new license overlays: gain control, reduce noise, and handle edge cases with precision.
Product
Socket now supports Rust and Cargo, offering package search for all users and experimental SBOM generation for enterprise projects.