@uboness/homebridge-tedee 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +59 -7
- package/config.schema.json +252 -134
- package/dist/bin/tedee-cleanup.d.ts +3 -0
- package/dist/bin/tedee-cleanup.d.ts.map +1 -0
- package/dist/bin/tedee-cleanup.js +85 -0
- package/dist/bin/tedee-cleanup.js.map +1 -0
- package/dist/device/device.d.ts +5 -3
- package/dist/device/device.d.ts.map +1 -1
- package/dist/device/device.js +13 -14
- package/dist/device/device.js.map +1 -1
- package/dist/device/index.d.ts +1 -0
- package/dist/device/index.d.ts.map +1 -1
- package/dist/device/index.js +1 -0
- package/dist/device/index.js.map +1 -1
- package/dist/device/lock.d.ts +24 -3
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +36 -8
- package/dist/device/lock.js.map +1 -1
- package/dist/settings.d.ts +8 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +9 -2
- package/dist/settings.js.map +1 -1
- package/dist/tedee-bridge.d.ts +53 -0
- package/dist/tedee-bridge.d.ts.map +1 -0
- package/dist/tedee-bridge.js +182 -0
- package/dist/tedee-bridge.js.map +1 -0
- package/dist/tedee-client.d.ts +1 -6
- package/dist/tedee-client.d.ts.map +1 -1
- package/dist/tedee-client.js +27 -58
- package/dist/tedee-client.js.map +1 -1
- package/dist/tedee-platform.d.ts +10 -34
- package/dist/tedee-platform.d.ts.map +1 -1
- package/dist/tedee-platform.js +70 -148
- package/dist/tedee-platform.js.map +1 -1
- package/dist/webhook-server.d.ts +28 -0
- package/dist/webhook-server.d.ts.map +1 -0
- package/dist/{tedee-event-server.js → webhook-server.js} +52 -15
- package/dist/webhook-server.js.map +1 -0
- package/package.json +5 -2
- package/dist/tedee-event-server.d.ts +0 -25
- package/dist/tedee-event-server.d.ts.map +0 -1
- package/dist/tedee-event-server.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.2.1](https://github.com/uboness/homebridge-tedee/compare/v0.2.0...v0.2.1) (2026-07-07)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* imports ([80244df](https://github.com/uboness/homebridge-tedee/commit/80244df6d034b343588ce3dbb53990369e121272))
|
|
11
|
+
|
|
12
|
+
## [0.2.0](https://github.com/uboness/homebridge-tedee/compare/v0.1.2...v0.2.0) (2026-07-07)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ⚠ BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
* the config format has changed from a single bridge to a
|
|
18
|
+
`bridges[]` array with shared `webhook` and `defaults` sections. Each bridge
|
|
19
|
+
now requires a unique, stable `id`. Because accessory UUIDs now include that
|
|
20
|
+
id, existing accessories are re-created and lose their room and automation
|
|
21
|
+
assignments. Run `tedee-cleanup <homebridge-config.json>` after upgrading to
|
|
22
|
+
remove the old `/tedee/events` callbacks left by the previous version.
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* multi-bridge support via a shared local webhook server ([9e6ea87](https://github.com/uboness/homebridge-tedee/commit/9e6ea873b412be25886c3ca1b2c67c1fd474d736))
|
|
27
|
+
|
|
5
28
|
## [0.1.2](https://github.com/uboness/homebridge-tedee/compare/v0.1.1...v0.1.2) (2026-07-06)
|
|
6
29
|
|
|
7
30
|
## 0.1.1 (2026-06-02)
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Homebridge plugin for Tedee locks using the local Tedee Bridge API only.
|
|
4
4
|
|
|
5
|
+
A single platform manages multiple Tedee bridges through one shared webhook server.
|
|
6
|
+
|
|
5
7
|
## Local Development
|
|
6
8
|
|
|
7
9
|
Install dependencies with pnpm:
|
|
@@ -10,7 +12,7 @@ Install dependencies with pnpm:
|
|
|
10
12
|
pnpm install
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
Edit `.homebridge/config.json` with your Tedee
|
|
15
|
+
Edit `.homebridge/config.json` with your Tedee bridge(s) IP/host and local API token.
|
|
14
16
|
|
|
15
17
|
Run Homebridge locally:
|
|
16
18
|
|
|
@@ -24,18 +26,68 @@ Run the Homebridge UI locally:
|
|
|
24
26
|
pnpm run ui
|
|
25
27
|
```
|
|
26
28
|
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
```jsonc
|
|
32
|
+
{
|
|
33
|
+
"platform": "Tedee",
|
|
34
|
+
"name": "Tedee",
|
|
35
|
+
"webhook": { "port": 8088 },
|
|
36
|
+
"defaults": {
|
|
37
|
+
"bridge": { "port": 80, "tokenMode": "encrypted", "unlockMode": 3, "lowBatteryThreshold": 20, "refreshInterval": 600000 },
|
|
38
|
+
"lock": { "pullSpringSwitch": false, "unlockMode": 3 }
|
|
39
|
+
},
|
|
40
|
+
"bridges": [
|
|
41
|
+
{
|
|
42
|
+
"id": "main",
|
|
43
|
+
"host": "192.168.1.139",
|
|
44
|
+
"token": "…",
|
|
45
|
+
"locks": [ { "id": 77178, "pullSpringSwitch": true } ]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "annex",
|
|
49
|
+
"host": "192.168.1.138",
|
|
50
|
+
"token": "…",
|
|
51
|
+
"locks": [ { "id": 77176 } ]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Each entry under `bridges` is one Tedee bridge, keyed by a unique, stable `id`.
|
|
58
|
+
- `defaults.bridge` / `defaults.lock` set values inherited by every bridge / lock; per-entry
|
|
59
|
+
settings override them.
|
|
60
|
+
- `webhook.host` is optional — leave it unset to auto-detect the local address each bridge
|
|
61
|
+
can reach the plugin on; set it only for unusual multi-subnet setups.
|
|
62
|
+
|
|
63
|
+
The bridge `id` is part of each accessory's identity and of the webhook path, so changing it
|
|
64
|
+
re-creates that bridge's accessories in HomeKit.
|
|
65
|
+
|
|
27
66
|
## Tedee Features
|
|
28
67
|
|
|
29
|
-
- Discovers all locks paired to
|
|
68
|
+
- Discovers all locks paired to each configured Tedee bridge.
|
|
30
69
|
- Exposes each lock as a HomeKit Lock Mechanism.
|
|
31
70
|
- Adds a Battery service per lock with battery level, low battery, and charging state.
|
|
32
|
-
- Adds a linked momentary Switch service for pulling the spring.
|
|
33
|
-
-
|
|
71
|
+
- Adds a linked momentary Switch service for pulling the spring (per-lock, optional).
|
|
72
|
+
- Runs one shared local callback server registered with every Tedee bridge.
|
|
34
73
|
|
|
35
74
|
## Webhook Registration
|
|
36
75
|
|
|
37
|
-
The callback server is mandatory and
|
|
76
|
+
The callback server is mandatory and managed by the plugin. It listens on `webhook.port`
|
|
77
|
+
(default `8088`) and receives events for every bridge at `/tedee/events/<bridgeId>`.
|
|
78
|
+
|
|
79
|
+
On startup, each bridge resolves the local address the Tedee bridge can reach the plugin on
|
|
80
|
+
(or uses `webhook.host` when set), registers a single POST callback tagged with an internal
|
|
81
|
+
`X-Homebridge-Tedee-Instance` secret header, updates it if the URL changed, and removes any
|
|
82
|
+
duplicates. The callback is removed from the bridge on shutdown, so a bridge removed from the
|
|
83
|
+
configuration doesn't leave an orphaned callback behind.
|
|
84
|
+
|
|
85
|
+
## Migrating from 0.1.x
|
|
38
86
|
|
|
39
|
-
|
|
87
|
+
The multi-bridge configuration is a breaking change and accessories are re-created. A
|
|
88
|
+
one-shot cleanup CLI removes the old callbacks left by the single-bridge version from your
|
|
89
|
+
bridges:
|
|
40
90
|
|
|
41
|
-
|
|
91
|
+
```sh
|
|
92
|
+
npx tedee-cleanup <path-to-homebridge-config.json> [--dry-run]
|
|
93
|
+
```
|
package/config.schema.json
CHANGED
|
@@ -11,168 +11,286 @@
|
|
|
11
11
|
"required": false,
|
|
12
12
|
"default": "Tedee"
|
|
13
13
|
},
|
|
14
|
-
"
|
|
15
|
-
"title": "
|
|
16
|
-
"type": "
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"default": 80,
|
|
25
|
-
"description": "The local Tedee Bridge API port."
|
|
26
|
-
},
|
|
27
|
-
"token": {
|
|
28
|
-
"title": "API Token",
|
|
29
|
-
"type": "string",
|
|
30
|
-
"required": true,
|
|
31
|
-
"description": "The local Bridge API token from the Tedee app."
|
|
32
|
-
},
|
|
33
|
-
"tokenMode": {
|
|
34
|
-
"title": "Token Mode",
|
|
35
|
-
"type": "string",
|
|
36
|
-
"required": false,
|
|
37
|
-
"default": "plain",
|
|
38
|
-
"oneOf": [
|
|
39
|
-
{
|
|
40
|
-
"title": "Plain",
|
|
41
|
-
"enum": [
|
|
42
|
-
"plain"
|
|
43
|
-
]
|
|
14
|
+
"webhook": {
|
|
15
|
+
"title": "Webhook Server",
|
|
16
|
+
"type": "object",
|
|
17
|
+
"description": "The local callback server the plugin runs to receive events from all Tedee bridges.",
|
|
18
|
+
"properties": {
|
|
19
|
+
"host": {
|
|
20
|
+
"title": "Webhook Host",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"required": false,
|
|
23
|
+
"description": "Optional. The address the Tedee bridges should reach this server on. Leave empty to auto-detect the local interface on each bridge's subnet."
|
|
44
24
|
},
|
|
45
|
-
{
|
|
46
|
-
"title": "
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
25
|
+
"port": {
|
|
26
|
+
"title": "Webhook Port",
|
|
27
|
+
"type": "number",
|
|
28
|
+
"required": false,
|
|
29
|
+
"default": 8088,
|
|
30
|
+
"minimum": 0,
|
|
31
|
+
"maximum": 65535
|
|
50
32
|
}
|
|
51
|
-
|
|
52
|
-
},
|
|
53
|
-
"apiVersion": {
|
|
54
|
-
"title": "Bridge API Version",
|
|
55
|
-
"type": "string",
|
|
56
|
-
"required": false,
|
|
57
|
-
"default": "v1.0"
|
|
33
|
+
}
|
|
58
34
|
},
|
|
59
|
-
"
|
|
60
|
-
"title": "
|
|
61
|
-
"type": "
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
]
|
|
35
|
+
"defaults": {
|
|
36
|
+
"title": "Defaults",
|
|
37
|
+
"type": "object",
|
|
38
|
+
"description": "Default settings applied to every bridge and lock. Individual bridges and locks can override these.",
|
|
39
|
+
"properties": {
|
|
40
|
+
"port": {
|
|
41
|
+
"title": "Bridge Port",
|
|
42
|
+
"type": "number",
|
|
43
|
+
"required": false,
|
|
44
|
+
"default": 80
|
|
70
45
|
},
|
|
71
|
-
{
|
|
72
|
-
"title": "
|
|
73
|
-
"
|
|
74
|
-
|
|
46
|
+
"tokenMode": {
|
|
47
|
+
"title": "Token Mode",
|
|
48
|
+
"type": "string",
|
|
49
|
+
"required": false,
|
|
50
|
+
"default": "encrypted",
|
|
51
|
+
"oneOf": [
|
|
52
|
+
{ "title": "Plain", "enum": [ "plain" ] },
|
|
53
|
+
{ "title": "Encrypted", "enum": [ "encrypted" ] }
|
|
75
54
|
]
|
|
76
55
|
},
|
|
77
|
-
{
|
|
78
|
-
"title": "
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
56
|
+
"apiVersion": {
|
|
57
|
+
"title": "Bridge API Version",
|
|
58
|
+
"type": "string",
|
|
59
|
+
"required": false,
|
|
60
|
+
"default": "v1.0"
|
|
82
61
|
},
|
|
83
|
-
{
|
|
84
|
-
"title": "
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
62
|
+
"lowBatteryThreshold": {
|
|
63
|
+
"title": "Low Battery Threshold",
|
|
64
|
+
"type": "number",
|
|
65
|
+
"required": false,
|
|
66
|
+
"default": 20,
|
|
67
|
+
"minimum": 1,
|
|
68
|
+
"maximum": 100
|
|
69
|
+
},
|
|
70
|
+
"refreshInterval": {
|
|
71
|
+
"title": "Refresh Interval",
|
|
72
|
+
"type": "number",
|
|
73
|
+
"required": false,
|
|
74
|
+
"default": 600000,
|
|
75
|
+
"description": "Periodic full refresh interval in milliseconds. Set to 0 to disable."
|
|
76
|
+
},
|
|
77
|
+
"lock": {
|
|
78
|
+
"title": "Lock Defaults",
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"pullSpringSwitch": {
|
|
82
|
+
"title": "Show Pull Spring Switch",
|
|
83
|
+
"type": "boolean",
|
|
84
|
+
"required": false,
|
|
85
|
+
"default": true
|
|
86
|
+
},
|
|
87
|
+
"unlockMode": {
|
|
88
|
+
"title": "Unlock Mode",
|
|
89
|
+
"type": "string",
|
|
90
|
+
"required": false,
|
|
91
|
+
"default": "without_pull",
|
|
92
|
+
"oneOf": [
|
|
93
|
+
{ "title": "Normal", "enum": [ "normal" ] },
|
|
94
|
+
{ "title": "Force", "enum": [ "force" ] },
|
|
95
|
+
{ "title": "Without Pull", "enum": [ "without_pull" ] },
|
|
96
|
+
{ "title": "Unlock Or Pull", "enum": [ "unlock_or_pull" ] }
|
|
97
|
+
],
|
|
98
|
+
"description": "Default unlock mode for all locks. 'Without Pull' avoids pulling the spring because a separate switch is exposed for that."
|
|
99
|
+
}
|
|
100
|
+
}
|
|
88
101
|
}
|
|
89
|
-
|
|
90
|
-
"description": "Mode used when HomeKit unlocks the main lock service. The default avoids pulling the spring because a separate switch is exposed for that."
|
|
91
|
-
},
|
|
92
|
-
"lowBatteryThreshold": {
|
|
93
|
-
"title": "Low Battery Threshold",
|
|
94
|
-
"type": "number",
|
|
95
|
-
"required": false,
|
|
96
|
-
"default": 20,
|
|
97
|
-
"minimum": 1,
|
|
98
|
-
"maximum": 100
|
|
99
|
-
},
|
|
100
|
-
"refreshInterval": {
|
|
101
|
-
"title": "Refresh Interval",
|
|
102
|
-
"type": "number",
|
|
103
|
-
"required": false,
|
|
104
|
-
"default": 600000,
|
|
105
|
-
"description": "Periodic full refresh interval in milliseconds. Set to 0 to disable."
|
|
106
|
-
},
|
|
107
|
-
"webhookPort": {
|
|
108
|
-
"title": "Webhook Port",
|
|
109
|
-
"type": "number",
|
|
110
|
-
"required": false,
|
|
111
|
-
"default": 8088,
|
|
112
|
-
"minimum": 0,
|
|
113
|
-
"maximum": 65535,
|
|
114
|
-
"description": "Local port used by the plugin's mandatory Tedee callback server. The callback host and path are managed automatically."
|
|
102
|
+
}
|
|
115
103
|
},
|
|
116
|
-
"
|
|
117
|
-
"title": "
|
|
104
|
+
"bridges": {
|
|
105
|
+
"title": "Bridges",
|
|
118
106
|
"type": "array",
|
|
119
107
|
"required": false,
|
|
120
108
|
"items": {
|
|
121
|
-
"title": "
|
|
109
|
+
"title": "Bridge",
|
|
110
|
+
"buttonText": "Add Bridge",
|
|
122
111
|
"type": "object",
|
|
123
112
|
"properties": {
|
|
124
113
|
"id": {
|
|
125
114
|
"title": "ID",
|
|
115
|
+
"type": "string",
|
|
116
|
+
"required": true,
|
|
117
|
+
"description": "A unique, stable identifier for this bridge (e.g. \"main\"). Changing it re-creates its accessories."
|
|
118
|
+
},
|
|
119
|
+
"host": {
|
|
120
|
+
"title": "Tedee Bridge IP/Host",
|
|
121
|
+
"type": "string",
|
|
122
|
+
"required": true,
|
|
123
|
+
"description": "The local IP address or hostname of the Tedee Bridge API."
|
|
124
|
+
},
|
|
125
|
+
"port": {
|
|
126
|
+
"title": "Bridge Port",
|
|
126
127
|
"type": "number",
|
|
127
|
-
"required":
|
|
128
|
+
"required": false,
|
|
129
|
+
"description": "The local Tedee Bridge API port. Falls back to the bridge default (80)."
|
|
128
130
|
},
|
|
129
|
-
"
|
|
130
|
-
"title": "
|
|
131
|
-
"type": "
|
|
131
|
+
"token": {
|
|
132
|
+
"title": "API Token",
|
|
133
|
+
"type": "string",
|
|
134
|
+
"required": true,
|
|
135
|
+
"description": "The local Bridge API token from the Tedee app."
|
|
136
|
+
},
|
|
137
|
+
"tokenMode": {
|
|
138
|
+
"title": "Token Mode",
|
|
139
|
+
"type": "string",
|
|
132
140
|
"required": false,
|
|
133
|
-
"
|
|
141
|
+
"oneOf": [
|
|
142
|
+
{ "title": "Plain", "enum": [ "plain" ] },
|
|
143
|
+
{ "title": "Encrypted", "enum": [ "encrypted" ] }
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"apiVersion": {
|
|
147
|
+
"title": "Bridge API Version",
|
|
148
|
+
"type": "string",
|
|
149
|
+
"required": false
|
|
134
150
|
},
|
|
135
|
-
"
|
|
136
|
-
"title": "
|
|
137
|
-
"type": "
|
|
151
|
+
"lowBatteryThreshold": {
|
|
152
|
+
"title": "Low Battery Threshold",
|
|
153
|
+
"type": "number",
|
|
138
154
|
"required": false,
|
|
139
|
-
"
|
|
155
|
+
"minimum": 1,
|
|
156
|
+
"maximum": 100
|
|
140
157
|
},
|
|
141
|
-
"
|
|
142
|
-
"title": "
|
|
158
|
+
"refreshInterval": {
|
|
159
|
+
"title": "Refresh Interval",
|
|
143
160
|
"type": "number",
|
|
144
161
|
"required": false,
|
|
145
|
-
"
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
"description": "Periodic full refresh interval in milliseconds. Set to 0 to disable."
|
|
163
|
+
},
|
|
164
|
+
"locks": {
|
|
165
|
+
"title": "Locks",
|
|
166
|
+
"type": "array",
|
|
167
|
+
"required": false,
|
|
168
|
+
"items": {
|
|
169
|
+
"title": "Lock",
|
|
170
|
+
"type": "object",
|
|
171
|
+
"properties": {
|
|
172
|
+
"id": {
|
|
173
|
+
"title": "ID",
|
|
174
|
+
"type": "number",
|
|
175
|
+
"required": true
|
|
176
|
+
},
|
|
177
|
+
"ignore": {
|
|
178
|
+
"title": "Ignore This Lock",
|
|
179
|
+
"type": "boolean",
|
|
180
|
+
"required": false,
|
|
181
|
+
"default": false
|
|
182
|
+
},
|
|
183
|
+
"pullSpringSwitch": {
|
|
184
|
+
"title": "Show Pull Spring Switch",
|
|
185
|
+
"type": "boolean",
|
|
186
|
+
"required": false
|
|
187
|
+
},
|
|
188
|
+
"unlockMode": {
|
|
189
|
+
"title": "Unlock Mode",
|
|
190
|
+
"type": "string",
|
|
191
|
+
"required": false,
|
|
192
|
+
"oneOf": [
|
|
193
|
+
{ "title": "Normal", "enum": [ "normal" ] },
|
|
194
|
+
{ "title": "Force", "enum": [ "force" ] },
|
|
195
|
+
{ "title": "Without Pull", "enum": [ "without_pull" ] },
|
|
196
|
+
{ "title": "Unlock Or Pull", "enum": [ "unlock_or_pull" ] }
|
|
197
|
+
],
|
|
198
|
+
"description": "Overrides the unlock mode for this specific lock. Falls back to the lock default."
|
|
199
|
+
}
|
|
169
200
|
}
|
|
170
|
-
|
|
171
|
-
"description": "Overrides the platform unlock mode for this specific lock. Falls back to the platform Unlock Mode setting when not set."
|
|
201
|
+
}
|
|
172
202
|
}
|
|
173
203
|
}
|
|
174
204
|
}
|
|
175
205
|
}
|
|
176
206
|
}
|
|
177
|
-
}
|
|
207
|
+
},
|
|
208
|
+
"layout": [
|
|
209
|
+
"name",
|
|
210
|
+
{
|
|
211
|
+
"type": "fieldset",
|
|
212
|
+
"title": "Advanced",
|
|
213
|
+
"labelHtmlClass": "fs-5",
|
|
214
|
+
"expandable": true,
|
|
215
|
+
"expanded": false,
|
|
216
|
+
"items": [
|
|
217
|
+
{
|
|
218
|
+
"type": "fieldset",
|
|
219
|
+
"title": "Webhook Server",
|
|
220
|
+
"labelHtmlClass": "fs-6",
|
|
221
|
+
"expandable": true,
|
|
222
|
+
"expanded": false,
|
|
223
|
+
"description": "The local callback server the plugin runs to receive events from all Tedee bridges.",
|
|
224
|
+
"items": [
|
|
225
|
+
"webhook.host",
|
|
226
|
+
"webhook.port"
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"type": "fieldset",
|
|
231
|
+
"title": "Bridge Defaults",
|
|
232
|
+
"labelHtmlClass": "fs-6",
|
|
233
|
+
"expandable": true,
|
|
234
|
+
"expanded": false,
|
|
235
|
+
"items": [
|
|
236
|
+
"defaults.port",
|
|
237
|
+
"defaults.tokenMode",
|
|
238
|
+
"defaults.apiVersion",
|
|
239
|
+
"defaults.lowBatteryThreshold",
|
|
240
|
+
"defaults.refreshInterval"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"type": "fieldset",
|
|
245
|
+
"title": "Lock Defaults",
|
|
246
|
+
"labelHtmlClass": "fs-6",
|
|
247
|
+
"expandable": true,
|
|
248
|
+
"expanded": false,
|
|
249
|
+
"items": [
|
|
250
|
+
"defaults.lock.pullSpringSwitch",
|
|
251
|
+
"defaults.lock.unlockMode"
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"key": "bridges",
|
|
258
|
+
"type": "array",
|
|
259
|
+
"title": "Bridges",
|
|
260
|
+
"buttonText": "Add Bridge",
|
|
261
|
+
"items": [
|
|
262
|
+
"bridges[].id",
|
|
263
|
+
"bridges[].host",
|
|
264
|
+
"bridges[].token",
|
|
265
|
+
{
|
|
266
|
+
"key": "bridges[]",
|
|
267
|
+
"type": "section",
|
|
268
|
+
"title": "Advanced",
|
|
269
|
+
"labelHtmlClass": "fs-6",
|
|
270
|
+
"expandable": true,
|
|
271
|
+
"expanded": false,
|
|
272
|
+
"items": [
|
|
273
|
+
"bridges[].port",
|
|
274
|
+
"bridges[].tokenMode",
|
|
275
|
+
"bridges[].apiVersion",
|
|
276
|
+
"bridges[].lowBatteryThreshold",
|
|
277
|
+
"bridges[].refreshInterval"
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"key": "bridges[].locks",
|
|
282
|
+
"type": "array",
|
|
283
|
+
"title": "Locks",
|
|
284
|
+
"labelHtmlClass": "fs-5",
|
|
285
|
+
"buttonText": "Add Lock",
|
|
286
|
+
"items": [
|
|
287
|
+
"bridges[].locks[].id",
|
|
288
|
+
"bridges[].locks[].ignore",
|
|
289
|
+
"bridges[].locks[].pullSpringSwitch",
|
|
290
|
+
"bridges[].locks[].unlockMode"
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
]
|
|
178
296
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tedee-cleanup.d.ts","sourceRoot":"","sources":["../../src/bin/tedee-cleanup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { WEBHOOK_PATH } from "../settings.js";
|
|
4
|
+
import { TedeeClient } from "../tedee-client.js";
|
|
5
|
+
const consoleLogger = () => {
|
|
6
|
+
const logger = {
|
|
7
|
+
debug: (message, ...params) => console.debug(message, ...params),
|
|
8
|
+
info: (message, ...params) => console.info(message, ...params),
|
|
9
|
+
warn: (message, ...params) => console.warn(message, ...params),
|
|
10
|
+
error: (message, ...params) => console.error(message, ...params),
|
|
11
|
+
getLogger: () => logger
|
|
12
|
+
};
|
|
13
|
+
return logger;
|
|
14
|
+
};
|
|
15
|
+
const isLegacyCallback = (url) => {
|
|
16
|
+
try {
|
|
17
|
+
return new URL(url).pathname === WEBHOOK_PATH;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
async function cleanupBridge(platform, dryRun, logger) {
|
|
24
|
+
if (!platform.host || !platform.token) {
|
|
25
|
+
logger.warn(`skipping Tedee platform with missing host/token`);
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
const client = new TedeeClient({
|
|
29
|
+
host: platform.host,
|
|
30
|
+
port: platform.port,
|
|
31
|
+
token: platform.token,
|
|
32
|
+
tokenMode: platform.tokenMode,
|
|
33
|
+
apiVersion: platform.apiVersion
|
|
34
|
+
}, logger);
|
|
35
|
+
const callbacks = await client.listCallbacks();
|
|
36
|
+
const legacy = callbacks.filter(callback => isLegacyCallback(callback.url));
|
|
37
|
+
if (legacy.length === 0) {
|
|
38
|
+
logger.info(`[${platform.host}] no legacy callbacks found`);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
let removed = 0;
|
|
42
|
+
for (const callback of legacy) {
|
|
43
|
+
if (dryRun) {
|
|
44
|
+
logger.info(`[${platform.host}] would remove legacy callback [${callback.url}] id [${callback.id}]`);
|
|
45
|
+
removed++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await client.deleteCallback(callback.id);
|
|
50
|
+
logger.info(`[${platform.host}] removed legacy callback [${callback.url}] id [${callback.id}]`);
|
|
51
|
+
removed++;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
logger.error(`[${platform.host}] failed to remove callback id [${callback.id}]`, error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return removed;
|
|
58
|
+
}
|
|
59
|
+
async function main() {
|
|
60
|
+
const args = process.argv.slice(2);
|
|
61
|
+
const dryRun = args.includes('--dry-run');
|
|
62
|
+
const configPath = args.find(arg => !arg.startsWith('--'));
|
|
63
|
+
if (!configPath) {
|
|
64
|
+
console.error('Usage: tedee-cleanup <path-to-homebridge-config.json> [--dry-run]');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const logger = consoleLogger();
|
|
68
|
+
const config = global.JSON.parse(readFileSync(configPath, 'utf8'));
|
|
69
|
+
const platforms = (config.platforms ?? []).filter(platform => platform.platform === 'Tedee');
|
|
70
|
+
if (platforms.length === 0) {
|
|
71
|
+
logger.warn(`no Tedee platforms found in [${configPath}]`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
logger.info(`found ${platforms.length} Tedee platform(s)${dryRun ? ' (dry run)' : ''}`);
|
|
75
|
+
let total = 0;
|
|
76
|
+
for (const platform of platforms) {
|
|
77
|
+
total += await cleanupBridge(platform, dryRun, logger);
|
|
78
|
+
}
|
|
79
|
+
logger.info(`${dryRun ? 'would remove' : 'removed'} ${total} legacy callback(s)`);
|
|
80
|
+
}
|
|
81
|
+
main().catch(error => {
|
|
82
|
+
console.error(error);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=tedee-cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tedee-cleanup.js","sourceRoot":"","sources":["../../src/bin/tedee-cleanup.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqBjD,MAAM,aAAa,GAAG,GAAY,EAAE;IAChC,MAAM,MAAM,GAAY;QACpB,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;QAChE,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;QAC9D,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;QAC9D,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;QAChE,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM;KAC1B,CAAC;IACF,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAW,EAAE;IAC9C,IAAI,CAAC;QACD,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,YAAY,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC,CAAC;AAEF,KAAK,UAAU,aAAa,CAAC,QAAkB,EAAE,MAAe,EAAE,MAAe;IAC7E,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC;IACb,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC;QAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;KAClC,EAAE,MAAM,CAAC,CAAC;IAEX,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,6BAA6B,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACb,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,mCAAmC,QAAQ,CAAC,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;YACrG,OAAO,EAAE,CAAC;YACV,SAAS;QACb,CAAC;QACD,IAAI,CAAC;YACD,MAAM,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,8BAA8B,QAAQ,CAAC,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;YAChG,OAAO,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,mCAAmC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5F,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,IAAI;IACf,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAE3D,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAA+B,CAAC;IACjG,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAE7F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,gCAAgC,UAAU,GAAG,CAAC,CAAC;QAC3D,OAAO;IACX,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,qBAAqB,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,KAAK,IAAI,MAAM,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,qBAAqB,CAAC,CAAC;AACtF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|