hoffmation-base 0.1.1 → 0.1.5

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 (113) hide show
  1. package/.eslintrc.js +27 -27
  2. package/.github/workflows/npm-publish.yml +50 -0
  3. package/.prettierrc.js +9 -9
  4. package/LICENSE +21 -21
  5. package/index.js +1 -1
  6. package/models/connectionCallbacks.ts +13 -13
  7. package/models/daytime.ts +3 -3
  8. package/models/deviceConfig.ts +8 -8
  9. package/models/dimmerSettings.ts +5 -5
  10. package/models/iTemperaturDataPoint.ts +9 -9
  11. package/models/lampSettings.ts +5 -5
  12. package/models/ledSettings.ts +19 -19
  13. package/models/logLevel.ts +9 -9
  14. package/models/persistence/BasicRoomInfo.ts +3 -3
  15. package/models/persistence/DailyMovementCount.ts +3 -3
  16. package/models/persistence/RoomDetailInfo.ts +4 -4
  17. package/models/persistence/temperaturDataPoint.ts +12 -12
  18. package/models/persistence/todaysCount.ts +3 -3
  19. package/models/rooms/RoomBase.ts +357 -357
  20. package/models/rooms/RoomSettings/RoomSettings.ts +159 -159
  21. package/models/rooms/RoomSettings/hmIPRoomSettings.ts +53 -53
  22. package/models/rooms/RoomSettings/iRoomDefaultSettings.ts +17 -17
  23. package/models/rooms/RoomSettings/readme.md +17 -17
  24. package/models/rooms/RoomSettings/zigbeeRoomSettings.ts +51 -51
  25. package/models/rooms/iRoomImportEnforcer.ts +3 -3
  26. package/models/rooms/readme.md +11 -11
  27. package/models/temperaturSettings.ts +22 -22
  28. package/models/timeCallback.ts +90 -90
  29. package/package.json +1 -1
  30. package/server/config/config-readme.md +19 -19
  31. package/server/config/iConfig.ts +53 -53
  32. package/server/config/private/mainConfig.json +64 -64
  33. package/server/devices/DeviceInfo.ts +66 -66
  34. package/server/devices/Griffe.ts +31 -31
  35. package/server/devices/Heizgruppen.ts +91 -91
  36. package/server/devices/Rollos.ts +48 -48
  37. package/server/devices/deviceUpdater.ts +72 -72
  38. package/server/devices/devices.ts +189 -189
  39. package/server/devices/groups/fensterGroup.ts +175 -175
  40. package/server/devices/groups/heatGroup.ts +32 -32
  41. package/server/devices/groups/lampenGroup.ts +88 -88
  42. package/server/devices/groups/praesenzGroup.ts +182 -182
  43. package/server/devices/groups/smokeGroup.ts +16 -16
  44. package/server/devices/groups/sonosGroup.ts +33 -33
  45. package/server/devices/groups/tasterGroup.ts +48 -48
  46. package/server/devices/groups/waterGroup.ts +16 -16
  47. package/server/devices/hmIPDevices/Fenster.ts +114 -114
  48. package/server/devices/hmIPDevices/FensterPosition.ts +5 -5
  49. package/server/devices/hmIPDevices/TuerPosition.ts +4 -4
  50. package/server/devices/hmIPDevices/hmIpBewegung.ts +126 -126
  51. package/server/devices/hmIPDevices/hmIpDevice.ts +90 -90
  52. package/server/devices/hmIPDevices/hmIpDeviceType.ts +14 -14
  53. package/server/devices/hmIPDevices/hmIpGriff.ts +143 -143
  54. package/server/devices/hmIPDevices/hmIpHeizgruppe.ts +172 -172
  55. package/server/devices/hmIPDevices/hmIpHeizung.ts +69 -69
  56. package/server/devices/hmIPDevices/hmIpLampe.ts +119 -119
  57. package/server/devices/hmIPDevices/hmIpPraezenz.ts +99 -99
  58. package/server/devices/hmIPDevices/hmIpRoll.ts +133 -133
  59. package/server/devices/hmIPDevices/hmIpTaster.ts +82 -73
  60. package/server/devices/hmIPDevices/hmIpTherm.ts +19 -19
  61. package/server/devices/hmIPDevices/hmIpTuer.ts +115 -115
  62. package/server/devices/hmIPDevices/hmIpWippe.ts +55 -55
  63. package/server/devices/iDeviceUpdater.ts +4 -4
  64. package/server/devices/iIoBrokerDevice.ts +44 -44
  65. package/server/devices/iTaster.ts +6 -0
  66. package/server/devices/{hmIPDevices/hmIpTaste.ts → taste.ts} +84 -72
  67. package/server/devices/wledDevice.ts +124 -124
  68. package/server/devices/zigbee/ZigbeeActuator.ts +113 -113
  69. package/server/devices/zigbee/zigbeeAquaraVibra.ts +171 -171
  70. package/server/devices/zigbee/zigbeeAquaraWater.ts +94 -94
  71. package/server/devices/zigbee/zigbeeBlitzShp.ts +77 -77
  72. package/server/devices/zigbee/zigbeeDevice.ts +115 -115
  73. package/server/devices/zigbee/zigbeeDeviceType.ts +13 -13
  74. package/server/devices/zigbee/zigbeeHeimanSmoke.ts +99 -99
  75. package/server/devices/zigbee/zigbeeIkeaSteckdose.ts +31 -31
  76. package/server/devices/zigbee/zigbeeIlluActuator.ts +37 -37
  77. package/server/devices/zigbee/zigbeeIlluDimmer.ts +165 -165
  78. package/server/devices/zigbee/zigbeeIlluLampe.ts +33 -33
  79. package/server/devices/zigbee/zigbeeIlluLedRGBCCT.ts +137 -137
  80. package/server/ioBroker/connection.ts +1655 -1655
  81. package/server/ioBroker/ioBroker.main.ts +99 -99
  82. package/server/ioBroker/socketIOAuthInfo.ts +5 -5
  83. package/server/ioBroker/socketIOConnectOptions.ts +6 -6
  84. package/server/ioBroker/socketIOLogging.ts +29 -29
  85. package/server/ioBroker/socketIOVisCommand.ts +11 -11
  86. package/server/services/HTTPSOptions.ts +14 -14
  87. package/server/services/Sonos/OwnSonosDevices.ts +9 -0
  88. package/server/services/Sonos/mp3-server.ts +75 -75
  89. package/server/services/Sonos/polly-service.ts +100 -100
  90. package/server/services/Sonos/sonos-service.ts +194 -199
  91. package/server/services/Telegram/telegram-Commands.ts +237 -215
  92. package/server/services/Telegram/telegram-service.ts +171 -171
  93. package/server/services/Telegram/telegramMessageCalback.ts +11 -11
  94. package/server/services/calendar/muell-tonne.ts +82 -83
  95. package/server/services/calendar/m/303/274ll-service.ts +147 -146
  96. package/server/services/dbo/persist.ts +125 -125
  97. package/server/services/https-service.ts +71 -71
  98. package/server/services/log-service.ts +69 -69
  99. package/server/services/news-service.ts +81 -81
  100. package/server/services/settings-service.ts +15 -15
  101. package/server/services/time-callback-service.ts +223 -223
  102. package/server/services/utils/ringstorage.ts +24 -24
  103. package/server/services/utils/utils.ts +52 -52
  104. package/server/services/weather/weather-alert.ts +7 -7
  105. package/server/services/weather/weather-current.ts +26 -26
  106. package/server/services/weather/weather-daily.ts +22 -22
  107. package/server/services/weather/weather-feelsLike.ts +6 -6
  108. package/server/services/weather/weather-hourly.ts +17 -17
  109. package/server/services/weather/weather-item.ts +6 -6
  110. package/server/services/weather/weather-minutes.ts +4 -4
  111. package/server/services/weather/weather-service.ts +277 -277
  112. package/server/services/weather/weather-temp.ts +8 -8
  113. package/tsconfig.json +58 -58
@@ -1,100 +1,100 @@
1
- import AWS from 'aws-sdk';
2
- import { ServerLogService } from '../log-service';
3
- import { LogLevel } from '../../../models/logLevel';
4
- import * as fs from 'fs';
5
- import getMP3Duration from 'get-mp3-duration';
6
- import crypto from 'crypto';
7
- import { iPollySettings } from '../../config/iConfig';
8
-
9
- export class PollyService {
10
- private static _mp3Path: string;
11
- public static active: boolean = false;
12
- public static polly: AWS.Polly;
13
- public static voice: string;
14
-
15
- public static initialize(config: iPollySettings): void {
16
- this.active = true;
17
- this._mp3Path = config.mp3Path;
18
- this.polly = new AWS.Polly({
19
- region: config.region,
20
- signatureVersion: config.signatureVersion,
21
- credentials: {
22
- accessKeyId: config.accessKeyId,
23
- secretAccessKey: config.secretAccessKey,
24
- },
25
- });
26
- this.voice = config.voiceID;
27
- }
28
-
29
- public static getDuration(name: string): number {
30
- const fPath: string = this._mp3Path + name + '.mp3';
31
- try {
32
- if (fs.existsSync(fPath)) {
33
- const duration: number = getMP3Duration(fs.readFileSync(fPath));
34
- return duration;
35
- }
36
- } catch (err) {
37
- console.error(err);
38
- }
39
- return 1800000;
40
- }
41
-
42
- public static preloadTTS(text: string): void {
43
- if (!this.active) {
44
- return;
45
- }
46
- this.tts(text, (link, duration) => {
47
- if (duration <= 0) {
48
- ServerLogService.writeLog(LogLevel.Error, `Retrieving tts for "${text}" failed as duration is 0 or lower`);
49
- } else if (!link) {
50
- ServerLogService.writeLog(LogLevel.Error, `Retrieving tts for "${text}" failed as link is empty`);
51
- }
52
- });
53
- }
54
-
55
- public static tts(text: string, cb: (fileLink: string, duration: number) => void): void {
56
- const hash: string = `${this.voice}_${crypto.createHash('md5').update(text).digest('hex')}`;
57
- const fPath: string = `${this._mp3Path}${hash}.mp3`;
58
- try {
59
- if (fs.existsSync(fPath)) {
60
- const duration: number = getMP3Duration(fs.readFileSync(fPath));
61
- cb(hash, duration);
62
- return;
63
- }
64
- } catch (err) {
65
- console.error(err);
66
- }
67
-
68
- ServerLogService.writeLog(LogLevel.Debug, `Für die Nachricht "${text}" fehlt die TTS --> bei AWS anfragen`);
69
- const params: AWS.Polly.SynthesizeSpeechInput = {
70
- Text: text,
71
- OutputFormat: 'mp3',
72
- VoiceId: this.voice,
73
- };
74
- this.polly.synthesizeSpeech(params, (err, data) => {
75
- if (err) {
76
- ServerLogService.writeLog(LogLevel.Error, `AWS Polly Error: ${err}`);
77
- return;
78
- }
79
-
80
- if (!data || data.AudioStream === undefined) {
81
- ServerLogService.writeLog(LogLevel.Error, `AWS Polly didn't send any data`);
82
- return;
83
- }
84
-
85
- ServerLogService.writeLog(LogLevel.Debug, `AWS Antwort für (${hash}) erhalten Text: "${text}"`);
86
-
87
- fs.writeFile(fPath, data.AudioStream as string | NodeJS.ArrayBufferView, (err) => {
88
- const duration: number = getMP3Duration(data.AudioStream);
89
- if (err) {
90
- ServerLogService.writeLog(LogLevel.Error, `AWS Polly: Saving failed`);
91
- return;
92
- }
93
- ServerLogService.writeLog(LogLevel.Trace, `AWS Polly: Saving sucessfully`);
94
-
95
- cb(hash, duration);
96
- return;
97
- });
98
- });
99
- }
100
- }
1
+ import AWS from 'aws-sdk';
2
+ import { ServerLogService } from '../log-service';
3
+ import { LogLevel } from '../../../models/logLevel';
4
+ import * as fs from 'fs';
5
+ import getMP3Duration from 'get-mp3-duration';
6
+ import crypto from 'crypto';
7
+ import { iPollySettings } from '../../config/iConfig';
8
+
9
+ export class PollyService {
10
+ private static _mp3Path: string;
11
+ public static active: boolean = false;
12
+ public static polly: AWS.Polly;
13
+ public static voice: string;
14
+
15
+ public static initialize(config: iPollySettings): void {
16
+ this.active = true;
17
+ this._mp3Path = config.mp3Path;
18
+ this.polly = new AWS.Polly({
19
+ region: config.region,
20
+ signatureVersion: config.signatureVersion,
21
+ credentials: {
22
+ accessKeyId: config.accessKeyId,
23
+ secretAccessKey: config.secretAccessKey,
24
+ },
25
+ });
26
+ this.voice = config.voiceID;
27
+ }
28
+
29
+ public static getDuration(name: string): number {
30
+ const fPath: string = this._mp3Path + name + '.mp3';
31
+ try {
32
+ if (fs.existsSync(fPath)) {
33
+ const duration: number = getMP3Duration(fs.readFileSync(fPath));
34
+ return duration;
35
+ }
36
+ } catch (err) {
37
+ console.error(err);
38
+ }
39
+ return 1800000;
40
+ }
41
+
42
+ public static preloadTTS(text: string): void {
43
+ if (!this.active) {
44
+ return;
45
+ }
46
+ this.tts(text, (link, duration) => {
47
+ if (duration <= 0) {
48
+ ServerLogService.writeLog(LogLevel.Error, `Retrieving tts for "${text}" failed as duration is 0 or lower`);
49
+ } else if (!link) {
50
+ ServerLogService.writeLog(LogLevel.Error, `Retrieving tts for "${text}" failed as link is empty`);
51
+ }
52
+ });
53
+ }
54
+
55
+ public static tts(text: string, cb: (fileLink: string, duration: number) => void): void {
56
+ const hash: string = `${this.voice}_${crypto.createHash('md5').update(text).digest('hex')}`;
57
+ const fPath: string = `${this._mp3Path}${hash}.mp3`;
58
+ try {
59
+ if (fs.existsSync(fPath)) {
60
+ const duration: number = getMP3Duration(fs.readFileSync(fPath));
61
+ cb(hash, duration);
62
+ return;
63
+ }
64
+ } catch (err) {
65
+ console.error(err);
66
+ }
67
+
68
+ ServerLogService.writeLog(LogLevel.Debug, `Für die Nachricht "${text}" fehlt die TTS --> bei AWS anfragen`);
69
+ const params: AWS.Polly.SynthesizeSpeechInput = {
70
+ Text: text,
71
+ OutputFormat: 'mp3',
72
+ VoiceId: this.voice,
73
+ };
74
+ this.polly.synthesizeSpeech(params, (err, data) => {
75
+ if (err) {
76
+ ServerLogService.writeLog(LogLevel.Error, `AWS Polly Error: ${err}`);
77
+ return;
78
+ }
79
+
80
+ if (!data || data.AudioStream === undefined) {
81
+ ServerLogService.writeLog(LogLevel.Error, `AWS Polly didn't send any data`);
82
+ return;
83
+ }
84
+
85
+ ServerLogService.writeLog(LogLevel.Debug, `AWS Antwort für (${hash}) erhalten Text: "${text}"`);
86
+
87
+ fs.writeFile(fPath, data.AudioStream as string | NodeJS.ArrayBufferView, (err) => {
88
+ const duration: number = getMP3Duration(data.AudioStream);
89
+ if (err) {
90
+ ServerLogService.writeLog(LogLevel.Error, `AWS Polly: Saving failed`);
91
+ return;
92
+ }
93
+ ServerLogService.writeLog(LogLevel.Trace, `AWS Polly: Saving sucessfully`);
94
+
95
+ cb(hash, duration);
96
+ return;
97
+ });
98
+ });
99
+ }
100
+ }
@@ -1,199 +1,194 @@
1
- import { SonosDevice, SonosManager } from '@svrooij/sonos/lib';
2
- import { PlayNotificationOptions } from '@svrooij/sonos/lib/models';
3
- import { ServerLogService } from '../log-service';
4
- import { PollyService } from './polly-service';
5
- import { LogLevel } from '../../../models/logLevel';
6
- import { Utils } from '../utils/utils';
7
- import { TelegramService } from '../Telegram/telegram-service';
8
- import { TimeCallback, TimeCallbackType } from '../../../models/timeCallback';
9
- import { TimeCallbackService } from '../time-callback-service';
10
-
11
- export class OwnSonosDevice {
12
- public maxPlayOnAllVolume: number = 80;
13
- public playTestMessage() {
14
- SonosService.speakOnDevice(`Ich bin ${this.name}`, this);
15
- }
16
- public constructor(
17
- public name: string,
18
- public roomName: string,
19
- public device: SonosDevice | undefined,
20
- ) {};
21
- }
22
-
23
- export class SonosService {
24
- private static sonosManager: SonosManager;
25
- private static ownDevices: { [name: string]: OwnSonosDevice } = {};
26
-
27
- private static isInitialized: boolean;
28
- public static all: SonosDevice[] = [];
29
- public static devicesDict: { [name: string]: SonosDevice } = {};
30
- private static checkTimeCallback: TimeCallback;
31
- private static reinitializationDevice: OwnSonosDevice | undefined;
32
-
33
- public static addOwnDevices(
34
- snDevices: { [name: string]: OwnSonosDevice },
35
- reinitializationDevice?: OwnSonosDevice
36
- ): void {
37
- this.ownDevices = snDevices;
38
- this.reinitializationDevice = reinitializationDevice;
39
- }
40
-
41
- public static initialize(reinitialize: boolean = false): void {
42
- ServerLogService.writeLog(LogLevel.Debug, `Initialisiere Sonos Service`);
43
- if (!reinitialize) {
44
- this.checkTimeCallback = new TimeCallback(
45
- 'SonosFunctionallityChecker',
46
- TimeCallbackType.TimeOfDay,
47
- () => {
48
- this.checkAll();
49
- },
50
- 0,
51
- 23,
52
- 30,
53
- );
54
- TimeCallbackService.addCallback(this.checkTimeCallback);
55
- }
56
- this.all = [];
57
- this.sonosManager = new SonosManager();
58
- this.sonosManager
59
- .InitializeWithDiscovery(10)
60
- .then(() => {
61
- this.sonosManager.OnNewDevice((d: SonosDevice) => {
62
- ServerLogService.writeLog(LogLevel.Info, `SonosDevice ${d.Name} joined`);
63
- SonosService.initializeDevice(d);
64
- });
65
- ServerLogService.writeLog(LogLevel.Debug, `${this.sonosManager.Devices.length} Sonos Geräte gefunden.`);
66
- this.sonosManager.Devices.forEach((d: SonosDevice) => {
67
- SonosService.initializeDevice(d);
68
- });
69
- this.isInitialized = true;
70
- if (!reinitialize && this.reinitializationDevice !== undefined) {
71
- this.speakOnDevice(
72
- `Sonos System initialisiert und bereit für Sprachausgaben.`,
73
- this.reinitializationDevice,
74
- 30
75
- );
76
- }
77
- })
78
- .catch(console.error);
79
- }
80
-
81
- public static async checkAll(): Promise<void> {
82
- let currentDevice: OwnSonosDevice | undefined;
83
- try {
84
- for (const deviceName in this.ownDevices) {
85
- currentDevice = this.ownDevices[deviceName];
86
- if(currentDevice?.device === undefined) {
87
- throw `${currentDevice?.name} is missing`;
88
- }
89
- await currentDevice.device.GetState();
90
- }
91
- if(currentDevice !== undefined) {
92
- ServerLogService.writeLog(LogLevel.Info, `Alle Geräte okay --> Last checked ${currentDevice.name}`);
93
- }
94
- } catch (e) {
95
- ServerLogService.writeLog(
96
- LogLevel.Error,
97
- `Atleast one device failed --> Last checked ${(currentDevice?.name ?? "undefined")}`
98
- );
99
- TelegramService.inform(`Sonos device is failing --> Reinitialize whole system`);
100
- this.initialize(true);
101
- }
102
- }
103
-
104
- public static speakOnAll(pMessage: string, volumeOverride: number = -1): void {
105
- if (!this.isInitialized) {
106
- ServerLogService.writeLog(LogLevel.Alert, `SonosService noch nicht initialisiert.`);
107
- }
108
- PollyService.tts(pMessage, (networkPath: string, duration: number) => {
109
- const hours: number = new Date().getHours();
110
- let volume: number = hours < 10 || hours > 22 ? 40 : 80;
111
-
112
- for (const deviceName in this.ownDevices) {
113
- SonosService.playOnDevice(
114
- this.ownDevices[deviceName],
115
- networkPath,
116
- duration,
117
- (volumeOverride > -1) ? volumeOverride : Math.min(volume, this.ownDevices[deviceName].maxPlayOnAllVolume)
118
- );
119
- }
120
- });
121
- }
122
-
123
- public static playOnDevice(
124
- ownSnDevice: OwnSonosDevice,
125
- mp3Name: string,
126
- duration: number,
127
- volume: number | undefined = undefined,
128
- onlyWhenPlaying: boolean | undefined = undefined,
129
- resolveAfterRevert: boolean | undefined = false,
130
- ): void {
131
- const specificTimeout: number = Math.ceil(duration / 1000) + 5;
132
- const options: PlayNotificationOptions = {
133
- trackUri: `http://192.168.178.13:8081/file.mp3?fname=${mp3Name}`,
134
- delayMs: 750,
135
- onlyWhenPlaying: onlyWhenPlaying,
136
- resolveAfterRevert: resolveAfterRevert,
137
- volume: volume,
138
- specificTimeout: specificTimeout,
139
- notificationFired: (played) => {
140
- ServerLogService.writeLog(
141
- LogLevel.Trace,
142
- `Sonos Notification ("${mp3Name}") was${played ? '' : "n't"} played in ${ownSnDevice.roomName} (duration: "${specificTimeout}")`,
143
- );
144
- },
145
- };
146
- try {
147
- const device: SonosDevice| undefined = ownSnDevice.device;
148
- if (device === undefined) {
149
- ServerLogService.writeLog(LogLevel.Alert, `Sonos Geräte ${ownSnDevice.name} ist nicht initialisiert`);
150
- Utils.guardedTimeout(
151
- () => {
152
- this.initialize();
153
- },
154
- 500,
155
- this,
156
- );
157
- return;
158
- }
159
- ServerLogService.writeLog(
160
- LogLevel.Trace,
161
- `Spiele nun die Ausgabe für "${mp3Name}" auf "${ownSnDevice.name}"`,
162
- );
163
- device.PlayNotificationTwo(options).then((played) => {
164
- ServerLogService.writeLog(
165
- LogLevel.Debug,
166
- `Sonos Notification ("${mp3Name}") was${played ? '' : "n't"} played in ${
167
- ownSnDevice.roomName
168
- } (duration: "${specificTimeout}")`,
169
- );
170
- });
171
- } catch (err) {
172
- ServerLogService.writeLog(LogLevel.Info, `Sonos Error ${err.message}: ${err.stack}`);
173
- }
174
- }
175
-
176
- public static speakOnDevice(
177
- pMessage: string,
178
- ownSnDevice: OwnSonosDevice,
179
- volume: number | undefined = undefined,
180
- onlyWhenPlaying: boolean | undefined = undefined,
181
- resolveAfterRevert: boolean | undefined = undefined,
182
- ): void {
183
- PollyService.tts(pMessage, (networkPath: string, duration: number) => {
184
- SonosService.playOnDevice(ownSnDevice, networkPath, duration, volume, onlyWhenPlaying, resolveAfterRevert);
185
- });
186
- }
187
-
188
- public static speakTestMessageOnEachDevice(): void {
189
- for (const deviceName in this.ownDevices) {
190
- this.ownDevices[deviceName].playTestMessage();
191
- }
192
- }
193
-
194
- private static initializeDevice(d: SonosDevice) {
195
- this.devicesDict[d.Name] = d;
196
- this.ownDevices[d.Name].device = d;
197
- ServerLogService.writeLog(LogLevel.Debug, `Sonos ${d.Uuid} für ${d.Name} gefunden`);
198
- }
199
- }
1
+ import { SonosDevice, SonosManager } from '@svrooij/sonos/lib';
2
+ import { PlayNotificationOptions } from '@svrooij/sonos/lib/models';
3
+ import { ServerLogService } from '../log-service';
4
+ import { PollyService } from './polly-service';
5
+ import { LogLevel } from '../../../models/logLevel';
6
+ import { Utils } from '../utils/utils';
7
+ import { TelegramService } from '../Telegram/telegram-service';
8
+ import { TimeCallback, TimeCallbackType } from '../../../models/timeCallback';
9
+ import { TimeCallbackService } from '../time-callback-service';
10
+
11
+ export class OwnSonosDevice {
12
+ public maxPlayOnAllVolume: number = 80;
13
+ public playTestMessage() {
14
+ SonosService.speakOnDevice(`Ich bin ${this.name}`, this);
15
+ }
16
+ public constructor(public name: string, public roomName: string, public device: SonosDevice | undefined) {}
17
+ }
18
+
19
+ export class SonosService {
20
+ private static sonosManager: SonosManager;
21
+ private static ownDevices: { [name: string]: OwnSonosDevice } = {};
22
+
23
+ private static isInitialized: boolean;
24
+ public static all: SonosDevice[] = [];
25
+ public static devicesDict: { [name: string]: SonosDevice } = {};
26
+ private static checkTimeCallback: TimeCallback;
27
+ private static reinitializationDevice: OwnSonosDevice | undefined;
28
+
29
+ public static addOwnDevices(
30
+ snDevices: { [name: string]: OwnSonosDevice },
31
+ reinitializationDevice?: OwnSonosDevice,
32
+ ): void {
33
+ this.ownDevices = snDevices;
34
+ this.reinitializationDevice = reinitializationDevice;
35
+ }
36
+
37
+ public static initialize(reinitialize: boolean = false): void {
38
+ ServerLogService.writeLog(LogLevel.Debug, `Initialisiere Sonos Service`);
39
+ if (!reinitialize) {
40
+ this.checkTimeCallback = new TimeCallback(
41
+ 'SonosFunctionallityChecker',
42
+ TimeCallbackType.TimeOfDay,
43
+ () => {
44
+ this.checkAll();
45
+ },
46
+ 0,
47
+ 23,
48
+ 30,
49
+ );
50
+ TimeCallbackService.addCallback(this.checkTimeCallback);
51
+ }
52
+ this.all = [];
53
+ this.sonosManager = new SonosManager();
54
+ this.sonosManager
55
+ .InitializeWithDiscovery(10)
56
+ .then(() => {
57
+ this.sonosManager.OnNewDevice((d: SonosDevice) => {
58
+ ServerLogService.writeLog(LogLevel.Info, `SonosDevice ${d.Name} joined`);
59
+ SonosService.initializeDevice(d);
60
+ });
61
+ ServerLogService.writeLog(LogLevel.Debug, `${this.sonosManager.Devices.length} Sonos Geräte gefunden.`);
62
+ this.sonosManager.Devices.forEach((d: SonosDevice) => {
63
+ SonosService.initializeDevice(d);
64
+ });
65
+ this.isInitialized = true;
66
+ if (!reinitialize && this.reinitializationDevice !== undefined) {
67
+ this.speakOnDevice(
68
+ `Sonos System initialisiert und bereit für Sprachausgaben.`,
69
+ this.reinitializationDevice,
70
+ 30,
71
+ );
72
+ }
73
+ })
74
+ .catch(console.error);
75
+ }
76
+
77
+ public static async checkAll(): Promise<void> {
78
+ let currentDevice: OwnSonosDevice | undefined;
79
+ try {
80
+ for (const deviceName in this.ownDevices) {
81
+ currentDevice = this.ownDevices[deviceName];
82
+ if (currentDevice?.device === undefined) {
83
+ throw `${currentDevice?.name} is missing`;
84
+ }
85
+ await currentDevice.device.GetState();
86
+ }
87
+ if (currentDevice !== undefined) {
88
+ ServerLogService.writeLog(LogLevel.Info, `Alle Geräte okay --> Last checked ${currentDevice.name}`);
89
+ }
90
+ } catch (e) {
91
+ ServerLogService.writeLog(
92
+ LogLevel.Error,
93
+ `Atleast one device failed --> Last checked ${currentDevice?.name ?? 'undefined'}`,
94
+ );
95
+ TelegramService.inform(`Sonos device is failing --> Reinitialize whole system`);
96
+ this.initialize(true);
97
+ }
98
+ }
99
+
100
+ public static speakOnAll(pMessage: string, volumeOverride: number = -1): void {
101
+ if (!this.isInitialized) {
102
+ ServerLogService.writeLog(LogLevel.Alert, `SonosService noch nicht initialisiert.`);
103
+ }
104
+ PollyService.tts(pMessage, (networkPath: string, duration: number) => {
105
+ const hours: number = new Date().getHours();
106
+ const volume: number = hours < 10 || hours > 22 ? 40 : 80;
107
+
108
+ for (const deviceName in this.ownDevices) {
109
+ SonosService.playOnDevice(
110
+ this.ownDevices[deviceName],
111
+ networkPath,
112
+ duration,
113
+ volumeOverride > -1 ? volumeOverride : Math.min(volume, this.ownDevices[deviceName].maxPlayOnAllVolume),
114
+ );
115
+ }
116
+ });
117
+ }
118
+
119
+ public static playOnDevice(
120
+ ownSnDevice: OwnSonosDevice,
121
+ mp3Name: string,
122
+ duration: number,
123
+ volume: number | undefined = undefined,
124
+ onlyWhenPlaying: boolean | undefined = undefined,
125
+ resolveAfterRevert: boolean | undefined = false,
126
+ ): void {
127
+ const specificTimeout: number = Math.ceil(duration / 1000) + 5;
128
+ const options: PlayNotificationOptions = {
129
+ trackUri: `http://192.168.178.13:8081/file.mp3?fname=${mp3Name}`,
130
+ delayMs: 750,
131
+ onlyWhenPlaying: onlyWhenPlaying,
132
+ resolveAfterRevert: resolveAfterRevert,
133
+ volume: volume,
134
+ specificTimeout: specificTimeout,
135
+ notificationFired: (played) => {
136
+ ServerLogService.writeLog(
137
+ LogLevel.Trace,
138
+ `Sonos Notification ("${mp3Name}") was${played ? '' : "n't"} played in ${
139
+ ownSnDevice.roomName
140
+ } (duration: "${specificTimeout}")`,
141
+ );
142
+ },
143
+ };
144
+ try {
145
+ const device: SonosDevice | undefined = ownSnDevice.device;
146
+ if (device === undefined) {
147
+ ServerLogService.writeLog(LogLevel.Alert, `Sonos Geräte ${ownSnDevice.name} ist nicht initialisiert`);
148
+ Utils.guardedTimeout(
149
+ () => {
150
+ this.initialize();
151
+ },
152
+ 500,
153
+ this,
154
+ );
155
+ return;
156
+ }
157
+ ServerLogService.writeLog(LogLevel.Trace, `Spiele nun die Ausgabe für "${mp3Name}" auf "${ownSnDevice.name}"`);
158
+ device.PlayNotificationTwo(options).then((played) => {
159
+ ServerLogService.writeLog(
160
+ LogLevel.Debug,
161
+ `Sonos Notification ("${mp3Name}") was${played ? '' : "n't"} played in ${
162
+ ownSnDevice.roomName
163
+ } (duration: "${specificTimeout}")`,
164
+ );
165
+ });
166
+ } catch (err) {
167
+ ServerLogService.writeLog(LogLevel.Info, `Sonos Error ${err.message}: ${err.stack}`);
168
+ }
169
+ }
170
+
171
+ public static speakOnDevice(
172
+ pMessage: string,
173
+ ownSnDevice: OwnSonosDevice,
174
+ volume: number | undefined = undefined,
175
+ onlyWhenPlaying: boolean | undefined = undefined,
176
+ resolveAfterRevert: boolean | undefined = undefined,
177
+ ): void {
178
+ PollyService.tts(pMessage, (networkPath: string, duration: number) => {
179
+ SonosService.playOnDevice(ownSnDevice, networkPath, duration, volume, onlyWhenPlaying, resolveAfterRevert);
180
+ });
181
+ }
182
+
183
+ public static speakTestMessageOnEachDevice(): void {
184
+ for (const deviceName in this.ownDevices) {
185
+ this.ownDevices[deviceName].playTestMessage();
186
+ }
187
+ }
188
+
189
+ private static initializeDevice(d: SonosDevice) {
190
+ this.devicesDict[d.Name] = d;
191
+ this.ownDevices[d.Name].device = d;
192
+ ServerLogService.writeLog(LogLevel.Debug, `Sonos ${d.Uuid} für ${d.Name} gefunden`);
193
+ }
194
+ }