hoffmation-base 0.0.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.
Files changed (108) hide show
  1. package/.eslintrc.js +27 -0
  2. package/.prettierrc.js +9 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1 -0
  5. package/index.js +1 -0
  6. package/models/connectionCallbacks.ts +13 -0
  7. package/models/daytime.ts +3 -0
  8. package/models/deviceConfig.ts +8 -0
  9. package/models/dimmerSettings.ts +5 -0
  10. package/models/lampSettings.ts +5 -0
  11. package/models/ledSettings.ts +19 -0
  12. package/models/logLevel.ts +9 -0
  13. package/models/persistence/BasicRoomInfo.ts +3 -0
  14. package/models/persistence/DailyMovementCount.ts +3 -0
  15. package/models/persistence/RoomDetailInfo.ts +4 -0
  16. package/models/persistence/temperaturDataPoint.ts +12 -0
  17. package/models/persistence/todaysCount.ts +3 -0
  18. package/models/rooms/RoomBase.ts +357 -0
  19. package/models/rooms/RoomSettings/RoomSettings.ts +159 -0
  20. package/models/rooms/RoomSettings/hmIPRoomSettings.ts +53 -0
  21. package/models/rooms/RoomSettings/iRoomDefaultSettings.ts +17 -0
  22. package/models/rooms/RoomSettings/readme.md +18 -0
  23. package/models/rooms/RoomSettings/zigbeeRoomSettings.ts +51 -0
  24. package/models/rooms/iRoomImportEnforcer.ts +3 -0
  25. package/models/rooms/readme.md +11 -0
  26. package/models/temperaturSettings.ts +22 -0
  27. package/models/timeCallback.ts +90 -0
  28. package/package.json +57 -0
  29. package/server/config/config-readme.md +19 -0
  30. package/server/config/iConfig.ts +53 -0
  31. package/server/devices/DeviceInfo.ts +66 -0
  32. package/server/devices/Griffe.ts +31 -0
  33. package/server/devices/Heizgruppen.ts +91 -0
  34. package/server/devices/Rollos.ts +48 -0
  35. package/server/devices/deviceUpdater.ts +72 -0
  36. package/server/devices/devices.ts +189 -0
  37. package/server/devices/groups/fensterGroup.ts +175 -0
  38. package/server/devices/groups/heatGroup.ts +32 -0
  39. package/server/devices/groups/lampenGroup.ts +88 -0
  40. package/server/devices/groups/praesenzGroup.ts +182 -0
  41. package/server/devices/groups/smokeGroup.ts +16 -0
  42. package/server/devices/groups/sonosGroup.ts +33 -0
  43. package/server/devices/groups/tasterGroup.ts +48 -0
  44. package/server/devices/groups/waterGroup.ts +16 -0
  45. package/server/devices/hmIPDevices/Fenster.ts +114 -0
  46. package/server/devices/hmIPDevices/FensterPosition.ts +5 -0
  47. package/server/devices/hmIPDevices/TuerPosition.ts +4 -0
  48. package/server/devices/hmIPDevices/hmIpBewegung.ts +126 -0
  49. package/server/devices/hmIPDevices/hmIpDevice.ts +90 -0
  50. package/server/devices/hmIPDevices/hmIpDeviceType.ts +14 -0
  51. package/server/devices/hmIPDevices/hmIpGriff.ts +143 -0
  52. package/server/devices/hmIPDevices/hmIpHeizgruppe.ts +172 -0
  53. package/server/devices/hmIPDevices/hmIpHeizung.ts +69 -0
  54. package/server/devices/hmIPDevices/hmIpLampe.ts +119 -0
  55. package/server/devices/hmIPDevices/hmIpPraezenz.ts +99 -0
  56. package/server/devices/hmIPDevices/hmIpRoll.ts +133 -0
  57. package/server/devices/hmIPDevices/hmIpTaste.ts +72 -0
  58. package/server/devices/hmIPDevices/hmIpTaster.ts +73 -0
  59. package/server/devices/hmIPDevices/hmIpTherm.ts +19 -0
  60. package/server/devices/hmIPDevices/hmIpTuer.ts +115 -0
  61. package/server/devices/hmIPDevices/hmIpWippe.ts +55 -0
  62. package/server/devices/iDeviceUpdater.ts +4 -0
  63. package/server/devices/iIoBrokerDevice.ts +44 -0
  64. package/server/devices/wledDevice.ts +124 -0
  65. package/server/devices/zigbee/ZigbeeActuator.ts +113 -0
  66. package/server/devices/zigbee/zigbeeAquaraVibra.ts +171 -0
  67. package/server/devices/zigbee/zigbeeAquaraWater.ts +94 -0
  68. package/server/devices/zigbee/zigbeeBlitzShp.ts +77 -0
  69. package/server/devices/zigbee/zigbeeDevice.ts +115 -0
  70. package/server/devices/zigbee/zigbeeDeviceType.ts +13 -0
  71. package/server/devices/zigbee/zigbeeHeimanSmoke.ts +99 -0
  72. package/server/devices/zigbee/zigbeeIkeaSteckdose.ts +31 -0
  73. package/server/devices/zigbee/zigbeeIlluActuator.ts +37 -0
  74. package/server/devices/zigbee/zigbeeIlluDimmer.ts +165 -0
  75. package/server/devices/zigbee/zigbeeIlluLampe.ts +33 -0
  76. package/server/devices/zigbee/zigbeeIlluLedRGBCCT.ts +137 -0
  77. package/server/ioBroker/connection.ts +1655 -0
  78. package/server/ioBroker/ioBroker.main.ts +99 -0
  79. package/server/ioBroker/socketIOAuthInfo.ts +5 -0
  80. package/server/ioBroker/socketIOConnectOptions.ts +6 -0
  81. package/server/ioBroker/socketIOLogging.ts +29 -0
  82. package/server/ioBroker/socketIOVisCommand.ts +11 -0
  83. package/server/services/HTTPSOptions.ts +14 -0
  84. package/server/services/Sonos/mp3-server.ts +75 -0
  85. package/server/services/Sonos/polly-service.ts +100 -0
  86. package/server/services/Sonos/sonos-service.ts +199 -0
  87. package/server/services/Telegram/telegram-Commands.ts +215 -0
  88. package/server/services/Telegram/telegram-service.ts +171 -0
  89. package/server/services/Telegram/telegramMessageCalback.ts +11 -0
  90. package/server/services/calendar/m/303/274ll-service.ts +224 -0
  91. package/server/services/dbo/persist.ts +125 -0
  92. package/server/services/https-service.ts +71 -0
  93. package/server/services/log-service.ts +69 -0
  94. package/server/services/news-service.ts +81 -0
  95. package/server/services/settings-service.ts +23 -0
  96. package/server/services/time-callback-service.ts +223 -0
  97. package/server/services/utils/ringstorage.ts +24 -0
  98. package/server/services/utils/utils.ts +52 -0
  99. package/server/services/weather/weather-alert.ts +7 -0
  100. package/server/services/weather/weather-current.ts +26 -0
  101. package/server/services/weather/weather-daily.ts +22 -0
  102. package/server/services/weather/weather-feelsLike.ts +6 -0
  103. package/server/services/weather/weather-hourly.ts +17 -0
  104. package/server/services/weather/weather-item.ts +6 -0
  105. package/server/services/weather/weather-minutes.ts +4 -0
  106. package/server/services/weather/weather-service.ts +277 -0
  107. package/server/services/weather/weather-temp.ts +8 -0
  108. package/tsconfig.json +59 -0
@@ -0,0 +1,143 @@
1
+ import { FensterPosition } from './FensterPosition';
2
+ import { HmIPDevice } from './hmIpDevice';
3
+ import { HmIpDeviceType } from './hmIpDeviceType';
4
+ import { DeviceInfo } from '../DeviceInfo';
5
+ import { LogLevel } from '../../../models/logLevel';
6
+ import { ServerLogService } from '../../services/log-service';
7
+ import { TelegramService } from '../../services/Telegram/telegram-service';
8
+ import { Utils } from '../../services/utils/utils';
9
+ import { Fenster } from './Fenster';
10
+ import { WeatherService } from '../../services/weather/weather-service';
11
+
12
+ export class HmIpGriff extends HmIPDevice {
13
+ public position: FensterPosition = FensterPosition.geschlossen;
14
+ private _kippCallback: Array<(pValue: boolean) => void> = [];
15
+ private _closedCallback: Array<(pValue: boolean) => void> = [];
16
+ private _offenCallback: Array<(pValue: boolean) => void> = [];
17
+ private _iOpen: NodeJS.Timeout | undefined;
18
+ private minutesOpen: number = 0;
19
+ private _fenster: Fenster | undefined = undefined;
20
+ private _helpingRoomTemp: boolean = false;
21
+
22
+ public constructor(pInfo: DeviceInfo) {
23
+ super(pInfo, HmIpDeviceType.HmIpGriff);
24
+ }
25
+
26
+ public addOffenCallback(pCallback: (pValue: boolean) => void): void {
27
+ this._offenCallback.push(pCallback);
28
+ }
29
+
30
+ public addKippCallback(pCallback: (pValue: boolean) => void): void {
31
+ this._kippCallback.push(pCallback);
32
+ }
33
+
34
+ public addClosedCallback(pCallback: (pValue: boolean) => void): void {
35
+ this._closedCallback.push(pCallback);
36
+ }
37
+
38
+ public set Fenster(value: Fenster) {
39
+ this._fenster = value;
40
+ }
41
+
42
+ public update(idSplit: string[], state: ioBroker.State, initial: boolean = false): void {
43
+ ServerLogService.writeLog(
44
+ LogLevel.DeepTrace,
45
+ `Griff Update: JSON: ${JSON.stringify(state)}ID: ${idSplit.join('.')}`,
46
+ );
47
+ super.update(idSplit, state, initial, true);
48
+ switch (idSplit[3]) {
49
+ case '1':
50
+ if (idSplit[4] === 'STATE') {
51
+ this.updatePosition(state.val as FensterPosition);
52
+ }
53
+ break;
54
+ }
55
+ }
56
+
57
+ public updatePosition(pValue: FensterPosition): void {
58
+ if (pValue === this.position) {
59
+ return;
60
+ }
61
+
62
+ ServerLogService.writeLog(
63
+ LogLevel.Trace,
64
+ `Update Fenstergriff "${this.info.customName}"\nauf Position "${FensterPosition[pValue]}"`,
65
+ );
66
+
67
+ this.position = pValue;
68
+ for (const c1 of this._closedCallback) {
69
+ c1(pValue === 0);
70
+ }
71
+
72
+ for (const c2 of this._kippCallback) {
73
+ c2(pValue === 1);
74
+ }
75
+
76
+ for (const c3 of this._offenCallback) {
77
+ c3(pValue === 2);
78
+ }
79
+
80
+ if (pValue === FensterPosition.geschlossen) {
81
+ if (this._iOpen !== undefined) {
82
+ clearInterval(this._iOpen);
83
+ ServerLogService.writeLog(
84
+ LogLevel.Info,
85
+ `Fenster: "${this.info.customName}" nach ${this.minutesOpen} Minuten geschlossen`,
86
+ );
87
+ this.minutesOpen = 0;
88
+ this._iOpen = undefined;
89
+ }
90
+ return;
91
+ } else if (this._iOpen === undefined) {
92
+ this._iOpen = Utils.guardedInterval(
93
+ () => {
94
+ this.minutesOpen++;
95
+ if (this._fenster !== undefined && this._fenster.room !== undefined) {
96
+ const desiredTemp: number = this._fenster.room.HeatGroup.desiredTemp;
97
+ const currentTemp: number = this._fenster.room.HeatGroup.currentTemp;
98
+ const outSideTemp: number = WeatherService.getCurrentTemp();
99
+
100
+ // Check if any of these values are unavailable
101
+ if (desiredTemp > -99 && currentTemp > -99 && outSideTemp > -99) {
102
+ const wouldHelp: boolean =
103
+ (desiredTemp < currentTemp && outSideTemp < currentTemp) ||
104
+ (desiredTemp > currentTemp && outSideTemp > currentTemp);
105
+ if (!wouldHelp && this._helpingRoomTemp) {
106
+ const info: string = `Das Fenster "${this.info.customName}" sollte geschlossen werden, es hilft dem Raum nicht mehr`;
107
+ ServerLogService.writeLog(LogLevel.Info, info);
108
+ TelegramService.inform(info);
109
+ this._helpingRoomTemp = false;
110
+ } else if (wouldHelp && !this._helpingRoomTemp) {
111
+ this._helpingRoomTemp = true;
112
+ const info: string = `Das Fenster "${this.info.customName}" hilft der Innentemperatur ihr Ziel von ${desiredTemp} zu erreichen. Draußen sind es ${outSideTemp}. Du wirst informiert wenn es nicht mehr hilft.`;
113
+ ServerLogService.writeLog(LogLevel.Info, info);
114
+ TelegramService.inform(info);
115
+ return;
116
+ } else if (wouldHelp && this._helpingRoomTemp) {
117
+ return;
118
+ }
119
+ }
120
+ }
121
+ const message = `Fenster: "${this.info.customName}" seit ${this.minutesOpen} Minuten auf Position ${
122
+ FensterPosition[this.position]
123
+ }`;
124
+ switch (this.minutesOpen) {
125
+ case 15:
126
+ case 30:
127
+ case 60:
128
+ case 120:
129
+ case 240:
130
+ ServerLogService.writeLog(LogLevel.Info, message);
131
+ TelegramService.inform(message);
132
+ break;
133
+ default:
134
+ ServerLogService.writeLog(LogLevel.Trace, message);
135
+ break;
136
+ }
137
+ },
138
+ 60000,
139
+ this,
140
+ );
141
+ }
142
+ }
143
+ }
@@ -0,0 +1,172 @@
1
+ import { HmIPDevice } from './hmIpDevice';
2
+ import { HmIpDeviceType } from './hmIpDeviceType';
3
+ import { DeviceInfo } from '../DeviceInfo';
4
+ import { LogLevel } from '/models/logLevel';
5
+ import { ServerLogService } from '/server/services/log-service';
6
+ import { TemperaturSettings } from '/models/temperaturSettings';
7
+ import { Persist } from '/server/services/dbo/persist';
8
+ import { HmIpHeizung } from './hmIpHeizung';
9
+ import { Devices } from '../devices';
10
+ import { Utils } from '/server/services/utils/utils';
11
+
12
+ export class HmIpHeizgruppe extends HmIPDevice {
13
+ private _automaticMode: boolean = true;
14
+ private _iAutomaticInterval: NodeJS.Timeout;
15
+ private _level: number = 0;
16
+ private _temperatur: number = 0;
17
+ private _humidity: number = 0;
18
+ private _desiredTemperatur: number = 0;
19
+ private _setPointTemperaturID: string = '';
20
+ private _automaticFallBackTemperatur: number = 20;
21
+ private _automaticPoints: { [name: string]: TemperaturSettings } = {};
22
+ private _humidityCallbacks: Array<(pValue: number) => void> = [];
23
+
24
+ public constructor(pInfo: DeviceInfo) {
25
+ super(pInfo, HmIpDeviceType.HmIpHeizgruppe);
26
+ this._setPointTemperaturID = `${this.info.fullID}.1.SET_POINT_TEMPERATURE`;
27
+ this._iAutomaticInterval = Utils.guardedInterval(this.checkAutomaticChange, 300000, this); // Alle 5 Minuten prüfen
28
+ }
29
+
30
+ public get sLevel(): string {
31
+ return `${this._level * 100}%`;
32
+ }
33
+
34
+ public get iLevel(): number {
35
+ return this._level;
36
+ }
37
+
38
+ public get sTemperatur(): string {
39
+ return `${this._temperatur}°C`;
40
+ }
41
+
42
+ public get iTemperatur(): number {
43
+ return this._temperatur;
44
+ }
45
+
46
+ public get desiredTemperatur(): number {
47
+ return this._desiredTemperatur;
48
+ }
49
+
50
+ public get humidity(): number {
51
+ return this._humidity;
52
+ }
53
+
54
+ private set humidity(val: number) {
55
+ this._humidity = val;
56
+ for (const cb of this._humidityCallbacks) {
57
+ cb(val);
58
+ }
59
+ }
60
+
61
+ public set desiredTemperatur(val: number) {
62
+ if (!this.ioConn) {
63
+ ServerLogService.writeLog(LogLevel.Error, `Keine Connection für "${this.info.customName}" bekannt.`);
64
+ return;
65
+ }
66
+
67
+ ServerLogService.writeLog(LogLevel.Info, `Neue Temperatur (${val}) für "${this.info.customName}".`);
68
+ this.ioConn.setState(this._setPointTemperaturID, val, (err) => {
69
+ if (err) {
70
+ ServerLogService.writeLog(
71
+ LogLevel.Error,
72
+ `Temperaturänderung für "${this.info.customName}" ergab Fehler ${err}.`,
73
+ );
74
+ } else {
75
+ ServerLogService.writeLog(
76
+ LogLevel.Debug,
77
+ `Temperaturänderung für "${this.info.customName}" auf ${val} erfolgreich`,
78
+ );
79
+ }
80
+ });
81
+ }
82
+
83
+ public addHumidityCallback(pCallback: (pValue: number) => void): void {
84
+ this._humidityCallbacks.push(pCallback);
85
+ if (this._humidity > 0) {
86
+ pCallback(this._humidity);
87
+ }
88
+ }
89
+
90
+ public deleteAutomaticPoint(name: string): void {
91
+ if (this._automaticPoints[name] !== undefined) delete this._automaticPoints[name];
92
+ }
93
+
94
+ public getBelongingHeizungen(): HmIpHeizung[] {
95
+ const result: HmIpHeizung[] = [];
96
+ for (const dID in Devices.hmIP) {
97
+ const d = Devices.hmIP[dID];
98
+ if (d.deviceType === HmIpDeviceType.HmIpHeizung && d.info.room === this.info.room) {
99
+ result.push(d as HmIpHeizung);
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+
105
+ public setAutomaticPoint(name: string, setting: TemperaturSettings): void {
106
+ this._automaticPoints[name] = setting;
107
+ }
108
+
109
+ public update(idSplit: string[], state: ioBroker.State, initial: boolean = false): void {
110
+ ServerLogService.writeLog(
111
+ LogLevel.Trace,
112
+ `Heizgruppe "${this.info.customName}" Update: ID: ${idSplit.join('.')} JSON: ${JSON.stringify(state)}`,
113
+ );
114
+ super.update(idSplit, state, initial, true);
115
+
116
+ switch (idSplit[3]) {
117
+ case '1':
118
+ this.updateBaseInformation(idSplit[4], state, initial);
119
+ break;
120
+ }
121
+ }
122
+
123
+ private updateBaseInformation(name: string, state: ioBroker.State, initial: boolean) {
124
+ switch (name) {
125
+ case 'ACTUAL_TEMPERATURE':
126
+ this._temperatur = state.val as number;
127
+ break;
128
+ case 'LEVEL':
129
+ this._level = state.val as number;
130
+ break;
131
+ case 'HUMIDITY':
132
+ this.humidity = state.val as number;
133
+ break;
134
+ case 'SET_POINT_TEMPERATURE':
135
+ ServerLogService.writeLog(
136
+ LogLevel.Trace,
137
+ `Heizgruppe "${this.info.customName}" Update Soll-Temperatur JSON: ${JSON.stringify(state)}`,
138
+ );
139
+ this._desiredTemperatur = state.val as number;
140
+ break;
141
+ }
142
+ }
143
+
144
+ private checkAutomaticChange(): void {
145
+ if (!this._automaticMode) {
146
+ Persist.addTemperaturDataPoint(this);
147
+ return;
148
+ }
149
+
150
+ for (const name in this._automaticPoints) {
151
+ if (this._automaticPoints[name] === undefined) {
152
+ continue;
153
+ }
154
+
155
+ const settings: TemperaturSettings = this._automaticPoints[name];
156
+ if (!settings.isNowInRange()) {
157
+ continue;
158
+ }
159
+
160
+ if (this._desiredTemperatur !== settings.temperatur) {
161
+ ServerLogService.writeLog(
162
+ LogLevel.Debug,
163
+ `Automatische Temperaturanpassung für ${this.info.customName} auf ${settings.temperatur}°C`,
164
+ );
165
+ this.desiredTemperatur = settings.temperatur;
166
+ }
167
+ break;
168
+ }
169
+
170
+ Persist.addTemperaturDataPoint(this);
171
+ }
172
+ }
@@ -0,0 +1,69 @@
1
+ import { HmIPDevice } from './hmIpDevice';
2
+ import { HmIpDeviceType } from './hmIpDeviceType';
3
+ import { DeviceInfo } from '../DeviceInfo';
4
+ import { LogLevel } from '/models/logLevel';
5
+ import { ServerLogService } from '/server/services/log-service';
6
+
7
+ export class HmIpHeizung extends HmIPDevice {
8
+ private _temperatur: number = 0;
9
+ private _level: number = 0;
10
+ private _adaptionState: number | undefined;
11
+ private _desiredTemperatur: number = 0;
12
+
13
+ public get desiredTemperatur(): number {
14
+ return this._desiredTemperatur;
15
+ }
16
+
17
+ public get iLevel(): number {
18
+ return this._level;
19
+ }
20
+
21
+ public get iTemperatur(): number {
22
+ return this._temperatur;
23
+ }
24
+
25
+ public constructor(pInfo: DeviceInfo) {
26
+ super(pInfo, HmIpDeviceType.HmIpHeizung);
27
+ }
28
+
29
+ public update(idSplit: string[], state: ioBroker.State, initial: boolean = false): void {
30
+ ServerLogService.writeLog(
31
+ LogLevel.Trace,
32
+ `Heizung "${this.info.customName}" Update: ID: ${idSplit.join('.')} JSON: ${JSON.stringify(state)}`,
33
+ );
34
+ super.update(idSplit, state, initial, true);
35
+
36
+ switch (idSplit[3]) {
37
+ case '1':
38
+ this.updateBaseInformation(idSplit[4], state, initial);
39
+ break;
40
+ }
41
+ }
42
+
43
+ private updateBaseInformation(name: string, state: ioBroker.State, initial: boolean) {
44
+ switch (name) {
45
+ case 'ACTUAL_TEMPERATURE':
46
+ this._temperatur = state.val as number;
47
+ break;
48
+ case 'LEVEL':
49
+ this._level = state.val as number;
50
+ break;
51
+ case 'VALVE_STATE':
52
+ this._adaptionState = state.val as number;
53
+ if (this._adaptionState !== 4) {
54
+ ServerLogService.writeLog(
55
+ LogLevel.Alert,
56
+ `Adaption State für Heizung "${this.info.customName}" ungewöhnlich: ${this._adaptionState}`,
57
+ );
58
+ }
59
+ break;
60
+ case 'SET_POINT_TEMPERATURE':
61
+ ServerLogService.writeLog(
62
+ LogLevel.Trace,
63
+ `Heizung "${this.info.customName}" Update Soll-Temperatur JSON: ${JSON.stringify(state)}`,
64
+ );
65
+ this._desiredTemperatur = state.val as number;
66
+ break;
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,119 @@
1
+ import { HmIPDevice } from './hmIpDevice';
2
+ import { HmIpDeviceType } from './hmIpDeviceType';
3
+ import { DeviceInfo } from '../DeviceInfo';
4
+ import { LogLevel } from '/models/logLevel';
5
+ import { ServerLogService } from '/server/services/log-service';
6
+ import { LampSettings } from '/models/lampSettings';
7
+ import { Utils } from '/server/services/utils/utils';
8
+
9
+ export class HmIpLampe extends HmIPDevice {
10
+ public lightOn: boolean | undefined = undefined;
11
+ public queuedLightValue: boolean | null = null;
12
+ public isStromStoss: boolean = false;
13
+ public settings: LampSettings = new LampSettings();
14
+ private lightOnSwitchID: string = '';
15
+ private turnOffTimeout: NodeJS.Timeout | undefined = undefined;
16
+ private turnOffTime: number = 0;
17
+
18
+ public constructor(pInfo: DeviceInfo) {
19
+ super(pInfo, HmIpDeviceType.HmIpLampe);
20
+ this.lightOnSwitchID = `${this.info.fullID}.2.STATE`;
21
+ }
22
+
23
+ public update(idSplit: string[], state: ioBroker.State, initial: boolean = false): void {
24
+ ServerLogService.writeLog(
25
+ LogLevel.DeepTrace,
26
+ `Lampen Update für "${this.info.customName}": ID: ${idSplit.join('.')} JSON: ${JSON.stringify(state)}`,
27
+ );
28
+ super.update(idSplit, state, initial, true);
29
+ this.queuedLightValue = null;
30
+ switch (idSplit[3]) {
31
+ case '1':
32
+ if (idSplit[4] === 'STATE') {
33
+ this.lightOn = state.val as boolean;
34
+ }
35
+ break;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * This function thats the light to a specific value
41
+ * @param pValue The desired value
42
+ * @param timeout A chosen Timeout after which the light should be reset
43
+ */
44
+ public setLight(pValue: boolean, timeout: number = -1, force: boolean = false): void {
45
+ if (!force && pValue === this.lightOn && this.queuedLightValue === null) {
46
+ ServerLogService.writeLog(
47
+ LogLevel.DeepTrace,
48
+ `Skip light command for "${this.info.customName}" as it is already ${pValue}`,
49
+ );
50
+ return;
51
+ }
52
+ if (this.lightOnSwitchID === '') {
53
+ ServerLogService.writeLog(LogLevel.Error, `Keine Switch ID für "${this.info.customName}" bekannt.`);
54
+ return;
55
+ }
56
+
57
+ if (!this.ioConn) {
58
+ ServerLogService.writeLog(LogLevel.Error, `Keine Connection für "${this.info.customName}" bekannt.`);
59
+ return;
60
+ }
61
+
62
+ if (!force && Utils.nowMS() < this.turnOffTime) {
63
+ ServerLogService.writeLog(
64
+ LogLevel.Debug,
65
+ `Skip automatic command for "${this.info.customName}" to ${pValue} as it is locked until ${new Date(
66
+ this.turnOffTime,
67
+ ).toLocaleString()}`,
68
+ );
69
+ return;
70
+ }
71
+
72
+ ServerLogService.writeLog(LogLevel.Debug, `Lampe schalten: "${this.info.customName}" Wert: ${pValue}`);
73
+ this.ioConn.setState(this.lightOnSwitchID, pValue, (err) => {
74
+ if (err) {
75
+ ServerLogService.writeLog(LogLevel.Error, `Lampe schalten ergab Fehler: ${err}`);
76
+ }
77
+ });
78
+ this.queuedLightValue = pValue;
79
+
80
+ if (this.isStromStoss) {
81
+ timeout = 5000;
82
+ }
83
+
84
+ if (this.turnOffTimeout !== undefined) {
85
+ clearTimeout(this.turnOffTimeout);
86
+ this.turnOffTimeout = undefined;
87
+ }
88
+
89
+ if (timeout < 0 || !pValue) {
90
+ return;
91
+ }
92
+
93
+ this.turnOffTime = Utils.nowMS() + timeout;
94
+ this.turnOffTimeout = Utils.guardedTimeout(
95
+ () => {
96
+ ServerLogService.writeLog(LogLevel.Debug, `Delayed Turnoff for "${this.info.customName}" initiated`);
97
+ this.turnOffTimeout = undefined;
98
+ if (!this.room) {
99
+ this.setLight(false, -1, true);
100
+ } else {
101
+ this.room.setLightTimeBased(true);
102
+ }
103
+ },
104
+ timeout,
105
+ this,
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Switch the current condition of the light
111
+ * @param force Whether this is a forcing action skipping delays and locks
112
+ */
113
+ public toggleLight(force: boolean = false): boolean {
114
+ const newVal = this.queuedLightValue !== null ? !this.queuedLightValue : !this.lightOn;
115
+ const timeout: number = newVal && force ? 30 * 60 * 1000 : -1;
116
+ this.setLight(newVal, timeout, force);
117
+ return newVal;
118
+ }
119
+ }
@@ -0,0 +1,99 @@
1
+ import { HmIPDevice } from './hmIpDevice';
2
+ import { HmIpDeviceType } from './hmIpDeviceType';
3
+ import { DeviceInfo } from '../DeviceInfo';
4
+ import { LogLevel } from '/models/logLevel';
5
+ import { ServerLogService } from '/server/services/log-service';
6
+ import { Persist } from '/server/services/dbo/persist';
7
+ import { CountToday } from '../../../models/persistence/todaysCount';
8
+ import { Utils } from '/server/services/utils/utils';
9
+
10
+ export class HmIpPraezenz extends HmIPDevice {
11
+ public excludeFromNightAlarm: boolean = false;
12
+ public presenceDetected: boolean = false;
13
+ private _detectionsToday: number = 0;
14
+ private _presenceDetectedCallback: Array<(pValue: boolean) => void> = [];
15
+ private static PRESENCE_DETECTION: string = 'PRESENCE_DETECTION_STATE';
16
+ private presenceStateID: string;
17
+ private initialized: boolean = false;
18
+
19
+ public get detectionsToday(): number {
20
+ return this._detectionsToday;
21
+ }
22
+
23
+ public set detectionsToday(pVal: number) {
24
+ const oldVal: number = this._detectionsToday;
25
+ this._detectionsToday = pVal;
26
+ Persist.persistTodayCount(this, pVal, oldVal);
27
+ }
28
+
29
+ public constructor(pInfo: DeviceInfo) {
30
+ super(pInfo, HmIpDeviceType.HmIpPraezenz);
31
+ this.presenceStateID = `${this.info.fullID}.1.${HmIpPraezenz.PRESENCE_DETECTION}`;
32
+ Persist.getCount(this).then((todayCount: CountToday) => {
33
+ this.detectionsToday = todayCount.counter;
34
+ ServerLogService.writeLog(
35
+ LogLevel.Debug,
36
+ `Präsenzcounter "${this.info.customName}" vorinitialisiert mit ${this.detectionsToday}`,
37
+ );
38
+ this.initialized = true;
39
+ });
40
+ }
41
+
42
+ public addPresenceCallback(pCallback: (pValue: boolean) => void): void {
43
+ this._presenceDetectedCallback.push(pCallback);
44
+ }
45
+
46
+ public update(idSplit: string[], state: ioBroker.State, initial: boolean = false): void {
47
+ ServerLogService.writeLog(LogLevel.Trace, `Präzens Update: JSON: ${JSON.stringify(state)}ID: ${idSplit.join('.')}`);
48
+ super.update(idSplit, state, initial, true);
49
+
50
+ if (idSplit[3] !== '1') {
51
+ // Nur die Infos in Kanal 1 sind relevant
52
+ return;
53
+ }
54
+
55
+ switch (idSplit[4]) {
56
+ case HmIpPraezenz.PRESENCE_DETECTION:
57
+ this.updatePresence(state.val as boolean);
58
+ break;
59
+ }
60
+ }
61
+
62
+ public updatePresence(pVal: boolean): void {
63
+ if (!this.initialized && pVal) {
64
+ ServerLogService.writeLog(
65
+ LogLevel.Debug,
66
+ `Präsenz für "${this.info.customName}" erkannt aber die Initialisierung aus der DB ist noch nicht erfolgt --> verzögern`,
67
+ );
68
+ Utils.guardedTimeout(
69
+ () => {
70
+ this.updatePresence(pVal);
71
+ },
72
+ 1000,
73
+ this,
74
+ );
75
+ return;
76
+ }
77
+ if (pVal === this.presenceDetected) {
78
+ ServerLogService.writeLog(
79
+ LogLevel.Debug,
80
+ `Überspringe Präsenz für "${this.info.customName}" da bereits der Wert ${pVal} vorliegt`,
81
+ );
82
+ return;
83
+ }
84
+
85
+ this.presenceDetected = pVal;
86
+ ServerLogService.writeLog(LogLevel.Debug, `Neuer Präsenzstatus Wert für "${this.info.customName}": ${pVal}`);
87
+
88
+ if (pVal) {
89
+ this.detectionsToday++;
90
+ ServerLogService.writeLog(
91
+ LogLevel.Trace,
92
+ `Dies ist die ${this.detectionsToday} Bewegung für "${this.info.customName}"`,
93
+ );
94
+ }
95
+ for (const c of this._presenceDetectedCallback) {
96
+ c(pVal);
97
+ }
98
+ }
99
+ }