fixed grain colour, added nfc page
This commit is contained in:
parent
2ab02a0349
commit
dab1d04a81
7 changed files with 272 additions and 1 deletions
|
|
@ -75,7 +75,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
strokeOpacity: 0.85
|
strokeOpacity: 0.85
|
||||||
},
|
},
|
||||||
grainInventory: {
|
grainInventory: {
|
||||||
fill: theme.palette.secondary.main,
|
fill: GRAIN_COLOUR,
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
},
|
},
|
||||||
cableLine: {
|
cableLine: {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ const Fields = lazy(()=> import("pages/Fields"));
|
||||||
const Marketplace = lazy(() => import("userFeatures/UserFeatures"))
|
const Marketplace = lazy(() => import("userFeatures/UserFeatures"))
|
||||||
const Logs = lazy(() => import("pages/Logs"))
|
const Logs = lazy(() => import("pages/Logs"))
|
||||||
const Firmware = lazy(() => import("pages/Firmware"));
|
const Firmware = lazy(() => import("pages/Firmware"));
|
||||||
|
const Nfc = lazy(() => import("pages/Nfc"));
|
||||||
|
|
||||||
export const appendToUrl = (appendage: number | string) => {
|
export const appendToUrl = (appendage: number | string) => {
|
||||||
const basePath = location.pathname.replace(/\/$/, "");
|
const basePath = location.pathname.replace(/\/$/, "");
|
||||||
|
|
@ -315,6 +316,7 @@ export default function Router() {
|
||||||
{user.hasFeature("admin") && (
|
{user.hasFeature("admin") && (
|
||||||
<Route path="firmware" element={<Firmware />} />
|
<Route path="firmware" element={<Firmware />} />
|
||||||
)}
|
)}
|
||||||
|
<Route path="nfc" element={<Nfc />} />
|
||||||
|
|
||||||
{/* Map pages */}
|
{/* Map pages */}
|
||||||
<Route path="visualFarm" element={<FieldMap />} />
|
<Route path="visualFarm" element={<FieldMap />} />
|
||||||
|
|
|
||||||
|
|
@ -396,6 +396,20 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
|
{user.hasFeature("admin") && window.NDEFReader &&
|
||||||
|
<Tooltip title="Logs" placement="right">
|
||||||
|
<ListItemButton
|
||||||
|
id="tour-logs"
|
||||||
|
onClick={() => goTo("/logs")}
|
||||||
|
classes={getClasses("/logs")}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<DataDuckIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
{open && <ListItemText primary="Logs" />}
|
||||||
|
</ListItemButton>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
<Tooltip title="Marketplace" placement="right">
|
<Tooltip title="Marketplace" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-marketplace"
|
id="tour-marketplace"
|
||||||
|
|
|
||||||
32
src/nfc/commandHistory.tsx
Normal file
32
src/nfc/commandHistory.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { Box, List, ListItem, ListItemIcon, ListItemText, Typography } from "@mui/material";
|
||||||
|
import { NfcCommand } from "pages/Nfc";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
commands: NfcCommand[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CommandHistory(props: Props) {
|
||||||
|
const { commands } = props;
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Typography style={{ fontSize: 20, fontWeight: 650 }}>Session Command History</Typography>
|
||||||
|
|
||||||
|
<Box height={250} overflow="scroll" border={"2px solid white"} borderRadius={10}>
|
||||||
|
<List>
|
||||||
|
{commands.map((command, i) => (
|
||||||
|
<ListItem key={i}>
|
||||||
|
<ListItemIcon style={{ marginRight: 10 }}>
|
||||||
|
<Typography style={{ fontWeight: 650 }}>
|
||||||
|
{command.command + " : " + command.type}
|
||||||
|
</Typography>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>
|
||||||
|
<Typography>{command.data}</Typography>
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
109
src/nfc/nfcCommands.tsx
Normal file
109
src/nfc/nfcCommands.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { Box, Button, Grid, TextField } from "@mui/material";
|
||||||
|
import { NfcCommand } from "pages/Nfc";
|
||||||
|
import { useSnackbar } from "providers";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onCommandRun: (command: NfcCommand[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NfcCommands(props: Props) {
|
||||||
|
const { onCommandRun } = props;
|
||||||
|
const [textCommand, setTextCommand] = useState("");
|
||||||
|
const { openSnack } = useSnackbar();
|
||||||
|
const ndef = window.NDEFReader ? new NDEFReader() : undefined;
|
||||||
|
|
||||||
|
const writeCommand = (commandData: string) => {
|
||||||
|
if (ndef) {
|
||||||
|
ndef
|
||||||
|
.write({
|
||||||
|
records: [{ recordType: "text", data: commandData }]
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
openSnack("Comand sent");
|
||||||
|
onCommandRun([{ type: "text", command: "write", data: commandData }]);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
openSnack("Failed to send command");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const readCommand = () => {
|
||||||
|
if (ndef) {
|
||||||
|
ndef.scan().then(() => {
|
||||||
|
//the scan started looking for the tag
|
||||||
|
openSnack("Starting Scan");
|
||||||
|
|
||||||
|
//the tag is found and can be read
|
||||||
|
ndef.onreading = event => {
|
||||||
|
let records: NfcCommand[] = [];
|
||||||
|
openSnack("Scan Complete");
|
||||||
|
//goes through the records found on the tag
|
||||||
|
event.message.records.forEach(record => {
|
||||||
|
//if the records type is set as tex
|
||||||
|
if (record.recordType === "text") {
|
||||||
|
//create a decoder using the records encoding method
|
||||||
|
let decoder = new TextDecoder(record.encoding);
|
||||||
|
//push the record type and the decoded data into the records to show in the command history
|
||||||
|
records.push({
|
||||||
|
type: record.recordType,
|
||||||
|
command: "read",
|
||||||
|
data: decoder.decode(record.data) //decode the record into a string to display
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onCommandRun(records);
|
||||||
|
};
|
||||||
|
|
||||||
|
ndef.onreadingerror = event => {
|
||||||
|
openSnack("Failed to Complete Scan");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<TextField
|
||||||
|
label="NFC Command entry"
|
||||||
|
fullWidth
|
||||||
|
value={textCommand}
|
||||||
|
onChange={e => {
|
||||||
|
setTextCommand(e.target.value);
|
||||||
|
}}
|
||||||
|
style={{ paddingTop: 5, paddingBottom: 5 }}
|
||||||
|
/>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
if (ndef) {
|
||||||
|
writeCommand(textCommand);
|
||||||
|
} else {
|
||||||
|
openSnack("Browser does not support web nfc");
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Write to NFC Tag
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
if (ndef) {
|
||||||
|
readCommand();
|
||||||
|
} else {
|
||||||
|
openSnack("Browser does not support web nfc");
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Read NFC Tag
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
src/pages/Nfc.tsx
Normal file
34
src/pages/Nfc.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Box } from "@mui/material";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import CommandHistory from "nfc/commandHistory";
|
||||||
|
import NfcCommands from "nfc/nfcCommands";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import PageContainer from "./PageContainer";
|
||||||
|
|
||||||
|
export interface NfcCommand {
|
||||||
|
type: string;
|
||||||
|
command: "read" | "write";
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Nfc() {
|
||||||
|
const [executedCommands, setExecutedCommands] = useState<NfcCommand[]>([]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<React.Fragment>
|
||||||
|
<Box padding={2}>
|
||||||
|
<CommandHistory commands={executedCommands} />
|
||||||
|
<NfcCommands
|
||||||
|
onCommandRun={commands => {
|
||||||
|
//add to the list of executed commands
|
||||||
|
let c = cloneDeep(executedCommands);
|
||||||
|
c.push(...commands);
|
||||||
|
setExecutedCommands(c);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</React.Fragment>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
80
src/web-nfc.d.ts
vendored
Normal file
80
src/web-nfc.d.ts
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Type definitions for Web NFC
|
||||||
|
// Project: https://github.com/w3c/web-nfc
|
||||||
|
// Definitions by: Takefumi Yoshii <https://github.com/takefumi-yoshii>
|
||||||
|
// TypeScript Version: 3.9
|
||||||
|
|
||||||
|
// This type definitions referenced to WebIDL.
|
||||||
|
// https://w3c.github.io/web-nfc/#actual-idl-index
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
NDEFMessage: NDEFMessage;
|
||||||
|
}
|
||||||
|
declare class NDEFMessage {
|
||||||
|
constructor(messageInit: NDEFMessageInit);
|
||||||
|
records: ReadonlyArray<NDEFRecord>;
|
||||||
|
}
|
||||||
|
declare interface NDEFMessageInit {
|
||||||
|
records: NDEFRecordInit[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type NDEFRecordDataSource = string | BufferSource | NDEFMessageInit;
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
NDEFRecord: NDEFRecord;
|
||||||
|
}
|
||||||
|
declare class NDEFRecord {
|
||||||
|
constructor(recordInit: NDEFRecordInit);
|
||||||
|
readonly recordType: string;
|
||||||
|
readonly mediaType?: string;
|
||||||
|
readonly id?: string;
|
||||||
|
readonly data?: DataView;
|
||||||
|
readonly encoding?: string;
|
||||||
|
readonly lang?: string;
|
||||||
|
toRecords?: () => NDEFRecord[];
|
||||||
|
}
|
||||||
|
declare interface NDEFRecordInit {
|
||||||
|
recordType: string;
|
||||||
|
mediaType?: string;
|
||||||
|
id?: string;
|
||||||
|
encoding?: string;
|
||||||
|
lang?: string;
|
||||||
|
data?: NDEFRecordDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type NDEFMessageSource = string | BufferSource | NDEFMessageInit;
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
NDEFReader: NDEFReader;
|
||||||
|
}
|
||||||
|
declare class NDEFReader extends EventTarget {
|
||||||
|
constructor();
|
||||||
|
onreading: (this: this, event: NDEFReadingEvent) => any;
|
||||||
|
onreadingerror: (this: this, error: Event) => any;
|
||||||
|
scan: (options?: NDEFScanOptions) => Promise<void>;
|
||||||
|
write: (message: NDEFMessageSource, options?: NDEFWriteOptions) => Promise<void>;
|
||||||
|
makeReadOnly: (options?: NDEFMakeReadOnlyOptions) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
NDEFReadingEvent: NDEFReadingEvent;
|
||||||
|
}
|
||||||
|
declare class NDEFReadingEvent extends Event {
|
||||||
|
constructor(type: string, readingEventInitDict: NDEFReadingEventInit);
|
||||||
|
serialNumber: string;
|
||||||
|
message: NDEFMessage;
|
||||||
|
}
|
||||||
|
interface NDEFReadingEventInit extends EventInit {
|
||||||
|
serialNumber?: string;
|
||||||
|
message: NDEFMessageInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NDEFWriteOptions {
|
||||||
|
overwrite?: boolean;
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
interface NDEFMakeReadOnlyOptions {
|
||||||
|
signal?: AbortSignal;
|
||||||
|
}
|
||||||
|
interface NDEFScanOptions {
|
||||||
|
signal: AbortSignal;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue