Skip to content

Commit

Permalink
cleanup and publish
Browse files Browse the repository at this point in the history
  • Loading branch information
grrowl committed Jan 27, 2024
1 parent 6c2b3d6 commit db5e6e8
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 40 deletions.
41 changes: 37 additions & 4 deletions README.md
Expand Up @@ -2,6 +2,9 @@

Control your homebridge instance with Javascript.

> [!WARNING]
> This plugin is very new, but since it's so useful and unique (no simpler homebridge automation approaches exist) I'm releasing it for constributors, testers, and as a request for feedback.
## Examples

(sorry this is so gnarly, we can improve the interface in `PLATFORM_SCRIPT`)
Expand All @@ -12,29 +15,57 @@ function onMessage(event) {
}
if (event.name === "Book Globe") {
}
}
```

When Dummy Switch is turned on, wait 5 seconds, then turn it Off.

```js
function onMessage(event) {
if (event.name === "Dummy Switch") {
const On = event.serviceCharacteristics.find((c) => c.name === "On");

if (On && On.value === 1) {
setTimeout(function () {
automation.set(event.uniqueId, On.iid, 0);
}, 5_000);
return true;
}
return false;
}
return null;
}
```

On Motion Sensed (Active), set Globe light to On

```js
function onMessage(event) {
if (event.name === "Motion Sensor") {
if (
event.serviceCharacteristics.find(
(c) => c.name === "Active" && c.value === true,
)
) {
const light = automation.services.find((s) => s.name === "Book Globe");
const light = automation.services.find((s) => s.name === "Globe");
if (light) {
const on = light.serviceCharacteristics.find((s) => s.type === "On");
if (on) {
automation.set(light.uniqueId, on.iid, 1);
}
}
automation.set();
}
}
}
```

## API

See `schemas/Service.ts` and `schemas/Characteristic.ts`
The `automation` object is available in your function module scope and defined in [`platformApi.ts`](https://github.com/grrowl/homebridge-plugin-automation/blob/main/src/platformApi.ts).

See [`schemas/Service.ts`](https://github.com/grrowl/homebridge-plugin-automation/blob/main/src/schemas/Service.ts) and [`schemas/Characteristic.ts`](https://github.com/grrowl/homebridge-plugin-automation/blob/main/src/schemas/Characteristic.ts).

Your function module scope is preserved between invocations, but is lost on Homebridge restart.

## Development

Expand All @@ -47,11 +78,13 @@ Simply run `npm run watch` to start. By default it uses the config at `~/.homebr
This runs segregated from your local network for more specific testing scenarios.

```shell
docker run --name=homebridge-automation -p 18581:8581 -v $(pwd)/homebridge:/homebridge -v $(pwd):/var/lib/homebridge-automation homebridge/homebridge:latest; docker rm homebridge-automation
docker run --name=homebridge-automation -p 18581:8581 -v $(pwd)/homebridge:/homebridge -v $(pwd):/var/lib/homebridge-plugin-automation homebridge/homebridge:latest; docker rm homebridge-automation
```

Then open homebridge UI: http://localhost:18581/

Note: because of our use of `isolated-vm`, linking your host node_modules/dist into a docker container of a different arch (e.g. arm64 or x86) won't work, with error "invalid ELF header"

---

### Link To Homebridge
Expand Down
2 changes: 1 addition & 1 deletion config.schema.json
Expand Up @@ -13,7 +13,7 @@
"required": false,
"placeholder": "function onMessage(event) {}",
"default": "function onMessage(event) {}",
"description": "Function to run on every change, must be called onEvent"
"description": "Function to run on every change, must be called onEvent. DO NOT ENTER UNTRUSTED CODE."
},
"pin": {
"title": "Homebridge PIN",
Expand Down
2 changes: 1 addition & 1 deletion homebridge/.uix-hb-service-homebridge-startup.json
Expand Up @@ -3,7 +3,7 @@
"keepOrphans": false,
"insecureMode": true,
"env": {
"DEBUG": "homebridge-plugin-ai",
"DEBUG": "homebridge-plugin-automation",
"NODE_ENV": "development",
"AI_UPSTREAM_API": "wss://host.containers.internal:3000"
}
Expand Down
4 changes: 2 additions & 2 deletions homebridge/startup.sh
@@ -1,4 +1,4 @@
#!/bin/bash

echo "adding homebridge-plugin-ai"
npm add file:/var/lib/homebridge-plugin-ai
echo "adding homebridge-plugin-automation"
npm add file:/var/lib/homebridge-plugin-automation
34 changes: 2 additions & 32 deletions src/platform.ts
Expand Up @@ -20,6 +20,7 @@ import { findConfigPin } from "./util/findConfigPin";
import { ServiceSchema } from "./schemas/Service";
import { ClientMessage, MetricsData } from "./schemas/ClientMessage";
import ivm from "isolated-vm";
import { PLATFORM_SCRIPT } from "./platformApi";

// how long after the last instance was discovered to start monitoring
const START_MONITORING_DELAY = 4_000;
Expand All @@ -34,37 +35,6 @@ const CONNECTION_RESET_DELAY = 5_000;

const VM_MEMORY_LIMIT_MB = 128;

const PLATFORM_SCRIPT = `
const automation = {
services: [];
handleMessage(message) {
if (message.type === "deviceStatusChange") {
onMessage(message.data);
const service = automation.services.find(s => s.uniqueId === message.data.uniqueId);
if (service) {
Object.assign(service, message.data);
}
}
if (message.type === "deviceList") {
automation.services = message.data;
}
}
set(serviceId, iid, value) {
__host({
version: 1,
type: "SetCharacteristic",
data: {
serviceId,
iid,
value,
},
});
}
}
`;

export class HomebridgeAutomation implements DynamicPlatformPlugin {
private socket?: WebSocket;
private reconnectAttempts = 0;
Expand Down Expand Up @@ -196,7 +166,7 @@ export class HomebridgeAutomation implements DynamicPlatformPlugin {
`automation.handleMessage($0);`,
[message],
);
this.log.debug(`Automation result:\n${JSON.stringify(result)}`);
this.log.debug(`Automation result: ${JSON.stringify(result)}`);
}

connectSocket(): void {
Expand Down
30 changes: 30 additions & 0 deletions src/platformApi.ts
@@ -0,0 +1,30 @@
export const PLATFORM_SCRIPT = `
const automation = {
services: [];
handleMessage(message) {
if (message.type === "deviceStatusChange") {
onMessage(message.data);
const service = automation.services.find(s => s.uniqueId === message.data.uniqueId);
if (service) {
Object.assign(service, message.data);
}
}
if (message.type === "deviceList") {
automation.services = message.data;
}
}
set(serviceId, iid, value) {
__host({
version: 1,
type: "SetCharacteristic",
data: {
serviceId,
iid,
value,
},
});
}
}
`;

0 comments on commit db5e6e8

Please sign in to comment.