Basic spotify and plant

This commit is contained in:
Daniel Kluge 2022-01-04 00:56:06 +01:00
parent f3f01f9717
commit c0cc162ae4
9 changed files with 186 additions and 6 deletions

View File

@ -9,7 +9,7 @@ module.exports = {
resolve: "gatsby-plugin-react-svg", resolve: "gatsby-plugin-react-svg",
options: { options: {
rule: { rule: {
include: /weather/ // See below to configure properly include: /weather/
} }
} }
} }

18
package-lock.json generated
View File

@ -13,7 +13,8 @@
"gatsby-plugin-react-svg": "^3.1.0", "gatsby-plugin-react-svg": "^3.1.0",
"os-browserify": "^0.3.0", "os-browserify": "^0.3.0",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1" "react-dom": "^17.0.1",
"react-use-websocket": "^2.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/webpack-env": "^1.16.3" "@types/webpack-env": "^1.16.3"
@ -13263,6 +13264,15 @@
"node": ">=0.10.0" "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": { "node_modules/read": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "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", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz",
"integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==" "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": { "read": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",

View File

@ -20,7 +20,8 @@
"gatsby-plugin-react-svg": "^3.1.0", "gatsby-plugin-react-svg": "^3.1.0",
"os-browserify": "^0.3.0", "os-browserify": "^0.3.0",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1" "react-dom": "^17.0.1",
"react-use-websocket": "^2.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/webpack-env": "^1.16.3" "@types/webpack-env": "^1.16.3"

View File

@ -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<Record<string, PlantStateType>>({});
const pullPlants = async () => {
const plantStates: Record<string, PlantStateType> = {}
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 <div className={`container ${styles.container}`}>
{Object.keys(plantStates).map((key) => {
return <div key={key} className={styles.plant}>
<div>{key}</div>
<div className={plantStates[key].problem.includes("moisture") ? styles.problem : ""}>
<span className={styles.icon}>💧</span><br />
{plantStates[key].moisture === "unavailable" ? "?" : plantStates[key].moisture} {plantStates[key].unit_of_measurement_dict.moisture}
</div>
<div className={plantStates[key].problem.includes("conductivity") ? styles.problem : ""}>
<span className={styles.icon}>🪴</span><br />
{plantStates[key].conductivity === "unavailable" ? "?" : plantStates[key].conductivity} {plantStates[key].unit_of_measurement_dict.conductivity}
</div>
</div>
})}
</div>
}
export default PlantState;

View File

@ -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 <div className={`container ${styles.container}`}>
</div>
}
export default Spotify;

View File

@ -33,13 +33,13 @@ export interface Event {
} }
export interface News { export interface News {
title: string; title: string;
updated: string; updated: string;
} }
export interface PostillonNews { export interface PostillonNews {
title: string; title: string;
pubDate: string; pubDate: string;
categories: string[]; categories: string[];
} }
@ -50,4 +50,18 @@ export interface Departure {
ScheduledTime: string; ScheduledTime: string;
State?: "Delayed" | "InTime" | "Canceled"; State?: "Delayed" | "InTime" | "Canceled";
CancelReasons?: string[]; 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;
}
} }

View File

@ -3,6 +3,8 @@ import secrets from "../../secrets.json"
import Calendar from "../components/Calendar"; import Calendar from "../components/Calendar";
import DVB from "../components/DVB"; import DVB from "../components/DVB";
import News from "../components/News"; import News from "../components/News";
import Spotify from "../components/Spotify";
import PlantState from "../components/PlantState";
import WeatherAndTimeContainer from "../components/WeatherAndTime" import WeatherAndTimeContainer from "../components/WeatherAndTime"
import WeatherRadar from "../components/WeatherRadar"; import WeatherRadar from "../components/WeatherRadar";
@ -38,6 +40,7 @@ const IndexPage = () => {
<WeatherRadar /> <WeatherRadar />
<News /> <News />
<DVB stopId={secrets.dvb.stopId} /> <DVB stopId={secrets.dvb.stopId} />
<Spotify wsUrl="ws://localhost:10000" Alternative={<PlantState hassUrl={secrets.hass.url} token={secrets.hass.token} plants={["Chili", "Basilikum"]} />} />
</main>) </main>)
} }

View File

@ -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;
}

View File

@ -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;
}