homebridge-mq77-customizer 1.5.0
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 +323 -0
- package/LICENSE +21 -0
- package/README.md +164 -0
- package/config.schema.json +258 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +14 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/json-topic/adapter.d.ts +50 -0
- package/dist/adapters/json-topic/adapter.js +270 -0
- package/dist/adapters/json-topic/adapter.js.map +1 -0
- package/dist/adapters/json-topic/keys.d.ts +27 -0
- package/dist/adapters/json-topic/keys.js +41 -0
- package/dist/adapters/json-topic/keys.js.map +1 -0
- package/dist/adapters/types.d.ts +90 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/zigbee2mqtt/adapter.d.ts +58 -0
- package/dist/adapters/zigbee2mqtt/adapter.js +416 -0
- package/dist/adapters/zigbee2mqtt/adapter.js.map +1 -0
- package/dist/adapters/zigbee2mqtt/exposes.d.ts +17 -0
- package/dist/adapters/zigbee2mqtt/exposes.js +110 -0
- package/dist/adapters/zigbee2mqtt/exposes.js.map +1 -0
- package/dist/adapters/zigbee2mqtt/protocol.d.ts +64 -0
- package/dist/adapters/zigbee2mqtt/protocol.js +9 -0
- package/dist/adapters/zigbee2mqtt/protocol.js.map +1 -0
- package/dist/build-info.json +5 -0
- package/dist/catalog.d.ts +69 -0
- package/dist/catalog.js +129 -0
- package/dist/catalog.js.map +1 -0
- package/dist/config.d.ts +34 -0
- package/dist/config.js +190 -0
- package/dist/config.js.map +1 -0
- package/dist/homekit/manager.d.ts +70 -0
- package/dist/homekit/manager.js +346 -0
- package/dist/homekit/manager.js.map +1 -0
- package/dist/homekit/mapping.d.ts +59 -0
- package/dist/homekit/mapping.js +367 -0
- package/dist/homekit/mapping.js.map +1 -0
- package/dist/homekit/names.d.ts +10 -0
- package/dist/homekit/names.js +65 -0
- package/dist/homekit/names.js.map +1 -0
- package/dist/homekit/roles.d.ts +44 -0
- package/dist/homekit/roles.js +140 -0
- package/dist/homekit/roles.js.map +1 -0
- package/dist/homekit/values.d.ts +33 -0
- package/dist/homekit/values.js +162 -0
- package/dist/homekit/values.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.js +16 -0
- package/dist/logger.js.map +1 -0
- package/dist/model/payload.d.ts +15 -0
- package/dist/model/payload.js +55 -0
- package/dist/model/payload.js.map +1 -0
- package/dist/model/types.d.ts +114 -0
- package/dist/model/types.js +11 -0
- package/dist/model/types.js.map +1 -0
- package/dist/mqtt/client.d.ts +43 -0
- package/dist/mqtt/client.js +129 -0
- package/dist/mqtt/client.js.map +1 -0
- package/dist/mqtt/topics.d.ts +4 -0
- package/dist/mqtt/topics.js +34 -0
- package/dist/mqtt/topics.js.map +1 -0
- package/dist/platform.d.ts +23 -0
- package/dist/platform.js +125 -0
- package/dist/platform.js.map +1 -0
- package/dist/rules/conditions.d.ts +26 -0
- package/dist/rules/conditions.js +94 -0
- package/dist/rules/conditions.js.map +1 -0
- package/dist/rules/convert.d.ts +13 -0
- package/dist/rules/convert.js +34 -0
- package/dist/rules/convert.js.map +1 -0
- package/dist/rules/engine.d.ts +168 -0
- package/dist/rules/engine.js +882 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/match.d.ts +22 -0
- package/dist/rules/match.js +112 -0
- package/dist/rules/match.js.map +1 -0
- package/dist/rules/types.d.ts +298 -0
- package/dist/rules/types.js +45 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/validate.d.ts +12 -0
- package/dist/rules/validate.js +369 -0
- package/dist/rules/validate.js.map +1 -0
- package/dist/settings.d.ts +13 -0
- package/dist/settings.js +14 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.d.ts +119 -0
- package/dist/store.js +270 -0
- package/dist/store.js.map +1 -0
- package/dist/web/auth.d.ts +20 -0
- package/dist/web/auth.js +75 -0
- package/dist/web/auth.js.map +1 -0
- package/dist/web/public/app.css +1356 -0
- package/dist/web/public/app.js +4235 -0
- package/dist/web/public/favicon.svg +27 -0
- package/dist/web/public/index.html +193 -0
- package/dist/web/server.d.ts +61 -0
- package/dist/web/server.js +510 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
## [1.5.0] - 2026-08-27
|
|
10
|
+
|
|
11
|
+
The first public release, on npm.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- The web interface says plainly that it belongs on your own network: anybody past its one password can switch every device it publishes
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Installed from npm, the way any Homebridge plugin is installed
|
|
20
|
+
|
|
21
|
+
## [1.4.1] - 2026-08-27
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Installing the plugin no longer asks for `sudo`, which `hb-service add` does not need
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- The build's progress messages go to stderr rather than stdout, so anything reading `npm pack --json` gets JSON and nothing else
|
|
30
|
+
|
|
31
|
+
## [1.4.0] - 2026-08-27
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- A device panel says under Diagnostics whether the broker keeps that device's messages, read from Zigbee2MQTT's own configuration, and the timestamp the device last reported for itself
|
|
36
|
+
- Test builds and releases are built on GitHub and published as an installable tarball, so a Raspberry Pi installs what GitHub compiled rather than compiling it itself
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- When a device was last heard now comes from the device rather than from this plugin, which no longer keeps arrival times of its own. Zigbee2MQTT publishes it once `advanced.last_seen` is turned on; a device that publishes none shows none, since a retained message replayed on connect says nothing about when the device spoke
|
|
41
|
+
- What a device is and the topic it lives on move off the card header onto the first line of the open panel, so the header reads as the name, when it was last heard, and what it became in HomeKit
|
|
42
|
+
- A device's functions are listed by name within Functions, Settings and Diagnostics, and the tile picker is called what it chooses: the HomeKit tile
|
|
43
|
+
- The README says what the settings are for and leaves naming them to the settings form, which describes its own fields more clearly. Installation is the command any plugin is installed with
|
|
44
|
+
|
|
45
|
+
## [1.3.0] - 2026-08-25
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- A Cycle button for sliders: one button for the whole range, stepping up to the top, back down to off, and up again. It starts upward whenever the level was last set by something else, and ignores a second press within a second, unlike the stepping buttons
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- The tabs become a dropdown below 960px rather than below 640px, aligned left with the Zigbee2MQTT link still at the end of the line. The Map is in the dropdown now, since a window that narrow can still draw one
|
|
54
|
+
- The Controllers tab draws two tables side by side where there is room, marks where one physical button gives way to the next, and drops the `Button | Action` heading row, which said what the two columns say themselves. `controller-config.md` keeps its heading, since a markdown table cannot do without one
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- The Clear button is back on the Activity tab, at the end of the line above the log. It was removed altogether when it should only have stood down on a phone, which is what it does now
|
|
59
|
+
|
|
60
|
+
## [1.2.0] - 2026-08-25
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- The Controllers tab says `In HomeKit` of a button whose press reaches HomeKit, in place of `none` where no rule answers it and underneath the rules where one does
|
|
65
|
+
- A HomeKit buttons tick in the header, beside Unused buttons, says whether those lines are wanted. With both down a button nothing answers is left out entirely, in the tables and in `controller-config.md` alike
|
|
66
|
+
|
|
67
|
+
## [1.1.0] - 2026-08-25
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
|
|
71
|
+
- A Controllers tab, listing every button of every remote and what it sets off. Buttons nothing answers read as `none` and can be hidden, and the whole overview downloads as `controller-config.md` to keep beside the remote
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
|
|
75
|
+
- A press and the rule it sets off read as one line in the activity log, `Woonkamer Remote 4 Single Long → Woonkamer: All Off - ran: 2 actions sent`. Presses that set nothing off keep a line of their own, and start hidden
|
|
76
|
+
- Actions read as buttons in the activity log too, `4 Single Long` rather than `4_single_long`
|
|
77
|
+
- A slider says what it did in the words somebody would use: `Brightness+ 1/6`, `Brightness- 0/6 (off)`, `On to Brightness 94`
|
|
78
|
+
- A mirror says which function it read and which it wrote: `Gang Voor State → Gang Achter State`
|
|
79
|
+
- A rule with more than one outcome says which one ran, in quotes
|
|
80
|
+
- Held back and nothing to do both read as `ignored`, and a timer called off says so without repeating why
|
|
81
|
+
- On a phone a log line stacks into what set it off, which rule, and what it did
|
|
82
|
+
|
|
83
|
+
## [1.0.0] - 2026-08-24
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- Settings can be downloaded and uploaded from the footer, which is the only copy that survives losing the machine
|
|
88
|
+
- The last ten dated copies of the settings are kept in a `backups` folder, one at startup and at most one an hour after that, and one can be taken on the spot from the footer
|
|
89
|
+
- A device that carries the same function more than once, such as a three gang switch, can put every channel into a mirror instead of one of them
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
|
|
93
|
+
- A remote's actions read as buttons, `1 Single Long` rather than `1_single_long`, and are listed in the order somebody would read them out
|
|
94
|
+
- Picking what sets a rule off marks with a `*` any value already used by another automation, slider or timer, so two rules do not end up on one button press by accident
|
|
95
|
+
- A rule just added stays at the top of the list until it is saved, including when the list is grouped by room, and has no enabled switch until then
|
|
96
|
+
- The footer reads left to right: which build this is, what the settings are doing, and the way out. It says when the last copy was taken and stacks onto two lines on a phone
|
|
97
|
+
- Descriptions break after the arrow rather than in the middle of what follows it, in rule lines and in the activity log
|
|
98
|
+
- Rule lists redraw far quicker, most of all when grouped by room. A panel is built when it is opened rather than for every rule in the list, sort keys are worked out once rather than inside every comparison, and devices are looked up by name rather than by walking the list
|
|
99
|
+
- A settings file that cannot be used says so in a dialog rather than in the corner of the header
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
- A run that starts with nothing refuses to write over a settings file that has something in it, and says so
|
|
104
|
+
|
|
105
|
+
## [0.16.1] - 2026-08-24
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
|
|
109
|
+
- Adding a device to a mirror did nothing. The function rows were redrawn with the new device in them, but the group behind them was only written back when something was clicked, so saving sent the members it had before
|
|
110
|
+
- Taking devices away until one was left kept a group of one, which mirrors nothing. The save was then refused for a reason nothing on the screen explained, since the row had already gone
|
|
111
|
+
|
|
112
|
+
## [0.16.0] - 2026-08-24
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- Signing out and the build label move to a footer at the foot of the page, and how the connection is doing becomes a word beside the title, green when live
|
|
117
|
+
- Switching a rule on or off is a tick box in its header, saved as it is clicked. It writes the stored rule with one thing changed, so turning something off does not push half written panel edits out with it
|
|
118
|
+
- The "In HomeKit only" and "Enabled only" filters are gone: a rule switched off is still a rule you are looking for
|
|
119
|
+
- The activity log reads as three columns with room to breathe, so every description starts in the same place, and can be emptied
|
|
120
|
+
- The add buttons read "+ automation", "+ outcome" and the like, and each tab's description says what it is for in one line
|
|
121
|
+
- Inputs and selects state their height, since the same padding on both left them a few pixels apart on one row
|
|
122
|
+
|
|
123
|
+
## [0.15.0] - 2026-08-23
|
|
124
|
+
|
|
125
|
+
### Added
|
|
126
|
+
|
|
127
|
+
- A Timers tab waits between one thing and another: a light coming on, thirty seconds, the light going out again. The clock starts again if the same thing happens again, and is called off the moment what started it stops being so, which an automation with a delayed action cannot do. A timer counting when Homebridge restarts is forgotten
|
|
128
|
+
- An automation or a timer can be run by hand from its panel, switched on or not, once it has been saved. The conditions still hold sway, and the button is absent while the panel and the stored rule disagree
|
|
129
|
+
|
|
130
|
+
## [0.14.0] - 2026-08-23
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
|
|
134
|
+
- Every device takes a name, a room and a kind of its own, set in its panel. They are for the interface: HomeKit keeps rooms in the Home app, where no accessory can set or read them. The name reaches HomeKit only where the source names nothing itself
|
|
135
|
+
- Eight kinds, each drawing an icon: Light, Sensor, Controller, Fan, TV, Audio device, Media device and Other
|
|
136
|
+
- The device list sorts into groups by room or by kind, and the rule lists by room, meaning the rooms a rule acts in. A rule reaching two rooms is listed under both
|
|
137
|
+
- Button presses from a device marked as a Controller appear in the Activity tab, with a filter of their own
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- A rule is named by the rooms it acts in rather than the room it is set off from: "Study: Nightlight toggle". The rooms come off only under a heading that has said all of them
|
|
142
|
+
- The line under a rule's name names devices and counts the rest, rather than spelling out which function of each it writes
|
|
143
|
+
- Under a room heading a device from another room keeps its room in its name, since which one it is still matters
|
|
144
|
+
- The activity log reads as a sentence, with the outcome and then what happened, and names devices the way every other list does
|
|
145
|
+
- Automation triggers and slider buttons are no longer joined by "or"
|
|
146
|
+
- The pencil rename button is gone: the name is one of the three fields now, and offered on every device
|
|
147
|
+
- Mirror and slider lists sort by name or room only
|
|
148
|
+
|
|
149
|
+
## [0.13.0] - 2026-08-23
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
|
|
153
|
+
- A Sliders tab drives a dimmer or a fan from buttons. The level is cut into steps and a press moves it one step, which as automations would be four to six rules that only make sense together. Either button switches the device on when it is off: step up goes to the level the device itself keeps, step down to the bottom of the range. Step down from the first step switches it off rather than leaving a light at zero brightness and still on
|
|
154
|
+
- Each slider button takes several triggers, so one slider can be driven by more than one remote
|
|
155
|
+
|
|
156
|
+
### Changed
|
|
157
|
+
|
|
158
|
+
- Delete on a rule sits at the far end of the footer, is red, and asks once before deleting anything that has been saved, going back to asking after two seconds. A rule only just added still goes on the first click
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- A rule just added disappeared when the list was filtered, or when "Enabled only" was ticked, since it is saved the moment it is added and so starts with a placeholder name and switched off
|
|
163
|
+
|
|
164
|
+
## [0.12.0] - 2026-08-22
|
|
165
|
+
|
|
166
|
+
### Added
|
|
167
|
+
|
|
168
|
+
- A Map tab draws the Zigbee network: the hub on the left and a column per hop out from it, so what reaches it directly and what goes through something else can be read down the page. Every link found is drawn, with the route each device uses picked out, and clicking a device says what it can hear and how well. A device the scan found but nothing connects to is drawn dashed rather than left out
|
|
169
|
+
- Automations sorted by trigger are listed under the device that sets them off, one line per trigger, so a remote with six buttons reads as six lines. A rule with several triggers appears under each of them
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
|
|
173
|
+
- An outcome is called what it was named in the activity log, falling back to its number
|
|
174
|
+
- A rule just added stays at the top of its list until it is saved, rather than sorting under a name nobody has chosen yet
|
|
175
|
+
- Sorting automations by target device is gone
|
|
176
|
+
- Mirror device selection runs down three columns instead of wrapping across the page
|
|
177
|
+
- Described devices sit behind a collapsed panel in the config form, with Rules only moved up under ID
|
|
178
|
+
|
|
179
|
+
### Fixed
|
|
180
|
+
|
|
181
|
+
- A child lock ticked on a socket showed nothing in the Home app. HomeKit allows a physical lock on its air services only, so on anything but a fan the lock now gets a switch of its own
|
|
182
|
+
- Every healthy router was reported as having failed the network scan, since an empty list of unanswered requests reads as true
|
|
183
|
+
- A tick box in the mirror editor was stretched to the width of a value box
|
|
184
|
+
|
|
185
|
+
## [0.11.0] - 2026-08-22
|
|
186
|
+
|
|
187
|
+
### Added
|
|
188
|
+
|
|
189
|
+
- A flat JSON source can describe functions a device has but never reports, such as the speed and swing of a fan. What was described is logged at startup, and a described topic nothing reports on is named in a warning alongside the topics that did
|
|
190
|
+
- Outcomes can be named, beside a remove button that is now a plain cross
|
|
191
|
+
|
|
192
|
+
### Changed
|
|
193
|
+
|
|
194
|
+
- The automation editor keeps "or", "and" and the buttons that add another on the row they belong to, instead of each on a line of its own
|
|
195
|
+
- Remove group sits at the top right of its box
|
|
196
|
+
- Outcomes are spaced apart and faintly shaded
|
|
197
|
+
- Rule rows have fixed widths, so the columns line up from one row to the next
|
|
198
|
+
- Number inputs are styled like every other input instead of unstyled, which is what made the delay box look out of place
|
|
199
|
+
- In the config form, described devices sit behind a collapsed panel and Rules only moved up under ID
|
|
200
|
+
|
|
201
|
+
### Fixed
|
|
202
|
+
|
|
203
|
+
- Sorting and filtering on the Automation and Mirror tabs, which threw on any rule saved since outcomes arrived and emptied both tabs without saying why
|
|
204
|
+
- The device picker in a rule was styled as a device card, since it shared its class
|
|
205
|
+
|
|
206
|
+
## [0.10.0] - 2026-08-21
|
|
207
|
+
|
|
208
|
+
### Changed
|
|
209
|
+
|
|
210
|
+
- The broker is configured as one address, `localhost:1883`, instead of a separate host and port. The port may be left off. A host and port stored separately are still read, so an existing install keeps its broker
|
|
211
|
+
- Broker username and password only appear once "Requires authentication" is ticked, and are ignored when it is not
|
|
212
|
+
|
|
213
|
+
## [0.9.1] - 2026-08-20
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
- Accessories are no longer dropped and re-added on every start. The catalog is empty before the broker answers because nothing has arrived, not because there is nothing, and removing an accessory makes HomeKit forget which room it is in
|
|
218
|
+
|
|
219
|
+
## [0.9.0] - 2026-08-20
|
|
220
|
+
|
|
221
|
+
### Added
|
|
222
|
+
|
|
223
|
+
- A rule can have several outcomes, each a condition and its own actions. The first that holds runs and the rest are skipped, which is if, else if and else
|
|
224
|
+
- Any outcome may be left without a condition, meaning it always holds
|
|
225
|
+
- The activity list says which outcome ran, and what each wanted when none did
|
|
226
|
+
|
|
227
|
+
## [0.8.0] - 2026-08-20
|
|
228
|
+
|
|
229
|
+
### Added
|
|
230
|
+
|
|
231
|
+
- Conditions are an expression: groups joined by or, tests within a group joined by and, and any group can be negated
|
|
232
|
+
- A rule can have several triggers, any of which fires it
|
|
233
|
+
- The interface header shows the version on a released build, or the branch it was built from on any other
|
|
234
|
+
|
|
235
|
+
### Changed
|
|
236
|
+
|
|
237
|
+
- Failing an or reports what every branch had against it, rather than only the first
|
|
238
|
+
|
|
239
|
+
## [0.7.0] - 2026-08-20
|
|
240
|
+
|
|
241
|
+
### Added
|
|
242
|
+
|
|
243
|
+
- Activity is its own tab, listing both kinds of rule with each entry saying which it came from
|
|
244
|
+
- Each tab offers the controls that suit it: In HomeKit only on Devices, Enabled only on the rule tabs, a checkbox per kind on Activity
|
|
245
|
+
- Rule lists can be ordered by name, or by the first device on either side, and filtered by the devices a rule touches as well as its name
|
|
246
|
+
|
|
247
|
+
### Changed
|
|
248
|
+
|
|
249
|
+
- Automation and mirrored devices are separate tabs rather than one list behind a checkbox
|
|
250
|
+
- Filters and orderings are kept per tab
|
|
251
|
+
|
|
252
|
+
## [0.6.1] - 2026-08-19
|
|
253
|
+
|
|
254
|
+
### Added
|
|
255
|
+
|
|
256
|
+
- Optional link to the Zigbee2MQTT interface in the tab bar, set with `web.zigbee2mqttUrl`
|
|
257
|
+
|
|
258
|
+
## [0.6.0] - 2026-08-19
|
|
259
|
+
|
|
260
|
+
### Added
|
|
261
|
+
|
|
262
|
+
- Sort the device list by name, topic, device or when it was last heard from
|
|
263
|
+
|
|
264
|
+
### Changed
|
|
265
|
+
|
|
266
|
+
- Device pickers in rules are always ordered by name, whatever the device list is sorted by
|
|
267
|
+
|
|
268
|
+
## [0.5.0] - 2026-08-19
|
|
269
|
+
|
|
270
|
+
### Added
|
|
271
|
+
|
|
272
|
+
- Rules engine: when something happens on one device, send something to another, across sources
|
|
273
|
+
- Triggers, optional conditions and one or more actions, with optional delays
|
|
274
|
+
- An action can send a fixed value or match whatever triggered the rule, translated into the target's terms
|
|
275
|
+
- Mirror rules: pick devices and the functions to keep in step, every member both trigger and target
|
|
276
|
+
- Rule editor and a run log in the web interface
|
|
277
|
+
- Devices whose source does not name them can be renamed, from a pencil in the card header
|
|
278
|
+
- Show when a device was last heard from, and the local time behind any timestamp value
|
|
279
|
+
- Filter devices by name, topic, model or manufacturer, and hide anything not in HomeKit
|
|
280
|
+
- Toggle offered as an action wherever a device understands one
|
|
281
|
+
|
|
282
|
+
### Changed
|
|
283
|
+
|
|
284
|
+
- Rules never run on retained messages, so reconnecting cannot replay an old press
|
|
285
|
+
- Per rule rate limit, a settling window for mirrors, and a rule that runs away is turned off and logged
|
|
286
|
+
- Accessory names are corrected to what HomeKit accepts, rather than warned about on every start
|
|
287
|
+
- Values that have not moved are no longer sent to HomeKit
|
|
288
|
+
- State is copied at startup, and what was loaded is reported in the log
|
|
289
|
+
|
|
290
|
+
### Fixed
|
|
291
|
+
|
|
292
|
+
- The interface is sent the words a device uses for on and off, instead of assuming ON and OFF
|
|
293
|
+
- Endpoints are named in rule dropdowns, so a device's channels can be told apart
|
|
294
|
+
- A characteristic with no value yet reports the last known one rather than failing the read
|
|
295
|
+
|
|
296
|
+
## [0.4.1] - 2026-08-18
|
|
297
|
+
|
|
298
|
+
### Changed
|
|
299
|
+
|
|
300
|
+
- Marked private, since the package is not published. `npm publish` now refuses rather than putting it on the registry by accident
|
|
301
|
+
- Installation documents the only route that works, installing from source, rather than leading with an npm package that does not exist
|
|
302
|
+
|
|
303
|
+
## [0.4.0] - 2026-08-18
|
|
304
|
+
|
|
305
|
+
First release. Everything below arrived across v0.1.0 to v0.4.0, none of which was published separately.
|
|
306
|
+
|
|
307
|
+
### Added
|
|
308
|
+
|
|
309
|
+
- Homebridge platform plugin connecting to one MQTT broker shared by every source
|
|
310
|
+
- Pluggable source adapters producing one normalised device model, so the HomeKit mapping never sees a source format
|
|
311
|
+
- Zigbee2MQTT source discovering devices and their functions from `bridge/devices`, updating live on joins, renames and removals
|
|
312
|
+
- `json-topic` source for publishers that put flat JSON on a topic per device, with properties inferred from the keys seen and unrecognised keys kept rather than dropped
|
|
313
|
+
- Sources can be marked rules only, for devices another plugin already publishes to HomeKit
|
|
314
|
+
- Password protected web interface listing every device and function, with live values over server sent events
|
|
315
|
+
- Tick a function to publish it to HomeKit, applied immediately with no Homebridge restart
|
|
316
|
+
- Tile type per endpoint, optional separate accessory per endpoint, and name overrides
|
|
317
|
+
- Rename devices whose source does not name them itself
|
|
318
|
+
- Filter devices by name, topic, model or manufacturer, and hide anything not in HomeKit
|
|
319
|
+
- HomeKit mapping for on/off, brightness, fan speed and swing, thermostat, temperature, humidity, battery and child lock
|
|
320
|
+
- Buttons inferred from the actions a device publishes, one service per physical button, with per gesture selection
|
|
321
|
+
- Property name to characteristic table, so a new kind of sensor needs no change to the mapper
|
|
322
|
+
- Functions with no HomeKit equivalent stay listed and marked, ready for the rules engine
|
|
323
|
+
- Persistent state under the Homebridge storage path, kept out of `config.json`
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Luud Jacobs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# MQ77 Customizer 1.5.0
|
|
2
|
+
|
|
3
|
+
**This Homebridge plugin has been 100% vibe coded using Claude Code.**
|
|
4
|
+
|
|
5
|
+
A Homebridge plugin that exposes MQTT devices to HomeKit and links them together, configured from a web interface instead of a config form. Devices and their functions are discovered from the broker, so nothing has to be typed out by hand.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 20.19, 22.12 or 24 and up
|
|
10
|
+
- Homebridge 1.8 or up
|
|
11
|
+
- An MQTT broker, for example Mosquitto
|
|
12
|
+
- Zigbee2MQTT, for the Zigbee2MQTT source
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Install it the way you install any Homebridge plugin, from the Plugins screen of the Homebridge UI or from the command line:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
hb-service add homebridge-mq77-customizer
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Settings
|
|
23
|
+
|
|
24
|
+
Everything is set in the plugin's settings form in the Homebridge UI, and each field says what it is for. There are three things to fill in:
|
|
25
|
+
|
|
26
|
+
- **MQTT Broker**, where your broker is and what it wants to be called
|
|
27
|
+
- **Sources**, one per publisher on that broker. A Zigbee2MQTT source needs its base topic, `zigbee2mqtt` unless you changed it. With no sources at all, that is what is assumed
|
|
28
|
+
- **Web Interface**, a port and a password. The interface can switch your devices, so it refuses to start without one
|
|
29
|
+
|
|
30
|
+
Everything else, which devices reach HomeKit and what they do between them, is set in the web interface itself.
|
|
31
|
+
|
|
32
|
+
### Sources
|
|
33
|
+
|
|
34
|
+
Two kinds. **Zigbee2MQTT** needs nothing but its base topic: it describes its own devices, so they arrive complete. **Flat JSON topics** reads any publisher that puts flat JSON on a topic per device, working the functions out from the keys it sees. Those accumulate across messages, so a partial update carrying one key does not redefine the device.
|
|
35
|
+
|
|
36
|
+
Recognised keys are `state`, `level`, `speed`, `swing`, `temperature`, `humidity` and `co2_levels`. Anything else still becomes a function, typed from its value, and stays available to the rules engine.
|
|
37
|
+
|
|
38
|
+
**Rules only** keeps a source's devices out of HomeKit while leaving them usable as rule triggers and targets. Set it where another plugin already publishes those devices, so they can't appear twice.
|
|
39
|
+
|
|
40
|
+
**Topic filter** narrows what a flat JSON source listens to, as an MQTT filter, `+` standing for one level and `#` for the rest. Everything under the base topic by default.
|
|
41
|
+
|
|
42
|
+
**Command topic suffix** is what is added to a device's topic to write to it, usually `set`. Without one the source is read only.
|
|
43
|
+
|
|
44
|
+
### Describing a device
|
|
45
|
+
|
|
46
|
+
A flat JSON topic carries no schema, so a function is only known once it has turned up in a payload. A fan that reports nothing but `state` until somebody changes its speed has no speed to tick. Name the missing functions under **Described devices** and they are there from the moment the device first reports.
|
|
47
|
+
|
|
48
|
+
A device is named by the part of its topic after the base topic: one publishing on `<base topic>/kitchen_fan` is written as `kitchen_fan`, though the whole topic is accepted too. Only the recognised keys above can be named, since a name on its own says nothing about the kind of value it carries. A function the device does report is left exactly as reported.
|
|
49
|
+
|
|
50
|
+
What was described is logged at startup, so a topic that matches no device is visible rather than silent.
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
Open `http://<your-homebridge-host>:8888`, or whichever port you set, and sign in with the password from the settings.
|
|
55
|
+
|
|
56
|
+
Keep it on your own network. Anybody who gets past that one password can switch every device the plugin publishes, so the port does not belong on the open internet or behind a port forward. Reach it from outside through a VPN, the way you would reach Homebridge itself.
|
|
57
|
+
|
|
58
|
+
Every device found on the broker is listed with all of its functions, grouped into functions, settings and diagnostics and listed by name within each. Tick a function to publish it to HomeKit. Changes take effect immediately, with no Homebridge restart.
|
|
59
|
+
|
|
60
|
+
Per device you can also:
|
|
61
|
+
|
|
62
|
+
- choose the HomeKit tile: Switch, Outlet, Lightbulb or Fan
|
|
63
|
+
- publish each endpoint as its own accessory, for multi channel switches
|
|
64
|
+
- give it a name, a room and a kind, which this interface uses to label and group it
|
|
65
|
+
|
|
66
|
+
Functions with no HomeKit equivalent are still listed and marked, and stay available to the rules engine rather than being hidden.
|
|
67
|
+
|
|
68
|
+
Accessory names are corrected to what HomeKit accepts, which must start and end with a letter or number. A name in brackets, `Hall light (front door)`, is published as `Hall light front door`. The name shown here is left as you wrote it.
|
|
69
|
+
|
|
70
|
+
### What reaches HomeKit
|
|
71
|
+
|
|
72
|
+
| Function | Becomes |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| on/off | Switch, Outlet, Lightbulb or Fan, your choice |
|
|
75
|
+
| brightness | Brightness on a Lightbulb |
|
|
76
|
+
| temperature, humidity | their sensor services |
|
|
77
|
+
| battery | a battery reading on the accessory, with a low warning |
|
|
78
|
+
| child lock | the physical controls lock on the tile |
|
|
79
|
+
| climate | a Thermostat, using the temperature range the device declares |
|
|
80
|
+
| speed, swing | a Fan with rotation speed and swing |
|
|
81
|
+
| button actions | one button per physical button, mapped to single, double and long press |
|
|
82
|
+
|
|
83
|
+
Button names and gestures are worked out from the action names the device publishes, so a double rocker becomes three buttons without anything being typed out. Gestures HomeKit has no equivalent for, such as triple press, stay available to the rules engine.
|
|
84
|
+
|
|
85
|
+
### Naming and grouping
|
|
86
|
+
|
|
87
|
+
Every device takes a name, a room and a kind, set in its panel. They are for this interface: HomeKit keeps rooms in the Home app, where no accessory can set or read them.
|
|
88
|
+
|
|
89
|
+
Marking a device as a Controller puts its button presses in the Activity tab, with their own filter. Only marked devices: every remote in the house reporting in would bury the rules.
|
|
90
|
+
|
|
91
|
+
The name reaches HomeKit only where the source names nothing itself, which is the flat JSON publishers. Zigbee2MQTT owns its own names, so one set here stays in this interface. Renaming never changes an accessory's identity, so nothing is lost in the Home app either way.
|
|
92
|
+
|
|
93
|
+
### Last seen and retainment
|
|
94
|
+
|
|
95
|
+
A device card says when the device was last heard, and its panel says the timestamp behind that along with whether the broker keeps its messages.
|
|
96
|
+
|
|
97
|
+
Both come from the source rather than from this plugin. When a message reached the broker is not an answer to when a device spoke: a retained message is replayed the moment the plugin connects, which would have every retaining device looking as though it had just reported. Zigbee2MQTT publishes the real answer once `advanced.last_seen` is set to something other than `disable`, and a flat JSON publisher that puts a `last_seen` in its payload is taken at its word the same way. A device that publishes no such time shows none, and sorting by Last seen puts those last.
|
|
98
|
+
|
|
99
|
+
Whether messages are retained is read from Zigbee2MQTT's own configuration, where three things decide it: the device's own `retain`, the `device_options` defaults it otherwise inherits, and `mqtt.force_disable_retain`, which overrides both. A source that keeps no such configuration says nothing rather than guessing.
|
|
100
|
+
|
|
101
|
+
### Controllers
|
|
102
|
+
|
|
103
|
+
The Controllers tab lists every device marked as a Controller, one table per remote, saying what each of its buttons sets off. A button no rule answers reads as `none`, or `In HomeKit` where the press reaches HomeKit as well, said under any rules it does answer. The Unused buttons and HomeKit buttons ticks in the header say which of those lines are wanted, and a button neither tick keeps is left out. Download writes the whole overview to `controller-config.md`, which follows the tick: hidden buttons are left out of the file too.
|
|
104
|
+
|
|
105
|
+
### Map
|
|
106
|
+
|
|
107
|
+
The Map tab draws the Zigbee network: what reaches the hub directly and what reaches it through something else. Every link found is drawn, and the route each device uses back to the hub is picked out.
|
|
108
|
+
|
|
109
|
+
A scan questions every device in turn, so it takes minutes on a mesh of any size and only runs when asked for. Zigbee2MQTT only: a flat JSON source has no network to describe.
|
|
110
|
+
|
|
111
|
+
### Activity
|
|
112
|
+
|
|
113
|
+
The Activity tab lists what the rules have been doing, newest first, including the ones that decided not to run and why. A press and the rule it set off read as one line, and each entry says which kind of rule it was. Presses that set nothing off have a filter of their own, off by default.
|
|
114
|
+
|
|
115
|
+
## Rules
|
|
116
|
+
|
|
117
|
+
Rules live in four tabs: Automation, Mirror devices, Sliders and Timers. Automation is the general one: when something happens on one device, send something to another. All four work across sources, so a Zigbee button can drive an infrared blaster, and apply the moment they are saved.
|
|
118
|
+
|
|
119
|
+
Across all four:
|
|
120
|
+
|
|
121
|
+
- anything readable can set a rule off, including functions that never reach HomeKit, and anything writable can be acted on
|
|
122
|
+
- an action can copy whatever set the rule off, restated in the target's own terms, so a switch that says `ON` can drive one that expects `true` and a dimmer counting to 254 can drive one counting to 100
|
|
123
|
+
- a rule with several outcomes runs the first whose condition holds and skips the rest
|
|
124
|
+
- picking what sets a rule off marks any value another rule already uses with a `*`, since two rules on one button press is a mistake nobody sees until both of them run
|
|
125
|
+
- rules never run on retained messages, so reconnecting to the broker cannot replay yesterday's button press
|
|
126
|
+
- a rule will not run more often than its rate limit, one second by default, and one that runs more than twenty times in ten seconds is switched off and logged on the assumption it is setting itself off
|
|
127
|
+
|
|
128
|
+
An automation or a timer can be run by hand with the Trigger button beside Save, whether or not it is switched on. Only what has been saved can be run.
|
|
129
|
+
|
|
130
|
+
### Mirror devices
|
|
131
|
+
|
|
132
|
+
Which devices, and which of their functions, should stay in step. Every member is both a trigger and a target. Functions are matched on meaning rather than on name, so a socket calling its on/off `state` mirrors a two channel switch calling the same thing `state_l1`.
|
|
133
|
+
|
|
134
|
+
After a write the group is left to settle, one and a half seconds by default and set per rule between 0.25 and 60 seconds. A device reporting its old state once more is indistinguishable from somebody flipping a switch, so without the pause a group that disagrees would send itself back and forth for ever. The cost is that flipping a mirrored device again inside the window is ignored.
|
|
135
|
+
|
|
136
|
+
### Timers
|
|
137
|
+
|
|
138
|
+
A wait between one thing and another: a light coming on, thirty seconds, the light going out again.
|
|
139
|
+
|
|
140
|
+
The clock starts again if the same thing happens again. It is called off the moment what started it stops being true: told to run when a light came on, it stops caring once the light is off, however that happened. A timer counting when Homebridge restarts is forgotten.
|
|
141
|
+
|
|
142
|
+
An automation with a delayed action does the first half of this and cannot be called off, which is the difference between the two.
|
|
143
|
+
|
|
144
|
+
### Sliders
|
|
145
|
+
|
|
146
|
+
A dimmer driven from buttons. One press moves one step. Down from the first step switches the device off rather than leaving a light at zero brightness and still on, and either stepping button switches it on when it is off.
|
|
147
|
+
|
|
148
|
+
Coming on from off lands where the device says it should, which Zigbee2MQTT keeps as `level_config.on_level`. "On at" sets it for a device that has no such setting, and without either it comes on at the first step.
|
|
149
|
+
|
|
150
|
+
Cycle is one button for the whole range: up to the top, back down to off, and up again from there. It starts upward whenever the level was last set by something other than the slider, and ignores a second press within a second, since it is a button to press rather than to hold.
|
|
151
|
+
|
|
152
|
+
Each button takes several triggers, so one slider can be driven by more than one remote. Stepping counts from what the slider last sent for a couple of seconds rather than from what the device last reported, so a held button that sends faster than the light can answer still climbs.
|
|
153
|
+
|
|
154
|
+
## Backup settings
|
|
155
|
+
|
|
156
|
+
Everything set here lives in `state.json` under the Homebridge storage path, alongside a `backups` folder holding the last ten dated copies. One is taken when the plugin starts, before anything is touched, and at most once an hour after that.
|
|
157
|
+
|
|
158
|
+
The footer offers `back up: download / upload`, along with when the last copy was taken and a way to take one now. Download hands you the lot as a file, which is the only copy that survives losing the machine it runs on. Upload takes one back, after copying what it replaces. The session secret is left out of the download and kept on upload, so a settings file is safe to keep somewhere else and putting one back does not sign you out.
|
|
159
|
+
|
|
160
|
+
A run that starts with nothing will not write over a file that has something in it. Somebody deleting their last rule is entitled to an empty file, but a run that began empty and is about to stamp on one that is not has misread something, and the file is worth more than the write. It says so in the log and in the interface rather than carrying on.
|
|
161
|
+
|
|
162
|
+
## Links
|
|
163
|
+
|
|
164
|
+
[License](https://github.com/LuudJacobs/homebridge-mq77-customizer/blob/main/LICENSE) • [Changelog](https://github.com/LuudJacobs/homebridge-mq77-customizer/blob/main/CHANGELOG.md)
|