diff --git a/config/entropia.js b/config/entropia.js index 36e25d9..ea6939a 100644 --- a/config/entropia.js +++ b/config/entropia.js @@ -1,6 +1,8 @@ // @flow import type { Config } from "config/flowtypes"; import { hex, rgb, rgba, rainbow } from "config/colors"; +import * as types from "config/types"; +import { mdi } from "config/icon"; import { esper_topics, esper_statistics } from "./utils"; const config : Config = { @@ -12,16 +14,18 @@ const config : Config = { topics: [ { hauptraum_table_light: { - command: "/public/sensoren/TPH/leinwand/control", - state: "test", - defaultValue: "A1 ON", - values: { on: "A1 ON", off: "A1 OFF" } + command: { + name: "/public/sensoren/TPH/leinwand/control", + type: types.option({ "A1 ON": "on", "A1 OFF": "off" }) + }, + defaultValue: "off" }, hauptraum_table_light_on_hack: { - command: "/public/sensoren/TPH/leinwand/control", - state: "test", - defaultValue: "A1 OFF", - values: { on: "A1 ON", off: "A1 OFF" } + command: { + name: "/public/sensoren/TPH/leinwand/control", + type: types.option({ "A1 ON": "on", "A1 OFF": "off" }) + }, + defaultValue: "on" } } ], @@ -29,20 +33,20 @@ const config : Config = { hauptraum_table_light: { name: "Hauptraum Tisch", position: [450, 450], - icon: "white-balance-iridescent", + icon: mdi("white-balance-iridescent"), iconColor: () => hex("#000000"), ui: [ { type: "toggle", text: "Licht", topic: "hauptraum_table_light", - icon: "power" + icon: mdi("power") }, { type: "toggle", text: "Licht", topic: "hauptraum_table_light_on_hack", - icon: "power" + icon: mdi("power") } ] } diff --git a/config/rzl.js b/config/rzl.js index 8d4732e..75bb138 100644 --- a/config/rzl.js +++ b/config/rzl.js @@ -2,203 +2,367 @@ import type { Config } from "config/flowtypes"; import * as types from "config/types"; import { hex, rgb, rgba, rainbow } from "config/colors"; -import { esper_topics, esper_statistics, floalt } from "./utils"; +import { mdi, raw_mdi, mdi_battery } from "config/icon"; +import { esper_topics, esper_statistics, floalt, tradfri_remote } from "./utils"; const config : Config = { space: { name: "RZL", color: "orange", - mqtt: "ws://map.rzl:1884" + mqtt: "ws://map.rzl.so:1884" }, topics: [ { led_stahltraeger: { - state: "/service/openhab/out/pca301_ledstrips/state", - command: "/service/openhab/in/pca301_ledstrips/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_ledstrips/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_ledstrips/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, snackbar: { - state: "/service/openhab/out/pca301_snackbar/state", - command: "/service/openhab/in/pca301_snackbar/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_snackbar/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_snackbar/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off", }, twinkle: { - state: "/service/openhab/out/pca301_twinkle/state", - command: "/service/openhab/in/pca301_twinkle/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_twinkle/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_twinkle/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, fan: { - state: "/service/openhab/out/pca301_fan/state", - command: "/service/openhab/in/pca301_fan/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_fan/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_fan/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, videogames: { - state: "/service/openhab/out/pca301_videogames/state", - command: "/service/openhab/in/pca301_videogames/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_videogames/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_videogames/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, olymp_pc: { - state: "/service/openhab/out/pca301_olymp_pc/state", - command: "/service/openhab/in/pca301_olymp_pc/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_olymp_pc/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_olymp_pc/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" + }, + olymp_printer: { + state: { + name: "stat/sonoff2/POWER", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "cmnd/sonoff2/power", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, flyfry: { - state: "/service/openhab/out/wifi_flyfry/state", - command: "/service/openhab/in/wifi_flyfry/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } - }, - artnet: { - state: "/artnet/state", - command: "/artnet/push", - defaultValue: "blackout", - values: { off: "blackout", yellow: "yellow", purple: "purple", - blue: "blue", green: "green", red: "red", random: "random", - cycle: "cycle-random" } + state: { + name: "/service/openhab/out/wifi_flyfry/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/wifi_flyfry/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, onkyo_connection: { - state: "/service/onkyo/connected", - command: "", - defaultValue: "0", - values: { disconnected: "0", connecting: "1", connected: "2" }, + state: { + name: "/service/onkyo/connected", + type: types.option({ + "0": "disconnected", + "1": "connecting", + "2": "connected" + }) + }, + defaultValue: "disconnected" }, onkyo_power: { - state: "/service/onkyo/status/system-power", - command: "/service/onkyo/command", - defaultValue: "PWR00", - values: { off: "PWR00", on: "PWR01" }, - type: types.json("onkyo_raw") + state: { + name: "/service/onkyo/status/system-power", + type: types.json("onkyo_raw", types.option({ + PWR00: "off", + PWR01: "on" + })) + }, + command: { + name: "/service/onkyo/command", + type: types.option({ off: "PWR00", on: "PWR01" }) + }, + defaultValue: "off" }, onkyo_mute: { - state: "/service/onkyo/status/audio-muting", - command: "/service/onkyo/command", - defaultValue: "AMT00", - values: { off: "AMT00", on: "AMT01" }, - type: types.json("onkyo_raw") + state: { + name: "/service/onkyo/status/audio-muting", + type: types.json("onkyo_raw", types.option({ + AMT00: "off", + AMT01: "on" + })) + }, + command: { + name: "/service/onkyo/command", + type: types.option({ off: "AMT00", on: "AMT01" }) + }, + defaultValue: "off" }, onkyo_volume: { - state: "/service/onkyo/status/volume", - command: "/service/onkyo/set/volume", - defaultValue: 0, - values: {}, - type: types.json("val") + state: { + name: "/service/onkyo/status/volume", + type: types.json("val") + }, + command: { + name: "/service/onkyo/set/volume", + type: types.string + }, + defaultValue: "0" }, onkyo_inputs: { - state: "/service/onkyo/status/input-selector", - command: "/service/onkyo/command", - defaultValue: "SLI00", - values: { tisch: "SLI11", chromecast: "SLI01", pult: "SLI10", netzwerk: "SLI2B", front: "SLI03" }, - type: types.json("onkyo_raw") + state: { + name: "/service/onkyo/status/input-selector", + type: types.json("onkyo_raw", types.option({ + SLI11: "tisch", + SLI01: "chromecast", + SLI10: "pult", + SLI2B: "netzwerk", + SLI03: "front", + otherwise: "unknown" + })) + }, + command: { + name: "/service/onkyo/command", + type: types.option({ + tisch: "SLI11", + chromecast: "SLI01", + pult: "SLI10", + netzwerk: "SLI2B", + front: "SLI03", + unknown: "SLI00" + }) + }, + defaultValue: "unknown", }, onkyo_radios: { - state: "/service/onkyo/status/latest-NPR", - command: "/service/onkyo/command", - defaultValue: "", - values: { mpd: "NPR01", kohina: "NPR02", somafm_dronezone: "NPR03", somafm_thetrip: "NPR04", - querfunk: "NPR05", somafm_defconradio: "NPR06", somafm_secretagent: "NPR07", somafm_lush: "NPR08", - somafm_beatblender: "NPR09", ponyville: "NPR0a"} + state: { + name: "/service/onkyo/status/latest-NPR", + type: types.option({ + NPR01: "mpd", + NPR02: "kohina", + NPR03: "somafm_dronezone", + NPR04: "somafm_thetrip", + NPR05: "querfunk", + NPR06: "somafm_defconradio", + NPR07: "somafm_secretagent", + NPR08: "somafm_lush", + NPR09: "somafm_beatblender", + NPR0a: "ponyville", + otherwise: "unknown" + }) + }, + command: { + name: "/service/onkyo/command", + type: types.option({ + mpd: "NPR01", + kohina: "NPR02", + somafm_dronezone: "NPR03", + somafm_thetrip: "NPR04", + querfunk: "NPR05", + somafm_defconradio: "NPR06", + somafm_secretagent: "NPR07", + somafm_lush: "NPR08", + somafm_beatblender: "NPR09", + ponyville: "NPR0a", + otherwise: "NPR00" + }) + }, + defaultValue: "unknown" }, rundumleuchte: { - state: "/service/openhab/out/pca301_rundumleuchte/state", - command: "/service/openhab/in/pca301_rundumleuchte/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_rundumleuchte/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_rundumleuchte/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" }, loetarbeitsplatz4: { - state: "stat/sonoff4/POWER", - command: "", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "stat/sonoff4/POWER", + type: types.option({ ON: "on", OFF: "off" }) + }, + defaultValue: "off", }, loetarbeitsplatz5: { - state: "stat/sonoff5/POWER", - command: "", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "stat/sonoff5/POWER", + type: types.option({ ON: "on", OFF: "off" }) + }, + defaultValue: "off", }, door_status: { - state: "/service/status", - command: "", - defaultValue: "\"closed\"", - values: { on: "\"open\"", off: "\"closed\"" } + state: { + name: "/service/status", + type: types.option({ "\"open\"": "on", "\"closed\"": "off" }) + }, + defaultValue: "off" }, presence_status: { - state: "service/status/presence", - command: "", - defaultValue: "", - values: {}, - type: msg => JSON.parse(msg.toString()).join(", ") + state: { + name: "service/status/presence", + type: types.jsonArray + }, + defaultValue: "" + }, + devices_status: { + state: { + name: "/service/status/devices", + type: types.string + }, + defaultValue: "" }, infoscreen: { - state: "/service/openhab/out/pca301_infoscreen/state", - command: "/service/openhab/in/pca301_infoscreen/command", - defaultValue: "OFF", - values: { on: "ON", off: "OFF" } + state: { + name: "/service/openhab/out/pca301_infoscreen/state", + type: types.option({ ON: "on", OFF: "off" }) + }, + command: { + name: "/service/openhab/in/pca301_infoscreen/command", + type: types.option({ on: "ON", off: "OFF" }) + }, + defaultValue: "off" + }, + projector: { + state: { + name: "/service/beamer/state", + type: types.option({ + START_UP: "transient_on", + START_UP_LAMP: "transient_on", + COOLING: "transient_off", + COOLING2: "transient_off", + POWER_ON: "on", + STANDBY: "off", + unknown: "unknown", + offline: "unknown" + }) + }, + command: { + name: "/service/beamer/command", + type: types.option({ + on: "ON", + off: "OFF", + transient_off: "OFF", + transient_on: "ON", + unknown: "OFF" + }) + }, + defaultValue: "unknown" }, printer_3d_status: { - state: "/service/ultimaker/state", - command: "", + state: { + name: "/service/ultimaker/state", + type: types.option({ + unreachable: "unavailable", + booting: "unavailable", + pre_print: "printing", + post_print: "printing", + printing: "printing", + otherwise: "awaiting_interaction" + }) + }, defaultValue: "unavailable", - values: {}, - type: msg => { - switch (msg.toString()) { - case "unreachable": - case "booting": - return "unavailable" - - case "pausing": - case "paused": - case "resuming": - case "wait_cleanup": - case "maintenance": - return "awaiting_interaction" - - case "pre_print": - case "post_print": - case "printing": - return "printing" - - default: - return msg.toString() - } - } }, printer_3d_progress: { - state: "/service/ultimaker/job", - command: "", - defaultValue: "", - values: {}, - type: msg => JSON.parse(msg.toString()).progress || 0 + state: { + name: "/service/ultimaker/job", + type: msg => JSON.parse(msg.toString()).progress || "0" + }, + defaultValue: "0" }, kitchen_light_color: { - state: "/service/openhab/out/kitchen_light_all_color_temperature/state", - command: "/service/openhab/in/kitchen_light_all_color_temperature/command", - defaultValue: "0", - values: {} + state: { + name: "/service/openhab/out/kitchen_light_all_color_temperature/state", + type: types.string + }, + command: { + name: "/service/openhab/in/kitchen_light_all_color_temperature/command", + type: types.string + }, + defaultValue: "0" }, kitchen_light_brightness: { - state: "/service/openhab/out/kitchen_light_all_brightness/state", - command: "/service/openhab/in/kitchen_light_all_brightness/command", - defaultValue: "0", - values: {} + state: { + name: "/service/openhab/out/kitchen_light_all_brightness/state", + type: types.string + }, + command: { + name: "/service/openhab/in/kitchen_light_all_brightness/command", + type: types.string + }, + defaultValue: "0" }, kitchen_sink_light_brightness: { - state: "/service/openhab/out/tradfri_0100_gwb8d7af2b448f_65545_brightness/state", - command: "/service/openhab/in/tradfri_0100_gwb8d7af2b448f_65545_brightness/command", - defaultValue: "0", - values: {} + state: { + name: "/service/openhab/out/tradfri_0100_gwb8d7af2b448f_65545_brightness/state", + type: types.string + }, + command: { + name: "/service/openhab/in/tradfri_0100_gwb8d7af2b448f_65545_brightness/command", + type: types.string + }, + defaultValue: "0" } }, + //Kuechen-Floalts floalt.topics("65537"), floalt.topics("65538"), floalt.topics("65539"), floalt.topics("65540"), + tradfri_remote.topics("65536"), + tradfri_remote.topics("65547"), + + //Theken-Floalts + floalt.topics("65543"), + floalt.topics("65544"), + tradfri_remote.topics("65542"), + tradfri_remote.topics("65546"), + esper_topics("afba40", "flyfry"), esper_topics("afba45", "alarm") ], @@ -206,63 +370,64 @@ const config : Config = { led_stahltrager: { name: "LED Stahlträger", position: [380, 590], - icon: "white-balance-iridescent", + icon: mdi("white-balance-iridescent"), iconColor: ({led_stahltraeger}) => led_stahltraeger == "on" ? rainbow : hex("#000000"), ui: [ { type: "toggle", text: "Stahlträger LED", topic: "led_stahltraeger", - icon: "power" + icon: mdi("power") }, ] }, snackbar: { name: "Snackbar", position: [510, 500], - icon: "fridge", + icon: mdi("fridge"), iconColor: ({snackbar}) => snackbar == "on" ? hex("#E20074") : hex("#000000"), ui: [ { type: "toggle", text: "Snackbar", topic: "snackbar", - icon: "power" + icon: mdi("power") } ] }, twinkle: { name: "Twinkle", position: [530, 560], - icon: ({twinkle}) => twinkle == "on" ? "led-on flip-v" : "led-off flip-v", + icon: ({twinkle}) => + twinkle == "on" ? raw_mdi("led-on flip-v") : raw_mdi("led-off flip-v"), iconColor: ({twinkle}) => twinkle == "on" ? rainbow : hex("#000000"), ui: [ { type: "toggle", text: "Twinkle", topic: "twinkle", - icon: "power" + icon: mdi("power") } ] }, fan: { name: "Ventilator", position: [520, 450], - icon: "fan", + icon: mdi("fan"), iconColor: ({fan}) => fan == "on" ? hex("#00FF00") : hex("#000000"), ui: [ { type: "toggle", text: "Ventilator", topic: "fan", - icon: "power" + icon: mdi("power") } ] }, cashdesk: { name: "Cashdesk", position: [500, 470], - icon: "coin", + icon: mdi("coin"), ui: [ { type: "link", @@ -274,80 +439,83 @@ const config : Config = { videogames: { name: "Videospiele", position: [100, 100], - icon: "gamepad-variant", + icon: mdi("gamepad-variant"), iconColor: ({videogames}) => videogames == "on" ? hex("#00FF00") : hex("#000000"), ui: [ { type: "toggle", text: "Videospiele", topic: "videogames", - icon: "power" + icon: mdi("power") } ] }, olymp_pc: { - name: "Rechner und Drucker", + name: "Rechner", position: [297, 90], - icon: "desktop-classic", + icon: mdi("desktop-classic"), iconColor: ({olymp_pc}) => olymp_pc == "on" ? hex("#00FF00") : hex("#000000"), ui: [ { type: "toggle", - text: "Rechner und Drucker", + text: "Rechner", topic: "olymp_pc", - icon: "power" + icon: mdi("power") + } + ] + }, + olymp_printer: { + name: "Drucker", + position: [335, 90], + icon: mdi("printer"), + iconColor: ({olymp_printer}) => olymp_printer == "on" ? hex("#00FF00") : hex("#000000"), + ui: [ + { + type: "toggle", + text: "Drucker", + topic: "olymp_printer", + icon: mdi("power") + }, + { + type: "link", + link: "http://annette.rzl/", + text: "Open Annette" } ] }, flyfry: { name: "Fliegenbratgerät", position: [450, 590], - icon: "fire", + icon: mdi("fire"), iconColor: ({flyfry}) => flyfry == "on" ? hex("#6666FF") : hex("#000000"), ui: esper_statistics("flyfry", [ { type: "toggle", text: "Fliegenbratgerät", topic: "flyfry", - icon: "power" + icon: mdi("power") } ]) }, - artnet: { - name: "Artnet", - position: [535,480], - icon: "spotlight", - iconColor: ({artnet}) => + projector: { + name: "Beamer", + position: [415, 590], + icon: mdi("projector flip-v"), + iconColor: ({projector}) => ({ + transient_on: hex("#b3b300"), + transient_off: hex("#b3b300"), + on: hex("#00ff00"), off: hex("#000000"), - yellow: hex("#F0DF10"), - red: hex("#FF0000"), - purple: hex("#FF00FF"), - green: hex("#00FF00"), - cycle: rainbow - })[artnet], + unknown: hex("#888888"), + })[projector], ui: [ { type: "toggle", - text: "An/Aus", - topic: "artnet", - on: "cycle", - toggled: val => val != "off", - icon: "power" - }, - { - type: "dropDown", - text: "Farbe", - topic: "artnet", - options: { - yellow: "Gelb", - red: "Rot", - purple: "Pink", - green: "Grün", - cycle: "Farbwechsel" - }, - enableCondition: val => val != "off", - icon: "palette" + text: "Beamer", + topic: "projector", + toggled: val => val == "transient_on" || val == "on", + icon: mdi("power") } ] }, @@ -356,14 +524,14 @@ const config : Config = { position: [350, 650], iconColor: ({onkyo_connection, onkyo_power}) => onkyo_connection != "connected" ? hex("#888888") : (onkyo_power == "on" ? hex("#00FF00") : hex("#000000")), - icon: "audio-video", + icon: mdi("audio-video"), ui: [ { type: "toggle", text: "Power", - icon: "power", + icon: mdi("power"), topic: "onkyo_power", - enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" + enableCondition: ({ onkyo_connection }) => onkyo_connection == "connected" }, { type: "section", @@ -375,15 +543,15 @@ const config : Config = { topic: "onkyo_volume", min: 0, max: 50, - icon: "volume-high", - enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" + icon: mdi("volume-high"), + enableCondition: ({ onkyo_connection }) => onkyo_connection == "connected" }, { type: "toggle", text: "Mute", topic: "onkyo_mute", - icon: "volume-off", - enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" + icon: mdi("volume-off"), + enableCondition: ({ onkyo_connection }) => onkyo_connection == "connected" }, { type: "section", @@ -400,8 +568,8 @@ const config : Config = { pult: "Pult", front: "Front HDMI" }, - icon: "usb", - enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" + icon: mdi("usb"), + enableCondition: ({ onkyo_connection }) => onkyo_connection == "connected" }, { type: "dropDown", @@ -419,8 +587,8 @@ const config : Config = { somafm_beatblender: "Beat Blender (Soma FM)", ponyville: "Ponyville FM" }, - icon: "radio", - enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" && state.onkyo_inputs.internal == "netzwerk" + icon: mdi("radio"), + enableCondition: (state) => state.onkyo_connection == "connected" && state.onkyo_inputs == "netzwerk" }, { type: "section", @@ -436,14 +604,14 @@ const config : Config = { rundumleuchte: { name: "Rundumleuchte", position: [310,275], - icon: "alarm-light", + icon: mdi("alarm-light"), iconColor: ({rundumleuchte}) => rundumleuchte == "on" ? hex("#F0DF10") : hex("#000000"), ui: [ { type: "toggle", text: "Rundumleuchte", topic: "rundumleuchte", - icon: "power" + icon: mdi("power") } ] }, @@ -478,14 +646,14 @@ const config : Config = { alarm: { name: "Alarm", position: [340, 250], - icon: "alarm-bell", + icon: mdi("alarm-bell"), iconColor: () => hex("#000000"), ui: esper_statistics("alarm") }, door: { name: "Tür", position: [455,350], - icon: "swap-vertical", + icon: mdi("swap-vertical"), iconColor: ({door_status}) => door_status == "on" ? hex("#00FF00") : hex("#FF0000"), ui: [ { @@ -497,21 +665,28 @@ const config : Config = { type: "text", text: "Anwesend", topic: "presence_status", - icon: "account" + icon: mdi("account") + }, + { + type: "text", + text: "Devices", + topic: "devices_status", + icon: mdi("wifi") } + ] }, infoscreen: { name: "Infoscreen", position: [255, 495], - icon: "television-guide flip-v", + icon: mdi("television-guide flip-v"), iconColor: ({infoscreen}) => infoscreen == "on" ? hex("#4444FF") : hex("#000000"), ui: [ { type: "toggle", text: "Infoscreen", topic: "infoscreen", - icon: "power" + icon: mdi("power") }, { type: "link", @@ -523,7 +698,7 @@ const config : Config = { printer_3d: { name: "Ultimaker 3", position: [754, 560], - icon: "printer-3d", + icon: mdi("printer-3d"), iconColor: ({printer_3d_status}) => ({ awaiting_interaction: hex("#b3b300"), @@ -544,7 +719,7 @@ const config : Config = { }, { type: "progress", - icon: "rotate-right", + icon: mdi("rotate-right"), min: 0, max: 1, text: "Printing Progress", @@ -555,7 +730,7 @@ const config : Config = { partkeepr: { name: "Partkeepr", position: [48, 450], - icon: "chip", + icon: mdi("chip"), ui: [ { type: "link", @@ -567,23 +742,23 @@ const config : Config = { kitchen_light: { name: "Deckenlicht Küche", position: [325, 407], - icon: "ceiling-light", + icon: mdi("ceiling-light"), ui: [ { type: "toggle", - on: 50, - off: 0, + on: "50", + off: "0", toggled: n => parseInt(n) > 0, topic: "kitchen_light_brightness", text: "Ein/Ausschalten", - icon: "power" + icon: mdi("power") }, { type: "slider", min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: "kitchen_light_brightness", delayedApply: true }, @@ -592,7 +767,7 @@ const config : Config = { min: 0, max: 100, text: "Farbtemperatur", - icon: "weather-sunset-down", + icon: mdi("weather-sunset-down"), topic: "kitchen_light_color", delayedApply: true }, @@ -605,7 +780,7 @@ const config : Config = { min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: floalt.brightness("65537"), delayedApply: true }, @@ -614,7 +789,7 @@ const config : Config = { min: 0, max: 100, text: "Farbtemperatur", - icon: "weather-sunset-down", + icon: mdi("weather-sunset-down"), topic: floalt.color("65537"), delayedApply: true }, @@ -627,7 +802,7 @@ const config : Config = { min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: floalt.brightness("65538"), delayedApply: true }, @@ -636,7 +811,7 @@ const config : Config = { min: 0, max: 100, text: "Farbtemperatur", - icon: "weather-sunset-down", + icon: mdi("weather-sunset-down"), topic: floalt.color("65538"), delayedApply: true }, @@ -649,7 +824,7 @@ const config : Config = { min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: floalt.brightness("65539"), delayedApply: true }, @@ -658,7 +833,7 @@ const config : Config = { min: 0, max: 100, text: "Farbtemperatur", - icon: "weather-sunset-down", + icon: mdi("weather-sunset-down"), topic: floalt.color("65539"), delayedApply: true }, @@ -671,7 +846,7 @@ const config : Config = { min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: floalt.brightness("65540"), delayedApply: true }, @@ -680,7 +855,7 @@ const config : Config = { min: 0, max: 100, text: "Farbtemperatur", - icon: "weather-sunset-down", + icon: mdi("weather-sunset-down"), topic: floalt.color("65540"), delayedApply: true } @@ -689,28 +864,121 @@ const config : Config = { kitchen_sink_light: { name: "Licht Spüle", position: [300, 345], - icon: "wall-sconce-flat", + icon: mdi("wall-sconce-flat"), ui: [ { type: "toggle", - on: 50, - off: 0, + on: "50", + off: "0", toggled: n => parseInt(n) > 0, topic: "kitchen_sink_light_brightness", text: "Ein/Ausschalten", - icon: "power" + icon: mdi("power") }, { type: "slider", min: 0, max: 100, text: "Helligkeit", - icon: "brightness-7", + icon: mdi("brightness-7"), topic: "kitchen_sink_light_brightness", delayedApply: true } ] - } + }, + kitchen_counter_light: { + name: "Deckenlicht Theke", + position: [400, 440], + icon: mdi("ceiling-light"), + ui: [ + { + type: "section", + text: "Lampe Eingang" + }, + { + type: "slider", + min: 0, + max: 100, + text: "Helligkeit", + icon: mdi("brightness-7"), + topic: floalt.brightness("65544"), + delayedApply: true + }, + { + type: "slider", + min: 0, + max: 100, + text: "Farbtemperatur", + icon: mdi("weather-sunset-down"), + topic: floalt.color("65544"), + delayedApply: true + }, + { + type: "section", + text: "Lampe Hauptraum" + }, + { + type: "slider", + min: 0, + max: 100, + text: "Helligkeit", + icon: mdi("brightness-7"), + topic: floalt.brightness("65543"), + delayedApply: true + }, + { + type: "slider", + min: 0, + max: 100, + text: "Farbtemperatur", + icon: mdi("weather-sunset-down"), + topic: floalt.color("65543"), + delayedApply: true + } + ] + }, + remotes: { + name: "Fernbedinungen", + position: [400, 344], + 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") ? hex("#ff0000") : hex("#000000"), + ui: [ + { + type: "progress", + icon: mdi_battery(tradfri_remote.level("65536")), + min: 0, + max: 100, + text: "Licht Tisch 1", + topic: tradfri_remote.level("65536") + }, + { + type: "progress", + icon: mdi_battery(tradfri_remote.level("65547")), + min: 0, + max: 100, + text: "Licht Tisch 2", + topic: tradfri_remote.level("65547") + }, + { + type: "progress", + icon: mdi_battery(tradfri_remote.level("65542")), + min: 0, + max: 100, + text: "Licht Theke 1", + topic: tradfri_remote.level("65542") + }, + { + type: "progress", + icon: mdi_battery(tradfri_remote.level("65546")), + min: 0, + max: 100, + text: "Licht Theke 2", + topic: tradfri_remote.level("65546") + } + ] + }, }, layers: [ { diff --git a/config/utils.js b/config/utils.js index 20cc656..5ebd526 100644 --- a/config/utils.js +++ b/config/utils.js @@ -1,42 +1,44 @@ // @flow import type { ControlUI } from "config/flowtypes"; +import { mdi } from "config/icon"; +import * as types from "config/types"; export const esper_topics = (chip_id: string, name: string) => ({ [ `esper_${name}_version` ]: { - state: `/service/esper/${chip_id}/info`, - command: "", - defaultValue: "UNKNOWN", - values: {}, - type: msg => JSON.parse(msg.toString()).version.esper + state: { + name: `/service/esper/${chip_id}/info`, + type: types.json("version.esper") + }, + defaultValue: "UNKNOWN" }, [ `esper_${name}_ip` ]: { - state: `/service/esper/${chip_id}/info`, - command: "", - defaultValue: "UNKNOWN", - values: {}, - type: msg => JSON.parse(msg.toString()).network.ip + state: { + name: `/service/esper/${chip_id}/info`, + type: types.json("network.ip") + }, + defaultValue: "UNKNOWN" }, [ `esper_${name}_rssi` ]: { - state: `/service/esper/${chip_id}/info`, - command: "", - defaultValue: "UNKNOWN", - values: {}, - type: msg => JSON.parse(msg.toString()).wifi.rssi + state: { + name: `/service/esper/${chip_id}/info`, + type: types.json("wifi.rssi") + }, + defaultValue: "UNKNOWN" }, [ `esper_${name}_uptime` ]: { - state: `/service/esper/${chip_id}/info`, - command: "", - defaultValue: "UNKNOWN", - values: {}, - type: msg => new Date(JSON.parse(msg.toString()).time.startup * 1000) + state: { + name: `/service/esper/${chip_id}/info`, + type: msg => new Date(JSON.parse(msg.toString()).time.startup * 1000) .toLocaleString() + }, + defaultValue: "UNKNOWN", }, [ `esper_${name}_device` ]: { - state: `/service/esper/${chip_id}/info`, - command: "", - defaultValue: "UNKNOWN", - values: {}, - type: msg => JSON.parse(msg.toString()).device + state: { + name: `/service/esper/${chip_id}/info`, + type: types.json("device") + }, + defaultValue: "UNKNOWN" } }); @@ -45,16 +47,47 @@ export const floalt = { brightness: (light_id: string) => `floalt_${light_id}_brightness`, topics: (light_id: string) => ({ [ `floalt_${light_id}_color` ]: { - state: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/state`, - command: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/command`, - defaultValue: "0", - values: {} + state: { + name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/state`, + type: types.string + }, + command: { + name: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_color_temperature/command`, + type: types.string + }, + defaultValue: "0" }, [ `floalt_${light_id}_brightness` ]: { - state: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/state`, - command: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/command`, - defaultValue: "0", - values: {} + state: { + name: `/service/openhab/out/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/state`, + type: types.string + }, + command: { + name: `/service/openhab/in/tradfri_0220_gwb8d7af2b448f_${light_id}_brightness/command`, + type: types.string + }, + defaultValue: "0" + } + }) +} + +export const tradfri_remote = { + level: (remote_id: string) => `tradfri_remote_${remote_id}_level`, + low: (remote_id: string) => `tradfri_remote_${remote_id}_low`, + topics: (remote_id: string) => ({ + [ `tradfri_remote_${remote_id}_level` ]: { + state: { + name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remote_id}_battery_level/state`, + type: types.string + }, + defaultValue: "0" + }, + [ `tradfri_remote_${remote_id}_low` ]: { + state: { + name: `/service/openhab/out/tradfri_0830_gwb8d7af2b448f_${remote_id}_battery_low/state`, + type: types.option({ ON: "true", OFF: "false" }) + }, + defaultValue: "false", } }) } @@ -69,31 +102,31 @@ export const esper_statistics = (name: string, { type: "text", text: "Device Variant", - icon: "chart-donut", + icon: mdi("chart-donut"), topic: `esper_${name}_device` }, { type: "text", text: "Version", - icon: "source-branch", + icon: mdi("source-branch"), topic: `esper_${name}_version` }, { type: "text", text: "IP", - icon: "access-point-network", + icon: mdi("access-point-network"), topic: `esper_${name}_ip` }, { type: "text", text: "RSSI", - icon: "wifi", + icon: mdi("wifi"), topic: `esper_${name}_rssi` }, { type: "text", text: "Running since…", - icon: "av-timer", + icon: mdi("av-timer"), topic: `esper_${name}_uptime` } ]) diff --git a/package.json b/package.json index b269e53..4e44247 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "scripts": { "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.dev.js --mode development --env", + "watch": "webpack-dev-server --open --config webpack.config.js --mode development --env", "travis": "./travis.sh", - "lint": "eslint -- --ext js --ext jsx src/", + "lint": "eslint --ext js --ext jsx src/", "precommit": "yarn lint" }, "dependencies": { @@ -30,16 +30,16 @@ "babel-eslint": "^8.0.1", "babel-loader": "^7.1.1", "babel-plugin-transform-class-properties": "^6.24.1", - "babel-preset-react": "^6.24.1", "babel-preset-env": "^1.6.0", + "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^0.1.18", "css-loader": "^0.28.9", - "eslint": "^4.16.0", + "eslint": "^5.0.1", "eslint-plugin-flowtype": "^2.42.0", "eslint-plugin-react": "^7.6.1", "file-loader": "^1.1.5", "flow": "^0.2.3", - "flow-bin": "^0.70.0", + "flow-bin": "^0.75.0", "flow-typed": "^2.3.0", "html-webpack-plugin": "^3.1.0", "husky": "^0.14.3", diff --git a/src/components/App.js b/src/components/App.js index fc5becd..d11a56b 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -18,9 +18,6 @@ import ControlMap from "components/ControlMap"; import TopBar from "components/TopBar"; import UiItemList from "components/UiItemList"; -import keyOf from "utils/keyOf"; -import { controlGetIcon } from "utils/parseIconName"; - import connectMqtt from "../connectMqtt"; export type AppProps = { @@ -31,7 +28,7 @@ export type AppState = { selectedControl: ?Control, drawerOpened: boolean, mqttState: State, - mqttSend: (topic: string, value: Actual) => void, + mqttSend: (topic: string, value: Buffer) => void, mqttConnected: boolean, }; @@ -41,16 +38,15 @@ class App extends React.PureComponent { this.state = { selectedControl: null, drawerOpened: false, - mqttState: mapValues(this.topics, (topic) => ({ - actual: topic.defaultValue, - internal: keyOf(topic.values, topic.defaultValue) - })), + mqttState: mapValues(this.topics, (topic) => topic.defaultValue), mqttSend: connectMqtt(props.config.space.mqtt, { onMessage: this.receiveMessage.bind(this), onConnect: () => this.setState({ mqttConnected: true }), onReconnect: () => this.setState({ mqttConnected: false }), onDisconnect: () => this.setState({ mqttConnected: false }), - subscribe: map(this.topics, (x) => x.state) + subscribe: map( + filter(keys(this.topics), (x) => this.topics[x].state != null), + (x) => this.topics[x].state.name) }), mqttConnected: false }; @@ -77,23 +73,23 @@ class App extends React.PureComponent { }); } - receiveMessage(rawTopic: string, message: Object) { + receiveMessage(rawTopic: string, message: Buffer) { const topics = filter( keys(this.topics), - (k) => this.topics[k].state === rawTopic + (k) => this.topics[k].state != null && + this.topics[k].state.name === rawTopic ); if (topics.length === 0) { return; } for (let i in topics) { + // TODO: Remove FlowFixMe const topic = topics[i]; - const parseValue = this.topics[topic].type; + // $FlowFixMe + const parseValue = this.topics[topic].state.type; const val = parseValue == null ? message.toString() : parseValue(message); this.setState({mqttState: Object.assign({}, merge(this.state.mqttState, - { [topic]: { - actual: val, - internal: keyOf(this.topics[topic].values, val) || val - }}))}); + { [topic]: val}))}); } } @@ -105,15 +101,15 @@ class App extends React.PureComponent { this.setState({drawerOpened: false}); } - changeState(topic: string, value: Actual) { - const rawTopic = this.topics[topic].command; - if (rawTopic == null) { + changeState(topic: string, value: string) { + if (this.topics[topic].command == null) { return; } - this.state.mqttSend( - rawTopic, - String(this.topics[topic].values[value] || 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)); } render() { @@ -127,8 +123,7 @@ class App extends React.PureComponent { control={this.state.selectedControl} onCloseRequest={this.closeDrawer.bind(this)} icon={this.state.selectedControl == null ? null : - controlGetIcon(this.state.selectedControl, - this.state.mqttState)} + this.state.selectedControl.icon(this.state.mqttState)} > {this.state.selectedControl == null || { } createLeafletIcon(control: Control) { - const icon = controlGetIcon(control, this.props.state); - const iconClass = parseIconName(`${icon} 36px`); + const icon = control.icon(this.props.state); + const iconClass = `${icon} mdi-36px`; return divIcon({ iconSize: point(36, 36), iconAnchor: point(18, 18), @@ -61,10 +59,8 @@ export default class ControlMap extends React.PureComponent { } iconColor(control: Control): string { - const ints = mapValues(this.props.state, (x) => x.internal || x.actual); - const acts = mapValues(this.props.state, (x) => x.actual); if (control.iconColor != null) { - return control.iconColor(ints, acts, this.props.state); + return control.iconColor(this.props.state); } return "#000"; } diff --git a/src/components/SideBar.js b/src/components/SideBar.js index a94e62e..eff2c34 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -8,24 +8,26 @@ 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 { renderIcon } from "utils/parseIconName"; +import { renderIcon } 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?: ?string, + icon?: ?RawIcon, children?: React.Node }; export type SideBarState = { }; -class SideBar extends React.PureComponent -{ - constructor(props: SideBarProps & Classes) { +type Props = SideBarProps & Classes; + +class SideBar extends React.PureComponent { + constructor(props: Props) { super(props); } diff --git a/src/components/TopBar.js b/src/components/TopBar.js index 56cbe10..0d4953f 100644 --- a/src/components/TopBar.js +++ b/src/components/TopBar.js @@ -16,7 +16,7 @@ export type TopBarState = { }; export default class TopBar - extends React.PureComponent { + extends React.PureComponent { constructor(props: TopBarProps) { super(props); } diff --git a/src/components/UiItemList/UiItem.js b/src/components/UiItemList/UiItem.js index 3821c18..aadfd83 100644 --- a/src/components/UiItemList/UiItem.js +++ b/src/components/UiItemList/UiItem.js @@ -21,17 +21,16 @@ import type { } from "config/flowtypes"; import keyOf from "utils/keyOf"; -import { getInternals, getActuals } from "utils/state"; type UiItemProps = { item: I, state: State, - onChangeState: (topic: string, nextState: Actual) => void + onChangeState: (topic: string, nextState: string) => void }; // eslint-disable-next-line flowtype/no-weak-types export default class UiItem - extends React.PureComponent> { + extends React.PureComponent> { constructor(props: UiItemProps) { super(props); } @@ -54,9 +53,7 @@ export default class UiItem typeof this.props.item.enableCondition == "function") { const enableCondition = this.props.item.enableCondition; const state = this.props.state; - const internals = getInternals(state); - const actuals = getActuals(state); - return enableCondition(internals, actuals, state); + return enableCondition(state); } else { return true; } @@ -68,7 +65,7 @@ export class UiControl extends UiItem { super(props); } - changeState(next: Actual) { + changeState(next: string) { if (this.props.item.topic == null) { throw new Error( `Missing topic in ${this.props.item.type} "${this.props.item.text}"` @@ -93,19 +90,6 @@ export class UiControl extends UiItem { } return value; } - - isEnabled() { - if (Object.keys(this.props.item).includes("enableCondition") && - // $FlowFixMe - typeof this.props.item.enableCondition == "function") { - const enableCondition = this.props.item.enableCondition; - const value = this.getValue(); - return enableCondition( - value.internal || value.actual, value.actual, this.props.state); - } else { - return true; - } - } } export class Toggle extends UiControl { @@ -113,9 +97,8 @@ export class Toggle extends UiControl { const value = this.getValue(); const control = this.props.item; const isChecked = control.toggled || - ((i, _a, _s) => i === (control.on || "on")); - const checked = isChecked( - value.internal || value.actual, value.actual, this.props.state); + ((i, _s) => i === (control.on || "on")); + const checked = isChecked(value, this.props.state); return checked; } @@ -145,7 +128,7 @@ export class Toggle extends UiControl { } export class DropDown extends UiControl { - runPrimaryAction = (next?: Actual) => { + runPrimaryAction = (next?: string) => { if (this.isEnabled()) { const control = this.props.item; const optionKeys = keys(control.options); @@ -172,7 +155,7 @@ export class DropDown extends UiControl { return ( {control.text} - } @@ -185,9 +168,9 @@ export class DropDown extends UiControl { } export class Slider extends UiControl { - runPrimaryAction = (_e: ?any, v: ?number) => { + runPrimaryAction = (e: ?Event, v: ?number) => { if (v != null) { - this.changeState(v); + this.changeState(v.toString()); } } @@ -195,10 +178,11 @@ export class Slider extends UiControl { return [ , this.props.item.delayedApply || this.runPrimaryAction()} + step={this.props.item.step || 1} + onChange={(e, v) => + this.props.item.delayedApply || this.runPrimaryAction(e, v)} onDragEnd={this.runPrimaryAction} disabled={!this.isEnabled()} /> ]; @@ -244,7 +228,7 @@ export class Text extends UiControl { render() { return [ , - + ]; } } @@ -253,7 +237,7 @@ export class Progress extends UiControl { render() { const min = this.props.item.min || 0; const max = this.props.item.max || 100; - const val = parseFloat(this.getValue().internal || this.getValue().actual); + const val = parseFloat(this.getValue()); const value = val * 100 / max - min; return [ , diff --git a/src/components/UiItemList/index.js b/src/components/UiItemList/index.js index eef50ec..a627377 100644 --- a/src/components/UiItemList/index.js +++ b/src/components/UiItemList/index.js @@ -2,17 +2,17 @@ import React from "react"; import ListItem from "@material-ui/core/ListItem"; import ListItemIcon from "@material-ui/core/ListItemIcon"; -import { renderIcon } from "utils/parseIconName"; +import { renderIcon } from "config/icon"; import type { ControlUI } from "config/flowtypes"; import { Toggle, DropDown, Link, - Section, Text, Progress, Slider } from "./UiItem"; + Section, Text, Progress, Slider } from "./UiItem"; export type UiItemListProps = { controls: Array, state: State, - onChangeState: (topic: string, nextState: Actual) => void + onChangeState: (topic: string, nextState: string) => void }; export default class UiItemList extends React.PureComponent { @@ -33,7 +33,9 @@ export default class UiItemList extends React.PureComponent { return ( {control.icon == null || - {renderIcon(control.icon, "mdi-24px")}} + + {renderIcon(control.icon(this.props.state), "mdi-24px")} + } {this.renderControl(control)} ); diff --git a/src/config/flowtypes.js b/src/config/flowtypes.js index bef0562..6cccf3f 100644 --- a/src/config/flowtypes.js +++ b/src/config/flowtypes.js @@ -1,24 +1,21 @@ // @flow import type { Color } from "config/colors"; +import type { Icon } from "config/icon"; -export type TopicType = (msg: Buffer) => any; +export type TopicType = (msg: Buffer) => string; + +export type StateCommand = { + name: string, + type: TopicType +} export type Topic = { - state: string, - command: string, - defaultValue: Actual, - values: Map, - type?: TopicType + state?: StateCommand, + command?: StateCommand, + defaultValue: string }; export type Topics = Map; -export type TopicDependentOption = ( - internal: Internal, actual: Actual, state: State - ) => T; -export type StateDependentOption = ( - internals: Map, actuals: Map, state: State - ) => T; - export interface UIControl { +type: string, +text: string, @@ -26,27 +23,27 @@ export interface UIControl { } export interface Enableable { - enableCondition?: TopicDependentOption + enableCondition?: (s: State) => boolean } export type UIToggle = $ReadOnly<{| type: "toggle", text: string, topic: string, - icon?: string, - enableCondition?: TopicDependentOption, - on?: Actual, - off?: Actual, - toggled?: TopicDependentOption + icon?: Icon, + enableCondition?: (s: State) => boolean, + on?: string, + off?: string, + toggled?: (v: string, s: State) => boolean |}>; export type UIDropDown = $ReadOnly<{| type: "dropDown", text: string, topic: string, - icon?: string, - enableCondition?: TopicDependentOption, - options: Map, + icon?: Icon, + enableCondition?: (s: State) => boolean, + options: Map, renderValue?: (value: string) => string |}>; @@ -54,8 +51,8 @@ export type UISlider = $ReadOnly<{| type: "slider", text: string, topic: string, - icon?: string, - enableCondition?: TopicDependentOption, + icon?: Icon, + enableCondition?: (s: State) => boolean, min?: number, max?: number, step?: number, @@ -71,24 +68,24 @@ export type UILink = $ReadOnly<{| type: "link", text: string, link: string, - enableCondition?: StateDependentOption, + enableCondition?: (s: State) => boolean, // TODO: check if both the following options are implemented - icon?: string + icon?: Icon |}>; export type UIText = $ReadOnly<{| type: "text", text: string, topic: string, - icon?: string + icon?: Icon |}>; export type UIProgress = $ReadOnly<{| type: "progress", text: string, topic: string, - icon?: string, + icon?: Icon, min?: number, max?: number |}>; @@ -105,16 +102,8 @@ export type ControlUI = export type Control = { name: string, position: [number, number], - icon: string | ( - internals: Map, - actuals: Map, - state: State - ) => string, - iconColor?: ( - internals: Map, - actuals: Map, - state: State - ) => Color, + icon: Icon, + iconColor?: (state: State) => Color, ui: Array }; export type Controls = Map; diff --git a/src/config/icon.js b/src/config/icon.js new file mode 100644 index 0000000..e1ae9f8 --- /dev/null +++ b/src/config/icon.js @@ -0,0 +1,45 @@ +// @flow +import * as React from "react"; + +export opaque type RawIcon: string = string; + +export type Icon = (State) => RawIcon; + +export const raw_mdi = (name: string): RawIcon => { + return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`; +}; + +export const mdi = (icon: string) => () => raw_mdi(icon); + +export const mdi_battery = (topic: string) => (state: State) => { + const rawval = state[topic]; + const val = parseInt(rawval); + if (isNaN(val)) { + return raw_mdi("battery-unknown"); + } else if (val > 95) { + return raw_mdi("battery"); + } else if (val > 85) { + return raw_mdi("battery-90"); + } else if (val > 75) { + return raw_mdi("battery-80"); + } else if (val > 65) { + return raw_mdi("battery-70"); + } else if (val > 55) { + return raw_mdi("battery-60"); + } else if (val > 45) { + return raw_mdi("battery-50"); + } else if (val > 35) { + return raw_mdi("battery-40"); + } else if (val > 25) { + return raw_mdi("battery-30"); + } else if (val > 15) { + return raw_mdi("battery-20"); + } else { + return raw_mdi("battery-10"); + } +}; + +export const renderIcon = + (icon: RawIcon, extraClass?: string): React.Node => { + return ; + }; diff --git a/src/config/types.js b/src/config/types.js index 0a4961d..91bb28b 100644 --- a/src/config/types.js +++ b/src/config/types.js @@ -1,8 +1,21 @@ // @flow import type { TopicType } from "config/flowtypes"; +import at from "lodash/at"; + +export const string: TopicType = (msg: Buffer) => msg.toString(); -export const string: TopicType = msg => msg.toString(); export const json = (path: string, innerType?: TopicType): TopicType => { - const parseAgain = innerType == null ? x => x : innerType; - return msg => parseAgain(JSON.parse(msg.toString())[path]); + const parseAgain = innerType == null ? (x) => x.toString() : innerType; + return (msg) => parseAgain(Buffer.from( + at(JSON.parse(msg.toString()), path)[0].toString())); }; + +export type TypeOptionParam = { otherwise?: string, [string]: string }; +export const option = (values: TypeOptionParam): TopicType => { + // TODO: error + const defaultValue = values.otherwise != null ? values.otherwise : ""; + const mapVal = (x) => (values[x] != null ? values[x] : defaultValue); + return (x) => mapVal(x.toString()); +}; + +export const jsonArray = (msg: Buffer) => JSON.parse(msg.toString()).join(", "); diff --git a/src/index.jsx b/src/index.jsx index 66997e4..c8ab2bd 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -8,11 +8,13 @@ import App from "components/App"; import "../node_modules/@mdi/font/css/materialdesignicons.min.css"; import "../css/styles.css"; -const Config : Config = window.config; +import type { Config } from "config/flowtypes"; + +const config : Config = window.config; injectTapEventPlugin(); -document.title = `${Config.space.name} Map`; +document.title = `${config.space.name} Map`; // $FlowFixMe const contentElement: Element = document.getElementById("content"); -ReactDOM.render(, contentElement); +ReactDOM.render(, contentElement); diff --git a/src/utils/parseIconName.js b/src/utils/parseIconName.js deleted file mode 100644 index 96d290f..0000000 --- a/src/utils/parseIconName.js +++ /dev/null @@ -1,25 +0,0 @@ -// @flow -import * as React from "react"; -import { getInternals, getActuals } from "utils/state"; - -import type { Control } from "config/flowtypes"; - -export default function parseIconName(name: string): string { - return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`; -} - -export const renderIcon = (name: string, extraClass?: string): React.Node => { - return ; -}; - -export const controlGetIcon = (control: Control, state: State): string => { - const internals: Map = getInternals(state); - const actuals: Map = getActuals(state); - return typeof control.icon !== "function" ? control.icon - : control.icon(internals, actuals, state); -}; - -export const renderControlIcon = (control: Control, - state: State, extraClass?: string): React.Node => { - return renderIcon(controlGetIcon(control, state), extraClass); -}; diff --git a/src/utils/state.js b/src/utils/state.js deleted file mode 100644 index c68269c..0000000 --- a/src/utils/state.js +++ /dev/null @@ -1,8 +0,0 @@ -// @flow -import mapValues from "lodash/mapValues"; - -export const getInternals = (state: State): Map => - mapValues(state, (x) => x.internal || x.actual); - -export const getActuals = (state: State): Map => - mapValues(state, (x) => x.actual); diff --git a/types/types.js b/types/types.js index d0f09ba..5503e1a 100644 --- a/types/types.js +++ b/types/types.js @@ -7,26 +7,7 @@ declare type Classes = { classes: Map }; -declare type Internal = string; -declare type Actual = any; -declare type StateValue = { - internal: string, - actual: any -}; -declare type State = Map; - -//declare type State = { -// mqtt: ?any, -// uiOpened: ?string, - // A map of the actual state values for each topic. - // internal is the internal term for the value, - // that is equal to the key in the values section of that - // topic, for example given by: - // values: { off: "OFF", on: "ON" } - // and actual is the value of that or whatever is given by mqtt. -// values: Map, -// visibleLayers: Array -//}; +declare type State = Map; declare type Point = [number, number]; diff --git a/webpack.config.js b/webpack.config.js index 71d7f96..0c38752 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,7 +3,6 @@ const webpack = require('webpack'); const WebpackShellPlugin = require('webpack-shell-plugin'); const HtmlWebpackPlugin = require('html-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'] : []; diff --git a/yarn.lock b/yarn.lock index 592ad3d..ecf63c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -161,23 +161,19 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" +acorn-jsx@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" dependencies: - acorn "^3.0.4" + acorn "^5.0.3" -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^5.0.0, acorn@^5.5.0: +acorn@^5.0.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +acorn@^5.0.3, acorn@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" ajv-keywords@^3.0.0, ajv-keywords@^3.1.0: version "3.1.0" @@ -190,15 +186,6 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - ajv@^6.0.1, ajv@^6.1.0: version "6.4.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" @@ -208,6 +195,15 @@ ajv@^6.0.1, ajv@^6.1.0: json-schema-traverse "^0.3.0" uri-js "^3.0.2" +ajv@^6.5.0: + version "6.5.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.1.tgz#88ebc1263c7133937d108b80c5572e64e1d9322d" + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.1" + alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -422,7 +418,7 @@ babel-cli@^6.24.1: optionalDependencies: chokidar "^1.6.1" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1633,7 +1629,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.2: +concat-stream@^1.5.0, concat-stream@^1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -1738,7 +1734,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -2220,6 +2216,16 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + es-abstract@^1.5.1, es-abstract@^1.7.0: version "1.11.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" @@ -2268,59 +2274,66 @@ eslint-scope@^3.7.1, eslint-scope@~3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.16.0: - version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" +eslint@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.0.1.tgz#109b90ab7f7a736f54e0f341c8bb9d09777494c3" dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" + ajv "^6.5.0" + babel-code-frame "^6.26.0" chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" + cross-spawn "^6.0.5" debug "^3.1.0" doctrine "^2.1.0" - eslint-scope "^3.7.1" + eslint-scope "^4.0.0" eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" + espree "^4.0.0" + esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^11.0.1" + globals "^11.5.0" ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" + inquirer "^5.2.0" + is-resolvable "^1.1.0" + js-yaml "^3.11.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" + lodash "^4.17.5" + minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" - regexpp "^1.0.1" + regexpp "^1.1.0" require-uncached "^1.0.3" - semver "^5.3.0" + semver "^5.5.0" + string.prototype.matchall "^2.0.0" strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" + strip-json-comments "^2.0.1" + table "^4.0.3" + text-table "^0.2.0" -espree@^3.5.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" +espree@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" + acorn "^5.6.0" + acorn-jsx "^4.1.1" esprima@^2.6.0: version "2.7.3" @@ -2330,7 +2343,7 @@ esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" -esquery@^1.0.0: +esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: @@ -2463,7 +2476,7 @@ extend@^3.0.0, extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^2.0.4: +external-editor@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -2510,6 +2523,10 @@ fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -2635,9 +2652,9 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -flow-bin@^0.70.0: - version "0.70.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.70.0.tgz#080ae83a997f2b4ddb3dc2649bf13336825292b5" +flow-bin@^0.75.0: + version "0.75.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.75.0.tgz#b96d1ee99d3b446a3226be66b4013224ce9df260" flow-typed@^2.3.0: version "2.4.0" @@ -2872,10 +2889,14 @@ global@~4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^11.0.1, globals@^11.1.0: +globals@^11.1.0: version "11.4.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" +globals@^11.5.0: + version "11.7.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2957,6 +2978,10 @@ has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" @@ -3273,21 +3298,20 @@ ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" +inquirer@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.0.4" + external-editor "^2.1.0" figures "^2.0.0" lodash "^4.3.0" mute-stream "0.0.7" run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" + rxjs "^5.5.2" string-width "^2.1.0" strip-ansi "^4.0.0" through "^2.3.6" @@ -3573,7 +3597,7 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-resolvable@^1.0.0: +is-resolvable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" @@ -3665,9 +3689,9 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.9.1: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" +js-yaml@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -3699,6 +3723,10 @@ json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -5399,7 +5427,13 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: +regexp.prototype.flags@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" + dependencies: + define-properties "^1.1.2" + +regexpp@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" @@ -5565,15 +5599,11 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" +rxjs@^5.5.2: + version "5.5.11" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87" dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + symbol-observable "1.0.1" rxjs@^6.1.0: version "6.2.1" @@ -5970,6 +6000,16 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string.prototype.matchall@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz#2af8fe3d2d6dc53ca2a59bd376b089c3c152b3c8" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.10.0" + function-bind "^1.1.1" + has-symbols "^1.0.0" + regexp.prototype.flags "^1.2.0" + string_decoder@^1.0.0, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -6016,7 +6056,7 @@ strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" -strip-json-comments@~2.0.1: +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6061,6 +6101,10 @@ svgo@^0.7.0: sax "~1.2.1" whet.extend "~0.9.9" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + symbol-observable@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" @@ -6069,18 +6113,7 @@ symbol-observable@^1.0.3, symbol-observable@^1.0.4, symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - -table@^4.0.2: +table@^4.0.2, table@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" dependencies: @@ -6116,7 +6149,7 @@ tar@^2.2.1: fstream "^1.0.2" inherits "2" -text-table@~0.2.0: +text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6393,6 +6426,12 @@ uri-js@^3.0.2: dependencies: punycode "^2.1.0" +uri-js@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"