parent
2e1d9d83c8
commit
d39e547623
11 changed files with 3810 additions and 3406 deletions
3
.babelrc
3
.babelrc
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
modules: false
|
||||
modules: false,
|
||||
corejs: 3
|
||||
}],
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-flow"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ types/mqtt.js
|
|||
[options]
|
||||
esproposal.export_star_as=enable
|
||||
module.system.node.resolve_dirname=node_modules
|
||||
module.system.node.resolve_dirname=./src
|
||||
module.system.node.resolve_dirname=src
|
||||
|
||||
[lints]
|
||||
all=warn
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import * as types from "config/types";
|
|||
import { tasmota, esper } from "./utils";
|
||||
|
||||
export const topics: Topics = {
|
||||
...tasmota.topics("8", "ledOlymp"),
|
||||
...esper.topics("afba45", "alarm"),
|
||||
videogames: {
|
||||
state: {
|
||||
name: "/service/openhab/out/pca301_videogames/state",
|
||||
|
|
@ -38,9 +40,7 @@ export const topics: Topics = {
|
|||
type: types.option({ on: "ON", off: "OFF" })
|
||||
},
|
||||
defaultValue: "off"
|
||||
},
|
||||
...tasmota.topics("8", "ledOlymp"),
|
||||
...esper.topics("afba45", "alarm")
|
||||
}
|
||||
};
|
||||
|
||||
export const controls: Controls = {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// @flow
|
||||
import type { ControlUI } from "config/flowtypes";
|
||||
import type { ControlUI, Topics } from "config/flowtypes";
|
||||
import { mdi } from "config/icon";
|
||||
import { hex } from "config/colors";
|
||||
import { hex, type Color } from "config/colors";
|
||||
import * as types from "config/types";
|
||||
|
||||
export const tasmota = {
|
||||
topics: (id: string, name: string) => ({
|
||||
topics: (id: string, name: string): Topics => ({
|
||||
[name]: {
|
||||
state: {
|
||||
name: `stat/sonoff${id}/POWER`,
|
||||
|
|
@ -26,20 +26,20 @@ export const tasmota = {
|
|||
defaultValue: "off"
|
||||
}
|
||||
}),
|
||||
iconColor: (name: string, onColor: Color = hex("#00FF00")) =>
|
||||
(state: State) => {
|
||||
iconColor: (name: string, onCol: Color = hex("#00FF00")): (State => Color) =>
|
||||
(state: State): Color => {
|
||||
if (state[`${name}_online`] === "off") {
|
||||
return hex("#888888");
|
||||
} else if (state[name] === "on") {
|
||||
return onColor;
|
||||
return onCol;
|
||||
}
|
||||
return hex("#000000");
|
||||
}
|
||||
};
|
||||
export const floalt = {
|
||||
color: (lightId: string) => `floalt_${lightId}_color`,
|
||||
brightness: (lightId: string) => `floalt_${lightId}_brightness`,
|
||||
topics: (lightId: string) => ({
|
||||
color: (lightId: string): string => `floalt_${lightId}_color`,
|
||||
brightness: (lightId: string): string => `floalt_${lightId}_brightness`,
|
||||
topics: (lightId: string): Topics => ({
|
||||
[`floalt_${lightId}_color`]: {
|
||||
state: {
|
||||
name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${lightId}` +
|
||||
|
|
@ -70,9 +70,9 @@ export const floalt = {
|
|||
};
|
||||
|
||||
const tradfriRemote = {
|
||||
level: (remoteId: string) => `tradfri_remote_${remoteId}_level`,
|
||||
low: (remoteId: string) => `tradfri_remote_${remoteId}_low`,
|
||||
topics: (remoteId: string) => ({
|
||||
level: (remoteId: string): string => `tradfri_remote_${remoteId}_level`,
|
||||
low: (remoteId: string): string => `tradfri_remote_${remoteId}_low`,
|
||||
topics: (remoteId: string): Topics => ({
|
||||
[`tradfri_remote_${remoteId}_level`]: {
|
||||
state: {
|
||||
name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remoteId}` +
|
||||
|
|
@ -135,7 +135,7 @@ const esperStatistics = (name: string,
|
|||
}
|
||||
])
|
||||
);
|
||||
const esperTopics = (chipId: string, name: string) => ({
|
||||
const esperTopics = (chipId: string, name: string): Topics => ({
|
||||
[`esper_${name}_version`]: {
|
||||
state: {
|
||||
name: `/service/esper/${chipId}/info`,
|
||||
|
|
|
|||
34
package.json
34
package.json
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "mqtt-control-map",
|
||||
"version": "1.0.0",
|
||||
"author": "uwap <me+mqttmap.package.json@uwap.name>",
|
||||
"description": "control devices via mqtt on a beautiful map of your space",
|
||||
"author": "uwap <me@uwap.name>",
|
||||
"description": "Control Devices via mqtt, visualized on a Map",
|
||||
"scripts": {
|
||||
"build": "webpack --bail --config webpack.config.js -p --env",
|
||||
"dev": "webpack --bail --config webpack.config.js --mode development --env",
|
||||
|
|
@ -12,12 +12,12 @@
|
|||
"precommit": "yarn lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^3.0.1",
|
||||
"@material-ui/lab": "^3.0.0-alpha.16",
|
||||
"@mdi/font": "^4.0.96",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/lab": "^4.0.0-alpha.56",
|
||||
"@mdi/font": "^5.6.55",
|
||||
"leaflet": "^1.5.1",
|
||||
"lodash-es": "^4.17.15",
|
||||
"mqtt": "^3.0.0",
|
||||
"mqtt": "^4.2.1",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-leaflet": "^2.4.0",
|
||||
|
|
@ -28,25 +28,25 @@
|
|||
"@babel/core": "^7.5.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-flow": "^7.0.0-rc.1",
|
||||
"@babel/preset-react": "^7.0.0-rc.1",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"clean-webpack-plugin": "^2.0.0",
|
||||
"css-loader": "^3.0.0",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-plugin-flowtype": "^4.0.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"core-js": "3",
|
||||
"css-loader": "^4.3.0",
|
||||
"eslint": "^7.10.0",
|
||||
"eslint-plugin-flowtype": "^5.2.0",
|
||||
"eslint-plugin-fp": "^2.3.0",
|
||||
"eslint-plugin-react": "^7.14.3",
|
||||
"file-loader": "^5.0.0",
|
||||
"file-loader": "^6.1.0",
|
||||
"flow": "^0.2.3",
|
||||
"flow-bin": "^0.82.0",
|
||||
"flow-typed": "^2.3.0",
|
||||
"html-webpack-plugin": "^3.1.0",
|
||||
"husky": "^3.0.0",
|
||||
"style-loader": "^0.23.0",
|
||||
"flow-bin": "^0.135.0",
|
||||
"flow-typed": "^3.2.1",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"husky": "^4.3.0",
|
||||
"style-loader": "^1.3.0",
|
||||
"webpack": "^4.39.1",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import throttle from "lodash/throttle";
|
|||
|
||||
import type { Config, Control, Topics } from "config/flowtypes";
|
||||
|
||||
import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider";
|
||||
import createMuiTheme from "@material-ui/core/styles/createMuiTheme";
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import {
|
||||
MuiThemeProvider, createMuiTheme, withStyles
|
||||
} from "@material-ui/core/styles";
|
||||
import * as Colors from "@material-ui/core/colors";
|
||||
import Snackbar from "@material-ui/core/Snackbar";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
|
@ -55,7 +55,8 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
|
|||
onDisconnect: () => this.setState({ mqttConnected: false }),
|
||||
subscribe: map(
|
||||
filter(keys(this.topics), (x) => this.topics[x].state != null),
|
||||
(x) => this.topics[x].state.name)
|
||||
(x) => (this.topics[x].state != null ? this.topics[x].state.name : "")
|
||||
)
|
||||
}),
|
||||
mqttConnected: false,
|
||||
search: "",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import * as React from "react";
|
||||
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Drawer from "@material-ui/core/Drawer";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
|
@ -21,13 +21,23 @@ export type SideBarProps = {
|
|||
children?: React.Node
|
||||
};
|
||||
|
||||
type Props = SideBarProps & Classes;
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
drawerPaper: {
|
||||
width: 340
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
marginLeft: theme.spacing(1)
|
||||
}
|
||||
}));
|
||||
|
||||
const SideBar = (props: Props) => (
|
||||
const SideBar = (props: SideBarProps) => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Drawer open={props.open}
|
||||
anchor="right"
|
||||
onClose={props.onCloseRequest}
|
||||
classes={{paper: props.classes.drawerPaper}}
|
||||
classes={{paper: classes.drawerPaper}}
|
||||
variant="persistent"
|
||||
>
|
||||
<AppBar position="static">
|
||||
|
|
@ -35,7 +45,7 @@ const SideBar = (props: Props) => (
|
|||
<span>
|
||||
{props.icon == null || renderRawIcon(props.icon, "mdi-36px")}
|
||||
</span>
|
||||
<Typography variant="title" className={props.classes.title}>
|
||||
<Typography variant="subtitle1" className={classes.title}>
|
||||
{props.control == null ? "" : props.control.name}
|
||||
</Typography>
|
||||
<IconButton onClick={props.onCloseRequest}>
|
||||
|
|
@ -48,15 +58,6 @@ const SideBar = (props: Props) => (
|
|||
</List>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = (theme) => ({
|
||||
drawerPaper: {
|
||||
width: 340
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
marginLeft: theme.spacing.unit
|
||||
}
|
||||
});
|
||||
|
||||
export default withStyles(styles)(SideBar);
|
||||
export default SideBar;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import Toolbar from "@material-ui/core/Toolbar";
|
|||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import InputBase from "@material-ui/core/InputBase";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ const renderConnectionIndicator = (connected: boolean) => {
|
|||
);
|
||||
};
|
||||
|
||||
const searchStyles = (theme) => ({
|
||||
const useSearchStyles = makeStyles((theme) => ({
|
||||
search: {
|
||||
position: "relative",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
|
|
@ -36,16 +36,16 @@ const searchStyles = (theme) => ({
|
|||
"&:hover": {
|
||||
backgroundColor: fade(theme.palette.common.white, 0.25)
|
||||
},
|
||||
marginRight: theme.spacing.unit * 2,
|
||||
marginRight: theme.spacing(2),
|
||||
marginLeft: 0,
|
||||
width: "100%",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginLeft: theme.spacing(3),
|
||||
width: "auto"
|
||||
}
|
||||
},
|
||||
searchIcon: {
|
||||
width: theme.spacing.unit * 6,
|
||||
width: theme.spacing(6),
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
pointerEvents: "none",
|
||||
|
|
@ -59,31 +59,32 @@ const searchStyles = (theme) => ({
|
|||
width: "100%"
|
||||
},
|
||||
inputInput: {
|
||||
paddingTop: theme.spacing.unit,
|
||||
paddingRight: theme.spacing.unit,
|
||||
paddingBottom: theme.spacing.unit,
|
||||
paddingLeft: theme.spacing.unit * 6,
|
||||
paddingTop: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
paddingBottom: theme.spacing(1),
|
||||
paddingLeft: theme.spacing(6),
|
||||
transition: theme.transitions.create("width"),
|
||||
width: "100%",
|
||||
[theme.breakpoints.up("md")]: {
|
||||
width: 200
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
const RawSearch = (props: SearchBarProps & Classes) => (
|
||||
<div className={props.classes.search}>
|
||||
<i className={`mdi mdi-magnify ${props.classes.searchIcon}`}></i>
|
||||
const Search = (props: SearchBarProps) => {
|
||||
const classes = useSearchStyles();
|
||||
return (
|
||||
<div className={classes.search}>
|
||||
<i className={`mdi mdi-magnify ${classes.searchIcon}`}></i>
|
||||
<InputBase placeholder="Search…" type="search"
|
||||
onChange={(e) => props.onSearch(e.target.value)}
|
||||
classes={{
|
||||
root: props.classes.inputRoot,
|
||||
input: props.classes.inputInput
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const Search = withStyles(searchStyles)(RawSearch);
|
||||
};
|
||||
|
||||
const openOnGithub = () => window.open(
|
||||
"https://github.com/uwap/mqtt-control-map", "_blank");
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { isDisabled, getValue } from "./utils";
|
|||
|
||||
import type { UISlider } from "config/flowtypes";
|
||||
|
||||
import SliderComponent from "@material-ui/lab/Slider";
|
||||
import SliderComponent from "@material-ui/core/Slider";
|
||||
|
||||
const changeSliderValue = (item: UISlider, changeState) => (_e, v) =>
|
||||
changeState(item, v.toString());
|
||||
|
|
@ -36,5 +36,3 @@ export default createComponent({
|
|||
},
|
||||
baseComponent: BaseComponent
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const path = require('path');
|
|||
const webpack = require('webpack');
|
||||
const WebpackShellPlugin = require('webpack-shell-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const preBuildScripts = process.env.NO_FLOW == undefined ?
|
||||
process.env.FLOW_PATH != undefined ? [process.env.FLOW_PATH] : ['flow']
|
||||
: [];
|
||||
|
|
@ -16,7 +16,7 @@ const configPath = env => {
|
|||
|
||||
module.exports = env => ({
|
||||
entry: {
|
||||
main: ["@babel/polyfill", configPath(env),
|
||||
main: ["core-js/stable", "regenerator-runtime/runtime", configPath(env),
|
||||
path.resolve(__dirname, 'src/index.jsx')]
|
||||
},
|
||||
resolve: {
|
||||
|
|
@ -34,7 +34,7 @@ module.exports = env => ({
|
|||
rules: [
|
||||
// TODO: CSS follow imports and minify + sourcemap on production
|
||||
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
|
||||
{ test: /\.(woff2?|eot|ttf|svg)$/, loader: "file-loader" },
|
||||
{ test: /\.(woff2?|eot|ttf|svg)$/, use: [ { loader: "file-loader", options: { esModule: false } } ] },
|
||||
{ test: /\.js(x)?$/, loader: "babel-loader?cacheDirectory=true" }
|
||||
]
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue