homfy
v0.1.2
Published
Scriptable home automation server with fully typed object scheme
Readme
🔺 Homfy
Homfy is scriptable home automation server with auto-generated, fully typed home object scheme, plugin system, and CLI.
Install
npm install -g homfyQuick Start
# Start the server
homfy serve
# List all properties
homfy get
# Set a property value
homfy set livingRoom.on true
# Run an action
homfy run livingRoom.toggle
# See additional options
homfy -hKey concepts
- Plugins register objects (lights, sensors, switches, etc.)
- Objects have properties (boolean, integer, float, string, color), events, and actions
- Scripts define automations with type-safe triggers and conditions
- Schemas are auto-generated TypeScript types for your objects
- Plugins run in isolated Worker threads for stability and security
Writing a Plugin
Plugins are TypeScript files placed in ~/.homfy/plugins/. Each plugin exports a default function that receives a PluginAPI:
import type { PluginAPI } from "homfy";
export default function (plugin: PluginAPI) {
const light = plugin.registerObject("livingRoom", { name: "Living Room Light" });
light.defineProperty("on", { type: "boolean", writable: true, value: false });
light.defineProperty("brightness", { type: "integer", writable: true, value: 100 });
light.onSet("on", async (value) => {
plugin.log.info(`Light → ${value ? "ON" : "OFF"}`);
light.set("on", value);
});
light.defineAction("toggle", () => {
const current = light.get?.("on") ?? false;
light.set("on", !current);
return { on: !current };
});
plugin.on("stop", () => {
plugin.log.info("Plugin stopped");
});
}Writing a script
Scripts use auto-generated schemas for type-safe automations:
import { log, trigger } from "homfy";
import $ from "../schema/index.js";
// Toggle the living room light every day at 8:00 AM
trigger({
when: () => $.clock.time.is({ hour: 8, minute: 0, second: 0 }),
then: async () => {
const result = await $.livingRoomLight.toggle();
log.info(`Morning toggle: ${JSON.stringify(result)}`);
},
});
// Flash the light when the kitchen light turns on
trigger({
when: () => $.kitchenLight.on.eq(true),
then: async () => {
await $.livingRoomLight.flash(2);
},
});Homfy home directory structure
~/.homfy/
├── settings.json # Server settings (port, host)
├── plugins/ # Plugin files (.ts)
├── scripts/ # Automation scripts (.ts)
└── schema/ # Auto-generated TypeScript schemasTech Stack
- Runtime: Node.js ≥ 22, ESM, strict TypeScript
- HTTP: Hono
- CLI: Commander
- Plugin loader: jiti (TypeScript without a build step)
- Intentionally minimal dependencies
HTTP API
All endpoints are POST with JSON bodies, RPC-style:
| Endpoint | Description |
| ---------------- | -------------------------------- |
| health-check | Server status and uptime |
| plugins.list | List loaded plugins |
| objects.list | List all objects with properties |
| objects.get | Get a single object |
| objects.rename | Rename an object |
| props.get | Get a property value |
| props.set | Set a writable property |
| props.watch | SSE stream for property changes |
| actions.list | List available actions |
| actions.run | Invoke an action |
All paths are prefixed with /api/ (e.g. POST /api/objects.list).
