-
-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: area service #46
base: main
Are you sure you want to change the base?
Conversation
Example usage:
|
GeneralInteresting approach, so this seems like a functional approach to defining scenes & their various interactions, where the other one is more declarative. The data structure doesn't work well for type validation, so I am mostly looking at it from that (using some techniques from hass / synapse) and how this might be most useful for both simple and complex use cases Current APIDefinitionsYou have it defined as an array, with a name property. It allows for name collisions, which can be less than ideal for devs who may accidentally set it up in an invalid way {
definitions: {
[name]: {
on, timeout, friendly_name
}
}
} The difference being that the TimeoutYou have timeout: () => ['home', '1_home', '1_sleep'].includes(homeModeSensor.state)
? { minutes: 30 } : { seconds: 10 }, You can find the Operations being performedBreaking down high level concerns I'm seeing here
|
Proposed structureThis as a structure would allow for a more flexible approach to types, and consolidate those individual operations slightly differently. Bit of chicken scratch / part way done for vibes ManageArea({
// simple metadata
area_id: TAareaId,
// definitions
definitions: {
[scene_id]: {
friendly_name: string,
// replace = this scene becomes primary scene when registered
// merge = this definition modifies
type: "replace" | "merge"
hooks: {
// registered hooks from lib
pre: { type: "delay", duration: "5s" },
// pass as async function
post: () => sleep(5000),
// issue service calls / etc
},
// can be empty if you only want access to hooks
definition: { ... current room definition / static },
},
},
// related states
flags: {
[flag_name]: {
onUpdate: entity_ref[],
value: () => boolean
},
occupied: {
onUpdate: [motionSensor, houseMode],
value: () => motionSensor.state === "" && .....
}
},
//
rules: {
default: "scene_id",
rules: [
]
}
}) You can use generic types to extract keys out of objects pretty easy, and use them as string unions elsewhere (like with the default scene near the bottom. This covers functionality from both the current rooms, as well as your dynamic triggers. The base scenes can type into rooms, and provide the same "eventually correct" logic. Where it will detect where things are different from their intended / declared state, and correct those after the fact Also gives access to hooks, which can refine the way a transition is implemented. Call a service, add a delay, log some stuff 🤷🏻♀️ You could even have one that does a delay on the pre, calls a service on the post, and has an empty definition. I believe that'd be close to some of the use cases you have going on here? Additional metadata ideas: ManageArea({
// feature flags for how to generate helper entities
generate: {
sceneSelect: true,
flagSwitches: true,
sceneEntities: true,
currentSceneSensor: true,
circadian: true,
}
}) |
Object over array for scene definitions makes sense. I didn't consider scene id conflicts. ✅ What would be the possible flags in the proposed structure? In the additional metadata ideas. For ui controls like (switch or select) I think instead of boolean flags it could be beneficial to have one option like
other notes:
thoughts? |
It'd be great if the scene definitions can be calculated via function also definition: {
high: {
definition: () => {
return evening? FULL_BRIGHTNESS : 80_PCT
}
}
} A big headache in my own flows is needing a As a neat side effect, the definition of "high" can be made to transition gradually (across a period of minutes) by doing fancy math in the definition. Would make some slower / more gradual effects much easier to pull off without having another random
Can be used to create calculated states, like the local storage that can be done with
These could optionally generate sensor entities on behalf of the dev, and automatically associate them with the room's device. Rooms & synapse entities provide a return value. The problem is that return value cannot be used within a callback, a variable would indirectly be used in it's own definition. Typescript would respond by silently turning values to For example: this looks to be valid code at first glance, and may or may not produce build errors (seen it both ways depending on details), but const entity = synapse.binary_sensor({
is_on() {
return !entity.is_on;
}
}) In order to work around, the callbacks need to provide data as params into the callback. Here is an extended example to show a more complex interaction CreateRoom({
flags: {
sleeping: {
type: "boolean",
default: false,
},
occupied: {
type: "string",
onUpdate: [isHomeSensor, motionSensor],
value: ({ scene, flags }) =>
isHomeSensor.is_on === false ||
flags.sleeping ||
(scene !== "off" && motionSensor.state === "on"),
},
},
definition: {
high: {
onUpdate: [isEveningSensor],
definition() {
return isEveningSensor.is_on ? FULL_BRIGHTNESS : PARTIAL_BRIGHTNESS;
},
},
auto: {
definition({ flags }) {
return flags.occupied ? PARTIAL_BRIGHTNESS : OFF;
},
},
},
}); Functions typically run on a 30s interval, onUpdate for provided entities, and when something about itself changes. In the case of sleeping - const room = CreateRoom(...);
// available to assign this way
room.flags.sleeping = true; |
On the other stuff, def! Like options that allow rolling your own / calculated implementation and putting control where it's most relevant. There's a few spots in the project where you can accomplish the same thing 3 ways, but the implications are different depending on where you put the flag. No issues with adding to that list, haha |
Thats a good call there should definitely be a way to auto switch scenes and/or transition between them. Still a little confused on what flags are. Are those like conditions or option toggles? |
Did a little rework of the input types. still room for improvement.
that way if its defined we know to use the
should circadian option be in the scene definition? |
Variables attached to the room basically. They can be reflected as entities in home assistant as the most appropriate entity type
Broken up as a:
In the case of nothing, the data can be persisted via the synapse sqlite db They wouldn't do anything you technically couldn't do with said entities, but this could generate all the entities & handle the coordination for you. The module config system has similar type interactions to this, where it converts objects with Since synapse allows the creation of sub-devices underneath the main one created by the app - all generated entities can be automatically associated with the room device Maybe flags is the wrong word, helpers? |
So far I've been doing a "circadian unless color is specified" approach. I haven't convinced myself that I'd ever want to just turn on to an unknown state with a scene definition. Is there a use case for you? |
No I don't actually know what it does haha. Just trying to sort out if it affects an area, all scenes, or a specific scene |
Gotcha! In that case it's a system that's intended to actively manage the color / temp (if supported) of a light. Brightness only lights are unsupported. It works by setting up a sensor that tracks the current light temp (related to sun position), and sending periodic color update requests to those devices so they are approx the sensor value. There's some internal shenanigans to not just flood everything with update requests As long as the scene doesn't say "turn on to this color", just brightness, the light might as well track solar temperature. Low hanging fruit for making the rooms feel nice |
Oh thats cool! Ok so I personally could see myself using that on a 'default' scene for an area. default would be like like normal lighting with circadian so the color temp adjusts throughout the day. If i have other scenes like 'chill', for example, with purple mood lighting, I wouldn't want circadian running. Does that seem like a correct mental model? |
Exactly! |
Ok got it. Sounds like it should be an option or flag for a particular scene. |
📬 Changes
Manages the state of an area, determining whether it is "occupied" or "vacant" based on presence triggers or a custom callback. Optionally integrates with scene controllers to adjust scenes based on area state.
🗒️ Checklist
code of conduct