homebridge-eliot-smart-control 1.3.0 → 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 CHANGED
@@ -6,6 +6,91 @@ adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.5.0] — 2026-09-21
10
+
11
+ ### Fixed
12
+
13
+ - **A new target while the desk is moving now works.** Cancelling a move sent
14
+ `STOP` and then a step command, as insurance for a control box too old to
15
+ know `STOP`. On a box driving a `GOTO_HEIGHT` that step starts a small move
16
+ of its own, and the replacement target arrives in the middle of it — which is
17
+ a command arriving mid-move, the one thing this box answers by giving up. The
18
+ desk took the 4 mm step and ignored where it had been told to go, so setting
19
+ the slider to 65% moved it by one. `STOP` alone now, followed by a pause long
20
+ enough for the desk to finish coasting before it is given somewhere new.
21
+ - **The idle poll no longer cancels a move.** It skipped polling while the
22
+ plugin was driving the desk, but not while the *control box* was — which is
23
+ precisely the case that must not be polled, because `SETTINGS` is a command
24
+ and one arriving mid-move makes the box abandon it. The move died, the desk
25
+ stopped short, and the box then looked like one that had never understood
26
+ `GOTO_HEIGHT`, so the step-command fallback took over and the position
27
+ jumped. Dragging the slider was where this showed.
28
+ - **Service names are back, and the room can be changed.** `ConfiguredName` is
29
+ what the Home app displays for a bridged accessory's services — without it
30
+ every switch shows as "Schalter 1", "Schalter 2" and so on — but Switch,
31
+ MotionSensor and WindowCovering do not list it, so it has to be declared with
32
+ `addOptionalCharacteristic` before it is set. Setting it undeclared made
33
+ Homebridge warn on every start and left an accessory the Home app would not
34
+ fully edit. It is also written only when empty, so a name given in the Home
35
+ app stays.
36
+
37
+ ### Added
38
+
39
+ - **Automatic sit/stand movement.** Set a sitting height, a standing height, an
40
+ interval and the hours it applies to, and the desk alternates between them.
41
+ It arrives switched off behind an **Auto Movement** switch in the Home app,
42
+ because starting to move somebody's furniture on the strength of a config
43
+ file being saved is not a good first impression.
44
+ - **A *Desk Move Soon* sensor**, tripped a few minutes before each move. It is
45
+ a motion sensor because HomeKit gives an accessory no way to send a
46
+ notification and a sensor is the one thing the Home app will offer to notify
47
+ about; turning that on is a one-time step in the Home app that nothing here
48
+ can do for you.
49
+ - **The settings page checks the pairs of values the schema cannot.** A warning
50
+ that is not shorter than the interval, a sitting height above the standing
51
+ one, and a working-hours entry that is not a time range are all said while
52
+ they are being typed, rather than in the Homebridge log after a restart where
53
+ nobody is looking.
54
+ - **A warning of 0 turns the warning off** and takes the *Desk Move Soon*
55
+ sensor out of the Home app with it. A motion sensor that can never report
56
+ motion is a thing in somebody's house that does nothing and cannot be
57
+ explained.
58
+ - **Moving the desk by hand restarts the timer**, which makes a nudge on the
59
+ handset the snooze: the warning says it is about to move, you touch the
60
+ handset, and you have another interval.
61
+
62
+ ### Changed
63
+
64
+ - **Slider targets are allowed to settle before one is acted on.** A drag is
65
+ dozens of them, and each taken literally meant stopping the desk, waiting out
66
+ its coast and handing it somewhere new. Seven targets now make one command.
67
+ - **A target the desk is already at is not a move.** The Home app sends the
68
+ current position the moment the slider is touched, and the desk was setting
69
+ off towards where it already was — the small movement before the real one.
70
+ - **The settings page says less, and says it once.** Field hints had grown into
71
+ paragraphs and the sit/stand section said the same thing twice. What was cut
72
+ is in the README, where the long version belongs.
73
+ - **The dongle is no longer described as advertising under one particular
74
+ name.** It carries whatever name the desk was given in the Eliot app, which
75
+ on many units is nothing useful. The scan always matched the service UUID
76
+ instead, which does not depend on what anybody called it.
77
+
78
+ ## [1.4.0] — 2026-09-21
79
+
80
+ ### Changed
81
+
82
+ - **Eco mode now means travel speed 20**, not 28. 28 was where the Eliot app
83
+ stops offering, which turned out to be a fact about the app rather than the
84
+ control box — the desk here was found storing 21, a value no version of the
85
+ app could have written, and took 21 back without complaint. Eco mode that is
86
+ barely slower than no eco mode is not worth resetting a desk to switch on.
87
+ - **Switches are called what they are** — *Memory 1*, *Child Lock* — instead of
88
+ carrying the desk's name in front of them. The Home app already shows which
89
+ accessory a switch belongs to, and *Schreibtisch Memory 1* said it twice.
90
+ Switches named by an earlier version are renamed on the next start, but only
91
+ where the name is still exactly what that version wrote: anything else is
92
+ yours, including a rename that happens to begin with the desk's name.
93
+
9
94
  ## [1.3.0] — 2026-09-21
10
95
 
11
96
  ### Removed
@@ -261,7 +346,9 @@ First release.
261
346
  verified against hardware, including the measured travel speed and stopping
262
347
  distance.
263
348
 
264
- [Unreleased]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.3.0...HEAD
349
+ [Unreleased]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.5.0...HEAD
350
+ [1.5.0]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.4.0...v1.5.0
351
+ [1.4.0]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.3.0...v1.4.0
265
352
  [1.3.0]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.2.0...v1.3.0
266
353
  [1.2.0]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.1.0...v1.2.0
267
354
  [1.1.0]: https://github.com/rummeyer/homebridge-eliot-smart-control/compare/v1.0.0...v1.1.0
package/README.md CHANGED
@@ -67,11 +67,11 @@ your other accessories.
67
67
  desks**.
68
68
 
69
69
  This is the part worth having help with. The dongle does not announce itself:
70
- it appears as **`Schreibtisch`**, with no manufacturer name, and many units
71
- have nothing printed on them — in a scan list it sits among forty anonymous
72
- phones with nothing to tell them apart. The page looks for the Bluetooth
73
- service the desk actually speaks, so a result marked *confirmed* is the right
74
- device and not a good guess.
70
+ it advertises under whatever name the desk was given in the Eliot app, carries
71
+ no manufacturer name, and many units have nothing printed on them — in a scan
72
+ list it sits among forty anonymous phones with nothing to tell them apart. The
73
+ page looks for the Bluetooth service the desk actually speaks, so a result
74
+ marked *confirmed* is the right device and not a good guess.
75
75
 
76
76
  Press **Use this** next to yours, name it, and save.
77
77
 
@@ -92,6 +92,7 @@ dongle for five seconds.
92
92
  | **Memory switches** | on | Offer your stored positions as buttons. Rename them in the Home app |
93
93
  | **Child lock switch** | on | Offer the desk's child lock |
94
94
  | **Eco mode** | leave alone | Eco mode and travel speed, as a pair. Takes effect only after the desk is reset by hand |
95
+ | **Automatic sit/stand** | off | Move between two heights on a timer, during configured hours |
95
96
 
96
97
  Or by hand, in `config.json`:
97
98
 
@@ -100,7 +101,7 @@ Or by hand, in `config.json`:
100
101
  "platform": "EliotSmartControl",
101
102
  "desks": [
102
103
  {
103
- "name": "Schreibtisch",
104
+ "name": "Desk",
104
105
  "mac": "E5:11:22:33:44:55",
105
106
  "ecoMode": "off"
106
107
  }
@@ -108,6 +109,31 @@ Or by hand, in `config.json`:
108
109
  }
109
110
  ```
110
111
 
112
+ ## Automatic sit/stand
113
+
114
+ Configure it, and the desk gains an **Auto Movement** switch. Nothing moves
115
+ until you turn that on — the switch is the feature's on/off, so that turning it
116
+ off is somewhere obvious rather than in a config file.
117
+
118
+ Once on, inside the hours you have set, the desk alternates between your
119
+ sitting and standing heights. It always heads for whichever of the two it is
120
+ further from, so a desk parked halfway still does the right thing.
121
+
122
+ **Moving the desk yourself restarts the timer.** That is the snooze: when the
123
+ warning says it is about to move and you are mid-call, nudge the desk with the
124
+ handset and you have bought another interval. It is also simply true — the
125
+ timer measures time spent at a height, and that clock restarts when the height
126
+ does.
127
+
128
+ **Getting told about it takes one step you have to do yourself.** HomeKit gives
129
+ a plugin no way to send a notification, so the warning is a motion sensor
130
+ called **Desk Move Soon**. Open it in the Home app, and under *Status and
131
+ Notifications* turn notifications on. Nothing here can do that for you, and if
132
+ you never do it the feature still works, silently.
133
+
134
+ Outside the configured hours nothing moves and no warning is raised — a phone
135
+ buzzing at 17:05 about a move that will never happen is worse than silence.
136
+
111
137
  ## Things worth knowing
112
138
 
113
139
  **Positions land exactly.** The desk is handed a height and drives there on its
@@ -128,6 +154,18 @@ its button appears the next time the plugin connects.
128
154
  and the plugin names them only once, when it first creates them, so whatever
129
155
  you rename them to survives restarts.
130
156
 
157
+ **Eco mode is stored now and takes effect later.** The control box keeps
158
+ running whatever it was last reset with, so the settings it reports back can
159
+ differ from the speed it is visibly travelling at. A reset by hand — run the
160
+ desk to the bottom and hold the down key until it re-homes — is what makes a
161
+ stored setting live. No command over this connection can do it.
162
+
163
+ **The idle refresh is only for what happens between moves.** The control box
164
+ streams its height for as long as it is driving itself, so nothing needs asking
165
+ then. It is also why the poll must stay in seconds: a request arriving while
166
+ the box is moving makes it abandon the move, which looks exactly like a desk
167
+ that stops a centimetre after it starts.
168
+
131
169
  **The desk's own safety features are untouched.** Anti-collision and the soft
132
170
  limits live in the control box. The plugin adds limits of its own on top: it
133
171
  gives up if the desk stops making progress, if a move takes longer than the
@@ -3,7 +3,7 @@
3
3
  "pluginType": "platform",
4
4
  "singular": true,
5
5
  "headerDisplay": "Control an Eliot sit-stand desk with the Smart Dongle from the Home app, over Bluetooth. Requires Linux — the plugin talks to BlueZ.",
6
- "footerDisplay": "The dongle advertises as **Schreibtisch** and has no vendor name, so it can be hard to spot. Run `node tools/eliot-probe.js scan` on the Homebridge host to find its address.\n\nThe desk appears as a window covering: 0% is the lowest height it is set to allow, 100% the highest. Those come from the desk's own limits, so changing them on the handset changes what 0% and 100% mean.",
6
+ "footerDisplay": "The dongle advertises under whatever name the desk has been given in the Eliot app, and carries no manufacturer name, so there is often nothing in a scan list to pick it out by. The scan above matches on the Bluetooth service it speaks instead, which is the same whatever it is called.\n\nThe desk appears as a window covering: 0% is the lowest height it is set to allow, 100% the highest. Those come from the desk's own limits, so changing them on the handset changes what 0% and 100% mean.",
7
7
  "schema": {
8
8
  "type": "object",
9
9
  "properties": {
@@ -23,8 +23,8 @@
23
23
  "title": "Name",
24
24
  "type": "string",
25
25
  "required": true,
26
- "default": "Schreibtisch",
27
- "placeholder": "Schreibtisch",
26
+ "default": "Desk",
27
+ "placeholder": "Desk",
28
28
  "description": "What the desk is called in the Home app."
29
29
  },
30
30
  "mac": {
@@ -40,19 +40,19 @@
40
40
  "type": "integer",
41
41
  "default": 30,
42
42
  "minimum": 0,
43
- "description": "How often to ask a standing desk for its height. The desk reports by itself while the control box is driving, so this only catches the handset being used. 0 turns it off. Leave it in seconds, not milliseconds: asking mid-move cancels the move."
43
+ "description": "How often to ask a standing desk for its height, which is how the handset being used gets noticed. 0 turns it off; keep it in seconds, not milliseconds."
44
44
  },
45
45
  "memorySwitches": {
46
46
  "title": "Memory switches",
47
47
  "type": "boolean",
48
48
  "default": true,
49
- "description": "Offer the desk's memory positions as switches. They spring back after being pressed, like a scene. Only positions the desk actually has are shown, so an unused memory gets no switch. Rename them in the Home app if \"Memory 1\" is not what you want."
49
+ "description": "Offer the desk's memory positions as switches. Only positions the desk actually has appear."
50
50
  },
51
51
  "childLockSwitch": {
52
52
  "title": "Child lock as a switch",
53
53
  "type": "boolean",
54
54
  "default": true,
55
- "description": "Offer the desk's child lock in the Home app. It is the only setting the control box reports back, so it is the only one that can be shown honestly rather than remembered."
55
+ "description": "Offer the desk's child lock in the Home app. It is the one setting the control box reports back, so it is the one that can be shown honestly."
56
56
  },
57
57
  "ecoMode": {
58
58
  "title": "Eco mode",
@@ -66,19 +66,94 @@
66
66
  ]
67
67
  },
68
68
  {
69
- "title": "On - slow and quiet",
69
+ "title": "On - slow and quiet (speed 20)",
70
70
  "enum": [
71
71
  "on"
72
72
  ]
73
73
  },
74
74
  {
75
- "title": "Off - about twice as fast",
75
+ "title": "Off - about twice as fast (speed 40)",
76
76
  "enum": [
77
77
  "off"
78
78
  ]
79
79
  }
80
80
  ],
81
- "description": "Eco mode and travel speed, set as a pair. Measured on an Eliot desk: 22.6 mm/s with eco on, 42.4 mm/s with it off.\n\n**Takes effect only after the desk is reset.** Run the desk to the bottom and hold the down key until it re-homes. Until then it keeps its old speed, whatever this says.\n\n*Leave the desk as it is* writes nothing. The plugin logs what the desk has stored each time it connects, if you want to know where it stands."
81
+ "description": "Eco mode and travel speed, set as a pair: about 22 mm/s against 42 mm/s.<br><br><b>Takes effect only after the desk is reset by hand</b> — run it to the bottom and hold the down key until it re-homes. Until then it keeps its old speed, whatever this says."
82
+ },
83
+ "autoMove": {
84
+ "type": "object",
85
+ "description": "Move the desk between two heights on a timer. Adds an <b>Auto Movement</b> switch to the Home app, and nothing moves until you turn it on.",
86
+ "properties": {
87
+ "sittingMm": {
88
+ "title": "Sitting height (mm)",
89
+ "type": "integer",
90
+ "default": 800,
91
+ "minimum": 650,
92
+ "maximum": 1280,
93
+ "description": "Clamped to the desk's own limits if it will not go that far."
94
+ },
95
+ "standingMm": {
96
+ "title": "Standing height (mm)",
97
+ "type": "integer",
98
+ "default": 1200,
99
+ "minimum": 650,
100
+ "maximum": 1280,
101
+ "description": "Must be above the sitting height."
102
+ },
103
+ "intervalMinutes": {
104
+ "title": "Move every (minutes)",
105
+ "type": "integer",
106
+ "default": 30,
107
+ "minimum": 1,
108
+ "description": "Must be longer than the warning."
109
+ },
110
+ "warnMinutes": {
111
+ "title": "Warn before (minutes)",
112
+ "type": "integer",
113
+ "default": 5,
114
+ "minimum": 0,
115
+ "description": "A <b>Desk Move Soon</b> sensor trips this long before each move; turn on its notifications in the Home app to be told. 0 turns the warning off and removes the sensor."
116
+ },
117
+ "windows": {
118
+ "title": "Working hours",
119
+ "type": "array",
120
+ "default": [
121
+ "08:00-12:00",
122
+ "13:00-16:00"
123
+ ],
124
+ "items": {
125
+ "type": "string",
126
+ "title": "Window",
127
+ "placeholder": "08:00-12:00",
128
+ "pattern": "^\\s*\\d{1,2}:\\d{2}\\s*-\\s*\\d{1,2}:\\d{2}\\s*$"
129
+ },
130
+ "description": "Outside these hours nothing moves and nothing warns."
131
+ },
132
+ "days": {
133
+ "title": "Days",
134
+ "type": "array",
135
+ "default": [
136
+ "mon",
137
+ "tue",
138
+ "wed",
139
+ "thu",
140
+ "fri"
141
+ ],
142
+ "uniqueItems": true,
143
+ "items": {
144
+ "type": "string",
145
+ "enum": [
146
+ "mon",
147
+ "tue",
148
+ "wed",
149
+ "thu",
150
+ "fri",
151
+ "sat",
152
+ "sun"
153
+ ]
154
+ }
155
+ }
156
+ }
82
157
  }
83
158
  }
84
159
  }
@@ -100,7 +175,42 @@
100
175
  "desks[].idlePollSeconds",
101
176
  "desks[].ecoMode",
102
177
  "desks[].childLockSwitch",
103
- "desks[].memorySwitches"
178
+ "desks[].memorySwitches",
179
+ {
180
+ "key": "desks[].autoMove",
181
+ "type": "fieldset",
182
+ "expandable": true,
183
+ "expanded": false,
184
+ "title": "Automatic sit/stand",
185
+ "items": [
186
+ "desks[].autoMove.sittingMm",
187
+ "desks[].autoMove.standingMm",
188
+ "desks[].autoMove.intervalMinutes",
189
+ "desks[].autoMove.warnMinutes",
190
+ {
191
+ "key": "desks[].autoMove.windows",
192
+ "type": "array",
193
+ "orderable": false,
194
+ "buttonText": "Add window",
195
+ "items": [
196
+ "desks[].autoMove.windows[]"
197
+ ]
198
+ },
199
+ {
200
+ "key": "desks[].autoMove.days",
201
+ "type": "checkboxes",
202
+ "titleMap": {
203
+ "mon": "Monday",
204
+ "tue": "Tuesday",
205
+ "wed": "Wednesday",
206
+ "thu": "Thursday",
207
+ "fri": "Friday",
208
+ "sat": "Saturday",
209
+ "sun": "Sunday"
210
+ }
211
+ }
212
+ ]
213
+ }
104
214
  ]
105
215
  }
106
216
  ],