diff --git a/.babelrc b/.babelrc index 8b51aa3..56f3104 100644 --- a/.babelrc +++ b/.babelrc @@ -1,10 +1,7 @@ { "presets": [ ["@babel/preset-env", { - modules: false, - corejs: "3.6", - useBuiltIns: "entry", - targets: "last 3 years" + modules: false }], "@babel/preset-react", "@babel/preset-flow" diff --git a/.eslintrc.js b/.eslintrc.js index 84615c5..78a98d6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,8 +7,7 @@ module.exports = { "extends": [ "eslint:recommended", "plugin:flowtype/recommended", - "plugin:react/recommended", - "plugin:react-hooks/recommended" + "plugin:react/recommended" ], "parserOptions": { "ecmaFeatures": { @@ -162,6 +161,6 @@ module.exports = { "fp/no-throw": "warn", "fp/no-unused-expression": "warn", "fp/no-valueof-field": "warn", - "no-var": "warn" + "no-var": "warn" } }; diff --git a/.flowconfig b/.flowconfig index 671c6f5..2f7d7b8 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,8 +1,5 @@ [ignore] -[untyped] -.*/node_modules/react-leaflet - [include] [libs] @@ -10,8 +7,9 @@ types/types.js 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 diff --git a/.travis.yml b/.travis.yml index a688e44..7c6000a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,10 @@ node_js: script: - yarn travis +before_install: yarn global add greenkeeper-lockfile@1 +before_script: greenkeeper-lockfile-update +after_script: greenkeeper-lockfile-upload + after_success: - ./travis-upload-artifacts.sh diff --git a/README.md b/README.md index 9eddf0e..eca38da 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # MQTT Control Map [![Build Status](https://travis-ci.org/uwap/mqtt-control-map.svg?branch=master)](https://travis-ci.org/uwap/mqtt-control-map) +[![Greenkeeper badge](https://badges.greenkeeper.io/uwap/mqtt-control-map.svg)](https://greenkeeper.io/) ## Development / Configuration @@ -11,6 +12,33 @@ your the mqtt control map for the given CONFIG everytime something changes. for the given config. 4. run `yarn build CONFIG` to generate all files for production use. -## Documentation +## Config -The documentation can be found in our [mqtt-control-map wiki](https://github.com/uwap/mqtt-control-map/wiki). +See `config/`. + +The Config format consists out of two sections. Topics and Controls. + +### Topics + +The topics section defines the mqtt interfaces. + +### Controls + +The Controls define the UI Controls. + +| Name | Type | Optional? | Default | Description | +|-----------------|-------------------|------------|-----------------|-------------| +| type | "toggle" \| "dropDown" \| "slider" | No | | The type of the UI element. | +| text | string | No | | The text displayed right next to the UI element. | +| topic | string | No | | The topic the UI element is supposed to change and/or receive its status from. | +| enableCondition | (key: string, value: *) => boolean | Yes | () => true | This option allows you to enable or disable UI elements, depending on the current state. The first parameter is the internal representation of the value. For example "off". The second parameter is the actual value that was received via MQTT. Return true to enable the element and false to disable it. | +| **Toggle Options** | +| on | string | Yes | "on" | If the state is equal to the value of this option the toggle will be toggled on (if the toggled function is not overriden). This is also the value that will be sent when the button is toggled on. | +| off | string | Yes | "off" | If the state is equal to the value of this option the toggle will be toggled off (if the toggled function is not overriden). This is also the value that will be sent when the button is toggled off. | +| toggled | (key: string, value: *) => boolean | Yes | Use the on and off options | This is the function that decides whether the button should be in a toggled state or not. The parameters are equivalent to those of `enableCondition`. Return true to set the button to a toggled state. Return false to set it to the untoggled state. | +| **DropDown Options** | +| options | Map| Yes | {} | This is an attribute set that will map all values defined in the topics section to a description text. For example `{ on: "Lights On", off: "Lights Off" }` will give the drop down element two options, one that is named `Lights On` and one that is named `Lights Off`. | +| **Slider Options** | +| min | number | Yes | 0 | The minimum value of that slider. | +| max | number | Yes | 1 | The maximum value of that slider. | +| step | number | Yes | 1 | The smallest step of the slider. | diff --git a/config/entropia/index.js b/config/entropia/index.js index 593bd97..c3237a8 100644 --- a/config/entropia/index.js +++ b/config/entropia/index.js @@ -1,8 +1,8 @@ // @flow import type { Config } from "config/flowtypes"; +import { hex } from "config/colors"; import * as types from "config/types"; -import * as icons from "@mdi/js"; -import { svg } from "config/icon"; +import { mdi } from "config/icon"; const config: Config = { space: { @@ -32,19 +32,20 @@ const config: Config = { hauptraumTableLight: { name: "Hauptraum Tisch", position: [450, 450], - icon: svg(icons.mdiWhiteBalanceIridescent), + icon: mdi("white-balance-iridescent"), + iconColor: () => hex("#000000"), ui: [ { type: "toggle", text: "Licht", topic: "hauptraumTableLight", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "toggle", text: "Licht", topic: "hauptraumTableLightOnHack", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] } diff --git a/config/rzl/index.js b/config/rzl/index.js index 9c2ef78..e688571 100644 --- a/config/rzl/index.js +++ b/config/rzl/index.js @@ -2,9 +2,8 @@ import type { Config } from "config/flowtypes"; import * as types from "config/types"; import { hex, rainbow } from "config/colors"; -import { svg, withState } from "config/icon"; +import { mdi, rawMdi } from "config/icon"; import { esper, tasmota } from "./utils"; -import * as icons from "@mdi/js"; import * as onkyo from "./onkyo"; import * as olymp from "./olymp"; @@ -226,35 +225,6 @@ const config: Config = { type: types.option({ on: "ON", off: "OFF" }) }, defaultValue: "off" - }, - whirlpoolTemperatureSetpoint: { - state: { - name: "/service/whirlpool/state", - type: types.json("temperatureSetpointC") - }, - command: { - name: "/service/whirlpool/set/temperature", - type: types.string - }, - defaultValue: "0" - }, - whirlpoolBubbles: { - state: { - name: "/service/whirlpool/state", - type: types.json("bubbles") - }, - command: { - name: "/service/whirlpool/set/bubbles", - type: types.string - }, - defaultValue: "0" - }, - whirlpoolTemperature: { - state: { - name: "/service/whirlpool/state", - type: types.json("waterTemperatureC") - }, - defaultValue: "0" } }, //Tasmota-Dosen @@ -276,28 +246,29 @@ const config: Config = { ledStahltrager: { name: "LED Stahlträger", position: [340, 590], - icon: svg(icons.mdiWhiteBalanceIridescent).color(({ledStahltraeger}) => - (ledStahltraeger === "on" ? rainbow : hex("#000000"))), + icon: mdi("white-balance-iridescent"), + iconColor: ({ledStahltraeger}) => + (ledStahltraeger === "on" ? rainbow : hex("#000000")), ui: [ { type: "toggle", text: "Stahlträger LED", topic: "ledStahltraeger", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, snackbar: { name: "Snackbar", position: [510, 500], - icon: svg(icons.mdiFridge).color( - tasmota.iconColor("snackbar", hex("#E20074"))), + icon: mdi("fridge"), + iconColor: tasmota.iconColor("snackbar", hex("#E20074")), ui: [ { type: "toggle", text: "Snackbar", topic: "snackbar", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "section", @@ -307,7 +278,7 @@ const config: Config = { type: "text", text: "LED-Streifen", topic: "snackbarLedOnline", - icon: svg(icons.mdiWhiteBalanceIridescent) + icon: mdi("white-balance-iridescent") }, { type: "dropDown", @@ -326,7 +297,7 @@ const config: Config = { "11": "Rainbow Pattern", "12": "Fire Pattern" }, - icon: svg(icons.mdiCog), + icon: mdi("settings"), enableCondition: ({ snackbarLedOnline }) => snackbarLedOnline === "on" }, { @@ -335,7 +306,7 @@ const config: Config = { topic: "snackbarDimmmer", min: 0, max: 100, - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), enableCondition: ({ snackbarLedOnline }) => snackbarLedOnline === "on" }, { @@ -344,7 +315,7 @@ const config: Config = { topic: "snackbarSpeed", min: 0, max: 20, - icon: svg(icons.mdiSpeedometer), + icon: mdi("speedometer"), enableCondition: ({ snackbarLedOnline }) => snackbarLedOnline === "on" } ] @@ -352,151 +323,155 @@ const config: Config = { twinkle: { name: "Twinkle", position: [530, 560], - icon: withState(({twinkle}) => - (twinkle === "on" ? svg(icons.mdiLedOn).flipV().color(rainbow) - : svg(icons.mdiLedOff).flipV()) - ), + icon: ({twinkle}) => + (twinkle === "on" ? rawMdi("led-on flip-v") : rawMdi("led-off flip-v")), + iconColor: ({twinkle}) => (twinkle === "on" ? rainbow : hex("#000000")), ui: [ { type: "toggle", text: "Twinkle", topic: "twinkle", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, fan: { name: "Ventilator", position: [530, 440], - icon: svg(icons.mdiFan).color(({fan}) => - (fan === "on" ? hex("#00FF00") : hex("#000000"))), + icon: mdi("fan"), + iconColor: ({fan}) => (fan === "on" ? hex("#00FF00") : hex("#000000")), ui: [ { type: "toggle", text: "Ventilator", topic: "fan", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, cashdesk: { name: "Cashdesk", position: [510, 467], - icon: svg(icons.mdiCurrencyUsdCircle), + icon: mdi("coin"), ui: [ { type: "link", - link: "http://cashdesk.rzl:8000/", + link: "http://cashdesk.rzl:8081/", text: "Open Cashdesk", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") } ] }, flyfry: { name: "Fliegenbratgerät", position: [450, 570], - icon: svg(icons.mdiFire).color(({flyfry}) => - (flyfry === "on" ? hex("#6666FF") : hex("#000000"))), + icon: mdi("fire"), + iconColor: ({flyfry}) => + (flyfry === "on" ? hex("#6666FF") : hex("#000000")), ui: esper.statistics("flyfry", [ { type: "toggle", text: "Fliegenbratgerät", topic: "flyfry", - icon: svg(icons.mdiPower) + icon: mdi("power") } ]) }, projector: { name: "Beamer", position: [380, 590], - icon: svg(icons.mdiProjector).flipV().color(({projector}) => + icon: mdi("projector flip-v"), + iconColor: ({projector}) => ({ transientOn: hex("#b3b300"), transientOff: hex("#b3b300"), on: hex("#00ff00"), off: hex("#000000"), unknown: hex("#888888") - })[projector]), + })[projector], ui: [ { type: "toggle", text: "Beamer", topic: "projector", toggled: (val) => val === "transientOn" || val === "on", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, loetarbeitsplatz4: { name: "Lötarbeitsplatz", position: [205, 455], - icon: svg(icons.mdiEyedropperVariant).color(({loetarbeitsplatz4}) => - (loetarbeitsplatz4 === "on" ? hex("#FF0000") : hex("#000000"))), + icon: mdi("eyedropper-variant"), + iconColor: ({loetarbeitsplatz4}) => + (loetarbeitsplatz4 === "on" ? hex("#FF0000") : hex("#000000")), ui: [ { type: "text", text: "Status", topic: "loetarbeitsplatz4", - icon: svg(icons.mdiEyedropperVariant) + icon: mdi("eyedropper-variant") } ] }, loetarbeitsplatz5: { name: "Lötarbeitsplatz", position: [205, 405], - icon: svg(icons.mdiEyedropperVariant).color(({loetarbeitsplatz4}) => - (loetarbeitsplatz4 === "on" ? hex("#FF0000") : hex("#000000"))), + icon: mdi("eyedropper-variant"), + iconColor: ({loetarbeitsplatz5}) => + (loetarbeitsplatz5 === "on" ? hex("#FF0000") : hex("#000000")), ui: [ { type: "text", text: "Status", topic: "loetarbeitsplatz5", - icon: svg(icons.mdiEyedropperVariant) + icon: mdi("eyedropper-variant") } ] }, door: { name: "Tür", position: [455, 350], - icon: svg(icons.mdiSwapVertical).color(({doorStatus}) => - (doorStatus === "on" ? hex("#00FF00") : hex("#FF0000"))), + icon: mdi("swap-vertical"), + iconColor: ({doorStatus}) => + (doorStatus === "on" ? hex("#00FF00") : hex("#FF0000")), ui: [ { type: "link", link: "http://s.rzl.so", text: "Open Status Page", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") }, { type: "link", // eslint-disable-next-line max-len link: "http://kunterbunt.vm.rzl/dashboard/db/allgemeines-copy-ranlvor?orgId=1", text: "RZL-Dashboard", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") }, { type: "text", text: "Anwesend", topic: "presenceStatus", - icon: svg(icons.mdiAccount) + icon: mdi("account") }, { type: "text", text: "Devices", topic: "devicesStatus", - icon: svg(icons.mdiWifi) + icon: mdi("wifi") }, { type: "toggle", text: "Deko", topic: "deko", - icon: svg(icons.mdiInvertColors) + icon: mdi("invert-colors") }, { type: "text", text: "Power Hauptraum", topic: "powerConsumption", - icon: svg(icons.mdiSpeedometer) + icon: mdi("speedometer") } ] @@ -504,56 +479,56 @@ const config: Config = { infoscreen: { name: "Infoscreen", position: [255, 495], - icon: svg(icons.mdiTelevisionGuide).flipV().color( - tasmota.iconColor("infoscreen", hex("#4444FF")) - ), + icon: mdi("television-guide flip-v"), + iconColor: tasmota.iconColor("infoscreen", hex("#4444FF")), ui: [ { type: "toggle", text: "Infoscreen", topic: "infoscreen", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "link", link: "http://cashdesk.rzl:3030/rzl", text: "Open Infoscreen", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") } ] }, pilze: { name: "Pilze", position: [48, 499], - icon: withState(({pilze}) => - (pilze === "on" ? svg(icons.mdiLedOn) : svg(icons.mdiLedOff))).color( - tasmota.iconColor("pilze", rainbow)), + icon: ({pilze}) => + (pilze === "on" ? rawMdi("led-on") : rawMdi("led-off")), + iconColor: tasmota.iconColor("pilze", rainbow), ui: [ { type: "toggle", text: "Pilze", topic: "pilze", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, printer3D: { name: "Ultimaker 3", position: [754, 560], - icon: svg(icons.mdiPrinter3d).color(({printer3DStatus}) => + icon: mdi("printer-3d"), + iconColor: ({printer3DStatus}) => ({ awaitingInteraction: hex("#b3b300"), printing: hex("#00ff00"), idle: hex("#000000"), unavailable: hex("#888888"), error: hex("#ff0000") - })[printer3DStatus]), + })[printer3DStatus], ui: [ { type: "link", link: "http://ultimaker.rzl/", text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") }, { type: "section", @@ -561,7 +536,7 @@ const config: Config = { }, { type: "progress", - icon: svg(icons.mdiRotateRight), + icon: mdi("rotate-right"), min: 0, max: 1, text: "Printing Progress", @@ -570,7 +545,7 @@ const config: Config = { { type: "text", text: "Time Left", - icon: svg(icons.mdiClock), + icon: mdi("clock"), topic: "printer3Dremaining" } ] @@ -578,87 +553,51 @@ const config: Config = { partkeepr: { name: "Partkeepr", position: [48, 450], - icon: svg(icons.mdiChip), + icon: mdi("chip"), ui: [ { type: "link", link: "http://partkeepr.rzl/", text: "Open Partkeepr", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") } ] }, printerAnnette: { name: "Drucker", position: [800, 350], - icon: svg(icons.mdiPrinter).color(tasmota.iconColor("printerAnnette")), + icon: mdi("printer"), + iconColor: tasmota.iconColor("printerAnnette"), ui: [ { type: "toggle", text: "Drucker", topic: "printerAnnette", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "link", link: "http://annette.rzl/", text: "Open Annette", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") } ] }, nebenraumPowerStatus: { name: "Strom Fablab", position: [613, 537], - icon: withState(({nebenraumPowerStatus}) => - (nebenraumPowerStatus === "on" ? - svg(icons.mdiFlash).color(hex("#00FF00")) : svg(icons.mdiFlashOff))), + icon: ({nebenraumPowerStatus}) => + (nebenraumPowerStatus === "on" ? rawMdi("flash") : rawMdi("flash-off")), + iconColor: ({nebenraumPowerStatus}) => + (nebenraumPowerStatus === "on" ? hex("#00ff00") : hex("#000000")), ui: [ { type: "text", - icon: svg(icons.mdiPower), + icon: mdi("power"), text: "Strom Fablab", topic: "nebenraumPowerStatus" } ] - }, - whirlpool: { - name: "Vorstandswhirlpool", - position: [1413, 500], - icon: svg(icons.mdiPool).color( - ({whirlpoolBubbles}) => - (parseInt(whirlpoolBubbles, 10) > 0 ? hex("#00ff00") - : hex("#000000"))), - ui: [ - { - type: "text", - icon: svg(icons.mdiOilTemperature), - text: "Temperatur", - topic: "whirlpoolTemperature" - }, - { - type: "text", - icon: svg(icons.mdiOilTemperature), - text: "Temperatur Sollwert", - topic: "whirlpoolTemperatureSetpoint" - }, - { - type: "slider", - min: 4, - max: 100, - text: "Temperatur Sollwert", - icon: svg(icons.mdiOilTemperature), - topic: "whirlpoolTemperatureSetpoint" - }, - { - type: "slider", - min: 0, - max: 9, - text: "Bubbles", - icon: svg(icons.mdiChartBubble), - topic: "whirlpoolBubbles" - } - ] } }, layers: [ diff --git a/config/rzl/kitchen.js b/config/rzl/kitchen.js index 89fd23a..942328d 100644 --- a/config/rzl/kitchen.js +++ b/config/rzl/kitchen.js @@ -1,10 +1,9 @@ // @flow import type { Topics, Controls } from "config/flowtypes"; -import { svg, mdiBattery } from "config/icon"; +import { mdi, mdiBattery } from "config/icon"; import { hex } from "config/colors"; import * as types from "config/types"; -import { floalt, tradfri, tasmota } from "./utils"; -import * as icons from "@mdi/js"; +import { floalt, tradfri } from "./utils"; export const topics: Topics = { //Kuechen-Floalts @@ -21,8 +20,6 @@ export const topics: Topics = { ...tradfri.remote.topics("65542"), ...tradfri.remote.topics("65546"), - ...tasmota.topics("10", "lichtDunstabzug"), - kitchenLightColor: { state: { name: "/service/openhab/out/kitchen_light_all_color_temperature" @@ -66,7 +63,7 @@ export const controls: Controls = { kitchenLight: { name: "Deckenlicht Küche", position: [325, 407], - icon: svg(icons.mdiCeilingLight), + icon: mdi("ceiling-light"), ui: [ { type: "toggle", @@ -75,14 +72,14 @@ export const controls: Controls = { toggled: (n) => parseInt(n, 10) > 0, topic: "kitchenLightBrightness", text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "slider", min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: "kitchenLightBrightness" }, { @@ -90,7 +87,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: "kitchenLightColor" }, { @@ -102,7 +99,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65537") }, { @@ -110,7 +107,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65537") }, { @@ -122,7 +119,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65538") }, { @@ -130,7 +127,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65538") }, { @@ -142,7 +139,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65539") }, { @@ -150,7 +147,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65539") }, { @@ -162,7 +159,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65540") }, { @@ -170,7 +167,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65540") } ] @@ -178,7 +175,7 @@ export const controls: Controls = { kitchenSinkLight: { name: "Licht Spüle", position: [300, 345], - icon: svg(icons.mdiWallSconceFlat), + icon: mdi("wall-sconce-flat"), ui: [ { type: "toggle", @@ -187,14 +184,14 @@ export const controls: Controls = { toggled: (n) => parseInt(n, 10) > 0, topic: "kitchenSinkLightBrightness", text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) + icon: mdi("power") }, { type: "slider", min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: "kitchenSinkLightBrightness" } ] @@ -202,7 +199,7 @@ export const controls: Controls = { kitchenCounterLight: { name: "Deckenlicht Theke", position: [400, 440], - icon: svg(icons.mdiCeilingLight), + icon: mdi("ceiling-light"), ui: [ { type: "section", @@ -213,7 +210,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65544") }, { @@ -221,7 +218,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65544") }, { @@ -233,7 +230,7 @@ export const controls: Controls = { min: 0, max: 100, text: "Helligkeit", - icon: svg(icons.mdiBrightness7), + icon: mdi("brightness-7"), topic: floalt.brightness("65543") }, { @@ -241,29 +238,15 @@ export const controls: Controls = { min: 0, max: 100, text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), + icon: mdi("weather-sunset-down"), topic: floalt.color("65543") } ] }, - lichtDunstabzug: { - name: "Licht Dunstabzugshaube", - position: [252, 405], - icon: svg(icons.mdiCeilingLight), - iconColor: tasmota.iconColor("lichtDunstabzug"), - ui: [ - { - type: "toggle", - text: "Licht Dunstabzugshaube", - topic: "lichtDunstabzug", - icon: svg(icons.mdiPower) - } - ] - }, remotes: { name: "Fernbedinungen", position: [400, 344], - icon: svg(icons.mdiLightSwitch), + icon: mdi("light-switch"), iconColor: (state) => //if any remote is low make icon red (["65536", "65542", "65546", "65547"] .some((x) => state[tradfri.remote.low(x)] === "true") diff --git a/config/rzl/olymp.js b/config/rzl/olymp.js index 8b8e989..e3810bc 100644 --- a/config/rzl/olymp.js +++ b/config/rzl/olymp.js @@ -1,14 +1,11 @@ // @flow import type { Topics, Controls } from "config/flowtypes"; -import { svg } from "config/icon"; +import { mdi } from "config/icon"; import { hex, rainbow } from "config/colors"; import * as types from "config/types"; import { tasmota, esper } from "./utils"; -import * as icons from "@mdi/js"; export const topics: Topics = { - ...tasmota.topics("8", "ledOlymp"), - ...esper.topics("afba45", "alarm"), videogames: { state: { name: "/service/openhab/out/pca301_videogames/state", @@ -41,70 +38,75 @@ 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 = { ledOlymp: { name: "LED Olymp", position: [196, 154], - icon: svg(icons.mdiWhiteBalanceIridescent).rotate(45).color( - tasmota.iconColor("ledOlymp", rainbow)), + icon: mdi("white-balance-iridescent rotate-45"), + iconColor: tasmota.iconColor("ledOlymp", rainbow), ui: [ { type: "toggle", text: "LED Olymp", topic: "ledOlymp", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, videogames: { name: "Videospiele", position: [100, 100], - icon: svg(icons.mdiGamepadVariant).color(({videogames}) => - (videogames === "on" ? hex("#00FF00") : hex("#000000"))), + icon: mdi("gamepad-variant"), + iconColor: ({videogames}) => + (videogames === "on" ? hex("#00FF00") : hex("#000000")), ui: [ { type: "toggle", text: "Videospiele", topic: "videogames", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, olympPC: { name: "Rechner", position: [297, 90], - icon: svg(icons.mdiDesktopClassic).color(({olympPC}) => - (olympPC === "on" ? hex("#00FF00") : hex("#000000"))), + icon: mdi("desktop-classic"), + iconColor: ({olympPC}) => + (olympPC === "on" ? hex("#00FF00") : hex("#000000")), ui: [ { type: "toggle", text: "Rechner", topic: "olympPC", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, rundumleuchte: { name: "Rundumleuchte", position: [310, 275], - icon: svg(icons.mdiAlarmLight).color(({rundumleuchte}) => - (rundumleuchte === "on" ? hex("#F0DF10") : hex("#000000"))), + icon: mdi("alarm-light"), + iconColor: ({rundumleuchte}) => + (rundumleuchte === "on" ? hex("#F0DF10") : hex("#000000")), ui: [ { type: "toggle", text: "Rundumleuchte", topic: "rundumleuchte", - icon: svg(icons.mdiPower) + icon: mdi("power") } ] }, alarm: { name: "Alarm", position: [340, 250], - icon: svg(icons.mdiAlarmBell), + icon: mdi("alarm-bell"), iconColor: () => hex("#000000"), ui: esper.statistics("alarm") } diff --git a/config/rzl/onkyo.js b/config/rzl/onkyo.js index d1bca0a..edc8733 100644 --- a/config/rzl/onkyo.js +++ b/config/rzl/onkyo.js @@ -1,9 +1,8 @@ // @flow import type { Topics, Controls } from "config/flowtypes"; -import { svg } from "config/icon"; +import { mdi } from "config/icon"; import { hex } from "config/colors"; import * as types from "config/types"; -import * as icons from "@mdi/js"; export const topics: Topics = { onkyoConnection: { @@ -95,10 +94,6 @@ export const topics: Topics = { NPR08: "somafmLush", NPR09: "somafmBeatblender", NPR0a: "ponyville", - NPR0b: "deutschlandradio", - NPR0c: "somafmSuburbsOfGoa", - NPR0d: "somafmSonicUniverse", - NPR0e: "somafmChrismasLounge", otherwise: "unknown" }) }, @@ -115,10 +110,6 @@ export const topics: Topics = { somafmLush: "NPR08", somafmBeatblender: "NPR09", ponyville: "NPR0a", - deutschlandradio: "NPR0b", - somafmSuburbsOfGoa: "NPR0c", - somafmSonicUniverse: "NPR0d", - somafmChrismasLounge: "NPR0e", otherwise: "NPR00" }) }, @@ -133,12 +124,12 @@ export const controls: Controls = { iconColor: ({onkyoConnection, onkyoPower}) => (onkyoConnection !== "connected" ? hex("#888888") : (onkyoPower === "on" ? hex("#00FF00") : hex("#000000"))), - icon: svg(icons.mdiAudioVideo), + icon: mdi("audio-video"), ui: [ { type: "toggle", text: "Power", - icon: svg(icons.mdiPower), + icon: mdi("power"), topic: "onkyoPower", enableCondition: (state) => state.onkyoConnection === "connected" }, @@ -152,14 +143,14 @@ export const controls: Controls = { topic: "onkyoVolume", min: 0, max: 50, - icon: svg(icons.mdiVolumeHigh), + icon: mdi("volume-high"), enableCondition: (state) => state.onkyoConnection === "connected" }, { type: "toggle", text: "Mute", topic: "onkyoMute", - icon: svg(icons.mdiVolumeOff), + icon: mdi("volume-off"), enableCondition: (state) => state.onkyoConnection === "connected" }, { @@ -177,7 +168,7 @@ export const controls: Controls = { pult: "Pult", front: "Front HDMI" }, - icon: svg(icons.mdiUsb), + icon: mdi("usb"), enableCondition: (state) => state.onkyoConnection === "connected" }, { @@ -195,13 +186,9 @@ export const controls: Controls = { somafmLush: "Lush (SomaFM)", somafmBeatblender: "Beat Blender (Soma FM)", ponyville: "Ponyville FM", - deutschlandradio: "Deutschlandradio", - somafmSuburbsOfGoa: "Suburbs of Goa (SomaFM)", - somafmSonicUniverse: "Sonic Universe (SomaFM)", - somafmChrismasLounge: "Christmas Lounge (SomaFM)", unknown: "Unknown" }, - icon: svg(icons.mdiRadio), + icon: mdi("radio"), enableCondition: (state) => state.onkyoConnection === "connected" && state.onkyoInputs === "netzwerk" }, @@ -213,7 +200,7 @@ export const controls: Controls = { type: "link", link: "http://mpd.rzl/mpd/player/index.php", text: "Open MPD Interface", - icon: svg(icons.mdiOpenInNew) + icon: mdi("open-in-new") } ] } diff --git a/config/rzl/utils.js b/config/rzl/utils.js index 5daf02f..f1b5c60 100644 --- a/config/rzl/utils.js +++ b/config/rzl/utils.js @@ -1,12 +1,11 @@ // @flow -import type { ControlUI, Topics } from "config/flowtypes"; -import { svg } from "config/icon"; -import { hex, type Color } from "config/colors"; +import type { ControlUI } from "config/flowtypes"; +import { mdi } from "config/icon"; +import { hex } from "config/colors"; import * as types from "config/types"; -import * as icons from "@mdi/js"; export const tasmota = { - topics: (id: string, name: string): Topics => ({ + topics: (id: string, name: string) => ({ [name]: { state: { name: `stat/sonoff${id}/POWER`, @@ -27,20 +26,20 @@ export const tasmota = { defaultValue: "off" } }), - iconColor: (name: string, onCol: Color = hex("#00FF00")): (State => Color) => - (state: State): Color => { + iconColor: (name: string, onColor: Color = hex("#00FF00")) => + (state: State) => { if (state[`${name}_online`] === "off") { return hex("#888888"); } else if (state[name] === "on") { - return onCol; + return onColor; } return hex("#000000"); } }; export const floalt = { - color: (lightId: string): string => `floalt_${lightId}_color`, - brightness: (lightId: string): string => `floalt_${lightId}_brightness`, - topics: (lightId: string): Topics => ({ + color: (lightId: string) => `floalt_${lightId}_color`, + brightness: (lightId: string) => `floalt_${lightId}_brightness`, + topics: (lightId: string) => ({ [`floalt_${lightId}_color`]: { state: { name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${lightId}` + @@ -71,9 +70,9 @@ export const floalt = { }; const tradfriRemote = { - level: (remoteId: string): string => `tradfri_remote_${remoteId}_level`, - low: (remoteId: string): string => `tradfri_remote_${remoteId}_low`, - topics: (remoteId: string): Topics => ({ + level: (remoteId: string) => `tradfri_remote_${remoteId}_level`, + low: (remoteId: string) => `tradfri_remote_${remoteId}_low`, + topics: (remoteId: string) => ({ [`tradfri_remote_${remoteId}_level`]: { state: { name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remoteId}` + @@ -107,36 +106,36 @@ const esperStatistics = (name: string, { type: "text", text: "Device Variant", - icon: svg(icons.mdiChartDonut), + icon: mdi("chart-donut"), topic: `esper_${name}_device` }, { type: "text", text: "Version", - icon: svg(icons.mdiSourceBranch), + icon: mdi("source-branch"), topic: `esper_${name}_version` }, { type: "text", text: "IP", - icon: svg(icons.mdiAccessPointNetwork), + icon: mdi("access-point-network"), topic: `esper_${name}_ip` }, { type: "text", text: "RSSI", - icon: svg(icons.mdiWifi), + icon: mdi("wifi"), topic: `esper_${name}_rssi` }, { type: "text", text: "Running since…", - icon: svg(icons.mdiAvTimer), + icon: mdi("av-timer"), topic: `esper_${name}_uptime` } ]) ); -const esperTopics = (chipId: string, name: string): Topics => ({ +const esperTopics = (chipId: string, name: string) => ({ [`esper_${name}_version`]: { state: { name: `/service/esper/${chipId}/info`, diff --git a/config/uwap-home/assets/layers/rooms.svg b/config/uwap-home/assets/layers/rooms.svg deleted file mode 100644 index 693b62c..0000000 --- a/config/uwap-home/assets/layers/rooms.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/config/uwap-home/assets/raw/uwap-home.draw.io b/config/uwap-home/assets/raw/uwap-home.draw.io deleted file mode 100644 index c304779..0000000 --- a/config/uwap-home/assets/raw/uwap-home.draw.io +++ /dev/null @@ -1 +0,0 @@ -3Vxbk9o2GP01POLRxZLtx3Q3bR7SmbQ7TdqnjBcL8MQgxpjA9tdXBgksW7BiY9lKkxkWC+HLOZ++u5jgh9XhtzLdLH/nGSsmCGSHCX6cIARDGIs/9cjLaSQG5DSwKPNMTroMPOX/MjkI5Oguz9hWm1hxXlT5Rh+c8fWazSptLC1LvtenzXmhX3WTLlhn4GmWFt3RL3lWLeVTEHAZ/8DyxVJdGQL5ySpVk+XAdplmfN8Ywu8n+KHkvDq9Wx0eWFGDp3A5fe/XK5+eb6xk68rmCx/4u8/Tp93u4Us6e2EIPqZ//DXFp7N8T4udfGB5s9WLQmC/zCv2tEln9fFesDzBvyyrVSGOoHibbjcn3Of5gYlL/SLPyMqKHa7eKjwDICSH8RWryhcxRX5BQSZlBith2F8YgIqBZRN9NZhK1hfnU1+AEW8kNnfgFP4MOIV0dJyi13Eq+W6d1Qg8AoHCK6j1ANJZepQ0JV2UsAmlELhCKfEPJUR1lGIDSMgA0hnd3kFSJ/YKJR0k1AVJSE0XJJQ4Awn6B1IY6ygRYFBL8bAwIf9gaq84k/Y2qSXkDCQLZ2DkBUcNnsBZajQLFztDibyOUv3IufAhP6bPrPjEt3mV87X46JlXFV/pIKm574p8Uc+peI1iKo9mAidWigHhPW7qs68Oi9rRDuYF5+WmSNfBs3A0q92zmFPyKpVXmiagHwKmyGIxm8Q0ckYA9YyAbb7+9rUneYcqPLpTKYTO0Lbw6MZBuyHt9Wp3Az8iVvBj4gr+2DP4K54XrHKkbHDLU4/t0KeRI/SRhapZCJO4uQsPmapIn9UpwN044Ug3i6FBKSuZbCKVUFdyahHSDCqns2WayxmnrAt4s8zeEI3rioQGIQjJ5T/WCEsC2vVjIpNeCSiJYIhi+epK0C1irfHpy/JSrJvTVfds+3Yt9BZGIxLEGqN+E2oRF/pF6JqXNXADMhqiAJAmoy3bj4M4bnLVIViQCbsUoyi40Fu/OrNOFkGtXxxv+c4vjqckCkjS/Bd6x7JFVD4+y95Y1imGAWkyo1wlXxSzRSVhfDo9trTeE2yRH1JslMeK0FgrKQooSq6rRkQC3MSrCzMEoTiFIcygcUAMX+0fa9+SE88s+5rx3TGycxIhI50kQ5UGUlM61Fk2DluYpzFCZEI1oISkd5FStzpI2hJbeGtugLrB2/W0Lw4iguOQQvka6sqh6yYNiybyLS/G5/N8xr66do5OUnQjgRYADCKaIPmqsQa7awAL/9dAs5Zaxq44tMgZDWQpX4EVxkEDUxDp2TdTdwrAATIQ0cTVWQ8G9i2Zs+flt63iSudwXuSbz/I6w/FJYHCW+OOrxqehqh/SINH4NCwTZ3RaRAwGw+HYvkKgL4LIgBrEQ9YFsYXj7QKnG6R10RsPHd+qppYG8wf1ALkpxKFeb4LddW8qtbqyh9gimrG0h05Ra/XTmRY+NODmzt755gveb++c8oX1mBF3+Rq0owD7VirMSrbdHuc0PZDeegraPYORpaF0RkDom39oJKC3jIlSDyoTgA2ZADCkng99q81l4s2fpwd30qYOWw2hFHQpiEzOUOiKAYtcjD8MOFgUSaIRQnA3nxMZil6Rq/aR0LciV03IRzYfio+zAlI2Gnc7n4ZdIb51uc74bvb20vErJkK1hysTbXJpiWE9hLEr+H2L1mQI7EL2cSuTgMKu7JtavN3t9fJyE5Oeo4K0244CATKIaOIKJYuo66dBCTozbBbBzhgbB3WcTBssjebG1ZIjFiEJW2fv6g29k7pXbF0royzdLo/SBXXE2CGv/q6FLohRLI//OR4DqD5/PEipPB68NA4+sTIXT1UrxEZczrLOPuEW2OJm+a6csRuPCa8U3V4JxdVYyQqhfL/r92HiQl7hE8/FHV4LRGPaYvN0+/JLF0K752lvXGrvtanScsGqzomOknF+6h8QFh/jp2vOYh+LNdKLr4aiP6VDLlYfo6cBnXWStJz1xOCsm6InVy1HxMfoySac7c2D72w5RYaAdsj4ifTtQ7qQY6gnhqnB8TZWQJx53sS35shLZrIPvFt207iV0pSJpM4Uh29R/nFzH3Ij7rRVtyLEbndZ6Ax93+pWZbpesPbeyt7gB3rOkVJkBT9xlYYnvtWhSjYv8wUr04q3aiG91aLCWO8Iiwy7Wkz9o4qr3kmgFoHf/9mXPIv82ZfsNiFQgy/pzCTQnym4crIFPG6nIw3hVtxlJHKlp6iFd39HbmQt7qlOjsAAQKwG6uzIFAQAnEcu+ZHj0Uvz6O0ZklNm4MbDQmAmZ5gMCWmFEaph9t4MSdTKtLR/I8lxgoRauNFvkxhhw1sSA0cWmGRcedHNafuneUaXF3F4+YHB0/TLzzTi9/8B \ No newline at end of file diff --git a/config/uwap-home/index.js b/config/uwap-home/index.js deleted file mode 100644 index 4a283a0..0000000 --- a/config/uwap-home/index.js +++ /dev/null @@ -1,1673 +0,0 @@ -// @flow -import type { Config } from "config/flowtypes"; -import * as types from "config/types"; -import { svg, withState } from "config/icon"; -import { hex } from "config/colors"; -import * as icons from "@mdi/js"; -//import { Buffer } from "bl"; - -const topicBulbHomeRust = (bulb: string, argument: string) => ({ - [`${bulb}${argument}`]: { - state: { - name: `home-rust/bulb/${bulb}/${argument}`, - type: types.string - }, - command: { - name: `home-rust/bulb/${bulb}/${argument}/set`, - type: types.string - }, - defaultValue: "0" - } -}); - -const topicZigbeeState = (topic: string, bulb: string) => ({ - [`${topic}State`]: { - state: { - name: `zigbee2mqtt/${bulb}/state`, - type: types.option({ - OFF: "off", - ON: "on" - }) - }, - command: { - name: `zigbee2mqtt/${bulb}/set/state`, - type: types.string - }, - defaultValue: "OFF" - } -}); -const topicBulbState = (bulb: string) => topicZigbeeState(bulb, `bulb_${bulb}`); -const topicGroupState = (bulb: string) => topicZigbeeState(bulb, `group_${bulb}`); - -const topicZigbeeNumber = (topic: string, bulb: string, parameter: string) => ({ - [`${topic}${parameter}`]: { - state: { - name: `zigbee2mqtt/${bulb}/${parameter}`, - type: types.string - }, - command: { - name: `zigbee2mqtt/${bulb}/set/${parameter}`, - type: types.string - }, - defaultValue: "0" - } -}); -const topicBulbNumber = (bulb: string, parameter: string) => topicZigbeeNumber(bulb, `bulb_${bulb}`, parameter); -const topicGroupNumber = (bulb: string, parameter: string) => topicZigbeeNumber(bulb, `group_${bulb}`, parameter); - -const topicHomeBoolean = (name: string, topic: string, - defaultValue: boolean = false) => topicBoolean(name, `home-rust/${topic}`, defaultValue); - -const topicBoolean = (name: string, topic: string, - defaultValue: boolean = false) => ({ - [`${name}`]: { - state: { - name: `${topic}`, - type: types.option({ true: "on", false: "off" }) - }, - command: { - name: `${topic}/set`, - type: types.option({ on: "true", off: "false" }) - }, - defaultValue: defaultValue ? "on" : "off" - } -}); - -const topicHomeNumber = (name: string, topic: string, - defaultValue: number = 0) => ({ - [`${name}`]: { - state: { - name: `home-rust/${topic}`, - type: types.string - }, - command: { - name: `home-rust/${topic}/set`, - type: types.string - }, - defaultValue: defaultValue - } -}); - -const topicTasmota = (name: string, topic: string) => ({ - [`${name}State`]: { - state: { - name: `stat/${topic}/POWER`, - type: types.option({ - OFF: "off", - ON: "on" - }) - }, - command: { - name: `cmnd/${topic}/POWER`, - type: types.string - }, - defaultValue: "off" - } -}); - -const topicTasmotaPower = (name: string, topic: string) => ({ - [`${name}Power`]: { - state: { - name: `tele/${topic}/SENSOR`, - type: types.json("ENERGY.Power") - }, - defaultValue: "no Data" - } -}); - -const topicHeating = (name: string) => ({ - [`heater${name}Tsoll`]: { - state: { - name: `tele/home-rust/fritzbox/device/${name}`, - type: (msg) => { - const json = JSON.parse(msg.toString()); - if (!json || !json["tsoll"]) { - return "126.5"; - } else { - const tsoll = json["tsoll"] / 2; - if (!json["offset"] || tsoll > 50) { - return tsoll.toString(); - } else { - return (tsoll - json["offset"]/10).toString(); - } - } - } - }, - command: { - name: `home-rust/fritzbox/device/${name}/tsoll/set`, - //TODO: add offset before writing out new value - type: (msg) => (Buffer.from((parseFloat(msg) * 2).toString())) - }, - defaultValue: "126.5" - }, - [`heater${name}WindowEnd`]: { - state: { - name: `tele/home-rust/fritzbox/device/${name}`, - type: (msg) => { - const json = JSON.parse(msg.toString()); - if (!json || !json["windowopenactiveendtime"]) { - return "inactive"; - } else { - return new Date(json["windowopenactiveendtime"] * 1000).toLocaleTimeString(); - } - } - }, - defaultValue: "unavailable" - }, - [`heater${name}BoostEnd`]: { - state: { - name: `tele/home-rust/fritzbox/device/${name}`, - type: (msg) => { - const json = JSON.parse(msg.toString()); - if (!json || !json["boostactiveendtime"]) { - return "inactive"; - } else { - return new Date(json["boostactiveendtime"] * 1000).toLocaleTimeString(); - } - } - }, - defaultValue: "unavailable" - } -}); - - -const sliderRGB = (bulb: string, argument: string) => ( - [{ - type: "slider", - min: 0, - max: 255, - text: argument, - icon: svg(icons.mdiBrightness7), - topic: `${bulb}${argument}` - }] -); -const sliderH = (bulb: string, argument: string) => ( - [{ - type: "slider", - min: 0, - max: 360, - text: argument, - icon: svg(icons.mdiBrightness7), - topic: `${bulb}${argument}` - }] -); -const sliderSVXY = (bulb: string, argument: string) => ( - [{ - type: "slider", - min: 0, - max: 1, - step: 0.01, - text: argument, - icon: svg(icons.mdiBrightness7), - topic: `${bulb}${argument}` - }] -); -const radiatorUI = (name: string) => ([ - { - type: "toggle", - topic: `heater${name}Tsoll`, - text: "Volle Power", - icon: svg(icons.mdiRadiator), - on: "127", - off: "22" - }, - { - type: "toggle", - topic: `heater${name}Tsoll`, - text: "Ausschalten", - icon: svg(icons.mdiRadiatorDisabled), - on: "126.5", - off: "22" - }, - { - type: "slider", - min: 8, - max: 33, - step: 0.5, - text: "Zieltemperatur", - icon: svg(icons.mdiOilTemperature), - topic: `heater${name}Tsoll`, - marks: [ - { value: 3, label: "3°C" }, - { value: 22, label: "22°C" }, - { value: 33, label: "33°C" } - ] - }, - { - type: "text", - text: "Window open mode till", - icon: svg(icons.mdiSortClockAscending), - topic: `heater${name}WindowEnd`, - }, - { - type: "text", - text: "Boost mode till", - icon: svg(icons.mdiSortClockDescending), - topic: `heater${name}BoostEnd`, - } -]); - -const config: Config = { - space: { - name: "Home", - color: "teal", - mqtt: "ws://192.168.0.12:1884" - }, - topics: [ - { - ...topicBulbHomeRust("livingroom", "r"), - ...topicBulbHomeRust("livingroom", "g"), - ...topicBulbHomeRust("livingroom", "b"), - ...topicBulbHomeRust("livingroom", "h"), - ...topicBulbHomeRust("livingroom", "s"), - ...topicBulbHomeRust("livingroom", "v"), - ...topicBulbHomeRust("livingroom", "x"), - ...topicBulbHomeRust("livingroom", "y"), - ...topicBulbHomeRust("livingroom", "animation-speed"), - ...topicBulbHomeRust("livingroom", "mode"), - ...topicBulbNumber("livingroom", "brightness"), - ...topicBulbState("livingroom"), - - ...topicBulbHomeRust("ledstrip_livingroom", "r"), - ...topicBulbHomeRust("ledstrip_livingroom", "g"), - ...topicBulbHomeRust("ledstrip_livingroom", "b"), - ...topicBulbHomeRust("ledstrip_livingroom", "h"), - ...topicBulbHomeRust("ledstrip_livingroom", "s"), - ...topicBulbHomeRust("ledstrip_livingroom", "v"), - ...topicBulbHomeRust("ledstrip_livingroom", "x"), - ...topicBulbHomeRust("ledstrip_livingroom", "y"), - ...topicBulbNumber("ledstrip_livingroom", "brightness"), - ...topicBulbState("ledstrip_livingroom"), - - ...topicBulbHomeRust("office", "r"), - ...topicBulbHomeRust("office", "g"), - ...topicBulbHomeRust("office", "b"), - ...topicBulbHomeRust("office", "h"), - ...topicBulbHomeRust("office", "s"), - ...topicBulbHomeRust("office", "v"), - ...topicBulbHomeRust("office", "x"), - ...topicBulbHomeRust("office", "y"), - ...topicBulbNumber("office", "brightness"), - ...topicBulbNumber("office", "color_temp"), - ...topicBulbState("office"), - - - ...topicBulbNumber("bedroom", "brightness"), - ...topicBulbNumber("bedroom", "color_temp"), - ...topicBulbState("bedroom"), - - ...topicGroupNumber("kitchen", "brightness"), - ...topicGroupNumber("kitchen", "color_temp"), - ...topicGroupState("kitchen"), - - ...topicBulbNumber("office_window", "brightness"), - ...topicBulbNumber("office_window", "color_temp"), - ...topicBulbState("office_window"), - - ...topicBulbNumber("3d_printer", "brightness"), - ...topicBulbState("3d_printer"), - - ...topicBulbNumber("hallway", "brightness"), - ...topicBulbState("hallway"), - - ...topicBulbNumber("hallway2", "brightness"), - ...topicBulbState("hallway2"), - - ...topicBulbNumber("ledstrip_storeroom", "brightness"), - ...topicBulbState("ledstrip_storeroom"), - - ...topicBulbNumber("diningroom", "brightness"), - ...topicBulbState("diningroom"), - - ...topicZigbeeNumber("officeBlindLeft", "blinds_office_left", "position"), - ...topicZigbeeNumber("officeBlindRight", "blinds_office_right", "position"), - ...topicHomeBoolean("officeBlindsVirtualZero", "office-blinds-virtual-zero-position", - true), - - ...topicTasmota("speakerOffice", "sonoff-office-speaker"), - ...topicHomeBoolean("officeSwitchPollingActive", "switch/office/polling", - true), - - ...topicBoolean("wledOfficeAuto", "wled/office/automatic"), - - ...topicTasmota("fanBedroom", "sonoff-bedroom-fan"), - ...topicTasmota("fanOffice", "sonoff-office-fan"), - ...topicTasmota("tasmotaProjector", "tasmota-projector"), - ...topicTasmota("tasmotaDishwasher", "tasmota-dishwasher"), - ...topicTasmotaPower("tasmotaDishwasher", "tasmota-dishwasher"), - ...topicHomeBoolean("fanBedroomAuto", "temperature-control/bedroom"), - ...topicHomeBoolean("fanOfficeAuto", "temperature-control/office"), - ...topicHomeNumber("fanBedroomTarget", - "temperature-control/bedroom/target", 21.5), - ...topicHomeNumber("fanOfficeTarget", - "temperature-control/office/target", 21.5), - - ...topicHomeNumber("heaterOfficeTarget", - "temperature-control/office_heating/target", 21.5), - ...topicHomeBoolean("heaterOfficeAuto", - "temperature-control/office_heating"), - ...topicHomeBoolean("heaterOfficeSelfControl", - "temperature-control/office_heating/self_control"), - - ...topicHomeNumber("heaterLivingroomTarget", - "temperature-control/livingroom_heating/target", 21.5), - ...topicHomeBoolean("heaterLivingroomAuto", - "temperature-control/livingroom_heating"), - - ...topicHomeBoolean("livingroomKodiControlled", - "bulb/livingroom/kodi-controlled"), - ...topicHomeBoolean("projectorControlsSoundbar", - "projector-controls-soundbar", true), - ...topicHomeBoolean("bedroomWakeup", "wakeup"), - ...topicHomeBoolean("lueftenHint", "lueften"), - ...topicHomeBoolean("windowOpenWarning", "window_open_warning", true), - ...topicHomeBoolean("printerLight", - "bulb/bulb_3d_printer/auto"), - ...topicHomeNumber("temperatureWarningKitchen", - "temperature-warning/kitchen/setpoint", 15.0), - ...topicHomeNumber("temperatureWarningOffice", - "temperature-warning/office/setpoint", 15.0), - ...topicHomeNumber("temperatureWarningBedroom", - "temperature-warning/bedroom/setpoint", 15.0), - - ...topicZigbeeState("powerFountain", "power_fountain"), - - temperatureKitchen: { - state: { - name: "tele/sonoff-kittchen/SENSOR", - type: types.json("DS18B20-5674FF.Temperature") - //type: types.json("$..[?(@.Address==\"28FF7456B5013CBB\")].Temperature") - }, - defaultValue: "0" - }, - nasPower: { - state: { - name: "nas/online", - type: types.string - }, - command: { - name: "home-rust/wake/nas", - type: types.string - }, - defaultValue: "OFF" - }, - - ...topicHeating("diningroom"), - ...topicHeating("bedroom"), - ...topicHeating("office"), - - heaterBedroomSummermode: { - state: { - name: "tele/home-rust/fritzbox/device/bedroom", - type: types.json("summeractive") - }, - defaultValue: "1" - }, - heaterOfficeNachtabsenkung: { - state: { - name: "home-rust/temperature-control/office_heating/heat_request/4", - type: types.option({ true: "off", false: "on" }) - }, - command: { - name: "home-rust/temperature-control/office_heating/heat_request/4", - type: types.option({ off: "true", on: "false" }) - }, - defaultValue: "on" - }, - tucanaPower: { - state: { - name: "home-rust/switch/office/8", - type: types.option({ - "0": "Link Down", - "6": "1000M", - "5": "100M", - "4": "100M (Half Duplex)", - "3": "10M", - "2": "10M (Half Duplex)" - }) - }, - command: { - name: "home-rust/wake/tucana", - type: types.string - }, - defaultValue: "0" - }, - tasmotaProjectorAutoOff: { - state: { - name: "tele/tasmota-projector/auto-off", - type: types.option({ OFF: "off", ON: "on" }) - }, - command: { - name: "cmnd/tasmota-projector/backlog", - type: types.option({ - off: "Rule2 off; RuleTimer1 0; Publish2 tele/tasmota-projector/auto-off OFF;", - on: "Rule2 on; Publish2 tele/tasmota-projector/auto-off ON;" - }) - }, - defaultValue: "on" - }, - printer3DProgresss: { - state: { - name: "tele/octoPrint/progress/printing", - type: (msg) => JSON.parse(msg.toString()).printer_data.progress.completion || "0" - }, - defaultValue: "0" - }, - printer3Dremaining: { - state: { - name: "tele/octoPrint/progress/printing", - type: (msg) => { - const json = JSON.parse(msg.toString()); - if (!json) { - return "unavailable"; - } - const secondsLeft = json.printer_data.progress.printTimeLeft; - return new Date(secondsLeft * 1000).toISOString().substr(11, 8); - } - }, - defaultValue: "unavailable" - }, - kodi: { - state: { - name: "kodi/connected", - type: types.string - }, - command: { - name: "kodi/command/shutdown", - type: types.string - }, - defaultValue: "0" - }, - wled_livingroom_brightness: { - state: { - name: "wled/livingroom/g", - type: types.string - }, - command: { - name: "wled/livingroom", - type: types.string - }, - defaultValue: "0" - }, - wled_office_brightness: { - state: { - name: "wled/office/g", - type: types.string - }, - command: { - name: "wled/office", - type: types.string - }, - defaultValue: "0" - }, - wled_office_lwt: { - state: { - name: "home-rust/led-strip-office/lwt", - type: types.string - }, - defaultValue: "unknown" - }, - twitch_status_uwap: { - state: { - name: "tele/twitch/uwap", - type: (msg) => { return msg.toString().endsWith("off") ? "off" : "on"; } - }, - defaultValue: "off" - }, - tadpole_freshness: { - state: { - name: "stat/tadpole/freshness", - type: types.string - }, - defaultValue: "unkown" - }, - tadpole_mic: { - state: { - name: "stat/tadpole/mic", - type: types.string - }, - defaultValue: "unkown" - }, - tadpole_webcam: { - state: { - name: "stat/tadpole/webcam", - type: types.string - }, - defaultValue: "unkown" - }, - livingroomSoundbarPower: { - state: { - name: "media/cec/5", - type: types.option({ off: "off", on: "on" }) - }, - command: { - name: "media/cec/5/cmd", - type: types.option({ off: "off", on: "on" }) - }, - defaultValue: "off" - }, - livingroomSoundbarHDMI: { - command: { - name: "media/cec/tx", - type: types.option({ off: "1f:82:11:00", on: "1f:82:11:00" }) - }, - defaultValue: "off" - }, - livingroomSoundbarVolume: { - state: { - name: "media/cec/volume", - type: types.string - }, - command: { - name: "media/cec/volume/set", - type: types.string - }, - defaultValue: "0" - } - } - ], - controls: { - bedroomLight: { - name: "Schlafzimmer", - position: [180, 130], - icon: svg(icons.mdiCeilingLight).color(({bedroomState}) => - (bedroomState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "bedroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "bedroombrightness" - }, - { - type: "toggle", - topic: "bedroomWakeup", - text: "Lichtwecker", - icon: svg(icons.mdiWeatherSunsetUp) - }, - { - type: "slider", - min: 250, - max: 454, - text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), - topic: "bedroomcolor_temp" - } - ] - }, - bedroomFan: { - name: "Lüftung/Heizung Schlafzimmer", - position: [140, 25], - icon: withState((s) => ( - s["heaterBedroomSummermode"] === "1" ? - - //Sommermodus => Lüftungsstatus anzeigen - svg(icons.mdiFan).color(({fanBedroomState}) => - (fanBedroomState === "on" ? hex("#00FF00") : hex("#000000"))) - - //Wintermodus => Heizungsstatus anzeigen - : s["heaterbedroomTsoll"] === "126.5" ? - //Solltemperatur == aus - svg(icons.mdiRadiatorDisabled) - //Normalbetrieb - : svg(icons.mdiRadiator) - )), - ui: [ - { - type: "section", - text: "Lüftung" - }, - { - type: "toggle", - topic: "fanBedroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "fanBedroomAuto", - text: "Automatik", - icon: svg(icons.mdiAirConditioner) - }, - { - type: "slider", - min: 15, - max: 25, - step: 0.1, - text: "Zieltemperatur", - icon: svg(icons.mdiOilTemperature), - topic: "fanBedroomTarget", - marks: [ - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" }, - { value: 25, label: "25°C" } - ] - }, - { - type: "section", - text: "Heizung" - }].concat(radiatorUI("bedroom")) - }, - officeSpeaker: { - name: "Lautsprecher", - position: [245, 658], - icon: withState(({speakerOfficeState}) => - (speakerOfficeState !== "on" ? svg(icons.mdiVolumeOff) - : svg(icons.mdiVolumeHigh).color(hex("#00FF00"))) - ), - ui: [ - { - type: "toggle", - topic: "speakerOfficeState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - } - ] - }, - officeBlinds: { - name: "Jalousien Büro", - position: [170,658], - icon: withState((s) => ( - (parseInt(s["officeBlindLeftposition"]) <= 9 && - parseInt(s["officeBlindRightposition"]) <= 9) ? - svg(icons.mdiBlindsOpen) : - svg(icons.mdiBlinds) - )), - ui: [ - { - type: "slider", - min: 0, - max: 100, - step: 1, - text: "Links", - icon: svg(icons.mdiArrowUpDown), - topic: "officeBlindLeftposition", - marks: [ - { value: 100, label: "Unten" }, - { value: 0, label: "Oben" }, - { value: 61, label: "Meow" } - ] - }, - { - type: "slider", - min: 0, - max: 100, - step: 1, - text: "Rechts", - icon: svg(icons.mdiArrowUpDown), - topic: "officeBlindRightposition", - marks: [ - { value: 100, label: "Unten" }, - { value: 0, label: "Oben" }, - { value: 69, label: "Meow" } - ] - }, - { - type: "toggle", - topic: "officeBlindsVirtualZero", - text: "Hide Holes Mode", - icon: svg(icons.mdiBlindsOpen) - } - ], - }, - officeFan: { - name: "Lüftung/Heizung Büro", - position: [140, 658], - icon: withState(({heaterOfficeAuto}) => ( - - heaterOfficeAuto === "on" ? - - svg(icons.mdiRadiator).color(({heaterofficeTsoll}) => - (heaterofficeTsoll === "127" ? hex("#FF0000") : hex("#000000"))) - - : svg(icons.mdiFan).color(({fanOfficeState}) => - (fanOfficeState === "on" ? hex("#00FF00") : hex("#000000"))) - )), - ui: [ - { - type: "section", - text: "Lüftung" - }, - { - type: "toggle", - topic: "fanOfficeState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "fanOfficeAuto", - text: "Automatik", - icon: svg(icons.mdiAirConditioner) - }, - { - type: "slider", - min: 15, - max: 25, - step: 0.1, - text: "Zieltemperatur", - icon: svg(icons.mdiOilTemperature), - topic: "fanOfficeTarget", - marks: [ - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" }, - { value: 25, label: "25°C" } - ] - }, - { - type: "section", - text: "Heizung (Automatik)" - }, - { - type: "toggle", - topic: "heaterOfficeAuto", - text: "Automatik", - icon: svg(icons.mdiRadiator) - }, - { - type: "toggle", - topic: "heaterOfficeNachtabsenkung", - text: "Nachtabsekung", - icon: svg(icons.mdiWeatherNight) - }, - { - type: "toggle", - topic: "heaterOfficeSelfControl", - text: "Run control on valve", - icon: svg(icons.mdiRadiator) - }, - { - type: "slider", - min: 15, - max: 25, - step: 0.1, - text: "Zieltemperatur", - icon: svg(icons.mdiOilTemperature), - topic: "heaterOfficeTarget", - marks: [ - { value: 15, label: "15°C" }, - { value: 21.5, label: "21.5°C" }, - { value: 25, label: "25°C" } - ] - }, - { - type: "section", - text: "Heizung (Manuell)" - }].concat(radiatorUI("office")) - }, - tucana: { - name: "tucana", - position: [110, 658], - icon: svg(icons.mdiDesktopTower).color(({tucanaPower}) => - ({ - "Link Down": hex("#888888"), - "1000M": hex("#00ff00"), - "10M": hex("#000000") - })[tucanaPower] || hex("#ff0000")), - ui: [ - { - type: "toggle", - topic: "tucanaPower", - text: "Einschalten", - icon: svg(icons.mdiPower), - on: "1000M" - }, - { - type: "text", - text: "Link Speed", - icon: svg(icons.mdiEthernet), - topic: "tucanaPower" - } - ] - }, - officeSwitch: { - name: "Switch Büro", - position: [280, 658], - icon: svg(icons.mdiLan), - ui: [ - { - type: "toggle", - topic: "officeSwitchPollingActive", - text: "Poll switch status", - icon: svg(icons.mdiPower) - }, - { - type: "link", - link: "http://192.168.0.189/", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - } - - ] - }, - officeLight: { - name: "Büro", - position: [210, 570], - icon: svg(icons.mdiCeilingLight).color(({officeState}) => - (officeState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: ([ - { - type: "toggle", - topic: "officeState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "officebrightness" - }, - { - type: "slider", - min: 250, - max: 454, - text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), - topic: "officecolor_temp" - }, - { - type: "section", - text: "RGB" - } - ]).concat(sliderRGB("office", "r")) - .concat(sliderRGB("office", "g")) - .concat(sliderRGB("office", "b")) - .concat([ - { - type: "section", - text: "HSV" - } - ]).concat(sliderH("office", "h")) - .concat(sliderSVXY("office", "s")) - .concat(sliderSVXY("office", "v")) - .concat([ - { - type: "section", - text: "XY" - } - ]).concat(sliderSVXY("office", "x")) - .concat(sliderSVXY("office", "y")) - .concat([ - { - type: "link", - link: "http://192.168.0.12:8080/#/device/0x0c4314fffe9bc8c1/exposes", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - } - ]) - }, - officeLedStripWled: { - name: "Ledstreifen Büro", - position: [316, 570], - /* eslint-disable camelcase */ - icon: svg(icons.mdiWhiteBalanceIridescent).color( - ({wled_office_brightness}) => - (wled_office_brightness !== "0" ? hex("#00FF00") : hex("#000000"))), - /* eslint-enable camelcase */ - ui: ([ - { - type: "toggle", - topic: "wled_office_brightness", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower), - on: "107", - off: "0", - toggled: (n) => parseInt(n, 10) > 0 - }, - { - type: "toggle", - topic: "wledOfficeAuto", - text: "Automatik", - icon: svg(icons.mdiAutoDownload) - }, - { - type: "slider", - min: 1, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "wled_office_brightness" - }, - { - type: "text", - text: "Status", - icon: svg(icons.mdiRefresh), - topic: "wled_office_lwt" - }, - { - type: "link", - link: "http://192.168.0.66/", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - } - ]) - }, - hallwayLight: { - name: "Flur", - position: [520, 370], - icon: svg(icons.mdiCeilingLight).color(({hallwayState}) => - (hallwayState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "hallwayState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "hallwaybrightness" - } - ] - }, - hallway2Light: { - name: "Flur", - position: [250, 370], - icon: withState((s) => ( - svg(icons.mdiCeilingLight).color( - s["hallway2State"] === "on" ? - (s["tadpole_webcam"] == "on" ? hex("#FF0000") : s["tadpole_mic"] == "on" ? hex("#0000FF") : s["twitch_status_uwap"] === "on" ? hex("#FF00FF") : hex("#00FF00")) - : - (s["tadpole_webcam"] == "on" ? hex("#990000") : s["tadpole_mic"] == "on" ? hex("#000099") : s["twitch_status_uwap"] === "on" ? hex("#990099") : hex("#000000")) - ))), - ui: [ - { - type: "toggle", - topic: "hallway2State", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "hallway2brightness" - }, - { - type: "text", - text: "Twitch Uwap", - icon: svg(icons.mdiTwitch), - topic: "twitch_status_uwap" - }, - { - type: "section", - text: "Laptop tadpole" - }, - { - type: "text", - text: "Datenstand", - icon: svg(icons.mdiRefresh), - topic: "tadpole_freshness" - }, - { - type: "text", - text: "Mikrofon", - icon: svg(icons.mdiMicrophone), - topic: "tadpole_mic" - }, - { - type: "text", - text: "Webcam", - icon: svg(icons.mdiVideo), - topic: "tadpole_webcam" - } - ] - }, - dishwasher: { - name: "Spülmaschine", - position: [575, 449], - icon: withState((s) => ( - ( s["tasmotaDishwasherState"] === "off" ) - ? svg(icons.mdiDishwasherOff) - : - ( parseFloat(s["tasmotaDishwasherPower"]) - < 2 - ) - ? svg(icons.mdiDishwasherAlert).color(hex("#FF8700")) - : svg(icons.mdiDishwasher).color(hex("#00FF00")) - )), - ui: [ - { - type: "toggle", - topic: "tasmotaDishwasherState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "text", - text: "Stromverbrauch (W)", - icon: svg(icons.mdiPowerSocketDe), - topic: "tasmotaDishwasherPower" - }, - ] - }, - temperatureWarningKitchen: { - name: "Untertemperatur-Warnung", - position: [625, 660], - icon: withState((s) => ( - - ( parseFloat(s["temperatureKitchen"]) - < parseFloat(s["temperatureWarningKitchen"]) - ) - ? svg(icons.mdiThermometerAlert).color(hex("#FF0000")) - : svg(icons.mdiThermometer) - )), - ui: [ - { - type: "text", - text: "Istwert:", - icon: svg(icons.mdiThermometer), - topic: "temperatureKitchen" - }, - { - type: "slider", - min: 0, - max: 20, - step: 1, - text: "Schwellwert", - icon: svg(icons.mdiThermometerChevronDown), - topic: "temperatureWarningKitchen", - marks: [ - { value: 0, label: "0°C" }, - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" } - ] - }, - { - type: "toggle", - topic: "windowOpenWarning", - text: "Fenster Offen Warnung", - icon: svg(icons.mdiWindowOpenVariant) - }, - ] - }, - diningroomLight: { - name: "Esszimmer", - position: [410, 570], - icon: svg(icons.mdiCeilingLight).color(({diningroomState}) => - (diningroomState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "diningroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "diningroombrightness" - } - ] - }, - kitchenLight: { - name: "Küche", - position: [550, 570], - icon: svg(icons.mdiCeilingLight).color(({kitchenState}) => - (kitchenState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "kitchenState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "kitchenbrightness" - }, - { - type: "slider", - min: 250, - max: 454, - text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), - topic: "kitchencolor_temp" - } - ] - }, - diningroomHeater: { - name: "Heizung Esszimmer", - position: [410, 658], - icon: withState(({heaterdiningroomTsoll}) => ( - heaterdiningroomTsoll === "126.5" ? - svg(icons.mdiRadiatorDisabled) : svg(icons.mdiRadiator) - )), - ui: [ - { - type: "section", - text: "Heizung (Automatik)" - }, - { - type: "toggle", - topic: "heaterLivingroomAuto", - text: "Automatik", - icon: svg(icons.mdiRadiator) - }, - { - type: "slider", - min: 15, - max: 25, - step: 0.1, - text: "Zieltemperatur", - icon: svg(icons.mdiOilTemperature), - topic: "heaterLivingroomTarget", - marks: [ - { value: 15, label: "15°C" }, - { value: 21.5, label: "21.5°C" }, - { value: 25, label: "25°C" } - ] - }, - { - type: "section", - text: "Heizung (Manuell)" - }, - ] . concat(radiatorUI("diningroom")) - }, - pi: { - name: "Pi", - position: [550, 75], - icon: svg(icons.mdiRaspberryPi), - ui: [ - { - type: "toggle", - topic: "lueftenHint", - text: "Lüften Erinnerung", - icon: svg(icons.mdiFan) - }, - { - type: "link", - link: "http://192.168.0.12:3000/", - text: "Grafana", - icon: svg(icons.mdiOpenInNew) - }, - { - type: "link", - link: "http://192.168.0.12:1780/", - text: "Snapcast", - icon: svg(icons.mdiOpenInNew) - }, - { - type: "link", - link: "http://carina.fritz.box:9981/", - text: "tvheadend", - icon: svg(icons.mdiOpenInNew) - }, - { - type: "section", - text: "Kälte-Warnung" - }, - { - type: "slider", - min: 0, - max: 20, - step: 1, - text: "Küche", - icon: svg(icons.mdiThermometerChevronDown), - topic: "temperatureWarningKitchen", - marks: [ - { value: 0, label: "0°C" }, - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" } - ] - }, - { - type: "slider", - min: 0, - max: 20, - step: 1, - text: "Büro", - icon: svg(icons.mdiThermometerChevronDown), - topic: "temperatureWarningOffice", - marks: [ - { value: 0, label: "0°C" }, - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" } - ] - }, - { - type: "slider", - min: 0, - max: 20, - step: 1, - text: "Schlafzimmer", - icon: svg(icons.mdiThermometerChevronDown), - topic: "temperatureWarningBedroom", - marks: [ - { value: 0, label: "0°C" }, - { value: 15, label: "15°C" }, - { value: 20, label: "20°C" } - ] - }, - ] - }, - nas: { - name: "NAS", - position: [310, 500], - icon: svg(icons.mdiNas).color(({nasPower}) => - (nasPower === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "nasPower", - text: "Einschalten", - icon: svg(icons.mdiPower), - } - ] - }, - officeWindowLight: { - name: "Büro Fenster", - position: [310, 658], - /* eslint-disable camelcase */ - icon: svg(icons.mdiDeskLamp).color(({office_windowState}) => - (office_windowState === "on" ? hex("#00FF00") : hex("#000000"))), - /* eslint-enable camelcase */ - ui: [ - { - type: "section", - text: "Beleuchtung" - }, - { - type: "toggle", - topic: "office_windowState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "office_windowbrightness" - }, - { - type: "slider", - min: 250, - max: 454, - text: "Farbtemperatur", - icon: svg(icons.mdiWeatherSunsetDown), - topic: "office_windowcolor_temp" - }, - ] - }, - printer3D: { - name: "3D-Drucker", - position: [310, 430], - icon: svg(icons.mdiPrinter3d), - ui: [ - { - type: "link", - link: "http://octopi.fritz.box/", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - }, - { - type: "section", - text: "Current Job" - }, - { - type: "progress", - icon: svg(icons.mdiRotateRight), - min: 0, - max: 100, - text: "Printing Progress", - topic: "printer3DProgresss" - }, - { - type: "text", - text: "Time Left", - icon: svg(icons.mdiClock), - topic: "printer3Dremaining" - }, - { - type: "section", - text: "Beleuchtung" - }, - { - type: "toggle", - topic: "3d_printerState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "printerLight", - text: "Sync to 3D printer", - icon: svg(icons.mdiBrightnessAuto) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "3d_printerbrightness" - }, - ] - }, - storeRoomStrip: { - name: "LED-Leisten Lager", - position: [310, 465], - icon: svg(icons.mdiWhiteBalanceIridescent), - icon: svg(icons.mdiWhiteBalanceIridescent).color(({ledstrip_storeroomState}) => - (ledstrip_storeroomState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "ledstrip_storeroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "ledstrip_storeroombrightness" - } - ] - }, - projector: { - name: "Beamer", - position: [410, 230], - icon: svg(icons.mdiProjector).color(({tasmotaProjectorState}) => - (tasmotaProjectorState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: [ - { - type: "toggle", - topic: "tasmotaProjectorState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "tasmotaProjectorAutoOff", - text: "Automatik", - icon: svg(icons.mdiAutoDownload) - }, - { - type: "section", - text: "Kodi" - }, - { - type: "toggle", - topic: "kodi", - text: "Kodi herunterfahren", - icon: svg(icons.mdiPower), - on: "2", - off: "0", - }, - { - type: "link", - link: "http://192.168.0.10:8080/", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - } - ] - }, - livingroomLight: { - name: "Wohnzimmer", - position: [450, 200], - icon: svg(icons.mdiCeilingLight).color(({livingroomState}) => - (livingroomState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: ([ - { - type: "toggle", - topic: "livingroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "livingroomKodiControlled", - text: "Kodi Einbindung", - icon: svg(icons.mdiBrightnessAuto) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - marks: [ - { value: 1, label: "Dunkel" }, - { value: 120, label: "Medium" }, - { value: 254, label: "Hell" } - ], - icon: svg(icons.mdiBrightness7), - topic: "livingroombrightness" - }, - { - type: "slider", - max: 1, - min: 300, - step: -1, - text: "Speed", - icon: svg(icons.mdiSpeedometer), - topic: "livingroomanimation-speed" - }, - { - type: "dropDown", - text: "Modus", - topic: "livingroommode", - options: { - "-1": "Cancel Animation", - "0": "Pink", - "1": "Kodi", - "2": "Sleep", - "3": "RGB Fade", - "4": "Work", - "5": "Winter" - }, - icon: svg(icons.mdiCog) - }, - { - type: "section", - text: "RGB" - } - ]).concat(sliderRGB("livingroom", "r")) - .concat(sliderRGB("livingroom", "g")) - .concat(sliderRGB("livingroom", "b")) - .concat([ - { - type: "section", - text: "HSV" - } - ]).concat(sliderH("livingroom", "h")) - .concat(sliderSVXY("livingroom", "s")) - .concat(sliderSVXY("livingroom", "v")) - .concat([ - { - type: "section", - text: "XY" - } - ]).concat(sliderSVXY("livingroom", "x")) - .concat(sliderSVXY("livingroom", "y")) - }, - livingroomLedStrip: { - name: "Ledstreifen Wohnzimmer", - position: [450, 73], - /* eslint-disable camelcase */ - icon: svg(icons.mdiWhiteBalanceIridescent).color( - ({ledstrip_livingroomState}) => - (ledstrip_livingroomState === "on" ? hex("#00FF00") : hex("#000000"))), - /* eslint-enable camelcase */ - ui: ([ - { - type: "toggle", - topic: "ledstrip_livingroomState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "slider", - min: 0, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "ledstrip_livingroombrightness" - }, - { - type: "dropDown", - text: "Modus", - topic: "livingroommode", - options: { - "-1": "Cancel Animation", - "0": "Pink", - "1": "Kodi", - "2": "Sleep", - "3": "RGB Fade", - "4": "Work", - "5": "Winter" - }, - icon: svg(icons.mdiCog) - }, - { - type: "section", - text: "RGB" - } - ]).concat(sliderRGB("ledstrip_livingroom", "r")) - .concat(sliderRGB("ledstrip_livingroom", "g")) - .concat(sliderRGB("ledstrip_livingroom", "b")) - .concat([ - { - type: "section", - text: "HSV" - } - ]).concat(sliderH("ledstrip_livingroom", "h")) - .concat(sliderSVXY("ledstrip_livingroom", "s")) - .concat(sliderSVXY("ledstrip_livingroom", "v")) - .concat([ - { - type: "section", - text: "XY" - } - ]).concat(sliderSVXY("ledstrip_livingroom", "x")) - .concat(sliderSVXY("ledstrip_livingroom", "y")) - }, - livingroomFountain: { - name: "Brunnen Wohnzimmer", - position: [550, 240], - icon: svg(icons.mdiFountain).color( - ({powerFountainState}) => - (powerFountainState === "on" ? hex("#00FF00") : hex("#000000"))), - ui: ([ - { - type: "toggle", - topic: "powerFountainState", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - ]), - }, - livingroomSoundbar: { - name: "Soundbar Wohnzimmer", - position: [550, 200], - icon: svg(icons.mdiSpeaker).color( - ({livingroomSoundbarPower}) => - (livingroomSoundbarPower === "on" ? hex("#00FF00") : hex("#000000"))), - ui: ([ - { - type: "toggle", - topic: "livingroomSoundbarPower", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower) - }, - { - type: "toggle", - topic: "livingroomSoundbarHDMI", - text: "Input: HDMI", - icon: svg(icons.mdiVideoInputHdmi) - }, - { - type: "slider", - min: 0, - max: 100, - text: "Lautstärke", - icon: svg(icons.mdiVolumeHigh), - topic: "livingroomSoundbarVolume" - }, - { - type: "toggle", - topic: "projectorControlsSoundbar", - text: "Projector Controlled", - icon: svg(icons.mdiProjector) - }, - ]) - }, - livingroomLedStripWled: { - name: "Ledstreifen Wohnzimmer", - position: [550, 160], - /* eslint-disable camelcase */ - icon: svg(icons.mdiWhiteBalanceIridescent).color( - ({wled_livingroom_brightness}) => - (wled_livingroom_brightness !== "0" ? hex("#00FF00") : hex("#000000"))), - /* eslint-enable camelcase */ - ui: ([ - { - type: "toggle", - topic: "wled_livingroom_brightness", - text: "Ein/Ausschalten", - icon: svg(icons.mdiPower), - on: "107", - off: "0", - toggled: (n) => parseInt(n, 10) > 0 - }, - { - type: "slider", - min: 1, - max: 255, - text: "Helligkeit", - icon: svg(icons.mdiBrightness7), - topic: "wled_livingroom_brightness" - }, - { - type: "link", - link: "http://192.168.0.61/", - text: "Open Webinterface", - icon: svg(icons.mdiOpenInNew) - } - ]) - } - }, - layers: [ - { - image: require("./assets/layers/rooms.svg"), - baseLayer: true, - name: "Rooms", - defaultVisibility: "visible", - opacity: 0.7, - bounds: { - topLeft: [0, 0], - bottomRight: [720, 680] - } - } - ] -}; - -window.config = config; diff --git a/index.ejs b/index.ejs index af4cf0c..bede683 100644 --- a/index.ejs +++ b/index.ejs @@ -2,6 +2,7 @@ + <%= htmlWebpackPlugin.options.title %> diff --git a/package.json b/package.json index e3281c7..593abcf 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "mqtt-control-map", "version": "1.0.0", - "author": "uwap ", - "description": "Control Devices via mqtt, visualized on a Map", + "author": "uwap ", + "description": "control devices via mqtt on a beautiful map of your space", "scripts": { - "build": "webpack --bail --config webpack.config.js --mode production --env", + "build": "webpack --bail --config webpack.config.js -p --env", "dev": "webpack --bail --config webpack.config.js --mode development --env", "watch": "webpack-dev-server --open --config webpack.config.js --mode development --env", "travis": "./travis.sh", @@ -12,52 +12,45 @@ "precommit": "yarn lint" }, "dependencies": { - "@emotion/react": "^11.10.5", - "@emotion/styled": "^11.10.5", - "@fontsource/roboto": "^4.5.8", - "@mdi/react": "^1.4.0", - "@mui/material": "^5.10.15", - "@mui/styles": "^5.10.15", - "leaflet": "^1.5.1", - "mqtt": "^4.2.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-leaflet": "^4.1.0" + "@material-ui/core": "^3.0.1", + "@material-ui/lab": "^3.0.0-alpha.16", + "@mdi/font": "^3.0.39", + "leaflet": "^1.3.1", + "lodash-es": "^4.17.4", + "mqtt": "^2.14.0", + "react": "^16.0.0", + "react-dom": "^16.0.0", + "react-leaflet": "^2.0.0", + "redux": "^3.7.2" }, "devDependencies": { - "@babel/cli": "^7.5.5", - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-class-properties": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/preset-env": "^7.5.5", + "@babel/cli": "^7.0.0-rc.1", + "@babel/core": "^7.0.0-rc.1", + "@babel/plugin-proposal-class-properties": "^7.0.0-rc.1", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0-rc.1", + "@babel/polyfill": "^7.0.0-rc.1", + "@babel/preset-env": "^7.0.0-rc.1", "@babel/preset-flow": "^7.0.0-rc.1", "@babel/preset-react": "^7.0.0-rc.1", - "@mdi/js": "^7.0.96", - "babel-eslint": "^10.0.2", - "babel-loader": "^9.1.0", - "buffer": "^6.0.3", - "clean-webpack-plugin": "^4.0.0", - "core-js": "^3.6.0", - "css-loader": "^6.7.2", - "eslint": "^8.28.0", - "eslint-plugin-flowtype": "^8.0.3", + "babel-eslint": "^10.0.0", + "babel-loader": "^8.0.0-beta", + "clean-webpack-plugin": "^2.0.0", + "css-loader": "^2.0.0", + "eslint": "^5.0.1", + "eslint-plugin-flowtype": "^3.0.0", "eslint-plugin-fp": "^2.3.0", - "eslint-plugin-react": "^7.14.3", - "eslint-plugin-react-hooks": "^4.1.2", - "file-loader": "^6.1.0", + "eslint-plugin-react": "^7.6.1", + "file-loader": "^3.0.0", "flow": "^0.2.3", - "flow-bin": "^0.193.0", - "flow-typed": "^3.2.1", - "html-webpack-plugin": "^5.5.0", - "husky": "^8.0.2", - "lodash-es": "^4.17.15", - "process": "^0.11.10", - "style-loader": "^3.3.1", - "url": "^0.11.0", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.0", - "webpack-dev-server": "^4.11.1", - "webpack-shell-plugin-next": "^2.3.1" + "flow-bin": "^0.101.0", + "flow-typed": "^2.3.0", + "html-webpack-plugin": "^3.1.0", + "husky": "^2.0.0", + "style-loader": "^0.23.0", + "webpack": "^4.3.0", + "webpack-cli": "^3.0.0", + "webpack-dev-server": "^3.1.1", + "webpack-shell-plugin": "^0.5.0" }, "license": "MIT" } diff --git a/src/components/App.js b/src/components/App.js index e40b018..6d8ed79 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -9,10 +9,13 @@ import throttle from "lodash/throttle"; import type { Config, Control, Topics } from "config/flowtypes"; -import { withStyles } from "@mui/styles"; -import Snackbar from "@mui/material/Snackbar"; -import IconButton from "@mui/material/IconButton"; -import Typography from "@mui/material/Typography"; +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 * as Colors from "@material-ui/core/colors"; +import Snackbar from "@material-ui/core/Snackbar"; +import IconButton from "@material-ui/core/IconButton"; +import Typography from "@material-ui/core/Typography"; import SideBar from "components/SideBar"; import ControlMap from "components/ControlMap"; @@ -36,14 +39,6 @@ export type AppState = { error: ?string }; -/* - *const App = (props: AppProps) => { - * const topics = Array.isArray(props.config.topics) ? - * Object.assign({}, ...props.config.topics) : props.config.topics; - * const [mqttConnected, setMqttConnected] = useState(false); - *}; - */ - class App extends React.PureComponent { controlMap: React.Node @@ -60,8 +55,7 @@ class App extends React.PureComponent { onDisconnect: () => this.setState({ mqttConnected: false }), subscribe: map( filter(keys(this.topics), (x) => this.topics[x].state != null), - (x) => (this.topics[x].state != null ? this.topics[x].state.name : "") - ) + (x) => this.topics[x].state.name) }), mqttConnected: false, search: "", @@ -100,6 +94,14 @@ class App extends React.PureComponent { }; } + static theme(config: Config) { + return createMuiTheme({ + palette: { + primary: Colors[config.space.color] + } + }); + } + receiveMessage(rawTopic: string, message: Buffer) { try { const topics = filter( @@ -113,8 +115,8 @@ class App extends React.PureComponent { for (let i in topics) { const topic = topics[i]; const stateTopic = this.topics[topic].state; - const typeConversion = stateTopic?.type?.from ?? stateTopic?.type; - const val = (typeConversion ?? ((x: Buffer) => x.toString()))(message); + const parseVal = stateTopic ? stateTopic.type : null; + const val = parseVal == null ? message.toString() : parseVal(message); this.setMqttStateDebounced( {mqttState: Object.assign({}, merge(this.state.mqttState, { [topic]: val}))}); @@ -134,16 +136,16 @@ class App extends React.PureComponent { this.setState({drawerOpened: false}); } - changeState = (topic: string, val: string) => { + changeState = (topic: string, value: string) => { try { - const commandTopic = this.topics[topic].command; - if (commandTopic == null) { + if (this.topics[topic].command == null) { return; } - const rawTopic = commandTopic.name; - const typeConversion = commandTopic?.type?.to ?? commandTopic.type; - const value = (typeConversion ?? Buffer.from)(val); - this.state.mqttSend(rawTopic, value); + const rawTopic = this.topics[topic].command.name; + const transformValue = this.topics[topic].command.type; + const val = + transformValue == null ? value : transformValue(Buffer.from(value)); + this.state.mqttSend(rawTopic, Buffer.from(val)); } catch (err) { this.setState({ error: err.toString() }); } @@ -168,7 +170,7 @@ class App extends React.PureComponent { control={this.state.selectedControl} onCloseRequest={this.closeDrawer} icon={this.state.selectedControl == null ? null : - this.state.selectedControl.icon.render(this.state.mqttState)} + this.state.selectedControl.icon(this.state.mqttState)} > {this.state.selectedControl == null || } @@ -202,6 +204,11 @@ class App extends React.PureComponent { } } - - -export default withStyles(App.styles)(App); +export default (props: AppProps) => { + const StyledApp = withStyles(App.styles)(App); + return ( + + + + ); +}; diff --git a/src/components/ControlMap.js b/src/components/ControlMap.js index e567e4c..6532002 100644 --- a/src/components/ControlMap.js +++ b/src/components/ControlMap.js @@ -1,15 +1,12 @@ // @flow import React from "react"; -import { MapContainer, ImageOverlay, Marker, LayersControl } from "react-leaflet"; +import { Map, ImageOverlay, Marker, LayersControl } from "react-leaflet"; import { CRS, point, divIcon } from "leaflet"; import map from "lodash/map"; import filter from "lodash/filter"; import reduce from "lodash/reduce"; import MqttContext from "mqtt/context"; -import type { - Controls, Control, UIControl, ControlUI, Layer -} from "config/flowtypes"; -import { renderToString } from "react-dom/server"; +import type { Controls, Control, UIControl, ControlUI } from "config/flowtypes"; export type Point = [number, number]; @@ -31,11 +28,21 @@ const center = (props: ControlMapProps): Point => props.height / 2 ]); +const iconColor = (control: Control, state: State): string => { + if (control.iconColor != null) { + return control.iconColor(state); + } + return "#000"; +}; + const createLeafletIcon = (control: Control, state: State) => { + const icon = control.icon(state); + const iconClass = `${icon} mdi-36px`; return divIcon({ iconSize: point(36, 36), iconAnchor: point(18, 18), - html: renderToString(control.icon.render(state)) + html: `` }); }; @@ -45,9 +52,7 @@ const renderMarker = (props: ControlMapProps) => {({ state }) => ( props.onChangeControl(control) - }} + onClick={() => props.onChangeControl(control)} > )} @@ -120,13 +125,13 @@ const renderLayers = (props: ControlMapProps) => ( ); const ControlMap = (props: ControlMapProps) => ( - {renderMarkers(props)} {renderLayers(props)} - + ); export default ControlMap; diff --git a/src/components/SideBar.js b/src/components/SideBar.js index 18092cd..8a2de0c 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -1,63 +1,62 @@ // @flow import * as React from "react"; -import { makeStyles } from "@mui/styles"; -import Drawer from "@mui/material/Drawer"; -import Typography from "@mui/material/Typography"; -import IconButton from "@mui/material/IconButton"; -import AppBar from "@mui/material/AppBar"; -import Toolbar from "@mui/material/Toolbar"; -import List from "@mui/material/List"; -import ReactIcon from "@mdi/react"; -import { mdiClose } from "@mdi/js"; +import withStyles from "@material-ui/core/styles/withStyles"; +import Drawer from "@material-ui/core/Drawer"; +import Typography from "@material-ui/core/Typography"; +import IconButton from "@material-ui/core/IconButton"; +import AppBar from "@material-ui/core/AppBar"; +import Toolbar from "@material-ui/core/Toolbar"; +import List from "@material-ui/core/List"; +import { renderRawIcon } from "config/icon"; +import type { RawIcon } from "config/icon"; import type { Control } from "config/flowtypes"; export type SideBarProps = { control: ?Control, open: boolean, onCloseRequest: () => void, - icon?: ?React.Node, + icon?: ?RawIcon, children?: React.Node }; -const useStyles = makeStyles((theme) => ({ +type Props = SideBarProps & Classes; + +const SideBar = (props: Props) => ( + + + + + {props.icon == null || renderRawIcon(props.icon, "mdi-36px")} + + + {props.control == null ? "" : props.control.name} + + + + + + + + {props.children} + + +); + +const styles = (theme) => ({ drawerPaper: { width: 340 }, title: { flex: 1, - marginLeft: theme.spacing(1) + marginLeft: theme.spacing.unit } -})); +}); -const SideBar = (props: SideBarProps) => { - const classes = useStyles(); - return ( - - - - - {props.icon == null || props.icon} - - - {props.control == null ? "" : props.control.name} - - - - - - - - {props.children} - - - ); -}; - -export default SideBar; +export default withStyles(styles)(SideBar); diff --git a/src/components/TopBar.js b/src/components/TopBar.js index b99a2a7..0510711 100644 --- a/src/components/TopBar.js +++ b/src/components/TopBar.js @@ -1,16 +1,14 @@ // @flow import React from "react"; -import AppBar from "@mui/material/AppBar"; -import Toolbar from "@mui/material/Toolbar"; -import CircularProgress from "@mui/material/CircularProgress"; -import InputBase from "@mui/material/InputBase"; -import { styled } from "@mui/styles"; -import { alpha } from "@mui/material/styles"; -import Tooltip from "@mui/material/Tooltip"; -import IconButton from "@mui/material/IconButton"; -import ReactIcon from "@mdi/react"; -import { mdiMap, mdiGithub, mdiMagnify } from "@mdi/js"; +import AppBar from "@material-ui/core/AppBar"; +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 Tooltip from "@material-ui/core/Tooltip"; +import IconButton from "@material-ui/core/IconButton"; export type TopBarProps = { connected: boolean, @@ -23,74 +21,89 @@ export type SearchBarProps = { const renderConnectionIndicator = (connected: boolean) => { if (connected) { - return (); + return (); } return ( ); }; -const Search = styled('div')(({ theme }) => ({ - position: 'relative', - borderRadius: theme.shape.borderRadius, - backgroundColor: alpha(theme.palette.common.white, 0.15), - '&:hover': { - backgroundColor: alpha(theme.palette.common.white, 0.25), - }, - marginRight: theme.spacing(2), - marginLeft: 0, - width: '100%', - [theme.breakpoints.up('sm')]: { - marginLeft: theme.spacing(3), - width: 'auto', - }, -})); - -const SearchIconWrapper = styled('div')(({ theme }) => ({ - padding: theme.spacing(0, 2), - height: '100%', - position: 'absolute', - pointerEvents: 'none', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', -})); - -const StyledInputBase = styled(InputBase)(({ theme }) => ({ - color: 'inherit', - '& .MuiInputBase-input': { - padding: theme.spacing(1, 1, 1, 0), - // vertical padding + font size from searchIcon - paddingLeft: `calc(1em + ${theme.spacing(4)})`, - transition: theme.transitions.create('width'), - width: '100%', - [theme.breakpoints.up('md')]: { - width: '20ch', +const searchStyles = (theme) => ({ + search: { + position: "relative", + borderRadius: theme.shape.borderRadius, + backgroundColor: fade(theme.palette.common.white, 0.15), + "&:hover": { + backgroundColor: fade(theme.palette.common.white, 0.25) }, + marginRight: theme.spacing.unit * 2, + marginLeft: 0, + width: "100%", + [theme.breakpoints.up("sm")]: { + marginLeft: theme.spacing.unit * 3, + width: "auto" + } }, -})); + searchIcon: { + width: theme.spacing.unit * 6, + height: "100%", + position: "absolute", + pointerEvents: "none", + display: "flex", + alignItems: "center", + justifyContent: "center", + fontSize: "24px" + }, + inputRoot: { + color: "inherit", + width: "100%" + }, + inputInput: { + paddingTop: theme.spacing.unit, + paddingRight: theme.spacing.unit, + paddingBottom: theme.spacing.unit, + paddingLeft: theme.spacing.unit * 6, + transition: theme.transitions.create("width"), + width: "100%", + [theme.breakpoints.up("md")]: { + width: 200 + } + } +}); + +const RawSearch = (props: SearchBarProps & Classes) => ( +
+ + props.onSearch(e.target.value)} + classes={{ + root: props.classes.inputRoot, + input: props.classes.inputInput + }} /> +
+); + +const Search = withStyles(searchStyles)(RawSearch); const openOnGithub = () => window.open( "https://github.com/uwap/mqtt-control-map", "_blank"); +const sendFeedback = () => window.open("mailto:mail+feedback@uwap.name"); + const TopBar = (props: TopBarProps) => ( - + {renderConnectionIndicator(props.connected)} - - - - - props.onSearch(e.target.value)} - /> - + - - - + + + + + + + + diff --git a/src/components/UiItemList.js b/src/components/UiItemList.js index d7c8313..dd256fd 100644 --- a/src/components/UiItemList.js +++ b/src/components/UiItemList.js @@ -1,6 +1,6 @@ // @flow import * as React from "react"; -import ListItem from "@mui/material/ListItem"; +import ListItem from "@material-ui/core/ListItem"; import type { ControlUI } from "config/flowtypes"; diff --git a/src/components/UiItems/DropDown.js b/src/components/UiItems/DropDown.js index 6f6677a..47f94e8 100644 --- a/src/components/UiItems/DropDown.js +++ b/src/components/UiItems/DropDown.js @@ -6,11 +6,11 @@ import { isDisabled, getValue } from "./utils"; import type { UIDropDown } from "config/flowtypes"; -import Select from "@mui/material/Select"; -import FormControl from "@mui/material/FormControl"; -import InputLabel from "@mui/material/InputLabel"; -import MenuItem from "@mui/material/MenuItem"; -import Input from "@mui/material/Input"; +import Select from "@material-ui/core/Select"; +import FormControl from "@material-ui/core/FormControl"; +import InputLabel from "@material-ui/core/InputLabel"; +import MenuItem from "@material-ui/core/MenuItem"; +import Input from "@material-ui/core/Input"; const componentId = (item: UIDropDown) => `dropdown-${item.topic}`; diff --git a/src/components/UiItems/Link.js b/src/components/UiItems/Link.js index 05bc2c4..506f86d 100644 --- a/src/components/UiItems/Link.js +++ b/src/components/UiItems/Link.js @@ -2,10 +2,11 @@ import React from "react"; import createComponent from "./base"; import { isEnabled, isDisabled } from "./utils"; +import { renderRawIcon } from "config/icon"; import type { UILink } from "config/flowtypes"; -import Button from "@mui/material/Button"; +import Button from "@material-ui/core/Button"; const followLink = (item, state) => () => { if (isEnabled(item, state)) { @@ -18,7 +19,7 @@ const Icon = ({item, state}) => { if (item.icon == null) { return false; } - return item.icon.render(state); + return renderRawIcon(item.icon(state), "mdi-24px"); }; const BaseComponent = (_h, item: UILink, state, _changeState) => ( diff --git a/src/components/UiItems/Progress.js b/src/components/UiItems/Progress.js index 445b922..6cebd81 100644 --- a/src/components/UiItems/Progress.js +++ b/src/components/UiItems/Progress.js @@ -5,7 +5,7 @@ import { getValue } from "./utils"; import type { UIProgress } from "config/flowtypes"; -import LinearProgress from "@mui/material/LinearProgress"; +import LinearProgress from "@material-ui/core/LinearProgress"; const progressVal = (item, state) => { const min = item.min || 0; diff --git a/src/components/UiItems/Section.js b/src/components/UiItems/Section.js index b23dd76..c03724f 100644 --- a/src/components/UiItems/Section.js +++ b/src/components/UiItems/Section.js @@ -4,7 +4,7 @@ import createComponent from "./base"; import type { UISection } from "config/flowtypes"; -import ListSubheader from "@mui/material/ListSubheader"; +import ListSubheader from "@material-ui/core/ListSubheader"; const BaseComponent = (_b, item: UISection, _state, _changeState) => ( {item.text} diff --git a/src/components/UiItems/Slider.js b/src/components/UiItems/Slider.js index 4b13b75..e3fceac 100644 --- a/src/components/UiItems/Slider.js +++ b/src/components/UiItems/Slider.js @@ -5,7 +5,7 @@ import { isDisabled, getValue } from "./utils"; import type { UISlider } from "config/flowtypes"; -import SliderComponent from "@mui/material/Slider"; +import SliderComponent from "@material-ui/lab/Slider"; const changeSliderValue = (item: UISlider, changeState) => (_e, v) => changeState(item, v.toString()); @@ -16,12 +16,10 @@ const BaseComponent = ({Icon, Label}, item, state, changeState) => (