Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New config format #7

Open
3 of 6 tasks
uwap opened this issue Oct 27, 2017 · 15 comments
Open
3 of 6 tasks

New config format #7

uwap opened this issue Oct 27, 2017 · 15 comments
Milestone

Comments

@uwap
Copy link
Owner

uwap commented Oct 27, 2017

We should design a new config format which is cleaner.

Open questions:

  • More logical grouping
  • Types instead of parseState
  • Icon Colors
  • Bidirection of types is still unclear
  • Actions
  • Custom Syntax
@Bfritz0815
Copy link

Bfritz0815 commented Oct 28, 2017 via email

@uwap
Copy link
Owner Author

uwap commented Oct 28, 2017

it is clumsy. especially it will get more clumsy when I change a bit about the ui part. I guess I should first make the changes before thinking about how to clean up the config format.

@uwap uwap mentioned this issue Nov 6, 2017
12 tasks
@uwap
Copy link
Owner Author

uwap commented Nov 16, 2017

We should definely change

my_component = {
  icon: "home",
  iconColor: ({some_topic}) => some_topic == "some_value" ? "#000" : "#111"
}

to

my_component = {
  icon: {
    name: "home",
    color: ({some_topic}) => some_topic == "some_value" ? "#000" : "#111"
  }
}

or even to

my_component = {
  icon: {
    mdi-name: "home",
    color: ({some_topic}) => some_topic == "some_value" ? "#000" : "#111"
  }
}

A further idea would be to also add a <component>.icon.topic option for a more consistent behavior of functions in the config. That would lead to something like:

my_component = {
  icon: {
    mdi-name: "home",
    color: (value) => value == "some_value" ? "#000" : "#111",
    topic: "some_topic"
  }
}

it would also allow to mix different icon sets:

first_component = {
  icon: {
    mdi-name: "home" // material design icons
  }
},
second_component = {
  icon: {
    fa-name: "bell" // font awesome icons
  }
}

Edit:
Maybe do it like this:

first_component = {
  icon: {
    name: mdi("home") // material design icons
  }
},
second_component = {
  icon: {
    name: font-awesome("bell") // font awesome icons
  }
}

@uwap
Copy link
Owner Author

uwap commented Feb 2, 2018

Additionally to the icons being weird in the config format, I think that the topics section is weird too.

I think it is not great that parseState is needed that often. For the esper support in utils I needed to make the topics section an array. It is now an array of javascript objects, that gets merged. This is totally weird and provides possible error sources.

First of all, I want to provide a new way to describe message types.
So instead of

onkyo_mute: {
        state: "/service/onkyo/status/audio-muting",
        command: "/service/onkyo/command",
        defaultValue: "AMT00",
        values: { off: "AMT00", on: "AMT01" },
        parseState: msg => JSON.parse(msg.toString()).onkyo_raw
}

I want it to be like:

onkyo_mute: {
        state: "/service/onkyo/status/audio-muting",
        command: "/service/onkyo/command",
        defaultValue: "AMT00",
        values: { off: "AMT00", on: "AMT01" },
        type: json("onkyo_raw")
}

Possible types would be string, number, json and date.

For the array part I need to brainstorm a bit more about possible ideas. cc @Bfritz0815 @Ranlvor

@uwap
Copy link
Owner Author

uwap commented Feb 2, 2018

I like to rewrite icon colors.

Right now it is always a function. I don't like it. Instead, I want it to be either a color newtype or a javascript object or a function.

Examples:

icon: {
  color: hex("#333333")
}
icon: {
  color: rgb(255, 255, 100)
}
icon: {
  topic: "lightswitch",
  color: {
    on: hex("#333999"),
    off: rgba(255, 100, 100, 0.2)
  }
}
icon: {
  topic: "lightswitch",
  color: {
    on: hex("#333999"),
    off: rgba(255, 100, 100, 0.2)
    default: hex("#FFFFFF")
  }
}

Maybe default should be always required or maybe the map should do a check if all possible values are covered.

Last but not least only for complex setups it should be possible to use a function:

icon: {
  color: ({lightswitch}) => lightswitch == "on" ? hex("#333999") : hex("#001122")
}

@uwap
Copy link
Owner Author

uwap commented Feb 2, 2018

Maybe flows $Keys type could be used to force the use of all values for colors if default is not given:

@uwap
Copy link
Owner Author

uwap commented Mar 28, 2018

We should make the type option for a topic required and not only have it define parseState but also let it define values (and maybe defaultValue too?).

This could result in this for example:

my_toggle: {
        state: "/service/toggle/status",
        command: "/service/toggle/command",
        type: types.enum({on: "ON", off: "OFF"})
}

@uwap
Copy link
Owner Author

uwap commented Mar 29, 2018

I always thought the internal representation of values was kind of redundant and unintuitive but sadly I couldn't find a way around that. Now that I'm looking at the topic types again I really think I've found a way.

Originally the parseState function was only a way around the lack of representations in the config format. But we could actually use it to emulate the internal representation thing. The best example is the my_toggle topic from above. We could have types like types.enum that actually map a value onto a representation. This could also work the other way around.

The only problem with this representation now is that parseState only worked on the state and the internal representation work on both and we still want to support having different types in both directions.

@uwap
Copy link
Owner Author

uwap commented Mar 29, 2018

I also thought about the types.json example. A json could contain all sorts of values. Therefore I thought about making the following types valid

type: types.json("volume", types.number)
type: types.json("name", types.string)
type: types.json("switchState", types.enum({on: "POWERED", off: "DOWN"}))

@uwap uwap added this to the v1.0 milestone Jul 18, 2018
@uwap
Copy link
Owner Author

uwap commented Jul 21, 2018

In the very beginning of this project, we had actions. Each UI control would trigger an action. The action itself would then do something on certain topics. This seemed redundant to me, so we removed it really quickly. Especially since it had some flaws. A slider, mutating values, and a toggle button could in no way share the same actions. But the way we defined actions had no way of preventing it.

We need to reinvent actions in a non redundant way. One slider for example could easily modify multiple values, for example when changing the brightness of a lighting group. A toggle button could toggle multiple things at once. It should be even possible to have it toggle between two of many options.

@uwap
Copy link
Owner Author

uwap commented Jul 21, 2018

One way I can think of this is expanding the topic setting to actual allow multiple topics.

For example an old way of defining a button could look like this:

{
          type: "toggle",
          on: "50",
          off: "0",
          toggled: n => parseInt(n) > 0,
          topic: "kitchen_light_brightness",
          text: "Ein/Ausschalten",
          icon: mdi("power")
}

A new way could look like this:

{
          type: "toggle",
          topics: {
            kitchen_light_brightness: {
              on: "50",
              off: "0",
              toggled: n => parseInt(n) > 0
            },
            kitchen_light_color: {
              on: "50",
              off: "0",
              toggled: true
            }
          },
          text: "Ein/Ausschalten",
          icon: mdi("power")
},

This already has multiple drawbacks:

  • I want a clean way of saying "I want to toggle on that topic with all default values" that doesn't force us to set it to {} or anything else unintuitive.
  • Which topic identifies if a button is toggled or not? In this case I thought of it as doing a large AND over all toggled properties. This doesn't seem right to me though.

@uwap
Copy link
Owner Author

uwap commented Jul 21, 2018

The slider is a more interesting topic though. If a slider changes a light group consisting out of 3 light bulbs, each with their own mqtt topic, which one sets the actual light brightness / the state for this component?

@uwap
Copy link
Owner Author

uwap commented Jul 23, 2018

Another thing that should be possible is having a slider controlling the light for example. When the slider is turned down to 0 is should be able to send "OFF", when it is turned higher than 0 it should sent "ON", but only once. I want the new actions to capable of doing so.

@uwap
Copy link
Owner Author

uwap commented Aug 6, 2018

I thought about it. Maybe we can do something like this:

{
          type: "slider",
          topic: "kitchen_light_brightness",
          text: "Brightness",
          icon: mdi("power"),
          actions: [
            onDrag.oldValueEquals(0).newValueAbove(0).trigger("kitchen_light_power", "on"),
            onDrag.oldValueAbove(0).newValueEquals(0).trigger("kitchen_light_power", "off")
          ]
}

This, but with a more elegant API would be a valid way to describe actions, I think.

@uwap
Copy link
Owner Author

uwap commented Oct 4, 2020

With the config being essential close to JSON, the syntax seems increadibly bloaty. While actions might be a solution to increase the complexity of what we can express and might have the change to express this in a short and eloquent manner, it would be nice to have a custom syntax.

@ Define Config
[Space]
name: "Entropia"
color: "orange"
mqtt: "ws://...:1884"

[Topics]
"hauptraumTableLight" defaults to: "off"
- command topic "/public/sensoren/TPH/leinwand/control" as option("A1 ON" -> "on", "A1 OFF" -> "off")

"hauptraumTableLightOnHack" defaults to: "on"
- command topic "/public/sensoren/TPH/leinwand/control" as option("A1 ON" -> "on", "A1 OFF" -> "off")

[Controls]
Define "Hauptraum Tisch" for "hauptraumTableLight" at [450, 450]:
- icon: mdi("white-balance-iridescent"
- iconColor: hex("#000000")
With "Licht" as "toggle":
- topic: "hauptraumTableLight"
- icon: mdi("power")
With "Licht" as "toggle":
- topic: "hauptraumTableLightOnHack"
- icon: mdi("power")

// Define ... for ... etc.

[Layers]
Define BaseLayer "Entropia" from "./assets/layers/rooms.svg" as default "visible":
- opacity: 0.7
With Bounds:
- topLeft: [0, 0]
- bottomRight: [720, 680]

@ End Config

I could imagine something like this instead of the current entropia config. There might be a way to parse custom javascript syntax using Babel. We could then transform it to javascript. The only issue here would be the flow type checker, as it's important that it runs through AFTER transforming the custom syntax into javascript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants