iobroker.webuntis2 0.1.0 → 0.1.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.
package/README.de.md CHANGED
@@ -74,6 +74,10 @@ nicht vertrauliche Logmeldungen.
74
74
 
75
75
  ## Änderungsverlauf
76
76
 
77
+ ### 0.1.1 (2026-09-12)
78
+
79
+ - (@Voodoo2man) Verbesserte rollierende Sieben-Tage-Ansicht und Wochentagszusammenfassungen ergänzt. Datumsfelder enthalten jetzt reine Datumswerte sowie zusätzliche Unix-Zeitstempel in Millisekunden.
80
+
77
81
  ### 0.1.0 (2026-09-11)
78
82
 
79
83
  - (@Voodoo2man) Vollständige Funktionsveröffentlichung mit Stundenplandaten, Ferienterminen, verständlichen Stundennamen, Tagesübersichten, Informationen zur aktuellen und nächsten Stunde sowie React-Administrationsoberfläche.
package/README.md CHANGED
@@ -69,6 +69,12 @@ and include only relevant, non-sensitive log messages when asking for help.
69
69
 
70
70
  ## Changelog
71
71
 
72
+ ### 0.1.1 (2026-09-12)
73
+
74
+ - (@Voodoo2man) Improved the rolling seven-day timetable and added weekly summary states. Date fields now contain date-only values and companion Unix timestamps in milliseconds.
75
+
76
+ For earlier releases, see [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
77
+
72
78
  ### 0.1.0 (2026-09-11)
73
79
 
74
80
  - (@Voodoo2man) Complete feature release with timetable data, holidays, readable lesson names, daily summaries, current and next lesson information, and the React administration interface.
@@ -87,4 +93,4 @@ and include only relevant, non-sensitive log messages when asking for help.
87
93
 
88
94
  Copyright (c) 2026 Voodoo2man <Voodoo2man@outlook.de>
89
95
 
90
- MIT License. See [LICENSE](LICENSE).
96
+ MIT License. See [LICENSE](LICENSE).
@@ -22,6 +22,7 @@ __export(Timetable_exports, {
22
22
  dateNumber: () => dateNumber,
23
23
  dayRange: () => dayRange,
24
24
  lessonChannelName: () => lessonChannelName,
25
+ nextWeekday: () => nextWeekday,
25
26
  normalizeLesson: () => normalizeLesson,
26
27
  normalizeLessons: () => normalizeLessons,
27
28
  resolveTimetableReferences: () => resolveTimetableReferences,
@@ -167,14 +168,21 @@ function dateNumber(date) {
167
168
  `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, "0")}${String(date.getDate()).padStart(2, "0")}`
168
169
  );
169
170
  }
171
+ function nextWeekday(date, targetWeekday) {
172
+ const result = new Date(date);
173
+ result.setHours(12, 0, 0, 0);
174
+ const currentWeekday = (result.getDay() + 6) % 7;
175
+ result.setDate(result.getDate() + (targetWeekday - currentWeekday + 7) % 7);
176
+ return result;
177
+ }
170
178
  function dayRange(date) {
171
179
  return { startDate: dateNumber(date), endDate: dateNumber(date) };
172
180
  }
173
181
  function weekRange(date) {
174
182
  const start = new Date(date);
175
- start.setDate(start.getDate() - start.getDay() + 1);
183
+ start.setHours(12, 0, 0, 0);
176
184
  const end = new Date(start);
177
- end.setDate(start.getDate() + 4);
185
+ end.setDate(end.getDate() + 6);
178
186
  return { startDate: dateNumber(start), endDate: dateNumber(end) };
179
187
  }
180
188
  function splitTimetable(lessons, today) {
@@ -200,6 +208,7 @@ function assertTimetableResponse(value) {
200
208
  dateNumber,
201
209
  dayRange,
202
210
  lessonChannelName,
211
+ nextWeekday,
203
212
  normalizeLesson,
204
213
  normalizeLessons,
205
214
  resolveTimetableReferences,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/webuntis/Timetable.ts"],
4
- "sourcesContent": ["/* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param, jsdoc/no-blank-blocks */\n\nimport { createHash } from \"node:crypto\";\nimport { WebUntisError } from \"./WebUntisErrors\";\nimport type { WebUntisPeriod } from \"./WebUntisTypes\";\n\n/**\n *\n */\nexport interface TimetableLesson {\n\t/**\n\t *\n\t */\n\tid: string;\n\t/**\n\t *\n\t */\n\tdate: string;\n\t/**\n\t *\n\t */\n\tstartTime: string;\n\t/**\n\t *\n\t */\n\tendTime: string;\n\t/**\n\t *\n\t */\n\tsubject: string;\n\t/**\n\t *\n\t */\n\tsubjectLong: string;\n\t/**\n\t *\n\t */\n\tteacher: string;\n\t/**\n\t *\n\t */\n\troom: string;\n\t/**\n\t *\n\t */\n\tclass: string;\n\t/**\n\t *\n\t */\n\tlessonId: number | null;\n\t/**\n\t *\n\t */\n\tperiodId: number | null;\n\t/**\n\t *\n\t */\n\tstatus: string;\n\t/**\n\t *\n\t */\n\tchanged: boolean;\n\t/**\n\t *\n\t */\n\tcancelled: boolean;\n\t/**\n\t *\n\t */\n\tsubstitution: string;\n\t/**\n\t *\n\t */\n\toriginalTeacher: string;\n\t/**\n\t *\n\t */\n\toriginalRoom: string;\n\t/**\n\t *\n\t */\n\toriginalSubject: string;\n}\n\nexport interface TimetableSummary {\n\thasSchool: boolean;\n\tlessonCount: number;\n\tlessonDurationMinutes: number;\n\tschoolStart: string;\n\tschoolEnd: string;\n\tsubjects: string;\n\tsubjectCount: number;\n\tfirstSubject: string;\n\tlastSubject: string;\n\thasChanges: boolean;\n\tchangeCount: number;\n\tcancellationCount: number;\n}\n\nexport interface TimetableMasterData {\n\tsubjects: WebUntisPeriod[];\n\tteachers: WebUntisPeriod[];\n\trooms: WebUntisPeriod[];\n\tklassen: WebUntisPeriod[];\n}\n\nexport function lessonChannelName(lesson: TimetableLesson): string {\n\tconst time =\n\t\tlesson.startTime && lesson.endTime\n\t\t\t? `${lesson.startTime}\u2013${lesson.endTime}`\n\t\t\t: lesson.startTime || lesson.endTime;\n\treturn [time, lesson.subjectLong || lesson.subject, lesson.teacher, lesson.room]\n\t\t.map(value => value.trim())\n\t\t.filter(Boolean)\n\t\t.join(\" \u00B7 \");\n}\n\nfunction text(value: unknown): string {\n\treturn typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n}\n\nfunction firstName(value: unknown, long = false): string {\n\tif (!Array.isArray(value) || !value.length || typeof value[0] !== \"object\" || value[0] === null) {\n\t\treturn \"\";\n\t}\n\tconst item = value[0] as Record<string, unknown>;\n\treturn text(item[long ? \"longname\" : \"name\"] ?? item.longName ?? item.name);\n}\n\nfunction dateString(value: unknown): string {\n\tconst raw = text(value);\n\tif (/^\\d{8}$/.test(raw)) {\n\t\treturn `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6)}`;\n\t}\n\treturn raw;\n}\n\nfunction timeString(value: unknown): string {\n\tconst raw = text(value).padStart(4, \"0\");\n\treturn /^\\d{4}$/.test(raw) ? `${raw.slice(0, 2)}:${raw.slice(2)}` : text(value);\n}\n\nfunction bool(value: unknown): boolean {\n\treturn value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n\nfunction stableId(period: WebUntisPeriod): string {\n\tconst id = period.id ?? period.lessonId ?? period.periodId;\n\tif (typeof id === \"number\" || typeof id === \"string\") {\n\t\treturn `period-${id}`;\n\t}\n\tconst key = [period.date, period.startTime, period.endTime, firstName(period.su), firstName(period.kl)].join(\"|\");\n\treturn `period-${createHash(\"sha1\").update(key).digest(\"hex\").slice(0, 16)}`;\n}\n\n/**\n *\n */\nexport function normalizeLesson(period: WebUntisPeriod): TimetableLesson {\n\tconst substitution = text(period.substText ?? period.substitution ?? period.subst);\n\tconst cancelled = bool(period.cancelled ?? period.isCancelled ?? period.cancelledLesson);\n\tconst changed =\n\t\tcancelled || Boolean(substitution) || Boolean(period.substTeacher ?? period.substRoom ?? period.substSubject);\n\treturn {\n\t\tid: stableId(period),\n\t\tdate: dateString(period.date),\n\t\tstartTime: timeString(period.startTime),\n\t\tendTime: timeString(period.endTime),\n\t\tsubject: firstName(period.su),\n\t\tsubjectLong: firstName(period.su, true),\n\t\tteacher: firstName(period.te),\n\t\troom: firstName(period.ro),\n\t\tclass: firstName(period.kl),\n\t\tlessonId: typeof period.id === \"number\" ? period.id : null,\n\t\tperiodId: typeof period.periodId === \"number\" ? period.periodId : null,\n\t\tstatus: text(period.activityType ?? period.status),\n\t\tchanged,\n\t\tcancelled,\n\t\tsubstitution,\n\t\toriginalTeacher: firstName(period.origTe ?? period.originalTeacher),\n\t\toriginalRoom: firstName(period.origRo ?? period.originalRoom),\n\t\toriginalSubject: firstName(period.origSu ?? period.originalSubject),\n\t};\n}\n\nfunction resolveReferences(value: unknown, masterData: WebUntisPeriod[]): unknown {\n\tif (!Array.isArray(value)) {\n\t\treturn value;\n\t}\n\tconst byId = new Map(\n\t\tmasterData.flatMap(item => {\n\t\t\tconst id = item.id ?? item.elementId;\n\t\t\treturn typeof id === \"string\" || typeof id === \"number\" ? [[String(id), item] as const] : [];\n\t\t}),\n\t);\n\treturn value.map(item => {\n\t\tif (typeof item !== \"object\" || item === null) {\n\t\t\treturn item;\n\t\t}\n\t\tconst id = (item as Record<string, unknown>).id;\n\t\treturn byId.get(String(id)) || item;\n\t});\n}\n\nexport function resolveTimetableReferences(\n\tperiods: WebUntisPeriod[],\n\tmasterData: TimetableMasterData,\n): WebUntisPeriod[] {\n\treturn periods.map(period => ({\n\t\t...period,\n\t\tkl: resolveReferences(period.kl, masterData.klassen),\n\t\tte: resolveReferences(period.te, masterData.teachers),\n\t\tsu: resolveReferences(period.su, masterData.subjects),\n\t\tro: resolveReferences(period.ro, masterData.rooms),\n\t\torigTe: resolveReferences(period.origTe, masterData.teachers),\n\t\torigRo: resolveReferences(period.origRo, masterData.rooms),\n\t\torigSu: resolveReferences(period.origSu, masterData.subjects),\n\t}));\n}\n\n/**\n *\n */\nexport function normalizeLessons(periods: WebUntisPeriod[]): TimetableLesson[] {\n\treturn periods\n\t\t.map(normalizeLesson)\n\t\t.sort((a, b) => `${a.date}${a.startTime}${a.id}`.localeCompare(`${b.date}${b.startTime}${b.id}`));\n}\n\nfunction durationMinutes(startTime: string, endTime: string): number {\n\tconst start = /^([0-9]{2}):([0-9]{2})$/.exec(startTime);\n\tconst end = /^([0-9]{2}):([0-9]{2})$/.exec(endTime);\n\tif (!start || !end) {\n\t\treturn 0;\n\t}\n\tconst startMinutes = Number(start[1]) * 60 + Number(start[2]);\n\tconst endMinutes = Number(end[1]) * 60 + Number(end[2]);\n\treturn Math.max(0, endMinutes - startMinutes);\n}\n\nexport function summarizeTimetable(lessons: TimetableLesson[]): TimetableSummary {\n\tconst subjects = lessons\n\t\t.map(lesson => lesson.subjectLong || lesson.subject)\n\t\t.filter((subject, index, values) => subject !== \"\" && values.indexOf(subject) === index);\n\treturn {\n\t\thasSchool: lessons.length > 0,\n\t\tlessonCount: lessons.length,\n\t\t// Cancelled lessons count as periods but have no actual teaching duration.\n\t\tlessonDurationMinutes: lessons.reduce(\n\t\t\t(total, lesson) => total + (lesson.cancelled ? 0 : durationMinutes(lesson.startTime, lesson.endTime)),\n\t\t\t0,\n\t\t),\n\t\tschoolStart: lessons[0]?.startTime || \"\",\n\t\tschoolEnd: lessons.at(-1)?.endTime || \"\",\n\t\tsubjects: subjects.join(\", \"),\n\t\tsubjectCount: subjects.length,\n\t\tfirstSubject: lessons[0]?.subjectLong || lessons[0]?.subject || \"\",\n\t\tlastSubject: lessons.at(-1)?.subjectLong || lessons.at(-1)?.subject || \"\",\n\t\thasChanges: lessons.some(lesson => lesson.changed || Boolean(lesson.substitution)),\n\t\tchangeCount: lessons.filter(lesson => lesson.changed || Boolean(lesson.substitution)).length,\n\t\tcancellationCount: lessons.filter(lesson => lesson.cancelled).length,\n\t};\n}\n\n/**\n *\n */\nexport function dateNumber(date: Date): number {\n\treturn Number(\n\t\t`${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, \"0\")}${String(date.getDate()).padStart(2, \"0\")}`,\n\t);\n}\n\n/**\n *\n */\nexport function dayRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\treturn { startDate: dateNumber(date), endDate: dateNumber(date) };\n}\n\n/**\n *\n */\nexport function weekRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\tconst start = new Date(date);\n\tstart.setDate(start.getDate() - start.getDay() + 1);\n\tconst end = new Date(start);\n\tend.setDate(start.getDate() + 4);\n\treturn { startDate: dateNumber(start), endDate: dateNumber(end) };\n}\n\n/**\n *\n */\nexport function splitTimetable(\n\tlessons: TimetableLesson[],\n\ttoday: Date,\n): {\n\t/**\n\t *\n\t */\n\ttoday: TimetableLesson[];\n\t/**\n\t *\n\t */\n\ttomorrow: TimetableLesson[];\n\t/**\n\t *\n\t */\n\tweek: TimetableLesson[];\n} {\n\tconst todayKey = dateNumber(today).toString();\n\tconst tomorrow = new Date(today);\n\ttomorrow.setDate(today.getDate() + 1);\n\tconst tomorrowKey = dateNumber(tomorrow).toString();\n\tconst dateKey = (value: string): string => value.replaceAll(\"-\", \"\");\n\treturn {\n\t\ttoday: lessons.filter(lesson => dateKey(lesson.date) === todayKey),\n\t\ttomorrow: lessons.filter(lesson => dateKey(lesson.date) === tomorrowKey),\n\t\tweek: lessons,\n\t};\n}\n\n/**\n *\n */\nexport function assertTimetableResponse(value: unknown): asserts value is WebUntisPeriod[] {\n\tif (!Array.isArray(value) || !value.every(period => typeof period === \"object\" && period !== null)) {\n\t\tthrow new WebUntisError(\"INVALID_RESPONSE\", \"Invalid WebUntis timetable result\");\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param, jsdoc/no-blank-blocks */\n\nimport { createHash } from \"node:crypto\";\nimport { WebUntisError } from \"./WebUntisErrors\";\nimport type { WebUntisPeriod } from \"./WebUntisTypes\";\n\n/**\n *\n */\nexport interface TimetableLesson {\n\t/**\n\t *\n\t */\n\tid: string;\n\t/**\n\t *\n\t */\n\tdate: string;\n\t/**\n\t *\n\t */\n\tstartTime: string;\n\t/**\n\t *\n\t */\n\tendTime: string;\n\t/**\n\t *\n\t */\n\tsubject: string;\n\t/**\n\t *\n\t */\n\tsubjectLong: string;\n\t/**\n\t *\n\t */\n\tteacher: string;\n\t/**\n\t *\n\t */\n\troom: string;\n\t/**\n\t *\n\t */\n\tclass: string;\n\t/**\n\t *\n\t */\n\tlessonId: number | null;\n\t/**\n\t *\n\t */\n\tperiodId: number | null;\n\t/**\n\t *\n\t */\n\tstatus: string;\n\t/**\n\t *\n\t */\n\tchanged: boolean;\n\t/**\n\t *\n\t */\n\tcancelled: boolean;\n\t/**\n\t *\n\t */\n\tsubstitution: string;\n\t/**\n\t *\n\t */\n\toriginalTeacher: string;\n\t/**\n\t *\n\t */\n\toriginalRoom: string;\n\t/**\n\t *\n\t */\n\toriginalSubject: string;\n}\n\nexport interface TimetableSummary {\n\thasSchool: boolean;\n\tlessonCount: number;\n\tlessonDurationMinutes: number;\n\tschoolStart: string;\n\tschoolEnd: string;\n\tsubjects: string;\n\tsubjectCount: number;\n\tfirstSubject: string;\n\tlastSubject: string;\n\thasChanges: boolean;\n\tchangeCount: number;\n\tcancellationCount: number;\n}\n\nexport interface TimetableMasterData {\n\tsubjects: WebUntisPeriod[];\n\tteachers: WebUntisPeriod[];\n\trooms: WebUntisPeriod[];\n\tklassen: WebUntisPeriod[];\n}\n\nexport function lessonChannelName(lesson: TimetableLesson): string {\n\tconst time =\n\t\tlesson.startTime && lesson.endTime\n\t\t\t? `${lesson.startTime}\u2013${lesson.endTime}`\n\t\t\t: lesson.startTime || lesson.endTime;\n\treturn [time, lesson.subjectLong || lesson.subject, lesson.teacher, lesson.room]\n\t\t.map(value => value.trim())\n\t\t.filter(Boolean)\n\t\t.join(\" \u00B7 \");\n}\n\nfunction text(value: unknown): string {\n\treturn typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n}\n\nfunction firstName(value: unknown, long = false): string {\n\tif (!Array.isArray(value) || !value.length || typeof value[0] !== \"object\" || value[0] === null) {\n\t\treturn \"\";\n\t}\n\tconst item = value[0] as Record<string, unknown>;\n\treturn text(item[long ? \"longname\" : \"name\"] ?? item.longName ?? item.name);\n}\n\nfunction dateString(value: unknown): string {\n\tconst raw = text(value);\n\tif (/^\\d{8}$/.test(raw)) {\n\t\treturn `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6)}`;\n\t}\n\treturn raw;\n}\n\nfunction timeString(value: unknown): string {\n\tconst raw = text(value).padStart(4, \"0\");\n\treturn /^\\d{4}$/.test(raw) ? `${raw.slice(0, 2)}:${raw.slice(2)}` : text(value);\n}\n\nfunction bool(value: unknown): boolean {\n\treturn value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n\nfunction stableId(period: WebUntisPeriod): string {\n\tconst id = period.id ?? period.lessonId ?? period.periodId;\n\tif (typeof id === \"number\" || typeof id === \"string\") {\n\t\treturn `period-${id}`;\n\t}\n\tconst key = [period.date, period.startTime, period.endTime, firstName(period.su), firstName(period.kl)].join(\"|\");\n\treturn `period-${createHash(\"sha1\").update(key).digest(\"hex\").slice(0, 16)}`;\n}\n\n/**\n *\n */\nexport function normalizeLesson(period: WebUntisPeriod): TimetableLesson {\n\tconst substitution = text(period.substText ?? period.substitution ?? period.subst);\n\tconst cancelled = bool(period.cancelled ?? period.isCancelled ?? period.cancelledLesson);\n\tconst changed =\n\t\tcancelled || Boolean(substitution) || Boolean(period.substTeacher ?? period.substRoom ?? period.substSubject);\n\treturn {\n\t\tid: stableId(period),\n\t\tdate: dateString(period.date),\n\t\tstartTime: timeString(period.startTime),\n\t\tendTime: timeString(period.endTime),\n\t\tsubject: firstName(period.su),\n\t\tsubjectLong: firstName(period.su, true),\n\t\tteacher: firstName(period.te),\n\t\troom: firstName(period.ro),\n\t\tclass: firstName(period.kl),\n\t\tlessonId: typeof period.id === \"number\" ? period.id : null,\n\t\tperiodId: typeof period.periodId === \"number\" ? period.periodId : null,\n\t\tstatus: text(period.activityType ?? period.status),\n\t\tchanged,\n\t\tcancelled,\n\t\tsubstitution,\n\t\toriginalTeacher: firstName(period.origTe ?? period.originalTeacher),\n\t\toriginalRoom: firstName(period.origRo ?? period.originalRoom),\n\t\toriginalSubject: firstName(period.origSu ?? period.originalSubject),\n\t};\n}\n\nfunction resolveReferences(value: unknown, masterData: WebUntisPeriod[]): unknown {\n\tif (!Array.isArray(value)) {\n\t\treturn value;\n\t}\n\tconst byId = new Map(\n\t\tmasterData.flatMap(item => {\n\t\t\tconst id = item.id ?? item.elementId;\n\t\t\treturn typeof id === \"string\" || typeof id === \"number\" ? [[String(id), item] as const] : [];\n\t\t}),\n\t);\n\treturn value.map(item => {\n\t\tif (typeof item !== \"object\" || item === null) {\n\t\t\treturn item;\n\t\t}\n\t\tconst id = (item as Record<string, unknown>).id;\n\t\treturn byId.get(String(id)) || item;\n\t});\n}\n\nexport function resolveTimetableReferences(\n\tperiods: WebUntisPeriod[],\n\tmasterData: TimetableMasterData,\n): WebUntisPeriod[] {\n\treturn periods.map(period => ({\n\t\t...period,\n\t\tkl: resolveReferences(period.kl, masterData.klassen),\n\t\tte: resolveReferences(period.te, masterData.teachers),\n\t\tsu: resolveReferences(period.su, masterData.subjects),\n\t\tro: resolveReferences(period.ro, masterData.rooms),\n\t\torigTe: resolveReferences(period.origTe, masterData.teachers),\n\t\torigRo: resolveReferences(period.origRo, masterData.rooms),\n\t\torigSu: resolveReferences(period.origSu, masterData.subjects),\n\t}));\n}\n\n/**\n *\n */\nexport function normalizeLessons(periods: WebUntisPeriod[]): TimetableLesson[] {\n\treturn periods\n\t\t.map(normalizeLesson)\n\t\t.sort((a, b) => `${a.date}${a.startTime}${a.id}`.localeCompare(`${b.date}${b.startTime}${b.id}`));\n}\n\nfunction durationMinutes(startTime: string, endTime: string): number {\n\tconst start = /^([0-9]{2}):([0-9]{2})$/.exec(startTime);\n\tconst end = /^([0-9]{2}):([0-9]{2})$/.exec(endTime);\n\tif (!start || !end) {\n\t\treturn 0;\n\t}\n\tconst startMinutes = Number(start[1]) * 60 + Number(start[2]);\n\tconst endMinutes = Number(end[1]) * 60 + Number(end[2]);\n\treturn Math.max(0, endMinutes - startMinutes);\n}\n\nexport function summarizeTimetable(lessons: TimetableLesson[]): TimetableSummary {\n\tconst subjects = lessons\n\t\t.map(lesson => lesson.subjectLong || lesson.subject)\n\t\t.filter((subject, index, values) => subject !== \"\" && values.indexOf(subject) === index);\n\treturn {\n\t\thasSchool: lessons.length > 0,\n\t\tlessonCount: lessons.length,\n\t\t// Cancelled lessons count as periods but have no actual teaching duration.\n\t\tlessonDurationMinutes: lessons.reduce(\n\t\t\t(total, lesson) => total + (lesson.cancelled ? 0 : durationMinutes(lesson.startTime, lesson.endTime)),\n\t\t\t0,\n\t\t),\n\t\tschoolStart: lessons[0]?.startTime || \"\",\n\t\tschoolEnd: lessons.at(-1)?.endTime || \"\",\n\t\tsubjects: subjects.join(\", \"),\n\t\tsubjectCount: subjects.length,\n\t\tfirstSubject: lessons[0]?.subjectLong || lessons[0]?.subject || \"\",\n\t\tlastSubject: lessons.at(-1)?.subjectLong || lessons.at(-1)?.subject || \"\",\n\t\thasChanges: lessons.some(lesson => lesson.changed || Boolean(lesson.substitution)),\n\t\tchangeCount: lessons.filter(lesson => lesson.changed || Boolean(lesson.substitution)).length,\n\t\tcancellationCount: lessons.filter(lesson => lesson.cancelled).length,\n\t};\n}\n\n/**\n *\n */\nexport function dateNumber(date: Date): number {\n\treturn Number(\n\t\t`${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, \"0\")}${String(date.getDate()).padStart(2, \"0\")}`,\n\t);\n}\n\n/**\n * Returns the next date for a weekday, including today.\n */\nexport function nextWeekday(date: Date, targetWeekday: number): Date {\n\tconst result = new Date(date);\n\tresult.setHours(12, 0, 0, 0);\n\tconst currentWeekday = (result.getDay() + 6) % 7;\n\tresult.setDate(result.getDate() + ((targetWeekday - currentWeekday + 7) % 7));\n\treturn result;\n}\n\n/**\n *\n */\nexport function dayRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\treturn { startDate: dateNumber(date), endDate: dateNumber(date) };\n}\n\n/**\n *\n */\nexport function weekRange(date: Date): {\n\t/**\n\t *\n\t */\n\tstartDate: number;\n\t/**\n\t *\n\t */\n\tendDate: number;\n} {\n\tconst start = new Date(date);\n\tstart.setHours(12, 0, 0, 0);\n\tconst end = new Date(start);\n\tend.setDate(end.getDate() + 6);\n\treturn { startDate: dateNumber(start), endDate: dateNumber(end) };\n}\n\n/**\n *\n */\nexport function splitTimetable(\n\tlessons: TimetableLesson[],\n\ttoday: Date,\n): {\n\t/**\n\t *\n\t */\n\ttoday: TimetableLesson[];\n\t/**\n\t *\n\t */\n\ttomorrow: TimetableLesson[];\n\t/**\n\t *\n\t */\n\tweek: TimetableLesson[];\n} {\n\tconst todayKey = dateNumber(today).toString();\n\tconst tomorrow = new Date(today);\n\ttomorrow.setDate(today.getDate() + 1);\n\tconst tomorrowKey = dateNumber(tomorrow).toString();\n\tconst dateKey = (value: string): string => value.replaceAll(\"-\", \"\");\n\treturn {\n\t\ttoday: lessons.filter(lesson => dateKey(lesson.date) === todayKey),\n\t\ttomorrow: lessons.filter(lesson => dateKey(lesson.date) === tomorrowKey),\n\t\tweek: lessons,\n\t};\n}\n\n/**\n *\n */\nexport function assertTimetableResponse(value: unknown): asserts value is WebUntisPeriod[] {\n\tif (!Array.isArray(value) || !value.every(period => typeof period === \"object\" && period !== null)) {\n\t\tthrow new WebUntisError(\"INVALID_RESPONSE\", \"Invalid WebUntis timetable result\");\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/build/main.js CHANGED
@@ -46,6 +46,7 @@ const SUMMARY_STATE_DEFINITIONS = {
46
46
  };
47
47
  const LESSON_STATE_NAMES = {
48
48
  date: "Date",
49
+ dateTimestamp: "Date (Unix timestamp ms)",
49
50
  startTime: "Lesson start",
50
51
  endTime: "Lesson end",
51
52
  subject: "Subject",
@@ -89,6 +90,13 @@ const CURRENT_NEXT_STATE_DEFINITIONS = {
89
90
  unit: "min"
90
91
  }
91
92
  };
93
+ function dateOnly(value) {
94
+ return value.trim().split(/[T ]/, 1)[0] || "";
95
+ }
96
+ function numericDate(value) {
97
+ const [year, month, day] = dateOnly(value).split("-").map(Number);
98
+ return year && month && day ? new Date(year, month - 1, day).getTime() : 0;
99
+ }
92
100
  class WebuntisNext extends utils.Adapter {
93
101
  webUntis;
94
102
  timetableTimer;
@@ -149,7 +157,7 @@ class WebuntisNext extends utils.Adapter {
149
157
  await this.setState("info.lastSuccessfulUpdate", now.toISOString(), true);
150
158
  await this.setState("info.nextUpdate", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);
151
159
  await this.setState("info.connection", true, true);
152
- this.log.warn(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);
160
+ this.log.debug(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);
153
161
  } catch (error) {
154
162
  await this.setState("info.connection", false, true);
155
163
  await this.setState("info.nextUpdate", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);
@@ -202,31 +210,62 @@ class WebuntisNext extends utils.Adapter {
202
210
  );
203
211
  await this.writeSimpleState(
204
212
  "holidays.current.startDate",
205
- summary.current.startDate,
213
+ dateOnly(summary.current.startDate),
206
214
  "Start date",
207
215
  "string",
208
- "date",
216
+ "text",
209
217
  ""
210
218
  );
219
+ await this.writeSimpleState(
220
+ "holidays.current.startDateTimestamp",
221
+ numericDate(summary.current.startDate),
222
+ "Start date (Unix timestamp ms)",
223
+ "number",
224
+ "value",
225
+ 0
226
+ );
211
227
  await this.writeSimpleState(
212
228
  "holidays.current.endDate",
213
- summary.current.endDate,
229
+ dateOnly(summary.current.endDate),
214
230
  "End date",
215
231
  "string",
216
- "date",
232
+ "text",
217
233
  ""
218
234
  );
235
+ await this.writeSimpleState(
236
+ "holidays.current.endDateTimestamp",
237
+ numericDate(summary.current.endDate),
238
+ "End date (Unix timestamp ms)",
239
+ "number",
240
+ "value",
241
+ 0
242
+ );
219
243
  await this.writeSimpleState("holidays.next.name", summary.next.name, "Name", "string", "text", "");
220
244
  await this.writeSimpleState("holidays.next.longName", summary.next.longName, "Long name", "string", "text", "");
221
245
  await this.writeSimpleState(
222
246
  "holidays.next.startDate",
223
- summary.next.startDate,
247
+ dateOnly(summary.next.startDate),
224
248
  "Start date",
225
249
  "string",
226
- "date",
250
+ "text",
251
+ ""
252
+ );
253
+ await this.writeSimpleState(
254
+ "holidays.next.startDateTimestamp",
255
+ numericDate(summary.next.startDate),
256
+ "Start date (Unix timestamp ms)",
257
+ "number",
258
+ "value",
259
+ 0
260
+ );
261
+ await this.writeSimpleState(
262
+ "holidays.next.endDate",
263
+ dateOnly(summary.next.endDate),
264
+ "End date",
265
+ "string",
266
+ "text",
227
267
  ""
228
268
  );
229
- await this.writeSimpleState("holidays.next.endDate", summary.next.endDate, "End date", "string", "date", "");
230
269
  await this.writeSimpleState(
231
270
  "holidays.next.daysUntil",
232
271
  summary.next.daysUntil,
@@ -235,6 +274,14 @@ class WebuntisNext extends utils.Adapter {
235
274
  "value",
236
275
  0
237
276
  );
277
+ await this.writeSimpleState(
278
+ "holidays.next.endDateTimestamp",
279
+ numericDate(summary.next.endDate),
280
+ "End date (Unix timestamp ms)",
281
+ "number",
282
+ "value",
283
+ 0
284
+ );
238
285
  }
239
286
  async writeDaySummary(path, summary) {
240
287
  for (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS)) {
@@ -312,18 +359,17 @@ class WebuntisNext extends utils.Adapter {
312
359
  let removed = await this.removeLegacyLessons(group);
313
360
  if (group === "week") {
314
361
  const weekdayNames = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
315
- const byDay = weekdayNames.map(
316
- (_, index) => lessons.filter((lesson) => {
317
- const date = /* @__PURE__ */ new Date(`${lesson.date}T12:00:00`);
318
- return (date.getDay() + 6) % 7 === index;
319
- })
320
- );
362
+ const byDay = weekdayNames.map((_, index) => {
363
+ const targetDate = this.timetableDate((0, import_Timetable.nextWeekday)(now, index));
364
+ return lessons.filter((lesson) => lesson.date === targetDate);
365
+ });
321
366
  for (let index = 0; index < weekdayNames.length; index++) {
322
367
  const result = await this.writeTimetableDay(
323
368
  `timetable.week.${weekdayNames[index]}`,
324
369
  byDay[index],
325
- this.timetableDate(this.getMonday(now, index))
370
+ this.timetableDate((0, import_Timetable.nextWeekday)(now, index))
326
371
  );
372
+ await this.writeDaySummary(`week.${weekdayNames[index]}`, (0, import_Timetable.summarizeTimetable)(byDay[index]));
327
373
  removed += result.removed;
328
374
  }
329
375
  } else {
@@ -363,7 +409,15 @@ class WebuntisNext extends utils.Adapter {
363
409
  common: { name: path.split(".").at(-1) || "Day" },
364
410
  native: {}
365
411
  });
366
- await this.writeSimpleState(`${path}.date`, date, "Date", "string", "date", "");
412
+ await this.writeSimpleState(`${path}.date`, dateOnly(date), "Date", "string", "text", "");
413
+ await this.writeSimpleState(
414
+ `${path}.dateTimestamp`,
415
+ numericDate(date),
416
+ "Date (Unix timestamp ms)",
417
+ "number",
418
+ "value",
419
+ 0
420
+ );
367
421
  await this.writeSimpleState(`${path}.lessonCount`, lessons.length, "Lesson count", "number", "value", 0);
368
422
  await this.setObjectNotExistsAsync(`${path}.lessons`, {
369
423
  type: "channel",
@@ -390,12 +444,6 @@ class WebuntisNext extends utils.Adapter {
390
444
  }
391
445
  return { removed: stale.size };
392
446
  }
393
- getMonday(date, dayOffset) {
394
- const monday = new Date(date);
395
- monday.setHours(12, 0, 0, 0);
396
- monday.setDate(monday.getDate() - (monday.getDay() + 6) % 7 + dayOffset);
397
- return monday;
398
- }
399
447
  timetableDate(date) {
400
448
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
401
449
  }
@@ -405,6 +453,7 @@ class WebuntisNext extends utils.Adapter {
405
453
  common: { name, type, role, read: true, write: false, def },
406
454
  native: {}
407
455
  });
456
+ await this.extendObjectAsync(id, { common: { name, type, role, read: true, write: false, def } });
408
457
  await this.setStateAsync(id, value, true);
409
458
  }
410
459
  async writeLesson(path, slot, lesson) {
@@ -417,7 +466,8 @@ class WebuntisNext extends utils.Adapter {
417
466
  });
418
467
  await this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });
419
468
  const values = {
420
- date: { value: lesson.date, type: "string", role: "date" },
469
+ date: { value: dateOnly(lesson.date), type: "string", role: "text" },
470
+ dateTimestamp: { value: numericDate(lesson.date), type: "number", role: "value" },
421
471
  startTime: { value: lesson.startTime, type: "string", role: "text" },
422
472
  endTime: { value: lesson.endTime, type: "string", role: "text" },
423
473
  subject: { value: lesson.subject, type: "string", role: "text" },
package/build/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { WebUntisService, type WebUntisConnectionConfig } from \"./lib/webuntis/WebUntisService\";\nimport { cleanupLegacyNamespace } from \"./lib/LegacyNamespaceCleanup\";\nimport type { HolidaySummary } from \"./lib/webuntis/Holidays\";\nimport { WebUntisError } from \"./lib/webuntis/WebUntisErrors\";\nimport {\n\tlessonChannelName,\n\tsummarizeTimetable,\n\ttype TimetableLesson,\n\ttype TimetableSummary,\n} from \"./lib/webuntis/Timetable\";\nimport type { WebUntisHttpDiagnostic } from \"./lib/webuntis/WebUntisTypes\";\nimport { deriveCurrentNextLesson, type CurrentNextLessonSummary } from \"./lib/webuntis/CurrentNextLesson\";\n\nconst TIMETABLE_INTERVAL_MS = 5 * 60 * 1000;\nconst CURRENT_NEXT_INTERVAL_MS = 60 * 1000;\nconst TIMETABLE_GROUPS = [\"today\", \"tomorrow\", \"week\"] as const;\ntype TimetableGroup = (typeof TIMETABLE_GROUPS)[number];\n\nconst SUMMARY_STATE_DEFINITIONS: Record<\n\tkeyof TimetableSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean }\n> = {\n\thasSchool: { type: \"boolean\", role: \"indicator\", name: \"Has school\", def: false },\n\tlessonCount: { type: \"number\", role: \"value\", name: \"Lesson count\", def: 0 },\n\tlessonDurationMinutes: { type: \"number\", role: \"value\", name: \"Lesson duration in minutes\", def: 0 },\n\tschoolStart: { type: \"string\", role: \"text\", name: \"School start\", def: \"\" },\n\tschoolEnd: { type: \"string\", role: \"text\", name: \"School end\", def: \"\" },\n\tsubjects: { type: \"string\", role: \"text\", name: \"Subjects\", def: \"\" },\n\tsubjectCount: { type: \"number\", role: \"value\", name: \"Subject count\", def: 0 },\n\tfirstSubject: { type: \"string\", role: \"text\", name: \"First subject\", def: \"\" },\n\tlastSubject: { type: \"string\", role: \"text\", name: \"Last subject\", def: \"\" },\n\thasChanges: { type: \"boolean\", role: \"indicator\", name: \"Has changes\", def: false },\n\tchangeCount: { type: \"number\", role: \"value\", name: \"Change count\", def: 0 },\n\tcancellationCount: { type: \"number\", role: \"value\", name: \"Cancellation count\", def: 0 },\n};\n\nconst LESSON_STATE_NAMES: Record<string, string> = {\n\tdate: \"Date\",\n\tstartTime: \"Lesson start\",\n\tendTime: \"Lesson end\",\n\tsubject: \"Subject\",\n\tsubjectLong: \"Subject name\",\n\tteacher: \"Teacher\",\n\troom: \"Room\",\n\tclass: \"Class\",\n\tlessonId: \"WebUntis lesson ID\",\n\tperiodId: \"WebUntis period ID\",\n\tstatus: \"Lesson status\",\n\tchanged: \"Lesson changed\",\n\tcancelled: \"Lesson cancelled\",\n\tsubstitution: \"Substitution\",\n\toriginalTeacher: \"Original teacher\",\n\toriginalRoom: \"Original room\",\n\toriginalSubject: \"Original subject\",\n};\n\nconst CURRENT_NEXT_STATE_DEFINITIONS: Record<\n\tkeyof CurrentNextLessonSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean; unit?: string }\n> = {\n\tcurrentLesson: { type: \"string\", role: \"text\", name: \"Current lesson\", def: \"\" },\n\tcurrentSubject: { type: \"string\", role: \"text\", name: \"Current subject\", def: \"\" },\n\tcurrentRoom: { type: \"string\", role: \"text\", name: \"Current room\", def: \"\" },\n\tcurrentTeacher: { type: \"string\", role: \"text\", name: \"Current teacher\", def: \"\" },\n\tnextLesson: { type: \"string\", role: \"text\", name: \"Next lesson\", def: \"\" },\n\tnextSubject: { type: \"string\", role: \"text\", name: \"Next subject\", def: \"\" },\n\tnextRoom: { type: \"string\", role: \"text\", name: \"Next room\", def: \"\" },\n\tnextTeacher: { type: \"string\", role: \"text\", name: \"Next teacher\", def: \"\" },\n\tnextLessonStart: { type: \"string\", role: \"text\", name: \"Next lesson start\", def: \"\" },\n\tminutesUntilNextLesson: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until next lesson\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n\tschoolRunning: { type: \"boolean\", role: \"indicator\", name: \"School running\", def: false },\n\tminutesUntilSchoolEnd: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until school end\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n};\n\nclass WebuntisNext extends utils.Adapter {\n\tprivate readonly webUntis: WebUntisService;\n\tprivate timetableTimer?: ioBroker.Interval;\n\tprivate currentNextTimer?: ioBroker.Interval;\n\tprivate todayLessons: TimetableLesson[] = [];\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({ ...options, name: \"webuntis2\" });\n\t\tthis.webUntis = new WebUntisService(\n\t\t\tthis.logHttpDiagnostic.bind(this),\n\t\t\tmessage => this.log.info(message),\n\t\t\tmessage => this.log.warn(message),\n\t\t\tfetch,\n\t\t\tmessage => this.log.debug(message),\n\t\t);\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate logHttpDiagnostic(diagnostic: WebUntisHttpDiagnostic): void {\n\t\tthis.log.debug(`WebUntis ${diagnostic.method || \"request\"} HTTP ${JSON.stringify(diagnostic)}`);\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tawait this.setState(\"info.connection\", false, true);\n\t\tif (!this.hasConnectionConfig()) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.updateTimetable();\n\t\tthis.timetableTimer = this.setInterval(() => void this.updateTimetable(), TIMETABLE_INTERVAL_MS);\n\t\tthis.currentNextTimer = this.setInterval(() => void this.updateCurrentNextStates(), CURRENT_NEXT_INTERVAL_MS);\n\t}\n\n\tprivate hasConnectionConfig(): this is { config: WebUntisConnectionConfig } {\n\t\treturn Boolean(\n\t\t\tthis.config.server &&\n\t\t\tthis.config.schoolName &&\n\t\t\ttypeof this.config.schoolId === \"number\" &&\n\t\t\tthis.config.username &&\n\t\t\tthis.config.password,\n\t\t);\n\t}\n\n\tprivate async updateTimetable(): Promise<void> {\n\t\tawait this.setState(\"info.lastUpdate\", new Date().toISOString(), true);\n\t\ttry {\n\t\t\tawait cleanupLegacyNamespace(this, \"messages\");\n\t\t\tawait this.ensureTimetableRoot();\n\t\t\tawait this.ensureHolidaysRoot();\n\t\t\tawait this.cleanupObsoleteStructure();\n\t\t\tconst now = new Date();\n\t\t\tconst data = await this.webUntis.loadTimetable(this.config, now);\n\t\t\tthis.todayLessons = data.today;\n\t\t\tlet updated = 0;\n\t\t\tlet removed = 0;\n\t\t\tfor (const group of TIMETABLE_GROUPS) {\n\t\t\t\tconst result = await this.writeTimetableGroup(group, data[group], now);\n\t\t\t\tupdated += result.updated;\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t\tif (data.holidays) {\n\t\t\t\tawait this.writeHolidaySummary(data.holidays);\n\t\t\t} else {\n\t\t\t\tthis.log.warn(\"WebUntis holidays are not available; previous holiday values were preserved\");\n\t\t\t}\n\t\t\tawait this.setState(\"info.lastSuccessfulUpdate\", now.toISOString(), true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tawait this.setState(\"info.connection\", true, true);\n\t\t\tthis.log.warn(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);\n\t\t} catch (error) {\n\t\t\tawait this.setState(\"info.connection\", false, true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tconst detail = error instanceof Error ? ` (${error.message})` : \"\";\n\t\t\tthis.log.warn(`Timetable update failed: ${code}${detail}; existing timetable data was kept`);\n\t\t}\n\t}\n\n\tprivate async ensureTimetableRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"timetable\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Timetable\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async ensureHolidaysRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"holidays\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Holidays\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.current\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Current holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.next\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Next holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async writeHolidaySummary(summary: HolidaySummary): Promise<void> {\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.active\",\n\t\t\tsummary.current.active,\n\t\t\t\"Active\",\n\t\t\t\"boolean\",\n\t\t\t\"indicator\",\n\t\t\tfalse,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.current.name\", summary.current.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.longName\",\n\t\t\tsummary.current.longName,\n\t\t\t\"Long name\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDate\",\n\t\t\tsummary.current.startDate,\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDate\",\n\t\t\tsummary.current.endDate,\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.name\", summary.next.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\"holidays.next.longName\", summary.next.longName, \"Long name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDate\",\n\t\t\tsummary.next.startDate,\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"date\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.endDate\", summary.next.endDate, \"End date\", \"string\", \"date\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.daysUntil\",\n\t\t\tsummary.next.daysUntil,\n\t\t\t\"Days until\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate async writeDaySummary(path: string, summary: TimetableSummary): Promise<void> {\n\t\tfor (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS) as [\n\t\t\tkeyof TimetableSummary,\n\t\t\t(typeof SUMMARY_STATE_DEFINITIONS)[keyof TimetableSummary],\n\t\t][]) {\n\t\t\tif (name === \"lessonCount\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.${path}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.${path}.${name}`, {\n\t\t\t\tcommon: { type: definition.type, role: definition.role, def: definition.def },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.${path}.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async writeCurrentNextSummary(lessons: TimetableLesson[], now: Date): Promise<void> {\n\t\tconst summary = deriveCurrentNextLesson(lessons, now);\n\t\tfor (const [name, definition] of Object.entries(CURRENT_NEXT_STATE_DEFINITIONS) as [\n\t\t\tkeyof CurrentNextLessonSummary,\n\t\t\t(typeof CURRENT_NEXT_STATE_DEFINITIONS)[keyof CurrentNextLessonSummary],\n\t\t][]) {\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.today.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.today.${name}`, {\n\t\t\t\tcommon: {\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.today.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async updateCurrentNextStates(): Promise<void> {\n\t\tawait this.writeCurrentNextSummary(this.todayLessons, new Date());\n\t}\n\n\tprivate async cleanupObsoleteStructure(): Promise<void> {\n\t\tfor (const id of [\n\t\t\t\"info.timetable\",\n\t\t\t\"timetable.timetable\",\n\t\t\t\"timetable.today.count\",\n\t\t\t\"timetable.tomorrow.count\",\n\t\t\t\"timetable.today.subjectsJson\",\n\t\t\t\"timetable.tomorrow.subjectsJson\",\n\t\t]) {\n\t\t\tif (await this.getObjectAsync(id)) {\n\t\t\t\tawait this.delObjectAsync(id, { recursive: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async writeTimetableGroup(\n\t\tgroup: TimetableGroup,\n\t\tlessons: TimetableLesson[],\n\t\tnow: Date,\n\t): Promise<{ updated: number; removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(`timetable.${group}`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: `Timetable ${group}` },\n\t\t\tnative: {},\n\t\t});\n\t\tlet removed = await this.removeLegacyLessons(group);\n\t\tif (group === \"week\") {\n\t\t\tconst weekdayNames = [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\"];\n\t\t\tconst byDay = weekdayNames.map((_, index) =>\n\t\t\t\tlessons.filter(lesson => {\n\t\t\t\t\tconst date = new Date(`${lesson.date}T12:00:00`);\n\t\t\t\t\treturn (date.getDay() + 6) % 7 === index;\n\t\t\t\t}),\n\t\t\t);\n\t\t\tfor (let index = 0; index < weekdayNames.length; index++) {\n\t\t\t\tconst result = await this.writeTimetableDay(\n\t\t\t\t\t`timetable.week.${weekdayNames[index]}`,\n\t\t\t\t\tbyDay[index],\n\t\t\t\t\tthis.timetableDate(this.getMonday(now, index)),\n\t\t\t\t);\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t} else {\n\t\t\tconst day = new Date(now);\n\t\t\tif (group === \"tomorrow\") {\n\t\t\t\tday.setDate(day.getDate() + 1);\n\t\t\t}\n\t\t\tconst result = await this.writeTimetableDay(`timetable.${group}`, lessons, this.timetableDate(day));\n\t\t\tawait this.writeDaySummary(group, summarizeTimetable(lessons));\n\t\t\tif (group === \"today\") {\n\t\t\t\tawait this.writeCurrentNextSummary(lessons, now);\n\t\t\t}\n\t\t\tremoved += result.removed;\n\t\t}\n\t\treturn { updated: lessons.length, removed };\n\t}\n\n\tprivate async removeLegacyLessons(group: TimetableGroup): Promise<number> {\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.timetable.${group}.`,\n\t\t\tendkey: `${this.namespace}.timetable.${group}.\\uffff`,\n\t\t});\n\t\tconst legacy = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst first = object.id.replace(`${this.namespace}.timetable.${group}.`, \"\").split(\".\")[0];\n\t\t\tif (first.startsWith(\"period-\")) {\n\t\t\t\tlegacy.add(first);\n\t\t\t}\n\t\t}\n\t\tfor (const id of legacy) {\n\t\t\tawait this.delObjectAsync(`timetable.${group}.${id}`, { recursive: true });\n\t\t}\n\t\treturn legacy.size;\n\t}\n\n\tprivate async writeTimetableDay(\n\t\tpath: string,\n\t\tlessons: TimetableLesson[],\n\t\tdate: string,\n\t): Promise<{ removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(path, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: path.split(\".\").at(-1) || \"Day\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.writeSimpleState(`${path}.date`, date, \"Date\", \"string\", \"date\", \"\");\n\t\tawait this.writeSimpleState(`${path}.lessonCount`, lessons.length, \"Lesson count\", \"number\", \"value\", 0);\n\t\tawait this.setObjectNotExistsAsync(`${path}.lessons`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Lessons\" },\n\t\t\tnative: {},\n\t\t});\n\t\tconst expected = new Set(lessons.map((_lesson, index) => String(index + 1).padStart(2, \"0\")));\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.${path}.lessons.`,\n\t\t\tendkey: `${this.namespace}.${path}.lessons.\\uffff`,\n\t\t});\n\t\tconst stale = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst slot = object.id.replace(`${this.namespace}.${path}.lessons.`, \"\").split(\".\")[0];\n\t\t\tif (slot && !expected.has(slot)) {\n\t\t\t\tstale.add(slot);\n\t\t\t}\n\t\t}\n\t\tfor (const slot of stale) {\n\t\t\tawait this.delObjectAsync(`${path}.lessons.${slot}`, { recursive: true });\n\t\t}\n\t\tfor (const [index, lesson] of lessons.entries()) {\n\t\t\tawait this.writeLesson(path, String(index + 1).padStart(2, \"0\"), lesson);\n\t\t}\n\t\treturn { removed: stale.size };\n\t}\n\n\tprivate getMonday(date: Date, dayOffset: number): Date {\n\t\tconst monday = new Date(date);\n\t\tmonday.setHours(12, 0, 0, 0);\n\t\tmonday.setDate(monday.getDate() - ((monday.getDay() + 6) % 7) + dayOffset);\n\t\treturn monday;\n\t}\n\n\tprivate timetableDate(date: Date): string {\n\t\treturn `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n\t}\n\n\tprivate async writeSimpleState(\n\t\tid: string,\n\t\tvalue: string | number | boolean,\n\t\tname: string,\n\t\ttype: \"string\" | \"number\" | \"boolean\",\n\t\trole: string,\n\t\tdef: string | number | boolean,\n\t): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: { name, type, role, read: true, write: false, def },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setStateAsync(id, value, true);\n\t}\n\n\tprivate async writeLesson(path: string, slot: string, lesson: TimetableLesson): Promise<void> {\n\t\tconst base = `${path}.lessons.${slot}`;\n\t\tconst label = lessonChannelName(lesson);\n\t\tawait this.setObjectNotExistsAsync(base, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: label || `Lesson ${slot}` },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });\n\t\tconst values: Record<\n\t\t\tstring,\n\t\t\t{ value: string | number | boolean; type: \"string\" | \"number\" | \"boolean\"; role: string }\n\t\t> = {\n\t\t\tdate: { value: lesson.date, type: \"string\", role: \"date\" },\n\t\t\tstartTime: { value: lesson.startTime, type: \"string\", role: \"text\" },\n\t\t\tendTime: { value: lesson.endTime, type: \"string\", role: \"text\" },\n\t\t\tsubject: { value: lesson.subject, type: \"string\", role: \"text\" },\n\t\t\tsubjectLong: { value: lesson.subjectLong, type: \"string\", role: \"text\" },\n\t\t\tteacher: { value: lesson.teacher, type: \"string\", role: \"text\" },\n\t\t\troom: { value: lesson.room, type: \"string\", role: \"text\" },\n\t\t\tclass: { value: lesson.class, type: \"string\", role: \"text\" },\n\t\t\t...(lesson.lessonId === null\n\t\t\t\t? {}\n\t\t\t\t: { lessonId: { value: String(lesson.lessonId), type: \"string\" as const, role: \"text\" } }),\n\t\t\t...(lesson.periodId === null\n\t\t\t\t? {}\n\t\t\t\t: { periodId: { value: String(lesson.periodId), type: \"string\" as const, role: \"text\" } }),\n\t\t\tstatus: { value: lesson.status, type: \"string\", role: \"text\" },\n\t\t\tchanged: { value: lesson.changed, type: \"boolean\", role: \"indicator\" },\n\t\t\tcancelled: { value: lesson.cancelled, type: \"boolean\", role: \"indicator\" },\n\t\t\t...(lesson.substitution\n\t\t\t\t? { substitution: { value: lesson.substitution, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalTeacher && lesson.originalTeacher !== lesson.teacher\n\t\t\t\t? { originalTeacher: { value: lesson.originalTeacher, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalRoom && lesson.originalRoom !== lesson.room\n\t\t\t\t? { originalRoom: { value: lesson.originalRoom, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalSubject && lesson.originalSubject !== lesson.subject\n\t\t\t\t? { originalSubject: { value: lesson.originalSubject, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t};\n\t\tconst optional = [\"substitution\", \"originalTeacher\", \"originalRoom\", \"originalSubject\"];\n\t\tfor (const name of optional) {\n\t\t\tif (!(name in values) && (await this.getObjectAsync(`${base}.${name}`))) {\n\t\t\t\tawait this.delObjectAsync(`${base}.${name}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, item] of Object.entries(values)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${base}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: LESSON_STATE_NAMES[name] || name,\n\t\t\t\t\ttype: item.type,\n\t\t\t\t\trole: item.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: item.value,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`${base}.${name}`, {\n\t\t\t\tcommon: { name: LESSON_STATE_NAMES[name] || name, type: item.type, role: item.role, def: item.value },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`${base}.${name}`, item.value, true);\n\t\t}\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj || !obj.command || !obj.callback) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (obj.command === \"searchSchools\") {\n\t\t\t\tconst results = await this.webUntis.searchSchools(this.getStringPayload(obj.message, \"query\"));\n\t\t\t\tthis.log.info(`School search returned ${results.length} results`);\n\t\t\t\tthis.sendTo(obj.from, obj.command, { ok: true, results }, obj.callback);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (obj.command === \"testConnection\") {\n\t\t\t\tconst result = await this.webUntis.testConnection(this.getConnectionPayload(obj.message));\n\t\t\t\tawait this.setState(\"info.connection\", result.ok, true);\n\t\t\t\tif (result.ok) {\n\t\t\t\t\tthis.log.info(\"WebUntis authentication successful\");\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.warn(`WebUntis authentication failed: ${result.code}`);\n\t\t\t\t}\n\t\t\t\tthis.sendTo(obj.from, obj.command, result, obj.callback);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tthis.log.warn(`WebUntis request failed: ${code}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { ok: false, code }, obj.callback);\n\t\t}\n\t}\n\n\tprivate getStringPayload(message: ioBroker.MessagePayload, key: string): string {\n\t\tif (\n\t\t\ttypeof message !== \"object\" ||\n\t\t\tmessage === null ||\n\t\t\ttypeof (message as Record<string, unknown>)[key] !== \"string\"\n\t\t) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid message payload\");\n\t\t}\n\t\treturn (message as Record<string, unknown>)[key] as string;\n\t}\n\n\tprivate getConnectionPayload(message: ioBroker.MessagePayload): WebUntisConnectionConfig {\n\t\tif (typeof message !== \"object\" || message === null) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid connection payload\");\n\t\t}\n\t\tconst value = message as Record<string, unknown>;\n\t\tconst stringValue = (key: string): string => (typeof value[key] === \"string\" ? value[key] : \"\");\n\t\treturn {\n\t\t\tserver: stringValue(\"server\"),\n\t\t\tschoolName: stringValue(\"schoolName\"),\n\t\t\tschoolDisplayName: stringValue(\"schoolDisplayName\"),\n\t\t\tschoolAddress: stringValue(\"schoolAddress\"),\n\t\t\tschoolId: typeof value.schoolId === \"number\" ? value.schoolId : null,\n\t\t\tusername: stringValue(\"username\"),\n\t\t\tpassword: stringValue(\"password\"),\n\t\t};\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.timetableTimer) {\n\t\t\tthis.clearInterval(this.timetableTimer);\n\t\t}\n\t\tif (this.currentNextTimer) {\n\t\t\tthis.clearInterval(this.currentNextTimer);\n\t\t}\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new WebuntisNext(options);\n} else {\n\t(() => new WebuntisNext())();\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { WebUntisService, type WebUntisConnectionConfig } from \"./lib/webuntis/WebUntisService\";\nimport { cleanupLegacyNamespace } from \"./lib/LegacyNamespaceCleanup\";\nimport type { HolidaySummary } from \"./lib/webuntis/Holidays\";\nimport { WebUntisError } from \"./lib/webuntis/WebUntisErrors\";\nimport {\n\tlessonChannelName,\n\tsummarizeTimetable,\n\tnextWeekday,\n\ttype TimetableLesson,\n\ttype TimetableSummary,\n} from \"./lib/webuntis/Timetable\";\nimport type { WebUntisHttpDiagnostic } from \"./lib/webuntis/WebUntisTypes\";\nimport { deriveCurrentNextLesson, type CurrentNextLessonSummary } from \"./lib/webuntis/CurrentNextLesson\";\n\nconst TIMETABLE_INTERVAL_MS = 5 * 60 * 1000;\nconst CURRENT_NEXT_INTERVAL_MS = 60 * 1000;\nconst TIMETABLE_GROUPS = [\"today\", \"tomorrow\", \"week\"] as const;\ntype TimetableGroup = (typeof TIMETABLE_GROUPS)[number];\n\nconst SUMMARY_STATE_DEFINITIONS: Record<\n\tkeyof TimetableSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean }\n> = {\n\thasSchool: { type: \"boolean\", role: \"indicator\", name: \"Has school\", def: false },\n\tlessonCount: { type: \"number\", role: \"value\", name: \"Lesson count\", def: 0 },\n\tlessonDurationMinutes: { type: \"number\", role: \"value\", name: \"Lesson duration in minutes\", def: 0 },\n\tschoolStart: { type: \"string\", role: \"text\", name: \"School start\", def: \"\" },\n\tschoolEnd: { type: \"string\", role: \"text\", name: \"School end\", def: \"\" },\n\tsubjects: { type: \"string\", role: \"text\", name: \"Subjects\", def: \"\" },\n\tsubjectCount: { type: \"number\", role: \"value\", name: \"Subject count\", def: 0 },\n\tfirstSubject: { type: \"string\", role: \"text\", name: \"First subject\", def: \"\" },\n\tlastSubject: { type: \"string\", role: \"text\", name: \"Last subject\", def: \"\" },\n\thasChanges: { type: \"boolean\", role: \"indicator\", name: \"Has changes\", def: false },\n\tchangeCount: { type: \"number\", role: \"value\", name: \"Change count\", def: 0 },\n\tcancellationCount: { type: \"number\", role: \"value\", name: \"Cancellation count\", def: 0 },\n};\n\nconst LESSON_STATE_NAMES: Record<string, string> = {\n\tdate: \"Date\",\n\tdateTimestamp: \"Date (Unix timestamp ms)\",\n\tstartTime: \"Lesson start\",\n\tendTime: \"Lesson end\",\n\tsubject: \"Subject\",\n\tsubjectLong: \"Subject name\",\n\tteacher: \"Teacher\",\n\troom: \"Room\",\n\tclass: \"Class\",\n\tlessonId: \"WebUntis lesson ID\",\n\tperiodId: \"WebUntis period ID\",\n\tstatus: \"Lesson status\",\n\tchanged: \"Lesson changed\",\n\tcancelled: \"Lesson cancelled\",\n\tsubstitution: \"Substitution\",\n\toriginalTeacher: \"Original teacher\",\n\toriginalRoom: \"Original room\",\n\toriginalSubject: \"Original subject\",\n};\n\nconst CURRENT_NEXT_STATE_DEFINITIONS: Record<\n\tkeyof CurrentNextLessonSummary,\n\t{ type: \"string\" | \"number\" | \"boolean\"; role: string; name: string; def: string | number | boolean; unit?: string }\n> = {\n\tcurrentLesson: { type: \"string\", role: \"text\", name: \"Current lesson\", def: \"\" },\n\tcurrentSubject: { type: \"string\", role: \"text\", name: \"Current subject\", def: \"\" },\n\tcurrentRoom: { type: \"string\", role: \"text\", name: \"Current room\", def: \"\" },\n\tcurrentTeacher: { type: \"string\", role: \"text\", name: \"Current teacher\", def: \"\" },\n\tnextLesson: { type: \"string\", role: \"text\", name: \"Next lesson\", def: \"\" },\n\tnextSubject: { type: \"string\", role: \"text\", name: \"Next subject\", def: \"\" },\n\tnextRoom: { type: \"string\", role: \"text\", name: \"Next room\", def: \"\" },\n\tnextTeacher: { type: \"string\", role: \"text\", name: \"Next teacher\", def: \"\" },\n\tnextLessonStart: { type: \"string\", role: \"text\", name: \"Next lesson start\", def: \"\" },\n\tminutesUntilNextLesson: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until next lesson\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n\tschoolRunning: { type: \"boolean\", role: \"indicator\", name: \"School running\", def: false },\n\tminutesUntilSchoolEnd: {\n\t\ttype: \"number\",\n\t\trole: \"value.interval\",\n\t\tname: \"Minutes until school end\",\n\t\tdef: 0,\n\t\tunit: \"min\",\n\t},\n};\n\nfunction dateOnly(value: string): string {\n\treturn value.trim().split(/[T ]/, 1)[0] || \"\";\n}\n\nfunction numericDate(value: string): number {\n\tconst [year, month, day] = dateOnly(value).split(\"-\").map(Number);\n\treturn year && month && day ? new Date(year, month - 1, day).getTime() : 0;\n}\n\nclass WebuntisNext extends utils.Adapter {\n\tprivate readonly webUntis: WebUntisService;\n\tprivate timetableTimer?: ioBroker.Interval;\n\tprivate currentNextTimer?: ioBroker.Interval;\n\tprivate todayLessons: TimetableLesson[] = [];\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({ ...options, name: \"webuntis2\" });\n\t\tthis.webUntis = new WebUntisService(\n\t\t\tthis.logHttpDiagnostic.bind(this),\n\t\t\tmessage => this.log.info(message),\n\t\t\tmessage => this.log.warn(message),\n\t\t\tfetch,\n\t\t\tmessage => this.log.debug(message),\n\t\t);\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate logHttpDiagnostic(diagnostic: WebUntisHttpDiagnostic): void {\n\t\tthis.log.debug(`WebUntis ${diagnostic.method || \"request\"} HTTP ${JSON.stringify(diagnostic)}`);\n\t}\n\n\tprivate async onReady(): Promise<void> {\n\t\tawait this.setState(\"info.connection\", false, true);\n\t\tif (!this.hasConnectionConfig()) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.updateTimetable();\n\t\tthis.timetableTimer = this.setInterval(() => void this.updateTimetable(), TIMETABLE_INTERVAL_MS);\n\t\tthis.currentNextTimer = this.setInterval(() => void this.updateCurrentNextStates(), CURRENT_NEXT_INTERVAL_MS);\n\t}\n\n\tprivate hasConnectionConfig(): this is { config: WebUntisConnectionConfig } {\n\t\treturn Boolean(\n\t\t\tthis.config.server &&\n\t\t\tthis.config.schoolName &&\n\t\t\ttypeof this.config.schoolId === \"number\" &&\n\t\t\tthis.config.username &&\n\t\t\tthis.config.password,\n\t\t);\n\t}\n\n\tprivate async updateTimetable(): Promise<void> {\n\t\tawait this.setState(\"info.lastUpdate\", new Date().toISOString(), true);\n\t\ttry {\n\t\t\tawait cleanupLegacyNamespace(this, \"messages\");\n\t\t\tawait this.ensureTimetableRoot();\n\t\t\tawait this.ensureHolidaysRoot();\n\t\t\tawait this.cleanupObsoleteStructure();\n\t\t\tconst now = new Date();\n\t\t\tconst data = await this.webUntis.loadTimetable(this.config, now);\n\t\t\tthis.todayLessons = data.today;\n\t\t\tlet updated = 0;\n\t\t\tlet removed = 0;\n\t\t\tfor (const group of TIMETABLE_GROUPS) {\n\t\t\t\tconst result = await this.writeTimetableGroup(group, data[group], now);\n\t\t\t\tupdated += result.updated;\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t\tif (data.holidays) {\n\t\t\t\tawait this.writeHolidaySummary(data.holidays);\n\t\t\t} else {\n\t\t\t\tthis.log.warn(\"WebUntis holidays are not available; previous holiday values were preserved\");\n\t\t\t}\n\t\t\tawait this.setState(\"info.lastSuccessfulUpdate\", now.toISOString(), true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(now.getTime() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tawait this.setState(\"info.connection\", true, true);\n\t\t\tthis.log.debug(`Timetable updated: ${updated} lessons updated, ${removed} obsolete lessons removed`);\n\t\t} catch (error) {\n\t\t\tawait this.setState(\"info.connection\", false, true);\n\t\t\tawait this.setState(\"info.nextUpdate\", new Date(Date.now() + TIMETABLE_INTERVAL_MS).toISOString(), true);\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tconst detail = error instanceof Error ? ` (${error.message})` : \"\";\n\t\t\tthis.log.warn(`Timetable update failed: ${code}${detail}; existing timetable data was kept`);\n\t\t}\n\t}\n\n\tprivate async ensureTimetableRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"timetable\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Timetable\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async ensureHolidaysRoot(): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(\"holidays\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Holidays\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.current\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Current holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.setObjectNotExistsAsync(\"holidays.next\", {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Next holiday\" },\n\t\t\tnative: {},\n\t\t});\n\t}\n\n\tprivate async writeHolidaySummary(summary: HolidaySummary): Promise<void> {\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.active\",\n\t\t\tsummary.current.active,\n\t\t\t\"Active\",\n\t\t\t\"boolean\",\n\t\t\t\"indicator\",\n\t\t\tfalse,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.current.name\", summary.current.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.longName\",\n\t\t\tsummary.current.longName,\n\t\t\t\"Long name\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDate\",\n\t\t\tdateOnly(summary.current.startDate),\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.startDateTimestamp\",\n\t\t\tnumericDate(summary.current.startDate),\n\t\t\t\"Start date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDate\",\n\t\t\tdateOnly(summary.current.endDate),\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.current.endDateTimestamp\",\n\t\t\tnumericDate(summary.current.endDate),\n\t\t\t\"End date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\"holidays.next.name\", summary.next.name, \"Name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\"holidays.next.longName\", summary.next.longName, \"Long name\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDate\",\n\t\t\tdateOnly(summary.next.startDate),\n\t\t\t\"Start date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.startDateTimestamp\",\n\t\t\tnumericDate(summary.next.startDate),\n\t\t\t\"Start date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.endDate\",\n\t\t\tdateOnly(summary.next.endDate),\n\t\t\t\"End date\",\n\t\t\t\"string\",\n\t\t\t\"text\",\n\t\t\t\"\",\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.daysUntil\",\n\t\t\tsummary.next.daysUntil,\n\t\t\t\"Days until\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(\n\t\t\t\"holidays.next.endDateTimestamp\",\n\t\t\tnumericDate(summary.next.endDate),\n\t\t\t\"End date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t}\n\n\tprivate async writeDaySummary(path: string, summary: TimetableSummary): Promise<void> {\n\t\tfor (const [name, definition] of Object.entries(SUMMARY_STATE_DEFINITIONS) as [\n\t\t\tkeyof TimetableSummary,\n\t\t\t(typeof SUMMARY_STATE_DEFINITIONS)[keyof TimetableSummary],\n\t\t][]) {\n\t\t\tif (name === \"lessonCount\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.${path}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.${path}.${name}`, {\n\t\t\t\tcommon: { type: definition.type, role: definition.role, def: definition.def },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.${path}.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async writeCurrentNextSummary(lessons: TimetableLesson[], now: Date): Promise<void> {\n\t\tconst summary = deriveCurrentNextLesson(lessons, now);\n\t\tfor (const [name, definition] of Object.entries(CURRENT_NEXT_STATE_DEFINITIONS) as [\n\t\t\tkeyof CurrentNextLessonSummary,\n\t\t\t(typeof CURRENT_NEXT_STATE_DEFINITIONS)[keyof CurrentNextLessonSummary],\n\t\t][]) {\n\t\t\tawait this.setObjectNotExistsAsync(`timetable.today.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: definition.name,\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`timetable.today.${name}`, {\n\t\t\t\tcommon: {\n\t\t\t\t\ttype: definition.type,\n\t\t\t\t\trole: definition.role,\n\t\t\t\t\tdef: definition.def,\n\t\t\t\t\t...(definition.unit ? { unit: definition.unit } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.setStateAsync(`timetable.today.${name}`, summary[name], true);\n\t\t}\n\t}\n\n\tprivate async updateCurrentNextStates(): Promise<void> {\n\t\tawait this.writeCurrentNextSummary(this.todayLessons, new Date());\n\t}\n\n\tprivate async cleanupObsoleteStructure(): Promise<void> {\n\t\tfor (const id of [\n\t\t\t\"info.timetable\",\n\t\t\t\"timetable.timetable\",\n\t\t\t\"timetable.today.count\",\n\t\t\t\"timetable.tomorrow.count\",\n\t\t\t\"timetable.today.subjectsJson\",\n\t\t\t\"timetable.tomorrow.subjectsJson\",\n\t\t]) {\n\t\t\tif (await this.getObjectAsync(id)) {\n\t\t\t\tawait this.delObjectAsync(id, { recursive: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async writeTimetableGroup(\n\t\tgroup: TimetableGroup,\n\t\tlessons: TimetableLesson[],\n\t\tnow: Date,\n\t): Promise<{ updated: number; removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(`timetable.${group}`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: `Timetable ${group}` },\n\t\t\tnative: {},\n\t\t});\n\t\tlet removed = await this.removeLegacyLessons(group);\n\t\tif (group === \"week\") {\n\t\t\tconst weekdayNames = [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\"];\n\t\t\tconst byDay = weekdayNames.map((_, index) => {\n\t\t\t\tconst targetDate = this.timetableDate(nextWeekday(now, index));\n\t\t\t\treturn lessons.filter(lesson => lesson.date === targetDate);\n\t\t\t});\n\t\t\tfor (let index = 0; index < weekdayNames.length; index++) {\n\t\t\t\tconst result = await this.writeTimetableDay(\n\t\t\t\t\t`timetable.week.${weekdayNames[index]}`,\n\t\t\t\t\tbyDay[index],\n\t\t\t\t\tthis.timetableDate(nextWeekday(now, index)),\n\t\t\t\t);\n\t\t\t\tawait this.writeDaySummary(`week.${weekdayNames[index]}`, summarizeTimetable(byDay[index]));\n\t\t\t\tremoved += result.removed;\n\t\t\t}\n\t\t} else {\n\t\t\tconst day = new Date(now);\n\t\t\tif (group === \"tomorrow\") {\n\t\t\t\tday.setDate(day.getDate() + 1);\n\t\t\t}\n\t\t\tconst result = await this.writeTimetableDay(`timetable.${group}`, lessons, this.timetableDate(day));\n\t\t\tawait this.writeDaySummary(group, summarizeTimetable(lessons));\n\t\t\tif (group === \"today\") {\n\t\t\t\tawait this.writeCurrentNextSummary(lessons, now);\n\t\t\t}\n\t\t\tremoved += result.removed;\n\t\t}\n\t\treturn { updated: lessons.length, removed };\n\t}\n\n\tprivate async removeLegacyLessons(group: TimetableGroup): Promise<number> {\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.timetable.${group}.`,\n\t\t\tendkey: `${this.namespace}.timetable.${group}.\\uffff`,\n\t\t});\n\t\tconst legacy = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst first = object.id.replace(`${this.namespace}.timetable.${group}.`, \"\").split(\".\")[0];\n\t\t\tif (first.startsWith(\"period-\")) {\n\t\t\t\tlegacy.add(first);\n\t\t\t}\n\t\t}\n\t\tfor (const id of legacy) {\n\t\t\tawait this.delObjectAsync(`timetable.${group}.${id}`, { recursive: true });\n\t\t}\n\t\treturn legacy.size;\n\t}\n\n\tprivate async writeTimetableDay(\n\t\tpath: string,\n\t\tlessons: TimetableLesson[],\n\t\tdate: string,\n\t): Promise<{ removed: number }> {\n\t\tawait this.setObjectNotExistsAsync(path, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: path.split(\".\").at(-1) || \"Day\" },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.writeSimpleState(`${path}.date`, dateOnly(date), \"Date\", \"string\", \"text\", \"\");\n\t\tawait this.writeSimpleState(\n\t\t\t`${path}.dateTimestamp`,\n\t\t\tnumericDate(date),\n\t\t\t\"Date (Unix timestamp ms)\",\n\t\t\t\"number\",\n\t\t\t\"value\",\n\t\t\t0,\n\t\t);\n\t\tawait this.writeSimpleState(`${path}.lessonCount`, lessons.length, \"Lesson count\", \"number\", \"value\", 0);\n\t\tawait this.setObjectNotExistsAsync(`${path}.lessons`, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: \"Lessons\" },\n\t\t\tnative: {},\n\t\t});\n\t\tconst expected = new Set(lessons.map((_lesson, index) => String(index + 1).padStart(2, \"0\")));\n\t\tconst existing = await this.getObjectListAsync({\n\t\t\tstartkey: `${this.namespace}.${path}.lessons.`,\n\t\t\tendkey: `${this.namespace}.${path}.lessons.\\uffff`,\n\t\t});\n\t\tconst stale = new Set<string>();\n\t\tfor (const object of existing.rows || []) {\n\t\t\tconst slot = object.id.replace(`${this.namespace}.${path}.lessons.`, \"\").split(\".\")[0];\n\t\t\tif (slot && !expected.has(slot)) {\n\t\t\t\tstale.add(slot);\n\t\t\t}\n\t\t}\n\t\tfor (const slot of stale) {\n\t\t\tawait this.delObjectAsync(`${path}.lessons.${slot}`, { recursive: true });\n\t\t}\n\t\tfor (const [index, lesson] of lessons.entries()) {\n\t\t\tawait this.writeLesson(path, String(index + 1).padStart(2, \"0\"), lesson);\n\t\t}\n\t\treturn { removed: stale.size };\n\t}\n\n\tprivate timetableDate(date: Date): string {\n\t\treturn `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n\t}\n\n\tprivate async writeSimpleState(\n\t\tid: string,\n\t\tvalue: string | number | boolean,\n\t\tname: string,\n\t\ttype: \"string\" | \"number\" | \"boolean\",\n\t\trole: string,\n\t\tdef: string | number | boolean,\n\t): Promise<void> {\n\t\tawait this.setObjectNotExistsAsync(id, {\n\t\t\ttype: \"state\",\n\t\t\tcommon: { name, type, role, read: true, write: false, def },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(id, { common: { name, type, role, read: true, write: false, def } });\n\t\tawait this.setStateAsync(id, value, true);\n\t}\n\n\tprivate async writeLesson(path: string, slot: string, lesson: TimetableLesson): Promise<void> {\n\t\tconst base = `${path}.lessons.${slot}`;\n\t\tconst label = lessonChannelName(lesson);\n\t\tawait this.setObjectNotExistsAsync(base, {\n\t\t\ttype: \"channel\",\n\t\t\tcommon: { name: label || `Lesson ${slot}` },\n\t\t\tnative: {},\n\t\t});\n\t\tawait this.extendObjectAsync(base, { common: { name: label || `Lesson ${slot}` } });\n\t\tconst values: Record<\n\t\t\tstring,\n\t\t\t{ value: string | number | boolean; type: \"string\" | \"number\" | \"boolean\"; role: string }\n\t\t> = {\n\t\t\tdate: { value: dateOnly(lesson.date), type: \"string\", role: \"text\" },\n\t\t\tdateTimestamp: { value: numericDate(lesson.date), type: \"number\", role: \"value\" },\n\t\t\tstartTime: { value: lesson.startTime, type: \"string\", role: \"text\" },\n\t\t\tendTime: { value: lesson.endTime, type: \"string\", role: \"text\" },\n\t\t\tsubject: { value: lesson.subject, type: \"string\", role: \"text\" },\n\t\t\tsubjectLong: { value: lesson.subjectLong, type: \"string\", role: \"text\" },\n\t\t\tteacher: { value: lesson.teacher, type: \"string\", role: \"text\" },\n\t\t\troom: { value: lesson.room, type: \"string\", role: \"text\" },\n\t\t\tclass: { value: lesson.class, type: \"string\", role: \"text\" },\n\t\t\t...(lesson.lessonId === null\n\t\t\t\t? {}\n\t\t\t\t: { lessonId: { value: String(lesson.lessonId), type: \"string\" as const, role: \"text\" } }),\n\t\t\t...(lesson.periodId === null\n\t\t\t\t? {}\n\t\t\t\t: { periodId: { value: String(lesson.periodId), type: \"string\" as const, role: \"text\" } }),\n\t\t\tstatus: { value: lesson.status, type: \"string\", role: \"text\" },\n\t\t\tchanged: { value: lesson.changed, type: \"boolean\", role: \"indicator\" },\n\t\t\tcancelled: { value: lesson.cancelled, type: \"boolean\", role: \"indicator\" },\n\t\t\t...(lesson.substitution\n\t\t\t\t? { substitution: { value: lesson.substitution, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalTeacher && lesson.originalTeacher !== lesson.teacher\n\t\t\t\t? { originalTeacher: { value: lesson.originalTeacher, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalRoom && lesson.originalRoom !== lesson.room\n\t\t\t\t? { originalRoom: { value: lesson.originalRoom, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t\t...(lesson.originalSubject && lesson.originalSubject !== lesson.subject\n\t\t\t\t? { originalSubject: { value: lesson.originalSubject, type: \"string\" as const, role: \"text\" } }\n\t\t\t\t: {}),\n\t\t};\n\t\tconst optional = [\"substitution\", \"originalTeacher\", \"originalRoom\", \"originalSubject\"];\n\t\tfor (const name of optional) {\n\t\t\tif (!(name in values) && (await this.getObjectAsync(`${base}.${name}`))) {\n\t\t\t\tawait this.delObjectAsync(`${base}.${name}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, item] of Object.entries(values)) {\n\t\t\tawait this.setObjectNotExistsAsync(`${base}.${name}`, {\n\t\t\t\ttype: \"state\",\n\t\t\t\tcommon: {\n\t\t\t\t\tname: LESSON_STATE_NAMES[name] || name,\n\t\t\t\t\ttype: item.type,\n\t\t\t\t\trole: item.role,\n\t\t\t\t\tread: true,\n\t\t\t\t\twrite: false,\n\t\t\t\t\tdef: item.value,\n\t\t\t\t},\n\t\t\t\tnative: {},\n\t\t\t});\n\t\t\tawait this.extendObjectAsync(`${base}.${name}`, {\n\t\t\t\tcommon: { name: LESSON_STATE_NAMES[name] || name, type: item.type, role: item.role, def: item.value },\n\t\t\t});\n\t\t\tawait this.setStateAsync(`${base}.${name}`, item.value, true);\n\t\t}\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj || !obj.command || !obj.callback) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (obj.command === \"searchSchools\") {\n\t\t\t\tconst results = await this.webUntis.searchSchools(this.getStringPayload(obj.message, \"query\"));\n\t\t\t\tthis.log.info(`School search returned ${results.length} results`);\n\t\t\t\tthis.sendTo(obj.from, obj.command, { ok: true, results }, obj.callback);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (obj.command === \"testConnection\") {\n\t\t\t\tconst result = await this.webUntis.testConnection(this.getConnectionPayload(obj.message));\n\t\t\t\tawait this.setState(\"info.connection\", result.ok, true);\n\t\t\t\tif (result.ok) {\n\t\t\t\t\tthis.log.info(\"WebUntis authentication successful\");\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.warn(`WebUntis authentication failed: ${result.code}`);\n\t\t\t\t}\n\t\t\t\tthis.sendTo(obj.from, obj.command, result, obj.callback);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst code = error instanceof WebUntisError ? error.code : \"UNEXPECTED_RESPONSE\";\n\t\t\tthis.log.warn(`WebUntis request failed: ${code}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { ok: false, code }, obj.callback);\n\t\t}\n\t}\n\n\tprivate getStringPayload(message: ioBroker.MessagePayload, key: string): string {\n\t\tif (\n\t\t\ttypeof message !== \"object\" ||\n\t\t\tmessage === null ||\n\t\t\ttypeof (message as Record<string, unknown>)[key] !== \"string\"\n\t\t) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid message payload\");\n\t\t}\n\t\treturn (message as Record<string, unknown>)[key] as string;\n\t}\n\n\tprivate getConnectionPayload(message: ioBroker.MessagePayload): WebUntisConnectionConfig {\n\t\tif (typeof message !== \"object\" || message === null) {\n\t\t\tthrow new WebUntisError(\"INVALID_CONFIG\", \"Invalid connection payload\");\n\t\t}\n\t\tconst value = message as Record<string, unknown>;\n\t\tconst stringValue = (key: string): string => (typeof value[key] === \"string\" ? value[key] : \"\");\n\t\treturn {\n\t\t\tserver: stringValue(\"server\"),\n\t\t\tschoolName: stringValue(\"schoolName\"),\n\t\t\tschoolDisplayName: stringValue(\"schoolDisplayName\"),\n\t\t\tschoolAddress: stringValue(\"schoolAddress\"),\n\t\t\tschoolId: typeof value.schoolId === \"number\" ? value.schoolId : null,\n\t\t\tusername: stringValue(\"username\"),\n\t\t\tpassword: stringValue(\"password\"),\n\t\t};\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tif (this.timetableTimer) {\n\t\t\tthis.clearInterval(this.timetableTimer);\n\t\t}\n\t\tif (this.currentNextTimer) {\n\t\t\tthis.clearInterval(this.currentNextTimer);\n\t\t}\n\t\tcallback();\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new WebuntisNext(options);\n} else {\n\t(() => new WebuntisNext())();\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "webuntis2",
4
- "version": "0.1.0",
4
+ "version": "0.1.1",
5
5
  "news": {
6
+ "0.1.1": {
7
+ "en": "Improved rolling weekly timetable, weekly summaries and date states with Unix timestamps",
8
+ "de": "Verbesserte rollierende Wochenansicht, Wochentagszusammenfassungen und Datumsdatenpunkte mit Unix-Zeitstempeln",
9
+ "ru": "Улучшенное скользящее недельное расписание, сводки по дням недели и состояния дат с временными метками Unix",
10
+ "pt": "Calendário semanal contínuo melhorado, resumos dos dias da semana e estados de data com marcas de tempo Unix",
11
+ "nl": "Verbeterd doorlopend weekrooster, weeksamenvattingen en datumstatussen met Unix-tijdstempels",
12
+ "fr": "Planning hebdomadaire glissant amélioré, résumés des jours de la semaine et états de date avec horodatages Unix",
13
+ "it": "Calendario settimanale continuo migliorato, riepiloghi dei giorni della settimana e stati delle date con timestamp Unix",
14
+ "es": "Calendario semanal continuo mejorado, resúmenes de los días de la semana y estados de fecha con marcas de tiempo Unix",
15
+ "pl": "Ulepszony kroczący tygodniowy plan lekcji, podsumowania dni tygodnia i stany dat z sygnaturami czasu Unix",
16
+ "uk": "Покращений ковзний тижневий розклад, підсумки днів тижня та стани дат із часовими мітками Unix",
17
+ "zh-cn": "改进的滚动周课表、每周每日摘要以及带 Unix 时间戳的日期状态"
18
+ },
6
19
  "0.1.0": {
7
20
  "en": "complete feature release",
8
21
  "de": "vollständige Funktionsveröffentlichung",
@@ -95,7 +108,7 @@
95
108
  ],
96
109
  "globalDependencies": [
97
110
  {
98
- "admin": ">=7.6.20"
111
+ "admin": ">=7.8.23"
99
112
  }
100
113
  ]
101
114
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.webuntis2",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Connect ioBroker to WebUntis for timetables, school information and related data",
5
5
  "author": {
6
6
  "name": "Voodoo2man",