iobroker.loxone 3.0.1 → 4.0.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.
Files changed (185) hide show
  1. package/LICENSE +183 -183
  2. package/README.md +417 -411
  3. package/admin/i18n/de.json +15 -0
  4. package/admin/i18n/en.json +15 -0
  5. package/admin/i18n/es.json +18 -0
  6. package/admin/i18n/fr.json +18 -0
  7. package/admin/i18n/it.json +18 -0
  8. package/admin/i18n/nl.json +18 -0
  9. package/admin/i18n/pl.json +18 -0
  10. package/admin/i18n/pt.json +18 -0
  11. package/admin/i18n/ru.json +18 -0
  12. package/admin/i18n/uk.json +18 -0
  13. package/admin/i18n/zh-cn.json +18 -0
  14. package/admin/jsonConfig.json +96 -0
  15. package/io-package.json +49 -38
  16. package/package.json +36 -49
  17. package/src/controls/AalEmergency.ts +90 -0
  18. package/src/controls/AalSmartAlarm.ts +99 -0
  19. package/src/controls/Alarm.ts +146 -0
  20. package/src/controls/AlarmClock.ts +137 -0
  21. package/src/controls/Application.ts +13 -0
  22. package/src/controls/AudioZone.ts +227 -0
  23. package/src/controls/AudioZoneV2.ts +135 -0
  24. package/src/controls/CentralAlarm.ts +59 -0
  25. package/src/controls/CentralAudioZone.ts +41 -0
  26. package/src/controls/CentralGate.ts +53 -0
  27. package/src/controls/CentralJalousie.ts +67 -0
  28. package/src/controls/CentralLightController.ts +45 -0
  29. package/src/controls/ColorPickerV2.ts +34 -0
  30. package/src/controls/Colorpicker.ts +30 -0
  31. package/src/controls/ColorpickerBase.ts +326 -0
  32. package/src/controls/Daytimer.ts +201 -0
  33. package/src/controls/Dimmer.ts +64 -0
  34. package/src/controls/EIBDimmer.ts +61 -0
  35. package/src/controls/Fronius.ts +217 -0
  36. package/src/controls/Gate.ts +150 -0
  37. package/src/controls/Hourcounter.ts +115 -0
  38. package/src/controls/IRCDaytimer.ts +4 -0
  39. package/src/controls/IRCV2Daytimer.ts +4 -0
  40. package/src/controls/IRoomControllerV2.ts +595 -0
  41. package/src/controls/InfoOnlyAnalog.ts +56 -0
  42. package/src/controls/InfoOnlyDigital.ts +95 -0
  43. package/src/controls/InfoOnlyText.ts +52 -0
  44. package/{build/controls/Intercom.js → src/controls/Intercom.ts} +27 -11
  45. package/src/controls/Jalousie.ts +219 -0
  46. package/src/controls/LightController.ts +112 -0
  47. package/src/controls/LightControllerV2.ts +246 -0
  48. package/src/controls/MailBox.ts +92 -0
  49. package/src/controls/Meter.ts +94 -0
  50. package/src/controls/None.ts +29 -0
  51. package/src/controls/PresenceDetector.ts +47 -0
  52. package/src/controls/Pushbutton.ts +55 -0
  53. package/src/controls/Radio.ts +61 -0
  54. package/{build/controls/Remote.js → src/controls/Remote.ts} +19 -11
  55. package/src/controls/Slider.ts +78 -0
  56. package/src/controls/SmokeAlarm.ts +163 -0
  57. package/src/controls/Switch.ts +46 -0
  58. package/src/controls/SystemScheme.ts +13 -0
  59. package/src/controls/TextInput.ts +96 -0
  60. package/src/controls/TextState.ts +37 -0
  61. package/src/controls/TimedSwitch.ts +75 -0
  62. package/src/controls/Tracker.ts +30 -0
  63. package/{build/controls/Unknown.js → src/controls/Unknown.ts} +18 -11
  64. package/src/controls/UpDownAnalog.ts +78 -0
  65. package/{build/controls/ValueSelector.js → src/controls/ValueSelector.ts} +21 -9
  66. package/src/controls/WindowMonitor.ts +139 -0
  67. package/src/controls/all-controls.ts +99 -0
  68. package/src/controls/control-base.ts +28 -0
  69. package/src/lib/adapter-config.d.ts +22 -0
  70. package/src/loxone-handler-base.ts +285 -0
  71. package/src/lxcommunicator.d.ts +1 -0
  72. package/src/main.test.ts +24 -0
  73. package/{build/main.js → src/main.ts} +545 -270
  74. package/src/structure-file.d.ts +154 -0
  75. package/src/weather-server-handler.ts +266 -0
  76. package/admin/admin.d.ts +0 -58
  77. package/admin/index_m.html +0 -126
  78. package/admin/style.css +0 -32
  79. package/admin/words.js +0 -25
  80. package/build/controls/AalEmergency.js +0 -45
  81. package/build/controls/AalEmergency.js.map +0 -1
  82. package/build/controls/AalSmartAlarm.js +0 -48
  83. package/build/controls/AalSmartAlarm.js.map +0 -1
  84. package/build/controls/Alarm.js +0 -81
  85. package/build/controls/Alarm.js.map +0 -1
  86. package/build/controls/AlarmClock.js +0 -59
  87. package/build/controls/AlarmClock.js.map +0 -1
  88. package/build/controls/Application.js +0 -11
  89. package/build/controls/Application.js.map +0 -1
  90. package/build/controls/AudioZone.js +0 -116
  91. package/build/controls/AudioZone.js.map +0 -1
  92. package/build/controls/CentralAlarm.js +0 -30
  93. package/build/controls/CentralAlarm.js.map +0 -1
  94. package/build/controls/CentralAudioZone.js +0 -22
  95. package/build/controls/CentralAudioZone.js.map +0 -1
  96. package/build/controls/CentralGate.js +0 -30
  97. package/build/controls/CentralGate.js.map +0 -1
  98. package/build/controls/CentralJalousie.js +0 -39
  99. package/build/controls/CentralJalousie.js.map +0 -1
  100. package/build/controls/CentralLightController.js +0 -27
  101. package/build/controls/CentralLightController.js.map +0 -1
  102. package/build/controls/ColorPickerV2.js +0 -24
  103. package/build/controls/ColorPickerV2.js.map +0 -1
  104. package/build/controls/Colorpicker.js +0 -20
  105. package/build/controls/Colorpicker.js.map +0 -1
  106. package/build/controls/ColorpickerBase.js +0 -263
  107. package/build/controls/ColorpickerBase.js.map +0 -1
  108. package/build/controls/Daytimer.js +0 -119
  109. package/build/controls/Daytimer.js.map +0 -1
  110. package/build/controls/Dimmer.js +0 -34
  111. package/build/controls/Dimmer.js.map +0 -1
  112. package/build/controls/EIBDimmer.js +0 -31
  113. package/build/controls/EIBDimmer.js.map +0 -1
  114. package/build/controls/Fronius.js +0 -64
  115. package/build/controls/Fronius.js.map +0 -1
  116. package/build/controls/Gate.js +0 -104
  117. package/build/controls/Gate.js.map +0 -1
  118. package/build/controls/Hourcounter.js +0 -46
  119. package/build/controls/Hourcounter.js.map +0 -1
  120. package/build/controls/IRCDaytimer.js +0 -9
  121. package/build/controls/IRCDaytimer.js.map +0 -1
  122. package/build/controls/IRCV2Daytimer.js +0 -9
  123. package/build/controls/IRCV2Daytimer.js.map +0 -1
  124. package/build/controls/IRoomControllerV2.js +0 -371
  125. package/build/controls/IRoomControllerV2.js.map +0 -1
  126. package/build/controls/InfoOnlyAnalog.js +0 -38
  127. package/build/controls/InfoOnlyAnalog.js.map +0 -1
  128. package/build/controls/InfoOnlyDigital.js +0 -65
  129. package/build/controls/InfoOnlyDigital.js.map +0 -1
  130. package/build/controls/InfoOnlyText.js +0 -35
  131. package/build/controls/InfoOnlyText.js.map +0 -1
  132. package/build/controls/Intercom.js.map +0 -1
  133. package/build/controls/Jalousie.js +0 -153
  134. package/build/controls/Jalousie.js.map +0 -1
  135. package/build/controls/LightController.js +0 -68
  136. package/build/controls/LightController.js.map +0 -1
  137. package/build/controls/LightControllerV2.js +0 -195
  138. package/build/controls/LightControllerV2.js.map +0 -1
  139. package/build/controls/MailBox.js +0 -41
  140. package/build/controls/MailBox.js.map +0 -1
  141. package/build/controls/Meter.js +0 -52
  142. package/build/controls/Meter.js.map +0 -1
  143. package/build/controls/None.js +0 -23
  144. package/build/controls/None.js.map +0 -1
  145. package/build/controls/PresenceDetector.js +0 -29
  146. package/build/controls/PresenceDetector.js.map +0 -1
  147. package/build/controls/Pushbutton.js +0 -35
  148. package/build/controls/Pushbutton.js.map +0 -1
  149. package/build/controls/Radio.js +0 -39
  150. package/build/controls/Radio.js.map +0 -1
  151. package/build/controls/Remote.js.map +0 -1
  152. package/build/controls/Slider.js +0 -44
  153. package/build/controls/Slider.js.map +0 -1
  154. package/build/controls/SmokeAlarm.js +0 -85
  155. package/build/controls/SmokeAlarm.js.map +0 -1
  156. package/build/controls/Switch.js +0 -31
  157. package/build/controls/Switch.js.map +0 -1
  158. package/build/controls/SystemScheme.js +0 -11
  159. package/build/controls/SystemScheme.js.map +0 -1
  160. package/build/controls/TextInput.js +0 -55
  161. package/build/controls/TextInput.js.map +0 -1
  162. package/build/controls/TextState.js +0 -20
  163. package/build/controls/TextState.js.map +0 -1
  164. package/build/controls/TimedSwitch.js +0 -36
  165. package/build/controls/TimedSwitch.js.map +0 -1
  166. package/build/controls/Tracker.js +0 -20
  167. package/build/controls/Tracker.js.map +0 -1
  168. package/build/controls/Unknown.js.map +0 -1
  169. package/build/controls/UpDownAnalog.js +0 -44
  170. package/build/controls/UpDownAnalog.js.map +0 -1
  171. package/build/controls/ValueSelector.js.map +0 -1
  172. package/build/controls/WindowMonitor.js +0 -84
  173. package/build/controls/WindowMonitor.js.map +0 -1
  174. package/build/controls/control-base.js +0 -12
  175. package/build/controls/control-base.js.map +0 -1
  176. package/build/loxone-handler-base.js +0 -186
  177. package/build/loxone-handler-base.js.map +0 -1
  178. package/build/main.js.map +0 -1
  179. package/build/weather-server-handler.js +0 -120
  180. package/build/weather-server-handler.js.map +0 -1
  181. package/doc/details-missing-control-type.png +0 -0
  182. package/doc/log-missing-control-type.png +0 -0
  183. package/doc/loxone-config-display-diagnostics.png +0 -0
  184. package/doc/loxone-config-info-only-digital.png +0 -0
  185. package/doc/loxone-config-use-in-visualization.png +0 -0
@@ -0,0 +1,95 @@
1
+ import type { Control } from '../structure-file';
2
+ import type { ControlType } from './control-base';
3
+ import { ControlBase } from './control-base';
4
+
5
+ /**
6
+ * Handler for InfoOnlyDigital controls.
7
+ */
8
+ export class InfoOnlyDigital extends ControlBase {
9
+ /**
10
+ * Loads the control and sets up state objects and event handlers.
11
+ *
12
+ * @param type The type of the control ('device' or 'channel').
13
+ * @param uuid The unique identifier of the control.
14
+ * @param control The control data from the structure file.
15
+ */
16
+ async loadAsync(type: ControlType, uuid: string, control: Control): Promise<void> {
17
+ await this.updateObjectAsync(uuid, {
18
+ type: type,
19
+ common: {
20
+ name: control.name,
21
+ role: 'switch',
22
+ },
23
+ native: { control },
24
+ });
25
+
26
+ await this.loadOtherControlStatesAsync(control.name, uuid, control.states, ['active']);
27
+
28
+ if (!('states' in control) || !('active' in control.states)) {
29
+ return;
30
+ }
31
+
32
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'active', 'indicator');
33
+
34
+ if (!('details' in control)) {
35
+ return;
36
+ }
37
+
38
+ if ('text' in control.details) {
39
+ const text: any = control.details.text;
40
+ await this.updateStateObjectAsync(
41
+ `${uuid}.active-text`,
42
+ {
43
+ name: `${control.name}: active as text`,
44
+ read: true,
45
+ write: false,
46
+ type: 'string',
47
+ role: 'text',
48
+ // TODO: re-add: smartIgnore: true,
49
+ },
50
+ control.states.active,
51
+ async (name: string, value: any) => {
52
+ await this.setStateAck(name, value == 1 ? text.on : text.off);
53
+ },
54
+ );
55
+ }
56
+
57
+ if ('image' in control.details) {
58
+ const image: any = control.details.image;
59
+ await this.updateStateObjectAsync(
60
+ `${uuid}.active-image`,
61
+ {
62
+ name: `${control.name}: active as image`,
63
+ read: true,
64
+ write: false,
65
+ type: 'string',
66
+ role: 'text',
67
+ // TODO: re-add: smartIgnore: true,
68
+ },
69
+ control.states.active,
70
+ async (name: string, value: any) => {
71
+ await this.setStateAck(name, value == 1 ? image.on : image.off);
72
+ },
73
+ );
74
+ }
75
+
76
+ if ('color' in control.details) {
77
+ const color: any = control.details.color;
78
+ await this.updateStateObjectAsync(
79
+ `${uuid}.active-color`,
80
+ {
81
+ name: `${control.name}: active as color`,
82
+ read: true,
83
+ write: false,
84
+ type: 'string',
85
+ role: 'text',
86
+ // TODO: re-add: smartIgnore: true,
87
+ },
88
+ control.states.active,
89
+ async (name: string, value: any) => {
90
+ await this.setStateAck(name, value == 1 ? color.on : color.off);
91
+ },
92
+ );
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,52 @@
1
+ import type { Control } from '../structure-file';
2
+ import type { ControlType } from './control-base';
3
+ import { ControlBase } from './control-base';
4
+
5
+ /**
6
+ * Handler for InfoOnlyText controls.
7
+ */
8
+ export class InfoOnlyText extends ControlBase {
9
+ /**
10
+ * Loads the control and sets up state objects and event handlers.
11
+ *
12
+ * @param type The type of the control ('device' or 'channel').
13
+ * @param uuid The unique identifier of the control.
14
+ * @param control The control data from the structure file.
15
+ */
16
+ async loadAsync(type: ControlType, uuid: string, control: Control): Promise<void> {
17
+ await this.updateObjectAsync(uuid, {
18
+ type: type,
19
+ common: {
20
+ name: control.name,
21
+ role: 'info',
22
+ },
23
+ native: { control },
24
+ });
25
+
26
+ await this.loadOtherControlStatesAsync(control.name, uuid, control.states, ['text']);
27
+
28
+ await this.createSimpleControlStateObjectAsync(control.name, uuid, control.states, 'text', 'string', 'text');
29
+
30
+ if (!('details' in control)) {
31
+ return;
32
+ }
33
+
34
+ if ('format' in control.details) {
35
+ await this.updateStateObjectAsync(
36
+ `${uuid}.text-formatted`,
37
+ {
38
+ name: `${control.name}: formatted value`,
39
+ read: true,
40
+ write: false,
41
+ type: 'string',
42
+ role: 'text',
43
+ // TODO: re-add: smartIgnore: true,
44
+ },
45
+ control.states.value,
46
+ async (name: string, value: any) => {
47
+ await this.setFormattedStateAck(name, value, control.details.format as string);
48
+ },
49
+ );
50
+ }
51
+ }
52
+ }
@@ -1,9 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Intercom = void 0;
4
- const control_base_1 = require("./control-base");
5
- class Intercom extends control_base_1.ControlBase {
6
- async loadAsync(type, uuid, control) {
1
+ import type { Control } from '../structure-file';
2
+ import type { ControlType } from './control-base';
3
+ import { ControlBase } from './control-base';
4
+
5
+ /**
6
+ * Handler for Intercom controls.
7
+ */
8
+ export class Intercom extends ControlBase {
9
+ /**
10
+ * Loads the control and sets up state objects and event handlers.
11
+ *
12
+ * @param type The type of the control ('device' or 'channel').
13
+ * @param uuid The unique identifier of the control.
14
+ * @param control The control data from the structure file.
15
+ */
16
+ async loadAsync(type: ControlType, uuid: string, control: Control): Promise<void> {
7
17
  await this.updateObjectAsync(uuid, {
8
18
  type: type,
9
19
  common: {
@@ -12,20 +22,26 @@ class Intercom extends control_base_1.ControlBase {
12
22
  },
13
23
  native: { control },
14
24
  });
25
+
15
26
  await this.loadOtherControlStatesAsync(control.name, uuid, control.states, [
16
27
  'bell',
17
28
  'lastBellEvents',
18
29
  'version',
19
30
  ]);
31
+
20
32
  await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'bell', 'indicator');
21
33
  await this.createListControlStateObjectAsync(control.name, uuid, control.states, 'lastBellEvents');
22
34
  await this.createSimpleControlStateObjectAsync(control.name, uuid, control.states, 'version', 'string', 'text');
35
+
23
36
  await this.createButtonCommandStateObjectAsync(control.name, uuid, 'answer');
24
- this.addStateChangeListener(uuid + '.answer', () => {
25
- this.sendCommand(control.uuidAction, 'answer');
26
- }, { selfAck: true });
37
+ this.addStateChangeListener(
38
+ `${uuid}.answer`,
39
+ () => {
40
+ this.sendCommand(control.uuidAction, 'answer');
41
+ },
42
+ { selfAck: true },
43
+ );
44
+
27
45
  await this.loadSubControlsAsync(uuid, control);
28
46
  }
29
47
  }
30
- exports.Intercom = Intercom;
31
- //# sourceMappingURL=Intercom.js.map
@@ -0,0 +1,219 @@
1
+ import type { CurrentStateValue, OldStateValue } from '../main';
2
+ import type { Control } from '../structure-file';
3
+ import type { ControlType } from './control-base';
4
+ import { ControlBase } from './control-base';
5
+
6
+ /**
7
+ * Handler for Jalousie controls.
8
+ */
9
+ export class Jalousie extends ControlBase {
10
+ private positionTarget: number | undefined;
11
+
12
+ /**
13
+ * Loads the control and sets up state objects and event handlers.
14
+ *
15
+ * @param type The type of the control ('device' or 'channel').
16
+ * @param uuid The unique identifier of the control.
17
+ * @param control The control data from the structure file.
18
+ */
19
+ async loadAsync(type: ControlType, uuid: string, control: Control): Promise<void> {
20
+ await this.updateObjectAsync(uuid, {
21
+ type: type,
22
+ common: {
23
+ name: control.name,
24
+ role: 'blind',
25
+ },
26
+ native: { control },
27
+ });
28
+
29
+ await this.loadOtherControlStatesAsync(control.name, uuid, control.states, [
30
+ 'up',
31
+ 'down',
32
+ 'position',
33
+ 'shadePosition',
34
+ 'safetyActive',
35
+ 'autoAllowed',
36
+ 'autoActive',
37
+ 'locked',
38
+ ]);
39
+
40
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'up', 'indicator', {
41
+ write: true,
42
+ });
43
+ this.addStateEventHandler(control.states.up, () => this.upDownChangeHandler(), 'up');
44
+
45
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'down', 'indicator', {
46
+ write: true,
47
+ });
48
+ this.addStateEventHandler(control.states.down, () => this.upDownChangeHandler(), 'down');
49
+
50
+ await this.createPercentageControlStateObjectAsync(
51
+ control.name,
52
+ uuid,
53
+ control.states,
54
+ 'position',
55
+ 'level.blind',
56
+ {
57
+ write: true,
58
+ // TODO: re-add: smartIgnore: false
59
+ },
60
+ );
61
+
62
+ await this.createPercentageControlStateObjectAsync(
63
+ control.name,
64
+ uuid,
65
+ control.states,
66
+ 'shadePosition',
67
+ 'level',
68
+ );
69
+ await this.createBooleanControlStateObjectAsync(
70
+ control.name,
71
+ uuid,
72
+ control.states,
73
+ 'safetyActive',
74
+ 'indicator',
75
+ );
76
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'autoAllowed', 'indicator');
77
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'autoActive', 'indicator', {
78
+ write: true,
79
+ });
80
+ await this.createBooleanControlStateObjectAsync(control.name, uuid, control.states, 'locked', 'indicator');
81
+ await this.createSimpleControlStateObjectAsync(
82
+ control.name,
83
+ uuid,
84
+ control.states,
85
+ 'infoText',
86
+ 'string',
87
+ 'text',
88
+ );
89
+
90
+ this.addStateChangeListener(`${uuid}.up`, (oldValue: OldStateValue, newValue: CurrentStateValue) => {
91
+ if (newValue) {
92
+ this.sendCommand(control.uuidAction, 'up');
93
+ } else {
94
+ this.sendCommand(control.uuidAction, 'UpOff');
95
+ }
96
+ });
97
+ this.addStateChangeListener(`${uuid}.down`, (oldValue: OldStateValue, newValue: CurrentStateValue) => {
98
+ if (newValue) {
99
+ this.sendCommand(control.uuidAction, 'down');
100
+ } else {
101
+ this.sendCommand(control.uuidAction, 'DownOff');
102
+ }
103
+ });
104
+ this.addStateChangeListener(
105
+ `${uuid}.autoActive`,
106
+ (oldValue: OldStateValue, newValue: CurrentStateValue) => {
107
+ if (newValue) {
108
+ this.sendCommand(control.uuidAction, 'auto');
109
+ } else {
110
+ this.sendCommand(control.uuidAction, 'NoAuto');
111
+ }
112
+ },
113
+ { notIfEqual: true },
114
+ );
115
+
116
+ // for Alexa support:
117
+ // ... but this is not really Alexa specific to be fair
118
+ if (control.states.position) {
119
+ this.addStateChangeListener(
120
+ `${uuid}.position`,
121
+ (oldValue: OldStateValue, newValue: CurrentStateValue) => {
122
+ if (typeof oldValue !== 'number' || typeof newValue !== 'number') {
123
+ // This should never happen due to convertToInt flag
124
+ this.adapter.log.error(`Jalousie position is not a number`);
125
+ return;
126
+ }
127
+
128
+ if (newValue === 100) {
129
+ this.sendCommand(control.uuidAction, 'FullDown');
130
+ return;
131
+ }
132
+ if (newValue === 0) {
133
+ this.sendCommand(control.uuidAction, 'FullUp');
134
+ return;
135
+ }
136
+
137
+ this.upDownAutoCommandHandled = false;
138
+ if (oldValue < newValue) {
139
+ this.positionTarget = (newValue - 5) / 100;
140
+ this.sendCommand(control.uuidAction, 'down');
141
+ } else {
142
+ // Negative here because we use -ve numbers to indicate movement up
143
+ this.positionTarget = -(newValue + 5) / 100;
144
+ this.sendCommand(control.uuidAction, 'up');
145
+ }
146
+ },
147
+ { notIfEqual: true, convertToInt: true, minInt: 0, maxInt: 100, ackTimeoutMs: 2500 },
148
+ );
149
+
150
+ this.addStateEventHandler(
151
+ control.states.position,
152
+ (value: any) => {
153
+ if (typeof this.positionTarget === 'number') {
154
+ // Below, the actual command ('up' or 'down') is irrelevant but we
155
+ // need to know the direction for target test.
156
+ if (this.positionTarget > 0) {
157
+ // Going down
158
+ if (value >= this.positionTarget) {
159
+ this.positionTarget = undefined;
160
+ this.sendCommand(control.uuidAction, 'down');
161
+ }
162
+ } else {
163
+ // Going up - don't forget target is negative
164
+ if (value <= -this.positionTarget) {
165
+ this.positionTarget = undefined;
166
+ this.sendCommand(control.uuidAction, 'up');
167
+ }
168
+ }
169
+ }
170
+ },
171
+ 'auto',
172
+ );
173
+ }
174
+
175
+ await this.createButtonCommandStateObjectAsync(control.name, uuid, 'fullUp');
176
+ this.addStateChangeListener(
177
+ `${uuid}.fullUp`,
178
+ () => {
179
+ this.sendCommand(control.uuidAction, 'FullUp');
180
+ },
181
+ { selfAck: true },
182
+ );
183
+
184
+ await this.createButtonCommandStateObjectAsync(control.name, uuid, 'fullDown');
185
+ this.addStateChangeListener(
186
+ `${uuid}.fullDown`,
187
+ () => {
188
+ this.sendCommand(control.uuidAction, 'FullDown');
189
+ },
190
+ { selfAck: true },
191
+ );
192
+
193
+ await this.createButtonCommandStateObjectAsync(control.name, uuid, 'shade');
194
+ this.addStateChangeListener(
195
+ `${uuid}.shade`,
196
+ () => {
197
+ this.sendCommand(control.uuidAction, 'shade');
198
+ },
199
+ { selfAck: true },
200
+ );
201
+ }
202
+
203
+ // The upDownChangeHandler callback will be triggered when any movement starts or stops.
204
+ // Normally we want upDownChangeHandler to clear any target as it signifies manual command
205
+ // has occurred. This can happen in normal use or before a target has been reached for
206
+ // example.
207
+ // But in the case of movement started as a result of an auto-position command, we don't
208
+ // want to clear that target.
209
+ // For this reason we have the below boolean that tells upDownChangeHandler to ignore the
210
+ // first change it sees after an auto-position command is started.
211
+ private upDownAutoCommandHandled = false;
212
+ private upDownChangeHandler(): void {
213
+ if (this.upDownAutoCommandHandled) {
214
+ this.positionTarget = undefined;
215
+ } else {
216
+ this.upDownAutoCommandHandled = true;
217
+ }
218
+ }
219
+ }
@@ -0,0 +1,112 @@
1
+ import type { CurrentStateValue, OldStateValue } from '../main';
2
+ import type { Control } from '../structure-file';
3
+ import type { ControlType } from './control-base';
4
+ import { ControlBase } from './control-base';
5
+
6
+ /**
7
+ * Handler for LightController controls.
8
+ */
9
+ export class LightController extends ControlBase {
10
+ /**
11
+ * Loads the control and sets up state objects and event handlers.
12
+ *
13
+ * @param type The type of the control ('device' or 'channel').
14
+ * @param uuid The unique identifier of the control.
15
+ * @param control The control data from the structure file.
16
+ */
17
+ async loadAsync(type: ControlType, uuid: string, control: Control): Promise<void> {
18
+ await this.updateObjectAsync(uuid, {
19
+ type: type,
20
+ common: {
21
+ name: control.name,
22
+ role: 'light',
23
+ },
24
+ native: { control },
25
+ });
26
+
27
+ await this.loadOtherControlStatesAsync(control.name, uuid, control.states, ['activeScene', 'sceneList']);
28
+
29
+ await this.createSimpleControlStateObjectAsync(
30
+ control.name,
31
+ uuid,
32
+ control.states,
33
+ 'activeScene',
34
+ 'number',
35
+ 'level',
36
+ { write: true },
37
+ );
38
+ this.addStateChangeListener(`${uuid}.activeScene`, (oldValue: OldStateValue, newValue: CurrentStateValue) => {
39
+ newValue = this.convertStateToInt(newValue);
40
+ if (newValue === 9) {
41
+ this.sendCommand(control.uuidAction, 'on');
42
+ } else {
43
+ this.sendCommand(control.uuidAction, newValue.toString());
44
+ }
45
+ });
46
+
47
+ if ('sceneList' in control.states) {
48
+ await this.updateStateObjectAsync(
49
+ `${uuid}.sceneList`,
50
+ {
51
+ name: `${control.name}: sceneList`,
52
+ read: true,
53
+ write: false,
54
+ type: 'array',
55
+ role: 'list',
56
+ // TODO: re-add: smartIgnore: true,
57
+ },
58
+ control.states.sceneList,
59
+ async (name: string, value: any) => {
60
+ // weird documentation: they say it's 'text' within the struct, but I get the value directly; let's support both
61
+ if ('text' in value) {
62
+ await this.setStateAck(name, value.text.split(','));
63
+ } else {
64
+ await this.setStateAck(name, value.toString().split(','));
65
+ }
66
+ },
67
+ );
68
+ }
69
+
70
+ await this.createButtonCommandStateObjectAsync(control.name, uuid, 'plus');
71
+ this.addStateChangeListener(
72
+ `${uuid}.plus`,
73
+ () => {
74
+ this.sendCommand(control.uuidAction, 'plus');
75
+ },
76
+ { selfAck: true },
77
+ );
78
+
79
+ await this.createButtonCommandStateObjectAsync(control.name, uuid, 'minus');
80
+ this.addStateChangeListener(
81
+ `${uuid}.minus`,
82
+ () => {
83
+ this.sendCommand(control.uuidAction, 'minus');
84
+ },
85
+ { selfAck: true },
86
+ );
87
+
88
+ // for Alexa support:
89
+ await this.createButtonCommandStateObjectAsync(
90
+ control.name,
91
+ uuid,
92
+ 'control',
93
+ /* TODO: re-add: { smartIgnore: false }*/
94
+ );
95
+ this.addStateChangeListener(
96
+ `${uuid}.control`,
97
+ (oldValue: OldStateValue, newValue: CurrentStateValue) => {
98
+ if (newValue) {
99
+ this.sendCommand(control.uuidAction, 'on');
100
+ } else {
101
+ this.sendCommand(control.uuidAction, '0');
102
+ }
103
+ },
104
+ { selfAck: true },
105
+ );
106
+
107
+ // TODO: currently we don't support scene modifications ("learn" and "delete" commands),
108
+ // IMHO this should be done by the user through the Loxone Web interface
109
+
110
+ await this.loadSubControlsAsync(uuid, control);
111
+ }
112
+ }