Working API communication with the server

This commit is contained in:
Nomi Nonsense (Nonszy) 2024-03-10 19:11:32 +07:00
parent 36c6cf5bda
commit 3450695885
13 changed files with 216 additions and 74 deletions

View File

@ -10,9 +10,11 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.7",
"bootstrap-icons": "^1.11.3", "bootstrap-icons": "^1.11.3",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0",
"socket.io-client": "^4.7.4"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.56", "@types/react": "^18.2.56",

View File

@ -4,7 +4,7 @@ import BackroundImg from "../assets/img/background.png";
export default function MainBody({ children }: { children?: ReactNode }) { export default function MainBody({ children }: { children?: ReactNode }) {
return ( return (
<div <div
className="bg-background text-white bg-repeat-y relative" className="bg-background text-white bg-repeat-y bg-cover relative"
style={{ style={{
backgroundImage: `url(${BackroundImg})` backgroundImage: `url(${BackroundImg})`
}} }}

View File

@ -1,11 +1,46 @@
import { ChangeEvent, Ref, useEffect } from "react";
import PinBox from "../forms/PinBox"; import PinBox from "../forms/PinBox";
import { useLed } from "../../hooks"; import { useLed } from "../../hooks";
import ControlSection from "../ControlSection"; import ControlSection from "../ControlSection";
import { Ref } from "react"; import { PinState } from "../../types/board";
import { PatchLed } from "../../controllers/BoardController";
function LedItem ({ led, index }: { led: PinState, index: number }) {
const { removeLed, setLed, setLedPin } = useLed();
const handleChange = (e: ChangeEvent<HTMLInputElement | null>) => {
const pin = e.target?.value;
setLedPin(index, pin);
}
const toggleLed = () => {
setLed(led.pin, !led.state);
}
const handleRemove = () => {
removeLed(index);
}
useEffect(() => {
const pin: number = typeof led.pin == "string" ? Number.parseInt(led.pin) : led.pin;
PatchLed(pin, led.state);
}, [led.state]);
return (
<PinBox.Toggle
className="w-36 animate-fade-in"
minusBtn={true}
value={led.pin}
state={led.state}
onValueChange={handleChange}
onStateChange={toggleLed}
onDelete={handleRemove}
/>
)
}
function ControlLED ({ refto }: { refto?: Ref<HTMLDivElement> }) { function ControlLED ({ refto }: { refto?: Ref<HTMLDivElement> }) {
const { addLed, leds, removeLed, setLed, setLedPin } = useLed(); const { addLed, leds } = useLed();
const handleAdd = (): void => { const handleAdd = (): void => {
let anopin = 13; let anopin = 13;
@ -28,23 +63,10 @@ function ControlLED ({ refto }: { refto?: Ref<HTMLDivElement> }) {
refto={refto} refto={refto}
stack={(<> stack={(<>
{leds.map((led, i) => ( {leds.map((led, i) => (
<PinBox.Toggle <LedItem
className="w-36 animate-fade-in" led={led}
index={i}
key={i} key={i}
minusBtn={true}
value={led.pin}
state={led.state}
onValueChange={(e) => {
const pin = e.target.value;
setLedPin(i, pin);
}}
onStateChange={() => {
const state = !led.state;
setLed(led.pin, state);
}}
onDelete={() => {
removeLed(i);
}}
/> />
))} ))}
{leds.length < 14 && <PinBox.Add {leds.length < 14 && <PinBox.Add

View File

@ -1,14 +1,15 @@
import { ChangeEvent, MouseEventHandler, Ref, useState } from "react"; import { ChangeEvent, MouseEventHandler, Ref, useEffect, useState } from "react";
import { usePhotoresistor } from "../../hooks"; import { usePhotoresistor } from "../../hooks";
import { DynamicPinState } from "../../types/board"; import { DynamicPinState } from "../../types/board";
import CircleResistance from "../shapes/CircleResistance"; import CircleResistance from "../shapes/CircleResistance";
import TwoRowTab from "../info/TwoRowTab"; import TwoRowTab from "../info/TwoRowTab";
import EvoInput from "../forms/EvoInput"; import EvoInput from "../forms/EvoInput";
import Button from "../forms/Button"; import Button from "../forms/Button";
import { io } from "../../socket/socket.io";
function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }) { function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }) {
const { setResistorPin, removeResistor } = usePhotoresistor(); const { setResistorPin, setResistance, removeResistor } = usePhotoresistor();
const [isListen, setListen] = useState<boolean>(false); const [isListen, setListen] = useState<boolean>(false);
@ -27,6 +28,26 @@ function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }
removeResistor(index); removeResistor(index);
} }
useEffect(() => {
const pin = typeof resistor.pin == "string" && resistor.pin[0] == "A" ?
resistor.pin[1] : resistor.pin;
if (isListen) {
io.emit("set-photoresistor", pin);
const handler = (value: string) => {
const res: number = Number.parseInt(value);
setResistance(resistor.pin, res);
}
io.on("photoresistor", handler);
return () => {
io.off("photoresistor", handler);
}
}
}, [io, isListen]);
return ( return (
<div className="border border-border bg-secondary col-span-2 rounded-lg p-6 animate-size-fade-in"> <div className="border border-border bg-secondary col-span-2 rounded-lg p-6 animate-size-fade-in">
<div className="flex justify-items-end"> <div className="flex justify-items-end">
@ -36,7 +57,7 @@ function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }
</div> </div>
<div className="h-52 flex items-center justify-center"> <div className="h-52 flex items-center justify-center">
<CircleResistance <CircleResistance
resistance={0} intensity={intensity}
/> />
</div> </div>
<div className="flex flex-col mt-3 gap-3"> <div className="flex flex-col mt-3 gap-3">
@ -98,7 +119,7 @@ function ControlPhotoresistor ({ refto }: { refto?: Ref<HTMLDivElement> }) {
Photoresistor Photoresistor
</h2> </h2>
<div className="grid grid-cols-8 mb-8"> <div className="grid grid-cols-8 mb-8">
<p className="col-span-6">Also known as LDR (Light Dependent Resistor), it is an electronic component whose resistance changes based on the intensity of light it receives. The higher the light intensity, the lower the resistance, When exposed to intense light, a photoresistor experiences a decrease in resistance due to photoconduction. The molecules in the photoresistor material become more active and allow electric current to flow through the material more easily.</p> <p className="col-span-6">Also known as LDR {"("}Light Dependent Resistor{")"}, it is an electronic component whose resistance changes based on the intensity of light it receives. The higher the light intensity, the lower the resistance, When exposed to intense light, a photoresistor experiences a decrease in resistance due to photoconduction. The molecules in the photoresistor material become more active and allow electric current to flow through the material more easily.</p>
</div> </div>
<div className={`grid grid-cols-8 gap-6`}> <div className={`grid grid-cols-8 gap-6`}>
{resistors.map((resistor, i) => ( {resistors.map((resistor, i) => (

View File

@ -1,6 +1,7 @@
import PinBox from "../forms/PinBox"; import PinBox from "../forms/PinBox";
import ControlSection from "../ControlSection"; import ControlSection from "../ControlSection";
import { Ref } from "react"; import { PatchPiezo } from "../../controllers/BoardController";
import { ChangeEvent, Ref, useEffect, useState } from "react";
import { usePiezo } from "../../hooks"; import { usePiezo } from "../../hooks";
import { DynamicPinState } from "../../types/board"; import { DynamicPinState } from "../../types/board";
import EvoInput from "../forms/EvoInput"; import EvoInput from "../forms/EvoInput";
@ -9,31 +10,48 @@ import Button from "../forms/Button";
function PiezoItem ({ piezo, index }: { piezo: DynamicPinState, index: number }) { function PiezoItem ({ piezo, index }: { piezo: DynamicPinState, index: number }) {
const { setFrequency, setPiezoPin, removePiezo } = usePiezo(); const { setFrequency, setPiezoPin, removePiezo } = usePiezo();
const [freq, setFreq] = useState<number | string>(piezo.state);
const handlePinChange = (e: ChangeEvent<HTMLInputElement | null>) => {
const pin = e.target?.value;
setPiezoPin(index, pin);
}
const handleFreqChange = (e: ChangeEvent<HTMLInputElement | null>) => {
setFreq(e.target.value);
}
const handleDelete = () => {
removePiezo(index);
}
const handlePatch = () => {
const pin: number = typeof piezo.pin == "string" ? Number.parseInt(piezo.pin) : piezo.pin;
PatchPiezo(pin, piezo.state);
}
useEffect(() => {
const f: number = typeof freq == "string" ? Number.parseInt(freq) : freq;
if (!Number.isNaN(freq)) setFrequency(index, f);
}, [freq])
return ( return (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<PinBox <PinBox
className="w-36 animate-fade-in" className="w-36 animate-fade-in"
minusBtn={true} minusBtn={true}
value={piezo.pin} value={piezo.pin}
onValueChange={(e) => { onValueChange={handlePinChange}
const pin = e.target.value; onDelete={handleDelete}
setPiezoPin(index, pin);
}}
onDelete={() => {
removePiezo(index);
}}
/> />
<EvoInput <EvoInput
className="w-36 h-11" className="w-36 h-11"
name="Frequency" name="Frequency"
type="number" type="number"
value={piezo.state.toString()} value={piezo.state.toString()}
onChange={(e) => { onChange={handleFreqChange}
const freq: number = Number.parseInt(e.target.value);
if (!Number.isNaN(freq)) setFrequency(piezo.pin, freq);
}}
/> />
<Button.Primary className="text-sm !py-0 h-11">Play</Button.Primary> <Button.Primary onClick={handlePatch} className="text-sm !py-0 h-11">Play</Button.Primary>
</div> </div>
) )
} }

View File

@ -1,3 +1,4 @@
import { PatchRgbLed } from "../../controllers/BoardController";
import { useRgbLed } from "../../hooks"; import { useRgbLed } from "../../hooks";
import { ChannelPinState, PinState } from "../../types/board"; import { ChannelPinState, PinState } from "../../types/board";
import EvoInput from "../forms/EvoInput"; import EvoInput from "../forms/EvoInput";
@ -5,34 +6,51 @@ import Switch from "../forms/Switch";
import { MouseEventHandler, Ref, useEffect, useState } from "react"; import { MouseEventHandler, Ref, useEffect, useState } from "react";
interface HorizontalBarProps { interface HorizontalBarProps {
pinState: ChannelPinState; rgbLed: ChannelPinState;
onUpdate?: (pin: ChannelPinState) => void; index: number;
onDelete?: () => void }
function HorizontalBar ({ rgbLed, index }: HorizontalBarProps) {
const { removeLed, setLed } = useRgbLed();
const handleUpdate = (led: ChannelPinState) => {
setLed(index, led);
}
const handleRemove = () => {
removeLed(index);
} }
function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
const [red, setRed] = useState<PinState>({ const [red, setRed] = useState<PinState>({
pin: pinState.red.pin.toString(), pin: rgbLed.red.pin.toString(),
state: pinState.red.state state: rgbLed.red.state
}); });
const [green, setGreen] = useState<PinState>({ const [green, setGreen] = useState<PinState>({
pin: pinState.green.pin.toString(), pin: rgbLed.green.pin.toString(),
state: pinState.green.state state: rgbLed.green.state
}); });
const [blue, setBlue] = useState<PinState>({ const [blue, setBlue] = useState<PinState>({
pin: pinState.blue.pin.toString(), pin: rgbLed.blue.pin.toString(),
state: pinState.blue.state state: rgbLed.blue.state
}); });
useEffect(() => { useEffect(() => {
if (onUpdate) onUpdate({red, green, blue}); handleUpdate({red, green, blue});
}, [red, green, blue]) }, [red, green, blue]);
useEffect(() => {
PatchRgbLed(rgbLed);
}, [
rgbLed.red.state,
rgbLed.green.state,
rgbLed.blue.state
]);
return ( return (
<div className="flex flex-col col-span-3 gap-2 animate-fade-in font-roboto-mono"> <div className="flex flex-col col-span-3 gap-2 animate-fade-in font-roboto-mono">
<button className="ms-auto bg-finn hover:bg-secondary transition border border-border rounded-lg px-5" onClick={onDelete}> <button className="ms-auto bg-finn hover:bg-secondary transition border border-border rounded-lg px-5" onClick={handleRemove}>
<i className="bi bi-dash text-xl"></i> <i className="bi bi-dash text-xl"></i>
</button> </button>
<div className="bg-secondary animate-size-in rounded-lg border border-border p-4 flex gap-3"> <div className="bg-secondary animate-size-in rounded-lg border border-border p-4 flex gap-3">
@ -122,7 +140,7 @@ function HorizontalBarPlus ({ onClick }: { onClick?: MouseEventHandler<HTMLButto
} }
function ControlRgbLed ({ refto }: { refto?: Ref<HTMLDivElement> }) { function ControlRgbLed ({ refto }: { refto?: Ref<HTMLDivElement> }) {
const { addLed, rgbLed, removeLed, setLed } = useRgbLed(); const { addLed, rgbLed } = useRgbLed();
const handleAdd = (): void => { const handleAdd = (): void => {
addLed({ addLed({
@ -155,13 +173,8 @@ function ControlRgbLed ({ refto }: { refto?: Ref<HTMLDivElement> }) {
{rgbLed.map((led, i) => ( {rgbLed.map((led, i) => (
<HorizontalBar <HorizontalBar
key={i} key={i}
pinState={led} index={i}
onUpdate={(newLed) => { rgbLed={led}
setLed(i, newLed);
}}
onDelete={() => {
removeLed(i);
}}
/> />
))} ))}
{rgbLed.length < 5 && <HorizontalBarPlus {rgbLed.length < 5 && <HorizontalBarPlus

View File

@ -4,6 +4,7 @@ import { DynamicPinState } from "../../types/board";
import EvoInput from "../forms/EvoInput"; import EvoInput from "../forms/EvoInput";
import Button from "../forms/Button"; import Button from "../forms/Button";
import { Slider } from "../forms/Slider"; import { Slider } from "../forms/Slider";
import { PatchServo } from "../../controllers/BoardController";
function Bar ({ index, servo }: { index: number, servo: DynamicPinState }) { function Bar ({ index, servo }: { index: number, servo: DynamicPinState }) {
@ -17,6 +18,10 @@ function Bar ({ index, servo }: { index: number, servo: DynamicPinState }) {
setDegree(servo.pin, deg); setDegree(servo.pin, deg);
}, [percentage]); }, [percentage]);
useEffect(() => {
if (isListen) PatchServo(servo.pin, servo.state);
}, [isListen, servo.state])
const toggleListen = () => { const toggleListen = () => {
setListen(!isListen); setListen(!isListen);
} }

View File

@ -3,7 +3,7 @@ interface CircleResistanceProps {
width?: number; width?: number;
height?: number; height?: number;
blur?: number; blur?: number;
resistance?: number; intensity?: number;
} }
export default function CircleResistance({ export default function CircleResistance({
@ -11,7 +11,7 @@ export default function CircleResistance({
width, width,
height, height,
blur, blur,
resistance, intensity,
}: CircleResistanceProps) { }: CircleResistanceProps) {
return ( return (
<div <div
@ -24,14 +24,15 @@ export default function CircleResistance({
}} }}
> >
<div <div
className="transition-opacity duration-75"
style={{ style={{
backgroundColor: "white", backgroundColor: "white",
borderRadius: 999, borderRadius: 999,
width: width || 122, width: width || 122,
height: height || 122, height: height || 122,
filter: `blur(${blur || 12}px)`, filter: `blur(${blur || 12}px)`,
boxShadow: '0 0 52 22 #FF2929', boxShadow: '0 0 52px 22px #FF2929',
opacity: resistance ? resistance/1023*100 : 0 opacity: intensity+"%"
}} }}
></div> ></div>
</div> </div>

View File

@ -43,12 +43,12 @@ const INIT_VALUES: ControllerContextProps = {
piezo: [ piezo: [
{ {
pin: 6, pin: 6,
state: 127 state: 262
} }
], ],
motoServo: [ motoServo: [
{ {
pin: "A0", pin: "9",
state: 0 state: 0
} }
], ],

View File

@ -0,0 +1,51 @@
import axios from "axios";
import { ChannelPinState } from "../types/board";
import { io } from "../socket/socket.io";
const url = "http://localhost:3000/api-arduino";
export async function PatchLed (pin: number, state: boolean) {
const act = state == true ? 'on' : 'off';
const res = await axios.patch(`${url}/led/${pin}/${act}`);
const data = res.data;
console.log("LED Response: ", data);
}
export async function PatchRgbLed (state: ChannelPinState) {
const { red, green, blue } = state;
const body = {
r: {
pin: red.pin,
value: red.state
},
g: {
pin: green.pin,
value: green.state
},
b: {
pin: blue.pin,
value: blue.state
}
}
const res = await axios.patch(`${url}/rgb-led`, body, {
headers: {
'Content-Type': 'application/json'
}
});
const data = res.data;
console.log("RGB LED Response: ", data);
}
export async function PatchPiezo (pin: number, freq: number) {
const res = await axios.patch(`${url}/piezo/${pin}/${freq}`);
const data = res.data;
console.log("Piezo Response: ", data);
}
export async function PatchServo(pin: string | number, value: number) {
io.emit("servo", pin, value);
}

View File

@ -86,7 +86,7 @@
.btn { .btn {
@apply px-5 py-4 transition font-roboto-mono rounded-lg @apply px-5 py-4 transition font-roboto-mono rounded-lg transition-[transform] duration-75 scale-100 active:scale-90;
} }

View File

@ -15,8 +15,7 @@ export function useLed () {
} }
const addLed = (pin: number | string, state?: boolean) => { const addLed = (pin: number | string, state?: boolean) => {
const newLed = [...leds, { pin, state: state || false }]; setLeds!(led => [...led, { pin, state: state || false }]);
setLeds!(newLed);
} }
const removeLed = (index: number) => { const removeLed = (index: number) => {
@ -100,12 +99,11 @@ export function usePiezo () {
setPiezo!(newPiezo); setPiezo!(newPiezo);
} }
const setFrequency = (pin: number | string, state: number) => { const setFrequency = (index: number, state: number) => {
const newPiezo = piezo.map(piezo => { setPiezo!(piezos => piezos.map((piezo, i) => {
if (piezo.pin == pin) return { pin, state }; if (i == index) return { pin: piezo.pin, state: state };
return piezo; return piezo;
}) }));
setPiezo!(newPiezo);
} }
const setPiezoPin = (index: number | string, newPin: number | string) => { const setPiezoPin = (index: number | string, newPin: number | string) => {
@ -175,6 +173,14 @@ export function usePhotoresistor () {
setPhotoresistor!(newPesistor); setPhotoresistor!(newPesistor);
} }
const setResistance = (pin: number | string, state: number) => {
const resistor = photoresistor.map(resist => {
if (resist.pin == pin) return { pin: resist.pin, state };
return resist;
})
setPhotoresistor!(resistor);
}
const setResistorPin = (index: number, newPin: number | string) => { const setResistorPin = (index: number, newPin: number | string) => {
const newPesistor = photoresistor.map((resist, i) => { const newPesistor = photoresistor.map((resist, i) => {
if (i == index) return { pin: newPin, state: resist.state }; if (i == index) return { pin: newPin, state: resist.state };
@ -183,5 +189,5 @@ export function usePhotoresistor () {
setPhotoresistor!(newPesistor); setPhotoresistor!(newPesistor);
} }
return { photoresistor, getResistor, addResistor, removeResistor, setResistorPin }; return { photoresistor, getResistor, addResistor, removeResistor, setResistance, setResistorPin };
} }

3
src/socket/socket.io.ts Normal file
View File

@ -0,0 +1,3 @@
import { connect } from "socket.io-client";
export const io = connect("http://localhost:3000");