Merge branch 'dev'
This commit is contained in:
commit
1bcff410e2
18 changed files with 31956 additions and 1165 deletions
|
@ -22,6 +22,11 @@ module.exports = {
|
|||
quotes: ["error", "double"],
|
||||
"import/no-extraneous-dependencies": ["error", { devDependencies: true }],
|
||||
"no-console": "off",
|
||||
"max-len": ["error", { code: 300 }],
|
||||
"no-shadow": "off",
|
||||
"@typescript-eslint/no-shadow": ["error"],
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
|
|
28642
Dashboard/package-lock.json
generated
Normal file
28642
Dashboard/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -46,7 +46,8 @@
|
|||
"package": "yarn build && electron-builder --publish never",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "cross-env NODE_ENV=development eslint . --cache --ext .js,.jsx,.ts,.tsx",
|
||||
"lint:fix": "cross-env NODE_ENV=development eslint . --cache --fix --ext .js,.jsx,.ts,.tsx"
|
||||
"lint:fix": "cross-env NODE_ENV=development eslint . --cache --fix --ext .js,.jsx,.ts,.tsx",
|
||||
"remotedev": "remotedev --hostname=localhost --port=8000"
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
@ -54,6 +55,7 @@
|
|||
"@types/node": "^15.12.5",
|
||||
"@types/react": "^17.0.11",
|
||||
"@types/react-dom": "^17.0.8",
|
||||
"@types/remote-redux-devtools": "^0.5.5",
|
||||
"@types/styled-components": "^5.1.11",
|
||||
"electron-acrylic-window": "^0.5.5",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
|
@ -63,15 +65,24 @@
|
|||
"fs-extra": "^9.0.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-select": "^4.3.1",
|
||||
"redux": "^4.1.1",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"remote-redux-devtools": "^0.5.16",
|
||||
"screenz": "^1.0.0",
|
||||
"serialport": "^9.2.0",
|
||||
"sqlite3": "^5.0.2",
|
||||
"styled-components": "^5.3.0",
|
||||
"typescript": "^4.3.4"
|
||||
"typesafe-actions": "^5.1.0",
|
||||
"typescript": "^4.3.4",
|
||||
"chalk": "^4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.0",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@types/react-select": "^4.0.17",
|
||||
"@types/serialport": "^8.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.1",
|
||||
"@typescript-eslint/parser": "^4.28.1",
|
||||
|
@ -90,6 +101,7 @@
|
|||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.2.12",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"remotedev-server": "^0.3.1",
|
||||
"style-loader": "^1.2.1",
|
||||
"ts-loader": "^9.2.3",
|
||||
"wait-on": "^6.0.0",
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { createGlobalStyle } from "styled-components";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "typesafe-actions";
|
||||
import Select from "react-select";
|
||||
import SerialPort from "serialport";
|
||||
import Knob from "./Components/Knob";
|
||||
import { port, parser } from "./SerialConnection";
|
||||
import { connect, disconnect } from "./redux/actions/asyncSerialConnectionActions";
|
||||
import { setSerialPort } from "./redux/actions/serialConnectionActions";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
html {
|
||||
|
@ -16,33 +20,61 @@ const GlobalStyle = createGlobalStyle`
|
|||
}
|
||||
`;
|
||||
|
||||
const options: [{value: string, label:string}] = [{ value: "placeholder", label: "Select Port" }];
|
||||
|
||||
const fetchPorts = async () => {
|
||||
const data = await SerialPort.list();
|
||||
options.shift();
|
||||
data.forEach((comPort) => { options.push({ value: comPort.path, label: comPort.path }); });
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const [status, setStatus] = useState(0);
|
||||
const dispatch = useDispatch();
|
||||
const serialConnection = useSelector<RootState, RootState["serialConnection"]>((state) => state.serialConnection);
|
||||
const SerialDataListener = (data: string) => {
|
||||
const parsedData = data.split(",");
|
||||
console.log(parsedData);
|
||||
setStatus(parseInt(parsedData[2], 10));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
parser.on("data", SerialDataListener);
|
||||
port.open();
|
||||
return () => {
|
||||
parser.removeListener("data", SerialDataListener);
|
||||
port.close();
|
||||
fetchPorts();
|
||||
|
||||
const [portSelectionValue, setPortSelectionValue] = useState(options[0]);
|
||||
const handlePortChange = async (selectedOption: any) => {
|
||||
setPortSelectionValue(selectedOption);
|
||||
dispatch(setSerialPort(selectedOption.value));
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (serialConnection.portController !== null) {
|
||||
serialConnection.portController.parser.on("data", SerialDataListener);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (serialConnection.portController !== null) {
|
||||
serialConnection.portController.parser.removeListener("data", SerialDataListener);
|
||||
}
|
||||
};
|
||||
}, [serialConnection]);
|
||||
|
||||
const sendIncreaseHandler = () => {
|
||||
if (serialConnection.portController !== null && serialConnection.portController.port !== null) {
|
||||
setStatus(status + 1);
|
||||
port.write("2i");
|
||||
serialConnection.portController.port.write("2i");
|
||||
}
|
||||
};
|
||||
const sendDecreaseHandler = () => {
|
||||
if (serialConnection.portController !== null && serialConnection.portController.port !== null) {
|
||||
setStatus(status - 1);
|
||||
port.write("2d");
|
||||
serialConnection.portController.port.write("2d");
|
||||
}
|
||||
};
|
||||
const sendToggleHandler = () => {
|
||||
port.write("2t");
|
||||
if (serialConnection.portController !== null && serialConnection.portController.port !== null) {
|
||||
setStatus(status - 1);
|
||||
serialConnection.portController.port.write("2t");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -57,30 +89,24 @@ const App = () => {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
port.open();
|
||||
dispatch(connect());
|
||||
}}
|
||||
>
|
||||
open
|
||||
connect
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
port.close();
|
||||
dispatch(disconnect());
|
||||
}}
|
||||
>
|
||||
close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const list = SerialPort.list();
|
||||
list.then((arg) => {
|
||||
console.log(arg);
|
||||
});
|
||||
}}
|
||||
>
|
||||
list
|
||||
disconnect
|
||||
</button>
|
||||
<Select
|
||||
value={portSelectionValue}
|
||||
onChange={handlePortChange}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,10 +1,51 @@
|
|||
import SerialPort, { parsers } from "serialport";
|
||||
|
||||
const port = new SerialPort("COM5", {
|
||||
class PortController {
|
||||
path: null | string;
|
||||
|
||||
port: null | SerialPort;
|
||||
|
||||
parser: any;
|
||||
|
||||
constructor() {
|
||||
this.path = null;
|
||||
this.port = null;
|
||||
}
|
||||
|
||||
get isOpen() {
|
||||
if (!this.port) {
|
||||
return false;
|
||||
}
|
||||
return this.port.isOpen;
|
||||
}
|
||||
|
||||
create(path: string) {
|
||||
this.path = path;
|
||||
this.port = new SerialPort(path, {
|
||||
baudRate: 9600,
|
||||
autoOpen: false,
|
||||
});
|
||||
|
||||
const parser = port.pipe(new parsers.Readline({ delimiter: "\r\n" }));
|
||||
this.parser = this.port.pipe(new parsers.Readline({ delimiter: "\r\n" }));
|
||||
}
|
||||
|
||||
export { port, parser };
|
||||
open(callback: (error:Error | null | undefined)=>void) {
|
||||
if (this.isOpen) {
|
||||
throw new Error("Port already open");
|
||||
}
|
||||
|
||||
if (this.port === null) {
|
||||
throw new Error("Port must be created first");
|
||||
}
|
||||
|
||||
this.port.open((error) => callback(error));
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.port) {
|
||||
this.port.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PortController;
|
||||
|
|
|
@ -7,6 +7,7 @@ const isDev = require("electron-is-dev");
|
|||
const screenz = require("screenz");
|
||||
const els = require("electron-localshortcut");
|
||||
const devTools = require("electron-devtools-installer");
|
||||
const chalk = require("chalk");
|
||||
|
||||
let tray = null;
|
||||
let mainWindow = null;
|
||||
|
@ -60,9 +61,13 @@ function createWindow() {
|
|||
: `file://${path.join(__dirname, "../build/index.html")}`,
|
||||
);
|
||||
|
||||
// Open the DevTools.
|
||||
if (isDev) {
|
||||
win.webContents.openDevTools({ mode: "detach" });
|
||||
|
||||
const remotedev = require("remotedev-server");
|
||||
remotedev({ hostname: "localhost", port: 8000 }).then(() => {
|
||||
console.log(chalk.blue("RemoteDev server running at http://localhost:8000/"));
|
||||
});
|
||||
}
|
||||
|
||||
// Register shortcut to open devtools
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import React from "react";
|
||||
import { render } from "react-dom";
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./redux/store";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
render(<App />, document.getElementById("root"));
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById("root"),
|
||||
);
|
||||
|
|
12
Dashboard/src/interfaces/ISerialConnectionState.ts
Normal file
12
Dashboard/src/interfaces/ISerialConnectionState.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import PortController from "../SerialConnection";
|
||||
|
||||
export default interface ISerialConnectionState {
|
||||
port: string | null;
|
||||
portController: PortController | null;
|
||||
status: {
|
||||
connecting: boolean;
|
||||
connected: boolean;
|
||||
error: string | null;
|
||||
};
|
||||
// eslint-disable-next-line semi
|
||||
}
|
36
Dashboard/src/redux/actions/asyncSerialConnectionActions.ts
Normal file
36
Dashboard/src/redux/actions/asyncSerialConnectionActions.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { ThunkResult } from "typesafe-actions";
|
||||
import {
|
||||
connectionStart, connectionSuccess, connectionFailure, setPortController, connectionEnd,
|
||||
} from "./serialConnectionActions";
|
||||
import PortController from "../../SerialConnection";
|
||||
|
||||
const connect = (): ThunkResult<void> => async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
dispatch(connectionStart());
|
||||
|
||||
if (state.serialConnection.port === null) {
|
||||
dispatch(connectionFailure(new Error("No Serial Port set")));
|
||||
return;
|
||||
}
|
||||
|
||||
const controller = new PortController();
|
||||
controller.create(state.serialConnection.port);
|
||||
|
||||
dispatch(setPortController(controller));
|
||||
|
||||
controller.open((error) => {
|
||||
if (error === null || error === undefined) {
|
||||
dispatch(connectionSuccess());
|
||||
} else {
|
||||
dispatch(connectionFailure(error));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const disconnect = (): ThunkResult<void> => async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
state.serialConnection.portController?.close();
|
||||
dispatch(connectionEnd());
|
||||
};
|
||||
|
||||
export { connect, disconnect };
|
23
Dashboard/src/redux/actions/serialConnectionActions.ts
Normal file
23
Dashboard/src/redux/actions/serialConnectionActions.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { action } from "typesafe-actions";
|
||||
import PortController from "../../SerialConnection";
|
||||
|
||||
export enum SerialConnectionActionTypes {
|
||||
SET_SERIAL_PORT = "SET_SERIAL_PORT",
|
||||
CONNECTION_START = "CONNECTION_START",
|
||||
CONNECTION_SUCCESS = "CONNECTION_SUCCESS",
|
||||
CONNECTION_FAILURE = "CONNECTION_FAILURE",
|
||||
CONNECTION_END = "CONNECTION_END",
|
||||
SET_PORT_CONTROLLER = "SET_PORT_CONTROLLER"
|
||||
}
|
||||
|
||||
export const setSerialPort = (port: string) => action(SerialConnectionActionTypes.SET_SERIAL_PORT, port);
|
||||
|
||||
export const connectionStart = () => action(SerialConnectionActionTypes.CONNECTION_START);
|
||||
|
||||
export const connectionSuccess = () => action(SerialConnectionActionTypes.CONNECTION_SUCCESS);
|
||||
|
||||
export const connectionFailure = (error: Error) => action(SerialConnectionActionTypes.CONNECTION_FAILURE, error);
|
||||
|
||||
export const connectionEnd = () => action(SerialConnectionActionTypes.CONNECTION_END);
|
||||
|
||||
export const setPortController = (controller: PortController) => action(SerialConnectionActionTypes.SET_PORT_CONTROLLER, controller);
|
58
Dashboard/src/redux/reducers/serialConnectionReducer.ts
Normal file
58
Dashboard/src/redux/reducers/serialConnectionReducer.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { createReducer } from "typesafe-actions";
|
||||
import ISerialConnectionState from "../../interfaces/ISerialConnectionState";
|
||||
import { SerialConnectionActionTypes } from "../actions/serialConnectionActions";
|
||||
|
||||
const initialState: ISerialConnectionState = {
|
||||
port: null,
|
||||
portController: null,
|
||||
status: {
|
||||
connecting: false,
|
||||
connected: false,
|
||||
error: null,
|
||||
},
|
||||
};
|
||||
|
||||
const SerialConnectionReducer = createReducer(initialState)
|
||||
.handleType(SerialConnectionActionTypes.SET_SERIAL_PORT, (state, action) => ({
|
||||
...state,
|
||||
port: action.payload,
|
||||
}))
|
||||
.handleType(SerialConnectionActionTypes.CONNECTION_START, (state) => ({
|
||||
...state,
|
||||
status: {
|
||||
connecting: true,
|
||||
connected: false,
|
||||
error: null,
|
||||
},
|
||||
}))
|
||||
.handleType(SerialConnectionActionTypes.CONNECTION_FAILURE, (state, action) => ({
|
||||
...state,
|
||||
status: {
|
||||
connecting: false,
|
||||
connected: false,
|
||||
error: action.payload.message,
|
||||
},
|
||||
}))
|
||||
.handleType(SerialConnectionActionTypes.CONNECTION_SUCCESS, (state) => ({
|
||||
...state,
|
||||
status: {
|
||||
connecting: false,
|
||||
connected: true,
|
||||
error: null,
|
||||
},
|
||||
}))
|
||||
.handleType(SerialConnectionActionTypes.CONNECTION_END, (state) => ({
|
||||
...state,
|
||||
portController: null,
|
||||
status: {
|
||||
connecting: false,
|
||||
connected: false,
|
||||
error: null,
|
||||
},
|
||||
}))
|
||||
.handleType(SerialConnectionActionTypes.SET_PORT_CONTROLLER, (state, action) => ({
|
||||
...state,
|
||||
portController: action.payload,
|
||||
}));
|
||||
|
||||
export default SerialConnectionReducer;
|
19
Dashboard/src/redux/store/index.ts
Normal file
19
Dashboard/src/redux/store/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import thunk from "redux-thunk";
|
||||
import { createStore, applyMiddleware } from "redux";
|
||||
import { RootAction, RootState } from "typesafe-actions";
|
||||
import composeEnhancers from "./utils";
|
||||
import rootReducer from "./root-reducer";
|
||||
|
||||
const middlewares = [thunk];
|
||||
|
||||
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
|
||||
|
||||
const initialState = {};
|
||||
|
||||
const store = createStore<RootState, RootAction, any, any>(
|
||||
rootReducer,
|
||||
initialState,
|
||||
enhancer,
|
||||
);
|
||||
|
||||
export default store;
|
7
Dashboard/src/redux/store/root-action.ts
Normal file
7
Dashboard/src/redux/store/root-action.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import * as serialConnectionActions from "../actions/serialConnectionActions";
|
||||
|
||||
const rootAction = {
|
||||
serialConnection: serialConnectionActions,
|
||||
};
|
||||
|
||||
export default rootAction;
|
8
Dashboard/src/redux/store/root-reducer.ts
Normal file
8
Dashboard/src/redux/store/root-reducer.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { combineReducers } from "redux";
|
||||
import SerialConnectionReducer from "../reducers/serialConnectionReducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
serialConnection: SerialConnectionReducer,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
19
Dashboard/src/redux/store/types.d.ts
vendored
Normal file
19
Dashboard/src/redux/store/types.d.ts
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { StateType, ActionType } from "typesafe-actions";
|
||||
import { ThunkAction } from "redux-thunk";
|
||||
import rootReducer from "./root-reducer";
|
||||
import rootAction from "./root-action";
|
||||
import store from "./index";
|
||||
|
||||
declare module "typesafe-actions" {
|
||||
export type Store = StateType<typeof store>;
|
||||
|
||||
export type RootState = StateType<typeof rootReducer>;
|
||||
|
||||
export type RootAction = ActionType<typeof rootAction>;
|
||||
|
||||
export type ThunkResult<R> = ThunkAction<R, RootState, unknown, RootAction>;
|
||||
|
||||
interface Types {
|
||||
RootAction: RootAction;
|
||||
}
|
||||
}
|
12
Dashboard/src/redux/store/utils.ts
Normal file
12
Dashboard/src/redux/store/utils.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { composeWithDevTools } from "remote-redux-devtools";
|
||||
|
||||
// Access Redux devtools via http://localhost:8000
|
||||
const composeEnhancers = composeWithDevTools({
|
||||
name: "Light-Control",
|
||||
realtime: true,
|
||||
secure: false,
|
||||
hostname: "localhost",
|
||||
port: 8000,
|
||||
});
|
||||
|
||||
export default composeEnhancers;
|
4108
Dashboard/yarn.lock
4108
Dashboard/yarn.lock
File diff suppressed because it is too large
Load diff
|
@ -7,3 +7,12 @@
|
|||
</a>
|
||||
|
||||
Uses: https://github.com/GHOSCHT/simple-electron-react-boilerplate
|
||||
|
||||
Dashboard: node-gyp fails on sqlite3 build -> set default pyhton version to python 2
|
||||
```
|
||||
node-gyp --python /path/to/python2.7/python.exe
|
||||
```
|
||||
or
|
||||
```
|
||||
npm config set python /path/to/executable/python2.7
|
||||
```
|
Reference in a new issue