Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/gate-controller/components/AddRelayDialog.tsx
1072 views
1
'use client';
2
3
import { useState, useEffect } from "react";
4
import { invoke } from "@tauri-apps/api/core";
5
import { Button } from "@/components/ui/button";
6
import {
7
Dialog,
8
DialogContent,
9
DialogDescription,
10
DialogHeader,
11
DialogTitle,
12
} from "@/components/ui/dialog";
13
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
14
import {
15
Select,
16
SelectContent,
17
SelectItem,
18
SelectTrigger,
19
SelectValue,
20
} from "@/components/ui/select";
21
import { Input } from "@/components/ui/input";
22
import { toast } from "sonner";
23
24
interface UsbRelayInfo {
25
serial_number: string;
26
relay_type: string;
27
}
28
29
interface AddRelayDialogProps {
30
open: boolean;
31
onOpenChange: (open: boolean) => void;
32
onRelayAdded: () => void;
33
}
34
35
const getChannelCount = (relayType: string | undefined): number => {
36
if (!relayType) return 0;
37
const digitMatch = relayType.match(/(\d+)Channel/);
38
if (digitMatch) return parseInt(digitMatch[1], 10);
39
const wordMap: { [key: string]: number } = {
40
One: 1,
41
Two: 2,
42
Four: 4,
43
Eight: 8,
44
};
45
for (const word in wordMap) {
46
if (relayType.startsWith(word)) return wordMap[word];
47
}
48
return 0;
49
};
50
51
export function AddRelayDialog({
52
open,
53
onOpenChange,
54
onRelayAdded,
55
}: AddRelayDialogProps) {
56
const [availablePorts, setAvailablePorts] = useState<string[]>([]);
57
const [selectedPort, setSelectedPort] = useState<string>("");
58
59
const [availableUsbRelays, setAvailableUsbRelays] = useState<UsbRelayInfo[]>(
60
[],
61
);
62
const [selectedUsbRelay, setSelectedUsbRelay] = useState<UsbRelayInfo | null>(
63
null,
64
);
65
66
const [ch340Channels, setCh340Channels] = useState(1);
67
const [cp210xChannels, setCp210xChannels] = useState(1);
68
69
const refreshSerialPorts = async () => {
70
try {
71
const ports = await invoke<string[]>("list_serial_ports");
72
setAvailablePorts(ports);
73
if (ports.length > 0) setSelectedPort(ports[0]);
74
} catch (error) {
75
toast.error("Failed to list serial ports", {
76
description: String(error),
77
});
78
}
79
};
80
81
const refreshUsbRelays = async () => {
82
try {
83
const relays = await invoke<UsbRelayInfo[]>("list_hw348_relays");
84
setAvailableUsbRelays(relays);
85
if (relays.length > 0) setSelectedUsbRelay(relays[0]);
86
} catch (error) {
87
toast.error("Failed to list HW-348 relays", { description: String(error) });
88
}
89
};
90
91
useEffect(() => {
92
if (open) {
93
refreshSerialPorts();
94
refreshUsbRelays();
95
}
96
}, [open]);
97
98
const handleAddCh340 = async () => {
99
if (!selectedPort) {
100
toast.warning("Please select a serial port.");
101
return;
102
}
103
if (ch340Channels <= 0) {
104
toast.warning("Number of channels must be greater than 0.");
105
return;
106
}
107
try {
108
await invoke("add_ch340_relay", { port: selectedPort, channels: ch340Channels });
109
toast.success("CH340 Relay Added", {
110
description: `Port ${selectedPort} has been configured with ${ch340Channels} channels.`,
111
});
112
onRelayAdded();
113
onOpenChange(false);
114
} catch (error) {
115
toast.error("Failed to add CH340 relay", { description: String(error) });
116
}
117
};
118
119
const handleAddHw348 = async () => {
120
if (!selectedUsbRelay) {
121
toast.warning("Please select a USB relay.");
122
return;
123
}
124
try {
125
const channels = getChannelCount(selectedUsbRelay.relay_type);
126
await invoke("add_hw348_relay", {
127
serialNumber: selectedUsbRelay.serial_number,
128
channels,
129
});
130
toast.success("HW-348 Relay Added", {
131
description: `Relay ${selectedUsbRelay.serial_number} has been configured.`,
132
});
133
onRelayAdded();
134
onOpenChange(false);
135
} catch (error) {
136
toast.error("Failed to add HW-348 relay", { description: String(error) });
137
}
138
};
139
140
const handleAddCp210x = async () => {
141
if (!selectedPort) {
142
toast.warning("Please select a serial port.");
143
return;
144
}
145
if (cp210xChannels <= 0) {
146
toast.warning("Number of channels must be greater than 0.");
147
return;
148
}
149
try {
150
await invoke("add_cp210x_relay", { port: selectedPort, channels: cp210xChannels });
151
toast.success("CP210x Relay Added", {
152
description: `Port ${selectedPort} has been configured with ${cp210xChannels} channels.`,
153
});
154
onRelayAdded();
155
onOpenChange(false);
156
} catch (error) {
157
toast.error("Failed to add CP210x relay", { description: String(error) });
158
}
159
};
160
161
return (
162
<Dialog open={open} onOpenChange={onOpenChange}>
163
<DialogContent className="sm:max-w-[425px]">
164
<DialogHeader>
165
<DialogTitle>Add a New Relay</DialogTitle>
166
<DialogDescription>
167
Choose the chip of your USB relay you want to configure.
168
</DialogDescription>
169
</DialogHeader>
170
<Tabs defaultValue="ch340" className="w-full">
171
<TabsList className="grid w-full grid-cols-3">
172
<TabsTrigger value="ch340">CH340</TabsTrigger>
173
<TabsTrigger value="hw348">HW-348</TabsTrigger>
174
<TabsTrigger value="cp210x">CP210x</TabsTrigger>
175
</TabsList>
176
<TabsContent value="ch340">
177
<div className="space-y-4 py-4">
178
<div className="flex items-center gap-4">
179
<Select value={selectedPort} onValueChange={setSelectedPort}>
180
<SelectTrigger className="w-full">
181
<SelectValue placeholder="Select a serial port..." />
182
</SelectTrigger>
183
<SelectContent>
184
{availablePorts.map((port) => (
185
<SelectItem key={port} value={port}>
186
{port}
187
</SelectItem>
188
))}
189
</SelectContent>
190
</Select>
191
<Button variant="outline" onClick={refreshSerialPorts}>
192
Refresh
193
</Button>
194
</div>
195
<div className="flex items-center gap-4">
196
<label htmlFor="channels-ch340" className="text-sm font-medium">Channels</label>
197
<Input
198
id="channels-ch340"
199
type="number"
200
value={ch340Channels}
201
onChange={(e) => setCh340Channels(parseInt(e.target.value, 10) || 1)}
202
className="w-full"
203
min={1}
204
/>
205
</div>
206
<Button
207
className="w-full"
208
onClick={handleAddCh340}
209
disabled={!selectedPort}
210
>
211
Add Relay
212
</Button>
213
</div>
214
</TabsContent>
215
<TabsContent value="hw348">
216
<div className="space-y-4 py-4">
217
<div className="flex items-center gap-4">
218
<Select
219
value={selectedUsbRelay?.serial_number || ""}
220
onValueChange={(sn) =>
221
setSelectedUsbRelay(
222
availableUsbRelays.find((r) => r.serial_number === sn) ||
223
null,
224
)
225
}
226
>
227
<SelectTrigger className="w-full">
228
<SelectValue placeholder="Select a USB relay..." />
229
</SelectTrigger>
230
<SelectContent>
231
{availableUsbRelays.map((r) => (
232
<SelectItem key={r.serial_number} value={r.serial_number}>
233
{r.serial_number} ({r.relay_type})
234
</SelectItem>
235
))}
236
</SelectContent>
237
</Select>
238
<Button variant="outline" onClick={refreshUsbRelays}>
239
Refresh
240
</Button>
241
</div>
242
<Button
243
className="w-full"
244
onClick={handleAddHw348}
245
disabled={!selectedUsbRelay}
246
>
247
Add Relay
248
</Button>
249
</div>
250
</TabsContent>
251
<TabsContent value="cp210x">
252
<div className="space-y-4 py-4">
253
<div className="flex items-center gap-4">
254
<Select value={selectedPort} onValueChange={setSelectedPort}>
255
<SelectTrigger className="w-full">
256
<SelectValue placeholder="Select a serial port..." />
257
</SelectTrigger>
258
<SelectContent>
259
{availablePorts.map((port) => (
260
<SelectItem key={port} value={port}>
261
{port}
262
</SelectItem>
263
))}
264
</SelectContent>
265
</Select>
266
<Button variant="outline" onClick={refreshSerialPorts}>
267
Refresh
268
</Button>
269
</div>
270
<div className="flex items-center gap-4">
271
<label htmlFor="channels" className="text-sm font-medium">Channels</label>
272
<Input
273
id="channels"
274
type="number"
275
value={cp210xChannels}
276
onChange={(e) => setCp210xChannels(parseInt(e.target.value, 10) || 1)}
277
className="w-full"
278
min={1}
279
/>
280
</div>
281
<Button
282
className="w-full"
283
onClick={handleAddCp210x}
284
disabled={!selectedPort}
285
>
286
Add Relay
287
</Button>
288
</div>
289
</TabsContent>
290
</Tabs>
291
</DialogContent>
292
</Dialog>
293
);
294
}
295
296