diff --git a/gatsby-config.js b/gatsby-config.js index 4f2a67f..bf0e446 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -9,7 +9,7 @@ module.exports = { resolve: "gatsby-plugin-react-svg", options: { rule: { - include: /weather/ // See below to configure properly + include: /weather/ } } } diff --git a/package-lock.json b/package-lock.json index f26d056..1b74122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "gatsby-plugin-react-svg": "^3.1.0", "os-browserify": "^0.3.0", "react": "^17.0.1", - "react-dom": "^17.0.1" + "react-dom": "^17.0.1", + "react-use-websocket": "^2.9.1" }, "devDependencies": { "@types/webpack-env": "^1.16.3" @@ -13263,6 +13264,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-use-websocket": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-2.9.1.tgz", + "integrity": "sha512-jV6OxXuxWi6BiPVlbAJd/uWNaoQwkeGARFO9f6HidJeWUatB4J2UopbxI/fduiGpcpHGhRAmpLdfVjeRzrcTnQ==", + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -26439,6 +26449,12 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==" }, + "react-use-websocket": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-2.9.1.tgz", + "integrity": "sha512-jV6OxXuxWi6BiPVlbAJd/uWNaoQwkeGARFO9f6HidJeWUatB4J2UopbxI/fduiGpcpHGhRAmpLdfVjeRzrcTnQ==", + "requires": {} + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", diff --git a/package.json b/package.json index 879b26c..42cc00c 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "gatsby-plugin-react-svg": "^3.1.0", "os-browserify": "^0.3.0", "react": "^17.0.1", - "react-dom": "^17.0.1" + "react-dom": "^17.0.1", + "react-use-websocket": "^2.9.1" }, "devDependencies": { "@types/webpack-env": "^1.16.3" diff --git a/src/components/PlantState.tsx b/src/components/PlantState.tsx new file mode 100644 index 0000000..2375e9d --- /dev/null +++ b/src/components/PlantState.tsx @@ -0,0 +1,53 @@ +import * as React from "react" +import { PlantState as PlantStateType } from "../lib/interfaces"; +import * as styles from "../styles/containers/PlantState.module.css" + +const PLANT_REFRESH_INTERVAL = 15 * 60 * 1000; + +const PlantState = ({ hassUrl, token, plants }: { hassUrl: string, token: string, plants: string[] }) => { + const [plantStates, setPlantStates] = React.useState>({}); + + const pullPlants = async () => { + const plantStates: Record = {} + + for (const plant of plants) { + const response = await fetch(`${hassUrl}/api/states/plant.${plant.toLowerCase()}`, { + method: "GET", + headers: { + "Authorization": `Bearer ${token}`, + "Content-Type": "application/json" + } + }); + const data = await response.json(); + plantStates[plant] = data.attributes + } + + console.log(plantStates); + setPlantStates(plantStates); + } + + React.useEffect(() => { + pullPlants() + const plantInterval = setInterval(pullPlants, PLANT_REFRESH_INTERVAL); + + return () => clearInterval(plantInterval); + }, []) + + return
+ {Object.keys(plantStates).map((key) => { + return
+
{key}
+
+ 💧
+ {plantStates[key].moisture === "unavailable" ? "?" : plantStates[key].moisture} {plantStates[key].unit_of_measurement_dict.moisture} +
+
+ 🪴
+ {plantStates[key].conductivity === "unavailable" ? "?" : plantStates[key].conductivity} {plantStates[key].unit_of_measurement_dict.conductivity} +
+
+ })} +
+} + +export default PlantState; \ No newline at end of file diff --git a/src/components/Spotify.tsx b/src/components/Spotify.tsx new file mode 100644 index 0000000..8bc1013 --- /dev/null +++ b/src/components/Spotify.tsx @@ -0,0 +1,28 @@ +import * as React from "react" +import useWebSocket from "react-use-websocket"; +import * as styles from "../styles/containers/Spotify.module.css" + +const Spotify = ({ wsUrl, Alternative }: { wsUrl: string, Alternative: any }) => { + const { lastJsonMessage, getWebSocket, sendJsonMessage } = useWebSocket(wsUrl, { + onOpen: () => sendJsonMessage({GET:1}), + onMessage: (evt) => { + console.log(evt.data) + }, + //Will attempt to reconnect on all close events, such as server shutting down + shouldReconnect: (closeEvent) => closeEvent.code !== 1000, + }); + + React.useEffect(() => { + console.log(lastJsonMessage) + }, [lastJsonMessage]) + + if (!lastJsonMessage || lastJsonMessage.playbackState !== "Play") { + return Alternative; + } + + return
+ +
+} + +export default Spotify; \ No newline at end of file diff --git a/src/lib/interfaces.ts b/src/lib/interfaces.ts index f3c6666..569d72f 100644 --- a/src/lib/interfaces.ts +++ b/src/lib/interfaces.ts @@ -33,13 +33,13 @@ export interface Event { } export interface News { - title: string; + title: string; updated: string; } export interface PostillonNews { - title: string; - pubDate: string; + title: string; + pubDate: string; categories: string[]; } @@ -50,4 +50,18 @@ export interface Departure { ScheduledTime: string; State?: "Delayed" | "InTime" | "Canceled"; CancelReasons?: string[]; +} + +export interface PlantState { + brightness: number | "unavailable"; + conductivity: number | "unavailable"; + moisture: number | "unavailable"; + problem: string; + temperature: number | "unavailable"; + unit_of_measurement_dict: { + brightness: string; + conductivity: string; + moisture: string; + temperature: string; + } } \ No newline at end of file diff --git a/src/pages/index.tsx b/src/pages/index.tsx index ecf5f80..4f7e47c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -3,6 +3,8 @@ import secrets from "../../secrets.json" import Calendar from "../components/Calendar"; import DVB from "../components/DVB"; import News from "../components/News"; +import Spotify from "../components/Spotify"; +import PlantState from "../components/PlantState"; import WeatherAndTimeContainer from "../components/WeatherAndTime" import WeatherRadar from "../components/WeatherRadar"; @@ -38,6 +40,7 @@ const IndexPage = () => { + } /> ) } diff --git a/src/styles/containers/PlantState.module.css b/src/styles/containers/PlantState.module.css new file mode 100644 index 0000000..2892574 --- /dev/null +++ b/src/styles/containers/PlantState.module.css @@ -0,0 +1,44 @@ +.container { + display: grid; + grid-template-columns: auto auto; + height: 100%; +} + +.plant { + display: grid; + grid-template-areas: + "plantName plantName" + "moisture conductivity"; + text-align: center; + border-right: 1px solid var(--iconColor); +} + +.plant:last-of-type { + border-right: none; +} + +.plant div:nth-child(1) { + grid-area: plantName; + font-weight: bold; + font-size: 200%; +} + +.plant div:nth-child(2) { + grid-area: moisture; + font-weight: bold; + font-size: 190%; +} + +.plant div:nth-child(3) { + grid-area: conductivity; + font-weight: bold; + font-size: 190%; +} + +.icon { + font-size: 250%; +} + +.problem { + color: #ff0000; +} \ No newline at end of file diff --git a/src/styles/containers/Spotify.module.css b/src/styles/containers/Spotify.module.css new file mode 100644 index 0000000..d08032b --- /dev/null +++ b/src/styles/containers/Spotify.module.css @@ -0,0 +1,21 @@ +.container { + grid-area: spotify; + display: grid; + grid-template-columns: auto max-content; + justify-content: start; + width:100%; + height:100%; + padding:5px; + background: var(--spotifyColor); + border-radius: 5px; +} +.container p { + max-width: 21vw; + color: inherit; + word-wrap: normal; +} +.title { + font-size: 180%; + font-weight: bold; + color: inherit; +} \ No newline at end of file