diff --git a/src/App.tsx b/src/App.tsx
index 51d9746..cfe54d4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,12 +1,14 @@
import "@/App.css";
-import Timetable from "@/components/Timetable/Timetable";
import Flatastic from "@/components/Flatastic/Flatastic";
+import HomeAssistant from "@/components/HomeAssistant/HomeAssistant";
+import Timetable from "@/components/Timetable/Timetable";
function App() {
return (
<>
+
>
);
}
diff --git a/src/api/homeAssistant.ts b/src/api/homeAssistant.ts
new file mode 100644
index 0000000..ded16d7
--- /dev/null
+++ b/src/api/homeAssistant.ts
@@ -0,0 +1,30 @@
+const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkMjQ1OTg0YjliYzE0OTNjYTdmZDJmNTA3ODgzN2U1YSIsImlhdCI6MTc1MzQwMjAzNiwiZXhwIjoyMDY4NzYyMDM2fQ.fnLSFKPdk8lkAEB-4ekdGUJ1PSCBxcAyasQF1PyrD3k";
+
+async function fetchTentHumidity() {
+ const url = "/api/states/sensor.third_reality_inc_3rths0224z_luftfeuchtigkeit_2";
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ "Authorization": `Bearer ${token}`,
+ }
+ });
+ const data = await response.json();
+
+ return data.state;
+}
+
+async function fetchTentTemperature() {
+ const url = "/api/states/sensor.third_reality_inc_3rths0224z_temperatur_2";
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ "Authorization": `Bearer ${token}`,
+ }
+ });
+
+ const data = await response.json();
+
+ return data.state;
+}
+
+export { fetchTentHumidity, fetchTentTemperature };
\ No newline at end of file
diff --git a/src/api/kvv.ts b/src/api/kvv.ts
index 6e1f901..f67cbc3 100644
--- a/src/api/kvv.ts
+++ b/src/api/kvv.ts
@@ -1,5 +1,5 @@
async function fetchKvvDepartures(stopId: number) {
- const API_URL = `https://projekte.kvv-efa.de/sl3-alone/XSLT_DM_REQUEST?outputFormat=JSON&coordOutputFormat=WGS84[dd.ddddd]&depType=stopEvents&locationServerActive=1&mode=direct&name_dm=${stopId}&type_dm=stop&useOnlyStops=1&useRealtime=1&limit=6&line=kvv:22301:E:H:s25&line=kvv:21012:E:H:s25&line=kvv:21012:E:R:s25&line=kvv:22305:E:H:s25`;
+ const API_URL = `https://projekte.kvv-efa.de/sl3-alone/XSLT_DM_REQUEST?outputFormat=JSON&coordOutputFormat=WGS84%5Bdd.ddddd%5D&command=&itdLPxx_timeFormat=12&language=de&itdLPxx_useJs=1&std3_suggestMacro=std3_suggest&std3_commonMacro=dm&itdLPxx_contractor=&std3_contractorMacro=&includeCompleteStopSeq=1&useAllStops=1&name_dm=${stopId}&type_dm=any&itdDateTimeDepArr=dep&includedMeans=checkbox&itdLPxx_ptActive=on&useRealtime=1&std3_inclMOT_0Macro=true&std3_inclMOT_1Macro=true&std3_inclMOT_4Macro=true&std3_inclMOT_5Macro=true&imparedOptionsActive=1&nameInfo_dm=7000044&itdLPxx_multiStepDm=2&deleteAssignedStops=1&mode=direct&line=kvv%253A22301%253AE%253AH%253As25&line=kvv%253A22301%253AE%253AR%253As25&line=kvv%253A21012%253AE%253AH%253As25&line=kvv%253A21012%253AE%253AR%253As25&line=kvv%253A22305%253AE%253AH%253As25&line=kvv%253A22305%253AE%253AR%253As25&line=kvv%253A22308%253AE%253AR%253As25&line=kvv%253A22311%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AR%253As25&itdLPxx_snippet=1&itdLPxx_template=dmresults&limit=10`;
const data = await fetch(API_URL, {
method: "GET",
diff --git a/src/components/DepartureList/DepartureList.tsx b/src/components/DepartureList/DepartureList.tsx
new file mode 100644
index 0000000..c643460
--- /dev/null
+++ b/src/components/DepartureList/DepartureList.tsx
@@ -0,0 +1,66 @@
+import TimetableRow from "@/components/TimetableRow/TimetableRow";
+import type { DepartureType } from "@/types/departureType";
+
+import style from "./style.module.css";
+
+function parseTimetableData(data: DepartureType[]) {
+ const left: DepartureType[] = [];
+ const right: DepartureType[] = [];
+
+ data.forEach((departure) => {
+ if (
+ departure.servingLine?.liErgRiProj?.direction === "R" &&
+ right.length < 5
+ ) {
+ right.push(departure);
+ } else if (left.length < 5) {
+ left.push(departure);
+ }
+
+ // Limit to 5 departures per side
+ if (left.length >= 5 && right.length >= 5) {
+ return;
+ }
+ });
+
+ return {
+ left,
+ right,
+ };
+}
+
+function departureTables(departures: DepartureType[], name: string) {
+ return (
+
+
{name} Departures
+
+
+ {departures.map((departure, index) => (
+ // biome-ignore lint/suspicious/noArrayIndexKey: there is no id
+
+ ))}
+
+
+
+ );
+}
+
+export default function DepartureList(props: {
+ departures: DepartureType[];
+ name: string;
+}) {
+ const { departures, name } = props;
+
+ if (!departures || departures.length === 0) {
+ return No departures available
;
+ }
+
+ const { left, right } = parseTimetableData(departures);
+
+ return (
+
+ {departureTables(left, name)}
+ {departureTables(right, name)}
+
+ );
+}
diff --git a/src/components/DepartureList/style.module.css b/src/components/DepartureList/style.module.css
new file mode 100644
index 0000000..7ce8db2
--- /dev/null
+++ b/src/components/DepartureList/style.module.css
@@ -0,0 +1,5 @@
+.container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
diff --git a/src/components/HomeAssistant/HomeAssistant.tsx b/src/components/HomeAssistant/HomeAssistant.tsx
new file mode 100644
index 0000000..4d4ac81
--- /dev/null
+++ b/src/components/HomeAssistant/HomeAssistant.tsx
@@ -0,0 +1,24 @@
+import { useEffect } from "react";
+import { useHomeAssistantStore } from "@/store/homeAssistant";
+
+export default function Timetable() {
+ const fetchHomeAssistantData = useHomeAssistantStore((state) => state.fetch);
+ const tentTemperature = useHomeAssistantStore((state) => state.tentTemperature);
+ const tentHumidity = useHomeAssistantStore((state) => state.tentHumidity);
+
+ useEffect(() => {
+ fetchHomeAssistantData();
+ const interval = setInterval(() => {
+ fetchHomeAssistantData();
+ }, 60000);
+ return () => clearInterval(interval);
+ }, [fetchHomeAssistantData]);
+
+ return (
+
+
Tent
+
Temperature: {tentTemperature}°C
+
Humidity: {tentHumidity}%
+
+ );
+}
diff --git a/src/components/Timetable/Timetable.tsx b/src/components/Timetable/Timetable.tsx
index 19c289b..c4d2d11 100644
--- a/src/components/Timetable/Timetable.tsx
+++ b/src/components/Timetable/Timetable.tsx
@@ -1,18 +1,6 @@
import { useEffect } from "react";
-
-import TimetableRow from "@/components/TimetableRow/TimetableRow";
+import DepartureList from "@/components/DepartureList/DepartureList";
import { useKVVStore } from "@/store/kvv";
-import type { DepartureType } from "@/types/departureType";
-
-function parseTimetableData(data: DepartureType[]) {
- const result = data.map((item) => {
- return {
- ...item,
- };
- });
-
- return result;
-}
export default function Timetable() {
const fetchTimetable = useKVVStore((state) => state.fetch);
@@ -27,30 +15,11 @@ export default function Timetable() {
return () => clearInterval(interval);
}, [fetchTimetable]);
- const hStreetData = parseTimetableData(hStreet.departureList || []);
- const pStreetData = parseTimetableData(pStreet.departureList || []);
-
return (
Timetable
-
H-Street Departures
-
-
- {hStreetData.map((departure, index) => (
- // biome-ignore lint/suspicious/noArrayIndexKey: there is no id
-
- ))}
-
-
-
P-Street Departures
-
-
- {pStreetData.map((departure, index) => (
- // biome-ignore lint/suspicious/noArrayIndexKey: there is no id
-
- ))}
-
-
+
+
);
}
diff --git a/src/components/TimetableRow/TimetableRow.tsx b/src/components/TimetableRow/TimetableRow.tsx
index ac5efa7..7c7bb15 100644
--- a/src/components/TimetableRow/TimetableRow.tsx
+++ b/src/components/TimetableRow/TimetableRow.tsx
@@ -14,7 +14,6 @@ export default function TimetableRow({
return (
| {dateTimeString} |
- {departure.servingLine.name} |
{departure.servingLine.number} |
({departure.servingLine.direction}) |
diff --git a/src/store/homeAssistant.ts b/src/store/homeAssistant.ts
new file mode 100644
index 0000000..7ebbf73
--- /dev/null
+++ b/src/store/homeAssistant.ts
@@ -0,0 +1,28 @@
+import { create } from "zustand";
+import { devtools } from "zustand/middleware";
+import { fetchTentHumidity, fetchTentTemperature } from "@/api/homeAssistant";
+
+const useHomeAssistantStore = create(
+ devtools(
+ (set) => ({
+ tentTemperature: 0,
+ tentHumidity: 0,
+ fetch: async () => {
+ const [temperature, humidity] = await Promise.all([
+ fetchTentTemperature(),
+ fetchTentHumidity(),
+ ]);
+
+ set({
+ tentTemperature: temperature,
+ tentHumidity: humidity,
+ });
+ },
+ }),
+ {
+ name: "home-assistant-store",
+ },
+ ),
+);
+
+export { useHomeAssistantStore };
diff --git a/src/types/departureType.ts b/src/types/departureType.ts
index 1b29ea9..19687dd 100644
--- a/src/types/departureType.ts
+++ b/src/types/departureType.ts
@@ -10,6 +10,9 @@ export type DepartureType = {
number: string;
name: string;
direction: string;
+ liErgRiProj: {
+ direction: string;
+ };
};
stopID: number;
};
diff --git a/src/types/dwdType.ts b/src/types/dwdType.ts
index 31d1231..57b4da4 100644
--- a/src/types/dwdType.ts
+++ b/src/types/dwdType.ts
@@ -1,13 +1,13 @@
export interface Forecast2 {
- stationId: string;
- start: number;
- timeStep: number;
- temperature: number[];
- precipitationTotal: number[];
- sunshine: number[];
- dewPoint2m: number[];
- surfacePressure: number[];
- humidity: number[];
- isDay: boolean[];
- temperatureStd: number[];
+ stationId: string;
+ start: number;
+ timeStep: number;
+ temperature: number[];
+ precipitationTotal: number[];
+ sunshine: number[];
+ dewPoint2m: number[];
+ surfacePressure: number[];
+ humidity: number[];
+ isDay: boolean[];
+ temperatureStd: number[];
}
diff --git a/vite.config.ts b/vite.config.ts
index 3d421f9..08dbeec 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,6 +1,6 @@
-import { defineConfig } from "vite";
-import react from "@vitejs/plugin-react-swc";
import path from "node:path";
+import react from "@vitejs/plugin-react-swc";
+import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
@@ -16,4 +16,14 @@ export default defineConfig({
"@slices": path.resolve(__dirname, "src/store/slices"),
},
},
+ server: {
+ proxy: {
+ "/api": {
+ target: "https://home.rivercry.com",
+ changeOrigin: true,
+ secure: false,
+ rewrite: (path) => path.replace(/^\/api/, "/api"),
+ },
+ },
+ },
});