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"
},
"dependencies": {
"axios": "^1.6.7",
"bootstrap-icons": "^1.11.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"socket.io-client": "^4.7.4"
},
"devDependencies": {
"@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 }) {
return (
<div
className="bg-background text-white bg-repeat-y relative"
className="bg-background text-white bg-repeat-y bg-cover relative"
style={{
backgroundImage: `url(${BackroundImg})`
}}

View File

@ -1,11 +1,46 @@
import { ChangeEvent, Ref, useEffect } from "react";
import PinBox from "../forms/PinBox";
import { useLed } from "../../hooks";
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> }) {
const { addLed, leds, removeLed, setLed, setLedPin } = useLed();
const { addLed, leds } = useLed();
const handleAdd = (): void => {
let anopin = 13;
@ -28,23 +63,10 @@ function ControlLED ({ refto }: { refto?: Ref<HTMLDivElement> }) {
refto={refto}
stack={(<>
{leds.map((led, i) => (
<PinBox.Toggle
className="w-36 animate-fade-in"
<LedItem
led={led}
index={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

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 { DynamicPinState } from "../../types/board";
import CircleResistance from "../shapes/CircleResistance";
import TwoRowTab from "../info/TwoRowTab";
import EvoInput from "../forms/EvoInput";
import Button from "../forms/Button";
import { io } from "../../socket/socket.io";
function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }) {
const { setResistorPin, removeResistor } = usePhotoresistor();
const { setResistorPin, setResistance, removeResistor } = usePhotoresistor();
const [isListen, setListen] = useState<boolean>(false);
@ -27,6 +28,26 @@ function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }
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 (
<div className="border border-border bg-secondary col-span-2 rounded-lg p-6 animate-size-fade-in">
<div className="flex justify-items-end">
@ -36,7 +57,7 @@ function Card ({ index, resistor }: { index: number, resistor: DynamicPinState }
</div>
<div className="h-52 flex items-center justify-center">
<CircleResistance
resistance={0}
intensity={intensity}
/>
</div>
<div className="flex flex-col mt-3 gap-3">
@ -98,7 +119,7 @@ function ControlPhotoresistor ({ refto }: { refto?: Ref<HTMLDivElement> }) {
Photoresistor
</h2>
<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 className={`grid grid-cols-8 gap-6`}>
{resistors.map((resistor, i) => (

View File

@ -1,6 +1,7 @@
import PinBox from "../forms/PinBox";
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 { DynamicPinState } from "../../types/board";
import EvoInput from "../forms/EvoInput";
@ -9,31 +10,48 @@ import Button from "../forms/Button";
function PiezoItem ({ piezo, index }: { piezo: DynamicPinState, index: number }) {
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 (
<div className="flex flex-col gap-3">
<PinBox
className="w-36 animate-fade-in"
minusBtn={true}
value={piezo.pin}
onValueChange={(e) => {
const pin = e.target.value;
setPiezoPin(index, pin);
}}
onDelete={() => {
removePiezo(index);
}}
onValueChange={handlePinChange}
onDelete={handleDelete}
/>
<EvoInput
className="w-36 h-11"
name="Frequency"
type="number"
value={piezo.state.toString()}
onChange={(e) => {
const freq: number = Number.parseInt(e.target.value);
if (!Number.isNaN(freq)) setFrequency(piezo.pin, freq);
}}
onChange={handleFreqChange}
/>
<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>
)
}

View File

@ -1,3 +1,4 @@
import { PatchRgbLed } from "../../controllers/BoardController";
import { useRgbLed } from "../../hooks";
import { ChannelPinState, PinState } from "../../types/board";
import EvoInput from "../forms/EvoInput";
@ -5,34 +6,51 @@ import Switch from "../forms/Switch";
import { MouseEventHandler, Ref, useEffect, useState } from "react";
interface HorizontalBarProps {
pinState: ChannelPinState;
onUpdate?: (pin: ChannelPinState) => void;
onDelete?: () => void
rgbLed: ChannelPinState;
index: number;
}
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>({
pin: pinState.red.pin.toString(),
state: pinState.red.state
pin: rgbLed.red.pin.toString(),
state: rgbLed.red.state
});
const [green, setGreen] = useState<PinState>({
pin: pinState.green.pin.toString(),
state: pinState.green.state
pin: rgbLed.green.pin.toString(),
state: rgbLed.green.state
});
const [blue, setBlue] = useState<PinState>({
pin: pinState.blue.pin.toString(),
state: pinState.blue.state
pin: rgbLed.blue.pin.toString(),
state: rgbLed.blue.state
});
useEffect(() => {
if (onUpdate) onUpdate({red, green, blue});
}, [red, green, blue])
handleUpdate({red, green, blue});
}, [red, green, blue]);
useEffect(() => {
PatchRgbLed(rgbLed);
}, [
rgbLed.red.state,
rgbLed.green.state,
rgbLed.blue.state
]);
return (
<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>
</button>
<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> }) {
const { addLed, rgbLed, removeLed, setLed } = useRgbLed();
const { addLed, rgbLed } = useRgbLed();
const handleAdd = (): void => {
addLed({
@ -155,13 +173,8 @@ function ControlRgbLed ({ refto }: { refto?: Ref<HTMLDivElement> }) {
{rgbLed.map((led, i) => (
<HorizontalBar
key={i}
pinState={led}
onUpdate={(newLed) => {
setLed(i, newLed);
}}
onDelete={() => {
removeLed(i);
}}
index={i}
rgbLed={led}
/>
))}
{rgbLed.length < 5 && <HorizontalBarPlus

View File

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

View File

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

View File

@ -43,12 +43,12 @@ const INIT_VALUES: ControllerContextProps = {
piezo: [
{
pin: 6,
state: 127
state: 262
}
],
motoServo: [
{
pin: "A0",
pin: "9",
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 {
@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 newLed = [...leds, { pin, state: state || false }];
setLeds!(newLed);
setLeds!(led => [...led, { pin, state: state || false }]);
}
const removeLed = (index: number) => {
@ -100,12 +99,11 @@ export function usePiezo () {
setPiezo!(newPiezo);
}
const setFrequency = (pin: number | string, state: number) => {
const newPiezo = piezo.map(piezo => {
if (piezo.pin == pin) return { pin, state };
const setFrequency = (index: number, state: number) => {
setPiezo!(piezos => piezos.map((piezo, i) => {
if (i == index) return { pin: piezo.pin, state: state };
return piezo;
})
setPiezo!(newPiezo);
}));
}
const setPiezoPin = (index: number | string, newPin: number | string) => {
@ -175,6 +173,14 @@ export function usePhotoresistor () {
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 newPesistor = photoresistor.map((resist, i) => {
if (i == index) return { pin: newPin, state: resist.state };
@ -183,5 +189,5 @@ export function usePhotoresistor () {
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");